From 13309b3d8f837eb32774dd6e401452d1cf5010a1 Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Fri, 1 Mar 2019 17:11:02 +0000 Subject: [PATCH 0001/1255] Update stubs to use libnativehelper for java.nio.Buffer access Bug: 124338141 Test: atest CtsGraphicsTestCases Change-Id: I5e4978f4523d4f80bc6813740f2ed9cb57c6d9f4 --- opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp | 46 ++------- opengl/tools/glgen/stubs/gles11/common.cpp | 62 +++--------- opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp | 99 ++++--------------- 3 files changed, 42 insertions(+), 165 deletions(-) diff --git a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp index 1c53c9e8e2..3e9b2c9a69 100644 --- a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp +++ b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp @@ -34,16 +34,6 @@ static jclass egldisplayClass; static jclass eglsurfaceClass; static jclass eglconfigClass; static jclass eglcontextClass; -static jclass bufferClass; -static jclass nioAccessClass; - -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; - -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; static jmethodID egldisplayGetHandleID; static jmethodID eglconfigGetHandleID; @@ -115,24 +105,6 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass) _env->SetStaticObjectField(eglClass, noSurfaceFieldID, eglNoSurfaceObject); // EGL 1.5 init - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); - jclass eglimageClassLocal = _env->FindClass("android/opengl/EGLImage"); eglimageClass = (jclass) _env->NewGlobalRef(eglimageClassLocal); jclass eglsyncClassLocal = _env->FindClass("android/opengl/EGLSync"); @@ -159,23 +131,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *array = NULL; + *array = nullptr; + pointer += position << elementSizeShift; return reinterpret_cast(pointer); } - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } static void diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp index 51e62ed393..e763b4e983 100644 --- a/opengl/tools/glgen/stubs/gles11/common.cpp +++ b/opengl/tools/glgen/stubs/gles11/common.cpp @@ -4,15 +4,6 @@ #include #include -static jclass nioAccessClass; -static jclass bufferClass; -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; - /* special calls implemented in Android's GLES wrapper used to more * efficiently bound-check passed arrays */ @@ -47,28 +38,9 @@ static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type, #endif } -/* Cache method IDs each time the class is loaded. */ - static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * @@ -79,23 +51,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *array = NULL; + *array = nullptr; + pointer += position << elementSizeShift; return reinterpret_cast(pointer); } - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } class ByteArrayGetter { @@ -217,16 +183,18 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { - char* buf = (char*) _env->GetDirectBufferAddress(buffer); - if (buf) { - jint position = _env->GetIntField(buffer, positionID); - jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); - buf += position << elementSizeShift; - } else { + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); + if (pointer == 0) { jniThrowException(_env, "java/lang/IllegalArgumentException", "Must use a native order direct Buffer"); + return nullptr; } - return (void*) buf; + pointer += position << elementSizeShift; + return reinterpret_cast(pointer); } // -------------------------------------------------------------------------- diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp index c808fe9681..c12efc3795 100644 --- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp +++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp @@ -64,16 +64,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer, GLsizei count); } -static jclass nioAccessClass; -static jclass bufferClass; static jclass G11ImplClass; -static jmethodID getBasePointerID; -static jmethodID getBaseArrayID; -static jmethodID getBaseArrayOffsetID; -static jmethodID allowIndirectBuffersID; -static jfieldID positionID; -static jfieldID limitID; -static jfieldID elementSizeShiftID; static jfieldID haveCheckedExtensionsID; static jfieldID have_OES_blend_equation_separateID; static jfieldID have_OES_blend_subtractID; @@ -85,12 +76,6 @@ static jfieldID have_OES_texture_cube_mapID; static void nativeClassInit(JNIEnv *_env, jclass glImplClass) { - jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess"); - nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal); - - jclass bufferClassLocal = _env->FindClass("java/nio/Buffer"); - bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal); - jclass g11impClassLocal = _env->FindClass("com/google/android/gles_jni/GLImpl"); G11ImplClass = (jclass) _env->NewGlobalRef(g11impClassLocal); haveCheckedExtensionsID = _env->GetFieldID(G11ImplClass, "haveCheckedExtensions", "Z"); @@ -98,19 +83,6 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass) have_OES_blend_subtractID = _env->GetFieldID(G11ImplClass, "have_OES_blend_subtract", "Z"); have_OES_framebuffer_objectID = _env->GetFieldID(G11ImplClass, "have_OES_framebuffer_object", "Z"); have_OES_texture_cube_mapID = _env->GetFieldID(G11ImplClass, "have_OES_texture_cube_map", "Z"); - - getBasePointerID = _env->GetStaticMethodID(nioAccessClass, - "getBasePointer", "(Ljava/nio/Buffer;)J"); - getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;"); - getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass, - "getBaseArrayOffset", "(Ljava/nio/Buffer;)I"); - allowIndirectBuffersID = _env->GetStaticMethodID(g11impClassLocal, - "allowIndirectBuffers", "(Ljava/lang/String;)Z"); - positionID = _env->GetFieldID(bufferClass, "position", "I"); - limitID = _env->GetFieldID(bufferClass, "limit", "I"); - elementSizeShiftID = - _env->GetFieldID(bufferClass, "_elementSizeShift", "I"); } static void * @@ -121,28 +93,17 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o jint elementSizeShift; jlong pointer; - position = _env->GetIntField(buffer, positionID); - limit = _env->GetIntField(buffer, limitID); - elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); *remaining = (limit - position) << elementSizeShift; - pointer = _env->CallStaticLongMethod(nioAccessClass, - getBasePointerID, buffer); if (pointer != 0L) { - *offset = 0; - *array = NULL; - return reinterpret_cast(pointer); - } - - *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, - getBaseArrayID, buffer); - if (*array == NULL) { - *offset = 0; - return (void*) NULL; + *array = nullptr; + pointer += position << elementSizeShift; + return reinterpret_cast(pointer); } - *offset = _env->CallStaticIntMethod(nioAccessClass, - getBaseArrayOffsetID, buffer); - return NULL; + *array = jniGetNioBufferBaseArray(_env, buffer); + *offset = jniGetNioBufferBaseArrayOffset(_env, buffer); + return nullptr; } static void @@ -156,42 +117,24 @@ extern "C" { extern char* __progname; } -static bool -allowIndirectBuffers(JNIEnv *_env) { - static jint sIndirectBufferCompatability; - if (sIndirectBufferCompatability == 0) { - jobject appName = _env->NewStringUTF(::__progname); - sIndirectBufferCompatability = _env->CallStaticBooleanMethod(G11ImplClass, allowIndirectBuffersID, appName) ? 2 : 1; - } - return sIndirectBufferCompatability == 2; -} - static void * getDirectBufferPointer(JNIEnv *_env, jobject buffer) { - if (!buffer) { - return NULL; + if (buffer == nullptr) { + return nullptr; } - void* buf = _env->GetDirectBufferAddress(buffer); - if (buf) { - jint position = _env->GetIntField(buffer, positionID); - jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID); - buf = ((char*) buf) + (position << elementSizeShift); - } else { - if (allowIndirectBuffers(_env)) { - jarray array = 0; - jint remaining; - jint offset; - buf = getPointer(_env, buffer, &array, &remaining, &offset); - if (array) { - releasePointer(_env, array, buf, 0); - } - buf = (char*)buf + offset; - } else { - jniThrowException(_env, "java/lang/IllegalArgumentException", - "Must use a native order direct Buffer"); - } + + jint position; + jint limit; + jint elementSizeShift; + jlong pointer; + pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift); + if (pointer == 0) { + jniThrowException(_env, "java/lang/IllegalArgumentException", + "Must use a native order direct Buffer"); + return nullptr; } - return buf; + pointer += position << elementSizeShift; + return reinterpret_cast(pointer); } static int -- GitLab From 7aa71e7b6f224a55a0056664822c7b937be7c3f7 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 1 Apr 2019 15:34:32 -0700 Subject: [PATCH 0002/1255] gui: add hidl hybrid interface as libgui header dependency Bug: 129710438 Change-Id: I848a8c2f225920886883c23d5defd38fef5b8951 --- libs/gui/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 4c2e6532ff..a61e7e162b 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -15,6 +15,10 @@ cc_library_headers { name: "libgui_headers", vendor_available: true, export_include_dirs: ["include"], + + // we must build this module to get the required header as that is generated + export_shared_lib_headers: [ "android.hidl.token@1.0-utils" ], + shared_libs: [ "android.hidl.token@1.0-utils" ], } cc_library_shared { -- GitLab From 51d713f6cd804e00c57d4d1c37a61f9c1fd5fe25 Mon Sep 17 00:00:00 2001 From: Pawin Vongmasa Date: Wed, 3 Apr 2019 17:25:57 -0700 Subject: [PATCH 0003/1255] Add OWNERS to libs/gui/bufferqueue Bug: None Test: None Change-Id: Id114a1e0f43ee03a3fe95e821d8264187132ddfa --- libs/gui/bufferqueue/OWNERS | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 libs/gui/bufferqueue/OWNERS diff --git a/libs/gui/bufferqueue/OWNERS b/libs/gui/bufferqueue/OWNERS new file mode 100644 index 0000000000..cbe931707c --- /dev/null +++ b/libs/gui/bufferqueue/OWNERS @@ -0,0 +1,5 @@ +chz@google.com +lajos@google.com +pawin@google.com +taklee@google.com +wonsik@google.com -- GitLab From 1c403eef2013b0fe4c5ba32ccd48c80a1d3440ad Mon Sep 17 00:00:00 2001 From: Przemyslaw Szczepaniak Date: Thu, 4 Apr 2019 13:57:41 +0100 Subject: [PATCH 0004/1255] Remove PRODUCT_SERVICES from PackageManagerNative.getLocation. It's not used in next android release and its causing issues with cherry-picking to AOSP. Bug: 120483623 Test: Flashed crosshatch, NNAPI cts tests Change-Id: I651796b7f2a79b6236e01bf52d9a80927805f217 --- libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl | 3 --- 1 file changed, 3 deletions(-) diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl index b1c577ecd0..70ed80df85 100644 --- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -66,15 +66,12 @@ interface IPackageManagerNative { const int LOCATION_VENDOR = 0x2; /* ApplicationInfo.isProduct() == true */ const int LOCATION_PRODUCT = 0x4; - /* ApplicationInfo.isProductServices() == true */ - const int LOCATION_PRODUCT_SERVICES = 0x8; /** * Returns a set of bitflags about package location. * LOCATION_SYSTEM: getApplicationInfo(packageName).isSystemApp() * LOCATION_VENDOR: getApplicationInfo(packageName).isVendor() * LOCATION_PRODUCT: getApplicationInfo(packageName).isProduct() - * LOCATION_PRODUCT_SERVICES: getApplicationInfo(packageName).isProductService() */ int getLocationFlags(in @utf8InCpp String packageName); } -- GitLab From ad61a81779640b87900bdd112f3fb8aebebd3c32 Mon Sep 17 00:00:00 2001 From: Andrew Chant Date: Thu, 4 Apr 2019 17:39:17 +0000 Subject: [PATCH 0005/1255] Revert "[SurfaceFlinger] Remove force GPU composition for layers with color transform." This reverts commit 37083d0515500a5e0cb24d082c72eba7f676dea5. Reason for revert: Breaks some display output Bug: 129945273 Change-Id: Ie0cdf9bd696ed4926fdd931d3c8a82fafd1a203f --- services/surfaceflinger/SurfaceFlinger.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1e343550b2..0345bafee6 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1849,6 +1849,11 @@ void SurfaceFlinger::calculateWorkingSet() { layer->forceClientComposition(displayDevice); } + // TODO(b/111562338) remove when composer 2.3 is shipped. + if (layer->hasColorTransform()) { + layer->forceClientComposition(displayDevice); + } + if (layer->getRoundedCornerState().radius > 0.0f) { layer->forceClientComposition(displayDevice); } -- GitLab From 30c8d907d48758caa3901de33450398571e5eace Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Thu, 4 Apr 2019 13:12:49 -0700 Subject: [PATCH 0006/1255] SurfaceComposerClient: Fix potential null de-reference in setRelativeLayer Obviously the code immediately following the diff was going to segfault if we didnt return. Looks like just a trivial refactoring error. Bug: 76148527 Test: Trivial. Change-Id: I0b575e0d8123d57d8110c9450c7a623c65bcd87c --- libs/gui/SurfaceComposerClient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 83cf40c8e9..124eb7f007 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -620,6 +620,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelat layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eRelativeLayerChanged; s->relativeLayerHandle = relativeTo; -- GitLab From 77dd497e9b2131fc2121090d879f6daf5871e4a2 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 30 Jan 2019 09:50:04 -0800 Subject: [PATCH 0007/1255] Remove logspam in InputDispatcher Currently, we are logging an error when a window does not have a registered input channel. But that's not really an error. Convert to a comment instead. Bug: 122436672 Test: presubmit only Change-Id: Ic74a467e67b6a2df8bf46a03f7783d0f4805c429 --- services/inputflinger/InputDispatcher.cpp | 26 +++++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 0d5bc15577..7324c28a81 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -3114,17 +3114,29 @@ void InputDispatcher::setInputWindows(const std::vector>& std::vector> newHandles; for (const sp& handle : inputWindowHandles) { - if (!handle->updateInfo() || (getInputChannelLocked(handle->getToken()) == nullptr - && handle->getInfo()->portalToDisplayId == ADISPLAY_ID_NONE)) { - ALOGE("Window handle %s has no registered input channel", - handle->getName().c_str()); + if (!handle->updateInfo()) { + // handle no longer valid + continue; + } + const InputWindowInfo* info = handle->getInfo(); + + if ((getInputChannelLocked(handle->getToken()) == nullptr && + info->portalToDisplayId == ADISPLAY_ID_NONE)) { + const bool noInputChannel = + info->inputFeatures & InputWindowInfo::INPUT_FEATURE_NO_INPUT_CHANNEL; + const bool canReceiveInput = + !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_TOUCHABLE) || + !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_FOCUSABLE); + if (canReceiveInput && !noInputChannel) { + ALOGE("Window handle %s has no registered input channel", + handle->getName().c_str()); + } continue; } - if (handle->getInfo()->displayId != displayId) { + if (info->displayId != displayId) { ALOGE("Window %s updated by wrong display %d, should belong to display %d", - handle->getName().c_str(), displayId, - handle->getInfo()->displayId); + handle->getName().c_str(), displayId, info->displayId); continue; } -- GitLab From 2307104ba62274578856bdf01fd0a9217125639b Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 4 Apr 2019 14:25:07 -0700 Subject: [PATCH 0008/1255] Enable clang-format for input-related code Enable clang format for: - include/input - libs/input - services/inputflinger Bug: none Test: repo upload a CL Change-Id: I1466c211493738767210f9a5b189caf72df7dd21 --- PREUPLOAD.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 1a932c3d04..4f7cdf3e5e 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -4,13 +4,16 @@ clang_format = true [Builtin Hooks Options] # Only turn on clang-format check for the following subfolders. clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp + include/input/ libs/binder/ndk/ libs/graphicsenv/ libs/gui/ + libs/input/ libs/renderengine/ libs/ui/ libs/vr/ services/bufferhub/ + services/inputflinger/ services/surfaceflinger/ services/vr/ -- GitLab From b3ad35c924daa36a3d1164dabcb7eea6515589f4 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 5 Apr 2019 10:50:52 -0700 Subject: [PATCH 0009/1255] Refactor setInputWindows The logic for the actual window update is now factored out into a separate function. Otherwise, setInputWindows was too long and tough to reason about. There should be no functional change in this CL. Bug: none Test: atest -a inputflinger_tests Change-Id: I49c2eda5178de79de23f772ffc279249ca4402e8 --- services/inputflinger/InputDispatcher.cpp | 152 +++++++++++----------- services/inputflinger/InputDispatcher.h | 7 + 2 files changed, 85 insertions(+), 74 deletions(-) diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 7324c28a81..13de53dc20 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -236,9 +236,17 @@ static void dumpRegion(std::string& dump, const Region& region) { } } -template -static T getValueByKey(std::unordered_map& map, U key) { - typename std::unordered_map::const_iterator it = map.find(key); +/** + * Find the entry in std::unordered_map by key, and return it. + * If the entry is not found, return a default constructed entry. + * + * Useful when the entries are vectors, since an empty vector will be returned + * if the entry is not found. + * Also useful when the entries are sp<>. If an entry is not found, nullptr is returned. + */ +template +static T getValueByKey(const std::unordered_map& map, U key) { + auto it = map.find(key); return it != map.end() ? it->second : T{}; } @@ -3028,14 +3036,7 @@ void InputDispatcher::decrementPendingForegroundDispatches(EventEntry* entry) { std::vector> InputDispatcher::getWindowHandlesLocked( int32_t displayId) const { - std::unordered_map>>::const_iterator it = - mWindowHandlesByDisplay.find(displayId); - if(it != mWindowHandlesByDisplay.end()) { - return it->second; - } - - // Return an empty one if nothing found. - return std::vector>(); + return getValueByKey(mWindowHandlesByDisplay, displayId); } sp InputDispatcher::getWindowHandleLocked( @@ -3077,6 +3078,63 @@ sp InputDispatcher::getInputChannelLocked(const sp& token return mInputChannelsByToken.at(token); } +void InputDispatcher::updateWindowHandlesForDisplayLocked( + const std::vector>& inputWindowHandles, int32_t displayId) { + if (inputWindowHandles.empty()) { + // Remove all handles on a display if there are no windows left. + mWindowHandlesByDisplay.erase(displayId); + return; + } + + // Since we compare the pointer of input window handles across window updates, we need + // to make sure the handle object for the same window stays unchanged across updates. + const std::vector>& oldHandles = getWindowHandlesLocked(displayId); + std::unordered_map, sp, IBinderHash> oldHandlesByTokens; + for (const sp& handle : oldHandles) { + oldHandlesByTokens[handle->getToken()] = handle; + } + + std::vector> newHandles; + for (const sp& handle : inputWindowHandles) { + if (!handle->updateInfo()) { + // handle no longer valid + continue; + } + + const InputWindowInfo* info = handle->getInfo(); + if ((getInputChannelLocked(handle->getToken()) == nullptr && + info->portalToDisplayId == ADISPLAY_ID_NONE)) { + const bool noInputChannel = + info->inputFeatures & InputWindowInfo::INPUT_FEATURE_NO_INPUT_CHANNEL; + const bool canReceiveInput = + !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_TOUCHABLE) || + !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_FOCUSABLE); + if (canReceiveInput && !noInputChannel) { + ALOGE("Window handle %s has no registered input channel", + handle->getName().c_str()); + } + continue; + } + + if (info->displayId != displayId) { + ALOGE("Window %s updated by wrong display %d, should belong to display %d", + handle->getName().c_str(), displayId, info->displayId); + continue; + } + + if (oldHandlesByTokens.find(handle->getToken()) != oldHandlesByTokens.end()) { + const sp oldHandle = oldHandlesByTokens.at(handle->getToken()); + oldHandle->updateFrom(handle); + newHandles.push_back(oldHandle); + } else { + newHandles.push_back(handle); + } + } + + // Insert or replace + mWindowHandlesByDisplay[displayId] = newHandles; +} + /** * Called from InputManagerService, update window handle list by displayId that can receive input. * A window handle contains information about InputChannel, Touch Region, Types, Focused,... @@ -3096,73 +3154,19 @@ void InputDispatcher::setInputWindows(const std::vector>& const std::vector> oldWindowHandles = getWindowHandlesLocked(displayId); + updateWindowHandlesForDisplayLocked(inputWindowHandles, displayId); + sp newFocusedWindowHandle = nullptr; bool foundHoveredWindow = false; - - if (inputWindowHandles.empty()) { - // Remove all handles on a display if there are no windows left. - mWindowHandlesByDisplay.erase(displayId); - } else { - // Since we compare the pointer of input window handles across window updates, we need - // to make sure the handle object for the same window stays unchanged across updates. - const std::vector>& oldHandles = - mWindowHandlesByDisplay[displayId]; - std::unordered_map, sp, IBinderHash> oldHandlesByTokens; - for (const sp& handle : oldHandles) { - oldHandlesByTokens[handle->getToken()] = handle; - } - - std::vector> newHandles; - for (const sp& handle : inputWindowHandles) { - if (!handle->updateInfo()) { - // handle no longer valid - continue; - } - const InputWindowInfo* info = handle->getInfo(); - - if ((getInputChannelLocked(handle->getToken()) == nullptr && - info->portalToDisplayId == ADISPLAY_ID_NONE)) { - const bool noInputChannel = - info->inputFeatures & InputWindowInfo::INPUT_FEATURE_NO_INPUT_CHANNEL; - const bool canReceiveInput = - !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_TOUCHABLE) || - !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_FOCUSABLE); - if (canReceiveInput && !noInputChannel) { - ALOGE("Window handle %s has no registered input channel", - handle->getName().c_str()); - } - continue; - } - - if (info->displayId != displayId) { - ALOGE("Window %s updated by wrong display %d, should belong to display %d", - handle->getName().c_str(), displayId, info->displayId); - continue; - } - - if (oldHandlesByTokens.find(handle->getToken()) != oldHandlesByTokens.end()) { - const sp oldHandle = - oldHandlesByTokens.at(handle->getToken()); - oldHandle->updateFrom(handle); - newHandles.push_back(oldHandle); - } else { - newHandles.push_back(handle); - } + for (const sp& windowHandle : getWindowHandlesLocked(displayId)) { + // Set newFocusedWindowHandle to the top most focused window instead of the last one + if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus && + windowHandle->getInfo()->visible) { + newFocusedWindowHandle = windowHandle; } - - for (const sp& windowHandle : newHandles) { - // Set newFocusedWindowHandle to the top most focused window instead of the last one - if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus - && windowHandle->getInfo()->visible) { - newFocusedWindowHandle = windowHandle; - } - if (windowHandle == mLastHoverWindowHandle) { - foundHoveredWindow = true; - } + if (windowHandle == mLastHoverWindowHandle) { + foundHoveredWindow = true; } - - // Insert or replace - mWindowHandlesByDisplay[displayId] = newHandles; } if (!foundHoveredWindow) { diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 3735a0bcc6..183efa930b 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -1006,6 +1006,13 @@ private: sp getInputChannelLocked(const sp& windowToken) const REQUIRES(mLock); bool hasWindowHandleLocked(const sp& windowHandle) const REQUIRES(mLock); + /* + * Validate and update InputWindowHandles for a given display. + */ + void updateWindowHandlesForDisplayLocked( + const std::vector>& inputWindowHandles, int32_t displayId) + REQUIRES(mLock); + // Focus tracking for keys, trackball, etc. std::unordered_map> mFocusedWindowHandlesByDisplay GUARDED_BY(mLock); -- GitLab From 645365116b7c77204aaffbb88f9407549445396c Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 28 Mar 2019 09:53:04 -0700 Subject: [PATCH 0010/1255] SF: Remove per-display state in scheduler This CL removes per-display RefreshRateConfigs and AllowedDisplayConfigs to avoid bugs in the untested multi-display code path of the scheduler, adds checks to prevent crashes if the internal display is removed, and cleans up related code by: 1) Replacing AllowedDisplayConfigs with a simple set. 2) Making setAllowedDisplayConfigs consistent with setPowerMode. 3) Removing unnecessary locking and allocation. Bug: 129433906 Test: Boot with single/multiple display(s) Change-Id: I3f59e9bdeaceb2cf48b4b9b71cd27f1d6a574680 --- .../surfaceflinger/AllowedDisplayConfigs.h | 68 ------- .../Scheduler/RefreshRateConfigs.h | 14 +- .../Scheduler/RefreshRateStats.h | 26 ++- services/surfaceflinger/SurfaceFlinger.cpp | 168 ++++++------------ services/surfaceflinger/SurfaceFlinger.h | 42 ++--- .../unittests/AllowedDisplayConfigsTest.cpp | 96 ---------- .../surfaceflinger/tests/unittests/Android.bp | 1 - .../unittests/RefreshRateConfigsTest.cpp | 48 ++--- .../tests/unittests/RefreshRateStatsTest.cpp | 100 +++++------ 9 files changed, 154 insertions(+), 409 deletions(-) delete mode 100644 services/surfaceflinger/AllowedDisplayConfigs.h delete mode 100644 services/surfaceflinger/tests/unittests/AllowedDisplayConfigsTest.cpp diff --git a/services/surfaceflinger/AllowedDisplayConfigs.h b/services/surfaceflinger/AllowedDisplayConfigs.h deleted file mode 100644 index 7ca62ea550..0000000000 --- a/services/surfaceflinger/AllowedDisplayConfigs.h +++ /dev/null @@ -1,68 +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 -#include - -/* - * Used to represent the Display Configurations allowed to be set by SurfaceFlinger - */ -class AllowedDisplayConfigs { -private: - // Defining ConstructorTag as private to prevent instantiating this class from outside - // while still allowing it to be constructed by std::make_unique - struct ConstructorTag {}; - -public: - AllowedDisplayConfigs(ConstructorTag) {} - - class Builder { - public: - Builder() - : mAllowedDisplayConfigs(std::make_unique(ConstructorTag{})) {} - - std::unique_ptr build() { - return std::move(mAllowedDisplayConfigs); - } - - // add a config to the allowed config set - Builder& addConfig(int32_t config) { - mAllowedDisplayConfigs->addConfig(config); - return *this; - } - - private: - std::unique_ptr mAllowedDisplayConfigs; - }; - - bool isConfigAllowed(int32_t config) const { - return (std::find(mConfigs.begin(), mConfigs.end(), config) != mConfigs.end()); - } - - void getAllowedConfigs(std::vector* outConfigs) const { - if (outConfigs) { - *outConfigs = mConfigs; - } - } - -private: - // add a config to the allowed config set - void addConfig(int32_t config) { mConfigs.push_back(config); } - - std::vector mConfigs; -}; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 1aa6aded75..5874066aed 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -51,13 +51,7 @@ public: // TODO(b/122916473): Get this information from configs prepared by vendors, instead of // baking them in. - explicit RefreshRateConfigs( - const std::vector>& configs) { - init(configs); - } - ~RefreshRateConfigs() = default; - - const std::map>& getRefreshRates() { + const std::map>& getRefreshRates() const { return mRefreshRates; } std::shared_ptr getRefreshRate(RefreshRateType type) { @@ -68,8 +62,9 @@ public: return nullptr; } -private: - void init(const std::vector>& configs) { + void populate(const std::vector>& configs) { + mRefreshRates.clear(); + // This is the rate that HWC encapsulates right now when the device is in DOZE mode. mRefreshRates.emplace(RefreshRateType::POWER_SAVING, std::make_shared( @@ -120,6 +115,7 @@ private: } } +private: std::map> mRefreshRates; }; diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h index ff63faf029..7e7c6307a4 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateStats.h +++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h @@ -41,12 +41,8 @@ class RefreshRateStats { static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR; public: - explicit RefreshRateStats(const std::shared_ptr& refreshRateConfigs, - const std::shared_ptr& timeStats) - : mRefreshRateConfigs(refreshRateConfigs), - mTimeStats(timeStats), - mPreviousRecordedTime(systemTime()) {} - ~RefreshRateStats() = default; + RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats) + : mRefreshRateConfigs(refreshRateConfigs), mTimeStats(timeStats) {} // Sets power mode. We only collect the information when the power mode is not // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based @@ -83,7 +79,7 @@ public: flushTime(); std::unordered_map totalTime; - for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) { + for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) { int64_t totalTimeForConfig = 0; if (!config) { continue; @@ -98,11 +94,11 @@ public: // Traverses through the map of config modes and returns how long they've been running in easy // to read format. - std::string doDump() { + std::string doDump() const { std::ostringstream stream; stream << "+ Refresh rate: running time in seconds\n"; - for (auto stats : getTotalTimes()) { - stream << stats.first.c_str() << ": " << getDateFormatFromMs(stats.second) << "\n"; + for (const auto& [name, time] : const_cast(this)->getTotalTimes()) { + stream << name << ": " << getDateFormatFromMs(time) << '\n'; } return stream.str(); } @@ -126,12 +122,12 @@ private: mPreviousRecordedTime = currentTime; mConfigModesTotalTime[mode] += timeElapsedMs; - for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) { + for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) { if (!config) { continue; } if (config->configId == mode) { - mTimeStats->recordRefreshRate(config->fps, timeElapsed); + mTimeStats.recordRefreshRate(config->fps, timeElapsed); } } } @@ -148,17 +144,17 @@ private: } // Keeps information about refresh rate configs that device has. - std::shared_ptr mRefreshRateConfigs; + const RefreshRateConfigs& mRefreshRateConfigs; // Aggregate refresh rate statistics for telemetry. - std::shared_ptr mTimeStats; + TimeStats& mTimeStats; int64_t mCurrentConfigMode = SCREEN_OFF_CONFIG_ID; int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF; std::unordered_map mConfigModesTotalTime; - nsecs_t mPreviousRecordedTime; + nsecs_t mPreviousRecordedTime = systemTime(); }; } // namespace scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5676c59834..c248de4371 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -558,14 +558,10 @@ void SurfaceFlinger::bootFinished() mBootStage = BootStage::FINISHED; // set the refresh rate according to the policy - const auto displayId = getInternalDisplayIdLocked(); - LOG_ALWAYS_FATAL_IF(!displayId); - const auto& performanceRefreshRate = - mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE); + mRefreshRateConfigs.getRefreshRate(RefreshRateType::PERFORMANCE); - if (performanceRefreshRate && - isConfigAllowed(*displayId, performanceRefreshRate->configId)) { + if (performanceRefreshRate && isDisplayConfigAllowed(performanceRefreshRate->configId)) { setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); } else { setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); @@ -706,12 +702,8 @@ void SurfaceFlinger::init() { setRefreshRateTo(type, event); }); } - mRefreshRateConfigs[*display->getId()] = std::make_shared( - getHwComposer().getConfigs(*display->getId())); - mRefreshRateStats = - std::make_unique(mRefreshRateConfigs[*display->getId()], - mTimeStats); - mRefreshRateStats->setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId())); + mRefreshRateConfigs.populate(getHwComposer().getConfigs(*display->getId())); + mRefreshRateStats.setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId())); ALOGV("Done initializing"); } @@ -786,12 +778,14 @@ status_t SurfaceFlinger::getSupportedFrameTimestamps( return NO_ERROR; } -status_t SurfaceFlinger::getDisplayConfigsLocked(const sp& displayToken, - Vector* configs) { +status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, + Vector* configs) { if (!displayToken || !configs) { return BAD_VALUE; } + Mutex::Autolock lock(mStateLock); + const auto displayId = getPhysicalDisplayIdLocked(displayToken); if (!displayId) { return NAME_NOT_FOUND; @@ -917,18 +911,6 @@ int SurfaceFlinger::getActiveConfig(const sp& displayToken) { void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { ATRACE_CALL(); - // Lock is acquired by setRefreshRateTo. - const auto display = getDisplayDeviceLocked(info.displayToken); - if (!display) { - ALOGE("Attempt to set active config %d for invalid display token %p", info.configId, - info.displayToken.get()); - return; - } - if (display->isVirtual()) { - ALOGW("Attempt to set active config %d for virtual display", info.configId); - return; - } - // Don't check against the current mode yet. Worst case we set the desired // config twice. However event generation config might have changed so we need to update it // accordingly @@ -964,23 +946,28 @@ status_t SurfaceFlinger::setActiveConfig(const sp& displayToken, int mo void SurfaceFlinger::setActiveConfigInternal() { ATRACE_CALL(); + const auto display = getDefaultDisplayDeviceLocked(); + if (!display) { + return; + } + std::lock_guard lock(mActiveConfigLock); - mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId); + mRefreshRateStats.setConfigMode(mUpcomingActiveConfig.configId); - const auto display = getDisplayDeviceLocked(mUpcomingActiveConfig.displayToken); display->setActiveConfig(mUpcomingActiveConfig.configId); mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); mVsyncModulator.setPhaseOffsets(early, gl, late); ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId); + if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) { mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, mUpcomingActiveConfig.configId); } } -bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS { +bool SurfaceFlinger::performSetActiveConfig() { ATRACE_CALL(); if (mCheckPendingFence) { if (mPreviousPresentFence != Fence::NO_FENCE && @@ -1006,7 +993,7 @@ bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS { desiredActiveConfig = mDesiredActiveConfig; } - const auto display = getDisplayDevice(desiredActiveConfig.displayToken); + const auto display = getDefaultDisplayDeviceLocked(); if (!display || display->getActiveConfig() == desiredActiveConfig.configId) { // display is not valid or we are already in the requested mode // on both cases there is nothing left to do @@ -1021,7 +1008,7 @@ bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS { // Desired active config was set, it is different than the config currently in use, however // allowed configs might have change by the time we process the refresh. // Make sure the desired config is still allowed - if (!isConfigAllowed(*display->getId(), desiredActiveConfig.configId)) { + if (!isDisplayConfigAllowed(desiredActiveConfig.configId)) { std::lock_guard lock(mActiveConfigLock); mDesiredActiveConfig.configId = display->getActiveConfig(); return false; @@ -1422,29 +1409,19 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } -bool SurfaceFlinger::isConfigAllowed(const DisplayId& displayId, int32_t config) { - std::lock_guard lock(mAllowedConfigsLock); - - // if allowed configs are not set yet for this display, every config is considered allowed - if (mAllowedConfigs.find(displayId) == mAllowedConfigs.end()) { - return true; - } - - return mAllowedConfigs[displayId]->isConfigAllowed(config); +bool SurfaceFlinger::isDisplayConfigAllowed(int32_t configId) { + return mAllowedDisplayConfigs.empty() || mAllowedDisplayConfigs.count(configId); } void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::ConfigEvent event) { - if (mBootStage != BootStage::FINISHED) { + const auto display = getDefaultDisplayDeviceLocked(); + if (!display || mBootStage != BootStage::FINISHED) { return; } ATRACE_CALL(); // Don't do any updating if the current fps is the same as the new one. - const auto displayId = getInternalDisplayIdLocked(); - LOG_ALWAYS_FATAL_IF(!displayId); - const auto displayToken = getInternalDisplayTokenLocked(); - - const auto& refreshRateConfig = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate); + const auto& refreshRateConfig = mRefreshRateConfigs.getRefreshRate(refreshRate); if (!refreshRateConfig) { ALOGV("Skipping refresh rate change request for unsupported rate."); return; @@ -1452,19 +1429,18 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::Co const int desiredConfigId = refreshRateConfig->configId; - if (!isConfigAllowed(*displayId, desiredConfigId)) { + if (!isDisplayConfigAllowed(desiredConfigId)) { ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId); return; } mPhaseOffsets->setRefreshRateType(refreshRate); - const auto display = getDisplayDeviceLocked(displayToken); if (desiredConfigId == display->getActiveConfig()) { return; } - setDesiredActiveConfig({refreshRate, desiredConfigId, getInternalDisplayTokenLocked(), event}); + setDesiredActiveConfig({refreshRate, desiredConfigId, event}); } void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId, @@ -1604,7 +1580,7 @@ void SurfaceFlinger::updateVrFlinger() { setTransactionFlags(eDisplayTransactionNeeded); } -void SurfaceFlinger::onMessageReceived(int32_t what) { +void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { ATRACE_CALL(); switch (what) { case MessageQueue::INVALIDATE: { @@ -2483,9 +2459,6 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { state.displayName = info->name; mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state); mInterceptor->saveDisplayCreation(state); - // TODO(b/123715322): Removes the per-display state that was added to the scheduler. - mRefreshRateConfigs[info->id] = std::make_shared( - getHwComposer().getConfigs(info->id)); } } else { ALOGV("Removing display %s", to_string(info->id).c_str()); @@ -2497,7 +2470,6 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { mCurrentState.displays.removeItemsAt(index); } mPhysicalDisplayTokens.erase(info->id); - mRefreshRateConfigs.erase(info->id); } processDisplayChangesLocked(); @@ -4346,10 +4318,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, int if (display->isPrimary()) { mTimeStats->setPowerMode(mode); - if (mRefreshRateStats) { - // Update refresh rate stats. - mRefreshRateStats->setPowerMode(mode); - } + mRefreshRateStats.setPowerMode(mode); } ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str()); @@ -4877,7 +4846,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co result.append("\nScheduler state:\n"); result.append(mScheduler->doDump() + "\n"); StringAppendF(&result, "+ Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off"); - result.append(mRefreshRateStats->doDump() + "\n"); + result.append(mRefreshRateStats.doDump() + "\n"); } const Vector>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) { @@ -5795,95 +5764,66 @@ void SurfaceFlinger::traverseLayersInDisplay(const sp& disp } } -void SurfaceFlinger::setAllowedDisplayConfigsInternal( - const android::sp& displayToken, - std::unique_ptr&& allowedConfigs) { - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - ALOGE("setAllowedDisplayConfigsInternal: getPhysicalDisplayId failed"); +void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp& display, + const std::vector& allowedConfigs) { + if (!display->isPrimary()) { return; } ALOGV("Updating allowed configs"); - { - std::lock_guard lock(mAllowedConfigsLock); - mAllowedConfigs[*displayId] = std::move(allowedConfigs); - } + mAllowedDisplayConfigs = DisplayConfigs(allowedConfigs.begin(), allowedConfigs.end()); // Set the highest allowed config by iterating backwards on available refresh rates - const auto& refreshRates = mRefreshRateConfigs[*displayId]->getRefreshRates(); + const auto& refreshRates = mRefreshRateConfigs.getRefreshRates(); for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) { - if (iter->second && isConfigAllowed(*displayId, iter->second->configId)) { + if (iter->second && isDisplayConfigAllowed(iter->second->configId)) { ALOGV("switching to config %d", iter->second->configId); - setDesiredActiveConfig({iter->first, iter->second->configId, displayToken, - Scheduler::ConfigEvent::Changed}); + setDesiredActiveConfig( + {iter->first, iter->second->configId, Scheduler::ConfigEvent::Changed}); break; } } } -status_t SurfaceFlinger::setAllowedDisplayConfigs(const android::sp& displayToken, +status_t SurfaceFlinger::setAllowedDisplayConfigs(const sp& displayToken, const std::vector& allowedConfigs) { ATRACE_CALL(); - if (!displayToken) { - ALOGE("setAllowedDisplayConfigs: displayToken is null"); - return BAD_VALUE; - } - - if (!allowedConfigs.size()) { - ALOGE("setAllowedDisplayConfigs: empty config set provided"); + if (!displayToken || allowedConfigs.empty()) { return BAD_VALUE; } - { - ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - ALOGE("setAllowedDisplayConfigs: display not found"); - return NAME_NOT_FOUND; - } - } - - auto allowedDisplayConfigsBuilder = AllowedDisplayConfigs::Builder(); - for (int config : allowedConfigs) { - ALOGV("setAllowedDisplayConfigs: Adding config to the allowed configs = %d", config); - allowedDisplayConfigsBuilder.addConfig(config); - } - auto allowedDisplayConfigs = allowedDisplayConfigsBuilder.build(); postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS { - setAllowedDisplayConfigsInternal(displayToken, std::move(allowedDisplayConfigs)); + const auto display = getDisplayDeviceLocked(displayToken); + if (!display) { + ALOGE("Attempt to set allowed display configs for invalid display token %p", + displayToken.get()); + } else if (display->isVirtual()) { + ALOGW("Attempt to set allowed display configs for virtual display"); + } else { + setAllowedDisplayConfigsInternal(display, allowedConfigs); + } })); + return NO_ERROR; } -status_t SurfaceFlinger::getAllowedDisplayConfigs(const android::sp& displayToken, +status_t SurfaceFlinger::getAllowedDisplayConfigs(const sp& displayToken, std::vector* outAllowedConfigs) { ATRACE_CALL(); - if (!displayToken) { - ALOGE("getAllowedDisplayConfigs: displayToken is null"); + if (!displayToken || !outAllowedConfigs) { return BAD_VALUE; } - if (!outAllowedConfigs) { - ALOGE("getAllowedDisplayConfigs: outAllowedConfigs is null"); - return BAD_VALUE; - } + Mutex::Autolock lock(mStateLock); - ConditionalLock stateLock(mStateLock, std::this_thread::get_id() != mMainThreadId); - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - ALOGE("getAllowedDisplayConfigs: display not found"); + if (displayToken != getInternalDisplayTokenLocked()) { + ALOGE("%s is only supported for the internal display", __FUNCTION__); return NAME_NOT_FOUND; } - std::lock_guard allowedConfigLock(mAllowedConfigsLock); - auto allowedConfigIterator = mAllowedConfigs.find(displayId.value()); - if (allowedConfigIterator != mAllowedConfigs.end()) { - allowedConfigIterator->second->getAllowedConfigs(outAllowedConfigs); - } - + outAllowedConfigs->assign(mAllowedDisplayConfigs.begin(), mAllowedDisplayConfigs.end()); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 5cd0f213da..8ea425d06c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -46,7 +46,6 @@ #include #include -#include "AllowedDisplayConfigs.h" #include "DisplayDevice.h" #include "DisplayHardware/HWC2.h" #include "DisplayHardware/PowerAdvisor.h" @@ -74,6 +73,7 @@ #include #include #include +#include #include using namespace android::surfaceflinger; @@ -404,12 +404,7 @@ private: const Rect& sourceCrop, float frameScale, bool childrenOnly) override; status_t getDisplayStats(const sp& displayToken, DisplayStatInfo* stats) override; status_t getDisplayConfigs(const sp& displayToken, - Vector* configs) override { - Mutex::Autolock _l(mStateLock); - return getDisplayConfigsLocked(displayToken, configs); - } - status_t getDisplayConfigsLocked(const sp& displayToken, Vector* configs) - REQUIRES(mStateLock); + Vector* configs) override; int getActiveConfig(const sp& displayToken) override; status_t getDisplayColorModes(const sp& displayToken, Vector* configs) override; @@ -488,20 +483,10 @@ private: struct ActiveConfigInfo { RefreshRateType type; int configId; - sp displayToken; Scheduler::ConfigEvent event; bool operator!=(const ActiveConfigInfo& other) const { - if (type != other.type) { - return true; - } - if (configId != other.configId) { - return true; - } - if (displayToken != other.displayToken) { - return true; - } - return (event != other.event); + return type != other.type || configId != other.configId || event != other.event; } }; @@ -516,14 +501,14 @@ private: // desired config was set, HWC needs to update the panel on the next refresh, and when // we receive the fence back, we know that the process was complete. It returns whether // we need to wait for the next invalidate - bool performSetActiveConfig(); + bool performSetActiveConfig() REQUIRES(mStateLock); // called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp& display, int mode) REQUIRES(mStateLock); // called on the main thread in response to setAllowedDisplayConfigs() - void setAllowedDisplayConfigsInternal( - const sp& displayToken, - std::unique_ptr&& allowedConfigs) REQUIRES(mStateLock); + void setAllowedDisplayConfigsInternal(const sp& display, + const std::vector& allowedConfigs) + REQUIRES(mStateLock); // Returns whether the transaction actually modified any state bool handleMessageTransaction(); @@ -802,7 +787,7 @@ private: // the desired refresh rate. void setRefreshRateTo(RefreshRateType, Scheduler::ConfigEvent event) REQUIRES(mStateLock); - bool isConfigAllowed(const DisplayId& displayId, int32_t config); + bool isDisplayConfigAllowed(int32_t configId) REQUIRES(mStateLock); /* * Display identification @@ -1108,14 +1093,13 @@ private: std::unique_ptr mScheduler; sp mAppConnectionHandle; sp mSfConnectionHandle; - std::unique_ptr mRefreshRateStats; - std::unordered_map> - mRefreshRateConfigs; + scheduler::RefreshRateConfigs mRefreshRateConfigs; + scheduler::RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, *mTimeStats}; - std::mutex mAllowedConfigsLock; - std::unordered_map> mAllowedConfigs - GUARDED_BY(mAllowedConfigsLock); + // All configs are allowed if the set is empty. + using DisplayConfigs = std::unordered_set; + DisplayConfigs mAllowedDisplayConfigs GUARDED_BY(mStateLock); std::mutex mActiveConfigLock; // This bit is set once we start setting the config. We read from this bit during the diff --git a/services/surfaceflinger/tests/unittests/AllowedDisplayConfigsTest.cpp b/services/surfaceflinger/tests/unittests/AllowedDisplayConfigsTest.cpp deleted file mode 100644 index 42742543ac..0000000000 --- a/services/surfaceflinger/tests/unittests/AllowedDisplayConfigsTest.cpp +++ /dev/null @@ -1,96 +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. - */ - -#undef LOG_TAG -#define LOG_TAG "LibSurfaceFlingerUnittests" -#define LOG_NDEBUG 0 - -#include -#include - -#include - -#include - -#include "AllowedDisplayConfigs.h" - -namespace android { -namespace { - -class AllowedDisplayConfigsTest : public testing::Test { -protected: - AllowedDisplayConfigsTest(); - ~AllowedDisplayConfigsTest() override; - - void buildAllowedConfigs(); - - const std::vector expectedConfigs = {0, 2, 7, 129}; - constexpr static int32_t notAllowedConfig = 5; - std::unique_ptr mAllowedConfigs; -}; - -AllowedDisplayConfigsTest::AllowedDisplayConfigsTest() { - 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()); -} - -AllowedDisplayConfigsTest::~AllowedDisplayConfigsTest() { - 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()); -} - -void AllowedDisplayConfigsTest::buildAllowedConfigs() { - AllowedDisplayConfigs::Builder builder; - for (int config : expectedConfigs) { - builder.addConfig(config); - } - mAllowedConfigs = builder.build(); -} - -/* ------------------------------------------------------------------------ - * Test cases - */ - -TEST_F(AllowedDisplayConfigsTest, checkConfigs) { - buildAllowedConfigs(); - - // Check that all expected configs are allowed - for (int config : expectedConfigs) { - EXPECT_TRUE(mAllowedConfigs->isConfigAllowed(config)); - } - - // Check that all the allowed configs are expected - std::vector allowedConfigVector; - mAllowedConfigs->getAllowedConfigs(&allowedConfigVector); - EXPECT_EQ(allowedConfigVector, expectedConfigs); - - // Check that notAllowedConfig is indeed not allowed - EXPECT_TRUE(std::find(expectedConfigs.begin(), expectedConfigs.end(), notAllowedConfig) == - expectedConfigs.end()); - EXPECT_FALSE(mAllowedConfigs->isConfigAllowed(notAllowedConfig)); -} - -TEST_F(AllowedDisplayConfigsTest, getAllowedConfigsNullptr) { - buildAllowedConfigs(); - - // No other expectations rather than no crash - mAllowedConfigs->getAllowedConfigs(nullptr); -} - -} // namespace -} // namespace android diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index d4eac88ba1..85e9ce5f3f 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -35,7 +35,6 @@ cc_test { srcs: [ ":libsurfaceflinger_sources", "libsurfaceflinger_unittest_main.cpp", - "AllowedDisplayConfigsTest.cpp", "CompositionTest.cpp", "DispSyncSourceTest.cpp", "DisplayIdentificationTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index b218ad63d6..8b37c22356 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -49,6 +49,8 @@ protected: ASSERT_EQ(left.name, right.name); ASSERT_EQ(left.fps, right.fps); } + + RefreshRateConfigs mConfigs; }; RefreshRateConfigsTest::RefreshRateConfigsTest() { @@ -69,10 +71,10 @@ namespace { */ TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) { std::vector> displayConfigs; - RefreshRateConfigs configs(displayConfigs); + mConfigs.populate(displayConfigs); // We always store a configuration for screen off. - const auto& rates = configs.getRefreshRates(); + const auto& rates = mConfigs.getRefreshRates(); ASSERT_EQ(1, rates.size()); const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); ASSERT_NE(rates.end(), powerSavingRate); @@ -82,13 +84,13 @@ TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) { RefreshRate expectedConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}; assertRatesEqual(expectedConfig, *powerSavingRate->second); - ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING)); - assertRatesEqual(expectedConfig, *configs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE)); - ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::DEFAULT)); + ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); + assertRatesEqual(expectedConfig, *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); + ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); + ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); // Sanity check that getRefreshRate() does not modify the underlying configs. - ASSERT_EQ(1, configs.getRefreshRates().size()); + ASSERT_EQ(1, mConfigs.getRefreshRates().size()); } TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) { @@ -97,9 +99,9 @@ TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) { auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); config60.setVsyncPeriod(VSYNC_60); displayConfigs.push_back(config60.build()); - RefreshRateConfigs configs(displayConfigs); + mConfigs.populate(displayConfigs); - const auto& rates = configs.getRefreshRates(); + const auto& rates = mConfigs.getRefreshRates(); ASSERT_EQ(2, rates.size()); const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); @@ -112,15 +114,15 @@ TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) { RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60}; assertRatesEqual(expectedDefaultConfig, *defaultRate->second); - ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING)); + ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); assertRatesEqual(expectedPowerSavingConfig, - *configs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT)); - assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT)); - ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE)); + *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); + ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); + assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); + ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); // Sanity check that getRefreshRate() does not modify the underlying configs. - ASSERT_EQ(2, configs.getRefreshRates().size()); + ASSERT_EQ(2, mConfigs.getRefreshRates().size()); } TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) { @@ -132,9 +134,9 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) { auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90); config90.setVsyncPeriod(VSYNC_90); displayConfigs.push_back(config90.build()); - RefreshRateConfigs configs(displayConfigs); + mConfigs.populate(displayConfigs); - const auto& rates = configs.getRefreshRates(); + const auto& rates = mConfigs.getRefreshRates(); ASSERT_EQ(3, rates.size()); const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); @@ -150,14 +152,14 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) { RefreshRate expectedPerformanceConfig = RefreshRate{CONFIG_ID_90, "90fps", 90}; assertRatesEqual(expectedPerformanceConfig, *performanceRate->second); - ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING)); + ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); assertRatesEqual(expectedPowerSavingConfig, - *configs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT)); - assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT)); - ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::PERFORMANCE)); + *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); + ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); + assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); + ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); assertRatesEqual(expectedPerformanceConfig, - *configs.getRefreshRate(RefreshRateType::PERFORMANCE)); + *mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); } } // namespace } // namespace scheduler diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index 10f5af8cd2..411ec61770 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -42,11 +42,9 @@ protected: RefreshRateStatsTest(); ~RefreshRateStatsTest(); - void init(std::vector> configs); - - std::unique_ptr mRefreshRateStats; - std::shared_ptr mTimeStats; - std::shared_ptr mRefreshRateConfigs; + mock::TimeStats mTimeStats; + RefreshRateConfigs mRefreshRateConfigs; + RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, mTimeStats}; }; RefreshRateStatsTest::RefreshRateStatsTest() { @@ -61,22 +59,16 @@ RefreshRateStatsTest::~RefreshRateStatsTest() { ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } -void RefreshRateStatsTest::init(std::vector> configs) { - mTimeStats = std::make_shared(); - mRefreshRateConfigs = std::make_shared(configs); - mRefreshRateStats = std::make_unique(mRefreshRateConfigs, mTimeStats); -} - namespace { /* ------------------------------------------------------------------------ * Test cases */ TEST_F(RefreshRateStatsTest, canCreateAndDestroyTest) { std::vector> configs; - init(configs); + mRefreshRateConfigs.populate(configs); // There is one default config, so the refresh rates should have one item. - EXPECT_EQ(1, mRefreshRateStats->getTotalTimes().size()); + EXPECT_EQ(1, mRefreshRateStats.getTotalTimes().size()); } TEST_F(RefreshRateStatsTest, oneConfigTest) { @@ -87,12 +79,12 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { std::vector> configs; configs.push_back(config.build()); - init(configs); + mRefreshRateConfigs.populate(configs); - EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); - EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); + EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); + EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); - std::unordered_map times = mRefreshRateStats->getTotalTimes(); + std::unordered_map times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(2, times.size()); EXPECT_NE(0u, times.count("ScreenOff")); EXPECT_EQ(1u, times.count("90fps")); @@ -105,29 +97,29 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { // Screen is off by default. std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(0, times["90fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); - mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); - screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_90); + mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL); + screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_LT(ninety, times["90fps"]); - mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE); - ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE); + ninety = mRefreshRateStats.getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); - screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_90); + screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config // does not update refresh rates that come from the config. EXPECT_LT(screenOff, times["ScreenOff"]); @@ -146,13 +138,13 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { config60.setVsyncPeriod(VSYNC_60); configs.push_back(config60.build()); - init(configs); + mRefreshRateConfigs.populate(configs); - EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); - EXPECT_CALL(*mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1)); - EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); + EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); + EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1)); + EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); - std::unordered_map times = mRefreshRateStats->getTotalTimes(); + std::unordered_map times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(3, times.size()); EXPECT_NE(0u, times.count("ScreenOff")); EXPECT_EQ(1u, times.count("60fps")); @@ -168,60 +160,60 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { // Screen is off by default. std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(sixty, times["60fps"]); EXPECT_EQ(ninety, times["90fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); - mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); - screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_90); + mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL); + screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_EQ(sixty, times["60fps"]); EXPECT_LT(ninety, times["90fps"]); // When power mode is normal, time for configs updates. - mRefreshRateStats->setConfigMode(CONFIG_ID_60); - ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_60); + ninety = mRefreshRateStats.getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_LT(sixty, times["60fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); - sixty = mRefreshRateStats->getTotalTimes()["60fps"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_90); + sixty = mRefreshRateStats.getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_LT(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_60); - ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_60); + ninety = mRefreshRateStats.getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_LT(sixty, times["60fps"]); // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config // does not update refresh rates that come from the config. - mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); - sixty = mRefreshRateStats->getTotalTimes()["60fps"]; + mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE); + mRefreshRateStats.setConfigMode(CONFIG_ID_90); + sixty = mRefreshRateStats.getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_60); - screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_60); + screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); -- GitLab From 183c44ce4db3f30912a6233f3567ee7990de6063 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Mon, 8 Apr 2019 12:58:50 -0700 Subject: [PATCH 0011/1255] ASurfaceControl: support framebuffer devices There are Android devices that use a hwc2onfbadapter that allows them to ship framebuffer devices but still pass VTS and appear to the system as if they have hwc2.x*. Unfortunately, these devices do not support a present fence. This patch updates the documentation to let developers know that not all devices will return a present fence. Test: ASurfaceControlTest Bug: 129880031 Change-Id: I81dd21dc088b1d2d73d1bdb9c46216ef2e171063 --- include/android/surface_control.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/android/surface_control.h b/include/android/surface_control.h index ef2ad9998c..abb8368069 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -130,7 +130,7 @@ int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_ /** * Returns a sync fence that signals when the transaction has been presented. * The recipient of the callback takes ownership of the fence and is responsible for closing - * it. + * it. If a device does not support present fences, a -1 will be returned. */ int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats) __INTRODUCED_IN(29); -- GitLab From 6d78a57a95c59cf08549f2c861193b1d9771e92c Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Wed, 10 Apr 2019 15:35:38 -0700 Subject: [PATCH 0012/1255] libvulkan: update code gen templates Update code-generator.tmpl to match the result from doing `$ apic template ../api/vulkan.api code-generator.tmpl`. Update null_driver.tmpl to match the result from doing `$ apic template ../api/vulkan.api null_driver.tmpl`. Test: build Change-Id: Idcf6c148fd0d49bb1b6a31e657e82970f52923c0 --- vulkan/libvulkan/api_gen.cpp | 3 +-- vulkan/libvulkan/api_gen.h | 2 ++ vulkan/libvulkan/code-generator.tmpl | 15 ++++++++------- vulkan/libvulkan/driver_gen.cpp | 3 +-- vulkan/libvulkan/driver_gen.h | 1 + vulkan/nulldrv/null_driver.tmpl | 3 ++- vulkan/nulldrv/null_driver_gen.cpp | 1 + 7 files changed, 16 insertions(+), 12 deletions(-) diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp index df86af0c3b..ad46c3bf93 100644 --- a/vulkan/libvulkan/api_gen.cpp +++ b/vulkan/libvulkan/api_gen.cpp @@ -16,12 +16,11 @@ // WARNING: This file is generated. See ../README.md for instructions. +#include #include #include -#include - // to catch mismatches between vulkan.h and this file #undef VK_NO_PROTOTYPES #include "api.h" diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h index 4bedbeb16e..f5822249b3 100644 --- a/vulkan/libvulkan/api_gen.h +++ b/vulkan/libvulkan/api_gen.h @@ -20,7 +20,9 @@ #define LIBVULKAN_API_GEN_H #include + #include + #include "driver_gen.h" namespace vulkan { diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl index f04eb03eac..dd0de048fb 100644 --- a/vulkan/libvulkan/code-generator.tmpl +++ b/vulkan/libvulkan/code-generator.tmpl @@ -37,8 +37,10 @@ #ifndef LIBVULKAN_API_GEN_H #define LIBVULKAN_API_GEN_H ¶ -#include #include +¶ +#include +¶ #include "driver_gen.h" ¶ namespace vulkan {« @@ -90,12 +92,11 @@ bool InitDispatchTable( ¶ // WARNING: This file is generated. See ../README.md for instructions. ¶ +#include #include ¶ #include ¶ -#include -¶ // to catch mismatches between vulkan.h and this file #undef VK_NO_PROTOTYPES #include "api.h" @@ -217,9 +218,10 @@ namespace {« #ifndef LIBVULKAN_DRIVER_GEN_H #define LIBVULKAN_DRIVER_GEN_H ¶ -#include -#include #include +#include +¶ +#include ¶ namespace vulkan {« namespace driver {« @@ -271,12 +273,11 @@ bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, ¶ // WARNING: This file is generated. See ../README.md for instructions. ¶ +#include #include ¶ #include ¶ -#include -¶ #include "driver.h" ¶ namespace vulkan {« diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp index ec98b9fe04..b7bac0afa2 100644 --- a/vulkan/libvulkan/driver_gen.cpp +++ b/vulkan/libvulkan/driver_gen.cpp @@ -16,12 +16,11 @@ // WARNING: This file is generated. See ../README.md for instructions. +#include #include #include -#include - #include "driver.h" namespace vulkan { diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h index 14c3aba75a..37b2c6e930 100644 --- a/vulkan/libvulkan/driver_gen.h +++ b/vulkan/libvulkan/driver_gen.h @@ -21,6 +21,7 @@ #include #include + #include namespace vulkan { diff --git a/vulkan/nulldrv/null_driver.tmpl b/vulkan/nulldrv/null_driver.tmpl index ce155172e9..0f5301595c 100644 --- a/vulkan/nulldrv/null_driver.tmpl +++ b/vulkan/nulldrv/null_driver.tmpl @@ -97,9 +97,10 @@ VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitS ¶ // WARNING: This file is generated. See ../README.md for instructions. ¶ -#include "null_driver_gen.h" #include ¶ +#include "null_driver_gen.h" +¶ using namespace null_driver; ¶ namespace { diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp index 92b7468321..b8d7d2b643 100644 --- a/vulkan/nulldrv/null_driver_gen.cpp +++ b/vulkan/nulldrv/null_driver_gen.cpp @@ -17,6 +17,7 @@ // WARNING: This file is generated. See ../README.md for instructions. #include + #include "null_driver_gen.h" using namespace null_driver; -- GitLab From acec532d4c018cce542665b7a3f93d985437a5dd Mon Sep 17 00:00:00 2001 From: tangrobin Date: Thu, 21 Feb 2019 19:40:26 +0800 Subject: [PATCH 0013/1255] gui: add additional test for region sampling Add additional test that help verify the region sampling function. Bug: 119639245 Test: ./libgui_test --gtest_filter="RegionSamplingTest.*" Change-Id: Ie42b4cd5767b846f247781ab3b14a22ff9b7ad83 --- libs/gui/tests/RegionSampling_test.cpp | 66 ++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index d33ecfbdb9..c9de37d957 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -297,4 +297,70 @@ TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) { composer->removeRegionSamplingListener(grayListener); } +TEST_F(RegionSamplingTest, DISABLED_TestIfInvalidInputParameters) { + sp composer = ComposerService::getComposerService(); + sp listener = new Listener(); + const Rect sampleArea{100, 100, 200, 200}; + // Invalid input sampleArea + EXPECT_EQ(BAD_VALUE, + composer->addRegionSamplingListener(Rect::INVALID_RECT, mTopLayer->getHandle(), + listener)); + listener->reset(); + // Invalid input binder + EXPECT_EQ(NO_ERROR, composer->addRegionSamplingListener(sampleArea, NULL, listener)); + // Invalid input listener + EXPECT_EQ(BAD_VALUE, + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), NULL)); + EXPECT_EQ(BAD_VALUE, composer->removeRegionSamplingListener(NULL)); + // remove the listener + composer->removeRegionSamplingListener(listener); +} + +TEST_F(RegionSamplingTest, DISABLED_TestCallbackAfterRemoveListener) { + fill_render(rgba_green); + sp composer = ComposerService::getComposerService(); + sp listener = new Listener(); + const Rect sampleArea{100, 100, 200, 200}; + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + fill_render(rgba_green); + + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_green, error_margin); + + listener->reset(); + composer->removeRegionSamplingListener(listener); + fill_render(rgba_green); + EXPECT_FALSE(listener->wait_event(100ms)) + << "callback should stop after remove the region sampling listener"; +} + +TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromMovingLayer) { + sp composer = ComposerService::getComposerService(); + sp listener = new Listener(); + Rect sampleArea{100, 100, 200, 200}; + + // Test: listener in (100, 100). See layer before move, no layer after move. + fill_render(rgba_blue); + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_blue, error_margin); + listener->reset(); + SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply(); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_gray, error_margin); + composer->removeRegionSamplingListener(listener); + + // Test: listener offset to (600, 600). No layer before move, see layer after move. + fill_render(rgba_green); + sampleArea.offsetTo(600, 600); + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_gray, error_margin); + listener->reset(); + SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply(); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_green, error_margin); + composer->removeRegionSamplingListener(listener); +} + } // namespace android::test -- GitLab From a33b3a5c269a03f56574e7619fa1dc64059e12e3 Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Fri, 12 Apr 2019 15:39:16 -0700 Subject: [PATCH 0014/1255] Prepare for moving Vulkan headers In preparation for importing Vulkan headers from external/vulkan-headers, this reorganizes the Vulkan Soong modules a bit: * Separate the Vulkan API headers from the Vulkan HAL headers. The former will move, the latter won't. Also, many things need the API headers but very few should use the HAL headers. These probably should have always been separate modules, but now they have to be. * Add a llndk_headers module separate from the llndk_library module, so the header module can be in external/vulkan-headers but the library module can stay in frameworks/native. * Merge "vulkan_headers_ndk" into "vulkan_headers". A single module can serve both unbundled and platform clients, these never needed to be duplicated. Bug: 129696724 Test: make checkbuild Change-Id: I955c880298843db4a2f4c08d93f7c8edbb205ef8 --- vulkan/Android.bp | 36 +++++++++++++++++++++++------------- vulkan/libvulkan/Android.bp | 11 ++++++++++- vulkan/nulldrv/Android.bp | 5 ++++- vulkan/vkjson/Android.bp | 2 +- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/vulkan/Android.bp b/vulkan/Android.bp index b15bed99c5..ad4e300ffd 100644 --- a/vulkan/Android.bp +++ b/vulkan/Android.bp @@ -12,8 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +// This module defines which headers are included in the NDK sysroot during +// the NDK build process. ndk_headers { - name: "libvulkan_headers", + name: "ndk_vulkan_headers", from: "include", to: "", srcs: [ @@ -25,8 +27,28 @@ ndk_headers { license: "include/vulkan/NOTICE", } +// This module makes Vulkan headers available to other modules without +// having to link against libvulkan.so, e.g. for the Vulkan loader and +// drivers, or things that dlopen libvulkan.so. It's available to system +// modules, as part of the VNDK, and to unbundled modules. cc_library_headers { name: "vulkan_headers", + export_include_dirs: ["include"], + vendor_available: true, + sdk_version: "24", +} + +// This module makes Vulkan headers available to vendor code that is +// restricted to LLNDK dependencies. +llndk_headers { + name: "vulkan_headers_llndk", + export_include_dirs: ["include"], +} + +// This module makes the Vulkan libhardware HAL headers available, for +// the loader and for HAL/driver implementations. +cc_library_headers { + name: "hwvulkan_headers", vendor_available: true, header_libs: [ "libcutils_headers", @@ -39,18 +61,6 @@ cc_library_headers { export_include_dirs: ["include"], } -cc_library_headers { - name: "vulkan_headers_ndk", - export_include_dirs: ["include"], - sdk_version: "24", -} - -llndk_library { - name: "libvulkan", - symbol_file: "libvulkan/libvulkan.map.txt", - export_include_dirs: ["include"], -} - subdirs = [ "nulldrv", "libvulkan", diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp index 71a120a896..e1a1ebc102 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -20,6 +20,14 @@ ndk_library { unversioned_until: "current", } +llndk_library { + name: "libvulkan", + symbol_file: "libvulkan.map.txt", + export_llndk_headers: [ + "vulkan_headers_llndk", + ], +} + cc_library_shared { name: "libvulkan", clang: true, @@ -65,10 +73,11 @@ cc_library_shared { "swapchain.cpp", ], - export_header_lib_headers: ["vulkan_headers"], header_libs: [ + "hwvulkan_headers", "vulkan_headers", ], + export_header_lib_headers: ["vulkan_headers"], shared_libs: [ "android.hardware.configstore@1.0", "android.hardware.configstore-utils", diff --git a/vulkan/nulldrv/Android.bp b/vulkan/nulldrv/Android.bp index 7be9c66e4d..dedf419dc3 100644 --- a/vulkan/nulldrv/Android.bp +++ b/vulkan/nulldrv/Android.bp @@ -41,6 +41,9 @@ cc_library_shared { "null_driver_gen.cpp", ], - header_libs: ["vulkan_headers"], + header_libs: [ + "hwvulkan_headers", + "vulkan_headers", + ], shared_libs: ["liblog"], } diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp index 78d6694270..a626e4839d 100644 --- a/vulkan/vkjson/Android.bp +++ b/vulkan/vkjson/Android.bp @@ -45,7 +45,7 @@ cc_library_static { "libjsoncpp_ndk", ], header_libs: [ - "vulkan_headers_ndk", + "vulkan_headers", ], sdk_version: "24", stl: "libc++_static", -- GitLab From c5f7a3a6130860f07db0f48ac9096493a7219f2c Mon Sep 17 00:00:00 2001 From: Marius Renn Date: Fri, 26 Apr 2019 10:16:38 -0700 Subject: [PATCH 0015/1255] Adds new HardwareBuffer plane-locking functions to NDK This mirrors the API added to libandroid to libnativewindow. Test: Run cts-tradefed run commandAndExit cts -m CtsNativeHardwareTestCases Bug: 131319526 Change-Id: I8b97cdf8e7348e0c00f4ec62cbeb471ea4e00795 --- libs/nativewindow/libnativewindow.map.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 23a05f3dca..bad8b11540 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -8,6 +8,7 @@ LIBNATIVEWINDOW { AHardwareBuffer_isSupported; # introduced=29 AHardwareBuffer_lock; AHardwareBuffer_lockAndGetInfo; # introduced=29 + AHardwareBuffer_lockPlanes; # introduced=29 AHardwareBuffer_recvHandleFromUnixSocket; AHardwareBuffer_release; AHardwareBuffer_sendHandleToUnixSocket; -- GitLab From d45fdc3420e498cd1e300d92697f860bed62c475 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Tue, 30 Apr 2019 06:14:19 -0700 Subject: [PATCH 0016/1255] SurfaceComposerClient: Fix potential null de-reference in detachChildren We return from the function when we know the pointer is null to avoid dereferencing it. Test: TreeHugger Change-Id: I487b71ba185a48b505719a14b38b8a60283e10a7 --- libs/gui/SurfaceComposerClient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index a0ed940d71..01bfe2adef 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1051,6 +1051,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachCh layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eDetachChildren; -- GitLab From 0891c9b5b050e89a90585dd17ac4428e6ae56522 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 6 May 2019 15:05:13 -0700 Subject: [PATCH 0017/1255] binder: readCallingWorkSourceUid make const Bug: N/A Test: N/A Change-Id: I09ec79695efc05ca88884f7c43a6a7ca7353dfda --- libs/binder/Parcel.cpp | 2 +- libs/binder/include/binder/Parcel.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 5427ff8e4c..6d936147fd 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -628,7 +628,7 @@ bool Parcel::replaceCallingWorkSourceUid(uid_t uid) return err == NO_ERROR; } -uid_t Parcel::readCallingWorkSourceUid() +uid_t Parcel::readCallingWorkSourceUid() const { if (!mRequestHeaderPresent) { return IPCThreadState::kUnsetWorkSource; diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index e5219a5590..cfee364b97 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -399,7 +399,7 @@ public: bool replaceCallingWorkSourceUid(uid_t uid); // Returns the work source provided by the caller. This can only be trusted for trusted calling // uid. - uid_t readCallingWorkSourceUid(); + uid_t readCallingWorkSourceUid() const; void readRequestHeaders() const; private: -- GitLab From 5528022adf18120f758ae284b2df599b50569e6a Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Sun, 5 May 2019 09:54:59 -0700 Subject: [PATCH 0018/1255] Remove storage sandboxes related code. Bug: 131115422 Test: manual Test: atest --test-mapping packages/providers/MediaProvider Test: atest cts/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java Test: atest DownloadProviderTests Test: atest cts/tests/app/src/android/app/cts/DownloadManagerTest.java Test: atest cts/tests/app/DownloadManagerLegacyTest/src/android/app/cts/DownloadManagerLegacyTest.java Test: atest cts/tests/app/DownloadManagerApi28Test/src/android/app/cts/DownloadManagerApi28Test.java Change-Id: I93a0a624304b9f6f00aae600377a73b720900fba --- cmds/installd/InstalldNativeService.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index c730ab945c..59c19d174e 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -581,10 +581,6 @@ binder::Status InstalldNativeService::clearAppData(const std::unique_ptr Date: Tue, 7 May 2019 13:28:07 -0700 Subject: [PATCH 0019/1255] Mark miniDump() as pure virtual. Fixes a build error when building with -O0 due to missing vtable entry. Test: make NATIVE_COVERAGE=true COVERAGE_PATHS=frameworks/native/services/surfaceflinger Change-Id: Iaefb6921b4fe95a2c138444a0cfba2ecb739550f --- services/surfaceflinger/TimeStats/TimeStats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 4e040a31b1..2bcb5682b0 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -41,7 +41,7 @@ public: virtual void parseArgs(bool asProto, const Vector& args, std::string& result) = 0; virtual bool isEnabled() = 0; - virtual std::string miniDump(); + virtual std::string miniDump() = 0; virtual void incrementTotalFrames() = 0; virtual void incrementMissedFrames() = 0; -- GitLab From 4180aa424305e7fc9ffd66daddb50b3ec3ddaf01 Mon Sep 17 00:00:00 2001 From: Atif Niyaz Date: Fri, 10 May 2019 16:27:48 -0700 Subject: [PATCH 0020/1255] Remove mUserEpollWakeup from EventHub All devices supporting Oreo must have a linux kernel version 3.18 or above, meaning it isn't necessary to check if the kernel version is above 3.5. Bug: 118001226 Test: After compiling and creating a build and installing on device, there were no crashes. Change-Id: I74f04524199b9220d836c91f8e71e85fe75ba173 --- services/inputflinger/EventHub.cpp | 31 +----------------------------- services/inputflinger/EventHub.h | 2 -- 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp index ce5627271a..af023148cc 100644 --- a/services/inputflinger/EventHub.cpp +++ b/services/inputflinger/EventHub.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #define LOG_TAG "EventHub" @@ -94,14 +93,6 @@ static std::string sha1(const std::string& in) { return out; } -static void getLinuxRelease(int* major, int* minor) { - struct utsname info; - if (uname(&info) || sscanf(info.release, "%d.%d", major, minor) <= 0) { - *major = 0, *minor = 0; - ALOGE("Could not get linux version: %s", strerror(errno)); - } -} - /** * Return true if name matches "v4l-touch*" */ @@ -292,11 +283,6 @@ EventHub::EventHub(void) : result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", errno); - - int major, minor; - getLinuxRelease(&major, &minor); - // EPOLLWAKEUP was introduced in kernel 3.5 - mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5); } EventHub::~EventHub(void) { @@ -1487,28 +1473,13 @@ void EventHub::configureFd(Device* device) { } } - std::string wakeMechanism = "EPOLLWAKEUP"; - if (!mUsingEpollWakeup) { -#ifndef EVIOCSSUSPENDBLOCK - // uapi headers don't include EVIOCSSUSPENDBLOCK, and future kernels - // will use an epoll flag instead, so as long as we want to support - // this feature, we need to be prepared to define the ioctl ourselves. -#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int) -#endif - if (ioctl(device->fd, EVIOCSSUSPENDBLOCK, 1)) { - wakeMechanism = ""; - } else { - wakeMechanism = "EVIOCSSUSPENDBLOCK"; - } - } // Tell the kernel that we want to use the monotonic clock for reporting timestamps // associated with input events. This is important because the input system // uses the timestamps extensively and assumes they were recorded using the monotonic // clock. int clockId = CLOCK_MONOTONIC; bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId); - ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.c_str(), - toString(usingClockIoctl)); + ALOGI("usingClockIoctl=%s", toString(usingClockIoctl)); } void EventHub::openVideoDeviceLocked(const std::string& devicePath) { diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h index 63a20ef3e2..eb4e8f2e50 100644 --- a/services/inputflinger/EventHub.h +++ b/services/inputflinger/EventHub.h @@ -479,8 +479,6 @@ private: size_t mPendingEventCount; size_t mPendingEventIndex; bool mPendingINotify; - - bool mUsingEpollWakeup; }; }; // namespace android -- GitLab From 8f054a6a79f37b36a9708e566c0da6cb263daa92 Mon Sep 17 00:00:00 2001 From: Tao Wu Date: Tue, 14 May 2019 09:16:07 -0700 Subject: [PATCH 0021/1255] Add --Bsymbolic-functions link option to EGL stub. This make sure we always get the right value of function pointers of our EGL entry points. Test: compiled & booted Bug: None Change-Id: I8f9e3171e7e77bd32049ebcc02faaa491b15e565 --- opengl/libs/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index c0bace8486..32f3e66db4 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -162,7 +162,7 @@ cc_library_shared { "libEGL_getProcAddress", "libEGL_blobCache", ], - ldflags: ["-Wl,--exclude-libs=ALL"], + ldflags: ["-Wl,--exclude-libs=ALL,--Bsymbolic-functions"], export_include_dirs: ["EGL/include"], } -- GitLab From f5e6c7e5fade7dd2b416c896b39fd1d4a23e8713 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 17 May 2019 13:14:06 -0700 Subject: [PATCH 0022/1255] libbinder: readCString: no ubsan sub-overflow Bug: 131859347 Test: fuzzer Change-Id: I95a0f59684a172925f1eab97ff21e5d14bc79cc8 --- libs/binder/Parcel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 0c57335c89..580573e279 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -2074,8 +2074,8 @@ status_t Parcel::readUtf8FromUtf16(std::unique_ptr* str) const { const char* Parcel::readCString() const { - const size_t avail = mDataSize-mDataPos; - if (avail > 0) { + if (mDataPos < mDataSize) { + const size_t avail = mDataSize-mDataPos; const char* str = reinterpret_cast(mData+mDataPos); // is the string's trailing NUL within the parcel's valid bounds? const char* eos = reinterpret_cast(memchr(str, 0, avail)); -- GitLab From 1eafe08a93cead5628f1f827be99528a51f4ca70 Mon Sep 17 00:00:00 2001 From: Tianyu Jiang Date: Tue, 21 May 2019 19:44:48 -0700 Subject: [PATCH 0023/1255] Reduce debug level log from libbufferhub Logs that indicates possible racing between consumers and producers of a buffer are removed because they are expected to race each other. Log that indicates possible racing in bufferhubd is moved from info level to verbose level. Test: vega runs without libbufferhub log spam Bug: 129544259 Change-Id: I9307602797ff9c1bbc774264682a83bf4ddd0240 (cherry picked from commit b9d077f9be584114c39ac8417452cd20817c0236) --- libs/vr/libbufferhub/consumer_buffer.cpp | 12 ------------ libs/vr/libbufferhub/producer_buffer.cpp | 16 ---------------- services/vr/bufferhubd/producer_channel.cpp | 2 +- 3 files changed, 1 insertion(+), 29 deletions(-) diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp index 115e8666e5..7823e36d3d 100644 --- a/libs/vr/libbufferhub/consumer_buffer.cpp +++ b/libs/vr/libbufferhub/consumer_buffer.cpp @@ -52,12 +52,6 @@ int ConsumerBuffer::LocalAcquire(DvrNativeBufferMetadata* out_meta, while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGD( - "%s Failed to acquire the buffer. Current buffer state was changed to " - "%" PRIx32 - " when trying to acquire the buffer and modify the buffer state to " - "%" PRIx32 ". About to try again if the buffer is still posted.", - __FUNCTION__, current_buffer_state, updated_buffer_state); if (!BufferHubDefs::isClientPosted(current_buffer_state, client_state_mask())) { ALOGE( @@ -152,12 +146,6 @@ int ConsumerBuffer::LocalRelease(const DvrNativeBufferMetadata* meta, while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGD( - "%s: Failed to release the buffer. Current buffer state was changed to " - "%" PRIx32 - " when trying to release the buffer and modify the buffer state to " - "%" PRIx32 ". About to try again.", - __FUNCTION__, current_buffer_state, updated_buffer_state); // The failure of compare_exchange_weak updates current_buffer_state. updated_buffer_state = current_buffer_state & (~client_state_mask()); } diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp index 3d88ba5dbe..aa9d07282b 100644 --- a/libs/vr/libbufferhub/producer_buffer.cpp +++ b/libs/vr/libbufferhub/producer_buffer.cpp @@ -96,13 +96,6 @@ int ProducerBuffer::LocalPost(const DvrNativeBufferMetadata* meta, while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGD( - "%s: Failed to post the buffer. Current buffer state was changed to " - "%" PRIx32 - " when trying to post the buffer and modify the buffer state to " - "%" PRIx32 - ". About to try again if the buffer is still gained by this client.", - __FUNCTION__, current_buffer_state, updated_buffer_state); if (!BufferHubDefs::isClientGained(current_buffer_state, client_state_mask())) { ALOGE( @@ -186,15 +179,6 @@ int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta, while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGD( - "%s: Failed to gain the buffer. Current buffer state was changed to " - "%" PRIx32 - " when trying to gain the buffer and modify the buffer state to " - "%" PRIx32 - ". About to try again if the buffer is still not read by other " - "clients.", - __FUNCTION__, current_buffer_state, updated_buffer_state); - if (BufferHubDefs::isAnyClientAcquired(current_buffer_state) || BufferHubDefs::isAnyClientGained(current_buffer_state) || (BufferHubDefs::isAnyClientPosted( diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp index a7fd912294..b71964ba00 100644 --- a/services/vr/bufferhubd/producer_channel.cpp +++ b/services/vr/bufferhubd/producer_channel.cpp @@ -350,7 +350,7 @@ Status ProducerChannel::CreateConsumer( while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGI( + ALOGV( "%s: Failed to post to the new consumer. " "Current buffer state was changed to %" PRIx32 " when trying to acquire the buffer and modify the buffer state to " -- GitLab From 31c8de613834204e169c2af8933dd9a8ff43099c Mon Sep 17 00:00:00 2001 From: Jiwen 'Steve' Cai Date: Thu, 23 May 2019 18:27:14 -0700 Subject: [PATCH 0024/1255] Add lshal support for VrHwc Bug: 133452166 Bug: 133272775 Test: adb shell lshal debug android.hardware.graphics.composer@2.1::IComposer/vr Change-Id: I1b108857cd6cbabd53793095119275682b9d6b37 --- services/vr/hardware_composer/impl/vr_hwc.cpp | 20 +++++++++++++++++++ services/vr/hardware_composer/impl/vr_hwc.h | 3 +++ 2 files changed, 23 insertions(+) diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp index fb7932d804..7323277248 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.cpp +++ b/services/vr/hardware_composer/impl/vr_hwc.cpp @@ -994,6 +994,26 @@ void VrHwc::UpdateVsyncCallbackEnabledLocked() { vsync_callback_->SetEventCallback(send_vsync ? event_callback_ : nullptr); } +Return VrHwc::debug(const hidl_handle& fd, + const hidl_vec& args) { + std::string result; + + { + std::lock_guard guard(mutex_); + for (const auto& pair : displays_) { + result += StringPrintf("Display id: %d\n", static_cast(pair.first)); + pair.second->dumpDebugInfo(&result); + } + result += "\n"; + } + + FILE* out = fdopen(dup(fd->data[0]), "w"); + fprintf(out, "%s", result.c_str()); + fclose(out); + + return Void(); +} + void HwcLayer::dumpDebugInfo(std::string* result) const { if (!result) { return; diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h index e8c0212039..15358c57bb 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.h +++ b/services/vr/hardware_composer/impl/vr_hwc.h @@ -295,6 +295,9 @@ class VrHwc : public IComposer, public ComposerHal, public ComposerView { void RegisterObserver(Observer* observer) override; void UnregisterObserver(Observer* observer) override; + Return debug(const hidl_handle& fd, + const hidl_vec& args) override; + private: class VsyncCallback : public BnVsyncCallback { public: -- GitLab From dbf960d37ebae3b5c92f42c82a40086ff4c33c98 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 20 May 2019 15:28:13 -0700 Subject: [PATCH 0025/1255] libbinder: Status: check dataPosition sets. Bug: 132650049 Test: fuzzer Change-Id: Id230eae4316a444bc82b416b2049d5a5f589f89a --- libs/binder/Status.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp index 8b33a56484..0ad99cee3f 100644 --- a/libs/binder/Status.cpp +++ b/libs/binder/Status.cpp @@ -102,13 +102,23 @@ status_t Status::readFromParcel(const Parcel& parcel) { // Skip over fat response headers. Not used (or propagated) in native code. if (mException == EX_HAS_REPLY_HEADER) { // Note that the header size includes the 4 byte size field. - const int32_t header_start = parcel.dataPosition(); + const size_t header_start = parcel.dataPosition(); + // Get available size before reading more + const size_t header_avail = parcel.dataAvail(); + int32_t header_size; status = parcel.readInt32(&header_size); if (status != OK) { setFromStatusT(status); return status; } + + if (header_size < 0 || static_cast(header_size) > header_avail) { + android_errorWriteLog(0x534e4554, "132650049"); + setFromStatusT(UNKNOWN_ERROR); + return UNKNOWN_ERROR; + } + parcel.setDataPosition(header_start + header_size); // And fat response headers are currently only used when there are no // exceptions, so act like there was no error. @@ -135,19 +145,36 @@ status_t Status::readFromParcel(const Parcel& parcel) { setFromStatusT(status); return status; } + if (remote_stack_trace_header_size < 0 || + static_cast(remote_stack_trace_header_size) > parcel.dataAvail()) { + + android_errorWriteLog(0x534e4554, "132650049"); + setFromStatusT(UNKNOWN_ERROR); + return UNKNOWN_ERROR; + } parcel.setDataPosition(parcel.dataPosition() + remote_stack_trace_header_size); if (mException == EX_SERVICE_SPECIFIC) { status = parcel.readInt32(&mErrorCode); } else if (mException == EX_PARCELABLE) { // Skip over the blob of Parcelable data - const int32_t header_start = parcel.dataPosition(); + const size_t header_start = parcel.dataPosition(); + // Get available size before reading more + const size_t header_avail = parcel.dataAvail(); + int32_t header_size; status = parcel.readInt32(&header_size); if (status != OK) { setFromStatusT(status); return status; } + + if (header_size < 0 || static_cast(header_size) > header_avail) { + android_errorWriteLog(0x534e4554, "132650049"); + setFromStatusT(UNKNOWN_ERROR); + return UNKNOWN_ERROR; + } + parcel.setDataPosition(header_start + header_size); } if (status != OK) { -- GitLab From 0b8f9add1c6bfd892f28a41e8a0ed9f33507820c Mon Sep 17 00:00:00 2001 From: Jiwen 'Steve' Cai Date: Wed, 29 May 2019 10:02:20 -0700 Subject: [PATCH 0026/1255] Add uhid permission to virtual_touchpad Bug: 133012518 Test: Build system and check vr-virtual-touchpad created Change-Id: Ie1d5bf99554bbd561dfce872ddc789191d61a91c --- services/vr/virtual_touchpad/virtual_touchpad.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/vr/virtual_touchpad/virtual_touchpad.rc b/services/vr/virtual_touchpad/virtual_touchpad.rc index 99315ef341..0de0f9eec7 100644 --- a/services/vr/virtual_touchpad/virtual_touchpad.rc +++ b/services/vr/virtual_touchpad/virtual_touchpad.rc @@ -1,5 +1,5 @@ service virtual_touchpad /system/bin/virtual_touchpad class core user system - group system input + group system input uhid writepid /dev/cpuset/system/tasks -- GitLab From 67e3d9b32a6bb343bf6f4acbe0cb159ba69a7382 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Fri, 22 Mar 2019 23:09:28 +0000 Subject: [PATCH 0027/1255] Revert "Revert "SF: Test coverage for OutputLayer::updateGeometryState"" This reverts commit 546a245730e0283115713e72748370ceb2d8634b. Reason for revert: Relanding the test coverage, this time without the breaking implementation change Bug: 121291683 Change-Id: I34f8f7d58b0b679b7fd6e9ed4bb48ea3d53b530b Test: atest libsurfaceflinger_unittest libcompositionengine_test Test: Manual camera rotation test --- .../tests/FloatRectMatcher.h | 48 ++++ .../tests/OutputLayerTest.cpp | 264 +++++++++++++++++- 2 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h diff --git a/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h b/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h new file mode 100644 index 0000000000..6741cc9b7a --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h @@ -0,0 +1,48 @@ +/* + * 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 + +#include +#include + +namespace { + +using android::base::StringAppendF; +using FloatRect = android::FloatRect; + +void dumpFloatRect(const FloatRect& rect, std::string& result, const char* name) { + StringAppendF(&result, "%s (%f %f %f %f) ", name, rect.left, rect.top, rect.right, rect.bottom); +} + +// Checks for a region match +MATCHER_P(FloatRectEq, expected, "") { + std::string buf; + buf.append("FloatRects are not equal\n"); + dumpFloatRect(expected, buf, "expected rect"); + dumpFloatRect(arg, buf, "actual rect"); + *result_listener << buf; + + const float TOLERANCE = 1e-3f; + return (std::fabs(expected.left - arg.left) < TOLERANCE) && + (std::fabs(expected.top - arg.top) < TOLERANCE) && + (std::fabs(expected.right - arg.right) < TOLERANCE) && + (std::fabs(expected.bottom - arg.bottom) < TOLERANCE); +} + +} // namespace diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 2060c5aaff..ae906cd525 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -21,6 +21,7 @@ #include #include +#include "FloatRectMatcher.h" #include "MockHWC2.h" #include "MockHWComposer.h" #include "RectMatcher.h" @@ -105,6 +106,114 @@ TEST_F(OutputLayerTest, initializingOutputLayerWithHwcDisplayCreatesHwcLayer) { mOutputLayer.editState().hwc.reset(); } +/* + * OutputLayer::calculateOutputSourceCrop() + */ + +struct OutputLayerSourceCropTest : public OutputLayerTest { + OutputLayerSourceCropTest() { + // Set reasonable default values for a simple case. Each test will + // set one specific value to something different. + mLayerState.frontEnd.geomUsesSourceCrop = true; + mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 1920, 1080}; + mLayerState.frontEnd.geomActiveTransparentRegion = Region{}; + mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f}; + mLayerState.frontEnd.geomLayerTransform = ui::Transform{TR_IDENT}; + mLayerState.frontEnd.geomBufferSize = Rect{0, 0, 1920, 1080}; + mLayerState.frontEnd.geomBufferTransform = TR_IDENT; + + mOutputState.viewport = Rect{0, 0, 1920, 1080}; + } + + FloatRect calculateOutputSourceCrop() { + mLayerState.frontEnd.geomInverseLayerTransform = + mLayerState.frontEnd.geomLayerTransform.inverse(); + + return mOutputLayer.calculateOutputSourceCrop(); + } +}; + +TEST_F(OutputLayerSourceCropTest, computesEmptyIfSourceCropNotUsed) { + mLayerState.frontEnd.geomUsesSourceCrop = false; + + const FloatRect expected{}; + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); +} + +TEST_F(OutputLayerSourceCropTest, correctForSimpleDefaultCase) { + const FloatRect expected{0.f, 0.f, 1920.f, 1080.f}; + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); +} + +TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewport) { + mLayerState.frontEnd.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f}; + + const FloatRect expected{0.f, 0.f, 1920.f, 1080.f}; + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); +} + +TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewportRotated) { + mLayerState.frontEnd.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f}; + mLayerState.frontEnd.geomLayerTransform.set(HAL_TRANSFORM_ROT_90, 1920, 1080); + + const FloatRect expected{0.f, 0.f, 1080.f, 1080.f}; + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); +} + +TEST_F(OutputLayerSourceCropTest, calculateOutputSourceCropWorksWithATransformedBuffer) { + struct Entry { + uint32_t bufferInvDisplay; + uint32_t buffer; + uint32_t display; + FloatRect expected; + }; + // Not an exhaustive list of cases, but hopefully enough. + const std::array testData = { + // clang-format off + // inv buffer display expected + /* 0 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 1 */ Entry{false, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 2 */ Entry{false, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 3 */ Entry{false, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + + /* 4 */ Entry{true, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 5 */ Entry{true, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 6 */ Entry{true, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 7 */ Entry{true, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + + /* 8 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 9 */ Entry{false, TR_ROT_90, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 10 */ Entry{false, TR_ROT_180, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 11 */ Entry{false, TR_ROT_270, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + + // clang-format on + }; + + for (size_t i = 0; i < testData.size(); i++) { + const auto& entry = testData[i]; + + mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = entry.bufferInvDisplay; + mLayerState.frontEnd.geomBufferTransform = entry.buffer; + mOutputState.orientation = entry.display; + + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(entry.expected)) << "entry " << i; + } +} + +TEST_F(OutputLayerSourceCropTest, geomContentCropAffectsCrop) { + mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 960, 540}; + + const FloatRect expected{0.f, 0.f, 960.f, 540.f}; + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); +} + +TEST_F(OutputLayerSourceCropTest, viewportAffectsCrop) { + mOutputState.viewport = Rect{0, 0, 960, 540}; + + const FloatRect expected{0.f, 0.f, 960.f, 540.f}; + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); +} + /* * OutputLayer::calculateOutputDisplayFrame() */ @@ -163,7 +272,7 @@ TEST_F(OutputLayerDisplayFrameTest, emptyGeomCropIsNotUsedToComputeFrame) { EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected)); } -TEST_F(OutputLayerDisplayFrameTest, geomLayerSnapToBoundsAffectsFrame) { +TEST_F(OutputLayerDisplayFrameTest, geomLayerBoundsAffectsFrame) { mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 960.f, 540.f}; const Rect expected{0, 0, 960, 540}; EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected)); @@ -242,6 +351,159 @@ TEST_F(OutputLayerTest, calculateOutputRelativeBufferTransformTestsNeeded) { } } +TEST_F(OutputLayerTest, + calculateOutputRelativeBufferTransformTestWithOfBufferUsesDisplayInverseTransform) { + mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = true; + + struct Entry { + uint32_t layer; + uint32_t buffer; + uint32_t display; + uint32_t expected; + }; + // Not an exhaustive list of cases, but hopefully enough. + const std::array testData = { + // clang-format off + // layer buffer display expected + /* 0 */ Entry{TR_IDENT, TR_IDENT, TR_IDENT, TR_IDENT}, + /* 1 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_90, TR_IDENT}, + /* 2 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_180, TR_IDENT}, + /* 3 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_270, TR_IDENT}, + + /* 4 */ Entry{TR_IDENT, TR_FLP_H, TR_IDENT, TR_FLP_H}, + /* 5 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_90, TR_FLP_H}, + /* 6 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_180, TR_FLP_H}, + /* 7 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_270, TR_FLP_H}, + + /* 8 */ Entry{TR_IDENT, TR_FLP_V, TR_IDENT, TR_FLP_V}, + /* 9 */ Entry{TR_IDENT, TR_ROT_90, TR_ROT_90, TR_ROT_90}, + /* 10 */ Entry{TR_IDENT, TR_ROT_180, TR_ROT_180, TR_ROT_180}, + /* 11 */ Entry{TR_IDENT, TR_ROT_270, TR_ROT_270, TR_ROT_270}, + + /* 12 */ Entry{TR_ROT_90, TR_IDENT, TR_IDENT, TR_IDENT}, + /* 13 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_90, TR_FLP_H}, + /* 14 */ Entry{TR_ROT_90, TR_IDENT, TR_ROT_180, TR_IDENT}, + /* 15 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_270, TR_FLP_H}, + + /* 16 */ Entry{TR_ROT_180, TR_FLP_H, TR_IDENT, TR_FLP_H}, + /* 17 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_90, TR_IDENT}, + /* 18 */ Entry{TR_ROT_180, TR_FLP_H, TR_ROT_180, TR_FLP_H}, + /* 19 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_270, TR_IDENT}, + + /* 20 */ Entry{TR_ROT_270, TR_IDENT, TR_IDENT, TR_IDENT}, + /* 21 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_90, TR_FLP_H}, + /* 22 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_180, TR_FLP_H}, + /* 23 */ Entry{TR_ROT_270, TR_IDENT, TR_ROT_270, TR_IDENT}, + // clang-format on + }; + + for (size_t i = 0; i < testData.size(); i++) { + const auto& entry = testData[i]; + + mLayerState.frontEnd.geomLayerTransform = ui::Transform{entry.layer}; + mLayerState.frontEnd.geomBufferTransform = entry.buffer; + mOutputState.orientation = entry.display; + + auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(); + EXPECT_EQ(entry.expected, actual) << "entry " << i; + } +} + +/* + * OutputLayer::updateCompositionState() + */ + +struct OutputLayerPartialMockForUpdateCompositionState : public impl::OutputLayer { + OutputLayerPartialMockForUpdateCompositionState(const compositionengine::Output& output, + std::shared_ptr layer, + sp layerFE) + : impl::OutputLayer(output, layer, layerFE) {} + // Mock everything called by updateCompositionState to simplify testing it. + MOCK_CONST_METHOD0(calculateOutputSourceCrop, FloatRect()); + MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect()); + MOCK_CONST_METHOD0(calculateOutputRelativeBufferTransform, uint32_t()); +}; + +struct OutputLayerUpdateCompositionStateTest : public OutputLayerTest { +public: + OutputLayerUpdateCompositionStateTest() { + EXPECT_CALL(*mLayer, getState()).WillRepeatedly(ReturnRef(mLayerState)); + EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState)); + } + + ~OutputLayerUpdateCompositionStateTest() = default; + + void setupGeometryChildCallValues() { + EXPECT_CALL(mOutputLayer, calculateOutputSourceCrop()).WillOnce(Return(kSourceCrop)); + EXPECT_CALL(mOutputLayer, calculateOutputDisplayFrame()).WillOnce(Return(kDisplayFrame)); + EXPECT_CALL(mOutputLayer, calculateOutputRelativeBufferTransform()) + .WillOnce(Return(mBufferTransform)); + } + + void validateComputedGeometryState() { + const auto& state = mOutputLayer.getState(); + EXPECT_EQ(kSourceCrop, state.sourceCrop); + EXPECT_EQ(kDisplayFrame, state.displayFrame); + EXPECT_EQ(static_cast(mBufferTransform), state.bufferTransform); + } + + const FloatRect kSourceCrop{1.f, 2.f, 3.f, 4.f}; + const Rect kDisplayFrame{11, 12, 13, 14}; + uint32_t mBufferTransform{21}; + + using OutputLayer = OutputLayerPartialMockForUpdateCompositionState; + StrictMock mOutputLayer{mOutput, mLayer, mLayerFE}; +}; + +TEST_F(OutputLayerUpdateCompositionStateTest, setsStateNormally) { + mLayerState.frontEnd.isSecure = true; + mOutputState.isSecure = true; + + setupGeometryChildCallValues(); + + mOutputLayer.updateCompositionState(true); + + validateComputedGeometryState(); + + EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition); +} + +TEST_F(OutputLayerUpdateCompositionStateTest, + alsoSetsForceCompositionIfSecureLayerOnNonsecureOutput) { + mLayerState.frontEnd.isSecure = true; + mOutputState.isSecure = false; + + setupGeometryChildCallValues(); + + mOutputLayer.updateCompositionState(true); + + validateComputedGeometryState(); + + EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition); +} + +TEST_F(OutputLayerUpdateCompositionStateTest, + alsoSetsForceCompositionIfUnsupportedBufferTransform) { + mLayerState.frontEnd.isSecure = true; + mOutputState.isSecure = true; + + mBufferTransform = ui::Transform::ROT_INVALID; + + setupGeometryChildCallValues(); + + mOutputLayer.updateCompositionState(true); + + validateComputedGeometryState(); + + EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition); +} + +TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) { + mOutputLayer.updateCompositionState(false); + + EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition); +} + /* * OutputLayer::writeStateToHWC() */ -- GitLab From 70a2196e7faf11e386962e45419fed87770029ad Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Fri, 31 May 2019 17:26:52 -0700 Subject: [PATCH 0028/1255] Vulkan: clean up the swapchain implementation Bits included in this change: 1. Refactor transform supports 2. Clean up error returns 3. Clean up redundant TODOs Bug: 134185757 Test: CtsDeqpTestCases and CtsGraphicsTestCases Change-Id: I113839bc294d08e0d5f3e1b6f70539f674605dcf --- vulkan/libvulkan/swapchain.cpp | 149 +++++++++++++-------------------- 1 file changed, 56 insertions(+), 93 deletions(-) diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index a8949d36f4..340f48fc6b 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -34,10 +34,6 @@ using android::hardware::graphics::common::V1_0::BufferUsage; -// TODO(jessehall): Currently we don't have a good error code for when a native -// window operation fails. Just returning INITIALIZATION_FAILED for now. Later -// versions (post SDK 0.9) of the API/extension have a better error code. -// When updating to that version, audit all error returns. namespace vulkan { namespace driver { @@ -48,29 +44,12 @@ const VkSurfaceTransformFlagsKHR kSupportedTransforms = VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR | - // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform. - // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR | - // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR | - // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR | - // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR | VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; -int TranslateVulkanToNativeTransform(VkSurfaceTransformFlagBitsKHR transform) { - switch (transform) { - // TODO: See TODO in TranslateNativeToVulkanTransform - case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: - return NATIVE_WINDOW_TRANSFORM_ROT_90; - case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: - return NATIVE_WINDOW_TRANSFORM_ROT_180; - case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: - return NATIVE_WINDOW_TRANSFORM_ROT_270; - case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: - case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR: - default: - return 0; - } -} - VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) { // Native and Vulkan transforms are isomorphic, but are represented // differently. Vulkan transforms are built up of an optional horizontal @@ -78,27 +57,22 @@ VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) { // transforms are built up from a horizontal flip, vertical flip, and // 90-degree rotation, all optional but always in that order. - // TODO(jessehall): For now, only support pure rotations, not - // flip or flip-and-rotate, until I have more time to test them and build - // sample code. As far as I know we never actually use anything besides - // pure rotations anyway. - switch (native) { - case 0: // 0x0 + case 0: return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - // case NATIVE_WINDOW_TRANSFORM_FLIP_H: // 0x1 - // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR; - // case NATIVE_WINDOW_TRANSFORM_FLIP_V: // 0x2 - // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR; - case NATIVE_WINDOW_TRANSFORM_ROT_180: // FLIP_H | FLIP_V + case NATIVE_WINDOW_TRANSFORM_FLIP_H: + return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR; + case NATIVE_WINDOW_TRANSFORM_FLIP_V: + return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR; + case NATIVE_WINDOW_TRANSFORM_ROT_180: return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR; - case NATIVE_WINDOW_TRANSFORM_ROT_90: // 0x4 + case NATIVE_WINDOW_TRANSFORM_ROT_90: return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR; - // case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90: - // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR; - // case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90: - // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR; - case NATIVE_WINDOW_TRANSFORM_ROT_270: // FLIP_H | FLIP_V | ROT_90 + case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90: + return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR; + case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90: + return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR; + case NATIVE_WINDOW_TRANSFORM_ROT_270: return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; case NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY: default: @@ -106,6 +80,31 @@ VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) { } } +int TranslateVulkanToNativeTransform(VkSurfaceTransformFlagBitsKHR transform) { + switch (transform) { + case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_ROT_90; + case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_ROT_180; + case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_ROT_270; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_H; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_H | + NATIVE_WINDOW_TRANSFORM_ROT_90; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_V; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_V | + NATIVE_WINDOW_TRANSFORM_ROT_90; + case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: + case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR: + default: + return 0; + } +} + int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) { switch (transform) { case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: @@ -114,17 +113,16 @@ int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) { return NATIVE_WINDOW_TRANSFORM_ROT_180; case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: return NATIVE_WINDOW_TRANSFORM_ROT_90; - // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform. - // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR: - // return NATIVE_WINDOW_TRANSFORM_FLIP_H; - // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR: - // return NATIVE_WINDOW_TRANSFORM_FLIP_H | - // NATIVE_WINDOW_TRANSFORM_ROT_90; - // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR: - // return NATIVE_WINDOW_TRANSFORM_FLIP_V; - // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR: - // return NATIVE_WINDOW_TRANSFORM_FLIP_V | - // NATIVE_WINDOW_TRANSFORM_ROT_90; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_H; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_H | + NATIVE_WINDOW_TRANSFORM_ROT_90; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_V; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_V | + NATIVE_WINDOW_TRANSFORM_ROT_90; case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR: default: @@ -201,8 +199,6 @@ class TimingInfo { { NATIVE_WINDOW_TIMESTAMP_PENDING }; }; -// ---------------------------------------------------------------------------- - struct Surface { android::sp window; VkSwapchainKHR swapchain_handle; @@ -539,15 +535,12 @@ VkResult CreateAndroidSurfaceKHR( strerror(-err), err); surface->~Surface(); allocator->pfnFree(allocator->pUserData, surface); - return VK_ERROR_INITIALIZATION_FAILED; + return VK_ERROR_SURFACE_LOST_KHR; } - // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN. err = native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err), err); surface->~Surface(); @@ -656,7 +649,6 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( return VK_ERROR_SURFACE_LOST_KHR; } - // TODO(jessehall): Figure out what the min/max values should be. int max_buffer_count; err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &max_buffer_count); if (err != 0) { @@ -670,8 +662,7 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( capabilities->currentExtent = VkExtent2D{static_cast(width), static_cast(height)}; - // TODO(jessehall): Figure out what the max extent should be. Maximum - // texture dimension maybe? + // TODO(http://b/134182502): Figure out what the max extent should be. capabilities->minImageExtent = VkExtent2D{1, 1}; capabilities->maxImageExtent = VkExtent2D{4096, 4096}; @@ -685,11 +676,6 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( // associated with the bufferqueue. It can't be changed from here. capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; - // TODO(jessehall): I think these are right, but haven't thought hard about - // it. Do we need to query the driver for support of any of these? - // Currently not included: - // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not - // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not capabilities->supportedUsageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | @@ -729,8 +715,7 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, int err = native_window_get_wide_color_support(surface.window.get(), &wide_color_support); if (err) { - // Not allowed to return a more sensible error code, so do this - return VK_ERROR_OUT_OF_HOST_MEMORY; + return VK_ERROR_SURFACE_LOST_KHR; } ALOGV("wide_color_support is: %d", wide_color_support); wide_color_support = @@ -1052,6 +1037,8 @@ VkResult CreateSwapchainKHR(VkDevice device, // non-FREE state at any given time. Disconnecting and re-connecting // orphans the previous buffers, getting us back to the state where we can // dequeue all buffers. + // + // TODO(http://b/134186185) recycle swapchain images more efficiently err = native_window_api_disconnect(surface.window.get(), NATIVE_WINDOW_API_EGL); ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", @@ -1072,8 +1059,6 @@ VkResult CreateSwapchainKHR(VkDevice device, create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1; err = surface.window->setSwapInterval(surface.window.get(), swap_interval); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1100,8 +1085,6 @@ VkResult CreateSwapchainKHR(VkDevice device, err = native_window_set_buffers_format(surface.window.get(), native_pixel_format); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)", native_pixel_format, strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1109,8 +1092,6 @@ VkResult CreateSwapchainKHR(VkDevice device, err = native_window_set_buffers_data_space(surface.window.get(), native_dataspace); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)", native_dataspace, strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1120,8 +1101,6 @@ VkResult CreateSwapchainKHR(VkDevice device, surface.window.get(), static_cast(create_info->imageExtent.width), static_cast(create_info->imageExtent.height)); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)", create_info->imageExtent.width, create_info->imageExtent.height, strerror(-err), err); @@ -1140,8 +1119,6 @@ VkResult CreateSwapchainKHR(VkDevice device, surface.window.get(), InvertTransformToNative(create_info->preTransform)); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", InvertTransformToNative(create_info->preTransform), strerror(-err), err); @@ -1151,8 +1128,6 @@ VkResult CreateSwapchainKHR(VkDevice device, err = native_window_set_scaling_mode( surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1182,8 +1157,6 @@ VkResult CreateSwapchainKHR(VkDevice device, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value); if (err != 0 || query_value < 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value); return VK_ERROR_SURFACE_LOST_KHR; @@ -1201,8 +1174,6 @@ VkResult CreateSwapchainKHR(VkDevice device, // can't actually use!). err = native_window_set_buffer_count(surface.window.get(), std::max(2u, num_images)); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images, strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1242,8 +1213,6 @@ VkResult CreateSwapchainKHR(VkDevice device, } err = native_window_set_usage(surface.window.get(), native_usage); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } @@ -1301,8 +1270,6 @@ VkResult CreateSwapchainKHR(VkDevice device, err = surface.window->dequeueBuffer(surface.window.get(), &buffer, &img.dequeue_fence); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate - // possible errors and translate them to valid Vulkan result codes? ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); result = VK_ERROR_SURFACE_LOST_KHR; break; @@ -1457,8 +1424,6 @@ VkResult AcquireNextImageKHR(VkDevice device, int fence_fd; err = window->dequeueBuffer(window, &buffer, &fence_fd); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } @@ -1513,8 +1478,6 @@ VkResult AcquireNextImage2KHR(VkDevice device, uint32_t* pImageIndex) { ATRACE_CALL(); - // TODO: this should actually be the other way around and this function - // should handle any additional structures that get passed in return AcquireNextImageKHR(device, pAcquireInfo->swapchain, pAcquireInfo->timeout, pAcquireInfo->semaphore, pAcquireInfo->fence, pImageIndex); -- GitLab From 533cea9f7b05fa38cea691225578c716855d7cc1 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 3 Jun 2019 18:43:24 -0700 Subject: [PATCH 0029/1255] Vulkan: refactor and unify the swapchain destroy Bug: 134185757 Test: CtsDeqpTestCases and CtsGraphicsTestCases Change-Id: Ic8a4baf7e219cc8e1fb3838d4e4b710b242efa9c --- vulkan/libvulkan/swapchain.cpp | 77 +++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 340f48fc6b..114b4c935e 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -281,6 +281,8 @@ void ReleaseSwapchainImage(VkDevice device, ANativeWindow* window, int release_fence, Swapchain::Image& image) { + ATRACE_CALL(); + ALOG_ASSERT(release_fence == -1 || image.dequeued, "ReleaseSwapchainImage: can't provide a release fence for " "non-dequeued images"); @@ -319,7 +321,9 @@ void ReleaseSwapchainImage(VkDevice device, } if (image.image) { + ATRACE_BEGIN("DestroyImage"); GetData(device).driver.DestroyImage(device, image.image, nullptr); + ATRACE_END(); image.image = VK_NULL_HANDLE; } @@ -963,6 +967,40 @@ VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice, return VK_SUCCESS; } +static void DestroySwapchainInternal(VkDevice device, + VkSwapchainKHR swapchain_handle, + const VkAllocationCallbacks* allocator) { + ATRACE_CALL(); + + const auto& dispatch = GetData(device).driver; + Swapchain* swapchain = SwapchainFromHandle(swapchain_handle); + if (!swapchain) { + return; + } + + bool active = swapchain->surface.swapchain_handle == swapchain_handle; + ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr; + + if (window && swapchain->frame_timestamps_enabled) { + native_window_enable_frame_timestamps(window, false); + } + + for (uint32_t i = 0; i < swapchain->num_images; i++) { + ReleaseSwapchainImage(device, window, -1, swapchain->images[i]); + } + + if (active) { + swapchain->surface.swapchain_handle = VK_NULL_HANDLE; + } + + if (!allocator) { + allocator = &GetData(device).allocator; + } + + swapchain->~Swapchain(); + allocator->pfnFree(allocator->pUserData, swapchain); +} + VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, @@ -1182,7 +1220,7 @@ VkResult CreateSwapchainKHR(VkDevice device, int32_t legacy_usage = 0; if (dispatch.GetSwapchainGrallocUsage2ANDROID) { uint64_t consumer_usage, producer_usage; - ATRACE_BEGIN("dispatch.GetSwapchainGrallocUsage2ANDROID"); + ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID"); result = dispatch.GetSwapchainGrallocUsage2ANDROID( device, create_info->imageFormat, create_info->imageUsage, swapchain_image_usage, &consumer_usage, &producer_usage); @@ -1194,7 +1232,7 @@ VkResult CreateSwapchainKHR(VkDevice device, legacy_usage = android_convertGralloc1To0Usage(producer_usage, consumer_usage); } else if (dispatch.GetSwapchainGrallocUsageANDROID) { - ATRACE_BEGIN("dispatch.GetSwapchainGrallocUsageANDROID"); + ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID"); result = dispatch.GetSwapchainGrallocUsageANDROID( device, create_info->imageFormat, create_info->imageUsage, &legacy_usage); @@ -1289,7 +1327,7 @@ VkResult CreateSwapchainKHR(VkDevice device, &image_native_buffer.usage2.producer, &image_native_buffer.usage2.consumer); - ATRACE_BEGIN("dispatch.CreateImage"); + ATRACE_BEGIN("CreateImage"); result = dispatch.CreateImage(device, &image_create, nullptr, &img.image); ATRACE_END(); @@ -1302,9 +1340,6 @@ VkResult CreateSwapchainKHR(VkDevice device, // -- Cancel all buffers, returning them to the queue -- // If an error occurred before, also destroy the VkImage and release the // buffer reference. Otherwise, we retain a strong reference to the buffer. - // - // TODO(jessehall): The error path here is the same as DestroySwapchain, - // but not the non-error path. Should refactor/unify. for (uint32_t i = 0; i < num_images; i++) { Swapchain::Image& img = swapchain->images[i]; if (img.dequeued) { @@ -1315,18 +1350,11 @@ VkResult CreateSwapchainKHR(VkDevice device, img.dequeued = false; } } - if (result != VK_SUCCESS) { - if (img.image) { - ATRACE_BEGIN("dispatch.DestroyImage"); - dispatch.DestroyImage(device, img.image, nullptr); - ATRACE_END(); - } - } } if (result != VK_SUCCESS) { - swapchain->~Swapchain(); - allocator->pfnFree(allocator->pUserData, swapchain); + DestroySwapchainInternal(device, HandleFromSwapchain(swapchain), + allocator); return result; } @@ -1341,24 +1369,7 @@ void DestroySwapchainKHR(VkDevice device, const VkAllocationCallbacks* allocator) { ATRACE_CALL(); - const auto& dispatch = GetData(device).driver; - Swapchain* swapchain = SwapchainFromHandle(swapchain_handle); - if (!swapchain) - return; - bool active = swapchain->surface.swapchain_handle == swapchain_handle; - ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr; - - if (swapchain->frame_timestamps_enabled) { - native_window_enable_frame_timestamps(window, false); - } - for (uint32_t i = 0; i < swapchain->num_images; i++) - ReleaseSwapchainImage(device, window, -1, swapchain->images[i]); - if (active) - swapchain->surface.swapchain_handle = VK_NULL_HANDLE; - if (!allocator) - allocator = &GetData(device).allocator; - swapchain->~Swapchain(); - allocator->pfnFree(allocator->pUserData, swapchain); + DestroySwapchainInternal(device, swapchain_handle, allocator); } VKAPI_ATTR -- GitLab From 0b46847352d6c1ab49a5597d8e334781cbe7d2ec Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 3 Jun 2019 18:57:19 -0700 Subject: [PATCH 0030/1255] Vulkan: fix vkQueuePresentKHR logic when queueBuffer fails Bug: 134185757 Test: CtsDeqpTestCases and CtsGraphicsTestCases Change-Id: I181b926fa39f10918ef87a11687ba987e7e350f8 --- vulkan/libvulkan/swapchain.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 114b4c935e..524fe0e594 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -1666,17 +1666,16 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { err = window->queueBuffer(window, img.buffer.get(), fence); // queueBuffer always closes fence, even on error if (err != 0) { - // TODO(jessehall): What now? We should probably cancel the - // buffer, I guess? ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err); swapchain_result = WorstPresentResult( swapchain_result, VK_ERROR_OUT_OF_DATE_KHR); + } else { + if (img.dequeue_fence >= 0) { + close(img.dequeue_fence); + img.dequeue_fence = -1; + } + img.dequeued = false; } - if (img.dequeue_fence >= 0) { - close(img.dequeue_fence); - img.dequeue_fence = -1; - } - img.dequeued = false; // If the swapchain is in shared mode, immediately dequeue the // buffer so it can be presented again without an intervening @@ -1703,7 +1702,6 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { } } if (swapchain_result != VK_SUCCESS) { - ReleaseSwapchainImage(device, window, fence, img); OrphanSwapchain(device, &swapchain); } int window_transform_hint; -- GitLab From 736c74eac3cfb2f9b35c66a8948a04e343a4eff8 Mon Sep 17 00:00:00 2001 From: Jiwen 'Steve' Cai Date: Tue, 28 May 2019 18:33:22 -0700 Subject: [PATCH 0031/1255] Update the how we propogate parent type and appId SurfaceFlinger sends each layer's metadata (i.e. type and appId) to the hardware composer. The feature was introduced in Android Q for the 2D-in-VR feature that Daydream uses. The logic was introduced in ag/3738015. When sending layer information to hal, layers also inherit type and app id from parent node when parent node has valid type/appId. However, there are some descendents about what is the invalid type and appId. The original CL ag/3738015 assumes -1 is invalid, while newer CLs ag/6072974 and unittests assumes 0 as default value. Actually, the current unittests is correct, for two reasons: 1/ window type comes from WindowManager.LayoutParams and all values defined here are non-zero. 2/ appId is basically app's UID, which should not be zero (i.e. app never runs under root). Thus, I now have enough reason to conclude that the parent type and appId should be tested with "type > 0 && appId > 0". In another word, the parent is only valid when the type and appId are both non-zero. Bug: 133452166 Test: Inspect the output of "adb shell lshal debug android.hardware.graphics.composer@2.1::IComposer/vr" and verify that each layer's type and app_id are correctly populated. Test: atest libsurfaceflinger_unittest Change-Id: Ib039a54bba241839f49e0be6d87c021001b470e9 --- services/surfaceflinger/Layer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3ca6ef500d..832067b708 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -415,7 +415,7 @@ void Layer::latchGeometry(compositionengine::LayerFECompositionState& compositio auto& parentState = parent->getDrawingState(); const int parentType = parentState.metadata.getInt32(METADATA_WINDOW_TYPE, 0); const int parentAppId = parentState.metadata.getInt32(METADATA_OWNER_UID, 0); - if (parentType >= 0 || parentAppId >= 0) { + if (parentType > 0 && parentAppId > 0) { type = parentType; appId = parentAppId; } -- GitLab From 685a174a9a4333dda22ca6305258b5e92a39e368 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Fri, 7 Jun 2019 10:29:30 -0700 Subject: [PATCH 0032/1255] Vulkan: Remove redundant files Bug: 134185757 Test: build, flash and boot Change-Id: Ifd611aee36dc51ba8778effeb6cf21c2af0875dc --- vulkan/api/templates/asciidoc.tmpl | 151 ---------- vulkan/api/templates/vk_xml.tmpl | 435 ----------------------------- vulkan/api/templates/vulkan_h.tmpl | 295 ------------------- 3 files changed, 881 deletions(-) delete mode 100644 vulkan/api/templates/asciidoc.tmpl delete mode 100644 vulkan/api/templates/vk_xml.tmpl delete mode 100644 vulkan/api/templates/vulkan_h.tmpl diff --git a/vulkan/api/templates/asciidoc.tmpl b/vulkan/api/templates/asciidoc.tmpl deleted file mode 100644 index 3009e19cad..0000000000 --- a/vulkan/api/templates/asciidoc.tmpl +++ /dev/null @@ -1,151 +0,0 @@ -{{Include "vulkan_common.tmpl"}} -{{if not (Global "AsciiDocPath")}}{{Global "AsciiDocPath" "../../doc/specs/vulkan/"}}{{end}} -{{$ | Macro "AsciiDoc.Main"}} - - -{{/* -------------------------------------------------------------------------------- - AsciiDoc generation main entry point. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Main"}} - {{$docPath := Global "AsciiDocPath"}} - - {{/* Generate AsciiDoc files for API enums and bitfields (flags). */}} - {{range $e := $.Enums}} - {{if not $e.IsBitfield}} - {{$filename := print $docPath "enums/" (Macro "EnumName" $e) ".txt"}} - {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Enum" $e) "File" $filename}} - {{else}} - {{$filename := print $docPath "flags/" (Macro "EnumName" $e) ".txt"}} - {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Flag" $e) "File" $filename}} - {{end}} - {{end}} - - {{/* Generate AsciiDoc files for API commands (protos). */}} - {{range $f := (AllCommands $)}} - {{if not (GetAnnotation $f "pfn")}} - {{$filename := print $docPath "protos/" $f.Name ".txt"}} - {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Proto" $f) "File" $filename}} - {{end}} - {{end}} - - {{/* Generate AsciiDoc files for API structs. */}} - {{range $c := $.Classes}} - {{if not (GetAnnotation $c "internal")}} - {{$filename := print $docPath "structs/" $c.Name ".txt"}} - {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Struct" $c) "File" $filename}} - {{end}} - {{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the AsciiDoc contents for the specified API enum. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Enum"}} - {{AssertType $ "Enum"}} - - {{Macro "Docs" $.Docs}} - typedef enum { - {{range $i, $e := $.Entries}} - {{Macro "EnumEntry" $e}} = {{AsSigned $e.Value}}, {{Macro "Docs" $e.Docs}} - {{end}} - ¶ - {{$name := Macro "EnumName" $ | TrimRight "ABCDEFGHIJKLMNOQRSTUVWXYZ" | SplitPascalCase | Upper | JoinWith "_"}} - {{$first := Macro "EnumFirstEntry" $}} - {{$last := Macro "EnumLastEntry" $}} - {{$name}}_BEGIN_RANGE = {{$first}}, - {{$name}}_END_RANGE = {{$last}}, - {{$name}}_NUM = ({{$last}} - {{$first}} + 1), - {{$name}}_MAX_ENUM = 0x7FFFFFFF - } {{Macro "EnumName" $}}; -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the AsciiDoc contents for the specified API bitfield. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Flag"}} - {{AssertType $ "Enum"}} - - {{Macro "Docs" $.Docs}} - typedef VkFlags {{Macro "EnumName" $}}; - {{if $.Entries}} - typedef enum { - {{range $e := $.Entries}} - {{Macro "BitfieldEntryName" $e}} = {{printf "%#.8x" $e.Value}}, {{Macro "Docs" $e.Docs}} - {{end}} - } {{Macro "EnumName" $ | TrimRight "s"}}Bits; - {{end}} -{{end}} - - - -{{/* -------------------------------------------------------------------------------- - Emits the AsciiDoc contents for the specified API class. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Struct"}} - {{AssertType $ "Class"}} - - {{Macro "Docs" $.Docs}} - typedef {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} { - {{range $f := $.Fields}} - {{Node "Type" $f}} {{$f.Name}}{{Macro "ArrayPostfix" (TypeOf $f)}}; {{Macro "Docs" $f.Docs}} - {{end}} - } {{Macro "StructName" $}}; -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the AsciiDoc contents for the specified API function. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Proto"}} - {{AssertType $ "Function"}} - - {{Macro "Docs" $.Docs}} - {{Node "Type" $.Return}} VKAPI {{Macro "FunctionName" $}}({{Macro "Parameters" $}}); -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Wraps the specified Code in AsciiDoc source tags then writes to the specified File. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Write"}} - {{AssertType $.Code "string"}} - {{AssertType $.File "string"}} - - {{$code := $.Code | Format (Global "clang-format")}} - {{JoinWith "\n" (Macro "AsciiDoc.Header") $code (Macro "AsciiDoc.Footer") ""| Write $.File}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits an AsciiDoc source header. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Header"}} -[source,{basebackend@docbook:c++:cpp}] ------------------------------------------------------------------------------- -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits an AsciiDoc source footer. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Footer"}} ------------------------------------------------------------------------------- -{{end}} diff --git a/vulkan/api/templates/vk_xml.tmpl b/vulkan/api/templates/vk_xml.tmpl deleted file mode 100644 index 893bde7833..0000000000 --- a/vulkan/api/templates/vk_xml.tmpl +++ /dev/null @@ -1,435 +0,0 @@ -{{Include "vulkan_common.tmpl"}} -{{Macro "DefineGlobals" $}} -{{$ | Macro "vk.xml" | Reflow 4 | Write "vk.xml"}} - - -{{/* -------------------------------------------------------------------------------- - Entry point -------------------------------------------------------------------------------- -*/}} -{{define "vk.xml"}} - - - »« -Copyright (c) 2015 The Khronos Group Inc. -¶ -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and/or associated documentation files (the -"Materials"), to deal in the Materials without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Materials, and to -permit persons to whom the Materials are furnished to do so, subject to -the following conditions: -¶ -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Materials. -¶ -THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -¶ ------------------------------------------------------------------------- -¶ -This file, vk.xml, is the Vulkan API Registry.» - -¶ - - » - #include "vk_platform.h" -¶ - #define VK_MAKE_VERSION(major, minor, patch) \ - «((major << 22) | (minor << 12) | patch)» -¶ - // Vulkan API version supported by this file«« -#define VK_API_VERSION VK_MAKE_VERSION({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}}) -¶ - »»«« -#if (_MSC_VER >= 1800 || __cplusplus >= 201103L) -#define VK_NONDISP_HANDLE_OPERATOR_BOOL() explicit operator bool() const { return handle != 0; } -#else -#define VK_NONDISP_HANDLE_OPERATOR_BOOL() -«#endif - »»» -¶ - ««« -#define VK_DEFINE_HANDLE(obj) typedef struct obj##_T* obj; - »»»««« -#if defined(__cplusplus) - »»#if (_MSC_VER >= 1800 || __cplusplus >= 201103L) - »// The bool operator only works if there are no implicit conversions from an obj to - // a bool-compatible type, which can then be used to unintentionally violate type safety. - // C++11 and above supports the "explicit" keyword on conversion operators to stop this - // from happening. Otherwise users of C++ below C++11 won't get direct access to evaluating - // the object handle as a bool in expressions like: - // if (obj) vkDestroy(obj); - #define VK_NONDISP_HANDLE_OPERATOR_BOOL() explicit operator bool() const { return handle != 0; } - #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - explicit obj(uint64_t x) : handle(x) { } \ - obj(decltype(nullptr)) : handle(0) { } - «#else» - #define VK_NONDISP_HANDLE_OPERATOR_BOOL() - #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - obj(uint64_t x) : handle(x) { } - «#endif - #define VK_DEFINE_NONDISP_HANDLE(obj) \» - struct obj { \ - obj() { } \ - VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - obj& operator =(uint64_t x) { handle = x; return *this; } \ - bool operator==(const obj& other) const { return handle == other.handle; } \ - bool operator!=(const obj& other) const { return handle != other.handle; } \ - bool operator!() const { return !handle; } \ - VK_NONDISP_HANDLE_OPERATOR_BOOL() \ - uint64_t handle; \ - }; -««#else - »#define VK_DEFINE_NONDISP_HANDLE(obj) typedef struct obj##_T { uint64_t handle; } obj;« -#endif - »» -¶ - -#if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1800) || __cplusplus >= 201103L) - »#define VK_NULL_HANDLE nullptr -«#else - »#define VK_NULL_HANDLE 0 -«#endif - »» -¶ - - - - - - - - - - - - - - {{range $e := $.Enums}} - {{if $e.IsBitfield}} - {{$bits := print (Macro "EnumName" $e | TrimRight "s") "Bits"}} - typedef VkFlags {{$e.Name}};§ - {{if $e.Entries}}{{Macro "XML.Docs" $e.Docs}} - {{else}}{{Macro "XML.Docs" (Strings $e.Docs "(no bits yet)")}} - {{end}} - {{end}} - {{end}} -¶ - - {{range $i, $p := $.Pseudonyms}} - {{ if (GetAnnotation $p "dispatchHandle")}} - {{if Global "VK_DEFINE_HANDLE_TYPE_DEFINED"}} - VK_DEFINE_HANDLE({{$p.Name}}) - {{else}} - {{Global "VK_DEFINE_HANDLE_TYPE_DEFINED" "YES"}} - VK_DEFINE_HANDLE({{$p.Name}}) - {{end}} - {{else if (GetAnnotation $p "nonDispatchHandle")}} - {{if Global "VK_DEFINE_NONDISP_HANDLE_TYPE_DEFINED"}} - VK_DEFINE_NONDISP_HANDLE({{$p.Name}}) - {{else}} - {{Global "VK_DEFINE_NONDISP_HANDLE_TYPE_DEFINED" "YES"}} - VK_DEFINE_NONDISP_HANDLE({{$p.Name}}) - {{end}} - {{end}} - {{end}} -¶ - - {{range $e := SortBy $.Enums "EnumName"}} - {{if and $e.Entries (not (GetAnnotation $e "internal"))}} - {{if $e.IsBitfield}} - - {{else}} - - {{end}} - {{end}} - {{end}} -¶ - - typedef void* (VKAPI *PFN_vkAllocFunction)(« - void* pUserData, - size_t size, - size_t alignment, - VkSystemAllocType allocType);» - typedef void (VKAPI *PFN_vkFreeFunction)(« - void* pUserData, - void* pMem);» -¶ - - typedef void (VKAPI *PFN_vkVoidFunction)(void); -¶ - - {{range $c := $.Classes}} - {{if not (GetAnnotation $c "internal")}} - {{Macro "Struct" $c}} - {{end}} - {{end}} - « -¶ - -¶ - » - - {{range $d := $.Definitions}} - {{if HasPrefix $d.Name "VK_"}} - {{Macro "XML.Docs" $d.Docs}} - {{end}} - {{end}} - - - - - - - - « -¶ - « -¶ - {{range $e := $.Enums}} - {{if not (or $e.IsBitfield (GetAnnotation $e "internal"))}} - {{Macro "XML.Enum" $e}} - {{end}} - {{end}} -¶ - - {{range $e := $.Enums}} - {{if $e.IsBitfield}} - {{Macro "XML.Bitfield" $e}} - {{end}} - {{end}} -¶ - - » - {{range $f := AllCommands $}} - {{if not (GetAnnotation $f "pfn")}} - {{Macro "XML.Function" $f}} - {{end}} - {{end}} - « -¶ - - » - » - - « - » - - « - » - - - - - - - - « - » - {{range $f := AllCommands $}} - {{if not (GetAnnotation $f "pfn")}} - - {{end}} - {{end}} - - «» - - - - - - - - « - « -¶ - -« -{{end}} - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified bitfield. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Bitfield"}} - {{AssertType $ "Enum"}} - - {{if $.Entries}} - » - {{range $e := $.Entries}} - {{$pos := Bitpos $e.Value}} - - {{end}} - « - {{end}} - -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified enum. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Enum"}} - {{AssertType $ "Enum"}} - - » - {{range $i, $e := $.Entries}} - - {{end}} - {{if $lu := GetAnnotation $ "lastUnused"}} - - {{end}} - « -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified class. -------------------------------------------------------------------------------- -*/}} -{{define "Struct"}} - {{AssertType $ "Class"}} - - » - {{range $f := $.Fields}} - {{Node "XML.Type" $f}} {{$f.Name}}{{Macro "XML.ArrayPostfix" $f}}{{Macro "XML.Docs" $f.Docs}} - {{end}} - « -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits either 'struct' or 'union' for the specified class. -------------------------------------------------------------------------------- -*/}} -{{define "StructType"}} - {{AssertType $ "Class"}} - - {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C function pointer typedef declaration for the specified command. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Function"}} - {{AssertType $ "Function"}} - - {{$ts := GetAnnotation $ "threadSafety"}} - » - {{Node "XML.Type" $.Return}} {{$.Name}} - {{range $p := $.CallParameters}} - {{Node "XML.Type" $p}} {{$p.Name}}{{Macro "ArrayPostfix" $p}} - {{end}} - « -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the XML translation for the specified documentation block (string array). -------------------------------------------------------------------------------- -*/}} -{{define "XML.Docs"}} - {{if $}} {{end}} -{{end}} - -{{/* -------------------------------------------------------------------------------- - Emits the C translation for the specified type. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Type.Class" }}{{Macro "StructName" $.Type}}{{end}} -{{define "XML.Type.Pseudonym" }}{{$.Type.Name}}{{end}} -{{define "XML.Type.Enum" }}{{$.Type.Name}}{{end}} -{{define "XML.Type.StaticArray"}}{{Node "XML.Type" $.Type.ValueType}}{{end}} -{{define "XML.Type.Pointer" }}{{if $.Type.Const}}{{Node "XML.ConstType" $.Type.To}}{{else}}{{Node "XML.Type" $.Type.To}}{{end}}*{{end}} -{{define "XML.Type.Slice" }}{{Node "XML.Type" $.Type.To}}*{{end}} -{{define "XML.Type#s8" }}int8_t{{end}} -{{define "XML.Type#u8" }}uint8_t{{end}} -{{define "XML.Type#s16" }}int16_t{{end}} -{{define "XML.Type#u16" }}uint16_t{{end}} -{{define "XML.Type#s32" }}int32_t{{end}} -{{define "XML.Type#u32" }}uint32_t{{end}} -{{define "XML.Type#f32" }}float{{end}} -{{define "XML.Type#s64" }}int64_t{{end}} -{{define "XML.Type#u64" }}uint64_t{{end}} -{{define "XML.Type#f64" }}double{{end}} -{{define "XML.Type#char" }}char{{end}} -{{define "XML.Type#void" }}void{{end}} - -{{define "XML.ConstType_Default"}}const {{Node "XML.Type" $.Type}}{{end}} -{{define "XML.ConstType.Pointer"}}{{Node "XML.Type" $.Type}} const{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits a C type and name for the given parameter -------------------------------------------------------------------------------- -*/}} -{{define "XML.Parameter"}} - {{AssertType $ "Parameter"}} - - {{Macro "ParameterType" $}} {{$.Name}}{{Macro "ArrayPostfix" $}} -{{end}} - -{{/* -------------------------------------------------------------------------------- - Emits a comma-separated list of C type-name paired parameters for the given - command. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Parameters"}} - {{AssertType $ "Function"}} - - {{ForEach $.CallParameters "XML.Parameter" | JoinWith ", "}} - {{if not $.CallParameters}}void{{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the fixed-size-array postfix for pseudonym types annotated with @array -------------------------------------------------------------------------------- -*/}} -{{define "XML.ArrayPostfix"}}{{Node "XML.ArrayPostfix" $}}{{end}} -{{define "XML.ArrayPostfix.StaticArray"}}[{{Node "XML.NamedValue" $.Type.SizeExpr}}]{{end}} -{{define "XML.ArrayPostfix_Default"}}{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the value of the given constant, or the tagged name if existant. -------------------------------------------------------------------------------- -*/}} -{{define "XML.NamedValue.Definition"}}{{$.Node.Name}}{{end}} -{{define "XML.NamedValue.EnumEntry"}}{{$.Node.Name}}{{end}} -{{define "XML.NamedValue_Default"}}{{$.Node}}{{end}} diff --git a/vulkan/api/templates/vulkan_h.tmpl b/vulkan/api/templates/vulkan_h.tmpl deleted file mode 100644 index 83a5e40804..0000000000 --- a/vulkan/api/templates/vulkan_h.tmpl +++ /dev/null @@ -1,295 +0,0 @@ -{{Include "vulkan_common.tmpl"}} -{{Macro "DefineGlobals" $}} -{{$ | Macro "vulkan.h" | Format (Global "clang-format") | Write "../include/vulkan.h"}} - - -{{/* -------------------------------------------------------------------------------- - Entry point -------------------------------------------------------------------------------- -*/}} -{{define "vulkan.h"}} -#ifndef __vulkan_h_ -#define __vulkan_h_ 1 -¶ -#ifdef __cplusplus -extern "C" { -#endif -¶ -/* -** Copyright (c) 2015-2016 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ -¶ -/* -** This header is generated from the Khronos Vulkan API Registry. -** -*/ -¶ -#define VK_VERSION_1_0 1 -#include "vk_platform.h" -¶ -#define VK_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch)) -¶ -// Vulkan API version supported by this file -#define VK_API_VERSION \ - VK_MAKE_VERSION({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}}) -¶ -#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) -#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) -#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) -¶ -#if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L) - #define VK_NULL_HANDLE nullptr -#else - #define VK_NULL_HANDLE 0 -#endif -¶ -#define VK_DEFINE_HANDLE(obj) typedef struct obj##_T* obj; -¶ -#if defined(__cplusplus) -#if ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L) -// The bool operator only works if there are no implicit conversions from an obj to -// a bool-compatible type, which can then be used to unintentionally violate type safety. -// C++11 and above supports the "explicit" keyword on conversion operators to stop this -// from happening. Otherwise users of C++ below C++11 won't get direct access to evaluating -// the object handle as a bool in expressions like: -// if (obj) vkDestroy(obj); -#define VK_NONDISP_HANDLE_OPERATOR_BOOL() \ - explicit operator bool() const { return handle != 0; } -#define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - explicit obj(uint64_t x) : handle(x) { } \ - obj(decltype(nullptr)) : handle(0) { } -#else -#define VK_NONDISP_HANDLE_OPERATOR_BOOL() -#define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - obj(uint64_t x) : handle(x) { } -#endif -#define VK_DEFINE_NONDISP_HANDLE(obj) \ - struct obj { \ - obj() : handle(0) { } \ - VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - obj& operator=(uint64_t x) { \ - handle = x; \ - return *this; \ - } \ - bool operator==(const obj& other) const { return handle == other.handle; } \ - bool operator!=(const obj& other) const { return handle != other.handle; } \ - bool operator!() const { return !handle; } \ - VK_NONDISP_HANDLE_OPERATOR_BOOL() \ - uint64_t handle; \ - }; -#else -#define VK_DEFINE_NONDISP_HANDLE(obj) \ - typedef struct obj##_T { uint64_t handle; } obj; -#endif -¶ -#define VK_LOD_CLAMP_NONE 1000.0f -#define VK_REMAINING_MIP_LEVELS (~0U) -#define VK_REMAINING_ARRAY_LAYERS (~0U) -#define VK_WHOLE_SIZE (~0ULL) -#define VK_ATTACHMENT_UNUSED (~0U) -define VK_QUEUE_FAMILY_IGNORED (~0U) -define VK_SUBPASS_EXTERNAL (~0U) -{{range $d := $.Definitions}} - {{if HasPrefix $d.Name "VK_"}}#define {{$d.Name}} {{$d.Expression}}{{end}} -{{end}} -¶ -{{range $i, $p := $.Pseudonyms}} - {{if GetAnnotation $p "dispatchHandle"}}VK_DEFINE_HANDLE({{$p.Name}}) - {{else if GetAnnotation $p "nonDispatchHandle"}}VK_DEFINE_NONDISP_HANDLE({{$p.Name}}) - {{end}} -{{end}} -¶ -// ------------------------------------------------------------------------------------------------ -// Enumerations -¶ - {{range $e := $.Enums}} - {{if not $e.IsBitfield}} - {{Macro "Enum" $e}} - {{end}} - {{end}} -¶ -// ------------------------------------------------------------------------------------------------ -// Flags -¶ - {{range $e := $.Enums}} - {{if $e.IsBitfield}} - {{Macro "Bitfield" $e}} - {{end}} - {{end}} -¶ -// ------------------------------------------------------------------------------------------------ -// Vulkan structures -¶ - {{/* Function pointers */}} - {{range $f := AllCommands $}} - {{if GetAnnotation $f "pfn"}} - {{Macro "FunctionTypedef" $f}} - {{end}} - {{end}} -¶ - {{range $c := $.Classes}} - {{if not (GetAnnotation $c "internal")}} - {{Macro "Struct" $c}} - {{end}} - {{end}} -¶ -// ------------------------------------------------------------------------------------------------ -// API functions -¶ - {{range $f := AllCommands $}} - {{if not (GetAnnotation $f "pfn")}} - {{Macro "FunctionTypedef" $f}} - {{end}} - {{end}} -¶ -#ifdef VK_NO_PROTOTYPES -¶ - {{range $f := AllCommands $}} - {{if not (GetAnnotation $f "pfn")}} - {{Macro "FunctionDecl" $f}} - {{end}} - {{end}} -¶ -#endif -¶ -#ifdef __cplusplus -} -#endif -¶ -#endif -{{end}} - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified bitfield. -------------------------------------------------------------------------------- -*/}} -{{define "Bitfield"}} - {{AssertType $ "Enum"}} - - {{Macro "Docs" $.Docs}} - typedef VkFlags {{Macro "EnumName" $}}; - {{if $.Entries}} - typedef enum { - {{range $b := $.Entries}} - {{Macro "BitfieldEntryName" $b}} = {{printf "0x%.8X" $b.Value}}, {{Macro "Docs" $b.Docs}} - {{end}} - } {{Macro "EnumName" $ | TrimRight "s"}}Bits; - {{end}} - ¶ -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified enum. -------------------------------------------------------------------------------- -*/}} -{{define "Enum"}} - {{AssertType $ "Enum"}} - - {{Macro "Docs" $.Docs}} - typedef enum { - {{range $i, $e := $.Entries}} - {{Macro "EnumEntry" $e}} = {{printf "0x%.8X" $e.Value}}, {{Macro "Docs" $e.Docs}} - {{end}} - ¶ - {{$name := Macro "EnumName" $ | TrimRight "ABCDEFGHIJKLMNOQRSTUVWXYZ" | SplitPascalCase | Upper | JoinWith "_"}} - {{if GetAnnotation $ "enumMaxOnly"}} - VK_MAX_ENUM({{$name | SplitOn "VK_"}}) - {{else}} - {{$first := Macro "EnumFirstEntry" $ | SplitOn $name | TrimLeft "_"}} - {{$last := Macro "EnumLastEntry" $ | SplitOn $name | TrimLeft "_"}} - VK_ENUM_RANGE({{$name | SplitOn "VK_"}}, {{$first}}, {{$last}}) - {{end}} - } {{Macro "EnumName" $}}; - ¶ -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified class. -------------------------------------------------------------------------------- -*/}} -{{define "Struct"}} - {{AssertType $ "Class"}} - - {{Macro "Docs" $.Docs}} - typedef {{Macro "StructType" $}} { - {{ForEach $.Fields "Field" | JoinWith "\n"}} - } {{Macro "StructName" $}}; - ¶ -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified class field. -------------------------------------------------------------------------------- -*/}} -{{define "Field"}} - {{AssertType $ "Field"}} - - {{Node "Type" $}} {{$.Name}}§ - {{Macro "ArrayPostfix" (TypeOf $)}}; {{Macro "Docs" $.Docs}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits either 'struct' or 'union' for the specified class. -------------------------------------------------------------------------------- -*/}} -{{define "StructType"}} - {{AssertType $ "Class"}} - - {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C function pointer typedef declaration for the specified command. -------------------------------------------------------------------------------- -*/}} -{{define "FunctionTypedef"}} - {{AssertType $ "Function"}} - - typedef {{Node "Type" $.Return}} (VKAPI* {{Macro "FunctionPtrName" $}})({{Macro "Parameters" $}}); -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C function declaration for the specified command. -------------------------------------------------------------------------------- -*/}} -{{define "FunctionDecl"}} - {{AssertType $ "Function"}} - - {{if not (GetAnnotation $ "fptr")}} - {{Macro "Docs" $.Docs}} - {{Node "Type" $.Return}} VKAPI {{Macro "FunctionName" $}}({{Macro "Parameters" $}}); - {{end}} -{{end}} -- GitLab From df5290534ed9556c0bc77425855f5988b37c9631 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 7 Jun 2019 14:53:14 -0700 Subject: [PATCH 0033/1255] Fix surface tracing thread sync issues Tracing thread was incorrectly reading the drawing state while it was being updated by the surface flinger main thread. Move the notify to after composition. Fixes: 134752356 Test: capture surface flinger trace Change-Id: I32a59475ced80d7eaa062181c732ce0f9a81cca5 --- services/surfaceflinger/SurfaceFlinger.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 87c1bf9afa..f9af9ba1ed 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1783,6 +1783,12 @@ void SurfaceFlinger::handleMessageRefresh() { mVsyncModulator.onRefreshed(mHadClientComposition); mLayersWithQueuedFrames.clear(); + if (mVisibleRegionsDirty) { + mVisibleRegionsDirty = false; + if (mTracingEnabled) { + mTracing.notify("visibleRegionsDirty"); + } + } } @@ -1792,9 +1798,6 @@ bool SurfaceFlinger::handleMessageInvalidate() { if (mVisibleRegionsDirty) { computeLayerBounds(); - if (mTracingEnabled) { - mTracing.notify("visibleRegionsDirty"); - } } for (auto& layer : mLayersPendingRefresh) { @@ -2189,7 +2192,6 @@ void SurfaceFlinger::rebuildLayerStacks() { // rebuild the visible layer list per screen if (CC_UNLIKELY(mVisibleRegionsDirty)) { ATRACE_NAME("rebuildLayerStacks VR Dirty"); - mVisibleRegionsDirty = false; invalidateHwcGeometry(); for (const auto& pair : mDisplays) { -- GitLab From f92661b58260a3a5901f733f43f8ac37e9ffc338 Mon Sep 17 00:00:00 2001 From: Yuichiro Hanada Date: Thu, 6 Jun 2019 18:50:18 +0900 Subject: [PATCH 0034/1255] Fix debug print when a KCM file is not found. Bug: None Test: m Change-Id: I6d5507dd227a46c73d82c7a2433d70c7dccdef21 --- libs/input/Keyboard.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp index 0c22bfefed..56900c129e 100644 --- a/libs/input/Keyboard.cpp +++ b/libs/input/Keyboard.cpp @@ -38,29 +38,29 @@ KeyMap::KeyMap() { KeyMap::~KeyMap() { } -status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, +status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration) { // Use the configured key layout if available. if (deviceConfiguration) { String8 keyLayoutName; if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), keyLayoutName)) { - status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName.c_str()); + status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " "it was not found.", - deviceIdenfifier.name.c_str(), keyLayoutName.string()); + deviceIdentifier.name.c_str(), keyLayoutName.string()); } } String8 keyCharacterMapName; if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), keyCharacterMapName)) { - status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName.c_str()); + status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard character " "map '%s' but it was not found.", - deviceIdenfifier.name.c_str(), keyLayoutName.string()); + deviceIdentifier.name.c_str(), keyCharacterMapName.string()); } } @@ -70,25 +70,25 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, } // Try searching by device identifier. - if (probeKeyMap(deviceIdenfifier, "")) { + if (probeKeyMap(deviceIdentifier, "")) { return OK; } // Fall back on the Generic key map. // TODO Apply some additional heuristics here to figure out what kind of // generic key map to use (US English, etc.) for typical external keyboards. - if (probeKeyMap(deviceIdenfifier, "Generic")) { + if (probeKeyMap(deviceIdentifier, "Generic")) { return OK; } // Try the Virtual key map as a last resort. - if (probeKeyMap(deviceIdenfifier, "Virtual")) { + if (probeKeyMap(deviceIdentifier, "Virtual")) { return OK; } // Give up! ALOGE("Could not determine key map for device '%s' and no default key maps were found!", - deviceIdenfifier.name.c_str()); + deviceIdentifier.name.c_str()); return NAME_NOT_FOUND; } -- GitLab From e8097ca7c5e00ed61d7f604d8eda8d2fe2d2fa9b Mon Sep 17 00:00:00 2001 From: chaviw Date: Fri, 7 Jun 2019 17:08:53 -0700 Subject: [PATCH 0035/1255] Remove SurfaceControl.destroy function The destroy function was only used temporarily instead of all call points calling reparent(null) explicitly. Removing the Java destroy request so no need for the SurfaceControl.destroy method anymore. Test: SurfaceControlTest Change-Id: If69e030f3babf83a6382f85a26f0bb1eb451dc23 --- libs/gui/SurfaceControl.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 55488dad0b..011854edbb 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -71,14 +71,6 @@ SurfaceControl::~SurfaceControl() release(); } -void SurfaceControl::destroy() -{ - if (isValid()) { - SurfaceComposerClient::Transaction().reparent(this, nullptr).apply(); - } - release(); -} - void SurfaceControl::release() { // Trigger an IPC now, to make sure things -- GitLab From 12536a8fdae818ec39ae274d7da561480f4e1d61 Mon Sep 17 00:00:00 2001 From: silence_dogood Date: Fri, 7 Jun 2019 15:00:32 -0700 Subject: [PATCH 0036/1255] Cache NATIVE_WINDOW_MAX_BUFFER_COUNT in Surface To avoid the sync binder call to BufferQueue everytime vkGetPhysicalDeviceSurfaceCapabilitiesKHR is called, we cache the NATIVE_WINDOW_MAX_BUFFER_COUNT at the Surface each time the client connects. Bug: 133187007 Test: Vulkan cts tests Change-Id: I1942ff75ceb539c4904dc98c2e488c4d4cade31d --- libs/gui/BufferQueueProducer.cpp | 1 + libs/gui/Surface.cpp | 6 ++++++ libs/gui/include/gui/IGraphicBufferProducer.h | 1 + libs/gui/include/gui/Surface.h | 1 + 4 files changed, 9 insertions(+) diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 9c311a314f..b005707fd2 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1199,6 +1199,7 @@ status_t BufferQueueProducer::connect(const sp& listener, static_cast(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; output->bufferReplaced = false; + output->maxBufferCount = mCore->mMaxBufferCount; if (listener != nullptr) { // Set up a death notification so that we can disconnect diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e6eb327c6f..2e8a5d005b 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -96,6 +96,7 @@ Surface::Surface(const sp& bufferProducer, bool controll mConnectedToCpu = false; mProducerControlledByApp = controlledByApp; mSwapIntervalZero = false; + mMaxBufferCount = 0; } Surface::~Surface() { @@ -961,6 +962,10 @@ int Surface::query(int what, int* value) const { *value = static_cast(mDataSpace); return NO_ERROR; } + case NATIVE_WINDOW_MAX_BUFFER_COUNT: { + *value = mMaxBufferCount; + return NO_ERROR; + } } } return mGraphicBufferProducer->query(what, value); @@ -1298,6 +1303,7 @@ int Surface::connect( mDefaultWidth = output.width; mDefaultHeight = output.height; mNextFrameNumber = output.nextFrameNumber; + mMaxBufferCount = output.maxBufferCount; // Ignore transform hint if sticky transform is set or transform to display inverse flag is // set. Transform hint should be ignored if the client is expected to always submit buffers diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 3dde8c8c80..6e002dd505 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -412,6 +412,7 @@ public: uint64_t nextFrameNumber{0}; FrameEventHistoryDelta frameTimestamps; bool bufferReplaced{false}; + int maxBufferCount{0}; }; virtual status_t queueBuffer(int slot, const QueueBufferInput& input, diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 0c471bb701..80469dfeaf 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -465,6 +465,7 @@ protected: bool mReportRemovedBuffers = false; std::vector> mRemovedBuffers; + int mMaxBufferCount; }; } // namespace android -- GitLab From 621102e5d2c97bd00404817191fa5012749a7a0f Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 12 Jun 2019 14:16:57 -0700 Subject: [PATCH 0037/1255] Make SurfaceControl Transaction parcelable 2/2 Allow clients to send SurfaceControl Transactions across processes to enable more advanced synchronization use cases. Bug: 132205507 Test: atest SurfaceFlinger_test Change-Id: I20a33cafc0960e73f9a2c3d740f81319e02b68ff --- libs/gui/SurfaceComposerClient.cpp | 89 ++++++++++++++++++++ libs/gui/SurfaceControl.cpp | 3 +- libs/gui/include/gui/SurfaceComposerClient.h | 8 +- libs/gui/include/gui/SurfaceControl.h | 4 +- 4 files changed, 99 insertions(+), 5 deletions(-) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index cc9e468e16..3f97a969bf 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -322,10 +322,99 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mTransactionNestCount(other.mTransactionNestCount), mAnimation(other.mAnimation), mEarlyWakeup(other.mEarlyWakeup), + mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; mInputWindowCommands = other.mInputWindowCommands; + mListenerCallbacks = other.mListenerCallbacks; +} + +std::unique_ptr +SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) { + auto transaction = std::make_unique(); + if (transaction->readFromParcel(parcel) == NO_ERROR) { + return transaction; + } + return nullptr; +} + +status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) { + const uint32_t forceSynchronous = parcel->readUint32(); + const uint32_t transactionNestCount = parcel->readUint32(); + const bool animation = parcel->readBool(); + const bool earlyWakeup = parcel->readBool(); + const bool containsBuffer = parcel->readBool(); + const int64_t desiredPresentTime = parcel->readInt64(); + + size_t count = static_cast(parcel->readUint32()); + if (count > parcel->dataSize()) { + return BAD_VALUE; + } + SortedVector displayStates; + displayStates.setCapacity(count); + for (size_t i = 0; i < count; i++) { + DisplayState displayState; + if (displayState.read(*parcel) == BAD_VALUE) { + return BAD_VALUE; + } + displayStates.add(displayState); + } + + count = static_cast(parcel->readUint32()); + if (count > parcel->dataSize()) { + return BAD_VALUE; + } + std::unordered_map, ComposerState, SCHash> composerStates; + composerStates.reserve(count); + for (size_t i = 0; i < count; i++) { + sp surfaceControl = SurfaceControl::readFromParcel(parcel); + + ComposerState composerState; + if (composerState.read(*parcel) == BAD_VALUE) { + return BAD_VALUE; + } + composerStates[surfaceControl] = composerState; + } + + InputWindowCommands inputWindowCommands; + inputWindowCommands.read(*parcel); + + // Parsing was successful. Update the object. + mForceSynchronous = forceSynchronous; + mTransactionNestCount = transactionNestCount; + mAnimation = animation; + mEarlyWakeup = earlyWakeup; + mContainsBuffer = containsBuffer; + mDesiredPresentTime = desiredPresentTime; + mDisplayStates = displayStates; + mComposerStates = composerStates; + mInputWindowCommands = inputWindowCommands; + // listener callbacks contain function pointer addresses and may not be safe to parcel. + mListenerCallbacks.clear(); + return NO_ERROR; +} + +status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const { + parcel->writeUint32(mForceSynchronous); + parcel->writeUint32(mTransactionNestCount); + parcel->writeBool(mAnimation); + parcel->writeBool(mEarlyWakeup); + parcel->writeBool(mContainsBuffer); + parcel->writeInt64(mDesiredPresentTime); + parcel->writeUint32(static_cast(mDisplayStates.size())); + for (auto const& displayState : mDisplayStates) { + displayState.write(*parcel); + } + + parcel->writeUint32(static_cast(mComposerStates.size())); + for (auto const& [surfaceControl, composerState] : mComposerStates) { + surfaceControl->writeToParcel(parcel); + composerState.write(*parcel); + } + + mInputWindowCommands.write(*parcel); + return NO_ERROR; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 55488dad0b..d87a447a97 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -186,8 +186,7 @@ void SurfaceControl::writeToParcel(Parcel* parcel) parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer)); } -sp SurfaceControl::readFromParcel(Parcel* parcel) -{ +sp SurfaceControl::readFromParcel(const Parcel* parcel) { sp client = parcel->readStrongBinder(); sp handle = parcel->readStrongBinder(); if (client == nullptr || handle == nullptr) diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 0e17c7b015..1f2947c824 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -285,7 +285,7 @@ public: std::unordered_set, SCHash> surfaceControls; }; - class Transaction { + class Transaction : Parcelable { std::unordered_map, ComposerState, SCHash> mComposerStates; SortedVector mDisplayStates; std::unordered_map, CallbackInfo, TCLHash> @@ -325,6 +325,12 @@ public: virtual ~Transaction() = default; Transaction(Transaction const& other); + // Factory method that creates a new Transaction instance from the parcel. + static std::unique_ptr createFromParcel(const Parcel* parcel); + + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + status_t apply(bool synchronous = false); // Merge another transaction in to this one, clearing other // as if it had been applied. diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index 23bfc0256b..ae4a14690f 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -44,7 +44,7 @@ class SurfaceComposerClient; class SurfaceControl : public RefBase { public: - static sp readFromParcel(Parcel* parcel); + static sp readFromParcel(const Parcel* parcel); void writeToParcel(Parcel* parcel); static bool isValid(const sp& surface) { @@ -81,7 +81,7 @@ public: status_t getLayerFrameStats(FrameStats* outStats) const; sp getClient() const; - + explicit SurfaceControl(const sp& other); SurfaceControl(const sp& client, const sp& handle, -- GitLab From e4a1cabd61895eeda1968eabeb19b9c5ad74b430 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Fri, 14 Jun 2019 14:01:20 -0700 Subject: [PATCH 0038/1255] Fix bad doxygen tags in font headers. Test: Compared to other NDK headers. Bug: None Change-Id: If2ff22d1502ec8541e57aa26a5a42461abf9fdc7 --- include/android/font.h | 2 +- include/android/font_matcher.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/android/font.h b/include/android/font.h index 435a573f51..8001ee1938 100644 --- a/include/android/font.h +++ b/include/android/font.h @@ -16,7 +16,7 @@ /** * @addtogroup Font - * { + * @{ */ /** diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h index e286a4c812..0b8f892b9b 100644 --- a/include/android/font_matcher.h +++ b/include/android/font_matcher.h @@ -16,7 +16,7 @@ /** * @addtogroup Font - * { + * @{ */ /** -- GitLab From 44f34c55fc98247129b696109c4661570ab73dd2 Mon Sep 17 00:00:00 2001 From: Inseob Kim Date: Sat, 8 Jun 2019 20:47:59 +0900 Subject: [PATCH 0039/1255] Change surfacefliger properties scopes to public For sysprop_library, System scope and Public scope are identical from now on, and only Public or Internal scope are suppose to be used. This changes existing system scopes to public, and has no effect on code level. Bug: 131637873 Test: mma Change-Id: Ib285432d66fbe9ca99d94edb41b424937f04b26d --- .../sysprop/SurfaceFlingerProperties.sysprop | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index decabd5e88..a8ec7649c6 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -36,7 +36,7 @@ owner: Platform prop { api_name: "vsync_event_phase_offset_ns" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns" } @@ -44,7 +44,7 @@ prop { prop { api_name: "vsync_sf_event_phase_offset_ns" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns" } @@ -53,7 +53,7 @@ prop { prop { api_name: "use_context_priority" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.use_context_priority" } @@ -62,7 +62,7 @@ prop { prop { api_name: "max_frame_buffer_acquired_buffers" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers" } @@ -80,7 +80,7 @@ prop { prop { api_name: "has_wide_color_display" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.has_wide_color_display" } @@ -90,7 +90,7 @@ prop { prop { api_name: "running_without_sync_framework" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.running_without_sync_framework" } @@ -108,7 +108,7 @@ prop { prop { api_name: "has_HDR_display" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.has_HDR_display" } @@ -117,7 +117,7 @@ prop { prop { api_name: "present_time_offset_from_vsync_ns" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns" } @@ -129,7 +129,7 @@ prop { prop { api_name: "force_hwc_copy_for_virtual_displays" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays" } @@ -139,7 +139,7 @@ prop { prop { api_name: "max_virtual_display_dimension" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.max_virtual_display_dimension" } @@ -151,7 +151,7 @@ prop { prop { api_name: "use_vr_flinger" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.use_vr_flinger" } @@ -161,7 +161,7 @@ prop { prop { api_name: "start_graphics_allocator_service" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.start_graphics_allocator_service" } @@ -171,7 +171,7 @@ prop { api_name: "primary_display_orientation" type: Enum enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270" - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.primary_display_orientation" } @@ -182,7 +182,7 @@ prop { prop { api_name: "use_color_management" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.use_color_management" } @@ -209,7 +209,7 @@ prop { prop { api_name: "default_composition_dataspace" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.default_composition_dataspace" } @@ -220,7 +220,7 @@ prop { prop { api_name: "default_composition_pixel_format" type: Integer - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.default_composition_pixel_format" } @@ -235,7 +235,7 @@ prop { prop { api_name: "wcg_composition_dataspace" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.wcg_composition_dataspace" } @@ -246,7 +246,7 @@ prop { prop { api_name: "wcg_composition_pixel_format" type: Integer - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.wcg_composition_pixel_format" } @@ -258,7 +258,7 @@ prop { prop { api_name: "display_primary_red" type: DoubleList - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.display_primary_red" } @@ -266,7 +266,7 @@ prop { prop { api_name: "display_primary_green" type: DoubleList - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.display_primary_green" } @@ -274,7 +274,7 @@ prop { prop { api_name: "display_primary_blue" type: DoubleList - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.display_primary_blue" } @@ -282,7 +282,7 @@ prop { prop { api_name: "display_primary_white" type: DoubleList - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.display_primary_white" } @@ -293,7 +293,7 @@ prop { prop { api_name: "set_idle_timer_ms" type: Integer - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.set_idle_timer_ms" } @@ -304,7 +304,7 @@ prop { prop { api_name: "set_touch_timer_ms" type: Integer - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.set_touch_timer_ms" } @@ -314,7 +314,7 @@ prop { prop { api_name: "use_smart_90_for_video" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.use_smart_90_for_video" } @@ -322,7 +322,7 @@ prop { prop { api_name: "enable_protected_contents" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.protected_contents" } @@ -332,7 +332,7 @@ prop { prop { api_name: "support_kernel_idle_timer" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.support_kernel_idle_timer" } -- GitLab From e8ef7b0bccd7e49bec7dc77fcf1f37d82c4e32df Mon Sep 17 00:00:00 2001 From: Calin Juravle Date: Mon, 17 Jun 2019 17:22:19 -0700 Subject: [PATCH 0040/1255] Add a separate flag in the installer for keeping ART profiles Currently this is only use in the PackageManagerService. In follow up we should use this to integrate profile clearing in the same methods as AppDataClearing. Test: manual Bug: 135299330 Change-Id: I3bafdef769d7838d8048b7df4d7a779464104641 --- cmds/installd/binder/android/os/IInstalld.aidl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 26e9984f11..d99bcc8d13 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -127,4 +127,6 @@ interface IInstalld { const int FLAG_USE_QUOTA = 0x1000; const int FLAG_FORCE = 0x2000; + + const int FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES = 0x20000; } -- GitLab From fef244ee2b3ecb326cfa33aaf85efb1490a86ea6 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 17 Jun 2019 18:07:51 -0700 Subject: [PATCH 0041/1255] Add SurfaceComposerClient::Transaction clear api When a client parcels a transaction, it is desirable to clear the transaction object since applying the transaction multiple times by different clients may not make sense. Also fixes SurfaceComposerClient::Transaction merge api to clear states like mForceSynchronous when clearing the object. Bug: 132205507 Test: go/wm-smoke Test: test preserve surfaces codepath with split screen and ensure relative z is preserved Change-Id: Iaedb3d420804ff70089817d239273c381b7ebc31 --- libs/gui/SurfaceComposerClient.cpp | 20 ++++++++++++++------ libs/gui/include/gui/SurfaceComposerClient.h | 3 +++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 3f97a969bf..c59fddfb9d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -425,7 +425,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mComposerStates[kv.first].state.merge(kv.second.state); } } - other.mComposerStates.clear(); for (auto const& state : other.mDisplayStates) { ssize_t index = mDisplayStates.indexOf(state); @@ -435,7 +434,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mDisplayStates.editItemAt(static_cast(index)).merge(state); } } - other.mDisplayStates.clear(); for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) { auto& [callbackIds, surfaceControls] = callbackInfo; @@ -446,17 +444,27 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()), std::make_move_iterator(surfaceControls.end())); } - other.mListenerCallbacks.clear(); mInputWindowCommands.merge(other.mInputWindowCommands); - other.mInputWindowCommands.clear(); mContainsBuffer = other.mContainsBuffer; - other.mContainsBuffer = false; - + other.clear(); return *this; } +void SurfaceComposerClient::Transaction::clear() { + mComposerStates.clear(); + mDisplayStates.clear(); + mListenerCallbacks.clear(); + mInputWindowCommands.clear(); + mContainsBuffer = false; + mForceSynchronous = 0; + mTransactionNestCount = 0; + mAnimation = false; + mEarlyWakeup = false; + mDesiredPresentTime = -1; +} + void SurfaceComposerClient::doDropReferenceTransaction(const sp& handle, const sp& client) { sp sf(ComposerService::getComposerService()); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 1f2947c824..4dda97f5e1 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -331,6 +331,9 @@ public: status_t writeToParcel(Parcel* parcel) const override; status_t readFromParcel(const Parcel* parcel) override; + // Clears the contents of the transaction without applying it. + void clear(); + status_t apply(bool synchronous = false); // Merge another transaction in to this one, clearing other // as if it had been applied. -- GitLab From b2b26909b61efd566db3044d53e258cd5b445166 Mon Sep 17 00:00:00 2001 From: silence_dogood Date: Tue, 18 Jun 2019 14:47:43 -0700 Subject: [PATCH 0042/1255] Revert "Cache NATIVE_WINDOW_MAX_BUFFER_COUNT in Surface" This reverts commit 12536a8fdae818ec39ae274d7da561480f4e1d61. Bug: 135538872 Bug: 133187007 Test: dEQP-VK.wsi.android.surface#query_present_modes --- libs/gui/BufferQueueProducer.cpp | 1 - libs/gui/Surface.cpp | 6 ------ libs/gui/include/gui/IGraphicBufferProducer.h | 1 - libs/gui/include/gui/Surface.h | 1 - 4 files changed, 9 deletions(-) diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index b005707fd2..9c311a314f 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1199,7 +1199,6 @@ status_t BufferQueueProducer::connect(const sp& listener, static_cast(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; output->bufferReplaced = false; - output->maxBufferCount = mCore->mMaxBufferCount; if (listener != nullptr) { // Set up a death notification so that we can disconnect diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 2e8a5d005b..e6eb327c6f 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -96,7 +96,6 @@ Surface::Surface(const sp& bufferProducer, bool controll mConnectedToCpu = false; mProducerControlledByApp = controlledByApp; mSwapIntervalZero = false; - mMaxBufferCount = 0; } Surface::~Surface() { @@ -962,10 +961,6 @@ int Surface::query(int what, int* value) const { *value = static_cast(mDataSpace); return NO_ERROR; } - case NATIVE_WINDOW_MAX_BUFFER_COUNT: { - *value = mMaxBufferCount; - return NO_ERROR; - } } } return mGraphicBufferProducer->query(what, value); @@ -1303,7 +1298,6 @@ int Surface::connect( mDefaultWidth = output.width; mDefaultHeight = output.height; mNextFrameNumber = output.nextFrameNumber; - mMaxBufferCount = output.maxBufferCount; // Ignore transform hint if sticky transform is set or transform to display inverse flag is // set. Transform hint should be ignored if the client is expected to always submit buffers diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 6e002dd505..3dde8c8c80 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -412,7 +412,6 @@ public: uint64_t nextFrameNumber{0}; FrameEventHistoryDelta frameTimestamps; bool bufferReplaced{false}; - int maxBufferCount{0}; }; virtual status_t queueBuffer(int slot, const QueueBufferInput& input, diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 80469dfeaf..0c471bb701 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -465,7 +465,6 @@ protected: bool mReportRemovedBuffers = false; std::vector> mRemovedBuffers; - int mMaxBufferCount; }; } // namespace android -- GitLab From 12abc195bac9feedcc1447855c878f9b31a9e7c8 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Tue, 18 Jun 2019 15:13:05 -0700 Subject: [PATCH 0043/1255] Fix another doxygen issue. Test: Eyeballs Bug: None Change-Id: I0eb5c82498a532c88eb13fa72b41c720c6d8537e --- include/android/system_fonts.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h index dde9055c7a..f0485a1871 100644 --- a/include/android/system_fonts.h +++ b/include/android/system_fonts.h @@ -16,7 +16,7 @@ /** * @addtogroup Font - * { + * @{ */ /** -- GitLab From e9d092a9fc53b2b559353c89a58d393a22692c34 Mon Sep 17 00:00:00 2001 From: silence_dogood Date: Wed, 19 Jun 2019 16:14:53 -0700 Subject: [PATCH 0044/1255] Cache NATIVE_WINDOW_MAX_BUFFER_COUNT in Surface To avoid the sync binder call to BufferQueue everytime vkGetPhysicalDeviceSurfaceCapabilitiesKHR and GetPhysicalDeviceSurfacePresentModesKHR are called, we cache the NATIVE_WINDOW_MAX_BUFFER_COUNT at the Surface each time the client connects. Bug: 133187007 Test: dEQP-VK.wsi.android.surface#query_present_modes, libgui_test:BufferQueueTest#GetMaxBufferCountInQueueBufferOutput_Succeeds Change-Id: I7c1a0e99d73151cd451a2f3cb173f843efd57ce1 --- libs/gui/BufferQueueProducer.cpp | 4 +--- libs/gui/IGraphicBufferProducer.cpp | 10 ++++------ libs/gui/Surface.cpp | 6 ++++++ libs/gui/include/gui/IGraphicBufferProducer.h | 1 + libs/gui/include/gui/Surface.h | 1 + libs/gui/tests/BufferQueue_test.cpp | 12 ++++++++++++ 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 9c311a314f..b9a4749ccd 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1132,9 +1132,6 @@ int BufferQueueProducer::query(int what, int *outValue) { case NATIVE_WINDOW_CONSUMER_IS_PROTECTED: value = static_cast(mCore->mConsumerIsProtected); break; - case NATIVE_WINDOW_MAX_BUFFER_COUNT: - value = static_cast(mCore->mMaxBufferCount); - break; default: return BAD_VALUE; } @@ -1199,6 +1196,7 @@ status_t BufferQueueProducer::connect(const sp& listener, static_cast(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; output->bufferReplaced = false; + output->maxBufferCount = mCore->mMaxBufferCount; if (listener != nullptr) { // Set up a death notification so that we can disconnect diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 0e03b7d393..9db0a7ca33 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -1141,12 +1141,8 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( // ---------------------------------------------------------------------------- constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() { - return sizeof(width) + - sizeof(height) + - sizeof(transformHint) + - sizeof(numPendingBuffers) + - sizeof(nextFrameNumber) + - sizeof(bufferReplaced); + return sizeof(width) + sizeof(height) + sizeof(transformHint) + sizeof(numPendingBuffers) + + sizeof(nextFrameNumber) + sizeof(bufferReplaced) + sizeof(maxBufferCount); } size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const { @@ -1170,6 +1166,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::flatten( FlattenableUtils::write(buffer, size, numPendingBuffers); FlattenableUtils::write(buffer, size, nextFrameNumber); FlattenableUtils::write(buffer, size, bufferReplaced); + FlattenableUtils::write(buffer, size, maxBufferCount); return frameTimestamps.flatten(buffer, size, fds, count); } @@ -1187,6 +1184,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::unflatten( FlattenableUtils::read(buffer, size, numPendingBuffers); FlattenableUtils::read(buffer, size, nextFrameNumber); FlattenableUtils::read(buffer, size, bufferReplaced); + FlattenableUtils::read(buffer, size, maxBufferCount); return frameTimestamps.unflatten(buffer, size, fds, count); } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e6eb327c6f..2e8a5d005b 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -96,6 +96,7 @@ Surface::Surface(const sp& bufferProducer, bool controll mConnectedToCpu = false; mProducerControlledByApp = controlledByApp; mSwapIntervalZero = false; + mMaxBufferCount = 0; } Surface::~Surface() { @@ -961,6 +962,10 @@ int Surface::query(int what, int* value) const { *value = static_cast(mDataSpace); return NO_ERROR; } + case NATIVE_WINDOW_MAX_BUFFER_COUNT: { + *value = mMaxBufferCount; + return NO_ERROR; + } } } return mGraphicBufferProducer->query(what, value); @@ -1298,6 +1303,7 @@ int Surface::connect( mDefaultWidth = output.width; mDefaultHeight = output.height; mNextFrameNumber = output.nextFrameNumber; + mMaxBufferCount = output.maxBufferCount; // Ignore transform hint if sticky transform is set or transform to display inverse flag is // set. Transform hint should be ignored if the client is expected to always submit buffers diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 3dde8c8c80..6e002dd505 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -412,6 +412,7 @@ public: uint64_t nextFrameNumber{0}; FrameEventHistoryDelta frameTimestamps; bool bufferReplaced{false}; + int maxBufferCount{0}; }; virtual status_t queueBuffer(int slot, const QueueBufferInput& input, diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 0c471bb701..80469dfeaf 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -465,6 +465,7 @@ protected: bool mReportRemovedBuffers = false; std::vector> mRemovedBuffers; + int mMaxBufferCount; }; } // namespace android diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 119e888edb..98dc1e6337 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -169,6 +169,18 @@ TEST_F(BufferQueueTest, DISABLED_BufferQueueInAnotherProcess) { ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } +TEST_F(BufferQueueTest, GetMaxBufferCountInQueueBufferOutput_Succeeds) { + createBufferQueue(); + sp dc(new DummyConsumer); + mConsumer->consumerConnect(dc, false); + int bufferCount = 50; + mConsumer->setMaxBufferCount(bufferCount); + + IGraphicBufferProducer::QueueBufferOutput output; + mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &output); + ASSERT_EQ(output.maxBufferCount, bufferCount); +} + TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { createBufferQueue(); sp dc(new DummyConsumer); -- GitLab From cf9bc5fd7558f3806b91b15db6a733f2785c7fa4 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 6 Jun 2019 17:29:18 -0700 Subject: [PATCH 0045/1255] libtimeinstate: fix map names The maps defined by the time_in_state.c BPF program now have names ending with "_map", so update our calls to bpf_obj_get() to reflect that. Test: libtimeinstate_test passes Bug: 78498733 Change-Id: If13df157c0245561eee3efa2a9c5a04f339ca194 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/cputimeinstate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 5fd4a95d7b..4ba66a5066 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -124,7 +124,7 @@ static bool initGlobals() { gPolicyCpus.emplace_back(cpus); } - gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times")}; + gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")}; if (gMapFd < 0) return false; gInitialized = true; @@ -196,7 +196,7 @@ bool getUidsCpuFreqTimes( std::unordered_map>> *freqTimeMap) { if (!gInitialized && !initGlobals()) return false; - int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times"); + int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map"); if (fd < 0) return false; BpfMap m(fd); -- GitLab From 4b9c498812c5f3635c941483a6fec19cb432bcb8 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 5 Jun 2019 18:03:12 -0700 Subject: [PATCH 0046/1255] libtimeinstate: use std::optional Simplify the interface and implementation of libtimeinstate by using std::optional instead of output parameters. Test: libtimeinstate_test passes Bug: 78498733 Change-Id: I97b697c9b51c31245b3c141eff063eba865f5d73 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/cputimeinstate.cpp | 65 +++++++++++++------------ libs/cputimeinstate/cputimeinstate.h | 5 +- libs/cputimeinstate/testtimeinstate.cpp | 37 +++++++------- 3 files changed, 56 insertions(+), 51 deletions(-) diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 4ba66a5066..41cbde1c18 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -62,19 +63,20 @@ static std::vector> gPolicyCpus; static std::set gAllFreqs; static unique_fd gMapFd; -static bool readNumbersFromFile(const std::string &path, std::vector *out) { +static std::optional> readNumbersFromFile(const std::string &path) { std::string data; - if (!android::base::ReadFileToString(path, &data)) return false; + if (!android::base::ReadFileToString(path, &data)) return {}; auto strings = android::base::Split(data, " \n"); + std::vector ret; for (const auto &s : strings) { if (s.empty()) continue; uint32_t n; - if (!android::base::ParseUint(s, &n)) return false; - out->emplace_back(n); + if (!android::base::ParseUint(s, &n)) return {}; + ret.emplace_back(n); } - return true; + return ret; } static int isPolicyFile(const struct dirent *d) { @@ -111,17 +113,19 @@ static bool initGlobals() { for (const auto &name : {"available", "boost"}) { std::string path = StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name); - if (!readNumbersFromFile(path, &freqs)) return false; + auto nums = readNumbersFromFile(path); + if (!nums) return false; + freqs.insert(freqs.end(), nums->begin(), nums->end()); } std::sort(freqs.begin(), freqs.end()); gPolicyFreqs.emplace_back(freqs); for (auto freq : freqs) gAllFreqs.insert(freq); - std::vector cpus; std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus"); - if (!readNumbersFromFile(path, &cpus)) return false; - gPolicyCpus.emplace_back(cpus); + auto cpus = readNumbersFromFile(path); + if (!cpus) return false; + gPolicyCpus.emplace_back(*cpus); } gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")}; @@ -151,17 +155,15 @@ bool startTrackingUidCpuFreqTimes() { } // Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes. -// Returns false on error. Otherwise, returns true and populates freqTimes with a vector of vectors -// using the format: +// Return contains no value on error, otherwise it contains a vector of vectors using the format: // [[t0_0, t0_1, ...], // [t1_0, t1_1, ...], ...] // where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq. -bool getUidCpuFreqTimes(uint32_t uid, std::vector> *freqTimes) { - if (!gInitialized && !initGlobals()) return false; +std::optional>> getUidCpuFreqTimes(uint32_t uid) { + if (!gInitialized && !initGlobals()) return {}; time_key_t key = {.uid = uid, .freq = 0}; - freqTimes->clear(); - freqTimes->resize(gNPolicies); + std::vector> out(gNPolicies); std::vector idxs(gNPolicies, 0); val_t value; @@ -172,32 +174,32 @@ bool getUidCpuFreqTimes(uint32_t uid, std::vector> *freqTi if (errno == ENOENT) memset(&value.ar, 0, sizeof(value.ar)); else - return false; + return {}; } for (uint32_t i = 0; i < gNPolicies; ++i) { if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue; uint64_t time = 0; for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu]; idxs[i] += 1; - (*freqTimes)[i].emplace_back(time); + out[i].emplace_back(time); } } - return true; + return out; } // Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap. -// Returns false on error. Otherwise, returns true and populates freqTimeMap with a map from uids to -// vectors of vectors using the format: +// Return contains no value on error, otherwise it contains a map from uids to vectors of vectors +// using the format: // { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...], // uid1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... } // where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq. -bool getUidsCpuFreqTimes( - std::unordered_map>> *freqTimeMap) { - if (!gInitialized && !initGlobals()) return false; +std::optional>>> +getUidsCpuFreqTimes() { + if (!gInitialized && !initGlobals()) return {}; int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map"); - if (fd < 0) return false; + if (fd < 0) return {}; BpfMap m(fd); std::vector> policyFreqIdxs; @@ -206,25 +208,26 @@ bool getUidsCpuFreqTimes( for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j; policyFreqIdxs.emplace_back(freqIdxs); } - - auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val, + std::unordered_map>> map; + auto fn = [&map, &policyFreqIdxs](const time_key_t &key, const val_t &val, const BpfMap &) { - if (freqTimeMap->find(key.uid) == freqTimeMap->end()) { - (*freqTimeMap)[key.uid].resize(gNPolicies); + if (map.find(key.uid) == map.end()) { + map[key.uid].resize(gNPolicies); for (uint32_t i = 0; i < gNPolicies; ++i) { - (*freqTimeMap)[key.uid][i].resize(gPolicyFreqs[i].size(), 0); + map[key.uid][i].resize(gPolicyFreqs[i].size(), 0); } } for (size_t policy = 0; policy < gNPolicies; ++policy) { for (const auto &cpu : gPolicyCpus[policy]) { auto freqIdx = policyFreqIdxs[policy][key.freq]; - (*freqTimeMap)[key.uid][policy][freqIdx] += val.ar[cpu]; + map[key.uid][policy][freqIdx] += val.ar[cpu]; } } return android::netdutils::status::ok; }; - return isOk(m.iterateWithValue(fn)); + if (isOk(m.iterateWithValue(fn))) return map; + return {}; } // Clear all time in state data for a given uid. Returns false on error, true otherwise. diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h index 9f6103ed9b..d7b45870ac 100644 --- a/libs/cputimeinstate/cputimeinstate.h +++ b/libs/cputimeinstate/cputimeinstate.h @@ -23,8 +23,9 @@ namespace android { namespace bpf { bool startTrackingUidCpuFreqTimes(); -bool getUidCpuFreqTimes(unsigned int uid, std::vector> *freqTimes); -bool getUidsCpuFreqTimes(std::unordered_map>> *tisMap); +std::optional>> getUidCpuFreqTimes(uint32_t uid); +std::optional>>> + getUidsCpuFreqTimes(); bool clearUidCpuFreqTimes(unsigned int uid); } // namespace bpf diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 9837865dfb..d4b87386e0 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -12,45 +12,46 @@ namespace bpf { using std::vector; TEST(TimeInStateTest, SingleUid) { - vector> times; - ASSERT_TRUE(getUidCpuFreqTimes(0, ×)); - EXPECT_FALSE(times.empty()); + auto times = getUidCpuFreqTimes(0); + ASSERT_TRUE(times.has_value()); + EXPECT_FALSE(times->empty()); } TEST(TimeInStateTest, AllUid) { vector sizes; - std::unordered_map>> map; - ASSERT_TRUE(getUidsCpuFreqTimes(&map)); + auto map = getUidsCpuFreqTimes(); + ASSERT_TRUE(map.has_value()); - ASSERT_FALSE(map.empty()); + ASSERT_FALSE(map->empty()); - auto firstEntry = map.begin()->second; + auto firstEntry = map->begin()->second; for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size()); - for (const auto &vec : map) { + for (const auto &vec : *map) { ASSERT_EQ(vec.second.size(), sizes.size()); for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]); } } TEST(TimeInStateTest, RemoveUid) { - vector> times, times2; - ASSERT_TRUE(getUidCpuFreqTimes(0, ×)); - ASSERT_FALSE(times.empty()); + auto times = getUidCpuFreqTimes(0); + ASSERT_TRUE(times.has_value()); + ASSERT_FALSE(times->empty()); uint64_t sum = 0; - for (size_t i = 0; i < times.size(); ++i) { - for (auto x : times[i]) sum += x; + for (size_t i = 0; i < times->size(); ++i) { + for (auto x : (*times)[i]) sum += x; } ASSERT_GT(sum, (uint64_t)0); ASSERT_TRUE(clearUidCpuFreqTimes(0)); - ASSERT_TRUE(getUidCpuFreqTimes(0, ×2)); - ASSERT_EQ(times2.size(), times.size()); - for (size_t i = 0; i < times.size(); ++i) { - ASSERT_EQ(times2[i].size(), times[i].size()); - for (size_t j = 0; j < times[i].size(); ++j) ASSERT_LE(times2[i][j], times[i][j]); + auto times2 = getUidCpuFreqTimes(0); + ASSERT_TRUE(times2.has_value()); + ASSERT_EQ(times2->size(), times->size()); + for (size_t i = 0; i < times->size(); ++i) { + ASSERT_EQ((*times2)[i].size(), (*times)[i].size()); + for (size_t j = 0; j < (*times)[i].size(); ++j) ASSERT_LE((*times2)[i][j], (*times)[i][j]); } } -- GitLab From 5e8622099e35b8d18062ba79c9d1fc062cb9598a Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Fri, 21 Jun 2019 14:59:16 -0700 Subject: [PATCH 0047/1255] Vulkan: clean up android::Vector in the loader Bug: 134185757 Test: CtsDeqpTestCases Test: CtsGraphicsTestCases Test: CtsGpuToolsHostTestCases Change-Id: Ic8080e822f2b1788eee672cfffa664f9bd29b9be --- vulkan/libvulkan/driver.cpp | 40 +++++++++++++++------------------- vulkan/libvulkan/swapchain.cpp | 24 ++++++++++---------- 2 files changed, 29 insertions(+), 35 deletions(-) diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 23506bad54..d33e5528e8 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -16,30 +16,29 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include "driver.h" + +#include #include #include #include -#include - -#include -#include -#include -#include - -#include #include #include +#include #include #include #include +#include +#include #include #include -#include -#include "android-base/properties.h" +#include +#include +#include +#include -#include "driver.h" #include "stubhal.h" using namespace android::hardware::configstore; @@ -809,8 +808,7 @@ VkResult EnumerateInstanceExtensionProperties( const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) { - - android::Vector loader_extensions; + std::vector loader_extensions; loader_extensions.push_back({ VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION}); @@ -833,7 +831,7 @@ VkResult EnumerateInstanceExtensionProperties( uint32_t count = std::min( *pPropertyCount, static_cast(loader_extensions.size())); - std::copy_n(loader_extensions.begin(), count, pProperties); + std::copy_n(loader_extensions.data(), count, pProperties); if (count < loader_extensions.size()) { *pPropertyCount = count; @@ -879,8 +877,7 @@ VkResult EnumerateInstanceExtensionProperties( bool QueryPresentationProperties( VkPhysicalDevice physicalDevice, - VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties) -{ + VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties) { const InstanceData& data = GetData(physicalDevice); // GPDP2 must be present and enabled on the instance. @@ -920,7 +917,7 @@ VkResult EnumerateDeviceExtensionProperties( VkExtensionProperties* pProperties) { const InstanceData& data = GetData(physicalDevice); // extensions that are unconditionally exposed by the loader - android::Vector loader_extensions; + std::vector loader_extensions; loader_extensions.push_back({ VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION}); @@ -956,7 +953,7 @@ VkResult EnumerateDeviceExtensionProperties( uint32_t count = std::min( *pPropertyCount, static_cast(loader_extensions.size())); - std::copy_n(loader_extensions.begin(), count, pProperties); + std::copy_n(loader_extensions.data(), count, pProperties); if (count < loader_extensions.size()) { *pPropertyCount = count; @@ -1245,11 +1242,10 @@ VkResult EnumeratePhysicalDeviceGroups( if (!device_count) return VK_INCOMPLETE; - android::Vector devices; - devices.resize(device_count); + std::vector devices(device_count); *pPhysicalDeviceGroupCount = device_count; - result = EnumeratePhysicalDevices(instance, &device_count, - devices.editArray()); + result = + EnumeratePhysicalDevices(instance, &device_count, devices.data()); if (result < 0) return result; diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 524fe0e594..761d128d79 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -132,7 +131,6 @@ int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) { class TimingInfo { public: - TimingInfo() = default; TimingInfo(const VkPresentTimeGOOGLE* qp, uint64_t nativeFrameId) : vals_{qp->presentID, qp->desiredPresentTime, 0, 0, 0}, native_frame_id_(nativeFrameId) {} @@ -266,7 +264,7 @@ struct Swapchain { bool dequeued; } images[android::BufferQueueDefs::NUM_BUFFER_SLOTS]; - android::Vector timing; + std::vector timing; }; VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) { @@ -349,7 +347,7 @@ uint32_t get_num_ready_timings(Swapchain& swapchain) { uint32_t num_ready = 0; const size_t num_timings = swapchain.timing.size() - MIN_NUM_FRAMES_AGO + 1; for (uint32_t i = 0; i < num_timings; i++) { - TimingInfo& ti = swapchain.timing.editItemAt(i); + TimingInfo& ti = swapchain.timing[i]; if (ti.ready()) { // This TimingInfo is ready to be reported to the user. Add it // to the num_ready. @@ -419,7 +417,7 @@ void copy_ready_timings(Swapchain& swapchain, } uint32_t num_copied = 0; - size_t num_to_remove = 0; + int32_t num_to_remove = 0; for (uint32_t i = 0; i <= last_ready && num_copied < *count; i++) { const TimingInfo& ti = swapchain.timing[i]; if (ti.ready()) { @@ -431,7 +429,8 @@ void copy_ready_timings(Swapchain& swapchain, // Discard old frames that aren't ready if newer frames are ready. // We don't expect to get the timing info for those old frames. - swapchain.timing.removeItemsAt(0, num_to_remove); + swapchain.timing.erase(swapchain.timing.begin(), + swapchain.timing.begin() + num_to_remove); *count = num_copied; } @@ -817,11 +816,10 @@ VkResult GetPhysicalDeviceSurfaceFormats2KHR( } else { // temp vector for forwarding; we'll marshal it into the pSurfaceFormats // after the call. - android::Vector surface_formats; - surface_formats.resize(*pSurfaceFormatCount); + std::vector surface_formats(*pSurfaceFormatCount); VkResult result = GetPhysicalDeviceSurfaceFormatsKHR( physicalDevice, pSurfaceInfo->surface, pSurfaceFormatCount, - &surface_formats.editItemAt(0)); + surface_formats.data()); if (result == VK_SUCCESS || result == VK_INCOMPLETE) { // marshal results individually due to stride difference. @@ -863,7 +861,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, } uint32_t max_buffer_count = static_cast(query_value); - android::Vector present_modes; + std::vector present_modes; if (min_undequeued_buffers + 1 < max_buffer_count) present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR); present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR); @@ -883,7 +881,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, if (*count < num_modes) result = VK_INCOMPLETE; *count = std::min(*count, num_modes); - std::copy(present_modes.begin(), present_modes.begin() + int(*count), modes); + std::copy_n(present_modes.data(), *count, modes); } else { *count = num_modes; } @@ -1647,9 +1645,9 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { // Add a new timing record with the user's presentID and // the nativeFrameId. - swapchain.timing.push_back(TimingInfo(time, nativeFrameId)); + swapchain.timing.emplace_back(time, nativeFrameId); while (swapchain.timing.size() > MAX_TIMING_INFOS) { - swapchain.timing.removeAt(0); + swapchain.timing.erase(swapchain.timing.begin()); } if (time->desiredPresentTime) { // Set the desiredPresentTime: -- GitLab From 88e20481b3b31c20b1857b44a541dc870a2fdb40 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Mon, 24 Jun 2019 10:49:42 -0700 Subject: [PATCH 0048/1255] blast: ordering layer death and callbacks There is an edge case where Transaction callbacks don't contain all the SurfaceControls that the Transaction had. This happens if: 1) A transaction is applied in the app process 2) A surface control is released/destroyed in the app process 3) The surface control is destroyed in surfaceflinger 4) The transaction is applied in surfaceflinger If the layer associated with the surface control is removed from surfaceflinger, the surface control won't be added to the callback. We need to add the surface control as unpresented to the callback once we realize the layer no longer exists. Bug: 135766997 Test: Transaction_test Change-Id: Ia7d7f15ead736c8a17343ceec84c8515a7000bbe --- services/surfaceflinger/SurfaceFlinger.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a96305e473..f92df61a64 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3931,6 +3931,11 @@ uint32_t SurfaceFlinger::setClientStateLocked( sp layer(client->getLayerUser(s.surface)); if (layer == nullptr) { + for (auto& listenerCallback : listenerCallbacks) { + mTransactionCompletedThread.addUnpresentedCallbackHandle( + new CallbackHandle(listenerCallback.transactionCompletedListener, + listenerCallback.callbackIds, s.surface)); + } return 0; } -- GitLab From f2c006d5fac9cfb2e5eb3ef8c960b5eab72af0ed Mon Sep 17 00:00:00 2001 From: Ana Krulec Date: Fri, 21 Jun 2019 15:37:07 -0700 Subject: [PATCH 0049/1255] SF: Renaming IdleTimer to OneShotTimer IdleTimer class is used for more than just idle timer, so renaming the class to a more appropriate name. Test: manual Bug: 132811842 Change-Id: Iabfaa28038dc90430a51536ef874618e35ed9014 --- services/surfaceflinger/Android.bp | 2 +- .../surfaceflinger/RegionSamplingThread.h | 4 +- .../{IdleTimer.cpp => OneShotTimer.cpp} | 18 ++--- .../Scheduler/{IdleTimer.h => OneShotTimer.h} | 8 +-- .../surfaceflinger/Scheduler/Scheduler.cpp | 29 ++++----- services/surfaceflinger/Scheduler/Scheduler.h | 6 +- .../surfaceflinger/tests/unittests/Android.bp | 2 +- ...IdleTimerTest.cpp => OneShotTimerTest.cpp} | 65 ++++++++++--------- 8 files changed, 65 insertions(+), 69 deletions(-) rename services/surfaceflinger/Scheduler/{IdleTimer.cpp => OneShotTimer.cpp} (88%) rename services/surfaceflinger/Scheduler/{IdleTimer.h => OneShotTimer.h} (93%) rename services/surfaceflinger/tests/unittests/{IdleTimerTest.cpp => OneShotTimerTest.cpp} (75%) diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 5b298b4a93..6e953f4af6 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -149,7 +149,7 @@ filegroup { "Scheduler/DispSyncSource.cpp", "Scheduler/EventControlThread.cpp", "Scheduler/EventThread.cpp", - "Scheduler/IdleTimer.cpp", + "Scheduler/OneShotTimer.cpp", "Scheduler/LayerHistory.cpp", "Scheduler/LayerInfo.cpp", "Scheduler/MessageQueue.cpp", diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h index 3c6fcf3872..ac7339c42a 100644 --- a/services/surfaceflinger/RegionSamplingThread.h +++ b/services/surfaceflinger/RegionSamplingThread.h @@ -27,7 +27,7 @@ #include #include #include -#include "Scheduler/IdleTimer.h" +#include "Scheduler/OneShotTimer.h" namespace android { @@ -107,7 +107,7 @@ private: SurfaceFlinger& mFlinger; Scheduler& mScheduler; const TimingTunables mTunables; - scheduler::IdleTimer mIdleTimer; + scheduler::OneShotTimer mIdleTimer; std::unique_ptr const mPhaseCallback; diff --git a/services/surfaceflinger/Scheduler/IdleTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp similarity index 88% rename from services/surfaceflinger/Scheduler/IdleTimer.cpp rename to services/surfaceflinger/Scheduler/OneShotTimer.cpp index 37fdfc7c62..4870a3bbdd 100644 --- a/services/surfaceflinger/Scheduler/IdleTimer.cpp +++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "IdleTimer.h" +#include "OneShotTimer.h" #include #include @@ -22,23 +22,23 @@ namespace android { namespace scheduler { -IdleTimer::IdleTimer(const Interval& interval, const ResetCallback& resetCallback, - const TimeoutCallback& timeoutCallback) +OneShotTimer::OneShotTimer(const Interval& interval, const ResetCallback& resetCallback, + const TimeoutCallback& timeoutCallback) : mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {} -IdleTimer::~IdleTimer() { +OneShotTimer::~OneShotTimer() { stop(); } -void IdleTimer::start() { +void OneShotTimer::start() { { std::lock_guard lock(mMutex); mState = TimerState::RESET; } - mThread = std::thread(&IdleTimer::loop, this); + mThread = std::thread(&OneShotTimer::loop, this); } -void IdleTimer::stop() { +void OneShotTimer::stop() { { std::lock_guard lock(mMutex); mState = TimerState::STOPPED; @@ -49,7 +49,7 @@ void IdleTimer::stop() { } } -void IdleTimer::loop() { +void OneShotTimer::loop() { while (true) { bool triggerReset = false; bool triggerTimeout = false; @@ -100,7 +100,7 @@ void IdleTimer::loop() { } } // namespace scheduler -void IdleTimer::reset() { +void OneShotTimer::reset() { { std::lock_guard lock(mMutex); mState = TimerState::RESET; diff --git a/services/surfaceflinger/Scheduler/IdleTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h similarity index 93% rename from services/surfaceflinger/Scheduler/IdleTimer.h rename to services/surfaceflinger/Scheduler/OneShotTimer.h index 2646688860..fd1aa02226 100644 --- a/services/surfaceflinger/Scheduler/IdleTimer.h +++ b/services/surfaceflinger/Scheduler/OneShotTimer.h @@ -29,15 +29,15 @@ namespace scheduler { * Class that sets off a timer for a given interval, and fires a callback when the * interval expires. */ -class IdleTimer { +class OneShotTimer { public: using Interval = std::chrono::milliseconds; using ResetCallback = std::function; using TimeoutCallback = std::function; - IdleTimer(const Interval& interval, const ResetCallback& resetCallback, - const TimeoutCallback& timeoutCallback); - ~IdleTimer(); + OneShotTimer(const Interval& interval, const ResetCallback& resetCallback, + const TimeoutCallback& timeoutCallback); + ~OneShotTimer(); // Initializes and turns on the idle timer. void start(); diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index bb24f73834..e393f1b2a6 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -38,9 +38,9 @@ #include "DispSyncSource.h" #include "EventControlThread.h" #include "EventThread.h" -#include "IdleTimer.h" #include "InjectVSyncSource.h" #include "LayerInfo.h" +#include "OneShotTimer.h" #include "SchedulerUtils.h" #include "SurfaceFlingerProperties.h" @@ -86,34 +86,29 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, if (mSetIdleTimerMs > 0) { if (mSupportKernelTimer) { - mIdleTimer = - std::make_unique(std::chrono::milliseconds( - mSetIdleTimerMs), - [this] { resetKernelTimerCallback(); }, - [this] { - expiredKernelTimerCallback(); - }); + mIdleTimer = std::make_unique( + std::chrono::milliseconds(mSetIdleTimerMs), + [this] { resetKernelTimerCallback(); }, + [this] { expiredKernelTimerCallback(); }); } else { - mIdleTimer = std::make_unique(std::chrono::milliseconds( - mSetIdleTimerMs), - [this] { resetTimerCallback(); }, - [this] { expiredTimerCallback(); }); + mIdleTimer = std::make_unique( + std::chrono::milliseconds(mSetIdleTimerMs), [this] { resetTimerCallback(); }, + [this] { expiredTimerCallback(); }); } mIdleTimer->start(); } if (mSetTouchTimerMs > 0) { // Touch events are coming to SF every 100ms, so the timer needs to be higher than that - mTouchTimer = - std::make_unique(std::chrono::milliseconds(mSetTouchTimerMs), - [this] { resetTouchTimerCallback(); }, - [this] { expiredTouchTimerCallback(); }); + mTouchTimer = std::make_unique( + std::chrono::milliseconds(mSetTouchTimerMs), [this] { resetTouchTimerCallback(); }, + [this] { expiredTouchTimerCallback(); }); mTouchTimer->start(); } } Scheduler::~Scheduler() { - // Ensure the IdleTimer thread is joined before we start destroying state. + // Ensure the OneShotTimer threads are joined before we start destroying state. mTouchTimer.reset(); mIdleTimer.reset(); } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index eaad37c3ee..a30776059f 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -26,9 +26,9 @@ #include "DispSync.h" #include "EventControlThread.h" #include "EventThread.h" -#include "IdleTimer.h" #include "InjectVSyncSource.h" #include "LayerHistory.h" +#include "OneShotTimer.h" #include "RefreshRateConfigs.h" #include "SchedulerUtils.h" @@ -273,14 +273,14 @@ private: // Timer that records time between requests for next vsync. If the time is higher than a given // interval, a callback is fired. Set this variable to >0 to use this feature. int64_t mSetIdleTimerMs = 0; - std::unique_ptr mIdleTimer; + std::unique_ptr mIdleTimer; // Enables whether to use idle timer callbacks that support the kernel // timer. bool mSupportKernelTimer; // Timer used to monitor touch events. int64_t mSetTouchTimerMs = 0; - std::unique_ptr mTouchTimer; + std::unique_ptr mTouchTimer; std::mutex mCallbackLock; ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock); diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index f842d61c7f..4917bc2a51 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -42,7 +42,7 @@ cc_test { "DisplayTransactionTest.cpp", "EventControlThreadTest.cpp", "EventThreadTest.cpp", - "IdleTimerTest.cpp", + "OneShotTimerTest.cpp", "LayerHistoryTest.cpp", "LayerMetadataTest.cpp", "SchedulerTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp similarity index 75% rename from services/surfaceflinger/tests/unittests/IdleTimerTest.cpp rename to services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp index eff22b6640..0208728026 100644 --- a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp +++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp @@ -21,17 +21,17 @@ #include #include "AsyncCallRecorder.h" -#include "Scheduler/IdleTimer.h" +#include "Scheduler/OneShotTimer.h" using namespace std::chrono_literals; namespace android { namespace scheduler { -class IdleTimerTest : public testing::Test { +class OneShotTimerTest : public testing::Test { protected: - IdleTimerTest() = default; - ~IdleTimerTest() override = default; + OneShotTimerTest() = default; + ~OneShotTimerTest() override = default; // This timeout should be used when a 3ms callback is expected. // While the tests typically request a callback after 3ms, the scheduler @@ -46,7 +46,7 @@ protected: AsyncCallRecorder mResetTimerCallback; AsyncCallRecorder mExpiredTimerCallback; - std::unique_ptr mIdleTimer; + std::unique_ptr mIdleTimer; void clearPendingCallbacks() { while (mExpiredTimerCallback.waitForCall(0us).has_value()) { @@ -55,13 +55,14 @@ protected: }; namespace { -TEST_F(IdleTimerTest, createAndDestroyTest) { - mIdleTimer = std::make_unique(3ms, [] {}, [] {}); +TEST_F(OneShotTimerTest, createAndDestroyTest) { + mIdleTimer = std::make_unique( + 3ms, [] {}, [] {}); } -TEST_F(IdleTimerTest, startStopTest) { - mIdleTimer = std::make_unique(30ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, startStopTest) { + mIdleTimer = std::make_unique(30ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); auto startTime = std::chrono::steady_clock::now(); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -70,7 +71,7 @@ TEST_F(IdleTimerTest, startStopTest) { bool callbackCalled = mExpiredTimerCallback.waitForCall(25ms).has_value(); // Under ideal conditions there should be no event. But occasionally // it is possible that the wait just prior takes more than 30ms, and - // a callback is observed. We check the elapsed time since before the IdleTimer + // a callback is observed. We check the elapsed time since before the OneShotTimer // thread was started as a sanity check to not have a flakey test. EXPECT_FALSE(callbackCalled && std::chrono::steady_clock::now() - startTime < 30ms); @@ -79,9 +80,9 @@ TEST_F(IdleTimerTest, startStopTest) { mIdleTimer->stop(); } -TEST_F(IdleTimerTest, resetTest) { - mIdleTimer = std::make_unique(20ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, resetTest) { + mIdleTimer = std::make_unique(20ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); // Observe any event that happens in about 25ms. We don't care if one was @@ -104,9 +105,9 @@ TEST_F(IdleTimerTest, resetTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); } -TEST_F(IdleTimerTest, resetBackToBackTest) { - mIdleTimer = std::make_unique(20ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, resetBackToBackTest) { + mIdleTimer = std::make_unique(20ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -135,9 +136,9 @@ TEST_F(IdleTimerTest, resetBackToBackTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); } -TEST_F(IdleTimerTest, startNotCalledTest) { - mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, startNotCalledTest) { + mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); // The start hasn't happened, so the callback does not happen. EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value()); EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value()); @@ -147,9 +148,9 @@ TEST_F(IdleTimerTest, startNotCalledTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); } -TEST_F(IdleTimerTest, idleTimerIdlesTest) { - mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, idleTimerIdlesTest) { + mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -167,18 +168,18 @@ TEST_F(IdleTimerTest, idleTimerIdlesTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); } -TEST_F(IdleTimerTest, timeoutCallbackExecutionTest) { - mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) { + mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value()); mIdleTimer->stop(); } -TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) { - mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) { + mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value()); @@ -190,9 +191,9 @@ TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value()); } -TEST_F(IdleTimerTest, noCallbacksAfterStopTest) { - mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) { + mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); -- GitLab From 3e092daa14c63831d76d3ad6e56b2919a0523536 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 21 Jun 2019 12:35:59 -0700 Subject: [PATCH 0050/1255] servicemanager: use libbinder Bug: 135768100 Test: boot Test: servicemanager_test Change-Id: I9d657b6c0d0be0f763b6d54e0e6c6bc1c1e3fc7a --- cmds/servicemanager/Access.cpp | 140 ++++ cmds/servicemanager/Access.h | 59 ++ cmds/servicemanager/Android.bp | 54 +- cmds/servicemanager/ServiceManager.cpp | 144 ++++ cmds/servicemanager/ServiceManager.h | 47 ++ cmds/servicemanager/TEST_MAPPING | 7 + cmds/servicemanager/bctest.c | 107 --- cmds/servicemanager/binder.c | 682 ------------------ cmds/servicemanager/binder.h | 94 --- cmds/servicemanager/main.cpp | 54 ++ cmds/servicemanager/service_manager.c | 442 ------------ cmds/servicemanager/test_sm.cpp | 261 +++++++ libs/binder/Android.bp | 4 +- libs/binder/IPCThreadState.cpp | 2 +- libs/binder/IServiceManager.cpp | 58 +- .../aidl/android/os/IServiceManager.aidl | 80 ++ libs/binder/include/binder/IPCThreadState.h | 2 + 17 files changed, 851 insertions(+), 1386 deletions(-) create mode 100644 cmds/servicemanager/Access.cpp create mode 100644 cmds/servicemanager/Access.h create mode 100644 cmds/servicemanager/ServiceManager.cpp create mode 100644 cmds/servicemanager/ServiceManager.h create mode 100644 cmds/servicemanager/TEST_MAPPING delete mode 100644 cmds/servicemanager/bctest.c delete mode 100644 cmds/servicemanager/binder.c delete mode 100644 cmds/servicemanager/binder.h create mode 100644 cmds/servicemanager/main.cpp delete mode 100644 cmds/servicemanager/service_manager.c create mode 100644 cmds/servicemanager/test_sm.cpp create mode 100644 libs/binder/aidl/android/os/IServiceManager.aidl diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp new file mode 100644 index 0000000000..f4005c4dee --- /dev/null +++ b/cmds/servicemanager/Access.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 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 "Access.h" + +#include +#include +#include +#include +#include + +namespace android { + +#ifdef VENDORSERVICEMANAGER +constexpr bool kIsVendor = true; +#else +constexpr bool kIsVendor = false; +#endif + +static std::string getPidcon(pid_t pid) { + android_errorWriteLog(0x534e4554, "121035042"); + + char* lookup = nullptr; + if (getpidcon(pid, &lookup) < 0) { + LOG(ERROR) << "SELinux: getpidcon(pid=" << pid << ") failed to retrieve pid context"; + return ""; + } + std::string result = lookup; + freecon(lookup); + return result; +} + +static struct selabel_handle* getSehandle() { + static struct selabel_handle* gSehandle = nullptr; + + if (gSehandle != nullptr && selinux_status_updated()) { + selabel_close(gSehandle); + gSehandle = nullptr; + } + + if (gSehandle == nullptr) { + gSehandle = kIsVendor + ? selinux_android_vendor_service_context_handle() + : selinux_android_service_context_handle(); + } + + CHECK(gSehandle != nullptr); + return gSehandle; +} + +static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) { + const Access::CallingContext* ad = reinterpret_cast(data); + + if (!ad) { + LOG(ERROR) << "No service manager audit data"; + return 0; + } + + snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name.c_str(), ad->debugPid, ad->uid); + return 0; +} + +Access::Access() { + union selinux_callback cb; + + cb.func_audit = auditCallback; + selinux_set_callback(SELINUX_CB_AUDIT, cb); + + cb.func_log = kIsVendor ? selinux_vendor_log_callback : selinux_log_callback; + selinux_set_callback(SELINUX_CB_LOG, cb); + + CHECK(selinux_status_open(true /*fallback*/) >= 0); + + CHECK(getcon(&mThisProcessContext) == 0); +} + +Access::~Access() { + freecon(mThisProcessContext); +} + +Access::CallingContext Access::getCallingContext(const std::string& name) { + IPCThreadState* ipc = IPCThreadState::self(); + + const char* callingSid = ipc->getCallingSid(); + pid_t callingPid = ipc->getCallingPid(); + + return CallingContext { + .debugPid = callingPid, + .uid = ipc->getCallingUid(), + .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid), + .name = name, + }; +} + +bool Access::canFind(const CallingContext& ctx) { + return actionAllowedFromLookup(ctx, "find"); +} + +bool Access::canAdd(const CallingContext& ctx) { + return actionAllowedFromLookup(ctx, "add"); +} + +bool Access::canList(const CallingContext& ctx) { + CHECK(ctx.name == ""); + + return actionAllowed(ctx, mThisProcessContext, "list"); +} + +bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm) { + const char* tclass = "service_manager"; + + return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm, reinterpret_cast(const_cast((&sctx)))); +} + +bool Access::actionAllowedFromLookup(const CallingContext& sctx, const char *perm) { + char *tctx = nullptr; + if (selabel_lookup(getSehandle(), &tctx, sctx.name.c_str(), 0) != 0) { + LOG(ERROR) << "SELinux: No match for " << sctx.name << " in service_contexts.\n"; + return false; + } + + bool allowed = actionAllowed(sctx, tctx, perm); + freecon(tctx); + return allowed; +} + +} // android diff --git a/cmds/servicemanager/Access.h b/cmds/servicemanager/Access.h new file mode 100644 index 0000000000..b2c78cc34d --- /dev/null +++ b/cmds/servicemanager/Access.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 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 +#include + +namespace android { + +// singleton +class Access { +public: + Access(); + virtual ~Access(); + + Access(const Access&) = delete; + Access& operator=(const Access&) = delete; + Access(Access&&) = delete; + Access& operator=(Access&&) = delete; + + struct CallingContext { + pid_t debugPid; + uid_t uid; + std::string sid; + + // name of the service + // + // empty if call is unrelated to service (e.g. list) + std::string name; + }; + + virtual CallingContext getCallingContext(const std::string& name); + + virtual bool canFind(const CallingContext& ctx); + virtual bool canAdd(const CallingContext& ctx); + virtual bool canList(const CallingContext& ctx); + +private: + bool actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm); + bool actionAllowedFromLookup(const CallingContext& sctx, const char *perm); + + char* mThisProcessContext = nullptr; +}; + +}; diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 428561bc8a..9cf3c5c134 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -1,51 +1,51 @@ cc_defaults { - name: "servicemanager_flags", + name: "servicemanager_defaults", cflags: [ "-Wall", "-Wextra", "-Werror", ], - product_variables: { - binder32bit: { - cflags: ["-DBINDER_IPC_32BIT=1"], - }, - }, - shared_libs: ["liblog"], -} - -cc_binary { - name: "bctest", - defaults: ["servicemanager_flags"], srcs: [ - "bctest.c", - "binder.c", + "Access.cpp", + "ServiceManager.cpp", + ], + + shared_libs: [ + "libbase", + "libbinder", // also contains servicemanager_interface + "libcutils", + "liblog", + "libutils", + "libselinux", ], } cc_binary { name: "servicemanager", - defaults: ["servicemanager_flags"], - srcs: [ - "service_manager.c", - "binder.c", - ], - shared_libs: ["libcutils", "libselinux"], + defaults: ["servicemanager_defaults"], init_rc: ["servicemanager.rc"], + srcs: ["main.cpp"], } cc_binary { name: "vndservicemanager", - defaults: ["servicemanager_flags"], + defaults: ["servicemanager_defaults"], + init_rc: ["vndservicemanager.rc"], vendor: true, - srcs: [ - "service_manager.c", - "binder.c", - ], cflags: [ "-DVENDORSERVICEMANAGER=1", ], - shared_libs: ["libcutils", "libselinux"], - init_rc: ["vndservicemanager.rc"], + srcs: ["main.cpp"], +} + +cc_test { + name: "servicemanager_test", + test_suites: ["device-tests"], + defaults: ["servicemanager_defaults"], + srcs: [ + "test_sm.cpp", + ], + static_libs: ["libgmock"], } diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp new file mode 100644 index 0000000000..b88b67d138 --- /dev/null +++ b/cmds/servicemanager/ServiceManager.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 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 "ServiceManager.h" + +#include +#include +#include + +using ::android::binder::Status; + +namespace android { + +ServiceManager::ServiceManager(std::unique_ptr&& access) : mAccess(std::move(access)) {} + +Status ServiceManager::getService(const std::string& name, sp* outBinder) { + // Servicemanager is single-threaded and cannot block. This method exists for legacy reasons. + return checkService(name, outBinder); +} + +Status ServiceManager::checkService(const std::string& name, sp* outBinder) { + auto ctx = mAccess->getCallingContext(name); + + auto it = mNameToService.find(name); + if (it == mNameToService.end()) { + *outBinder = nullptr; + return Status::ok(); + } + + const Service& service = it->second; + + if (!service.allowIsolated) { + uid_t appid = multiuser_get_app_id(ctx.uid); + bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END; + + if (isIsolated) { + *outBinder = nullptr; + return Status::ok(); + } + } + + // TODO(b/136023468): move this check to be first + if (!mAccess->canFind(ctx)) { + // returns ok and null for legacy reasons + *outBinder = nullptr; + return Status::ok(); + } + + *outBinder = service.binder; + return Status::ok(); +} + +Status ServiceManager::addService(const std::string& name, const sp& binder, bool allowIsolated, int32_t dumpPriority) { + auto ctx = mAccess->getCallingContext(name); + + // apps cannot add services + if (multiuser_get_app_id(ctx.uid) >= AID_APP) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + if (!mAccess->canAdd(ctx)) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + if (binder == nullptr) { + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); + } + + // match legacy rules + if (name.size() == 0 || name.size() > 127) { + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); + } + + if (OK != binder->linkToDeath(this)) { + LOG(ERROR) << "Could not linkToDeath when adding " << name; + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); + } + + auto it = mNameToService.find(name); + if (it != mNameToService.end()) { + if (OK != it->second.binder->unlinkToDeath(this)) { + LOG(WARNING) << "Could not unlinkToDeath when adding " << name; + } + } + + mNameToService[name] = Service { + .binder = binder, + .allowIsolated = allowIsolated, + .dumpPriority = dumpPriority, + }; + + return Status::ok(); +} + +Status ServiceManager::listServices(int32_t dumpPriority, std::vector* outList) { + if (!mAccess->canList(mAccess->getCallingContext(""))) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + size_t toReserve = 0; + for (auto const& [name, service] : mNameToService) { + (void) name; + + if (service.dumpPriority & dumpPriority) ++toReserve; + } + + CHECK(outList->empty()); + + outList->reserve(toReserve); + for (auto const& [name, service] : mNameToService) { + (void) service; + + if (service.dumpPriority & dumpPriority) { + outList->push_back(name); + } + } + + return Status::ok(); +} + +void ServiceManager::binderDied(const wp& who) { + for (auto it = mNameToService.begin(); it != mNameToService.end();) { + if (who == it->second.binder) { + it = mNameToService.erase(it); + } else { + ++it; + } + } +} + +} // namespace android diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h new file mode 100644 index 0000000000..78e48052b8 --- /dev/null +++ b/cmds/servicemanager/ServiceManager.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 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 + +#include "Access.h" + +namespace android { + +class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient { +public: + ServiceManager(std::unique_ptr&& access); + + binder::Status getService(const std::string& name, sp* outBinder) override; + binder::Status checkService(const std::string& name, sp* outBinder) override; + binder::Status addService(const std::string& name, const sp& binder, bool allowIsolated, int32_t dumpPriority) override; + binder::Status listServices(int32_t dumpPriority, std::vector* outList) override; + + void binderDied(const wp& who) override; + +private: + struct Service { + sp binder; + bool allowIsolated; + int32_t dumpPriority; + }; + + std::map mNameToService; + std::unique_ptr mAccess; +}; + +} // namespace android diff --git a/cmds/servicemanager/TEST_MAPPING b/cmds/servicemanager/TEST_MAPPING new file mode 100644 index 0000000000..3e47269fe0 --- /dev/null +++ b/cmds/servicemanager/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "servicemanager_test" + } + ] +} diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c deleted file mode 100644 index 354df670e5..0000000000 --- a/cmds/servicemanager/bctest.c +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#include -#include -#include -#include - -#include "binder.h" - -uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name) -{ - uint32_t handle; - unsigned iodata[512/4]; - struct binder_io msg, reply; - - bio_init(&msg, iodata, sizeof(iodata), 4); - bio_put_uint32(&msg, 0); // strict mode header - bio_put_string16_x(&msg, SVC_MGR_NAME); - bio_put_string16_x(&msg, name); - - if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)) - return 0; - - handle = bio_get_ref(&reply); - - if (handle) - binder_acquire(bs, handle); - - binder_done(bs, &msg, &reply); - - return handle; -} - -int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr) -{ - int status; - unsigned iodata[512/4]; - struct binder_io msg, reply; - - bio_init(&msg, iodata, sizeof(iodata), 4); - bio_put_uint32(&msg, 0); // strict mode header - bio_put_string16_x(&msg, SVC_MGR_NAME); - bio_put_string16_x(&msg, name); - bio_put_obj(&msg, ptr); - - if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)) - return -1; - - status = bio_get_uint32(&reply); - - binder_done(bs, &msg, &reply); - - return status; -} - -unsigned token; - -int main(int argc, char **argv) -{ - struct binder_state *bs; - uint32_t svcmgr = BINDER_SERVICE_MANAGER; - uint32_t handle; - - bs = binder_open("/dev/binder", 128*1024); - if (!bs) { - fprintf(stderr, "failed to open binder driver\n"); - return -1; - } - - argc--; - argv++; - while (argc > 0) { - if (!strcmp(argv[0],"alt")) { - handle = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr"); - if (!handle) { - fprintf(stderr,"cannot find alt_svc_mgr\n"); - return -1; - } - svcmgr = handle; - fprintf(stderr,"svcmgr is via %x\n", handle); - } else if (!strcmp(argv[0],"lookup")) { - if (argc < 2) { - fprintf(stderr,"argument required\n"); - return -1; - } - handle = svcmgr_lookup(bs, svcmgr, argv[1]); - fprintf(stderr,"lookup(%s) = %x\n", argv[1], handle); - argc--; - argv++; - } else if (!strcmp(argv[0],"publish")) { - if (argc < 2) { - fprintf(stderr,"argument required\n"); - return -1; - } - svcmgr_publish(bs, svcmgr, argv[1], &token); - argc--; - argv++; - } else { - fprintf(stderr,"unknown command %s\n", argv[0]); - return -1; - } - argc--; - argv++; - } - return 0; -} diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c deleted file mode 100644 index cf3b1728b6..0000000000 --- a/cmds/servicemanager/binder.c +++ /dev/null @@ -1,682 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#define LOG_TAG "Binder" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "binder.h" - -#define MAX_BIO_SIZE (1 << 30) - -#define TRACE 0 - -void bio_init_from_txn(struct binder_io *io, struct binder_transaction_data *txn); - -#if TRACE -void hexdump(void *_data, size_t len) -{ - unsigned char *data = _data; - size_t count; - - for (count = 0; count < len; count++) { - if ((count & 15) == 0) - fprintf(stderr,"%04zu:", count); - fprintf(stderr," %02x %c", *data, - (*data < 32) || (*data > 126) ? '.' : *data); - data++; - if ((count & 15) == 15) - fprintf(stderr,"\n"); - } - if ((count & 15) != 0) - fprintf(stderr,"\n"); -} - -void binder_dump_txn(struct binder_transaction_data *txn) -{ - struct flat_binder_object *obj; - binder_size_t *offs = (binder_size_t *)(uintptr_t)txn->data.ptr.offsets; - size_t count = txn->offsets_size / sizeof(binder_size_t); - - fprintf(stderr," target %016"PRIx64" cookie %016"PRIx64" code %08x flags %08x\n", - (uint64_t)txn->target.ptr, (uint64_t)txn->cookie, txn->code, txn->flags); - fprintf(stderr," pid %8d uid %8d data %"PRIu64" offs %"PRIu64"\n", - txn->sender_pid, txn->sender_euid, (uint64_t)txn->data_size, (uint64_t)txn->offsets_size); - hexdump((void *)(uintptr_t)txn->data.ptr.buffer, txn->data_size); - while (count--) { - obj = (struct flat_binder_object *) (((char*)(uintptr_t)txn->data.ptr.buffer) + *offs++); - fprintf(stderr," - type %08x flags %08x ptr %016"PRIx64" cookie %016"PRIx64"\n", - obj->type, obj->flags, (uint64_t)obj->binder, (uint64_t)obj->cookie); - } -} - -#define NAME(n) case n: return #n -const char *cmd_name(uint32_t cmd) -{ - switch(cmd) { - NAME(BR_NOOP); - NAME(BR_TRANSACTION_COMPLETE); - NAME(BR_INCREFS); - NAME(BR_ACQUIRE); - NAME(BR_RELEASE); - NAME(BR_DECREFS); - NAME(BR_TRANSACTION); - NAME(BR_REPLY); - NAME(BR_FAILED_REPLY); - NAME(BR_DEAD_REPLY); - NAME(BR_DEAD_BINDER); - default: return "???"; - } -} -#else -#define hexdump(a,b) do{} while (0) -#define binder_dump_txn(txn) do{} while (0) -#endif - -#define BIO_F_SHARED 0x01 /* needs to be buffer freed */ -#define BIO_F_OVERFLOW 0x02 /* ran out of space */ -#define BIO_F_IOERROR 0x04 -#define BIO_F_MALLOCED 0x08 /* needs to be free()'d */ - -struct binder_state -{ - int fd; - void *mapped; - size_t mapsize; -}; - -struct binder_state *binder_open(const char* driver, size_t mapsize) -{ - struct binder_state *bs; - struct binder_version vers; - - bs = malloc(sizeof(*bs)); - if (!bs) { - errno = ENOMEM; - return NULL; - } - - bs->fd = open(driver, O_RDWR | O_CLOEXEC); - if (bs->fd < 0) { - fprintf(stderr,"binder: cannot open %s (%s)\n", - driver, strerror(errno)); - goto fail_open; - } - - if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) || - (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) { - fprintf(stderr, - "binder: kernel driver version (%d) differs from user space version (%d)\n", - vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION); - goto fail_open; - } - - bs->mapsize = mapsize; - bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); - if (bs->mapped == MAP_FAILED) { - fprintf(stderr,"binder: cannot map device (%s)\n", - strerror(errno)); - goto fail_map; - } - - return bs; - -fail_map: - close(bs->fd); -fail_open: - free(bs); - return NULL; -} - -void binder_close(struct binder_state *bs) -{ - munmap(bs->mapped, bs->mapsize); - close(bs->fd); - free(bs); -} - -int binder_become_context_manager(struct binder_state *bs) -{ - struct flat_binder_object obj; - memset(&obj, 0, sizeof(obj)); - obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX; - - int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj); - - // fallback to original method - if (result != 0) { - android_errorWriteLog(0x534e4554, "121035042"); - - result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); - } - return result; -} - -int binder_write(struct binder_state *bs, void *data, size_t len) -{ - struct binder_write_read bwr; - int res; - - bwr.write_size = len; - bwr.write_consumed = 0; - bwr.write_buffer = (uintptr_t) data; - bwr.read_size = 0; - bwr.read_consumed = 0; - bwr.read_buffer = 0; - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - if (res < 0) { - fprintf(stderr,"binder_write: ioctl failed (%s)\n", - strerror(errno)); - } - return res; -} - -void binder_free_buffer(struct binder_state *bs, - binder_uintptr_t buffer_to_free) -{ - struct { - uint32_t cmd_free; - binder_uintptr_t buffer; - } __attribute__((packed)) data; - data.cmd_free = BC_FREE_BUFFER; - data.buffer = buffer_to_free; - binder_write(bs, &data, sizeof(data)); -} - -void binder_send_reply(struct binder_state *bs, - struct binder_io *reply, - binder_uintptr_t buffer_to_free, - int status) -{ - struct { - uint32_t cmd_free; - binder_uintptr_t buffer; - uint32_t cmd_reply; - struct binder_transaction_data txn; - } __attribute__((packed)) data; - - data.cmd_free = BC_FREE_BUFFER; - data.buffer = buffer_to_free; - data.cmd_reply = BC_REPLY; - data.txn.target.ptr = 0; - data.txn.cookie = 0; - data.txn.code = 0; - if (status) { - data.txn.flags = TF_STATUS_CODE; - data.txn.data_size = sizeof(int); - data.txn.offsets_size = 0; - data.txn.data.ptr.buffer = (uintptr_t)&status; - data.txn.data.ptr.offsets = 0; - } else { - data.txn.flags = 0; - data.txn.data_size = reply->data - reply->data0; - data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0); - data.txn.data.ptr.buffer = (uintptr_t)reply->data0; - data.txn.data.ptr.offsets = (uintptr_t)reply->offs0; - } - binder_write(bs, &data, sizeof(data)); -} - -int binder_parse(struct binder_state *bs, struct binder_io *bio, - uintptr_t ptr, size_t size, binder_handler func) -{ - int r = 1; - uintptr_t end = ptr + (uintptr_t) size; - - while (ptr < end) { - uint32_t cmd = *(uint32_t *) ptr; - ptr += sizeof(uint32_t); -#if TRACE - fprintf(stderr,"%s:\n", cmd_name(cmd)); -#endif - switch(cmd) { - case BR_NOOP: - break; - case BR_TRANSACTION_COMPLETE: - break; - case BR_INCREFS: - case BR_ACQUIRE: - case BR_RELEASE: - case BR_DECREFS: -#if TRACE - fprintf(stderr," %p, %p\n", (void *)ptr, (void *)(ptr + sizeof(void *))); -#endif - ptr += sizeof(struct binder_ptr_cookie); - break; - case BR_TRANSACTION_SEC_CTX: - case BR_TRANSACTION: { - struct binder_transaction_data_secctx txn; - if (cmd == BR_TRANSACTION_SEC_CTX) { - if ((end - ptr) < sizeof(struct binder_transaction_data_secctx)) { - ALOGE("parse: txn too small (binder_transaction_data_secctx)!\n"); - return -1; - } - memcpy(&txn, (void*) ptr, sizeof(struct binder_transaction_data_secctx)); - ptr += sizeof(struct binder_transaction_data_secctx); - } else /* BR_TRANSACTION */ { - if ((end - ptr) < sizeof(struct binder_transaction_data)) { - ALOGE("parse: txn too small (binder_transaction_data)!\n"); - return -1; - } - memcpy(&txn.transaction_data, (void*) ptr, sizeof(struct binder_transaction_data)); - ptr += sizeof(struct binder_transaction_data); - - txn.secctx = 0; - } - - binder_dump_txn(&txn.transaction_data); - if (func) { - unsigned rdata[256/4]; - struct binder_io msg; - struct binder_io reply; - int res; - - bio_init(&reply, rdata, sizeof(rdata), 4); - bio_init_from_txn(&msg, &txn.transaction_data); - res = func(bs, &txn, &msg, &reply); - if (txn.transaction_data.flags & TF_ONE_WAY) { - binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer); - } else { - binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res); - } - } - break; - } - case BR_REPLY: { - struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr; - if ((end - ptr) < sizeof(*txn)) { - ALOGE("parse: reply too small!\n"); - return -1; - } - binder_dump_txn(txn); - if (bio) { - bio_init_from_txn(bio, txn); - bio = 0; - } else { - /* todo FREE BUFFER */ - } - ptr += sizeof(*txn); - r = 0; - break; - } - case BR_DEAD_BINDER: { - struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr; - ptr += sizeof(binder_uintptr_t); - death->func(bs, death->ptr); - break; - } - case BR_FAILED_REPLY: - r = -1; - break; - case BR_DEAD_REPLY: - r = -1; - break; - default: - ALOGE("parse: OOPS %d\n", cmd); - return -1; - } - } - - return r; -} - -void binder_acquire(struct binder_state *bs, uint32_t target) -{ - uint32_t cmd[2]; - cmd[0] = BC_ACQUIRE; - cmd[1] = target; - binder_write(bs, cmd, sizeof(cmd)); -} - -void binder_release(struct binder_state *bs, uint32_t target) -{ - uint32_t cmd[2]; - cmd[0] = BC_RELEASE; - cmd[1] = target; - binder_write(bs, cmd, sizeof(cmd)); -} - -void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death) -{ - struct { - uint32_t cmd; - struct binder_handle_cookie payload; - } __attribute__((packed)) data; - - data.cmd = BC_REQUEST_DEATH_NOTIFICATION; - data.payload.handle = target; - data.payload.cookie = (uintptr_t) death; - binder_write(bs, &data, sizeof(data)); -} - -int binder_call(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply, - uint32_t target, uint32_t code) -{ - int res; - struct binder_write_read bwr; - struct { - uint32_t cmd; - struct binder_transaction_data txn; - } __attribute__((packed)) writebuf; - unsigned readbuf[32]; - - if (msg->flags & BIO_F_OVERFLOW) { - fprintf(stderr,"binder: txn buffer overflow\n"); - goto fail; - } - - writebuf.cmd = BC_TRANSACTION; - writebuf.txn.target.handle = target; - writebuf.txn.code = code; - writebuf.txn.flags = 0; - writebuf.txn.data_size = msg->data - msg->data0; - writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0); - writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0; - writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0; - - bwr.write_size = sizeof(writebuf); - bwr.write_consumed = 0; - bwr.write_buffer = (uintptr_t) &writebuf; - - hexdump(msg->data0, msg->data - msg->data0); - for (;;) { - bwr.read_size = sizeof(readbuf); - bwr.read_consumed = 0; - bwr.read_buffer = (uintptr_t) readbuf; - - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - - if (res < 0) { - fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno)); - goto fail; - } - - res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0); - if (res == 0) return 0; - if (res < 0) goto fail; - } - -fail: - memset(reply, 0, sizeof(*reply)); - reply->flags |= BIO_F_IOERROR; - return -1; -} - -void binder_loop(struct binder_state *bs, binder_handler func) -{ - int res; - struct binder_write_read bwr; - uint32_t readbuf[32]; - - bwr.write_size = 0; - bwr.write_consumed = 0; - bwr.write_buffer = 0; - - readbuf[0] = BC_ENTER_LOOPER; - binder_write(bs, readbuf, sizeof(uint32_t)); - - for (;;) { - bwr.read_size = sizeof(readbuf); - bwr.read_consumed = 0; - bwr.read_buffer = (uintptr_t) readbuf; - - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - - if (res < 0) { - ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno)); - break; - } - - res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func); - if (res == 0) { - ALOGE("binder_loop: unexpected reply?!\n"); - break; - } - if (res < 0) { - ALOGE("binder_loop: io error %d %s\n", res, strerror(errno)); - break; - } - } -} - -void bio_init_from_txn(struct binder_io *bio, struct binder_transaction_data *txn) -{ - bio->data = bio->data0 = (char *)(intptr_t)txn->data.ptr.buffer; - bio->offs = bio->offs0 = (binder_size_t *)(intptr_t)txn->data.ptr.offsets; - bio->data_avail = txn->data_size; - bio->offs_avail = txn->offsets_size / sizeof(size_t); - bio->flags = BIO_F_SHARED; -} - -void bio_init(struct binder_io *bio, void *data, - size_t maxdata, size_t maxoffs) -{ - size_t n = maxoffs * sizeof(size_t); - - if (n > maxdata) { - bio->flags = BIO_F_OVERFLOW; - bio->data_avail = 0; - bio->offs_avail = 0; - return; - } - - bio->data = bio->data0 = (char *) data + n; - bio->offs = bio->offs0 = data; - bio->data_avail = maxdata - n; - bio->offs_avail = maxoffs; - bio->flags = 0; -} - -static void *bio_alloc(struct binder_io *bio, size_t size) -{ - size = (size + 3) & (~3); - if (size > bio->data_avail) { - bio->flags |= BIO_F_OVERFLOW; - return NULL; - } else { - void *ptr = bio->data; - bio->data += size; - bio->data_avail -= size; - return ptr; - } -} - -void binder_done(struct binder_state *bs, - __unused struct binder_io *msg, - struct binder_io *reply) -{ - struct { - uint32_t cmd; - uintptr_t buffer; - } __attribute__((packed)) data; - - if (reply->flags & BIO_F_SHARED) { - data.cmd = BC_FREE_BUFFER; - data.buffer = (uintptr_t) reply->data0; - binder_write(bs, &data, sizeof(data)); - reply->flags = 0; - } -} - -static struct flat_binder_object *bio_alloc_obj(struct binder_io *bio) -{ - struct flat_binder_object *obj; - - obj = bio_alloc(bio, sizeof(*obj)); - - if (obj && bio->offs_avail) { - bio->offs_avail--; - *bio->offs++ = ((char*) obj) - ((char*) bio->data0); - return obj; - } - - bio->flags |= BIO_F_OVERFLOW; - return NULL; -} - -void bio_put_uint32(struct binder_io *bio, uint32_t n) -{ - uint32_t *ptr = bio_alloc(bio, sizeof(n)); - if (ptr) - *ptr = n; -} - -void bio_put_obj(struct binder_io *bio, void *ptr) -{ - struct flat_binder_object *obj; - - obj = bio_alloc_obj(bio); - if (!obj) - return; - - obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj->hdr.type = BINDER_TYPE_BINDER; - obj->binder = (uintptr_t)ptr; - obj->cookie = 0; -} - -void bio_put_ref(struct binder_io *bio, uint32_t handle) -{ - struct flat_binder_object *obj; - - if (handle) - obj = bio_alloc_obj(bio); - else - obj = bio_alloc(bio, sizeof(*obj)); - - if (!obj) - return; - - obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj->hdr.type = BINDER_TYPE_HANDLE; - obj->handle = handle; - obj->cookie = 0; -} - -void bio_put_string16(struct binder_io *bio, const uint16_t *str) -{ - size_t len; - uint16_t *ptr; - - if (!str) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - len = 0; - while (str[len]) len++; - - if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - /* Note: The payload will carry 32bit size instead of size_t */ - bio_put_uint32(bio, (uint32_t) len); - len = (len + 1) * sizeof(uint16_t); - ptr = bio_alloc(bio, len); - if (ptr) - memcpy(ptr, str, len); -} - -void bio_put_string16_x(struct binder_io *bio, const char *_str) -{ - unsigned char *str = (unsigned char*) _str; - size_t len; - uint16_t *ptr; - - if (!str) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - len = strlen(_str); - - if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - /* Note: The payload will carry 32bit size instead of size_t */ - bio_put_uint32(bio, len); - ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t)); - if (!ptr) - return; - - while (*str) - *ptr++ = *str++; - *ptr++ = 0; -} - -static void *bio_get(struct binder_io *bio, size_t size) -{ - size = (size + 3) & (~3); - - if (bio->data_avail < size){ - bio->data_avail = 0; - bio->flags |= BIO_F_OVERFLOW; - return NULL; - } else { - void *ptr = bio->data; - bio->data += size; - bio->data_avail -= size; - return ptr; - } -} - -uint32_t bio_get_uint32(struct binder_io *bio) -{ - uint32_t *ptr = bio_get(bio, sizeof(*ptr)); - return ptr ? *ptr : 0; -} - -uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz) -{ - size_t len; - - /* Note: The payload will carry 32bit size instead of size_t */ - len = (size_t) bio_get_uint32(bio); - if (sz) - *sz = len; - return bio_get(bio, (len + 1) * sizeof(uint16_t)); -} - -static struct flat_binder_object *_bio_get_obj(struct binder_io *bio) -{ - size_t n; - size_t off = bio->data - bio->data0; - - /* TODO: be smarter about this? */ - for (n = 0; n < bio->offs_avail; n++) { - if (bio->offs[n] == off) - return bio_get(bio, sizeof(struct flat_binder_object)); - } - - bio->data_avail = 0; - bio->flags |= BIO_F_OVERFLOW; - return NULL; -} - -uint32_t bio_get_ref(struct binder_io *bio) -{ - struct flat_binder_object *obj; - - obj = _bio_get_obj(bio); - if (!obj) - return 0; - - if (obj->hdr.type == BINDER_TYPE_HANDLE) - return obj->handle; - - return 0; -} diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h deleted file mode 100644 index a9ccc74130..0000000000 --- a/cmds/servicemanager/binder.h +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#ifndef _BINDER_H_ -#define _BINDER_H_ - -#include -#include - -struct binder_state; - -struct binder_io -{ - char *data; /* pointer to read/write from */ - binder_size_t *offs; /* array of offsets */ - size_t data_avail; /* bytes available in data buffer */ - size_t offs_avail; /* entries available in offsets array */ - - char *data0; /* start of data buffer */ - binder_size_t *offs0; /* start of offsets buffer */ - uint32_t flags; - uint32_t unused; -}; - -struct binder_death { - void (*func)(struct binder_state *bs, void *ptr); - void *ptr; -}; - -/* the one magic handle */ -#define BINDER_SERVICE_MANAGER 0U - -#define SVC_MGR_NAME "android.os.IServiceManager" - -enum { - /* Must match definitions in IBinder.h and IServiceManager.h */ - PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'), - SVC_MGR_GET_SERVICE = 1, - SVC_MGR_CHECK_SERVICE, - SVC_MGR_ADD_SERVICE, - SVC_MGR_LIST_SERVICES, -}; - -typedef int (*binder_handler)(struct binder_state *bs, - struct binder_transaction_data_secctx *txn, - struct binder_io *msg, - struct binder_io *reply); - -struct binder_state *binder_open(const char* driver, size_t mapsize); -void binder_close(struct binder_state *bs); - -/* initiate a blocking binder call - * - returns zero on success - */ -int binder_call(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply, - uint32_t target, uint32_t code); - -/* release any state associate with the binder_io - * - call once any necessary data has been extracted from the - * binder_io after binder_call() returns - * - can safely be called even if binder_call() fails - */ -void binder_done(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply); - -/* manipulate strong references */ -void binder_acquire(struct binder_state *bs, uint32_t target); -void binder_release(struct binder_state *bs, uint32_t target); - -void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death); - -void binder_loop(struct binder_state *bs, binder_handler func); - -int binder_become_context_manager(struct binder_state *bs); - -/* allocate a binder_io, providing a stack-allocated working - * buffer, size of the working buffer, and how many object - * offset entries to reserve from the buffer - */ -void bio_init(struct binder_io *bio, void *data, - size_t maxdata, size_t maxobjects); - -void bio_put_obj(struct binder_io *bio, void *ptr); -void bio_put_ref(struct binder_io *bio, uint32_t handle); -void bio_put_uint32(struct binder_io *bio, uint32_t n); -void bio_put_string16(struct binder_io *bio, const uint16_t *str); -void bio_put_string16_x(struct binder_io *bio, const char *_str); - -uint32_t bio_get_uint32(struct binder_io *bio); -uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz); -uint32_t bio_get_ref(struct binder_io *bio); - -#endif diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp new file mode 100644 index 0000000000..c8ceb42ac8 --- /dev/null +++ b/cmds/servicemanager/main.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 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 +#include +#include +#include +#include + +#include "Access.h" +#include "ServiceManager.h" + +using ::android::sp; +using ::android::ProcessState; +using ::android::IPCThreadState; +using ::android::ServiceManager; +using ::android::Access; + +int main(int argc, char** argv) { + if (argc > 2) { + LOG(FATAL) << "usage: " << argv[0] << " [binder driver]"; + } + + const char* driver = argc == 2 ? argv[1] : "/dev/binder"; + + android::base::InitLogging(nullptr, &android::base::KernelLogger); + + ProcessState::self()->initWithDriver(driver); + ProcessState::self()->setThreadPoolMaxThreadCount(0); + ProcessState::self()->setCallRestriction( + ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY); + + sp manager = new ServiceManager(std::make_unique()); + IPCThreadState::self()->setTheContextObject(manager); + ProcessState::self()->becomeContextManager(nullptr, nullptr); + + IPCThreadState::self()->joinThreadPool(); + + // should not be reached + return EXIT_FAILURE; +} diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c deleted file mode 100644 index ec3fac538d..0000000000 --- a/cmds/servicemanager/service_manager.c +++ /dev/null @@ -1,442 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "binder.h" - -#ifdef VENDORSERVICEMANAGER -#define LOG_TAG "VendorServiceManager" -#else -#define LOG_TAG "ServiceManager" -#endif -#include - -struct audit_data { - pid_t pid; - uid_t uid; - const char *name; -}; - -const char *str8(const uint16_t *x, size_t x_len) -{ - static char buf[128]; - size_t max = 127; - char *p = buf; - - if (x_len < max) { - max = x_len; - } - - if (x) { - while ((max > 0) && (*x != '\0')) { - *p++ = *x++; - max--; - } - } - *p++ = 0; - return buf; -} - -int str16eq(const uint16_t *a, const char *b) -{ - while (*a && *b) - if (*a++ != *b++) return 0; - if (*a || *b) - return 0; - return 1; -} - -static char *service_manager_context; -static struct selabel_handle* sehandle; - -static bool check_mac_perms(pid_t spid, const char* sid, uid_t uid, const char *tctx, const char *perm, const char *name) -{ - char *lookup_sid = NULL; - const char *class = "service_manager"; - bool allowed; - struct audit_data ad; - - if (sid == NULL && getpidcon(spid, &lookup_sid) < 0) { - ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid); - return false; - } - - ad.pid = spid; - ad.uid = uid; - ad.name = name; - - if (sid == NULL) { - android_errorWriteLog(0x534e4554, "121035042"); - } - - int result = selinux_check_access(sid ? sid : lookup_sid, tctx, class, perm, (void *) &ad); - allowed = (result == 0); - - freecon(lookup_sid); - return allowed; -} - -static bool check_mac_perms_from_getcon(pid_t spid, const char* sid, uid_t uid, const char *perm) -{ - return check_mac_perms(spid, sid, uid, service_manager_context, perm, NULL); -} - -static bool check_mac_perms_from_lookup(pid_t spid, const char* sid, uid_t uid, const char *perm, const char *name) -{ - bool allowed; - char *tctx = NULL; - - if (!sehandle) { - ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n"); - abort(); - } - - if (selabel_lookup(sehandle, &tctx, name, 0) != 0) { - ALOGE("SELinux: No match for %s in service_contexts.\n", name); - return false; - } - - allowed = check_mac_perms(spid, sid, uid, tctx, perm, name); - freecon(tctx); - return allowed; -} - -static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "add"; - - if (multiuser_get_app_id(uid) >= AID_APP) { - return 0; /* Don't allow apps to register services */ - } - - return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0; -} - -static int svc_can_list(pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "list"; - return check_mac_perms_from_getcon(spid, sid, uid, perm) ? 1 : 0; -} - -static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "find"; - return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0; -} - -struct svcinfo -{ - struct svcinfo *next; - uint32_t handle; - struct binder_death death; - int allow_isolated; - uint32_t dumpsys_priority; - size_t len; - uint16_t name[0]; -}; - -struct svcinfo *svclist = NULL; - -struct svcinfo *find_svc(const uint16_t *s16, size_t len) -{ - struct svcinfo *si; - - for (si = svclist; si; si = si->next) { - if ((len == si->len) && - !memcmp(s16, si->name, len * sizeof(uint16_t))) { - return si; - } - } - return NULL; -} - -void svcinfo_death(struct binder_state *bs, void *ptr) -{ - struct svcinfo *si = (struct svcinfo* ) ptr; - - ALOGI("service '%s' died\n", str8(si->name, si->len)); - if (si->handle) { - binder_release(bs, si->handle); - si->handle = 0; - } -} - -uint16_t svcmgr_id[] = { - 'a','n','d','r','o','i','d','.','o','s','.', - 'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r' -}; - - -uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid) -{ - struct svcinfo *si = find_svc(s, len); - - if (!si || !si->handle) { - return 0; - } - - if (!si->allow_isolated) { - // If this service doesn't allow access from isolated processes, - // then check the uid to see if it is isolated. - uid_t appid = uid % AID_USER; - if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { - return 0; - } - } - - if (!svc_can_find(s, len, spid, sid, uid)) { - return 0; - } - - return si->handle; -} - -int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, - uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid, const char* sid) { - struct svcinfo *si; - - //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle, - // allow_isolated ? "allow_isolated" : "!allow_isolated", uid); - - if (!handle || (len == 0) || (len > 127)) - return -1; - - if (!svc_can_register(s, len, spid, sid, uid)) { - ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", - str8(s, len), handle, uid); - return -1; - } - - si = find_svc(s, len); - if (si) { - if (si->handle) { - ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n", - str8(s, len), handle, uid); - svcinfo_death(bs, si); - } - si->handle = handle; - } else { - si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); - if (!si) { - ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n", - str8(s, len), handle, uid); - return -1; - } - si->handle = handle; - si->len = len; - memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); - si->name[len] = '\0'; - si->death.func = (void*) svcinfo_death; - si->death.ptr = si; - si->allow_isolated = allow_isolated; - si->dumpsys_priority = dumpsys_priority; - si->next = svclist; - svclist = si; - } - - binder_acquire(bs, handle); - binder_link_to_death(bs, handle, &si->death); - return 0; -} - -int svcmgr_handler(struct binder_state *bs, - struct binder_transaction_data_secctx *txn_secctx, - struct binder_io *msg, - struct binder_io *reply) -{ - struct svcinfo *si; - uint16_t *s; - size_t len; - uint32_t handle; - uint32_t strict_policy; - int allow_isolated; - uint32_t dumpsys_priority; - - struct binder_transaction_data *txn = &txn_secctx->transaction_data; - - //ALOGI("target=%p code=%d pid=%d uid=%d\n", - // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid); - - if (txn->target.ptr != BINDER_SERVICE_MANAGER) - return -1; - - if (txn->code == PING_TRANSACTION) - return 0; - - // Equivalent to Parcel::enforceInterface(), reading the RPC - // header with the strict mode policy mask and the interface name. - // Note that we ignore the strict_policy and don't propagate it - // further (since we do no outbound RPCs anyway). - strict_policy = bio_get_uint32(msg); - bio_get_uint32(msg); // Ignore worksource header. - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - - if ((len != (sizeof(svcmgr_id) / 2)) || - memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { - fprintf(stderr,"invalid id %s\n", str8(s, len)); - return -1; - } - - if (sehandle && selinux_status_updated() > 0) { -#ifdef VENDORSERVICEMANAGER - struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle(); -#else - struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle(); -#endif - if (tmp_sehandle) { - selabel_close(sehandle); - sehandle = tmp_sehandle; - } - } - - switch(txn->code) { - case SVC_MGR_GET_SERVICE: - case SVC_MGR_CHECK_SERVICE: - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid, - (const char*) txn_secctx->secctx); - if (!handle) - break; - bio_put_ref(reply, handle); - return 0; - - case SVC_MGR_ADD_SERVICE: - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - handle = bio_get_ref(msg); - allow_isolated = bio_get_uint32(msg) ? 1 : 0; - dumpsys_priority = bio_get_uint32(msg); - if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, - txn->sender_pid, (const char*) txn_secctx->secctx)) - return -1; - break; - - case SVC_MGR_LIST_SERVICES: { - uint32_t n = bio_get_uint32(msg); - uint32_t req_dumpsys_priority = bio_get_uint32(msg); - - if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) { - ALOGE("list_service() uid=%d - PERMISSION DENIED\n", - txn->sender_euid); - return -1; - } - si = svclist; - // walk through the list of services n times skipping services that - // do not support the requested priority - while (si) { - if (si->dumpsys_priority & req_dumpsys_priority) { - if (n == 0) break; - n--; - } - si = si->next; - } - if (si) { - bio_put_string16(reply, si->name); - return 0; - } - return -1; - } - default: - ALOGE("unknown code %d\n", txn->code); - return -1; - } - - bio_put_uint32(reply, 0); - return 0; -} - - -static int audit_callback(void *data, __unused security_class_t cls, char *buf, size_t len) -{ - struct audit_data *ad = (struct audit_data *)data; - - if (!ad || !ad->name) { - ALOGE("No service manager audit data"); - return 0; - } - - snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name, ad->pid, ad->uid); - return 0; -} - -int main(int argc, char** argv) -{ - struct binder_state *bs; - union selinux_callback cb; - char *driver; - - if (argc > 1) { - driver = argv[1]; - } else { - driver = "/dev/binder"; - } - - bs = binder_open(driver, 128*1024); - if (!bs) { -#ifdef VENDORSERVICEMANAGER - ALOGW("failed to open binder driver %s\n", driver); - while (true) { - sleep(UINT_MAX); - } -#else - ALOGE("failed to open binder driver %s\n", driver); -#endif - return -1; - } - - if (binder_become_context_manager(bs)) { - ALOGE("cannot become context manager (%s)\n", strerror(errno)); - return -1; - } - - cb.func_audit = audit_callback; - selinux_set_callback(SELINUX_CB_AUDIT, cb); -#ifdef VENDORSERVICEMANAGER - cb.func_log = selinux_vendor_log_callback; -#else - cb.func_log = selinux_log_callback; -#endif - selinux_set_callback(SELINUX_CB_LOG, cb); - -#ifdef VENDORSERVICEMANAGER - sehandle = selinux_android_vendor_service_context_handle(); -#else - sehandle = selinux_android_service_context_handle(); -#endif - selinux_status_open(true); - - if (sehandle == NULL) { - ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n"); - abort(); - } - - if (getcon(&service_manager_context) != 0) { - ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n"); - abort(); - } - - - binder_loop(bs, svcmgr_handler); - - return 0; -} diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp new file mode 100644 index 0000000000..812d5cacd5 --- /dev/null +++ b/cmds/servicemanager/test_sm.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (C) 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 +#include +#include +#include + +#include "Access.h" +#include "ServiceManager.h" + +using android::sp; +using android::Access; +using android::IBinder; +using android::ServiceManager; +using android::os::IServiceManager; +using testing::_; +using testing::ElementsAre; +using testing::NiceMock; +using testing::Return; + +static sp getBinder() { + // It doesn't matter what remote binder it is, we just need one so that linkToDeath will work. + // The context manager (servicemanager) is easy to get and is in another process. + return android::ProcessState::self()->getContextObject(nullptr); +} + +class MockAccess : public Access { +public: + MOCK_METHOD1(getCallingContext, CallingContext(const std::string& name)); + MOCK_METHOD1(canAdd, bool(const CallingContext&)); + MOCK_METHOD1(canFind, bool(const CallingContext&)); + MOCK_METHOD1(canList, bool(const CallingContext&)); +}; + +static sp getPermissiveServiceManager() { + std::unique_ptr access = std::make_unique>(); + + ON_CALL(*access, getCallingContext(_)).WillByDefault(Return(Access::CallingContext{})); + ON_CALL(*access, canAdd(_)).WillByDefault(Return(true)); + ON_CALL(*access, canFind(_)).WillByDefault(Return(true)); + ON_CALL(*access, canList(_)).WillByDefault(Return(true)); + + sp sm = new ServiceManager(std::move(access)); + return sm; +} + +TEST(AddService, HappyHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, EmptyNameDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService("", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, JustShortEnoughServiceNameHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService(std::string(127, 'a'), getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, TooLongNameDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService(std::string(128, 'a'), getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, AddNullServiceDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService("foo", nullptr, false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, AddDisallowedFromApp) { + for (uid_t uid : { AID_APP_START, AID_APP_START + 1, AID_APP_END }) { + std::unique_ptr access = std::make_unique>(); + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{ + .debugPid = 1337, + .uid = uid, + })); + EXPECT_CALL(*access, canAdd(_)).Times(0); + sp sm = new ServiceManager(std::move(access)); + + EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + } + +} + +TEST(AddService, HappyOverExistingService) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, NoPermissions) { + std::unique_ptr access = std::make_unique>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(false)); + + sp sm = new ServiceManager(std::move(access)); + + EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(GetService, HappyHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(getBinder(), out); +} + +TEST(GetService, NonExistant) { + auto sm = getPermissiveServiceManager(); + + sp out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(GetService, NoPermissionsForGettingService) { + std::unique_ptr access = std::make_unique>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillRepeatedly(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + EXPECT_CALL(*access, canFind(_)).WillOnce(Return(false)); + + sp sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp out; + // returns nullptr but has OK status for legacy compatibility + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(GetService, AllowedFromIsolated) { + std::unique_ptr access = std::make_unique>(); + + EXPECT_CALL(*access, getCallingContext(_)) + // something adds it + .WillOnce(Return(Access::CallingContext{})) + // next call is from isolated app + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + EXPECT_CALL(*access, canFind(_)).WillOnce(Return(true)); + + sp sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), true /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(getBinder(), out.get()); +} + +TEST(GetService, NotAllowedFromIsolated) { + std::unique_ptr access = std::make_unique>(); + + EXPECT_CALL(*access, getCallingContext(_)) + // something adds it + .WillOnce(Return(Access::CallingContext{})) + // next call is from isolated app + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + + // TODO(b/136023468): when security check is first, this should be called first + // EXPECT_CALL(*access, canFind(_)).WillOnce(Return(true)); + + sp sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp out; + // returns nullptr but has OK status for legacy compatibility + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(ListServices, NoPermissions) { + std::unique_ptr access = std::make_unique>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canList(_)).WillOnce(Return(false)); + + sp sm = new ServiceManager(std::move(access)); + + std::vector out; + EXPECT_FALSE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); + EXPECT_TRUE(out.empty()); +} + +TEST(ListServices, AllServices) { + auto sm = getPermissiveServiceManager(); + + EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk()); + EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk()); + EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk()); + + std::vector out; + EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); + + // all there and in the right order + EXPECT_THAT(out, ElementsAre("sa", "sb", "sc", "sd")); +} + +TEST(ListServices, CriticalServices) { + auto sm = getPermissiveServiceManager(); + + EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk()); + EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk()); + EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk()); + + std::vector out; + EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, &out).isOk()); + + // all there and in the right order + EXPECT_THAT(out, ElementsAre("sa")); +} diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 905b25f397..760d55b751 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -94,7 +94,6 @@ cc_library_shared { "PermissionController.cpp", "ProcessInfoService.cpp", "IpPrefix.cpp", - ":libbinder_aidl", ], }, }, @@ -142,8 +141,7 @@ filegroup { name: "libbinder_aidl", srcs: [ "aidl/android/content/pm/IPackageManagerNative.aidl", + "aidl/android/os/IServiceManager.aidl", ], path: "aidl", } - -subdirs = ["tests"] diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index a2d10ab0ab..3424c28883 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -1062,7 +1062,7 @@ status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, sp the_context_object; -void setTheContextObject(sp obj) +void IPCThreadState::setTheContextObject(sp obj) { the_context_object = obj; } diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 0203d41992..07550fb571 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -18,6 +18,7 @@ #include +#include #include #include #ifndef __ANDROID_VNDK__ @@ -34,6 +35,9 @@ namespace android { +using AidlServiceManager = android::os::IServiceManager; +using android::binder::Status; + sp defaultServiceManager() { static Mutex gDefaultServiceManagerLock; @@ -142,11 +146,12 @@ class BpServiceManager : public BpInterface { public: explicit BpServiceManager(const sp& impl) - : BpInterface(impl) + : BpInterface(impl), + mTheRealServiceManager(interface_cast(impl)) { } - virtual sp getService(const String16& name) const + sp getService(const String16& name) const override { static bool gSystemBootCompleted = false; @@ -179,43 +184,36 @@ public: return nullptr; } - virtual sp checkService( const String16& name) const - { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); - return reply.readStrongBinder(); + sp checkService(const String16& name) const override { + sp ret; + if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) { + return nullptr; + } + return ret; } - virtual status_t addService(const String16& name, const sp& service, - bool allowIsolated, int dumpsysPriority) { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - data.writeStrongBinder(service); - data.writeInt32(allowIsolated ? 1 : 0); - data.writeInt32(dumpsysPriority); - status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); - return err == NO_ERROR ? reply.readExceptionCode() : err; + status_t addService(const String16& name, const sp& service, + bool allowIsolated, int dumpsysPriority) override { + Status status = mTheRealServiceManager->addService(String8(name).c_str(), service, allowIsolated, dumpsysPriority); + return status.exceptionCode(); } virtual Vector listServices(int dumpsysPriority) { - Vector res; - int n = 0; + std::vector ret; + if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) { + return {}; + } - for (;;) { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeInt32(n++); - data.writeInt32(dumpsysPriority); - status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply); - if (err != NO_ERROR) - break; - res.add(reply.readString16()); + Vector res; + res.setCapacity(ret.size()); + for (const std::string& name : ret) { + res.push(String16(name.c_str())); } return res; } + +private: + sp mTheRealServiceManager; }; IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl new file mode 100644 index 0000000000..50a72aa9e4 --- /dev/null +++ b/libs/binder/aidl/android/os/IServiceManager.aidl @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2006 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. + */ + +package android.os; + +/** + * Basic interface for finding and publishing system services. + * + * You likely want to use android.os.ServiceManager in Java or + * android::IServiceManager in C++ in order to use this interface. + * + * @hide + */ +interface IServiceManager { + /* + * Must update values in IServiceManager.h + */ + /* Allows services to dump sections according to priorities. */ + const int DUMP_FLAG_PRIORITY_CRITICAL = 1; // 1 << 0 + const int DUMP_FLAG_PRIORITY_HIGH = 2; // 1 << 1 + const int DUMP_FLAG_PRIORITY_NORMAL = 4; // 1 << 2 + /** + * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the + * same priority as NORMAL priority but the services are not called with dump priority + * arguments. + */ + const int DUMP_FLAG_PRIORITY_DEFAULT = 8; // 1 << 3 + + const int DUMP_FLAG_PRIORITY_ALL = 15; + // DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH + // | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT; + + /* Allows services to dump sections in protobuf format. */ + const int DUMP_FLAG_PROTO = 16; // 1 << 4 + + /** + * Retrieve an existing service called @a name from the + * service manager. + * + * This is the same as checkService (returns immediately) but + * exists for legacy purposes. + * + * Returns null if the service does not exist. + */ + @UnsupportedAppUsage + IBinder getService(@utf8InCpp String name); + + /** + * Retrieve an existing service called @a name from the service + * manager. Non-blocking. Returns null if the service does not + * exist. + */ + @UnsupportedAppUsage + IBinder checkService(@utf8InCpp String name); + + /** + * Place a new @a service called @a name into the service + * manager. + */ + void addService(@utf8InCpp String name, IBinder service, + boolean allowIsolated, int dumpPriority); + + /** + * Return a list of all currently running services. + */ + @utf8InCpp String[] listServices(int dumpPriority); +} diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index 614b0b33dd..b810f7e8ee 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -110,6 +110,8 @@ public: // the maximum number of binder threads threads allowed for this process. void blockUntilThreadAvailable(); + // Service manager registration + void setTheContextObject(sp obj); // Is this thread currently serving a binder call. This method // returns true if while traversing backwards from the function call -- GitLab From 538cedc381f66f6b07265f82be65e5bc725c7e87 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 24 Jun 2019 19:35:03 -0700 Subject: [PATCH 0051/1255] BufferQueue: handle consumer driven size for pre-rotation This change adds an option for the producer to set auto pre-rotation on the buffers to be allocated. When auto pre-rotation is enabled, if the current buffer size is driven by the consumer and there's 90 or 270 degree rotation specified in the transform hint currently used by the producer, then the dimension of the buffers to be allocated will be additionally swapped upon buffers pre-allocaton or dequeueBuffer. Auto prerotaion will be cached at Surface producer side, and will be reset to false upon Surface disconnection. Bug: 129422697 Test: atest libgui_test:SurfaceTest#DequeueWithConsumerDrivenSize Change-Id: I01ddf3e00d5951935e557d18932ea9869f36b5d6 --- libs/gui/BufferQueueCore.cpp | 12 ++- libs/gui/BufferQueueProducer.cpp | 31 ++++++- libs/gui/IGraphicBufferProducer.cpp | 29 +++++++ libs/gui/Surface.cpp | 27 ++++++ libs/gui/include/gui/BufferQueueCore.h | 8 ++ libs/gui/include/gui/BufferQueueProducer.h | 3 + libs/gui/include/gui/IGraphicBufferProducer.h | 8 ++ libs/gui/include/gui/Surface.h | 3 + libs/gui/tests/Surface_test.cpp | 70 ++++++++++++++++ libs/nativewindow/ANativeWindow.cpp | 4 + libs/nativewindow/include/system/window.h | 83 +++++++++++-------- libs/nativewindow/include/vndk/window.h | 9 ++ libs/nativewindow/libnativewindow.map.txt | 1 + services/surfaceflinger/MonitoredProducer.cpp | 4 + services/surfaceflinger/MonitoredProducer.h | 1 + 15 files changed, 253 insertions(+), 40 deletions(-) diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index e0e3431ca5..b429d387ad 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -97,7 +97,9 @@ BufferQueueCore::BufferQueueCore() : mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE, HAL_DATASPACE_UNKNOWN), mLastQueuedSlot(INVALID_BUFFER_SLOT), - mUniqueId(getUniqueId()) + mUniqueId(getUniqueId()), + mAutoPrerotation(false), + mTransformHintInUse(0) { int numStartingBuffers = getMaxBufferCountLocked(); for (int s = 0; s < numStartingBuffers; s++) { @@ -123,10 +125,12 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const mQueueBufferCanDrop, mLegacyBufferDrop); outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(), mDefaultWidth, mDefaultHeight, mDefaultBufferFormat); - outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint, - mFrameCounter); + outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.string(), + mTransformHint, mFrameCounter); + outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.string(), + mTransformHintInUse, mAutoPrerotation); - outResult->appendFormat("\n%sFIFO(%zu):\n", prefix.string(), mQueue.size()); + outResult->appendFormat("%sFIFO(%zu):\n", prefix.string(), mQueue.size()); Fifo::const_iterator current(mQueue.begin()); while (current != mQueue.end()) { double timestamp = current->mTimestamp / 1e9; diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 9c311a314f..e05667e895 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -408,6 +408,10 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp* ou if (useDefaultSize) { width = mCore->mDefaultWidth; height = mCore->mDefaultHeight; + if (mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(width, height); + } } int found = BufferItem::INVALID_BUFFER_SLOT; @@ -951,7 +955,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, output->width = mCore->mDefaultWidth; output->height = mCore->mDefaultHeight; - output->transformHint = mCore->mTransformHint; + output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint; output->numPendingBuffers = static_cast(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; @@ -1194,7 +1198,7 @@ status_t BufferQueueProducer::connect(const sp& listener, output->width = mCore->mDefaultWidth; output->height = mCore->mDefaultHeight; - output->transformHint = mCore->mTransformHint; + output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint; output->numPendingBuffers = static_cast(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; @@ -1298,6 +1302,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { mCore->mConnectedPid = -1; mCore->mSidebandStream.clear(); mCore->mDequeueCondition.notify_all(); + mCore->mAutoPrerotation = false; listener = mCore->mConsumerListener; } else if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("disconnect: not connected (req=%d)", api); @@ -1341,6 +1346,8 @@ status_t BufferQueueProducer::setSidebandStream(const sp& stream) void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint64_t usage) { ATRACE_CALL(); + + const bool useDefaultSize = !width && !height; while (true) { size_t newBufferCount = 0; uint32_t allocWidth = 0; @@ -1367,6 +1374,11 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, allocWidth = width > 0 ? width : mCore->mDefaultWidth; allocHeight = height > 0 ? height : mCore->mDefaultHeight; + if (useDefaultSize && mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(allocWidth, allocHeight); + } + allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat; allocUsage = usage | mCore->mConsumerUsageBits; allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size()); @@ -1397,6 +1409,11 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, std::unique_lock lock(mCore->mMutex); uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth; uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight; + if (useDefaultSize && mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(checkWidth, checkHeight); + } + PixelFormat checkFormat = format != 0 ? format : mCore->mDefaultBufferFormat; uint64_t checkUsage = usage | mCore->mConsumerUsageBits; @@ -1599,4 +1616,14 @@ status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const { return NO_ERROR; } +status_t BufferQueueProducer::setAutoPrerotation(bool autoPrerotation) { + ATRACE_CALL(); + BQ_LOGV("setAutoPrerotation: %d", autoPrerotation); + + std::lock_guard lock(mCore->mMutex); + + mCore->mAutoPrerotation = autoPrerotation; + return NO_ERROR; +} + } // namespace android diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 0e03b7d393..0b8c70525b 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -73,6 +73,7 @@ enum { GET_UNIQUE_ID, GET_CONSUMER_USAGE, SET_LEGACY_BUFFER_DROP, + SET_AUTO_PREROTATION, }; class BpGraphicBufferProducer : public BpInterface @@ -547,6 +548,17 @@ public: } return actualResult; } + + virtual status_t setAutoPrerotation(bool autoPrerotation) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeBool(autoPrerotation); + status_t result = remote()->transact(SET_AUTO_PREROTATION, data, &reply); + if (result == NO_ERROR) { + result = reply.readInt32(); + } + return result; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -675,6 +687,10 @@ public: status_t getConsumerUsage(uint64_t* outUsage) const override { return mBase->getConsumerUsage(outUsage); } + + status_t setAutoPrerotation(bool autoPrerotation) override { + return mBase->setAutoPrerotation(autoPrerotation); + } }; IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, @@ -688,6 +704,12 @@ status_t IGraphicBufferProducer::setLegacyBufferDrop(bool drop) { return INVALID_OPERATION; } +status_t IGraphicBufferProducer::setAutoPrerotation(bool autoPrerotation) { + // No-op for IGBP other than BufferQueue. + (void)autoPrerotation; + return INVALID_OPERATION; +} + status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) { status_t res = OK; res = parcel->writeUint32(USE_BUFFER_QUEUE); @@ -1050,6 +1072,13 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(result); return NO_ERROR; } + case SET_AUTO_PREROTATION: { + CHECK_INTERFACE(IGraphicBuffer, data, reply); + bool autoPrerotation = data.readBool(); + status_t result = setAutoPrerotation(autoPrerotation); + reply->writeInt32(result); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e6eb327c6f..26b630fec6 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1072,6 +1072,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_GET_CONSUMER_USAGE64: res = dispatchGetConsumerUsage64(args); break; + case NATIVE_WINDOW_SET_AUTO_PREROTATION: + res = dispatchSetAutoPrerotation(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1272,6 +1275,11 @@ int Surface::dispatchGetConsumerUsage64(va_list args) { return getConsumerUsage(usage); } +int Surface::dispatchSetAutoPrerotation(va_list args) { + bool autoPrerotation = va_arg(args, int); + return setAutoPrerotation(autoPrerotation); +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; @@ -1339,6 +1347,7 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) { mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; mStickyTransform = 0; + mAutoPrerotation = false; if (api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = false; @@ -1941,4 +1950,22 @@ status_t Surface::attachAndQueueBuffer(Surface* surface, sp buffe return err; } +int Surface::setAutoPrerotation(bool autoPrerotation) { + ATRACE_CALL(); + ALOGV("Surface::setAutoPrerotation (%d)", autoPrerotation); + Mutex::Autolock lock(mMutex); + + if (mAutoPrerotation == autoPrerotation) { + return OK; + } + + status_t err = mGraphicBufferProducer->setAutoPrerotation(autoPrerotation); + if (err == NO_ERROR) { + mAutoPrerotation = autoPrerotation; + } + ALOGE_IF(err, "IGraphicBufferProducer::setAutoPrerotation(%d) returned %s", autoPrerotation, + strerror(-err)); + return err; +} + }; // namespace android diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 690a85f395..205e79c879 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -348,6 +348,14 @@ private: const uint64_t mUniqueId; + // When buffer size is driven by the consumer and mTransformHint specifies + // a 90 or 270 degree rotation, this indicates whether the width and height + // used by dequeueBuffer will be additionally swapped. + bool mAutoPrerotation; + + // mTransformHintInUse is to cache the mTransformHint used by the producer. + uint32_t mTransformHintInUse; + }; // class BufferQueueCore } // namespace android diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index d2a47a6aa8..9ad92a6e78 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -190,6 +190,9 @@ public: // See IGraphicBufferProducer::getConsumerUsage virtual status_t getConsumerUsage(uint64_t* outUsage) const override; + // See IGraphicBufferProducer::setAutoPrerotation + virtual status_t setAutoPrerotation(bool autoPrerotation); + private: // This is required by the IBinder::DeathRecipient interface virtual void binderDied(const wp& who); diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 3dde8c8c80..986adae864 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -629,6 +629,14 @@ public: // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute. virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0; + // Enable/disable the auto prerotation at buffer allocation when the buffer + // size is driven by the consumer. + // + // When buffer size is driven by the consumer and the transform hint + // specifies a 90 or 270 degree rotation, if auto prerotation is enabled, + // the width and height used for dequeueBuffer will be additionally swapped. + virtual status_t setAutoPrerotation(bool autoPrerotation); + // Static method exports any IGraphicBufferProducer object to a parcel. It // handles null producer as well. static status_t exportToParcel(const sp& producer, diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 0c471bb701..da0282c02e 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -230,6 +230,7 @@ private: int dispatchGetWideColorSupport(va_list args); int dispatchGetHdrSupport(va_list args); int dispatchGetConsumerUsage64(va_list args); + int dispatchSetAutoPrerotation(va_list args); bool transformToDisplayInverse(); protected: @@ -265,6 +266,7 @@ public: virtual int setAsyncMode(bool async); virtual int setSharedBufferMode(bool sharedBufferMode); virtual int setAutoRefresh(bool autoRefresh); + virtual int setAutoPrerotation(bool autoPrerotation); virtual int setBuffersDimensions(uint32_t width, uint32_t height); virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); virtual int unlockAndPost(); @@ -433,6 +435,7 @@ protected: // Caches the values that have been passed to the producer. bool mSharedBufferMode; bool mAutoRefresh; + bool mAutoPrerotation; // If in shared buffer mode and auto refresh is enabled, store the shared // buffer slot and return it for all calls to queue/dequeue without going diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index d3708586f5..7718bc1b8e 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1746,4 +1746,74 @@ TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) { EXPECT_EQ(-1, outDisplayPresentTime); } +TEST_F(SurfaceTest, DequeueWithConsumerDrivenSize) { + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setDefaultBufferSize(10, 10); + + sp surface = new Surface(producer); + sp window(surface); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + native_window_set_buffers_dimensions(window.get(), 0, 0); + + int fence; + ANativeWindowBuffer* buffer; + + // Buffer size is driven by the consumer + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(10, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Buffer size is driven by the consumer + consumer->setDefaultBufferSize(10, 20); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Transform hint isn't synced to producer before queueBuffer or connect + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence)); + + // Transform hint is synced to producer but no auto prerotation + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Prerotation is driven by the consumer with the transform hint used by producer + native_window_set_auto_prerotation(window.get(), true); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(20, buffer->width); + EXPECT_EQ(10, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Turn off auto prerotaton + native_window_set_auto_prerotation(window.get(), false); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Test auto prerotation bit is disabled after disconnect + native_window_set_auto_prerotation(window.get(), true); + native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_CPU); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + native_window_set_buffers_dimensions(window.get(), 0, 0); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); +} + } // namespace android diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 8435dac636..1751443419 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -262,3 +262,7 @@ int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMo int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh) { return native_window_set_auto_refresh(window, autoRefresh); } + +int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation) { + return native_window_set_auto_prerotation(window, autoPrerotation); +} diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 61590e0196..8cbf0a4244 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -203,41 +203,42 @@ enum { */ enum { // clang-format off - NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */ - NATIVE_WINDOW_CONNECT = 1, /* deprecated */ - NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */ - NATIVE_WINDOW_SET_CROP = 3, /* private */ - NATIVE_WINDOW_SET_BUFFER_COUNT = 4, - NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */ - NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6, - NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7, - NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8, - NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9, - NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */ - NATIVE_WINDOW_LOCK = 11, /* private */ - NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */ - NATIVE_WINDOW_API_CONNECT = 13, /* private */ - NATIVE_WINDOW_API_DISCONNECT = 14, /* private */ - NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */ - NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */ - NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */ - NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18, - NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19, - NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */ - NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21, - NATIVE_WINDOW_SET_AUTO_REFRESH = 22, - NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23, - NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24, - NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25, - NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26, - NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27, - NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28, - NATIVE_WINDOW_GET_HDR_SUPPORT = 29, - NATIVE_WINDOW_SET_USAGE64 = 30, - NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31, - NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32, - NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33, + NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */ + NATIVE_WINDOW_CONNECT = 1, /* deprecated */ + NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */ + NATIVE_WINDOW_SET_CROP = 3, /* private */ + NATIVE_WINDOW_SET_BUFFER_COUNT = 4, + NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */ + NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6, + NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7, + NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8, + NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9, + NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */ + NATIVE_WINDOW_LOCK = 11, /* private */ + NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */ + NATIVE_WINDOW_API_CONNECT = 13, /* private */ + NATIVE_WINDOW_API_DISCONNECT = 14, /* private */ + NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */ + NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */ + NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */ + NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18, + NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19, + NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */ + NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21, + NATIVE_WINDOW_SET_AUTO_REFRESH = 22, + NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23, + NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24, + NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25, + NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26, + NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27, + NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28, + NATIVE_WINDOW_GET_HDR_SUPPORT = 29, + NATIVE_WINDOW_SET_USAGE64 = 30, + NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31, + NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32, + NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33, NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34, + NATIVE_WINDOW_SET_AUTO_PREROTATION = 35, // clang-format on }; @@ -985,4 +986,18 @@ static inline int native_window_get_consumer_usage(struct ANativeWindow* window, return window->perform(window, NATIVE_WINDOW_GET_CONSUMER_USAGE64, outUsage); } +/* + * native_window_set_auto_prerotation(..., autoPrerotation) + * Enable/disable the auto prerotation at buffer allocation when the buffer size + * is driven by the consumer. + * + * When buffer size is driven by the consumer and the transform hint specifies + * a 90 or 270 degree rotation, if auto prerotation is enabled, the width and + * height used for dequeueBuffer will be additionally swapped. + */ +static inline int native_window_set_auto_prerotation(struct ANativeWindow* window, + bool autoPrerotation) { + return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation); +} + __END_DECLS diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h index 995ba44d20..500052c936 100644 --- a/libs/nativewindow/include/vndk/window.h +++ b/libs/nativewindow/include/vndk/window.h @@ -316,6 +316,15 @@ int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMo */ int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh); +/* + * Enable/disable the auto prerotation at buffer allocation when the buffer size + * is driven by the consumer. + * + * When buffer size is driven by the consumer and the transform hint specifies + * a 90 or 270 degree rotation, if auto prerotation is enabled, the width and + * height used for dequeueBuffer will be additionally swapped. + */ +int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation); /*****************************************************************************/ diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index bad8b11540..119a07dad7 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -28,6 +28,7 @@ LIBNATIVEWINDOW { ANativeWindow_queryf; # vndk ANativeWindow_queueBuffer; # vndk ANativeWindow_release; + ANativeWindow_setAutoPrerotation; # vndk ANativeWindow_setAutoRefresh; # vndk ANativeWindow_setBufferCount; # vndk ANativeWindow_setBuffersDataSpace; # introduced=28 diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index c60421b538..7a959f7b19 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -154,6 +154,10 @@ status_t MonitoredProducer::getConsumerUsage(uint64_t* outUsage) const { return mProducer->getConsumerUsage(outUsage); } +status_t MonitoredProducer::setAutoPrerotation(bool autoPrerotation) { + return mProducer->setAutoPrerotation(autoPrerotation); +} + IBinder* MonitoredProducer::onAsBinder() { return this; } diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index d346f821d3..788919b3da 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -70,6 +70,7 @@ public: virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override; virtual status_t getUniqueId(uint64_t* outId) const override; virtual status_t getConsumerUsage(uint64_t* outUsage) const override; + virtual status_t setAutoPrerotation(bool autoPrerotation) override; // The Layer which created this producer, and on which queued Buffer's will be displayed. sp getLayer() const; -- GitLab From 626670f88f442d5c3f0bc0e4179a78952c816e1b Mon Sep 17 00:00:00 2001 From: Robert Delgado Date: Thu, 27 Jun 2019 15:55:27 -0700 Subject: [PATCH 0052/1255] Lowered surface flinger trace buffer to 5MB. Bug: 136202290 Test: Create new sftrace and verify less than 5MB. Change-Id: If3dd5f776de337991934bfb178155b7119d485ae --- services/surfaceflinger/SurfaceTracing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index 4773307a65..18524f02d8 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -61,7 +61,7 @@ public: void setTraceFlags(uint32_t flags); private: - static constexpr auto kDefaultBufferCapInByte = 100_MB; + static constexpr auto kDefaultBufferCapInByte = 5_MB; static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb"; class LayersTraceBuffer { // ring buffer -- GitLab From c3e2f8dd52946b1736bb96db4da76425af34196f Mon Sep 17 00:00:00 2001 From: Sahana Rao Date: Fri, 28 Jun 2019 13:18:57 +0100 Subject: [PATCH 0053/1255] dumpstate: Update readme Add command to enable bugreport from new Bugreport API workflow Test: N/A Change-Id: I5299102634ef6421842be90022cbffbb5cdcc812 --- cmds/dumpstate/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md index c818c05117..26dabbbcef 100644 --- a/cmds/dumpstate/README.md +++ b/cmds/dumpstate/README.md @@ -92,6 +92,12 @@ Then to restore the default version: adb shell setprop dumpstate.version default ``` +## To set Bugreport API workflow for bugreport + +``` +adb shell setprop settings_call_bugreport_api true +``` + ## Code style and formatting Use the style defined at the -- GitLab From 8002fcab8445bf52b178691a13a67936c69c8035 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 28 Jun 2019 15:24:13 -0700 Subject: [PATCH 0054/1255] [SurfaceFlinger] Clean-up dead code * Remove methods that are no longer used. * Downgrade visibility of public RenderEngine methods that are currently unused. Test: builds Change-Id: I27d4e1cd7e88b1404d20149e9d0bc89f6cf1bde6 --- libs/renderengine/gl/GLESRenderEngine.cpp | 40 ------------ libs/renderengine/gl/GLESRenderEngine.h | 61 ++++++++----------- .../include/renderengine/RenderEngine.h | 56 ----------------- .../include/renderengine/mock/RenderEngine.h | 24 -------- .../surfaceflinger/BufferLayerConsumer.cpp | 24 -------- services/surfaceflinger/BufferLayerConsumer.h | 5 -- .../include/compositionengine/RenderSurface.h | 4 -- .../compositionengine/impl/RenderSurface.h | 1 - .../compositionengine/mock/RenderSurface.h | 1 - .../CompositionEngine/src/RenderSurface.cpp | 7 --- .../tests/RenderSurfaceTest.cpp | 14 ----- services/surfaceflinger/Layer.cpp | 26 -------- services/surfaceflinger/Layer.h | 2 - services/surfaceflinger/SurfaceFlinger.cpp | 5 -- services/surfaceflinger/SurfaceFlinger.h | 1 - .../tests/unittests/CompositionTest.cpp | 5 -- 16 files changed, 26 insertions(+), 250 deletions(-) diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 46a8e9eecf..6e7ec336e9 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -456,10 +456,6 @@ void GLESRenderEngine::primeCache() const { mFeatureFlags & USE_COLOR_MANAGEMENT); } -bool GLESRenderEngine::isCurrent() const { - return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext(); -} - base::unique_fd GLESRenderEngine::flush() { ATRACE_CALL(); if (!GLExtensions::getInstance().hasNativeFenceSync()) { @@ -795,7 +791,6 @@ status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0); uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d", glStatus); @@ -1013,33 +1008,6 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, return NO_ERROR; } -void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, - ui::Transform::orientation_flags rotation) { - setViewportAndProjection(Rect(vpw, vph), sourceCrop); - - if (rotation == ui::Transform::ROT_0) { - return; - } - - // Apply custom rotation to the projection. - float rot90InRadians = 2.0f * static_cast(M_PI) / 4.0f; - mat4 m = mState.projectionMatrix; - switch (rotation) { - case ui::Transform::ROT_90: - m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m; - break; - case ui::Transform::ROT_180: - m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m; - break; - case ui::Transform::ROT_270: - m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m; - break; - default: - break; - } - mState.projectionMatrix = m; -} - void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) { ATRACE_CALL(); mVpWidth = viewport.getWidth(); @@ -1103,14 +1071,6 @@ void GLESRenderEngine::setupLayerTexturing(const Texture& texture) { mState.textureEnabled = true; } -void GLESRenderEngine::setupLayerBlackedOut() { - glBindTexture(GL_TEXTURE_2D, mProtectedTexName); - Texture texture(Texture::TEXTURE_2D, mProtectedTexName); - texture.setDimensions(1, 1); // FIXME: we should get that from somewhere - mState.texture = texture; - mState.textureEnabled = true; -} - void GLESRenderEngine::setColorTransform(const mat4& colorTransform) { mState.colorMatrix = colorTransform; } diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index de793c2142..70b704abce 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -50,7 +50,6 @@ class GLESRenderEngine : public impl::RenderEngine { public: static std::unique_ptr create(int hwcFormat, uint32_t featureFlags, uint32_t imageCacheSize); - static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy, @@ -58,17 +57,7 @@ public: uint32_t imageCacheSize); ~GLESRenderEngine() override EXCLUDES(mRenderingMutex); - std::unique_ptr createFramebuffer() override; - std::unique_ptr createImage() override; - void primeCache() const override; - bool isCurrent() const override; - base::unique_fd flush() override; - bool finish() override; - bool waitFence(base::unique_fd fenceFd) override; - void clearWithColor(float red, float green, float blue, float alpha) override; - void fillRegionWithColor(const Region& region, float red, float green, float blue, - float alpha) override; void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; void bindExternalTextureImage(uint32_t texName, const Image& image) override; @@ -78,7 +67,6 @@ public: void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex); status_t bindFrameBuffer(Framebuffer* framebuffer) override; void unbindFrameBuffer(Framebuffer* framebuffer) override; - void checkErrors() const override; bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; @@ -88,9 +76,7 @@ public: base::unique_fd&& bufferFence, base::unique_fd* drawFence) EXCLUDES(mRenderingMutex) override; - // internal to RenderEngine EGLDisplay getEGLDisplay() const { return mEGLDisplay; } - EGLConfig getEGLConfig() const { return mEGLConfig; } // Creates an output image for rendering to EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected, bool useFramebufferCache); @@ -104,27 +90,6 @@ public: protected: Framebuffer* getFramebufferForDrawing() override; void dump(std::string& result) override; - void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, - ui::Transform::orientation_flags rotation) override; - void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, - const half4& color, float cornerRadius) override; - void setupLayerTexturing(const Texture& texture) override; - void setupLayerBlackedOut() override; - void setupFillWithColor(float r, float g, float b, float a) override; - void setColorTransform(const mat4& colorTransform) override; - void disableTexturing() override; - void disableBlending() override; - void setupCornerRadiusCropSize(float width, float height) override; - - // HDR and color management related functions and state - void setSourceY410BT2020(bool enable) override; - void setSourceDataSpace(ui::Dataspace source) override; - void setOutputDataSpace(ui::Dataspace dataspace) override; - void setDisplayMaxLuminance(const float maxLuminance) override; - - // drawing - void drawMesh(const Mesh& mesh) override; - size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; @@ -136,12 +101,16 @@ private: GLES_VERSION_3_0 = 0x30000, }; + static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); static GlesVersion parseGlesVersion(const char* str); static EGLContext createEglContext(EGLDisplay display, EGLConfig config, EGLContext shareContext, bool useContextPriority, Protection protection); static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config, int hwcFormat, Protection protection); + std::unique_ptr createFramebuffer(); + std::unique_ptr createImage(); + void checkErrors() const; void setScissor(const Rect& region); void disableScissor(); bool waitSync(EGLSyncKHR sync, EGLint flags); @@ -165,6 +134,28 @@ private: // blending is an expensive operation, we want to turn off blending when it's not necessary. void handleRoundedCorners(const DisplaySettings& display, const LayerSettings& layer, const Mesh& mesh); + base::unique_fd flush(); + bool finish(); + bool waitFence(base::unique_fd fenceFd); + void clearWithColor(float red, float green, float blue, float alpha); + void fillRegionWithColor(const Region& region, float red, float green, float blue, float alpha); + void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, + const half4& color, float cornerRadius); + void setupLayerTexturing(const Texture& texture); + void setupFillWithColor(float r, float g, float b, float a); + void setColorTransform(const mat4& colorTransform); + void disableTexturing(); + void disableBlending(); + void setupCornerRadiusCropSize(float width, float height); + + // HDR and color management related functions and state + void setSourceY410BT2020(bool enable); + void setSourceDataSpace(ui::Dataspace source); + void setOutputDataSpace(ui::Dataspace dataspace); + void setDisplayMaxLuminance(const float maxLuminance); + + // drawing + void drawMesh(const Mesh& mesh); EGLDisplay mEGLDisplay; EGLConfig mEGLConfig; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index e7070041f2..8a798eefd1 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -77,10 +77,6 @@ public: // This interface, while still in use until a suitable replacement is built, // should be considered deprecated, minus some methods which still may be // used to support legacy behavior. - - virtual std::unique_ptr createFramebuffer() = 0; - virtual std::unique_ptr createImage() = 0; - virtual void primeCache() const = 0; // dump the extension strings. always call the base class. @@ -88,24 +84,6 @@ public: virtual bool useNativeFenceSync() const = 0; virtual bool useWaitSync() const = 0; - - virtual bool isCurrent() const = 0; - - // helpers - // flush submits RenderEngine command stream for execution and returns a - // native fence fd that is signaled when the execution has completed. It - // returns -1 on errors. - virtual base::unique_fd flush() = 0; - // finish waits until RenderEngine command stream has been executed. It - // returns false on errors. - virtual bool finish() = 0; - // waitFence inserts a wait on an external fence fd to RenderEngine - // command stream. It returns false on errors. - virtual bool waitFence(base::unique_fd fenceFd) = 0; - - virtual void clearWithColor(float red, float green, float blue, float alpha) = 0; - virtual void fillRegionWithColor(const Region& region, float red, float green, float blue, - float alpha) = 0; virtual void genTextures(size_t count, uint32_t* names) = 0; virtual void deleteTextures(size_t count, uint32_t const* names) = 0; virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0; @@ -126,40 +104,6 @@ public: virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0; virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0; - // set-up - virtual void checkErrors() const = 0; - virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, - ui::Transform::orientation_flags rotation) = 0; - virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, - const half4& color, float cornerRadius) = 0; - virtual void setupLayerTexturing(const Texture& texture) = 0; - virtual void setupLayerBlackedOut() = 0; - virtual void setupFillWithColor(float r, float g, float b, float a) = 0; - // Sets up the crop size for corner radius clipping. - // - // Having corner radius will force GPU composition on the layer and its children, drawing it - // with a special shader. The shader will receive the radius and the crop rectangle as input, - // modifying the opacity of the destination texture, multiplying it by a number between 0 and 1. - // We query Layer#getRoundedCornerState() to retrieve the radius as well as the rounded crop - // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be - // in local layer coordinate space, so we have to take the layer transform into account when - // walking up the tree. - virtual void setupCornerRadiusCropSize(float width, float height) = 0; - - // Set a color transform matrix that is applied in linear space right before OETF. - virtual void setColorTransform(const mat4& /* colorTransform */) = 0; - virtual void disableTexturing() = 0; - virtual void disableBlending() = 0; - - // HDR and color management support - virtual void setSourceY410BT2020(bool enable) = 0; - virtual void setSourceDataSpace(ui::Dataspace source) = 0; - virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0; - virtual void setDisplayMaxLuminance(const float maxLuminance) = 0; - - // drawing - virtual void drawMesh(const Mesh& mesh) = 0; - // queries virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index e33bcfd994..f099cd2455 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -34,20 +34,12 @@ public: RenderEngine(); ~RenderEngine() override; - MOCK_METHOD0(createFramebuffer, std::unique_ptr()); - MOCK_METHOD0(createImage, std::unique_ptr()); MOCK_METHOD0(getFramebufferForDrawing, Framebuffer*()); MOCK_CONST_METHOD0(primeCache, void()); MOCK_METHOD1(dump, void(std::string&)); MOCK_CONST_METHOD0(useNativeFenceSync, bool()); MOCK_CONST_METHOD0(useWaitSync, bool()); MOCK_CONST_METHOD0(isCurrent, bool()); - MOCK_METHOD0(flush, base::unique_fd()); - MOCK_METHOD0(finish, bool()); - MOCK_METHOD1(waitFence, bool(base::unique_fd*)); - bool waitFence(base::unique_fd fd) override { return waitFence(&fd); }; - MOCK_METHOD4(clearWithColor, void(float, float, float, float)); - MOCK_METHOD5(fillRegionWithColor, void(const Region&, float, float, float, float)); MOCK_METHOD2(genTextures, void(size_t, uint32_t*)); MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*)); MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&)); @@ -55,22 +47,6 @@ public: MOCK_METHOD3(bindExternalTextureBuffer, status_t(uint32_t, const sp&, const sp&)); MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t)); - MOCK_CONST_METHOD0(checkErrors, void()); - MOCK_METHOD4(setViewportAndProjection, - void(size_t, size_t, Rect, ui::Transform::orientation_flags)); - MOCK_METHOD5(setupLayerBlending, void(bool, bool, bool, const half4&, float)); - MOCK_METHOD1(setupLayerTexturing, void(const Texture&)); - MOCK_METHOD0(setupLayerBlackedOut, void()); - MOCK_METHOD4(setupFillWithColor, void(float, float, float, float)); - MOCK_METHOD2(setupCornerRadiusCropSize, void(float, float)); - MOCK_METHOD1(setColorTransform, void(const mat4&)); - MOCK_METHOD1(setSaturationMatrix, void(const mat4&)); - MOCK_METHOD0(disableTexturing, void()); - MOCK_METHOD0(disableBlending, void()); - MOCK_METHOD1(setSourceY410BT2020, void(bool)); - MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace)); - MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace)); - MOCK_METHOD1(setDisplayMaxLuminance, void(const float)); MOCK_METHOD1(bindFrameBuffer, status_t(renderengine::Framebuffer*)); MOCK_METHOD1(unbindFrameBuffer, void(renderengine::Framebuffer*)); MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&)); diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 6709fb4b48..096cd1a9cc 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -419,30 +419,6 @@ std::shared_ptr BufferLayerConsumer::getCurrentFenceTime() const { return mCurrentFenceTime; } -status_t BufferLayerConsumer::doFenceWaitLocked() const { - if (mCurrentFence->isValid()) { - if (mRE.useWaitSync()) { - base::unique_fd fenceFd(mCurrentFence->dup()); - if (fenceFd == -1) { - BLC_LOGE("doFenceWait: error dup'ing fence fd: %d", errno); - return -errno; - } - if (!mRE.waitFence(std::move(fenceFd))) { - BLC_LOGE("doFenceWait: failed to wait on fence fd"); - return UNKNOWN_ERROR; - } - } else { - status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doFenceWaitLocked"); - if (err != NO_ERROR) { - BLC_LOGE("doFenceWait: error waiting for fence: %d", err); - return err; - } - } - } - - return NO_ERROR; -} - void BufferLayerConsumer::freeBufferLocked(int slotIndex) { BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); std::lock_guard lock(mImagesMutex); diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index e3f6100c35..144686c83d 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -252,11 +252,6 @@ private: // mCurrentTextureImage must not be nullptr. void computeCurrentTransformMatrixLocked(); - // doFenceWaitLocked inserts a wait command into the RenderEngine command - // stream to ensure that it is safe for future RenderEngine commands to - // access the current texture buffer. - status_t doFenceWaitLocked() const; - // getCurrentCropLocked returns the cropping rectangle of the current buffer. Rect getCurrentCropLocked() const; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index e21128ca81..9bff73e950 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -83,10 +83,6 @@ public: // Called after the HWC calls are made to present the display virtual void onPresentDisplayCompleted() = 0; - // Called to set the viewport and projection state for rendering into this - // surface - virtual void setViewportAndProjection() = 0; - // Called after the surface has been rendering to signal the surface should // be made ready for displaying virtual void flip() = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index 0f57315eb6..e4c9c80429 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -56,7 +56,6 @@ public: sp dequeueBuffer(base::unique_fd* bufferFence) override; void queueBuffer(base::unique_fd&& readyFence) override; void onPresentDisplayCompleted() override; - void setViewportAndProjection() override; void flip() override; // Debugging diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index ca2299aa26..146a2eae64 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -41,7 +41,6 @@ public: MOCK_METHOD1(dequeueBuffer, sp(base::unique_fd*)); MOCK_METHOD1(queueBuffer, void(base::unique_fd&&)); MOCK_METHOD0(onPresentDisplayCompleted, void()); - MOCK_METHOD0(setViewportAndProjection, void()); MOCK_METHOD0(flip, void()); MOCK_CONST_METHOD1(dump, void(std::string& result)); MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t()); diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 3fcd9d155d..8a91316e65 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -215,13 +215,6 @@ void RenderSurface::onPresentDisplayCompleted() { mDisplaySurface->onFrameCommitted(); } -void RenderSurface::setViewportAndProjection() { - auto& renderEngine = mCompositionEngine.getRenderEngine(); - Rect sourceCrop = Rect(mSize); - renderEngine.setViewportAndProjection(mSize.width, mSize.height, sourceCrop, - ui::Transform::ROT_0); -} - void RenderSurface::flip() { mPageFlipCount++; } diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index f75a4dcb85..87419ea6a8 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -363,20 +363,6 @@ TEST_F(RenderSurfaceTest, onPresentDisplayCompletedForwardsSignal) { mSurface.onPresentDisplayCompleted(); } -/* ------------------------------------------------------------------------ - * RenderSurface::setViewportAndProjection() - */ - -TEST_F(RenderSurfaceTest, setViewportAndProjectionAppliesChang) { - mSurface.setSizeForTest(ui::Size(100, 200)); - - EXPECT_CALL(mRenderEngine, - setViewportAndProjection(100, 200, Rect(100, 200), ui::Transform::ROT_0)) - .Times(1); - - mSurface.setViewportAndProjection(); -} - /* ------------------------------------------------------------------------ * RenderSurface::flip() */ diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b2df91d4ea..83ab5cfce2 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -619,32 +619,6 @@ bool Layer::addSyncPoint(const std::shared_ptr& point) { // local state // ---------------------------------------------------------------------------- -void Layer::computeGeometry(const RenderArea& renderArea, - renderengine::Mesh& mesh, - bool useIdentityTransform) const { - const ui::Transform renderAreaTransform(renderArea.getTransform()); - FloatRect win = getBounds(); - - vec2 lt = vec2(win.left, win.top); - vec2 lb = vec2(win.left, win.bottom); - vec2 rb = vec2(win.right, win.bottom); - vec2 rt = vec2(win.right, win.top); - - ui::Transform layerTransform = getTransform(); - if (!useIdentityTransform) { - lt = layerTransform.transform(lt); - lb = layerTransform.transform(lb); - rb = layerTransform.transform(rb); - rt = layerTransform.transform(rt); - } - - renderengine::Mesh::VertexArray position(mesh.getPositionArray()); - position[0] = renderAreaTransform.transform(lt); - position[1] = renderAreaTransform.transform(lb); - position[2] = renderAreaTransform.transform(rb); - position[3] = renderAreaTransform.transform(rt); -} - bool Layer::isSecure() const { const State& s(mDrawingState); return (s.flags & layer_state_t::eLayerSecure); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 6db6beb4f6..8a4d87f889 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -357,8 +357,6 @@ public: return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay); } - void computeGeometry(const RenderArea& renderArea, renderengine::Mesh& mesh, - bool useIdentityTransform) const; FloatRect getBounds(const Region& activeTransparentRegion) const; FloatRect getBounds() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e5896f9985..2cb2544448 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3534,11 +3534,6 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& displayDevice, return true; } -void SurfaceFlinger::drawWormhole(const Region& region) const { - auto& engine(getRenderEngine()); - engine.fillRegionWithColor(region, 0, 0, 0, 0); -} - status_t SurfaceFlinger::addClientLayer(const sp& client, const sp& handle, const sp& gbc, const sp& lbc, const sp& parentHandle, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6d4b2d755c..1a9dcdd2ef 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -790,7 +790,6 @@ private: void postFramebuffer(const sp& display); void postFrame(); - void drawWormhole(const Region& region) const; /* ------------------------------------------------------------------------ * Display management diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 4f8ed1ae1c..e6211c488e 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -303,11 +303,6 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1); EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true)); - // TODO: remove once we verify that we can just grab the fence from the - // FramebufferSurface. - EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() { - return base::unique_fd(); - })); EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1); EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1); -- GitLab From 9b5a821d1e214cac16a7d03b590964375fd2614a Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 1 Jul 2019 14:25:40 -0700 Subject: [PATCH 0055/1255] Do not use moved-from object We are currently reading a field from a moved-from object. Remove this read. Bug: none Test: none Change-Id: I0d33636f653b7f7ae0b98e4645ee8779bf9da2ea --- services/inputflinger/InputClassifier.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 6a7f2797f4..7c061c5857 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -276,7 +276,7 @@ void MotionClassifier::enqueueEvent(ClassifierEvent&& event) { bool eventAdded = mEvents.push(std::move(event)); if (!eventAdded) { // If the queue is full, suspect the HAL is slow in processing the events. - ALOGE("Dropped event with eventTime %" PRId64, event.args->eventTime); + ALOGE("Could not add the event to the queue. Resetting"); reset(); } } -- GitLab From 83e514e303ffb18557984a89fbd3f0bbaac498ee Mon Sep 17 00:00:00 2001 From: Tianyu Jiang Date: Wed, 15 May 2019 15:05:30 -0700 Subject: [PATCH 0056/1255] Add GraphicBuffer over binder test and fix a crash in unflatten logic Test: GraphicBuffer_test GraphicBufferOverBinder_test Bug: None Change-Id: Idf00fcb740661adc1e1bb41dc2d78ece4f589c95 --- libs/ui/BufferHubBuffer.cpp | 1 + libs/ui/GraphicBuffer.cpp | 2 +- libs/ui/tests/Android.bp | 18 ++ .../ui/tests/GraphicBufferOverBinder_test.cpp | 170 ++++++++++++++++++ 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 libs/ui/tests/GraphicBufferOverBinder_test.cpp diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp index da91a979fe..1dfc1e9e88 100644 --- a/libs/ui/BufferHubBuffer.cpp +++ b/libs/ui/BufferHubBuffer.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define LOG_TAG "BufferHubBuffer" #include #include diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 3fc6a2d34a..579e68e917 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -626,7 +626,7 @@ status_t GraphicBuffer::unflattenBufferHubBuffer(void const*& buffer, size_t& si bufferHubBuffer->desc().layers, bufferHubBuffer->desc().usage, bufferHubBuffer->desc().stride); mBufferId = bufferHubBuffer->id(); - mBufferHubBuffer.reset(std::move(bufferHubBuffer.get())); + mBufferHubBuffer = std::move(bufferHubBuffer); return NO_ERROR; } diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 373fa4f221..c5170d091c 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -46,6 +46,24 @@ cc_test { cflags: ["-Wall", "-Werror"], } +// This test has a main method, and requires a separate binary to be built. +cc_test { + name: "GraphicBufferOverBinder_test", + srcs: ["GraphicBufferOverBinder_test.cpp"], + cflags: ["-Wall", "-Werror"], + header_libs: [ + "libdvr_headers", + ], + shared_libs: [ + "android.frameworks.bufferhub@1.0", + "libbinder", + "libgui", + "liblog", + "libui", + "libutils", + ], +} + cc_test { name: "BufferHub_test", header_libs: [ diff --git a/libs/ui/tests/GraphicBufferOverBinder_test.cpp b/libs/ui/tests/GraphicBufferOverBinder_test.cpp new file mode 100644 index 0000000000..7c0a44a64f --- /dev/null +++ b/libs/ui/tests/GraphicBufferOverBinder_test.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "GraphicBufferOverBinder_test" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +constexpr uint32_t kTestWidth = 1024; +constexpr uint32_t kTestHeight = 1; +constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB; +constexpr uint32_t kTestLayerCount = 1; +constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN; +static const String16 kTestServiceName = String16("GraphicBufferOverBinderTestService"); +enum GraphicBufferOverBinderTestServiceCode { + GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION, + GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER, +}; + +class GraphicBufferOverBinderTestService : public BBinder { +public: + GraphicBufferOverBinderTestService() { + // GraphicBuffer + mGraphicBuffer = new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, + kTestUsage); + ALOGI("mGraphicBuffer id %" PRIi32, mGraphicBuffer->getBufferId()); + + // BufferHub-backed GraphicBuffer + std::unique_ptr bufferHubBuffer = + BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat, + kTestUsage, /*userMetadataSize=*/0); + mBufferhubBackedGraphicBuffer = new GraphicBuffer(std::move(bufferHubBuffer)); + if (!mBufferhubBackedGraphicBuffer->isBufferHubBuffer()) { + ALOGE("Failed to back GraphicBuffer with BufferHub."); + } + if (bufferHubBuffer != nullptr) { + ALOGE("Failed to move BufferHubBuffer to GraphicBuffer"); + } + ALOGI("mBufferhubBackedGraphicBuffer id %" PRIi32, + mBufferhubBackedGraphicBuffer->getBufferId()); + } + + ~GraphicBufferOverBinderTestService() = default; + + virtual status_t onTransact(uint32_t code, const Parcel& /*data*/, Parcel* reply, + uint32_t /*flags*/ = 0) { + switch (code) { + case GRAPHIC_BUFFER: { + return reply->write(*mGraphicBuffer); + } + case GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER: { + return reply->write(*mBufferhubBackedGraphicBuffer); + } + default: + return UNKNOWN_TRANSACTION; + }; + } + +protected: + sp mGraphicBuffer; + sp mBufferhubBackedGraphicBuffer; +}; + +static int runBinderServer() { + ProcessState::self()->startThreadPool(); + + sp sm = defaultServiceManager(); + sp service = new GraphicBufferOverBinderTestService; + sm->addService(kTestServiceName, service, false); + + ALOGI("Binder server running..."); + + while (true) { + int stat, retval; + retval = wait(&stat); + if (retval == -1 && errno == ECHILD) { + break; + } + } + + ALOGI("Binder server exiting..."); + return 0; +} + +class GraphicBufferOverBinderTest : public ::testing::TestWithParam { +protected: + virtual void SetUp() { + mService = defaultServiceManager()->getService(kTestServiceName); + if (mService == nullptr) { + ALOGE("Failed to connect to the test service."); + return; + } + + ALOGI("Binder service is ready for client."); + } + + status_t GetGraphicBuffer(sp* outBuf, uint32_t opCode) { + Parcel data; + Parcel reply; + status_t error = mService->transact(opCode, data, &reply); + if (error != NO_ERROR) { + ALOGE("Failed to get graphic buffer over binder, error=%d.", error); + return error; + } + + *outBuf = new GraphicBuffer(); + return reply.read(**outBuf); + } + +private: + sp mService; +}; + +TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferOverBinder) { + sp gb; + EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER), OK); + EXPECT_NE(gb, nullptr); + EXPECT_FALSE(gb->isBufferHubBuffer()); + void* vaddr; + EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK); + EXPECT_EQ(gb->unlock(), OK); +} + +TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferFromBufferHubBufferOverBinder) { + sp gb; + EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER), NO_ERROR); + EXPECT_NE(gb, nullptr); + EXPECT_TRUE(gb->isBufferHubBuffer()); + void* vaddr; + EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK); + EXPECT_EQ(gb->unlock(), OK); +} + +} // namespace android + +int main(int argc, char** argv) { + pid_t pid = fork(); + if (pid == 0) { + android::ProcessState::self()->startThreadPool(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + + } else { + ALOGI("Test process pid: %d.", pid); + return android::runBinderServer(); + } +} -- GitLab From ff7bf701ad4a66ee4b9fe54c41e24fb5099fb533 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 5 Jun 2019 18:27:47 -0700 Subject: [PATCH 0057/1255] libtimeinstate: add more tests Check reported values to confirm that getUidCpuFreqTimes() and getUidsCpuFreqTimes() are behaving reasonably. Also revise RemoveUid test to create and then delete map entries for an unused UID rather than UID 0. getUidCpuFreqTimes() is only meant to be called when an app is uninstalled, and calling it with a UID that has running tasks creates data inconsistencies that can cause the new tests to fail. Since the revised test needs to directly manipulate the BPF map in order to add a fake entry, move some definitions from cputimeinstate.cpp into a header file to make them available for the test. Test: libtimeinstate_test passes Bug: 78498733 Change-Id: I1587b1c7db870343ff863f2156b2a810d8ace915 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/Android.bp | 4 + libs/cputimeinstate/cputimeinstate.cpp | 12 +-- libs/cputimeinstate/testtimeinstate.cpp | 112 ++++++++++++++++++++++-- libs/cputimeinstate/timeinstate.h | 28 ++++++ 4 files changed, 136 insertions(+), 20 deletions(-) create mode 100644 libs/cputimeinstate/timeinstate.h diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp index 28cb13827d..9080ce13db 100644 --- a/libs/cputimeinstate/Android.bp +++ b/libs/cputimeinstate/Android.bp @@ -19,7 +19,11 @@ cc_test { name: "libtimeinstate_test", srcs: ["testtimeinstate.cpp"], shared_libs: [ + "libbase", + "libbpf", + "libbpf_android", "libtimeinstate", + "libnetdutils", ], cflags: [ "-Werror", diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 41cbde1c18..0e68e628b6 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "libtimeinstate" #include "cputimeinstate.h" +#include "timeinstate.h" #include #include @@ -38,23 +39,12 @@ #include #include -#define BPF_FS_PATH "/sys/fs/bpf/" - using android::base::StringPrintf; using android::base::unique_fd; namespace android { namespace bpf { -struct time_key_t { - uint32_t uid; - uint32_t freq; -}; - -struct val_t { - uint64_t ar[100]; -}; - static std::mutex gInitializedMutex; static bool gInitialized = false; static uint32_t gNPolicies = 0; diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index d4b87386e0..6347de166a 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -1,14 +1,24 @@ +#include "timeinstate.h" + +#include + #include #include #include +#include +#include #include +#include namespace android { namespace bpf { +static constexpr uint64_t NSEC_PER_SEC = 1000000000; +static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365; + using std::vector; TEST(TimeInStateTest, SingleUid) { @@ -33,8 +43,95 @@ TEST(TimeInStateTest, AllUid) { } } +TEST(TimeInStateTest, SingleAndAllUidConsistent) { + auto map = getUidsCpuFreqTimes(); + ASSERT_TRUE(map.has_value()); + ASSERT_FALSE(map->empty()); + + for (const auto &kv : *map) { + uint32_t uid = kv.first; + auto times1 = kv.second; + auto times2 = getUidCpuFreqTimes(uid); + ASSERT_TRUE(times2.has_value()); + + ASSERT_EQ(times1.size(), times2->size()); + for (uint32_t i = 0; i < times1.size(); ++i) { + ASSERT_EQ(times1[i].size(), (*times2)[i].size()); + for (uint32_t j = 0; j < times1[i].size(); ++j) { + ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC); + } + } + } +} + +void TestCheckDelta(uint64_t before, uint64_t after) { + // Times should never decrease + ASSERT_LE(before, after); + // UID can't have run for more than ~1s on each CPU + ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf()); +} + +TEST(TimeInStateTest, AllUidMonotonic) { + auto map1 = getUidsCpuFreqTimes(); + ASSERT_TRUE(map1.has_value()); + sleep(1); + auto map2 = getUidsCpuFreqTimes(); + ASSERT_TRUE(map2.has_value()); + + for (const auto &kv : *map1) { + uint32_t uid = kv.first; + auto times = kv.second; + ASSERT_NE(map2->find(uid), map2->end()); + for (uint32_t policy = 0; policy < times.size(); ++policy) { + for (uint32_t freqIdx = 0; freqIdx < times[policy].size(); ++freqIdx) { + auto before = times[policy][freqIdx]; + auto after = (*map2)[uid][policy][freqIdx]; + ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after)); + } + } + } +} + +TEST(TimeInStateTest, AllUidSanityCheck) { + auto map = getUidsCpuFreqTimes(); + ASSERT_TRUE(map.has_value()); + + bool foundLargeValue = false; + for (const auto &kv : *map) { + for (const auto &timeVec : kv.second) { + for (const auto &time : timeVec) { + ASSERT_LE(time, NSEC_PER_YEAR); + if (time > UINT32_MAX) foundLargeValue = true; + } + } + } + // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using + // uint64_t as expected, we should have some times higher than that. + ASSERT_TRUE(foundLargeValue); +} + TEST(TimeInStateTest, RemoveUid) { - auto times = getUidCpuFreqTimes(0); + uint32_t uid = 0; + { + // Find an unused UID + auto times = getUidsCpuFreqTimes(); + ASSERT_TRUE(times.has_value()); + ASSERT_FALSE(times->empty()); + for (const auto &kv : *times) uid = std::max(uid, kv.first); + ++uid; + } + { + // Add a map entry for our fake UID by copying a real map entry + android::base::unique_fd fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")}; + ASSERT_GE(fd, 0); + time_key_t k; + ASSERT_FALSE(getFirstMapKey(fd, &k)); + val_t val; + ASSERT_FALSE(findMapEntry(fd, &k, &val)); + k.uid = uid; + ASSERT_FALSE(writeToMapEntry(fd, &k, &val, BPF_NOEXIST)); + } + auto times = getUidCpuFreqTimes(uid); ASSERT_TRUE(times.has_value()); ASSERT_FALSE(times->empty()); @@ -44,15 +141,12 @@ TEST(TimeInStateTest, RemoveUid) { } ASSERT_GT(sum, (uint64_t)0); - ASSERT_TRUE(clearUidCpuFreqTimes(0)); + ASSERT_TRUE(clearUidCpuFreqTimes(uid)); - auto times2 = getUidCpuFreqTimes(0); - ASSERT_TRUE(times2.has_value()); - ASSERT_EQ(times2->size(), times->size()); - for (size_t i = 0; i < times->size(); ++i) { - ASSERT_EQ((*times2)[i].size(), (*times)[i].size()); - for (size_t j = 0; j < (*times)[i].size(); ++j) ASSERT_LE((*times2)[i][j], (*times)[i][j]); - } + auto allTimes = getUidsCpuFreqTimes(); + ASSERT_TRUE(allTimes.has_value()); + ASSERT_FALSE(allTimes->empty()); + ASSERT_EQ(allTimes->find(uid), allTimes->end()); } } // namespace bpf diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h new file mode 100644 index 0000000000..cf66ae7077 --- /dev/null +++ b/libs/cputimeinstate/timeinstate.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define BPF_FS_PATH "/sys/fs/bpf/" + +struct time_key_t { + uint32_t uid; + uint32_t freq; +}; + +struct val_t { + uint64_t ar[100]; +}; -- GitLab From 751a7dcc1f03d5704104d418387127c2f0843b1b Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan Date: Tue, 2 Jul 2019 17:17:25 -0700 Subject: [PATCH 0058/1255] Generate Vulkan framework from Vulkan registry Instead of using the manually created vulkan.api file for generating the Vulkan framework, we generate it directly from the vulkan registry (vk.xml) Bug: 134711355 Test: Build and flash, dEQP tests Change-Id: I7e85cd4b64d13b8ed2c54678090f405171854a40 --- vulkan/scripts/api_generator.py | 344 +++++++++++++++++++++++++++++ vulkan/scripts/code_generator.py | 26 +++ vulkan/scripts/generator_common.py | 238 ++++++++++++++++++++ 3 files changed, 608 insertions(+) create mode 100644 vulkan/scripts/api_generator.py create mode 100644 vulkan/scripts/code_generator.py create mode 100644 vulkan/scripts/generator_common.py diff --git a/vulkan/scripts/api_generator.py b/vulkan/scripts/api_generator.py new file mode 100644 index 0000000000..05dc9957b0 --- /dev/null +++ b/vulkan/scripts/api_generator.py @@ -0,0 +1,344 @@ +#!/usr/bin/env python3 +# +# 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. +# +# This script provides the functions required for generating the +# vulkan api framework directly from the vulkan registry (vk.xml) + +import os +import generator_common as gencom + +def isInstanceDispatchTableEntry(functionName): + if functionName == 'vkEnumerateDeviceLayerProperties': # deprecated, unused internally - @dbd33bc + return False + if gencom.gencom.isFunctionExported(functionName) and gencom.isInstanceDispatched(functionName): + return True + return False + +def isDeviceDispatchTableEntry(functionName): + if gencom.gencom.isFunctionExported(functionName) and gencom.gencom.isDeviceDispatched(functionName): + return True + return False + +def api_genh(): + + header = """#ifndef LIBVULKAN_API_GEN_H +#define LIBVULKAN_API_GEN_H + +#include + +#include + +#include "driver_gen.h" + +namespace vulkan { +namespace api { + +""" + + tail = """ +bool InitDispatchTable( + VkInstance instance, + PFN_vkGetInstanceProcAddr get_proc, + const std::bitset& extensions); +bool InitDispatchTable( + VkDevice dev, + PFN_vkGetDeviceProcAddr get_proc, + const std::bitset& extensions); + +} // namespace api +} // namespace vulkan + +#endif // LIBVULKAN_API_GEN_H +""" + genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen2.h') + with open(genfile, 'w') as f: + instanceDispatchTableEntries = [] + deviceDispatchTableEntries = [] + for commands in gencom.allCommandsList: + if commands not in gencom.aliasDict: + if gencom.isInstanceDispatchTableEntry(commands): + instanceDispatchTableEntries.append('PFN_'+commands+' '+commands[2:]+';') + elif gencom.isDeviceDispatchTableEntry(commands): + deviceDispatchTableEntries.append('PFN_'+commands+' '+commands[2:]+';') + + f.write (gencom.copyright) + f.write (gencom.warning) + f.write (header) + f.write ('struct InstanceDispatchTable {\n') + gencom.clang_off(f,1) + for functions in instanceDispatchTableEntries: + f.write(gencom.clang_off_spaces + functions + '\n') + gencom.clang_on(f,1) + f.write ('};\n\n') + + f.write ('struct DeviceDispatchTable {\n') + gencom.clang_off(f,1) + for functions in deviceDispatchTableEntries: + f.write(gencom.clang_off_spaces + functions + '\n') + gencom.clang_on(f,1) + f.write ('};\n') + + f.write (tail) + f.close() + +def defineInitProc(name, f): + f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n') + f.write ('\n') + f.write ("""#define INIT_PROC(required, obj, proc) \\ + do { \\ + data.""" + name + """.proc = \\ + reinterpret_cast(get_proc(obj, "vk" #proc)); \\ + if (UNLIKELY(required && !data.""" + name + """.proc)) { \\ + ALOGE("missing " #obj " proc: vk" #proc); \\ + success = false; \\ + } \\ + } while (0)\n\n""") + +def defineInitProcExt(f): + f.write ('// Exported extension functions may be invoked even when their extensions\n') + f.write ('// are disabled. Dispatch to stubs when that happens.\n') + f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc) \\ + do { \\ + if (extensions[driver::ProcHook::ext]) \\ + INIT_PROC(required, obj, proc); \\ + else \\ + data.dispatch.proc = disabled##proc; \\ + } while (0)\n\n""") + +def defineExtensionStub(functionName, f): + if functionName in gencom.extensionsDict and gencom.isFunctionExported(functionName): + extname = gencom.extensionsDict[functionName] + base_name = functionName[2:] + pList = gencom.paramDict[functionName] + firstParam = pList[0][0] + pList[0][1] + tailParams = [x[0][:-1] for x in pList[1:]] + tailP = ', '.join(tailParams) + f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' disabled' + base_name + '(' + firstParam + ', ' + tailP + ') {\n') + f.write (gencom.clang_off_spaces) + f.write ('driver::Logger(' + pList[0][1] + ').Err(' + pList[0][1] + ', \"' + extname + ' not enabled. Exported ' + functionName + ' not executed.\");\n') + if gencom.returnTypeDict[functionName] != 'void': + f.write(gencom.clang_off_spaces + 'return VK_SUCCESS;\n') + f.write ('}\n\n') + +def isIntercepted(functionName): + if gencom.isFunctionSupported(functionName): + if gencom.isGloballyDispatched(functionName): + return True + elif functionName == 'vkCreateDevice': + return True + elif functionName == 'vkEnumerateDeviceLayerProperties': + return True + elif functionName == 'vkEnumerateDeviceExtensionProperties': + return True + elif functionName == 'vkDestroyInstance': + return True + elif functionName == 'vkDestroyDevice': + return True + return False + +def interceptInstanceProcAddr(functionName, f): + indent = 1 + f.write (gencom.clang_off_spaces*indent + '// global functions\n' + gencom.clang_off_spaces*indent+ 'if (instance == VK_NULL_HANDLE) {\n') + indent = indent + 1 + for cmds in gencom.allCommandsList: + if gencom.isGloballyDispatched(cmds): + f.write(gencom.clang_off_spaces*indent + 'if (strcmp(pName, \"' + cmds + '\") == 0) return reinterpret_cast(' + cmds[2:] + ');\n') + + f.write ('\n') + f.write (""" ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \\\"%s\\\") call", pName); + return nullptr; + } + + static const struct Hook { + const char* name; + PFN_vkVoidFunction proc; + } hooks[] = {\n""") + sortedCommandsList = sorted(gencom.allCommandsList) + for cmds in sortedCommandsList: + if gencom.isFunctionExported(cmds): + if gencom.isGloballyDispatched(cmds): + f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", nullptr },\n') + elif isIntercepted(cmds) or cmds == 'vkGetInstanceProcAddr' or gencom.isDeviceDispatched(cmds): + f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", reinterpret_cast(' + cmds[2:] + ') },\n') + f.write (gencom.clang_off_spaces + """}; + // clang-format on + constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]); + auto hook = std::lower_bound( + hooks, hooks + count, pName, + [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; }); + if (hook < hooks + count && strcmp(hook->name, pName) == 0) { + if (!hook->proc) { + vulkan::driver::Logger(instance).Err( + instance, "invalid vkGetInstanceProcAddr(%p, \\\"%s\\\") call", + instance, pName); + } + return hook->proc; + } + // clang-format off\n\n""") + +def interceptDeviceProcAddr(functionName, f): + f.write (gencom.clang_off_spaces + """if (device == VK_NULL_HANDLE) { + ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call"); + return nullptr; + }\n\n""") + f.write (gencom.clang_off_spaces + 'static const char* const known_non_device_names[] = {\n') + sortedCommandsList = sorted(gencom.allCommandsList) + for cmds in sortedCommandsList: + if gencom.isFunctionSupported(cmds): + if not gencom.isDeviceDispatched(cmds): + f.write(gencom.clang_off_spaces*2 + '\"' + cmds + '\",\n') + f.write(gencom.clang_off_spaces + '};\n') + f.write(gencom.clang_off_spaces + """// clang-format on + constexpr size_t count = + sizeof(known_non_device_names) / sizeof(known_non_device_names[0]); + if (!pName || + std::binary_search( + known_non_device_names, known_non_device_names + count, pName, + [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) { + vulkan::driver::Logger(device).Err( + device, "invalid vkGetDeviceProcAddr(%p, \\\"%s\\\") call", device, + (pName) ? pName : "(null)"); + return nullptr; + } + // clang-format off\n\n""") + for cmds in gencom.allCommandsList: + if gencom.isDeviceDispatched(cmds): + if isIntercepted(cmds) or cmds == 'vkGetDeviceProcAddr': + f.write (gencom.clang_off_spaces + 'if (strcmp(pName, "' + cmds + '") == 0) return reinterpret_cast(' + cmds[2:] + ');\n') + f.write ('\n') + +def apiDispatch(functionName, f): + assert not isIntercepted(functionName) + + f.write (gencom.clang_off_spaces) + if gencom.returnTypeDict[functionName] != 'void': + f.write ('return ') + + paramList = gencom.paramDict[functionName] + p0 = paramList[0][1] + f.write('GetData(' + p0 + ').dispatch.' + functionName[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n') + + +def api_gencpp(): + genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen2.cpp') + header = """#include +#include + +#include + +// to catch mismatches between vulkan.h and this file +#undef VK_NO_PROTOTYPES +#include "api.h" + +namespace vulkan { +namespace api { + +""" + with open(genfile, 'w') as f: + f.write (gencom.copyright) + f.write (gencom.warning) + f.write ("""#include +#include + +#include + +// to catch mismatches between vulkan.h and this file +#undef VK_NO_PROTOTYPES +#include "api.h" + +namespace vulkan { +namespace api {\n\n""") + defineInitProc('dispatch',f) + defineInitProcExt(f) + f.write ('namespace {\n\n') + gencom.clang_off(f,0) + f.write ('\n') + for cmds in gencom.allCommandsList: + defineExtensionStub(cmds,f) + gencom.clang_on(f,0) + f.write ('\n} // namespace\n\n') + f.write ("""bool InitDispatchTable( + VkInstance instance, + PFN_vkGetInstanceProcAddr get_proc, + const std::bitset& extensions) { + auto& data = GetData(instance); + bool success = true;\n\n""") + gencom.clang_off(f,1) + for cmds in gencom.allCommandsList: + if gencom.isInstanceDispatchTableEntry(cmds): + gencom.initProc(cmds, f) + gencom.clang_on(f,1) + f.write ('\n') + f.write (' return success;\n}\n\n') + f.write ("""bool InitDispatchTable( + VkDevice dev, + PFN_vkGetDeviceProcAddr get_proc, + const std::bitset& extensions) { + auto& data = GetData(dev); + bool success = true;\n\n""") + + gencom.clang_off(f,1) + for cmds in gencom.allCommandsList: + if gencom.isDeviceDispatchTableEntry(cmds): + gencom.initProc(cmds, f) + gencom.clang_on(f,1) + f.write ('\n') + f.write (' return success;\n}\n\n') + + gencom.clang_off(f,0) + + f.write ('\nnamespace {\n\n') + f.write('// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr\n') + for cmds in gencom.allCommandsList: + if gencom.isFunctionExported(cmds) and not isIntercepted(cmds): + paramList = [''.join(i) for i in gencom.paramDict[cmds]] + f.write ('VKAPI_ATTR '+gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ');\n') + + f.write ('\n') + + for cmds in gencom.allCommandsList: + if gencom.isFunctionExported(cmds) and not isIntercepted(cmds): + paramList = [''.join(i) for i in gencom.paramDict[cmds]] + f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ') {\n') + if cmds == 'vkGetInstanceProcAddr': + interceptInstanceProcAddr(cmds, f) + elif cmds == 'vkGetDeviceProcAddr': + interceptDeviceProcAddr(cmds, f) + apiDispatch(cmds, f) + f.write('}\n\n') + f.write ("""\n} // anonymous namespace + +// clang-format on + +} // namespace api +} // namespace vulkan + +// clang-format off\n\n""") + + for cmds in gencom.allCommandsList: + if gencom.isFunctionExported(cmds): + paramList = [''.join(i) for i in gencom.paramDict[cmds]] + f.write ('__attribute__((visibility("default")))\n') + f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds + '(' + ', '.join(paramList) + ') {\n') + f.write (gencom.clang_off_spaces) + if gencom.returnTypeDict[cmds] != 'void': + f.write ('return ') + paramList = gencom.paramDict[cmds] + f.write ('vulkan::api::' + cmds[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n') + f.write ('}\n\n') + + gencom.clang_on(f, 0) + diff --git a/vulkan/scripts/code_generator.py b/vulkan/scripts/code_generator.py new file mode 100644 index 0000000000..91c0d3023a --- /dev/null +++ b/vulkan/scripts/code_generator.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# 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. +# +# This script provides the main function for generating +# vulkan framework directly from the vulkan registry (vk.xml). + +import generator_common as gencom +import api_generator as apigen + +if __name__ == '__main__': + gencom.parseVulkanRegistry() + apigen.api_genh() + apigen.api_gencpp() diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py new file mode 100644 index 0000000000..313357d288 --- /dev/null +++ b/vulkan/scripts/generator_common.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python3 +# +# 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. +# +# This script provides the common functions for generating the +# vulkan framework directly from the vulkan registry (vk.xml). + +copyright = """/* + * Copyright 2016 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. + */ + +""" + +warning = '// WARNING: This file is generated. See ../README.md for instructions.\n\n' + +blacklistedExtensions = [ + 'VK_KHR_display', + 'VK_KHR_display_swapchain', + 'VK_KHR_mir_surface', + 'VK_KHR_xcb_surface', + 'VK_KHR_xlib_surface', + 'VK_KHR_wayland_surface', + 'VK_KHR_win32_surface', + 'VK_KHR_external_memory_win32', + 'VK_KHR_win32_keyed_mutex', + 'VK_KHR_external_semaphore_win32', + 'VK_KHR_external_fence_win32', + 'VK_EXT_acquire_xlib_display', + 'VK_EXT_direct_mode_display', + 'VK_EXT_display_surface_counter', + 'VK_EXT_display_control', + 'VK_FUCHSIA_imagepipe_surface', + 'VK_MVK_ios_surface', + 'VK_MVK_macos_surface', + 'VK_NN_vi_surface', + 'VK_NV_external_memory_win32', + 'VK_NV_win32_keyed_mutex', + 'VK_EXT_metal_surface', #not present in vulkan.api + 'VK_NVX_image_view_handle', #not present in vulkan.api + 'VK_NV_cooperative_matrix' #not present in vulkan.api +] + +exportedExtensions = [ + 'VK_KHR_surface', + 'VK_KHR_swapchain', + 'VK_KHR_android_surface', + 'VK_ANDROID_external_memory_android_hardware_buffer' +] + +def isFunctionSupported(functionName): + if functionName not in extensionsDict: + return True + else: + if extensionsDict[functionName] not in blacklistedExtensions: + return True + return False + +def isInstanceDispatched(functionName): + return isFunctionSupported(functionName) and getDispatchTableType(functionName) == 'Instance' + +def isDeviceDispatched(functionName): + return isFunctionSupported(functionName) and getDispatchTableType(functionName) == 'Device' + +def isGloballyDispatched(functionName): + return isFunctionSupported(functionName) and getDispatchTableType(functionName) == 'Global' + +def isExtensionExported(extensionName): + if extensionName in exportedExtensions: + return True + return False + +def isFunctionExported(functionName): + if isFunctionSupported(functionName): + if functionName in extensionsDict: + return isExtensionExported(extensionsDict[functionName]) + return True + return False + +def getDispatchTableType(functionName): + if functionName not in paramDict: + return None + + switchCase = { + 'VkInstance ' : 'Instance', + 'VkPhysicalDevice ' : 'Instance', + 'VkDevice ' : 'Device', + 'VkQueue ' : 'Device', + 'VkCommandBuffer ' : 'Device' + } + + if len(paramDict[functionName])>0: + return switchCase.get(paramDict[functionName][0][0], 'Global') + return 'Global' + +def isInstanceDispatchTableEntry(functionName): + if functionName == 'vkEnumerateDeviceLayerProperties': # deprecated, unused internally - @dbd33bc + return False + if isFunctionExported(functionName) and isInstanceDispatched(functionName): + return True + return False + +def isDeviceDispatchTableEntry(functionName): + if isFunctionExported(functionName) and isDeviceDispatched(functionName): + return True + return False + + +def clang_on(f, indent): + f.write (clang_off_spaces * indent + '// clang-format on\n') + +def clang_off(f, indent): + f.write (clang_off_spaces * indent + '// clang-format off\n') + +clang_off_spaces = ' '*4 + +parametersList = [] +paramDict = {} +allCommandsList = [] +extensionsDict = {} +returnTypeDict = {} +versionDict = {} +aliasDict = {} + +def parseVulkanRegistry(): + import xml.etree.ElementTree as ET + import os + vulkan_registry = os.path.join(os.path.dirname(__file__),'..','..','..','..','external','vulkan-headers','registry','vk.xml') + tree = ET.parse(vulkan_registry) + root = tree.getroot() + protoset = False + fnName = "" + fnType = "" + for commands in root.iter('commands'): + for command in commands: + if command.tag == 'command': + if protoset == True: + paramDict[fnName] = parametersList.copy() + parametersList.clear() + protoset = False + if command.get('alias') != None: + alias = command.get('alias') + fnName = command.get('name') + aliasDict[fnName] = alias + allCommandsList.append(fnName) + paramDict[fnName] = paramDict[alias].copy() + for params in command: + if(params.tag == 'param'): + paramtype = "" + if params.text!=None: + paramtype = params.text + typeval = params.find('type') + paramtype = paramtype + typeval.text + if typeval.tail!=None: + paramtype = paramtype + typeval.tail + pname = params.find('name') + paramname = pname.text + if pname.tail != None: + parametersList.append((paramtype,paramname,pname.tail)) + else: + parametersList.append((paramtype,paramname)) + if params.tag == 'proto': + for c in params: + if c.tag == 'type': + fnType = c.text + if c.tag == 'name': + fnName = c.text + protoset = True + allCommandsList.append(fnName) + returnTypeDict[fnName] = fnType + + for exts in root.iter('extensions'): + for extension in exts: + apiversion = "" + if extension.tag == 'extension': + extname = extension.get('name') + for req in extension: + if req.get('feature')!=None: + apiversion = req.get('feature') + for commands in req: + if commands.tag == 'command': + commandname = commands.get('name') + if commandname not in extensionsDict: + extensionsDict[commandname] = extname + if apiversion != "": + versionDict[commandname] = apiversion + + for feature in root.iter('feature'): + apiversion = feature.get('name') + for req in feature: + for command in req: + if command.tag == 'command': + cmdName = command.get('name') + if cmdName in allCommandsList: + versionDict[cmdName] = apiversion + + +def initProc(name, f): + if name in extensionsDict: + f.write (' INIT_PROC_EXT(' + extensionsDict[name][3:] + ', ') + else: + f.write (' INIT_PROC(') + + if name in versionDict and versionDict[name] == 'VK_VERSION_1_1': + f.write('false, ') + else: + f.write('true, ') + + if isInstanceDispatched(name): + f.write('instance, ') + else: + f.write('dev, ') + + f.write(name[2:] + ');\n') + -- GitLab From 27ab3ac610954ac01a18a1cf8559827cf7679f99 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Tue, 2 Jul 2019 18:10:55 -0700 Subject: [PATCH 0059/1255] GpuStats: move GpuStats related structs and enums away from GraphicsEnv Bug: 135210726 Test: build, flash and boot Test: adb shell dumpsys gpu Change-Id: I48c5c432aca916f923ab5674f8ec533d4f5aac0f --- libs/graphicsenv/GraphicsEnv.cpp | 38 ++++++------ libs/graphicsenv/IGpuService.cpp | 4 +- .../include/graphicsenv/GpuStatsInfo.h | 39 ++++++++++++ .../include/graphicsenv/GraphicsEnv.h | 59 ++----------------- .../include/graphicsenv/IGpuService.h | 2 +- opengl/libs/EGL/Loader.cpp | 12 ++-- services/gpuservice/GpuService.cpp | 2 +- services/gpuservice/GpuService.h | 2 +- services/gpuservice/gpustats/GpuStats.cpp | 26 ++++---- services/gpuservice/gpustats/GpuStats.h | 2 +- vulkan/libvulkan/driver.cpp | 10 ++-- 11 files changed, 94 insertions(+), 102 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 24b6c2d6de..a411dd56f6 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -170,11 +170,11 @@ void GraphicsEnv::hintActivityLaunch() { std::lock_guard lock(mStatsLock); if (mGpuStats.glDriverToSend) { mGpuStats.glDriverToSend = false; - sendGpuStatsLocked(GraphicsEnv::Api::API_GL, true, mGpuStats.glDriverLoadingTime); + sendGpuStatsLocked(GpuStatsInfo::Api::API_GL, true, mGpuStats.glDriverLoadingTime); } if (mGpuStats.vkDriverToSend) { mGpuStats.vkDriverToSend = false; - sendGpuStatsLocked(GraphicsEnv::Api::API_VK, true, mGpuStats.vkDriverLoadingTime); + sendGpuStatsLocked(GpuStatsInfo::Api::API_VK, true, mGpuStats.vkDriverLoadingTime); } }); trySendGpuStatsThread.detach(); @@ -205,32 +205,32 @@ void GraphicsEnv::setGpuStats(const std::string& driverPackageName, mGpuStats.vulkanVersion = vulkanVersion; } -void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) { +void GraphicsEnv::setDriverToLoad(GpuStatsInfo::Driver driver) { ATRACE_CALL(); std::lock_guard lock(mStatsLock); switch (driver) { - case GraphicsEnv::Driver::GL: - case GraphicsEnv::Driver::GL_UPDATED: - case GraphicsEnv::Driver::ANGLE: { - if (mGpuStats.glDriverToLoad == GraphicsEnv::Driver::NONE) { + case GpuStatsInfo::Driver::GL: + case GpuStatsInfo::Driver::GL_UPDATED: + case GpuStatsInfo::Driver::ANGLE: { + if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE) { mGpuStats.glDriverToLoad = driver; break; } - if (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE) { + if (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE) { mGpuStats.glDriverFallback = driver; } break; } - case Driver::VULKAN: - case Driver::VULKAN_UPDATED: { - if (mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::NONE) { + case GpuStatsInfo::Driver::VULKAN: + case GpuStatsInfo::Driver::VULKAN_UPDATED: { + if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE) { mGpuStats.vkDriverToLoad = driver; break; } - if (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE) { + if (mGpuStats.vkDriverFallback == GpuStatsInfo::Driver::NONE) { mGpuStats.vkDriverFallback = driver; } break; @@ -240,13 +240,13 @@ void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) { } } -void GraphicsEnv::setDriverLoaded(GraphicsEnv::Api api, bool isDriverLoaded, +void GraphicsEnv::setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime) { ATRACE_CALL(); std::lock_guard lock(mStatsLock); const bool doNotSend = mGpuStats.appPackageName.empty(); - if (api == GraphicsEnv::Api::API_GL) { + if (api == GpuStatsInfo::Api::API_GL) { if (doNotSend) mGpuStats.glDriverToSend = true; mGpuStats.glDriverLoadingTime = driverLoadingTime; } else { @@ -278,7 +278,7 @@ void GraphicsEnv::setCpuVulkanInUse() { } } -void GraphicsEnv::sendGpuStatsLocked(GraphicsEnv::Api api, bool isDriverLoaded, +void GraphicsEnv::sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime) { ATRACE_CALL(); @@ -299,16 +299,16 @@ void GraphicsEnv::sendGpuStatsLocked(GraphicsEnv::Api api, bool isDriverLoaded, mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, mGpuStats.appPackageName.c_str(), mGpuStats.vulkanVersion, static_cast(api), isDriverLoaded, driverLoadingTime); - GraphicsEnv::Driver driver = GraphicsEnv::Driver::NONE; + GpuStatsInfo::Driver driver = GpuStatsInfo::Driver::NONE; bool isIntendedDriverLoaded = false; - if (api == GraphicsEnv::Api::API_GL) { + if (api == GpuStatsInfo::Api::API_GL) { driver = mGpuStats.glDriverToLoad; isIntendedDriverLoaded = - isDriverLoaded && (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE); + isDriverLoaded && (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE); } else { driver = mGpuStats.vkDriverToLoad; isIntendedDriverLoaded = - isDriverLoaded && (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE); + isDriverLoaded && (mGpuStats.vkDriverFallback == GpuStatsInfo::Driver::NONE); } const sp gpuService = getGpuService(); diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp index 5f9624918f..30e5370650 100644 --- a/libs/graphicsenv/IGpuService.cpp +++ b/libs/graphicsenv/IGpuService.cpp @@ -30,7 +30,7 @@ public: virtual void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, - const int32_t vulkanVersion, GraphicsEnv::Driver driver, + const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { Parcel data, reply; data.writeInterfaceToken(IGpuService::getInterfaceDescriptor()); @@ -143,7 +143,7 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* rep if ((status = data.readInt64(&driverLoadingTime)) != OK) return status; setGpuStats(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime, - appPackageName, vulkanVersion, static_cast(driver), + appPackageName, vulkanVersion, static_cast(driver), isDriverLoaded, driverLoadingTime); return OK; diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h index edcccfea4a..c2fd10ae63 100644 --- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h +++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h @@ -72,4 +72,43 @@ public: bool cpuVulkanInUse = false; }; +/* + * class for holding the gpu stats in GraphicsEnv before sending to GpuService. + */ +class GpuStatsInfo { +public: + enum Api { + API_GL = 0, + API_VK = 1, + }; + + enum Driver { + NONE = 0, + GL = 1, + GL_UPDATED = 2, + VULKAN = 3, + VULKAN_UPDATED = 4, + ANGLE = 5, + }; + + GpuStatsInfo() = default; + GpuStatsInfo(const GpuStatsInfo&) = default; + virtual ~GpuStatsInfo() = default; + + std::string driverPackageName = ""; + std::string driverVersionName = ""; + uint64_t driverVersionCode = 0; + int64_t driverBuildTime = 0; + std::string appPackageName = ""; + int32_t vulkanVersion = 0; + Driver glDriverToLoad = Driver::NONE; + Driver glDriverFallback = Driver::NONE; + Driver vkDriverToLoad = Driver::NONE; + Driver vkDriverFallback = Driver::NONE; + bool glDriverToSend = false; + bool vkDriverToSend = false; + int64_t glDriverLoadingTime = 0; + int64_t vkDriverLoadingTime = 0; +}; + } // namespace android diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index f5d19db493..aa14059d72 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -17,6 +17,8 @@ #ifndef ANDROID_UI_GRAPHICS_ENV_H #define ANDROID_UI_GRAPHICS_ENV_H 1 +#include + #include #include #include @@ -28,55 +30,6 @@ namespace android { struct NativeLoaderNamespace; class GraphicsEnv { -public: - enum Api { - API_GL = 0, - API_VK = 1, - }; - - enum Driver { - NONE = 0, - GL = 1, - GL_UPDATED = 2, - VULKAN = 3, - VULKAN_UPDATED = 4, - ANGLE = 5, - }; - -private: - struct GpuStats { - std::string driverPackageName; - std::string driverVersionName; - uint64_t driverVersionCode; - int64_t driverBuildTime; - std::string appPackageName; - int32_t vulkanVersion; - Driver glDriverToLoad; - Driver glDriverFallback; - Driver vkDriverToLoad; - Driver vkDriverFallback; - bool glDriverToSend; - bool vkDriverToSend; - int64_t glDriverLoadingTime; - int64_t vkDriverLoadingTime; - - GpuStats() - : driverPackageName(""), - driverVersionName(""), - driverVersionCode(0), - driverBuildTime(0), - appPackageName(""), - vulkanVersion(0), - glDriverToLoad(Driver::NONE), - glDriverFallback(Driver::NONE), - vkDriverToLoad(Driver::NONE), - vkDriverFallback(Driver::NONE), - glDriverToSend(false), - vkDriverToSend(false), - glDriverLoadingTime(0), - vkDriverLoadingTime(0) {} - }; - public: static GraphicsEnv& getInstance(); @@ -97,9 +50,9 @@ public: uint64_t versionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion); void setCpuVulkanInUse(); - void setDriverToLoad(Driver driver); - void setDriverLoaded(Api api, bool isDriverLoaded, int64_t driverLoadingTime); - void sendGpuStatsLocked(Api api, bool isDriverLoaded, int64_t driverLoadingTime); + void setDriverToLoad(GpuStatsInfo::Driver driver); + void setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); + void sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); bool shouldUseAngle(std::string appName); bool shouldUseAngle(); @@ -135,7 +88,7 @@ private: std::string mDriverPath; std::string mSphalLibraries; std::mutex mStatsLock; - GpuStats mGpuStats; + GpuStatsInfo mGpuStats; std::string mAnglePath; std::string mAngleAppName; std::string mAngleDeveloperOptIn; diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h index 34f1c7ee7e..a47bbafcc4 100644 --- a/libs/graphicsenv/include/graphicsenv/IGpuService.h +++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h @@ -37,7 +37,7 @@ public: virtual void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, - const int32_t vulkanVersion, GraphicsEnv::Driver driver, + const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) = 0; // set CPU Vulkan in use signal from GraphicsEnvironment. diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 038a432337..23e11a82ac 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -311,7 +311,7 @@ void* Loader::open(egl_connection_t* cnx) } if (!hnd) { - android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL, + android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, false, systemTime() - openTime); } @@ -330,7 +330,7 @@ void* Loader::open(egl_connection_t* cnx) } if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) { - android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL, + android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, false, systemTime() - openTime); } @@ -340,7 +340,7 @@ void* Loader::open(egl_connection_t* cnx) LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1, "couldn't load system OpenGL ES wrapper libraries"); - android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL, true, + android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, true, systemTime() - openTime); return (void*)hnd; @@ -637,7 +637,7 @@ Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) { return nullptr; } - android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::ANGLE); + android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::ANGLE); driver_t* hnd = nullptr; // ANGLE doesn't ship with GLES library, and thus we skip GLES driver. @@ -666,7 +666,7 @@ Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) } ALOGD("Load updated gl driver."); - android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL_UPDATED); + android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL_UPDATED); driver_t* hnd = nullptr; void* dso = load_updated_driver("GLES", ns); if (dso) { @@ -697,7 +697,7 @@ Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix, const bool exact) { ATRACE_CALL(); - android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL); + android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL); driver_t* hnd = nullptr; void* dso = load_system_driver("GLES", suffix, exact); if (dso) { diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 8accf9d450..72757dd02b 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -51,7 +51,7 @@ GpuService::GpuService() : mGpuStats(std::make_unique()){}; void GpuService::setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, - const int32_t vulkanVersion, GraphicsEnv::Driver driver, + const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { ATRACE_CALL(); diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h index 822690134a..3e0e1b5f9b 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/GpuService.h @@ -46,7 +46,7 @@ private: void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, - GraphicsEnv::Driver driver, bool isDriverLoaded, + GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) override; status_t getGpuStatsGlobalInfo(std::vector* outStats) const override; status_t getGpuStatsAppInfo(std::vector* outStats) const override; diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp index 37c6abc96b..576c72cd3c 100644 --- a/services/gpuservice/gpustats/GpuStats.cpp +++ b/services/gpuservice/gpustats/GpuStats.cpp @@ -27,20 +27,20 @@ namespace android { -static void addLoadingCount(GraphicsEnv::Driver driver, bool isDriverLoaded, +static void addLoadingCount(GpuStatsInfo::Driver driver, bool isDriverLoaded, GpuStatsGlobalInfo* const outGlobalInfo) { switch (driver) { - case GraphicsEnv::Driver::GL: - case GraphicsEnv::Driver::GL_UPDATED: + case GpuStatsInfo::Driver::GL: + case GpuStatsInfo::Driver::GL_UPDATED: outGlobalInfo->glLoadingCount++; if (!isDriverLoaded) outGlobalInfo->glLoadingFailureCount++; break; - case GraphicsEnv::Driver::VULKAN: - case GraphicsEnv::Driver::VULKAN_UPDATED: + case GpuStatsInfo::Driver::VULKAN: + case GpuStatsInfo::Driver::VULKAN_UPDATED: outGlobalInfo->vkLoadingCount++; if (!isDriverLoaded) outGlobalInfo->vkLoadingFailureCount++; break; - case GraphicsEnv::Driver::ANGLE: + case GpuStatsInfo::Driver::ANGLE: outGlobalInfo->angleLoadingCount++; if (!isDriverLoaded) outGlobalInfo->angleLoadingFailureCount++; break; @@ -49,22 +49,22 @@ static void addLoadingCount(GraphicsEnv::Driver driver, bool isDriverLoaded, } } -static void addLoadingTime(GraphicsEnv::Driver driver, int64_t driverLoadingTime, +static void addLoadingTime(GpuStatsInfo::Driver driver, int64_t driverLoadingTime, GpuStatsAppInfo* const outAppInfo) { switch (driver) { - case GraphicsEnv::Driver::GL: - case GraphicsEnv::Driver::GL_UPDATED: + case GpuStatsInfo::Driver::GL: + case GpuStatsInfo::Driver::GL_UPDATED: if (outAppInfo->glDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) { outAppInfo->glDriverLoadingTime.emplace_back(driverLoadingTime); } break; - case GraphicsEnv::Driver::VULKAN: - case GraphicsEnv::Driver::VULKAN_UPDATED: + case GpuStatsInfo::Driver::VULKAN: + case GpuStatsInfo::Driver::VULKAN_UPDATED: if (outAppInfo->vkDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) { outAppInfo->vkDriverLoadingTime.emplace_back(driverLoadingTime); } break; - case GraphicsEnv::Driver::ANGLE: + case GpuStatsInfo::Driver::ANGLE: if (outAppInfo->angleDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) { outAppInfo->angleDriverLoadingTime.emplace_back(driverLoadingTime); } @@ -77,7 +77,7 @@ static void addLoadingTime(GraphicsEnv::Driver driver, int64_t driverLoadingTime 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, - GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { + GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { ATRACE_CALL(); std::lock_guard lock(mLock); diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h index b293f5988d..a79b2ba208 100644 --- a/services/gpuservice/gpustats/GpuStats.h +++ b/services/gpuservice/gpustats/GpuStats.h @@ -36,7 +36,7 @@ public: void insert(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, - GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime); + GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime); // Set CPU Vulkan in use signal into app stats. void setCpuVulkanInUse(const std::string& appPackageName, const uint64_t driverVersionCode); // dumpsys interface diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index d33e5528e8..680f94f42a 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -211,7 +211,7 @@ int LoadBuiltinDriver(const hwvulkan_module_t** module) { if (!ns) return -ENOENT; android::GraphicsEnv::getInstance().setDriverToLoad( - android::GraphicsEnv::Driver::VULKAN); + android::GpuStatsInfo::Driver::VULKAN); return LoadDriver(ns, module); } @@ -222,7 +222,7 @@ int LoadUpdatedDriver(const hwvulkan_module_t** module) { if (!ns) return -ENOENT; android::GraphicsEnv::getInstance().setDriverToLoad( - android::GraphicsEnv::Driver::VULKAN_UPDATED); + android::GpuStatsInfo::Driver::VULKAN_UPDATED); return LoadDriver(ns, module); } @@ -257,7 +257,7 @@ bool Hal::Open() { } if (result != 0) { android::GraphicsEnv::getInstance().setDriverLoaded( - android::GraphicsEnv::Api::API_VK, false, systemTime() - openTime); + android::GpuStatsInfo::Api::API_VK, false, systemTime() - openTime); ALOGV("unable to load Vulkan HAL, using stub HAL (result=%d)", result); return true; } @@ -271,7 +271,7 @@ bool Hal::Open() { ATRACE_END(); if (result != 0) { android::GraphicsEnv::getInstance().setDriverLoaded( - android::GraphicsEnv::Api::API_VK, false, systemTime() - openTime); + android::GpuStatsInfo::Api::API_VK, false, systemTime() - openTime); // Any device with a Vulkan HAL should be able to open the device. ALOGE("failed to open Vulkan HAL device: %s (%d)", strerror(-result), result); @@ -283,7 +283,7 @@ bool Hal::Open() { hal_.InitDebugReportIndex(); android::GraphicsEnv::getInstance().setDriverLoaded( - android::GraphicsEnv::Api::API_VK, true, systemTime() - openTime); + android::GpuStatsInfo::Api::API_VK, true, systemTime() - openTime); return true; } -- GitLab From 81e26a1c64a4249bd1245c8f5f5b03fba47d225d Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Tue, 2 Jul 2019 19:48:23 -0700 Subject: [PATCH 0060/1255] GraphicsEnv: add documentations for the class Bug: 135210726 Test: build, flash and boot. Change-Id: I54f1abf0fc5d9867ee74a83d6639a767915ac738 --- .../include/graphicsenv/GraphicsEnv.h | 56 ++++++++++++++++++- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index aa14059d72..d0fc580fb6 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -33,8 +33,12 @@ class GraphicsEnv { public: static GraphicsEnv& getInstance(); + // Check if device is debuggable. int getCanLoadSystemLibraries(); + /* + * Apis for updatable driver + */ // Set a search path for loading graphics drivers. The path is a list of // directories separated by ':'. A directory can be contained in a zip file // (drivers must be stored uncompressed and page aligned); such elements @@ -44,17 +48,31 @@ public: // graphics drivers. The string is a list of libraries separated by ':', // which is required by android_link_namespaces. void setDriverPathAndSphalLibraries(const std::string path, const std::string sphalLibraries); + // Get the updatable driver namespace. android_namespace_t* getDriverNamespace(); + + /* + * Apis for GpuStats + */ + // Hint there's real activity launching on the app process. void hintActivityLaunch(); + // Set the initial GpuStats. void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t versionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion); + // Set that CPU type physical device is in use. void setCpuVulkanInUse(); + // Set which driver is intended to load. void setDriverToLoad(GpuStatsInfo::Driver driver); + // Set which driver is actually loaded. void setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); - void sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); + /* + * Apis for ANGLE + */ + // Check if the requested app should use ANGLE. bool shouldUseAngle(std::string appName); + // Check if this app process should use ANGLE. bool shouldUseAngle(); // Set a search path for loading ANGLE libraries. The path is a list of // directories separated by ':'. A directory can be contained in a zip file @@ -63,43 +81,75 @@ public: // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn, const int rulesFd, const long rulesOffset, const long rulesLength); + // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); + // Get the app name for ANGLE debug message. std::string& getAngleAppName(); + /* + * Apis for debug layer + */ + // Set additional layer search paths. void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths); + // Get the app namespace for loading layers. NativeLoaderNamespace* getAppNamespace(); - + // Get additional layer search paths. const std::string& getLayerPaths(); - + // Set the Vulkan debug layers. void setDebugLayers(const std::string layers); + // Set the GL debug layers. void setDebugLayersGLES(const std::string layers); + // Get the debug layers to load. const std::string& getDebugLayers(); + // Get the debug layers to load. const std::string& getDebugLayersGLES(); private: enum UseAngle { UNKNOWN, YES, NO }; + // Load requested ANGLE library. void* loadLibrary(std::string name); + // Check ANGLE support with the rules. bool checkAngleRules(void* so); + // Update whether ANGLE should be used. void updateUseAngle(); + // Link updatable driver namespace with llndk and vndk-sp libs. bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace); + // Send the initial complete GpuStats to GpuService. + void sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); GraphicsEnv() = default; + // Path to updatable driver libs. std::string mDriverPath; + // Path to additional sphal libs linked to updatable driver namespace. std::string mSphalLibraries; + // This mutex protects mGpuStats and get gpuservice call. std::mutex mStatsLock; + // Information bookkept for GpuStats. GpuStatsInfo mGpuStats; + // Path to ANGLE libs. std::string mAnglePath; + // This App's name. std::string mAngleAppName; + // ANGLE developer opt in status. std::string mAngleDeveloperOptIn; + // ANGLE rules. std::vector mRulesBuffer; + // Use ANGLE flag. UseAngle mUseAngle = UNKNOWN; + // Vulkan debug layers libs. std::string mDebugLayers; + // GL debug layers libs. std::string mDebugLayersGLES; + // Additional debug layers search path. std::string mLayerPaths; + // This mutex protects the namespace creation. std::mutex mNamespaceMutex; + // Updatable driver namespace. android_namespace_t* mDriverNamespace = nullptr; + // ANGLE namespace. android_namespace_t* mAngleNamespace = nullptr; + // This App's namespace. NativeLoaderNamespace* mAppNamespace = nullptr; }; -- GitLab From bcba4117941a0506971654331d89961b6fbfd3c0 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Wed, 3 Jul 2019 13:39:32 -0700 Subject: [PATCH 0061/1255] GpuStats: refactor single stats pieces into a uniform way This change makes it easy for adding single stats pieces into GpuService without adding or modifying the binder interface each time. Bug: 135210726 Test: adb shell dumpsys gpu Change-Id: I2907065a55d03a6c1494737e6f0a77f6e94272eb --- libs/graphicsenv/GraphicsEnv.cpp | 6 +++--- libs/graphicsenv/IGpuService.cpp | 19 ++++++++++++++----- .../include/graphicsenv/GpuStatsInfo.h | 4 ++++ .../include/graphicsenv/GraphicsEnv.h | 4 ++-- .../include/graphicsenv/IGpuService.h | 8 ++++---- services/gpuservice/GpuService.cpp | 16 +++------------- services/gpuservice/GpuService.h | 4 ++-- services/gpuservice/gpustats/GpuStats.cpp | 17 ++++++++++++++--- services/gpuservice/gpustats/GpuStats.h | 5 +++-- vulkan/libvulkan/driver.cpp | 3 ++- 10 files changed, 51 insertions(+), 35 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index a411dd56f6..c5d5f71800 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -267,14 +267,14 @@ static sp getGpuService() { return interface_cast(binder); } -void GraphicsEnv::setCpuVulkanInUse() { +void GraphicsEnv::setTargetStats(const GpuStatsInfo::Stats stats, const uint64_t value) { ATRACE_CALL(); - // Use the same stats lock to protect getGpuService() as well. std::lock_guard lock(mStatsLock); const sp gpuService = getGpuService(); if (gpuService) { - gpuService->setCpuVulkanInUse(mGpuStats.appPackageName, mGpuStats.driverVersionCode); + gpuService->setTargetStats(mGpuStats.appPackageName, mGpuStats.driverVersionCode, stats, + value); } } diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp index 30e5370650..9f5b0ff46f 100644 --- a/libs/graphicsenv/IGpuService.cpp +++ b/libs/graphicsenv/IGpuService.cpp @@ -92,15 +92,17 @@ public: return reply.readParcelableVector(outStats); } - virtual void setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) { + virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GpuStatsInfo::Stats stats, const uint64_t value) { Parcel data, reply; data.writeInterfaceToken(IGpuService::getInterfaceDescriptor()); data.writeUtf8AsUtf16(appPackageName); data.writeUint64(driverVersionCode); + data.writeInt32(static_cast(stats)); + data.writeUint64(value); - remote()->transact(BnGpuService::SET_CPU_VULKAN_IN_USE, data, &reply, IBinder::FLAG_ONEWAY); + remote()->transact(BnGpuService::SET_TARGET_STATS, data, &reply, IBinder::FLAG_ONEWAY); } }; @@ -174,7 +176,7 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* rep return OK; } - case SET_CPU_VULKAN_IN_USE: { + case SET_TARGET_STATS: { CHECK_INTERFACE(IGpuService, data, reply); std::string appPackageName; @@ -183,7 +185,14 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* rep uint64_t driverVersionCode; if ((status = data.readUint64(&driverVersionCode)) != OK) return status; - setCpuVulkanInUse(appPackageName, driverVersionCode); + int32_t stats; + if ((status = data.readInt32(&stats)) != OK) return status; + + uint64_t value; + if ((status = data.readUint64(&value)) != OK) return status; + + setTargetStats(appPackageName, driverVersionCode, + static_cast(stats), value); return OK; } diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h index c2fd10ae63..711e8691ab 100644 --- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h +++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h @@ -91,6 +91,10 @@ public: ANGLE = 5, }; + enum Stats { + CPU_VULKAN_IN_USE = 0, + }; + GpuStatsInfo() = default; GpuStatsInfo(const GpuStatsInfo&) = default; virtual ~GpuStatsInfo() = default; diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index d0fc580fb6..a47f468e7a 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -60,8 +60,8 @@ public: void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t versionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion); - // Set that CPU type physical device is in use. - void setCpuVulkanInUse(); + // Set stats for target GpuStatsInfo::Stats type. + void setTargetStats(const GpuStatsInfo::Stats stats, const uint64_t value = 0); // Set which driver is intended to load. void setDriverToLoad(GpuStatsInfo::Driver driver); // Set which driver is actually loaded. diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h index a47bbafcc4..f523d585be 100644 --- a/libs/graphicsenv/include/graphicsenv/IGpuService.h +++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h @@ -40,9 +40,9 @@ public: const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) = 0; - // set CPU Vulkan in use signal from GraphicsEnvironment. - virtual void setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) = 0; + // set target stats. + virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GpuStatsInfo::Stats stats, const uint64_t value = 0) = 0; // get GPU global stats from GpuStats module. virtual status_t getGpuStatsGlobalInfo(std::vector* outStats) const = 0; @@ -57,7 +57,7 @@ public: SET_GPU_STATS = IBinder::FIRST_CALL_TRANSACTION, GET_GPU_STATS_GLOBAL_INFO, GET_GPU_STATS_APP_INFO, - SET_CPU_VULKAN_IN_USE, + SET_TARGET_STATS, // Always append new enum to the end. }; diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 72757dd02b..c81ab509c3 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -53,33 +53,23 @@ void GpuService::setGpuStats(const std::string& driverPackageName, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { - ATRACE_CALL(); - mGpuStats->insert(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime, appPackageName, vulkanVersion, driver, isDriverLoaded, driverLoadingTime); } status_t GpuService::getGpuStatsGlobalInfo(std::vector* outStats) const { - ATRACE_CALL(); - mGpuStats->pullGlobalStats(outStats); - return OK; } status_t GpuService::getGpuStatsAppInfo(std::vector* outStats) const { - ATRACE_CALL(); - mGpuStats->pullAppStats(outStats); - return OK; } -void GpuService::setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) { - ATRACE_CALL(); - - mGpuStats->setCpuVulkanInUse(appPackageName, driverVersionCode); +void GpuService::setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GpuStatsInfo::Stats stats, const uint64_t value) { + mGpuStats->insertTargetStats(appPackageName, driverVersionCode, stats, value); } status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector& args) { diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h index 3e0e1b5f9b..525fb4fada 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/GpuService.h @@ -50,8 +50,8 @@ private: int64_t driverLoadingTime) override; status_t getGpuStatsGlobalInfo(std::vector* outStats) const override; status_t getGpuStatsAppInfo(std::vector* outStats) const override; - void setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) override; + void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GpuStatsInfo::Stats stats, const uint64_t value) override; /* * IBinder interface diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp index 576c72cd3c..423c89f797 100644 --- a/services/gpuservice/gpustats/GpuStats.cpp +++ b/services/gpuservice/gpustats/GpuStats.cpp @@ -126,14 +126,25 @@ void GpuStats::insert(const std::string& driverPackageName, const std::string& d addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]); } -void GpuStats::setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) { +void GpuStats::insertTargetStats(const std::string& appPackageName, + const uint64_t driverVersionCode, const GpuStatsInfo::Stats stats, + const uint64_t /*value*/) { + ATRACE_CALL(); + const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode); + + std::lock_guard lock(mLock); if (!mAppStats.count(appStatsKey)) { return; } - mAppStats[appStatsKey].cpuVulkanInUse = true; + switch (stats) { + case GpuStatsInfo::Stats::CPU_VULKAN_IN_USE: + mAppStats[appStatsKey].cpuVulkanInUse = true; + break; + default: + break; + } } void GpuStats::interceptSystemDriverStatsLocked() { diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h index a79b2ba208..656b181464 100644 --- a/services/gpuservice/gpustats/GpuStats.h +++ b/services/gpuservice/gpustats/GpuStats.h @@ -37,8 +37,9 @@ public: uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime); - // Set CPU Vulkan in use signal into app stats. - void setCpuVulkanInUse(const std::string& appPackageName, const uint64_t driverVersionCode); + // 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); // dumpsys interface void dump(const Vector& args, std::string* result); // Pull gpu global stats diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 680f94f42a..f596086ccf 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -1173,7 +1173,8 @@ VkResult CreateDevice(VkPhysicalDevice physicalDevice, if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) { // Log that the app is hitting software Vulkan implementation - android::GraphicsEnv::getInstance().setCpuVulkanInUse(); + android::GraphicsEnv::getInstance().setTargetStats( + android::GpuStatsInfo::Stats::CPU_VULKAN_IN_USE); } data->driver_device = dev; -- GitLab From 69395cd3ff5ef500c2b33991c2ab7284bc010ce9 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Wed, 3 Jul 2019 16:55:39 -0700 Subject: [PATCH 0062/1255] GpuStats: track Vulkan apps not doing pre-rotation correctly Bug: 135210726 Test: adb shell dumpsys gpu Change-Id: Iff15f0d486b74ca700c12cd960b839ddccebc112 --- libs/graphicsenv/GpuStatsInfo.cpp | 3 +++ .../include/graphicsenv/GpuStatsInfo.h | 2 ++ services/gpuservice/gpustats/GpuStats.cpp | 3 +++ vulkan/libvulkan/swapchain.cpp | 16 ++++++++++++++++ 4 files changed, 24 insertions(+) diff --git a/libs/graphicsenv/GpuStatsInfo.cpp b/libs/graphicsenv/GpuStatsInfo.cpp index 4a801bec38..85137f5ca9 100644 --- a/libs/graphicsenv/GpuStatsInfo.cpp +++ b/libs/graphicsenv/GpuStatsInfo.cpp @@ -86,6 +86,7 @@ status_t GpuStatsAppInfo::writeToParcel(Parcel* parcel) const { if ((status = parcel->writeInt64Vector(vkDriverLoadingTime)) != OK) return status; if ((status = parcel->writeInt64Vector(angleDriverLoadingTime)) != OK) return status; if ((status = parcel->writeBool(cpuVulkanInUse)) != OK) return status; + if ((status = parcel->writeBool(falsePrerotation)) != OK) return status; return OK; } @@ -97,6 +98,7 @@ status_t GpuStatsAppInfo::readFromParcel(const Parcel* parcel) { if ((status = parcel->readInt64Vector(&vkDriverLoadingTime)) != OK) return status; if ((status = parcel->readInt64Vector(&angleDriverLoadingTime)) != OK) return status; if ((status = parcel->readBool(&cpuVulkanInUse)) != OK) return status; + if ((status = parcel->readBool(&falsePrerotation)) != OK) return status; return OK; } @@ -105,6 +107,7 @@ std::string GpuStatsAppInfo::toString() const { StringAppendF(&result, "appPackageName = %s\n", appPackageName.c_str()); StringAppendF(&result, "driverVersionCode = %" PRIu64 "\n", driverVersionCode); StringAppendF(&result, "cpuVulkanInUse = %d\n", cpuVulkanInUse); + StringAppendF(&result, "falsePrerotation = %d\n", falsePrerotation); result.append("glDriverLoadingTime:"); for (int32_t loadingTime : glDriverLoadingTime) { StringAppendF(&result, " %d", loadingTime); diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h index 711e8691ab..7959652189 100644 --- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h +++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h @@ -70,6 +70,7 @@ public: std::vector vkDriverLoadingTime = {}; std::vector angleDriverLoadingTime = {}; bool cpuVulkanInUse = false; + bool falsePrerotation = false; }; /* @@ -93,6 +94,7 @@ public: enum Stats { CPU_VULKAN_IN_USE = 0, + FALSE_PREROTATION = 1, }; GpuStatsInfo() = default; diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp index 423c89f797..67babd496f 100644 --- a/services/gpuservice/gpustats/GpuStats.cpp +++ b/services/gpuservice/gpustats/GpuStats.cpp @@ -142,6 +142,9 @@ void GpuStats::insertTargetStats(const std::string& appPackageName, case GpuStatsInfo::Stats::CPU_VULKAN_IN_USE: mAppStats[appStatsKey].cpuVulkanInUse = true; break; + case GpuStatsInfo::Stats::FALSE_PREROTATION: + mAppStats[appStatsKey].falsePrerotation = true; + break; default: break; } diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 761d128d79..e5ac2de705 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -1253,6 +1254,15 @@ VkResult CreateSwapchainKHR(VkDevice device, return VK_ERROR_SURFACE_LOST_KHR; } + int transform_hint; + err = surface.window->query(surface.window.get(), + NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint); + if (err != 0) { + ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + // -- Allocate our Swapchain object -- // After this point, we must deallocate the swapchain on error. @@ -1356,6 +1366,12 @@ VkResult CreateSwapchainKHR(VkDevice device, return result; } + if (transform_hint != swapchain->pre_transform) { + // Log that the app is not doing pre-rotation. + android::GraphicsEnv::getInstance().setTargetStats( + android::GpuStatsInfo::Stats::FALSE_PREROTATION); + } + surface.swapchain_handle = HandleFromSwapchain(swapchain); *swapchain_handle = surface.swapchain_handle; return VK_SUCCESS; -- GitLab From 8e09730244a3fb935d5fdae94c572bb3946c5c6e Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 8 Jul 2019 16:11:12 -0700 Subject: [PATCH 0063/1255] GpuStats: Cache the gpu service binder Cache the gpu service binder in the app process so that sending stats pieces won't try to find gpu service every time. If gpu service accidentally restarts, just ignore the later stats from the app, since the memory that holds GpuStats for that app is gone already during the gpu service restart. Test: systrace while try killing gpu service Change-Id: Ib9c38a3592f509f18d146b6c6e8f14e9e997c994 --- libs/graphicsenv/GraphicsEnv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index a411dd56f6..1eedac111a 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -258,7 +258,7 @@ void GraphicsEnv::setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded, } static sp getGpuService() { - const sp binder = defaultServiceManager()->checkService(String16("gpu")); + static const sp binder = defaultServiceManager()->checkService(String16("gpu")); if (!binder) { ALOGE("Failed to get gpu service"); return nullptr; -- GitLab From 00f511d329924824b1961e9472c3a06683fc2216 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Wed, 12 Jun 2019 16:55:40 -0700 Subject: [PATCH 0064/1255] Dispatch mouse events to window under the cursor. This CL adds cursor positions to NotifyMotionArgs, MotionEntry, InputMessage motion body and MotionEvent. Bug: 134788085 Test: The window under the cursor always responds to the gesture. Test: atest inputflinger_tests Test: atest libinput_tests Change-Id: I8ea460ed8738ffc3a5e997215685889cc1e1f2fe --- include/input/Input.h | 48 ++-- include/input/InputTransport.h | 31 +-- libs/input/Input.cpp | 55 ++-- libs/input/InputTransport.cpp | 62 ++--- libs/input/tests/InputEvent_test.cpp | 52 +++- .../tests/InputPublisherAndConsumer_test.cpp | 40 ++- libs/input/tests/StructLayout_test.cpp | 6 +- libs/input/tests/VelocityTracker_test.cpp | 13 +- services/inputflinger/InputDispatcher.cpp | 240 ++++++++++------- services/inputflinger/InputDispatcher.h | 20 +- services/inputflinger/InputListener.cpp | 100 ++++--- services/inputflinger/InputReader.cpp | 248 ++++++++++-------- services/inputflinger/include/InputListener.h | 22 +- .../tests/InputClassifierConverter_test.cpp | 15 +- .../tests/InputClassifier_test.cpp | 15 +- .../tests/InputDispatcher_test.cpp | 143 +++++++--- 16 files changed, 650 insertions(+), 460 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index 805957a5ca..a97624658c 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -24,12 +24,14 @@ */ #include +#include #include #include #include #include #include -#include + +#include /* * Additional private constants not defined in ndk/ui/input.h. @@ -246,6 +248,13 @@ enum class MotionClassification : uint8_t { */ const char* motionClassificationToString(MotionClassification classification); +/** + * Invalid value for cursor position. Used for non-mouse events, tests and injected events. Don't + * use it for direct comparison with any other value, because NaN isn't equal to itself according to + * IEEE 754. Use isnan() instead to check if a cursor position is valid. + */ +constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits::quiet_NaN(); + /* * Pointer coordinate data. */ @@ -459,6 +468,14 @@ public: inline float getYPrecision() const { return mYPrecision; } + inline float getRawXCursorPosition() const { return mXCursorPosition; } + + float getXCursorPosition() const; + + inline float getRawYCursorPosition() const { return mYCursorPosition; } + + float getYCursorPosition() const; + inline nsecs_t getDownTime() const { return mDownTime; } inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; } @@ -600,26 +617,13 @@ public: ssize_t findPointerIndex(int32_t pointerId) const; - void initialize( - int32_t deviceId, - int32_t source, - int32_t displayId, - int32_t action, - int32_t actionButton, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - MotionClassification classification, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - size_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords); + void initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action, + int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, + int32_t buttonState, MotionClassification classification, float xOffset, + float yOffset, float xPrecision, float yPrecision, float mXCursorPosition, + float mYCursorPosition, nsecs_t downTime, nsecs_t eventTime, + size_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords); void copyFrom(const MotionEvent* other, bool keepHistory); @@ -669,6 +673,8 @@ protected: float mYOffset; float mXPrecision; float mYPrecision; + float mXCursorPosition; + float mYCursorPosition; nsecs_t mDownTime; Vector mPointerProperties; Vector mSampleEventTimes; diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 63606e5911..df23f613c8 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -113,6 +113,8 @@ struct InputMessage { float yOffset; float xPrecision; float yPrecision; + float xCursorPosition; + float yCursorPosition; uint32_t pointerCount; uint32_t empty3; // Note that PointerCoords requires 8 byte alignment. @@ -261,27 +263,14 @@ public: * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS. * Other errors probably indicate that the channel is broken. */ - status_t publishMotionEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t displayId, - int32_t action, - int32_t actionButton, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - MotionClassification classification, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - uint32_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords); + status_t publishMotionEvent(uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, + int32_t action, int32_t actionButton, int32_t flags, + int32_t edgeFlags, int32_t metaState, int32_t buttonState, + MotionClassification classification, float xOffset, float yOffset, + float xPrecision, float yPrecision, float xCursorPosition, + float yCursorPosition, nsecs_t downTime, nsecs_t eventTime, + uint32_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords); /* Receives the finished signal from the consumer in reply to the original dispatch signal. * If a signal was received, returns the message sequence number, diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 9fd25f9cb7..3266b0740d 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -235,26 +235,14 @@ void PointerProperties::copyFrom(const PointerProperties& other) { // --- MotionEvent --- -void MotionEvent::initialize( - int32_t deviceId, - int32_t source, - int32_t displayId, - int32_t action, - int32_t actionButton, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - MotionClassification classification, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - size_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords) { +void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action, + int32_t actionButton, int32_t flags, int32_t edgeFlags, + int32_t metaState, int32_t buttonState, + MotionClassification classification, float xOffset, float yOffset, + float xPrecision, float yPrecision, float xCursorPosition, + float yCursorPosition, nsecs_t downTime, nsecs_t eventTime, + size_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords) { InputEvent::initialize(deviceId, source, displayId); mAction = action; mActionButton = actionButton; @@ -267,6 +255,8 @@ void MotionEvent::initialize( mYOffset = yOffset; mXPrecision = xPrecision; mYPrecision = yPrecision; + mXCursorPosition = xCursorPosition; + mYCursorPosition = yCursorPosition; mDownTime = downTime; mPointerProperties.clear(); mPointerProperties.appendArray(pointerProperties, pointerCount); @@ -288,6 +278,8 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mYOffset = other->mYOffset; mXPrecision = other->mXPrecision; mYPrecision = other->mYPrecision; + mXCursorPosition = other->mXCursorPosition; + mYCursorPosition = other->mYCursorPosition; mDownTime = other->mDownTime; mPointerProperties = other->mPointerProperties; @@ -312,6 +304,16 @@ void MotionEvent::addSample( mSamplePointerCoords.appendArray(pointerCoords, getPointerCount()); } +float MotionEvent::getXCursorPosition() const { + const float rawX = getRawXCursorPosition(); + return rawX + mXOffset; +} + +float MotionEvent::getYCursorPosition() const { + const float rawY = getRawYCursorPosition(); + return rawY + mYOffset; +} + const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const { return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex]; } @@ -431,6 +433,15 @@ void MotionEvent::transform(const float matrix[9]) { float originX, originY; transformPoint(matrix, 0, 0, &originX, &originY); + // Apply the transformation to cursor position. + if (!isnan(mXCursorPosition) && !isnan(mYCursorPosition)) { + float x = mXCursorPosition + oldXOffset; + float y = mYCursorPosition + oldYOffset; + transformPoint(matrix, x, y, &x, &y); + mXCursorPosition = x - mXOffset; + mYCursorPosition = y - mYOffset; + } + // Apply the transformation to all samples. size_t numSamples = mSamplePointerCoords.size(); for (size_t i = 0; i < numSamples; i++) { @@ -470,6 +481,8 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mYOffset = parcel->readFloat(); mXPrecision = parcel->readFloat(); mYPrecision = parcel->readFloat(); + mXCursorPosition = parcel->readFloat(); + mYCursorPosition = parcel->readFloat(); mDownTime = parcel->readInt64(); mPointerProperties.clear(); @@ -521,6 +534,8 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeFloat(mYOffset); parcel->writeFloat(mXPrecision); parcel->writeFloat(mYPrecision); + parcel->writeFloat(mXCursorPosition); + parcel->writeFloat(mYCursorPosition); parcel->writeInt64(mDownTime); for (size_t i = 0; i < pointerCount; i++) { diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index d02cb8ea46..904a6feb03 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -191,6 +191,10 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { msg->body.motion.xPrecision = body.motion.xPrecision; // float yPrecision msg->body.motion.yPrecision = body.motion.yPrecision; + // float xCursorPosition + msg->body.motion.xCursorPosition = body.motion.xCursorPosition; + // float yCursorPosition + msg->body.motion.yCursorPosition = body.motion.yCursorPosition; // uint32_t pointerCount msg->body.motion.pointerCount = body.motion.pointerCount; //struct Pointer pointers[MAX_POINTERS] @@ -465,26 +469,12 @@ status_t InputPublisher::publishKeyEvent( } status_t InputPublisher::publishMotionEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t displayId, - int32_t action, - int32_t actionButton, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - MotionClassification classification, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - uint32_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords) { + uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, int32_t action, + int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, + int32_t buttonState, MotionClassification classification, float xOffset, float yOffset, + float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, + nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { if (ATRACE_ENABLED()) { std::string message = StringPrintf( "publishMotionEvent(inputChannel=%s, action=%" PRId32 ")", @@ -532,6 +522,8 @@ status_t InputPublisher::publishMotionEvent( msg.body.motion.yOffset = yOffset; msg.body.motion.xPrecision = xPrecision; msg.body.motion.yPrecision = yPrecision; + msg.body.motion.xCursorPosition = xCursorPosition; + msg.body.motion.yCursorPosition = yCursorPosition; msg.body.motion.downTime = downTime; msg.body.motion.eventTime = eventTime; msg.body.motion.pointerCount = pointerCount; @@ -1135,26 +1127,16 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); } - event->initialize( - msg->body.motion.deviceId, - msg->body.motion.source, - msg->body.motion.displayId, - msg->body.motion.action, - msg->body.motion.actionButton, - msg->body.motion.flags, - msg->body.motion.edgeFlags, - msg->body.motion.metaState, - msg->body.motion.buttonState, - msg->body.motion.classification, - msg->body.motion.xOffset, - msg->body.motion.yOffset, - msg->body.motion.xPrecision, - msg->body.motion.yPrecision, - msg->body.motion.downTime, - msg->body.motion.eventTime, - pointerCount, - pointerProperties, - pointerCoords); + event->initialize(msg->body.motion.deviceId, msg->body.motion.source, + msg->body.motion.displayId, msg->body.motion.action, + msg->body.motion.actionButton, msg->body.motion.flags, + msg->body.motion.edgeFlags, msg->body.motion.metaState, + msg->body.motion.buttonState, msg->body.motion.classification, + msg->body.motion.xOffset, msg->body.motion.yOffset, + msg->body.motion.xPrecision, msg->body.motion.yPrecision, + msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition, + msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount, + pointerProperties, pointerCoords); } void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) { diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index 2b75c82bb1..ec34f3e652 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -255,11 +255,11 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28); event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0, - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, - AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, - MotionClassification::NONE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f, - ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, - 2, pointerProperties, pointerCoords); + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP, + AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE, + X_OFFSET, Y_OFFSET, 2.0f, 2.1f, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_DOWN_TIME, + ARBITRARY_EVENT_TIME, 2, pointerProperties, pointerCoords); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111); @@ -571,10 +571,11 @@ TEST_F(MotionEventTest, Transform) { } MotionEvent event; event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, - 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, - AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, - 0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/, - 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); + 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, + 0 /*buttonState*/, MotionClassification::NONE, 0 /*xOffset*/, 0 /*yOffset*/, + 0 /*xPrecision*/, 0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/, + 2 /*yCursorPosition*/, 0 /*downTime*/, 0 /*eventTime*/, pointerCount, + pointerProperties, pointerCoords); float originalRawX = 0 + 3; float originalRawY = -RADIUS + 2; @@ -602,6 +603,10 @@ TEST_F(MotionEventTest, Transform) { ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1); } + // Check cursor positions. + ASSERT_NEAR(sinf(PI_180 * (90 + ROTATION)) * RADIUS, event.getXCursorPosition(), 0.001); + ASSERT_NEAR(-cosf(PI_180 * (90 + ROTATION)) * RADIUS, event.getYCursorPosition(), 0.001); + // Applying the transformation should preserve the raw X and Y of the first point. ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001); ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); @@ -626,11 +631,34 @@ TEST_F(MotionEventTest, Initialize_SetsClassification) { for (MotionClassification classification : classifications) { event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, - classification, 0, 0, 0, 0, 0 /*downTime*/, 0 /*eventTime*/, - pointerCount, pointerProperties, pointerCoords); + AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, + 0, classification, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, 0 /*eventTime*/, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(classification, event.getClassification()); } } +TEST_F(MotionEventTest, Initialize_SetsCursorPosition) { + MotionEvent event; + constexpr size_t pointerCount = 1; + PointerProperties pointerProperties[pointerCount]; + PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerProperties[i].id = i; + pointerCoords[i].clear(); + } + + event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, + 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, 0, + 0, 0, 0, 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 0 /*downTime*/, + 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); + event.offsetLocation(20, 60); + ASSERT_EQ(280, event.getRawXCursorPosition()); + ASSERT_EQ(540, event.getRawYCursorPosition()); + ASSERT_EQ(300, event.getXCursorPosition()); + ASSERT_EQ(600, event.getYCursorPosition()); +} + } // namespace android diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index f2cd1be33f..a362f3281d 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -146,6 +146,8 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { constexpr float yOffset = -20; constexpr float xPrecision = 0.25; constexpr float yPrecision = 0.5; + constexpr float xCursorPosition = 1.3; + constexpr float yCursorPosition = 50.6; constexpr nsecs_t downTime = 3; constexpr size_t pointerCount = 3; constexpr nsecs_t eventTime = 4; @@ -168,10 +170,12 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i); } - status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton, - flags, edgeFlags, metaState, buttonState, classification, - xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount, - pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton, + flags, edgeFlags, metaState, buttonState, classification, + xOffset, yOffset, xPrecision, yPrecision, + xCursorPosition, yCursorPosition, downTime, eventTime, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; @@ -199,6 +203,10 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { EXPECT_EQ(classification, motionEvent->getClassification()); EXPECT_EQ(xPrecision, motionEvent->getXPrecision()); EXPECT_EQ(yPrecision, motionEvent->getYPrecision()); + EXPECT_EQ(xCursorPosition, motionEvent->getRawXCursorPosition()); + EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition()); + EXPECT_EQ(xCursorPosition + xOffset, motionEvent->getXCursorPosition()); + EXPECT_EQ(yCursorPosition + yOffset, motionEvent->getYCursorPosition()); EXPECT_EQ(downTime, motionEvent->getDownTime()); EXPECT_EQ(eventTime, motionEvent->getEventTime()); EXPECT_EQ(pointerCount, motionEvent->getPointerCount()); @@ -266,9 +274,11 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZer pointerCoords[i].clear(); } - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - MotionClassification::NONE, 0, 0, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, + 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -279,9 +289,11 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; - status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - MotionClassification::NONE, 0, 0, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, + 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -297,9 +309,11 @@ TEST_F(InputPublisherAndConsumerTest, pointerCoords[i].clear(); } - status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - MotionClassification::NONE, 0, 0, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, + 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index 62023fb328..8d8cf06c91 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -64,8 +64,10 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 68); CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 72); CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 76); - CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 80); - CHECK_OFFSET(InputMessage::Body::Motion, pointers, 88); + CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 80); + CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 84); + CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 88); + CHECK_OFFSET(InputMessage::Body::Motion, pointers, 96); CHECK_OFFSET(InputMessage::Body::Finished, seq, 0); CHECK_OFFSET(InputMessage::Body::Finished, handled, 4); diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index 368446ff4d..968e2fa6bc 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -176,12 +176,13 @@ static std::vector createMotionEventStream( EXPECT_EQ(pointerIndex, pointerCount); MotionEvent event; - event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, - action, 0 /*actionButton*/, 0 /*flags*/, - AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, - MotionClassification::NONE, - 0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/, - 0 /*downTime*/, entry.eventTime.count(), pointerCount, properties, coords); + event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, action, + 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, + 0 /*buttonState*/, MotionClassification::NONE, 0 /*xOffset*/, + 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, + entry.eventTime.count(), pointerCount, properties, coords); events.emplace_back(event); } diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index c2ff4c9629..b32309990f 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -262,14 +262,18 @@ static T getValueByKey(std::unordered_map& map, U key) { // --- InputDispatcher --- -InputDispatcher::InputDispatcher(const sp& policy) : - mPolicy(policy), - mPendingEvent(nullptr), mLastDropReason(DROP_REASON_NOT_DROPPED), - mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), - mNextUnblockedEvent(nullptr), - mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), - mFocusedDisplayId(ADISPLAY_ID_DEFAULT), - mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { +InputDispatcher::InputDispatcher(const sp& policy) + : mPolicy(policy), + mPendingEvent(nullptr), + mLastDropReason(DROP_REASON_NOT_DROPPED), + mAppSwitchSawKeyDown(false), + mAppSwitchDueTime(LONG_LONG_MAX), + mNextUnblockedEvent(nullptr), + mDispatchEnabled(false), + mDispatchFrozen(false), + mInputFilterEnabled(false), + mFocusedDisplayId(ADISPLAY_ID_DEFAULT), + mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { mLooper = new Looper(false); mReporter = createInputReporter(); @@ -1326,6 +1330,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN || maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction); + const bool isFromMouse = entry->source == AINPUT_SOURCE_MOUSE; bool wrongDevice = false; if (newGesture) { bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; @@ -1361,11 +1366,17 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) { /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ + int32_t x; + int32_t y; int32_t pointerIndex = getMotionEventActionPointerIndex(action); - int32_t x = int32_t(entry->pointerCoords[pointerIndex]. - getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(entry->pointerCoords[pointerIndex]. - getAxisValue(AMOTION_EVENT_AXIS_Y)); + // Always dispatch mouse events to cursor position. + if (isFromMouse) { + x = int32_t(entry->xCursorPosition); + y = int32_t(entry->yCursorPosition); + } else { + x = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X)); + y = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)); + } bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN; sp newTouchedWindowHandle = findTouchedWindowAtLocked( displayId, x, y, isDown /*addOutsideTargets*/, true /*addPortalWindows*/); @@ -2256,15 +2267,21 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, } // Publish the motion event. - status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, - motionEntry->deviceId, motionEntry->source, motionEntry->displayId, - dispatchEntry->resolvedAction, motionEntry->actionButton, - dispatchEntry->resolvedFlags, motionEntry->edgeFlags, - motionEntry->metaState, motionEntry->buttonState, motionEntry->classification, - xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision, - motionEntry->downTime, motionEntry->eventTime, - motionEntry->pointerCount, motionEntry->pointerProperties, - usingCoords); + status = + connection->inputPublisher + .publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, + motionEntry->source, motionEntry->displayId, + dispatchEntry->resolvedAction, + motionEntry->actionButton, + dispatchEntry->resolvedFlags, + motionEntry->edgeFlags, motionEntry->metaState, + motionEntry->buttonState, + motionEntry->classification, xOffset, yOffset, + motionEntry->xPrecision, motionEntry->yPrecision, + motionEntry->xCursorPosition, + motionEntry->yCursorPosition, motionEntry->downTime, + motionEntry->eventTime, motionEntry->pointerCount, + motionEntry->pointerProperties, usingCoords); break; } @@ -2590,24 +2607,17 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet } } - MotionEntry* splitMotionEntry = new MotionEntry( - originalMotionEntry->sequenceNum, - originalMotionEntry->eventTime, - originalMotionEntry->deviceId, - originalMotionEntry->source, - originalMotionEntry->displayId, - originalMotionEntry->policyFlags, - action, - originalMotionEntry->actionButton, - originalMotionEntry->flags, - originalMotionEntry->metaState, - originalMotionEntry->buttonState, - originalMotionEntry->classification, - originalMotionEntry->edgeFlags, - originalMotionEntry->xPrecision, - originalMotionEntry->yPrecision, - originalMotionEntry->downTime, - splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0); + MotionEntry* splitMotionEntry = + new MotionEntry(originalMotionEntry->sequenceNum, originalMotionEntry->eventTime, + originalMotionEntry->deviceId, originalMotionEntry->source, + originalMotionEntry->displayId, originalMotionEntry->policyFlags, + action, originalMotionEntry->actionButton, originalMotionEntry->flags, + originalMotionEntry->metaState, originalMotionEntry->buttonState, + originalMotionEntry->classification, originalMotionEntry->edgeFlags, + originalMotionEntry->xPrecision, originalMotionEntry->yPrecision, + originalMotionEntry->xCursorPosition, + originalMotionEntry->yCursorPosition, originalMotionEntry->downTime, + splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0); if (originalMotionEntry->injectionState) { splitMotionEntry->injectionState = originalMotionEntry->injectionState; @@ -2753,12 +2763,14 @@ bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 - ", policyFlags=0x%x, " - "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x," - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, - args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, - args->action, args->actionButton, args->flags, args->metaState, args->buttonState, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); + ", policyFlags=0x%x, " + "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, " + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, " + "mYCursorPosition=%f, downTime=%" PRId64, + args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, + args->action, args->actionButton, args->flags, args->metaState, args->buttonState, + args->edgeFlags, args->xPrecision, args->yPrecision, arg->xCursorPosition, + args->yCursorPosition, args->downTime); for (uint32_t i = 0; i < args->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " "x=%f, y=%f, pressure=%f, size=%f, " @@ -2800,12 +2812,12 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mLock.unlock(); MotionEvent event; - event.initialize(args->deviceId, args->source, args->displayId, - args->action, args->actionButton, - args->flags, args->edgeFlags, args->metaState, args->buttonState, - args->classification, 0, 0, args->xPrecision, args->yPrecision, - args->downTime, args->eventTime, - args->pointerCount, args->pointerProperties, args->pointerCoords); + event.initialize(args->deviceId, args->source, args->displayId, args->action, + args->actionButton, args->flags, args->edgeFlags, args->metaState, + args->buttonState, args->classification, 0, 0, args->xPrecision, + args->yPrecision, args->xCursorPosition, args->yCursorPosition, + args->downTime, args->eventTime, args->pointerCount, + args->pointerProperties, args->pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { @@ -2816,12 +2828,14 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { } // Just enqueue a new motion event. - MotionEntry* newEntry = new MotionEntry(args->sequenceNum, args->eventTime, - args->deviceId, args->source, args->displayId, policyFlags, - args->action, args->actionButton, args->flags, - args->metaState, args->buttonState, args->classification, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, - args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0); + MotionEntry* newEntry = + new MotionEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source, + args->displayId, policyFlags, args->action, args->actionButton, + args->flags, args->metaState, args->buttonState, + args->classification, args->edgeFlags, args->xPrecision, + args->yPrecision, args->xCursorPosition, args->yCursorPosition, + args->downTime, args->pointerCount, args->pointerProperties, + args->pointerCoords, 0, 0); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); @@ -2952,31 +2966,34 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, mLock.lock(); const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); - firstInjectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), motionEvent->getDisplayId(), - policyFlags, - action, actionButton, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getButtonState(), - motionEvent->getClassification(), motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), - uint32_t(pointerCount), pointerProperties, samplePointerCoords, - motionEvent->getXOffset(), motionEvent->getYOffset()); + firstInjectedEntry = + new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, + motionEvent->getDeviceId(), motionEvent->getSource(), + motionEvent->getDisplayId(), policyFlags, action, actionButton, + motionEvent->getFlags(), motionEvent->getMetaState(), + motionEvent->getButtonState(), motionEvent->getClassification(), + motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), + motionEvent->getYPrecision(), motionEvent->getRawXCursorPosition(), + motionEvent->getRawYCursorPosition(), motionEvent->getDownTime(), + uint32_t(pointerCount), pointerProperties, samplePointerCoords, + motionEvent->getXOffset(), motionEvent->getYOffset()); lastInjectedEntry = firstInjectedEntry; for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { sampleEventTimes += 1; samplePointerCoords += pointerCount; - MotionEntry* nextInjectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, - *sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), - motionEvent->getDisplayId(), policyFlags, - action, actionButton, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getButtonState(), - motionEvent->getClassification(), motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), - uint32_t(pointerCount), pointerProperties, samplePointerCoords, - motionEvent->getXOffset(), motionEvent->getYOffset()); + MotionEntry* nextInjectedEntry = + new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, + motionEvent->getDeviceId(), motionEvent->getSource(), + motionEvent->getDisplayId(), policyFlags, action, actionButton, + motionEvent->getFlags(), motionEvent->getMetaState(), + motionEvent->getButtonState(), motionEvent->getClassification(), + motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), + motionEvent->getYPrecision(), + motionEvent->getRawXCursorPosition(), + motionEvent->getRawYCursorPosition(), + motionEvent->getDownTime(), uint32_t(pointerCount), + pointerProperties, samplePointerCoords, + motionEvent->getXOffset(), motionEvent->getYOffset()); lastInjectedEntry->next = nextInjectedEntry; lastInjectedEntry = nextInjectedEntry; } @@ -4633,21 +4650,32 @@ void InputDispatcher::KeyEntry::recycle() { // --- InputDispatcher::MotionEntry --- -InputDispatcher::MotionEntry::MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, - uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action, - int32_t actionButton, +InputDispatcher::MotionEntry::MotionEntry( + uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, + int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification, - int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime, - uint32_t pointerCount, + int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, + float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xOffset, float yOffset) : - EventEntry(sequenceNum, TYPE_MOTION, eventTime, policyFlags), + float xOffset, float yOffset) + : EventEntry(sequenceNum, TYPE_MOTION, eventTime, policyFlags), eventTime(eventTime), - deviceId(deviceId), source(source), displayId(displayId), action(action), - actionButton(actionButton), flags(flags), metaState(metaState), buttonState(buttonState), - classification(classification), edgeFlags(edgeFlags), - xPrecision(xPrecision), yPrecision(yPrecision), - downTime(downTime), pointerCount(pointerCount) { + deviceId(deviceId), + source(source), + displayId(displayId), + action(action), + actionButton(actionButton), + flags(flags), + metaState(metaState), + buttonState(buttonState), + classification(classification), + edgeFlags(edgeFlags), + xPrecision(xPrecision), + yPrecision(yPrecision), + xCursorPosition(xCursorPosition), + yCursorPosition(yCursorPosition), + downTime(downTime), + pointerCount(pointerCount) { for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); @@ -4662,11 +4690,14 @@ InputDispatcher::MotionEntry::~MotionEntry() { void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const { msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32 - ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, " - "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, pointers=[", - deviceId, source, displayId, motionActionToString(action).c_str(), actionButton, flags, - metaState, buttonState, motionClassificationToString(classification), edgeFlags, - xPrecision, yPrecision); + ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, " + "buttonState=0x%08x, " + "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, " + "xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[", + deviceId, source, displayId, motionActionToString(action).c_str(), + actionButton, flags, metaState, buttonState, + motionClassificationToString(classification), edgeFlags, xPrecision, + yPrecision, xCursorPosition, yCursorPosition); for (uint32_t i = 0; i < pointerCount; i++) { if (i) { @@ -4936,6 +4967,8 @@ void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry, memento.flags = flags; memento.xPrecision = entry->xPrecision; memento.yPrecision = entry->yPrecision; + memento.xCursorPosition = entry->xCursorPosition; + memento.yCursorPosition = entry->yCursorPosition; memento.downTime = entry->downTime; memento.setPointers(entry); memento.hovering = hovering; @@ -4966,13 +4999,16 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim if (shouldCancelMotion(memento, options)) { const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL; - outEvents.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.downTime, - memento.pointerCount, memento.pointerProperties, memento.pointerCoords, - 0 /*xOffset*/, 0 /*yOffset*/)); + outEvents.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, memento.pointerCount, + memento.pointerProperties, memento.pointerCoords, 0 /*xOffset*/, + 0 /*yOffset*/)); } } } diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 753b748884..46dd9bd273 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -570,19 +570,21 @@ private: int32_t edgeFlags; float xPrecision; float yPrecision; + float xCursorPosition; + float yCursorPosition; nsecs_t downTime; uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; - MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, - int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, - int32_t action, int32_t actionButton, int32_t flags, - int32_t metaState, int32_t buttonState, MotionClassification classification, - int32_t edgeFlags, float xPrecision, float yPrecision, - nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xOffset, float yOffset); + MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, + int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, + int32_t flags, int32_t metaState, int32_t buttonState, + MotionClassification classification, int32_t edgeFlags, float xPrecision, + float yPrecision, float xCursorPosition, float yCursorPosition, + nsecs_t downTime, uint32_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, + float xOffset, float yOffset); virtual void appendDescription(std::string& msg) const; protected: @@ -830,6 +832,8 @@ private: int32_t flags; float xPrecision; float yPrecision; + float xCursorPosition; + float yCursorPosition; nsecs_t downTime; uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp index 423b69cff3..0498e87732 100644 --- a/services/inputflinger/InputListener.cpp +++ b/services/inputflinger/InputListener.cpp @@ -21,6 +21,7 @@ #include "InputListener.h" #include +#include namespace android { @@ -87,21 +88,33 @@ void NotifyKeyArgs::notify(const sp& listener) const { // --- NotifyMotionArgs --- -NotifyMotionArgs::NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, - uint32_t source, int32_t displayId, uint32_t policyFlags, - int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, - int32_t buttonState, MotionClassification classification, +NotifyMotionArgs::NotifyMotionArgs( + uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, + int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, + int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification, int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, nsecs_t downTime, - const std::vector& videoFrames) : - NotifyArgs(sequenceNum, eventTime), deviceId(deviceId), source(source), - displayId(displayId), policyFlags(policyFlags), - action(action), actionButton(actionButton), - flags(flags), metaState(metaState), buttonState(buttonState), - classification(classification), edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp), + float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, + nsecs_t downTime, const std::vector& videoFrames) + : NotifyArgs(sequenceNum, eventTime), + deviceId(deviceId), + source(source), + displayId(displayId), + policyFlags(policyFlags), + action(action), + actionButton(actionButton), + flags(flags), + metaState(metaState), + buttonState(buttonState), + classification(classification), + edgeFlags(edgeFlags), + deviceTimestamp(deviceTimestamp), pointerCount(pointerCount), - xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime), + xPrecision(xPrecision), + yPrecision(yPrecision), + xCursorPosition(xCursorPosition), + yCursorPosition(yCursorPosition), + downTime(downTime), videoFrames(videoFrames) { for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); @@ -109,14 +122,26 @@ NotifyMotionArgs::NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int3 } } -NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) : - NotifyArgs(other.sequenceNum, other.eventTime), deviceId(other.deviceId), - source(other.source), displayId(other.displayId), policyFlags(other.policyFlags), - action(other.action), actionButton(other.actionButton), flags(other.flags), - metaState(other.metaState), buttonState(other.buttonState), - classification(other.classification), edgeFlags(other.edgeFlags), - deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount), - xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime), +NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) + : NotifyArgs(other.sequenceNum, other.eventTime), + deviceId(other.deviceId), + source(other.source), + displayId(other.displayId), + policyFlags(other.policyFlags), + action(other.action), + actionButton(other.actionButton), + flags(other.flags), + metaState(other.metaState), + buttonState(other.buttonState), + classification(other.classification), + edgeFlags(other.edgeFlags), + deviceTimestamp(other.deviceTimestamp), + pointerCount(other.pointerCount), + xPrecision(other.xPrecision), + yPrecision(other.yPrecision), + xCursorPosition(other.xCursorPosition), + yCursorPosition(other.yCursorPosition), + downTime(other.downTime), videoFrames(other.videoFrames) { for (uint32_t i = 0; i < pointerCount; i++) { pointerProperties[i].copyFrom(other.pointerProperties[i]); @@ -124,28 +149,23 @@ NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) : } } +static inline bool isCursorPositionEqual(float lhs, float rhs) { + return (isnan(lhs) && isnan(rhs)) || lhs == rhs; +} + bool NotifyMotionArgs::operator==(const NotifyMotionArgs& rhs) const { - bool equal = - sequenceNum == rhs.sequenceNum - && eventTime == rhs.eventTime - && deviceId == rhs.deviceId - && source == rhs.source - && displayId == rhs.displayId - && policyFlags == rhs.policyFlags - && action == rhs.action - && actionButton == rhs.actionButton - && flags == rhs.flags - && metaState == rhs.metaState - && buttonState == rhs.buttonState - && classification == rhs.classification - && edgeFlags == rhs.edgeFlags - && deviceTimestamp == rhs.deviceTimestamp - && pointerCount == rhs.pointerCount + bool equal = sequenceNum == rhs.sequenceNum && eventTime == rhs.eventTime && + deviceId == rhs.deviceId && source == rhs.source && displayId == rhs.displayId && + policyFlags == rhs.policyFlags && action == rhs.action && + actionButton == rhs.actionButton && flags == rhs.flags && metaState == rhs.metaState && + buttonState == rhs.buttonState && classification == rhs.classification && + edgeFlags == rhs.edgeFlags && deviceTimestamp == rhs.deviceTimestamp && + pointerCount == rhs.pointerCount // PointerProperties and PointerCoords are compared separately below - && xPrecision == rhs.xPrecision - && yPrecision == rhs.yPrecision - && downTime == rhs.downTime - && videoFrames == rhs.videoFrames; + && xPrecision == rhs.xPrecision && yPrecision == rhs.yPrecision && + isCursorPositionEqual(xCursorPosition, rhs.xCursorPosition) && + isCursorPositionEqual(yCursorPosition, rhs.yCursorPosition) && + downTime == rhs.downTime && videoFrames == rhs.videoFrames; if (!equal) { return false; } diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index a45b8a56ce..9e5990964c 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -2782,6 +2782,8 @@ void CursorInputMapper::sync(nsecs_t when) { mPointerVelocityControl.move(when, &deltaX, &deltaY); int32_t displayId; + float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; + float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; if (mSource == AINPUT_SOURCE_MOUSE) { if (moved || scrolled || buttonsChanged) { mPointerController->setPresentation( @@ -2798,10 +2800,9 @@ void CursorInputMapper::sync(nsecs_t when) { mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); } - float x, y; - mPointerController->getPosition(&x, &y); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); displayId = mPointerController->getDisplayId(); @@ -2845,21 +2846,25 @@ void CursorInputMapper::sync(nsecs_t when) { int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); buttonState &= ~actionButton; NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, - metaState, buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, + metaState, buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, + &pointerCoords, mXPrecision, mYPrecision, + xCursorPosition, yCursorPosition, downTime, + /* videoFrames */ {}); getListener()->notifyMotion(&releaseArgs); } } NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + displayId, policyFlags, motionEventAction, 0, 0, metaState, + currentButtonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, + /* videoFrames */ {}); getListener()->notifyMotion(&args); if (buttonsPressed) { @@ -2868,11 +2873,14 @@ void CursorInputMapper::sync(nsecs_t when) { int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit()); buttonState |= actionButton; NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS, - actionButton, 0, metaState, buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, + metaState, buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, + &pointerCoords, mXPrecision, mYPrecision, + xCursorPosition, yCursorPosition, downTime, + /* videoFrames */ {}); getListener()->notifyMotion(&pressArgs); } } @@ -2882,12 +2890,14 @@ void CursorInputMapper::sync(nsecs_t when) { // Send hover move after UP to tell the application that the mouse is hovering now. if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) { - NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, - metaState, currentButtonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, + 0, metaState, currentButtonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, + &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, + yCursorPosition, downTime, + /* videoFrames */ {}); getListener()->notifyMotion(&hoverArgs); } @@ -2897,11 +2907,14 @@ void CursorInputMapper::sync(nsecs_t when) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, + currentButtonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, + &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, + yCursorPosition, downTime, + /* videoFrames */ {}); getListener()->notifyMotion(&scrollArgs); } } @@ -3041,12 +3054,13 @@ void RotaryEncoderInputMapper::sync(nsecs_t when) { int32_t metaState = mContext->getGlobalMetaState(); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor); - NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, /* buttonState */ 0, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - 0, 0, 0, /* videoFrames */ {}); + NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, + metaState, /* buttonState */ 0, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}); getListener()->notifyMotion(&scrollArgs); } @@ -5450,12 +5464,12 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); const int32_t displayId = mPointerController->getDisplayId(); - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, - metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - 0, 0, mPointerGesture.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, + metaState, buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0, + x, y, mPointerGesture.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6360,29 +6374,31 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, int32_t metaState = getContext()->getGlobalMetaState(); int32_t displayId = mViewport.displayId; - if (mPointerController != nullptr) { - if (down || hovering) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - mPointerController->clearSpots(); - mPointerController->setButtonState(mCurrentRawState.buttonState); - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } - displayId = mPointerController->getDisplayId(); + if (down || hovering) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); + mPointerController->clearSpots(); + mPointerController->setButtonState(mCurrentRawState.buttonState); + mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); + } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); } + displayId = mPointerController->getDisplayId(); + + float xCursorPosition; + float yCursorPosition; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); if (mPointerSimple.down && !down) { mPointerSimple.down = false; // Send up. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState, + mLastRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, + mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, + yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6390,13 +6406,13 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.hovering = false; // Send hover exit. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, + metaState, mLastRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, + mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, + yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6406,25 +6422,25 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.downTime = when; // Send down. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0, + metaState, mCurrentRawState.buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties, + &mPointerSimple.currentCoords, mOrientedXPrecision, + mOrientedYPrecision, xCursorPosition, yCursorPosition, + mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } // Send move. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, + mCurrentRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, + yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6433,26 +6449,25 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.hovering = true; // Send hover enter. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState, - mCurrentRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, + metaState, mCurrentRawState.buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties, + &mPointerSimple.currentCoords, mOrientedXPrecision, + mOrientedYPrecision, xCursorPosition, yCursorPosition, + mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } // Send hover move. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, - mCurrentRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, + metaState, mCurrentRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, + yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6468,13 +6483,13 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &pointerCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, + mCurrentRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.currentProperties, &pointerCoords, + mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, + yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6531,16 +6546,21 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32 ALOG_ASSERT(false); } } + float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; + float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; + if (mDeviceMode == DEVICE_MODE_POINTER) { + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + } const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE); const int32_t deviceId = getDeviceId(); std::vector frames = mDevice->getEventHub()->getVideoFrames(deviceId); std::for_each(frames.begin(), frames.end(), [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); }); - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId, - source, displayId, policyFlags, - action, actionButton, flags, metaState, buttonState, MotionClassification::NONE, - edgeFlags, deviceTimestamp, pointerCount, pointerProperties, pointerCoords, - xPrecision, yPrecision, downTime, std::move(frames)); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId, source, displayId, + policyFlags, action, actionButton, flags, metaState, buttonState, + MotionClassification::NONE, edgeFlags, deviceTimestamp, pointerCount, + pointerProperties, pointerCoords, xPrecision, yPrecision, xCursorPosition, + yCursorPosition, downTime, std::move(frames)); getListener()->notifyMotion(&args); } @@ -7462,10 +7482,12 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { uint32_t policyFlags = 0; NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - &pointerProperties, &pointerCoords, 0, 0, 0, /* videoFrames */ {}); + AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}); getListener()->notifyMotion(&args); } diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h index b51dcb6cad..57c894bf8b 100644 --- a/services/inputflinger/include/InputListener.h +++ b/services/inputflinger/include/InputListener.h @@ -119,19 +119,27 @@ struct NotifyMotionArgs : public NotifyArgs { PointerCoords pointerCoords[MAX_POINTERS]; float xPrecision; float yPrecision; + /** + * Mouse cursor position when this event is reported relative to the origin of the specified + * display. Only valid if this is a mouse event (originates from a mouse or from a trackpad in + * gestures enabled mode. + */ + float xCursorPosition; + float yCursorPosition; nsecs_t downTime; std::vector videoFrames; inline NotifyMotionArgs() { } NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, - int32_t displayId, uint32_t policyFlags, - int32_t action, int32_t actionButton, int32_t flags, - int32_t metaState, int32_t buttonState, MotionClassification classification, - int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, nsecs_t downTime, - const std::vector& videoFrames); + int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, + int32_t flags, int32_t metaState, int32_t buttonState, + MotionClassification classification, int32_t edgeFlags, + uint32_t deviceTimestamp, uint32_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, + float xPrecision, float yPrecision, float xCursorPosition, + float yCursorPosition, nsecs_t downTime, + const std::vector& videoFrames); NotifyMotionArgs(const NotifyMotionArgs& other); diff --git a/services/inputflinger/tests/InputClassifierConverter_test.cpp b/services/inputflinger/tests/InputClassifierConverter_test.cpp index 813b69edbb..ba1c7c9284 100644 --- a/services/inputflinger/tests/InputClassifierConverter_test.cpp +++ b/services/inputflinger/tests/InputClassifierConverter_test.cpp @@ -38,12 +38,15 @@ static NotifyMotionArgs generateBasicMotionArgs() { coords.setAxisValue(AMOTION_EVENT_AXIS_Y, 2); coords.setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.5); static constexpr nsecs_t downTime = 2; - NotifyMotionArgs motionArgs(1/*sequenceNum*/, downTime/*eventTime*/, 3/*deviceId*/, - AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4/*policyFlags*/, AMOTION_EVENT_ACTION_DOWN, - 0/*actionButton*/, 0/*flags*/, AMETA_NONE, 0/*buttonState*/, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, 5/*deviceTimestamp*/, - 1/*pointerCount*/, &properties, &coords, 0/*xPrecision*/, 0/*yPrecision*/, - downTime, {}/*videoFrames*/); + NotifyMotionArgs motionArgs(1 /*sequenceNum*/, downTime /*eventTime*/, 3 /*deviceId*/, + AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4 /*policyFlags*/, + AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, 0 /*flags*/, + AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, 5 /*deviceTimestamp*/, + 1 /*pointerCount*/, &properties, &coords, 0 /*xPrecision*/, + 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, + {} /*videoFrames*/); return motionArgs; } diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp index 7cc17a2215..9bc4282d9c 100644 --- a/services/inputflinger/tests/InputClassifier_test.cpp +++ b/services/inputflinger/tests/InputClassifier_test.cpp @@ -38,12 +38,15 @@ static NotifyMotionArgs generateBasicMotionArgs() { coords.setAxisValue(AMOTION_EVENT_AXIS_X, 1); coords.setAxisValue(AMOTION_EVENT_AXIS_Y, 1); static constexpr nsecs_t downTime = 2; - NotifyMotionArgs motionArgs(1/*sequenceNum*/, downTime/*eventTime*/, 3/*deviceId*/, - AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4/*policyFlags*/, AMOTION_EVENT_ACTION_DOWN, - 0/*actionButton*/, 0/*flags*/, AMETA_NONE, 0/*buttonState*/, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, 5/*deviceTimestamp*/, - 1/*pointerCount*/, &properties, &coords, 0/*xPrecision*/, 0/*yPrecision*/, - downTime, {}/*videoFrames*/); + NotifyMotionArgs motionArgs(1 /*sequenceNum*/, downTime /*eventTime*/, 3 /*deviceId*/, + AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4 /*policyFlags*/, + AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, 0 /*flags*/, + AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, 5 /*deviceTimestamp*/, + 1 /*pointerCount*/, &properties, &coords, 0 /*xPrecision*/, + 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, + {} /*videoFrames*/); return motionArgs; } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 9fe6481ca0..c28a6214d6 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -249,8 +249,10 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects undefined motion actions. event.initialize(DEVICE_ID, source, DISPLAY_ID, - /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) @@ -258,18 +260,24 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects pointer down with invalid index. event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer down index too large."; event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + AMOTION_EVENT_ACTION_POINTER_DOWN | + (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) @@ -277,36 +285,45 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects pointer up with invalid index. event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + AMOTION_EVENT_ACTION_POINTER_UP | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer up index too large."; event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + AMOTION_EVENT_ACTION_POINTER_UP | + (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer up index too small."; // Rejects motion events with invalid number of pointers. - event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords); + event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, + metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 0, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with 0 pointers."; - event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); + event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, + metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) @@ -314,18 +331,22 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects motion events with invalid pointer ids. pointerProperties[0].id = -1; - event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, + metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer ids less than 0."; pointerProperties[0].id = MAX_POINTER_ID + 1; - event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, + metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) @@ -334,9 +355,11 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects motion events with duplicate pointer ids. pointerProperties[0].id = 1; pointerProperties[1].id = 1; - event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords); + event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, + metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 2, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) @@ -463,6 +486,7 @@ public: mInfo.frameRight = mFrame.right; mInfo.frameBottom = mFrame.bottom; mInfo.globalScaleFactor = 1.0; + mInfo.touchableRegion.clear(); mInfo.addTouchableRegion(mFrame); mInfo.visible = true; mInfo.canReceiveKeys = true; @@ -521,8 +545,10 @@ static int32_t injectKeyDown(const sp& dispatcher, INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); } -static int32_t injectMotionDown(const sp& dispatcher, int32_t source, - int32_t displayId, int32_t x = 100, int32_t y = 200) { +static int32_t injectMotionEvent(const sp& dispatcher, int32_t action, + int32_t source, int32_t displayId, int32_t x, int32_t y, + int32_t xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION, + int32_t yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION) { MotionEvent event; PointerProperties pointerProperties[1]; PointerCoords pointerCoords[1]; @@ -537,12 +563,11 @@ static int32_t injectMotionDown(const sp& dispatcher, int32_t s nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid motion down event. - event.initialize(DEVICE_ID, source, displayId, - AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, - AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, - /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0, - /* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties, - pointerCoords); + event.initialize(DEVICE_ID, source, displayId, action, /* actionButton */ 0, /* flags */ 0, + /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, + /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0, + /* yPrecision */ 0, xCursorPosition, yCursorPosition, currentTime, currentTime, + /*pointerCount*/ 1, pointerProperties, pointerCoords); // Inject event until dispatch out. return dispatcher->injectInputEvent( @@ -551,6 +576,11 @@ static int32_t injectMotionDown(const sp& dispatcher, int32_t s INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); } +static int32_t injectMotionDown(const sp& dispatcher, int32_t source, + int32_t displayId, int32_t x = 100, int32_t y = 200) { + return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, x, y); +} + static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) { nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid key event. @@ -576,11 +606,12 @@ static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid motion event. NotifyMotionArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, source, displayId, - POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0, - AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, pointerProperties, - pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0, currentTime, - /* videoFrames */ {}); + POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0, + AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + pointerProperties, pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /* videoFrames */ {}); return args; } @@ -704,6 +735,32 @@ TEST_F(InputDispatcherTest, SetInputWindow_InputWindowInfo) { windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE); } +TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { + sp application = new FakeApplicationHandle(); + + sp windowLeft = + new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + windowLeft->setFrame(Rect(0, 0, 600, 800)); + windowLeft->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL); + sp windowRight = + new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + windowRight->setFrame(Rect(600, 0, 1200, 800)); + windowRight->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL); + + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + + std::vector> inputWindowHandles{windowLeft, windowRight}; + mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT); + + // Inject an event with coordinate in the area of right window, with mouse cursor in the area of + // left window. This event should be dispatched to the left window. + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE, + ADISPLAY_ID_DEFAULT, 610, 400, 599, 400)); + windowLeft->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT); + windowRight->assertNoEvents(); +} + /* Test InputDispatcher for MultiDisplay */ class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest { public: -- GitLab From addb02b4146f119892499510255cd3df247db14c Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Tue, 25 Jun 2019 16:36:13 -0700 Subject: [PATCH 0065/1255] Stop splitting mouse events. Mouse events should always be dispatched to the window under the cursor, so it shouldn't be split in any case. This change's parent already uses mouse cursor position to dispatch mouse events regardless of the coordinate of events. Therefore this change is just to make it conceptually correct. Bug: 134788085 Test: The window under the cursor always responds to the gesture. Change-Id: Id0d791bb75df7be8ba5c49e840b5655c008fded0 --- services/inputflinger/InputDispatcher.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index b32309990f..be1370747c 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -1388,8 +1388,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // Figure out whether splitting will be allowed for this window. if (newTouchedWindowHandle != nullptr && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { - // New window supports splitting. - isSplit = true; + // New window supports splitting, but we should never split mouse events. + isSplit = !isFromMouse; } else if (isSplit) { // New window does not support splitting but we have already split events. // Ignore the new window. -- GitLab From efb71afcbb5d8f57af6435391f5d4835696375cc Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 27 Jun 2019 14:45:53 -0700 Subject: [PATCH 0066/1255] blast: fix registering callbacks This is a better fix for b/134194071 than ag/7998544. The previous patch only protected the call to notify the binder thread to send a callback. This patch has both a start registration and end registration call. During that time, the transaction callback cannot be sent. This is closer to a long term fix for the bug. Bug: 134194071 Test: Switch between front and back cameras to make sure the app doesn't crash. Change-Id: I2d20c13cc1c8d13e5a1340dfaa8cbbaa4d3a30ab --- .../gui/ITransactionCompletedListener.h | 10 ++++ services/surfaceflinger/BufferStateLayer.cpp | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 19 +++---- .../TransactionCompletedThread.cpp | 50 +++++++++++++++--- .../TransactionCompletedThread.h | 51 ++++++++++++++----- 5 files changed, 102 insertions(+), 32 deletions(-) diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index 774ad46b15..cbfd365692 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -106,6 +106,16 @@ public: const std::vector& ids) : transactionCompletedListener(listener), callbackIds(ids) {} + bool operator==(const ListenerCallbacks& rhs) const { + if (transactionCompletedListener != rhs.transactionCompletedListener) { + return false; + } + if (callbackIds.empty()) { + return rhs.callbackIds.empty(); + } + return callbackIds.front() == rhs.callbackIds.front(); + } + sp transactionCompletedListener; std::vector callbackIds; }; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 2abc1a75a9..4b01301467 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -85,7 +85,7 @@ void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const { } void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { - mFlinger->getTransactionCompletedThread().addPresentedCallbackHandles( + mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles( mDrawingState.callbackHandles); mDrawingState.callbackHandles = {}; @@ -310,7 +310,7 @@ bool BufferStateLayer::setTransactionCompletedListeners( } else { // If this layer will NOT need to be relatched and presented this frame // Notify the transaction completed thread this handle is done - mFlinger->getTransactionCompletedThread().addUnpresentedCallbackHandle(handle); + mFlinger->getTransactionCompletedThread().registerUnpresentedCallbackHandle(handle); } } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f53d3faef8..7d8630f6b1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2183,14 +2183,7 @@ void SurfaceFlinger::postComposition() } mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]); - - // Lock the mStateLock in case SurfaceFlinger is in the middle of applying a transaction. - // If we do not lock here, a callback could be sent without all of its SurfaceControls and - // metrics. - { - Mutex::Autolock _l(mStateLock); - mTransactionCompletedThread.sendCallbacks(); - } + mTransactionCompletedThread.sendCallbacks(); if (mLumaSampling && mRegionSamplingThread) { mRegionSamplingThread->notifyNewContent(); @@ -3790,8 +3783,8 @@ void SurfaceFlinger::applyTransactionState(const Vector& states, if (!listenerCallbacks.empty()) { mTransactionCompletedThread.run(); } - for (const auto& [listener, callbackIds] : listenerCallbacks) { - mTransactionCompletedThread.addCallback(listener, callbackIds); + for (const auto& listenerCallback : listenerCallbacks) { + mTransactionCompletedThread.startRegistration(listenerCallback); } uint32_t clientStateFlags = 0; @@ -3800,6 +3793,10 @@ void SurfaceFlinger::applyTransactionState(const Vector& states, postTime, privileged); } + for (const auto& listenerCallback : listenerCallbacks) { + mTransactionCompletedThread.endRegistration(listenerCallback); + } + // If the state doesn't require a traversal and there are callbacks, send them now if (!(clientStateFlags & eTraversalNeeded) && !listenerCallbacks.empty()) { mTransactionCompletedThread.sendCallbacks(); @@ -3937,7 +3934,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( sp layer(client->getLayerUser(s.surface)); if (layer == nullptr) { for (auto& listenerCallback : listenerCallbacks) { - mTransactionCompletedThread.addUnpresentedCallbackHandle( + mTransactionCompletedThread.registerUnpresentedCallbackHandle( new CallbackHandle(listenerCallback.transactionCompletedListener, listenerCallback.callbackIds, s.surface)); } diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp index 5cf8eb1a1d..0806f2aa93 100644 --- a/services/surfaceflinger/TransactionCompletedThread.cpp +++ b/services/surfaceflinger/TransactionCompletedThread.cpp @@ -75,14 +75,15 @@ void TransactionCompletedThread::run() { mThread = std::thread(&TransactionCompletedThread::threadMain, this); } -status_t TransactionCompletedThread::addCallback(const sp& listener, - const std::vector& callbackIds) { +status_t TransactionCompletedThread::startRegistration(const ListenerCallbacks& listenerCallbacks) { std::lock_guard lock(mMutex); if (!mRunning) { ALOGE("cannot add callback because the callback thread isn't running"); return BAD_VALUE; } + auto& [listener, callbackIds] = listenerCallbacks; + if (mCompletedTransactions.count(listener) == 0) { status_t err = IInterface::asBinder(listener)->linkToDeath(mDeathRecipient); if (err != NO_ERROR) { @@ -91,11 +92,41 @@ status_t TransactionCompletedThread::addCallback(const sp& transactionListener, + const std::vector& callbackIds) { + ListenerCallbacks listenerCallbacks(transactionListener, callbackIds); + + auto itr = mRegisteringTransactions.find(listenerCallbacks); + return itr != mRegisteringTransactions.end(); +} + status_t TransactionCompletedThread::registerPendingCallbackHandle( const sp& handle) { std::lock_guard lock(mMutex); @@ -105,7 +136,7 @@ status_t TransactionCompletedThread::registerPendingCallbackHandle( } // If we can't find the transaction stats something has gone wrong. The client should call - // addCallback before trying to register a pending callback handle. + // startRegistration before trying to register a pending callback handle. TransactionStats* transactionStats; status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats); if (err != NO_ERROR) { @@ -117,7 +148,7 @@ status_t TransactionCompletedThread::registerPendingCallbackHandle( return NO_ERROR; } -status_t TransactionCompletedThread::addPresentedCallbackHandles( +status_t TransactionCompletedThread::finalizePendingCallbackHandles( const std::deque>& handles) { std::lock_guard lock(mMutex); if (!mRunning) { @@ -158,7 +189,7 @@ status_t TransactionCompletedThread::addPresentedCallbackHandles( return NO_ERROR; } -status_t TransactionCompletedThread::addUnpresentedCallbackHandle( +status_t TransactionCompletedThread::registerUnpresentedCallbackHandle( const sp& handle) { std::lock_guard lock(mMutex); if (!mRunning) { @@ -189,7 +220,7 @@ status_t TransactionCompletedThread::findTransactionStats( status_t TransactionCompletedThread::addCallbackHandle(const sp& handle) { // If we can't find the transaction stats something has gone wrong. The client should call - // addCallback before trying to add a presnted callback handle. + // startRegistration before trying to add a callback handle. TransactionStats* transactionStats; status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats); if (err != NO_ERROR) { @@ -233,6 +264,13 @@ void TransactionCompletedThread::threadMain() { while (transactionStatsItr != transactionStatsDeque.end()) { auto& transactionStats = *transactionStatsItr; + // If this transaction is still registering, it is not safe to send a callback + // because there could be surface controls that haven't been added to + // transaction stats or mPendingTransactions. + if (isRegisteringTransaction(listener, transactionStats.callbackIds)) { + break; + } + // If we are still waiting on the callback handles for this transaction, stop // here because all transaction callbacks for the same listener must come in order auto pendingTransactions = mPendingTransactions.find(listener); diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h index 21e2678701..b821350657 100644 --- a/services/surfaceflinger/TransactionCompletedThread.h +++ b/services/surfaceflinger/TransactionCompletedThread.h @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -30,6 +31,12 @@ namespace android { +struct ITransactionCompletedListenerHash { + std::size_t operator()(const sp& listener) const { + return std::hash{}((listener) ? IInterface::asBinder(listener).get() : nullptr); + } +}; + struct CallbackIdsHash { // CallbackId vectors have several properties that let us get away with this simple hash. // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is @@ -42,6 +49,22 @@ struct CallbackIdsHash { } }; +struct ListenerCallbacksHash { + std::size_t HashCombine(size_t value1, size_t value2) const { + return value1 ^ (value2 + 0x9e3779b9 + (value1 << 6) + (value1 >> 2)); + } + + std::size_t operator()(const ListenerCallbacks& listenerCallbacks) const { + struct ITransactionCompletedListenerHash listenerHasher; + struct CallbackIdsHash callbackIdsHasher; + + std::size_t listenerHash = listenerHasher(listenerCallbacks.transactionCompletedListener); + std::size_t callbackIdsHash = callbackIdsHasher(listenerCallbacks.callbackIds); + + return HashCombine(listenerHash, callbackIdsHash); + } +}; + class CallbackHandle : public RefBase { public: CallbackHandle(const sp& transactionListener, @@ -64,10 +87,12 @@ public: void run(); // Adds listener and callbackIds in case there are no SurfaceControls that are supposed - // to be included in the callback. This functions should be call before attempting to add any - // callback handles. - status_t addCallback(const sp& transactionListener, - const std::vector& callbackIds); + // to be included in the callback. This functions should be call before attempting to register + // any callback handles. + status_t startRegistration(const ListenerCallbacks& listenerCallbacks); + // Ends the registration. After this is called, no more CallbackHandles will be registered. + // It is safe to send a callback if the Transaction doesn't have any Pending callback handles. + status_t endRegistration(const ListenerCallbacks& listenerCallbacks); // Informs the TransactionCompletedThread that there is a Transaction with a CallbackHandle // that needs to be latched and presented this frame. This function should be called once the @@ -76,11 +101,11 @@ public: // presented. status_t registerPendingCallbackHandle(const sp& handle); // Notifies the TransactionCompletedThread that a pending CallbackHandle has been presented. - status_t addPresentedCallbackHandles(const std::deque>& handles); + status_t finalizePendingCallbackHandles(const std::deque>& handles); // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and // presented this frame. - status_t addUnpresentedCallbackHandle(const sp& handle); + status_t registerUnpresentedCallbackHandle(const sp& handle); void addPresentFence(const sp& presentFence); @@ -89,6 +114,9 @@ public: private: void threadMain(); + bool isRegisteringTransaction(const sp& transactionListener, + const std::vector& callbackIds) REQUIRES(mMutex); + status_t findTransactionStats(const sp& listener, const std::vector& callbackIds, TransactionStats** outTransactionStats) REQUIRES(mMutex); @@ -106,13 +134,6 @@ private: }; sp mDeathRecipient; - struct ITransactionCompletedListenerHash { - std::size_t operator()(const sp& listener) const { - return std::hash{}((listener) ? IInterface::asBinder(listener).get() - : nullptr); - } - }; - // Protects the creation and destruction of mThread std::mutex mThreadMutex; @@ -121,11 +142,15 @@ private: std::mutex mMutex; std::condition_variable_any mConditionVariable; + std::unordered_set mRegisteringTransactions + GUARDED_BY(mMutex); + std::unordered_map< sp, std::unordered_map, uint32_t /*count*/, CallbackIdsHash>, ITransactionCompletedListenerHash> mPendingTransactions GUARDED_BY(mMutex); + std::unordered_map, std::deque, ITransactionCompletedListenerHash> mCompletedTransactions GUARDED_BY(mMutex); -- GitLab From 0136414e63036f660f5e05e5419d3741ab6846fa Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan Date: Tue, 2 Jul 2019 15:52:49 -0700 Subject: [PATCH 0067/1255] Generate Vulkan framework from Vulkan registry (Part 2) Instead of using the manually created vulkan.api file for generating the Vulkan driver framework, we generate it directly from the vulkan registry (vk.xml) Bug : 134711355 Test: Build and flash, dEQP tests Change-Id: I7a7c04a05d9eea5a03b4651fcff75948d3353933 --- vulkan/scripts/code_generator.py | 3 + vulkan/scripts/driver_generator.py | 393 +++++++++++++++++++++++++++++ vulkan/scripts/generator_common.py | 27 +- 3 files changed, 422 insertions(+), 1 deletion(-) create mode 100644 vulkan/scripts/driver_generator.py diff --git a/vulkan/scripts/code_generator.py b/vulkan/scripts/code_generator.py index 91c0d3023a..9e14b2886a 100644 --- a/vulkan/scripts/code_generator.py +++ b/vulkan/scripts/code_generator.py @@ -19,8 +19,11 @@ import generator_common as gencom import api_generator as apigen +import driver_generator as drivergen if __name__ == '__main__': gencom.parseVulkanRegistry() apigen.api_genh() apigen.api_gencpp() + drivergen.driver_genh() + drivergen.driver_gencpp() diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py new file mode 100644 index 0000000000..92326caf46 --- /dev/null +++ b/vulkan/scripts/driver_generator.py @@ -0,0 +1,393 @@ +#!/usr/bin/env python3 +# +# 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. +# +# This script provides the functions for generating the +# vulkan driver framework directly from the vulkan registry (vk.xml). + +import generator_common as gencom +import os + +interceptedExtensions = [ + 'VK_ANDROID_native_buffer', + 'VK_EXT_debug_report', + 'VK_EXT_hdr_metadata', + 'VK_EXT_swapchain_colorspace', + 'VK_GOOGLE_display_timing', + 'VK_KHR_android_surface', + 'VK_KHR_incremental_present', + 'VK_KHR_shared_presentable_image', + 'VK_KHR_surface', + 'VK_KHR_swapchain', + 'VK_KHR_get_surface_capabilities2' +] + +knownExtensions = interceptedExtensions + [ + 'VK_KHR_get_physical_device_properties2', + 'VK_ANDROID_external_memory_android_hardware_buffer', + 'VK_KHR_bind_memory2' +] + +def defineProcHookType(f): + f.write ("""struct ProcHook { + enum Type { + GLOBAL, + INSTANCE, + DEVICE, + }; + enum Extension {\n""") + for exts in knownExtensions: + f.write (gencom.clang_off_spaces*2 + exts[3:] + ',\n') + f.write ('\n') + f.write (gencom.clang_off_spaces*2 + """EXTENSION_CORE, // valid bit + EXTENSION_COUNT, + EXTENSION_UNKNOWN, + }; + + const char* name; + Type type; + Extension extension; + + PFN_vkVoidFunction proc; + PFN_vkVoidFunction checked_proc; // always nullptr for non-device hooks +};\n\n""") + +def isExtensionIntercepted(extensionName): + if extensionName in interceptedExtensions: + return True + return False + +def isDriverTableEntry(functionName): + switchCase = { + # Create functions of dispatchable objects + 'vkCreateDevice' : True, + 'vkGetDeviceQueue' : True, + 'vkGetDeviceQueue2' : True, + 'vkAllocateCommandBuffers' : True, + + # Destroy functions of dispatchable objects + 'vkDestroyInstance' : True, + 'vkDestroyDevice' : True, + + # Enumeration of extensions + 'vkEnumerateDeviceExtensionProperties' : True, + + # We cache physical devices in loader.cpp + 'vkEnumeratePhysicalDevices' : True, + 'vkEnumeratePhysicalDeviceGroups' : True, + + 'vkGetInstanceProcAddr' : True, + 'vkGetDeviceProcAddr' : True, + + # VK_KHR_swapchain->VK_ANDROID_native_buffer translation + 'vkCreateImage' : True, + 'vkDestroyImage' : True, + + 'vkGetPhysicalDeviceProperties' : True, + 'vkGetPhysicalDeviceProperties2' : True, + 'vkGetPhysicalDeviceProperties2KHR' : True, + + # VK_KHR_swapchain v69 requirement + 'vkBindImageMemory2' : True, + 'vkBindImageMemory2KHR' : True + } + if gencom.isFunctionSupported(functionName): + if functionName in switchCase: + return True + if functionName in gencom.extensionsDict: + if gencom.extensionsDict[functionName] == 'VK_ANDROID_native_buffer' or gencom.extensionsDict[functionName] == 'VK_EXT_debug_report': + return True + return False + +def isInstanceDriverTableEntry(functionName): + if isDriverTableEntry(functionName) and gencom.isInstanceDispatched(functionName): + return True + return False + +def isDeviceDriverTableEntry(functionName): + if isDriverTableEntry(functionName) and gencom.isDeviceDispatched(functionName): + return True + return False + +def driver_genh(): + header = """#ifndef LIBVULKAN_DRIVER_GEN_H +#define LIBVULKAN_DRIVER_GEN_H + +#include +#include + +#include + +namespace vulkan { +namespace driver {\n\n""" + genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen2.h') + with open(genfile, 'w') as f: + f.write (gencom.copyright) + f.write (gencom.warning) + f.write (header) + defineProcHookType(f) + f.write ('struct InstanceDriverTable {\n') + gencom.clang_off(f, 1) + for cmds in gencom.allCommandsList: + if isInstanceDriverTableEntry(cmds): + f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n') + gencom.clang_on(f, 1) + f.write ('};\n\n') + f.write ('struct DeviceDriverTable {\n') + gencom.clang_off(f,1) + for cmds in gencom.allCommandsList: + if isDeviceDriverTableEntry(cmds): + f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n') + gencom.clang_on(f,1) + f.write ('};\n\n') + f.write ("""const ProcHook* GetProcHook(const char* name); +ProcHook::Extension GetProcHookExtension(const char* name); + +bool InitDriverTable(VkInstance instance, + PFN_vkGetInstanceProcAddr get_proc, + const std::bitset& extensions); +bool InitDriverTable(VkDevice dev, + PFN_vkGetDeviceProcAddr get_proc, + const std::bitset& extensions); + +} // namespace driver +} // namespace vulkan + +#endif // LIBVULKAN_DRIVER_TABLE_H\n""") + +def isIntercepted(functionName): + switchCase = { + # Create functions of dispatchable objects + 'vkCreateInstance' : True, + 'vkCreateDevice' : True, + 'vkEnumeratePhysicalDevices' : True, + 'vkEnumeratePhysicalDeviceGroups' : True, + 'vkGetDeviceQueue' : True, + 'vkGetDeviceQueue2' : True, + 'vkAllocateCommandBuffers' : True, + + # Destroy functions of dispatchable objects + 'vkDestroyInstance' : True, + 'vkDestroyDevice' : True, + + # Enumeration of extensions + 'vkEnumerateInstanceExtensionProperties' : True, + 'vkEnumerateDeviceExtensionProperties' : True, + + 'vkGetInstanceProcAddr' : True, + 'vkGetDeviceProcAddr' : True, + + # VK_KHR_swapchain v69 requirement + 'vkBindImageMemory2' : True, + 'vkBindImageMemory2KHR' : True + } + if gencom.isFunctionSupported(functionName): + if functionName in switchCase: + return switchCase[functionName] + + if functionName in gencom.extensionsDict: + return isExtensionIntercepted(gencom.extensionsDict[functionName]) + return False + +def needProcHookStub(functionName): + if isIntercepted(functionName) and gencom.isDeviceDispatched(functionName): + if functionName in gencom.extensionsDict: + if not gencom.isExtensionInternal(gencom.extensionsDict[functionName]): + return True + return False + +def defineInitProc(name, f): + f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n') + f.write ('\n') + f.write ("""#define INIT_PROC(required, obj, proc) \\ + do { \\ + data.""" + name + """.proc = \\ + reinterpret_cast(get_proc(obj, "vk" #proc)); \\ + if (UNLIKELY(required && !data.""" + name + """.proc)) { \\ + ALOGE("missing " #obj " proc: vk" #proc); \\ + success = false; \\ + } \\ + } while (0)\n\n""") + +def defineInitProcExt(f): + f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc) \\ + do { \\ + if (extensions[ProcHook::ext]) \\ + INIT_PROC(required, obj, proc); \\ + } while (0)\n\n""") + +def defineProcHookStub(functionName, f): + if needProcHookStub(functionName): + ext_name = gencom.extensionsDict[functionName] + base_name = functionName[2:] + paramList = [''.join(i) for i in gencom.paramDict[functionName]] + p0 = gencom.paramDict[functionName][0][1] + f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' checked' + base_name + '(' + ', '.join(paramList) + ') {\n') + ext_hook = 'ProcHook::' + ext_name[3:] + + f.write (gencom.clang_off_spaces + 'if (GetData(' + p0 + ').hook_extensions[' + ext_hook + ']) {\n') + f.write (gencom.clang_off_spaces *2) + if gencom.returnTypeDict[functionName] != 'void': + f.write ('return ') + paramNames = [''.join(i[1]) for i in gencom.paramDict[functionName]] + f.write (base_name + '(' + ', '.join(paramNames) + ');\n') + f.write (gencom.clang_off_spaces + '} else {\n') + f.write (gencom.clang_off_spaces*2 + 'Logger(' + p0 + ').Err(' + p0 + ', \"' + ext_name + ' not enabled. ' + functionName + ' not executed.\");\n') + if gencom.returnTypeDict[functionName] != 'void': + f.write (gencom.clang_off_spaces*2 + 'return VK_SUCCESS;\n') + f.write (gencom.clang_off_spaces + '}\n') + f.write ('}\n\n') + +def defineGlobalProcHook(functionName, f): + base_name = functionName[2:] + assert (functionName not in gencom.extensionsDict) + f.write (gencom.clang_off_spaces + '{\n' + gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n' + gencom.clang_off_spaces*2) + f.write ("""ProcHook::GLOBAL, + ProcHook::EXTENSION_CORE, + reinterpret_cast(""" + base_name + """), + nullptr, + },\n""") + +def defineInstanceProcHook(functionName, f): + base_name = functionName[2:] + f.write (gencom.clang_off_spaces + '{\n') + f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n') + f.write (gencom.clang_off_spaces*2 + 'ProcHook::INSTANCE,\n') + + if functionName in gencom.extensionsDict: + ext_name = gencom.extensionsDict[functionName] + f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n') + if gencom.isExtensionInternal(ext_name): + f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n') + else: + f.write (gencom.clang_off_spaces*2 + 'reinterpret_cast(' + base_name + '),\n' + gencom.clang_off_spaces*2 + 'nullptr,\n') + + else: + f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE, + reinterpret_cast(""" + base_name + """), + nullptr,\n""") + + f.write (gencom.clang_off_spaces + '},\n') + +def defineDeviceProcHook(functionName, f): + base_name = functionName[2:] + f.write (gencom.clang_off_spaces + '{\n') + f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n') + f.write (gencom.clang_off_spaces*2 + 'ProcHook::DEVICE,\n') + + if functionName in gencom.extensionsDict: + ext_name = gencom.extensionsDict[functionName] + f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n') + if gencom.isExtensionInternal(ext_name): + f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n') + else: + f.write (gencom.clang_off_spaces*2 + 'reinterpret_cast(' + base_name + '),\n' + gencom.clang_off_spaces*2 + 'reinterpret_cast(checked' + base_name + '),\n') + + else: + f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE, + reinterpret_cast(""" + base_name + """), + nullptr,\n""") + + f.write (gencom.clang_off_spaces + '},\n') + +def driver_gencpp(): + header = """#include +#include + +#include + +#include "driver.h" + +namespace vulkan { +namespace driver { + +namespace { + +// clang-format off\n\n""" + + genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen2.cpp') + + with open(genfile, 'w') as f: + f.write (gencom.copyright) + f.write (gencom.warning) + f.write (header) + + for cmds in gencom.allCommandsList: + defineProcHookStub(cmds, f) + gencom.clang_on(f, 0) + f.write ('\n') + + f.write ('const ProcHook g_proc_hooks[] = {\n') + gencom.clang_off(f, 1) + sortedCommandsList = sorted(gencom.allCommandsList) + for cmds in sortedCommandsList: + if isIntercepted(cmds): + if gencom.isGloballyDispatched(cmds): + defineGlobalProcHook(cmds, f) + elif gencom.isInstanceDispatched(cmds): + defineInstanceProcHook(cmds, f) + elif gencom.isDeviceDispatched(cmds): + defineDeviceProcHook(cmds, f) + gencom.clang_on(f, 1) + f.write ('};\n\n} // namespace\n\n') + + f.write ("""const ProcHook* GetProcHook(const char* name) { + const auto& begin = g_proc_hooks; + const auto& end = + g_proc_hooks + sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]); + const auto hook = std::lower_bound( + begin, end, name, + [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; }); + return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr; +}\n\n""") + + f.write ('ProcHook::Extension GetProcHookExtension(const char* name) {\n') + gencom.clang_off(f, 1) + for exts in knownExtensions: + f.write (gencom.clang_off_spaces + 'if (strcmp(name, \"' + exts + '\") == 0) return ProcHook::' + exts[3:] + ';\n') + gencom.clang_on(f, 1) + f.write (gencom.clang_off_spaces + 'return ProcHook::EXTENSION_UNKNOWN;\n') + f.write ('}\n\n') + + defineInitProc('driver', f) + defineInitProcExt(f) + + f.write ("""bool InitDriverTable(VkInstance instance, + PFN_vkGetInstanceProcAddr get_proc, + const std::bitset& extensions) { + auto& data = GetData(instance); + bool success = true;\n\n""") + gencom.clang_off(f, 1) + for cmds in gencom.allCommandsList: + if isInstanceDriverTableEntry(cmds): + gencom.initProc(cmds, f) + gencom.clang_on(f, 1) + f.write ('\n' + gencom.clang_off_spaces + 'return success;\n') + f.write ('}\n\n') + + f.write ("""bool InitDriverTable(VkDevice dev, + PFN_vkGetDeviceProcAddr get_proc, + const std::bitset& extensions) { + auto& data = GetData(dev); + bool success = true;\n\n""") + gencom.clang_off(f, 1) + for cmds in gencom.allCommandsList: + if isDeviceDriverTableEntry(cmds): + gencom.initProc(cmds, f) + gencom.clang_on(f, 1) + f.write ('\n' + gencom.clang_off_spaces + 'return success;\n') + f.write ('}\n\n} // namespace driver\n} // namespace vulkan\n\n') + gencom.clang_on(f, 0) + diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py index 313357d288..51ad6f5d01 100644 --- a/vulkan/scripts/generator_common.py +++ b/vulkan/scripts/generator_common.py @@ -61,7 +61,11 @@ blacklistedExtensions = [ 'VK_NV_win32_keyed_mutex', 'VK_EXT_metal_surface', #not present in vulkan.api 'VK_NVX_image_view_handle', #not present in vulkan.api - 'VK_NV_cooperative_matrix' #not present in vulkan.api + 'VK_NV_cooperative_matrix', #not present in vulkan.api + 'VK_EXT_headless_surface', #not present in vulkan.api + 'VK_GGP_stream_descriptor_surface', #not present in vulkan.api + 'VK_NV_coverage_reduction_mode', #not present in vulkan.api + 'VK_EXT_full_screen_exclusive' #not present in vulkan.api ] exportedExtensions = [ @@ -71,6 +75,11 @@ exportedExtensions = [ 'VK_ANDROID_external_memory_android_hardware_buffer' ] +def isExtensionInternal(extensionName): + if extensionName == 'VK_ANDROID_native_buffer': + return True + return False + def isFunctionSupported(functionName): if functionName not in extensionsDict: return True @@ -167,6 +176,7 @@ def parseVulkanRegistry(): aliasDict[fnName] = alias allCommandsList.append(fnName) paramDict[fnName] = paramDict[alias].copy() + returnTypeDict[fnName] = returnTypeDict[alias] for params in command: if(params.tag == 'param'): paramtype = "" @@ -208,6 +218,19 @@ def parseVulkanRegistry(): if apiversion != "": versionDict[commandname] = apiversion + # TODO(adsrini): http://b/136570819 + extensionsDict['vkGetSwapchainGrallocUsage2ANDROID'] = 'VK_ANDROID_native_buffer' + allCommandsList.append('vkGetSwapchainGrallocUsage2ANDROID') + returnTypeDict['vkGetSwapchainGrallocUsage2ANDROID'] = 'VkResult' + paramDict['vkGetSwapchainGrallocUsage2ANDROID'] = [ + ('VkDevice ', 'device', None), + ('VkFormat ', 'format', None), + ('VkImageUsageFlags', 'imageUsage', None), + ('VkSwapchainImageUsageFlagsANDROID ', 'swapchainImageUsage', None), + ('u64* ', 'grallocConsumerUsage', None), + ('u64* ', 'grallocProducerUsage', None) + ] + for feature in root.iter('feature'): apiversion = feature.get('name') for req in feature: @@ -226,6 +249,8 @@ def initProc(name, f): if name in versionDict and versionDict[name] == 'VK_VERSION_1_1': f.write('false, ') + elif name == 'vkGetSwapchainGrallocUsageANDROID' or name == 'vkGetSwapchainGrallocUsage2ANDROID': # optional in vulkan.api + f.write('false, ') else: f.write('true, ') -- GitLab From 331130563b9b4ef6424a36bd7b284a5b33f313e7 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Wed, 10 Jul 2019 16:49:11 -0700 Subject: [PATCH 0068/1255] Vulkan: make framework gen script executable Also adds the .gitignore file to ignore the auto generated .pyc files. Bug: 134711355 Test: build, flash and boot. Change-Id: I68621c4af73c422c9f42c92822fc4a1daf89a451 --- .gitignore | 1 + vulkan/scripts/code_generator.py | 0 2 files changed, 1 insertion(+) create mode 100644 .gitignore mode change 100644 => 100755 vulkan/scripts/code_generator.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..0d20b6487c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/vulkan/scripts/code_generator.py b/vulkan/scripts/code_generator.py old mode 100644 new mode 100755 -- GitLab From 261614e00d042b23611c2ef64bcafcbe7c5993e6 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 10 Jul 2019 17:53:12 -0700 Subject: [PATCH 0069/1255] SurfaceFlinger: use isDisplayConfigAllowed in dumpVSync() Simplify the logic to dump the allowed display configs. Test: adb shell dumpsys SurfaceFlinger Change-Id: Id0c5f86779fc434f316c9da63e0118e2fc7de458 --- services/surfaceflinger/SurfaceFlinger.cpp | 10 ++++------ services/surfaceflinger/SurfaceFlinger.h | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6ebfc0d55d..47c17d0e51 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1477,7 +1477,7 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } -bool SurfaceFlinger::isDisplayConfigAllowed(int32_t configId) { +bool SurfaceFlinger::isDisplayConfigAllowed(int32_t configId) const { return mAllowedDisplayConfigs.empty() || mAllowedDisplayConfigs.count(configId); } @@ -4710,11 +4710,9 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { StringAppendF(&result, "+ Smart 90 for video detection: %s\n\n", mUseSmart90ForVideo ? "on" : "off"); StringAppendF(&result, "Allowed Display Configs: "); - for (int32_t configId : mAllowedDisplayConfigs) { - for (auto refresh : mRefreshRateConfigs.getRefreshRates()) { - if (refresh.second && refresh.second->configId == configId) { - StringAppendF(&result, "%dHz, ", refresh.second->fps); - } + for (auto refresh : mRefreshRateConfigs.getRefreshRates()) { + if (refresh.second && isDisplayConfigAllowed(refresh.second->configId)) { + StringAppendF(&result, "%dHz, ", refresh.second->fps); } } StringAppendF(&result, "(config override by backdoor: %s)\n\n", diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f7b7410296..fa801afff8 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -813,7 +813,7 @@ private: // the desired refresh rate. void setRefreshRateTo(RefreshRateType, Scheduler::ConfigEvent event) REQUIRES(mStateLock); - bool isDisplayConfigAllowed(int32_t configId) REQUIRES(mStateLock); + bool isDisplayConfigAllowed(int32_t configId) const REQUIRES(mStateLock); /* * Display identification -- GitLab From 21da0ffff1424d2792564e785c981d3978c6450e Mon Sep 17 00:00:00 2001 From: Atif Niyaz Date: Fri, 28 Jun 2019 13:22:51 -0700 Subject: [PATCH 0070/1255] Remove handling of EV_MSC/MSC_TIMESTAMP in Input MSC_TIMESTAMP is not being utilized anymore to report timestamps from drivers. MSC_TIMESTAMP and all other utilizations of it are removed. Bug: 119840121 Test: No crashes happening after building and running on flame Change-Id: I4d9bec3d763bee3583c351b4240f145a21711e33 --- .../inputflinger/InputClassifierConverter.cpp | 2 +- services/inputflinger/InputListener.cpp | 12 +- services/inputflinger/InputReader.cpp | 188 ++++++++---------- services/inputflinger/InputReader.h | 9 - services/inputflinger/include/InputListener.h | 11 +- .../tests/InputClassifierConverter_test.cpp | 6 +- .../tests/InputClassifier_test.cpp | 6 +- .../tests/InputDispatcher_test.cpp | 4 +- .../inputflinger/tests/InputReader_test.cpp | 63 ------ 9 files changed, 94 insertions(+), 207 deletions(-) diff --git a/services/inputflinger/InputClassifierConverter.cpp b/services/inputflinger/InputClassifierConverter.cpp index f82c8ef1fd..fc8c7c39f9 100644 --- a/services/inputflinger/InputClassifierConverter.cpp +++ b/services/inputflinger/InputClassifierConverter.cpp @@ -358,6 +358,7 @@ common::V1_0::MotionEvent notifyMotionArgsToHalMotionEvent(const NotifyMotionArg event.displayId = args.displayId; event.downTime = args.downTime; event.eventTime = args.eventTime; + event.deviceTimestamp = 0; event.action = getAction(args.action & AMOTION_EVENT_ACTION_MASK); event.actionIndex = getActionIndex(args.action); event.actionButton = getActionButton(args.actionButton); @@ -375,7 +376,6 @@ common::V1_0::MotionEvent notifyMotionArgsToHalMotionEvent(const NotifyMotionArg event.pointerProperties = pointerProperties; event.pointerCoords = pointerCoords; - event.deviceTimestamp = args.deviceTimestamp; event.frames = convertVideoFrames(args.videoFrames); return event; diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp index 0498e87732..de639772a8 100644 --- a/services/inputflinger/InputListener.cpp +++ b/services/inputflinger/InputListener.cpp @@ -92,10 +92,10 @@ NotifyMotionArgs::NotifyMotionArgs( uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification, - int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, - nsecs_t downTime, const std::vector& videoFrames) + int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords, float xPrecision, float yPrecision, + float xCursorPosition, float yCursorPosition, nsecs_t downTime, + const std::vector& videoFrames) : NotifyArgs(sequenceNum, eventTime), deviceId(deviceId), source(source), @@ -108,7 +108,6 @@ NotifyMotionArgs::NotifyMotionArgs( buttonState(buttonState), classification(classification), edgeFlags(edgeFlags), - deviceTimestamp(deviceTimestamp), pointerCount(pointerCount), xPrecision(xPrecision), yPrecision(yPrecision), @@ -135,7 +134,6 @@ NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) buttonState(other.buttonState), classification(other.classification), edgeFlags(other.edgeFlags), - deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount), xPrecision(other.xPrecision), yPrecision(other.yPrecision), @@ -159,7 +157,7 @@ bool NotifyMotionArgs::operator==(const NotifyMotionArgs& rhs) const { policyFlags == rhs.policyFlags && action == rhs.action && actionButton == rhs.actionButton && flags == rhs.flags && metaState == rhs.metaState && buttonState == rhs.buttonState && classification == rhs.classification && - edgeFlags == rhs.edgeFlags && deviceTimestamp == rhs.deviceTimestamp && + edgeFlags == rhs.edgeFlags && pointerCount == rhs.pointerCount // PointerProperties and PointerCoords are compared separately below && xPrecision == rhs.xPrecision && yPrecision == rhs.yPrecision && diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index 9e5990964c..b4c6b3326c 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -1731,10 +1731,12 @@ void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) { // --- MultiTouchMotionAccumulator --- -MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : - mCurrentSlot(-1), mSlots(nullptr), mSlotCount(0), mUsingSlotsProtocol(false), - mHaveStylus(false), mDeviceTimestamp(0) { -} +MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() + : mCurrentSlot(-1), + mSlots(nullptr), + mSlotCount(0), + mUsingSlotsProtocol(false), + mHaveStylus(false) {} MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { delete[] mSlots; @@ -1774,7 +1776,6 @@ void MultiTouchMotionAccumulator::reset(InputDevice* device) { } else { clearSlots(-1); } - mDeviceTimestamp = 0; } void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { @@ -1868,8 +1869,6 @@ void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { // MultiTouch Sync: The driver has returned all data for *one* of the pointers. mCurrentSlot += 1; - } else if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) { - mDeviceTimestamp = rawEvent->value; } } @@ -2849,8 +2848,7 @@ void CursorInputMapper::sync(nsecs_t when) { mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, metaState, buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, + AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, /* videoFrames */ {}); @@ -2861,8 +2859,7 @@ void CursorInputMapper::sync(nsecs_t when) { NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); @@ -2876,8 +2873,7 @@ void CursorInputMapper::sync(nsecs_t when) { mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, metaState, buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, + AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, /* videoFrames */ {}); @@ -2893,11 +2889,9 @@ void CursorInputMapper::sync(nsecs_t when) { NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, currentButtonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, + AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, - yCursorPosition, downTime, - /* videoFrames */ {}); + yCursorPosition, downTime, /* videoFrames */ {}); getListener()->notifyMotion(&hoverArgs); } @@ -2910,11 +2904,9 @@ void CursorInputMapper::sync(nsecs_t when) { mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, + AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, - yCursorPosition, downTime, - /* videoFrames */ {}); + yCursorPosition, downTime, /* videoFrames */ {}); getListener()->notifyMotion(&scrollArgs); } } @@ -3057,9 +3049,8 @@ void RotaryEncoderInputMapper::sync(nsecs_t when) { NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, /* buttonState */ 0, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, + &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}); getListener()->notifyMotion(&scrollArgs); } @@ -4781,7 +4772,6 @@ void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) { int32_t buttonState = mCurrentCookedState.buttonState; dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentCookedState.deviceTimestamp, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, @@ -4804,7 +4794,6 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentCookedState.deviceTimestamp, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, @@ -4839,7 +4828,6 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0, - mCurrentCookedState.deviceTimestamp, mLastCookedState.cookedPointerData.pointerProperties, mLastCookedState.cookedPointerData.pointerCoords, mLastCookedState.cookedPointerData.idToIndex, @@ -4854,7 +4842,6 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0, - mCurrentCookedState.deviceTimestamp, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, @@ -4873,7 +4860,6 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, - mCurrentCookedState.deviceTimestamp, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, @@ -4889,7 +4875,6 @@ void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { int32_t metaState = getContext()->getGlobalMetaState(); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastCookedState.buttonState, 0, - mLastCookedState.deviceTimestamp, mLastCookedState.cookedPointerData.pointerProperties, mLastCookedState.cookedPointerData.pointerCoords, mLastCookedState.cookedPointerData.idToIndex, @@ -4906,7 +4891,6 @@ void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFl if (!mSentHoverEnter) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState, mCurrentRawState.buttonState, 0, - mCurrentCookedState.deviceTimestamp, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, @@ -4918,7 +4902,6 @@ void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFl dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0, - mCurrentCookedState.deviceTimestamp, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, @@ -4938,7 +4921,6 @@ void TouchInputMapper::dispatchButtonRelease(nsecs_t when, uint32_t policyFlags) dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, metaState, buttonState, 0, - mCurrentCookedState.deviceTimestamp, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, @@ -4956,7 +4938,6 @@ void TouchInputMapper::dispatchButtonPress(nsecs_t when, uint32_t policyFlags) { buttonState |= actionButton; dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, metaState, buttonState, 0, - mCurrentCookedState.deviceTimestamp, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, @@ -4975,8 +4956,6 @@ void TouchInputMapper::cookPointerData() { uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount; mCurrentCookedState.cookedPointerData.clear(); - mCurrentCookedState.deviceTimestamp = - mCurrentRawState.deviceTimestamp; mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount; mCurrentCookedState.cookedPointerData.hoveringIdBits = mCurrentRawState.rawPointerData.hoveringIdBits; @@ -5368,13 +5347,11 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits); if (!dispatchedGestureIdBits.isEmpty()) { if (cancelPreviousGesture) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - dispatchedGestureIdBits, -1, 0, - 0, mPointerGesture.downTime); + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, + buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, + mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, + mPointerGesture.downTime); dispatchedGestureIdBits.clear(); } else { @@ -5391,7 +5368,6 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, id, @@ -5404,13 +5380,12 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send motion events for all pointers that moved. if (moveNeeded) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - dispatchedGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, + buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + mPointerGesture.currentGestureProperties, + mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, + mPointerGesture.downTime); } // Send motion events for all pointers that went down. @@ -5427,7 +5402,6 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, - /* deviceTimestamp */ 0, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, @@ -5437,13 +5411,12 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send motion events for hover. if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, + buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + mPointerGesture.currentGestureProperties, + mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, -1, 0, 0, mPointerGesture.downTime); } else if (dispatchedGestureIdBits.isEmpty() && !mPointerGesture.lastGestureIdBits.isEmpty()) { // Synthesize a hover move event after all pointers go up to indicate that @@ -5467,9 +5440,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0, - x, y, mPointerGesture.downTime, /* videoFrames */ {}); + AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, + 0, 0, x, y, mPointerGesture.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -5496,13 +5468,11 @@ void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) if (!mPointerGesture.lastGestureIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mCurrentRawState.buttonState; - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - mPointerGesture.lastGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, + buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, + mPointerGesture.lastGestureIdToIndex, mPointerGesture.lastGestureIdBits, -1, + 0, 0, mPointerGesture.downTime); } // Reset the current pointer gesture. @@ -6395,10 +6365,10 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, - yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); + AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties, + &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, + xCursorPosition, yCursorPosition, mPointerSimple.downTime, + /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6409,10 +6379,10 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, - yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); + AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties, + &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, + xCursorPosition, yCursorPosition, mPointerSimple.downTime, + /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6425,11 +6395,10 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties, - &mPointerSimple.currentCoords, mOrientedXPrecision, - mOrientedYPrecision, xCursorPosition, yCursorPosition, - mPointerSimple.downTime, /* videoFrames */ {}); + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, + &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, + yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6437,10 +6406,10 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, - yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); + AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties, + &mPointerSimple.currentCoords, mOrientedXPrecision, + mOrientedYPrecision, xCursorPosition, yCursorPosition, + mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6452,11 +6421,10 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState, mCurrentRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties, - &mPointerSimple.currentCoords, mOrientedXPrecision, - mOrientedYPrecision, xCursorPosition, yCursorPosition, - mPointerSimple.downTime, /* videoFrames */ {}); + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, + &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, + yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6464,10 +6432,10 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, - yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); + AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties, + &mPointerSimple.currentCoords, mOrientedXPrecision, + mOrientedYPrecision, xCursorPosition, yCursorPosition, + mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6486,10 +6454,10 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - &mPointerSimple.currentProperties, &pointerCoords, - mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, - yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); + AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties, + &pointerCoords, mOrientedXPrecision, mOrientedYPrecision, + xCursorPosition, yCursorPosition, mPointerSimple.downTime, + /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6510,11 +6478,12 @@ void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { } void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t actionButton, int32_t flags, - int32_t metaState, int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp, - const PointerProperties* properties, const PointerCoords* coords, - const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, - float xPrecision, float yPrecision, nsecs_t downTime) { + int32_t action, int32_t actionButton, int32_t flags, + int32_t metaState, int32_t buttonState, int32_t edgeFlags, + const PointerProperties* properties, + const PointerCoords* coords, const uint32_t* idToIndex, + BitSet32 idBits, int32_t changedId, float xPrecision, + float yPrecision, nsecs_t downTime) { PointerCoords pointerCoords[MAX_POINTERS]; PointerProperties pointerProperties[MAX_POINTERS]; uint32_t pointerCount = 0; @@ -6558,9 +6527,9 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32 [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); }); NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId, source, displayId, policyFlags, action, actionButton, flags, metaState, buttonState, - MotionClassification::NONE, edgeFlags, deviceTimestamp, pointerCount, - pointerProperties, pointerCoords, xPrecision, yPrecision, xCursorPosition, - yCursorPosition, downTime, std::move(frames)); + MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties, + pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition, + downTime, std::move(frames)); getListener()->notifyMotion(&args); } @@ -7043,7 +7012,6 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { outCount += 1; } - outState->deviceTimestamp = mMultiTouchMotionAccumulator.getDeviceTimestamp(); outState->rawPointerData.pointerCount = outCount; mPointerIdBits = newPointerIdBits; @@ -7484,8 +7452,8 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, + &pointerProperties, &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}); getListener()->notifyMotion(&args); diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index 9777779e7d..0c08e7da38 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -717,7 +717,6 @@ public: inline size_t getSlotCount() const { return mSlotCount; } inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } - inline uint32_t getDeviceTimestamp() const { return mDeviceTimestamp; } private: int32_t mCurrentSlot; @@ -725,7 +724,6 @@ private: size_t mSlotCount; bool mUsingSlotsProtocol; bool mHaveStylus; - uint32_t mDeviceTimestamp; void clearSlots(int32_t initialSlot); }; @@ -1174,7 +1172,6 @@ protected: struct RawState { nsecs_t when; - uint32_t deviceTimestamp; // Raw pointer sample data. RawPointerData rawPointerData; @@ -1187,7 +1184,6 @@ protected: void copyFrom(const RawState& other) { when = other.when; - deviceTimestamp = other.deviceTimestamp; rawPointerData.copyFrom(other.rawPointerData); buttonState = other.buttonState; rawVScroll = other.rawVScroll; @@ -1196,7 +1192,6 @@ protected: void clear() { when = 0; - deviceTimestamp = 0; rawPointerData.clear(); buttonState = 0; rawVScroll = 0; @@ -1205,7 +1200,6 @@ protected: }; struct CookedState { - uint32_t deviceTimestamp; // Cooked pointer sample data. CookedPointerData cookedPointerData; @@ -1217,7 +1211,6 @@ protected: int32_t buttonState; void copyFrom(const CookedState& other) { - deviceTimestamp = other.deviceTimestamp; cookedPointerData.copyFrom(other.cookedPointerData); fingerIdBits = other.fingerIdBits; stylusIdBits = other.stylusIdBits; @@ -1226,7 +1219,6 @@ protected: } void clear() { - deviceTimestamp = 0; cookedPointerData.clear(); fingerIdBits.clear(); stylusIdBits.clear(); @@ -1634,7 +1626,6 @@ private: void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, - uint32_t deviceTimestamp, const PointerProperties* properties, const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h index 57c894bf8b..0dcd2f9c38 100644 --- a/services/inputflinger/include/InputListener.h +++ b/services/inputflinger/include/InputListener.h @@ -107,13 +107,7 @@ struct NotifyMotionArgs : public NotifyArgs { */ MotionClassification classification; int32_t edgeFlags; - /** - * A timestamp in the input device's time base, not the platform's. - * The units are microseconds since the last reset. - * This can only be compared to other device timestamps from the same device. - * This value will overflow after a little over an hour. - */ - uint32_t deviceTimestamp; + uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; @@ -134,8 +128,7 @@ struct NotifyMotionArgs : public NotifyArgs { NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, - MotionClassification classification, int32_t edgeFlags, - uint32_t deviceTimestamp, uint32_t pointerCount, + MotionClassification classification, int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, diff --git a/services/inputflinger/tests/InputClassifierConverter_test.cpp b/services/inputflinger/tests/InputClassifierConverter_test.cpp index ba1c7c9284..f58b6281df 100644 --- a/services/inputflinger/tests/InputClassifierConverter_test.cpp +++ b/services/inputflinger/tests/InputClassifierConverter_test.cpp @@ -42,9 +42,9 @@ static NotifyMotionArgs generateBasicMotionArgs() { AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4 /*policyFlags*/, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, 0 /*flags*/, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, 5 /*deviceTimestamp*/, - 1 /*pointerCount*/, &properties, &coords, 0 /*xPrecision*/, - 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_EDGE_FLAG_NONE, 1 /*pointerCount*/, &properties, + &coords, 0 /*xPrecision*/, 0 /*yPrecision*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, {} /*videoFrames*/); return motionArgs; diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp index 9bc4282d9c..40086ef708 100644 --- a/services/inputflinger/tests/InputClassifier_test.cpp +++ b/services/inputflinger/tests/InputClassifier_test.cpp @@ -42,9 +42,9 @@ static NotifyMotionArgs generateBasicMotionArgs() { AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4 /*policyFlags*/, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, 0 /*flags*/, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, 5 /*deviceTimestamp*/, - 1 /*pointerCount*/, &properties, &coords, 0 /*xPrecision*/, - 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_EDGE_FLAG_NONE, 1 /*pointerCount*/, &properties, + &coords, 0 /*xPrecision*/, 0 /*yPrecision*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, {} /*videoFrames*/); return motionArgs; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index c28a6214d6..a86dcbc552 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -608,8 +608,8 @@ static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32 NotifyMotionArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, source, displayId, POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - pointerProperties, pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0, + AMOTION_EVENT_EDGE_FLAG_NONE, 1, pointerProperties, pointerCoords, + /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /* videoFrames */ {}); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index d35302885d..e10883485a 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -4688,7 +4688,6 @@ protected: void processSlot(MultiTouchInputMapper* mapper, int32_t slot); void processToolType(MultiTouchInputMapper* mapper, int32_t toolType); void processKey(MultiTouchInputMapper* mapper, int32_t code, int32_t value); - void processTimestamp(MultiTouchInputMapper* mapper, uint32_t value); void processMTSync(MultiTouchInputMapper* mapper); void processSync(MultiTouchInputMapper* mapper); }; @@ -4804,10 +4803,6 @@ void MultiTouchInputMapperTest::processKey( process(mapper, ARBITRARY_TIME, EV_KEY, code, value); } -void MultiTouchInputMapperTest::processTimestamp(MultiTouchInputMapper* mapper, uint32_t value) { - process(mapper, ARBITRARY_TIME, EV_MSC, MSC_TIMESTAMP, value); -} - void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper* mapper) { process(mapper, ARBITRARY_TIME, EV_SYN, SYN_MT_REPORT, 0); } @@ -6190,64 +6185,6 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTPressureIsPresent_HoversIfIts toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } -TEST_F(MultiTouchInputMapperTest, Process_HandlesTimestamp) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION); - addMapperAndConfigure(mapper); - NotifyMotionArgs args; - - // By default, deviceTimestamp should be zero - processPosition(mapper, 100, 100); - processMTSync(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(0U, args.deviceTimestamp); - - // Now the timestamp of 1000 is reported by evdev and should appear in MotionArgs - processPosition(mapper, 0, 0); - processTimestamp(mapper, 1000); - processMTSync(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(1000U, args.deviceTimestamp); -} - -TEST_F(MultiTouchInputMapperTest, WhenMapperIsReset_TimestampIsCleared) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); - - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION); - addMapperAndConfigure(mapper); - NotifyMotionArgs args; - - // Send a touch event with a timestamp - processPosition(mapper, 100, 100); - processTimestamp(mapper, 1); - processMTSync(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(1U, args.deviceTimestamp); - - // Since the data accumulates, and new timestamp has not arrived, deviceTimestamp won't change - processPosition(mapper, 100, 200); - processMTSync(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(1U, args.deviceTimestamp); - - mapper->reset(/* when */ 0); - // After the mapper is reset, deviceTimestamp should become zero again - processPosition(mapper, 100, 300); - processMTSync(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(0U, args.deviceTimestamp); -} - /** * Set the input device port <--> display port associations, and check that the * events are routed to the display that matches the display port. -- GitLab From 6a9b16ef3aa63a220e2e4519a0db3138a7c12340 Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan Date: Wed, 10 Jul 2019 17:49:49 -0700 Subject: [PATCH 0071/1255] Generate Vulkan framework from Vulkan registry (Part 3) Instead of using the manually created vulkan.api file for generating the Vulkan driver framework, we generate it directly from the vulkan registry (vk.xml) Bug: 134711355 Test: Build and flash, dEQP tests Change-Id: I2fc3bc03489bd47c2239eb083c988157979fd674 --- vulkan/scripts/code_generator.py | 3 + vulkan/scripts/generator_common.py | 12 +-- vulkan/scripts/null_generator.py | 154 +++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 6 deletions(-) create mode 100644 vulkan/scripts/null_generator.py diff --git a/vulkan/scripts/code_generator.py b/vulkan/scripts/code_generator.py index 9e14b2886a..39fedf4777 100644 --- a/vulkan/scripts/code_generator.py +++ b/vulkan/scripts/code_generator.py @@ -20,6 +20,7 @@ import generator_common as gencom import api_generator as apigen import driver_generator as drivergen +import null_generator as nullgen if __name__ == '__main__': gencom.parseVulkanRegistry() @@ -27,3 +28,5 @@ if __name__ == '__main__': apigen.api_gencpp() drivergen.driver_genh() drivergen.driver_gencpp() + nullgen.null_driver_genh() + nullgen.null_driver_gencpp() diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py index 51ad6f5d01..163fba3462 100644 --- a/vulkan/scripts/generator_common.py +++ b/vulkan/scripts/generator_common.py @@ -223,12 +223,12 @@ def parseVulkanRegistry(): allCommandsList.append('vkGetSwapchainGrallocUsage2ANDROID') returnTypeDict['vkGetSwapchainGrallocUsage2ANDROID'] = 'VkResult' paramDict['vkGetSwapchainGrallocUsage2ANDROID'] = [ - ('VkDevice ', 'device', None), - ('VkFormat ', 'format', None), - ('VkImageUsageFlags', 'imageUsage', None), - ('VkSwapchainImageUsageFlagsANDROID ', 'swapchainImageUsage', None), - ('u64* ', 'grallocConsumerUsage', None), - ('u64* ', 'grallocProducerUsage', None) + ('VkDevice ', 'device'), + ('VkFormat ', 'format'), + ('VkImageUsageFlags ', 'imageUsage'), + ('VkSwapchainImageUsageFlagsANDROID ', 'swapchainImageUsage'), + ('uint64_t* ', 'grallocConsumerUsage'), + ('uint64_t* ', 'grallocProducerUsage') ] for feature in root.iter('feature'): diff --git a/vulkan/scripts/null_generator.py b/vulkan/scripts/null_generator.py new file mode 100644 index 0000000000..fcbaf393a5 --- /dev/null +++ b/vulkan/scripts/null_generator.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +# +# 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. +# +# This script provides the functions for generating the null driver +# framework directly from the vulkan registry (vk.xml). + +import generator_common as gencom +import os + +copyright = """/* + * Copyright 2015 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. + */ + +""" + +def isDriverExtension(extensionName): + switchCase = { + 'VK_ANDROID_native_buffer' : True, + 'VK_EXT_debug_report' : True, + 'VK_KHR_get_physical_device_properties2' : True + } + + if extensionName in switchCase: + return switchCase[extensionName] + return False + +def isDriverFunction(functionName): + if functionName in gencom.extensionsDict: + return isDriverExtension(gencom.extensionsDict[functionName]) + return True + +def null_driver_genh(): + header = """#ifndef NULLDRV_NULL_DRIVER_H +#define NULLDRV_NULL_DRIVER_H 1 + +#include +#include + +namespace null_driver { + +PFN_vkVoidFunction GetGlobalProcAddr(const char* name); +PFN_vkVoidFunction GetInstanceProcAddr(const char* name); + +""" + genfile = os.path.join(os.path.dirname(__file__),'..','nulldrv','null_driver_gen2.h') + with open(genfile, 'w') as f: + f.write (copyright) + f.write (gencom.warning) + f.write (header) + gencom.clang_off(f,0) + + for cmds in gencom.allCommandsList: + if isDriverFunction(cmds): + paramList = [''.join(i) for i in gencom.paramDict[cmds]] + f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' +', '.join(paramList) + ');\n') + f.write ("""VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage); +VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence); +VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);\n""") + gencom.clang_on(f,0) + + f.write ('\n} // namespace null_driver\n') + f.write ('\n#endif // NULLDRV_NULL_DRIVER_H\n') + +def null_driver_gencpp(): + header = """#include + +#include "null_driver_gen.h" + +using namespace null_driver; + +namespace { + +struct NameProc { + const char* name; + PFN_vkVoidFunction proc; +}; + +PFN_vkVoidFunction Lookup(const char* name, + const NameProc* begin, + const NameProc* end) { + const auto& entry = std::lower_bound( + begin, end, name, + [](const NameProc& e, const char* n) { return strcmp(e.name, n) < 0; }); + if (entry == end || strcmp(entry->name, name) != 0) + return nullptr; + return entry->proc; +} + +template +PFN_vkVoidFunction Lookup(const char* name, const NameProc (&procs)[N]) { + return Lookup(name, procs, procs + N); +} + +const NameProc kGlobalProcs[] = { +""" + genfile = os.path.join(os.path.dirname(__file__),'..','nulldrv','null_driver_gen2.cpp') + with open(genfile, 'w') as f: + f.write (copyright) + f.write (gencom.warning) + f.write (header) + gencom.clang_off(f,1) + + sortedCommandsList = sorted(gencom.allCommandsList) + for cmds in sortedCommandsList: + if isDriverFunction(cmds) and gencom.getDispatchTableType(cmds) == 'Global': + f.write (gencom.clang_off_spaces + '{\"' + cmds + '\", reinterpret_cast(static_cast(' + cmds[2:] + '))},\n') + gencom.clang_on(f,1) + f.write ('};\n\n') + + f.write ('const NameProc kInstanceProcs[] = {\n') + gencom.clang_off(f,1) + for cmds in sortedCommandsList: + if isDriverFunction(cmds): + f.write (gencom.clang_off_spaces + '{\"' + cmds + '\", reinterpret_cast(static_cast(' + cmds[2:] + '))},\n') + gencom.clang_on(f,1) + f.write ('};\n\n} // namespace\n\n') + + f.write ("""namespace null_driver { + +PFN_vkVoidFunction GetGlobalProcAddr(const char* name) { + return Lookup(name, kGlobalProcs); +} + +PFN_vkVoidFunction GetInstanceProcAddr(const char* name) { + return Lookup(name, kInstanceProcs); +} + +} // namespace null_driver\n""") + -- GitLab From ab0ab9c57c8fa9d8c9648734fea74ee010e28e8c Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Wed, 10 Jul 2019 18:58:28 -0700 Subject: [PATCH 0072/1255] Address comments from a previous change. The original change is 00f511d329924824b1961e9472c3a06683fc2216. Bug: 134788085 Test: atest libinput_tests Change-Id: I1f3326067f94fe6a09850f4389483e60fa57a8d4 --- include/input/Input.h | 3 +++ libs/input/Input.cpp | 3 +-- libs/input/tests/InputEvent_test.cpp | 10 +++++++--- services/inputflinger/InputDispatcher.cpp | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index a97624658c..ad8c233577 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -476,6 +477,8 @@ public: float getYCursorPosition() const; + static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } + inline nsecs_t getDownTime() const { return mDownTime; } inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 3266b0740d..dc4978b836 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "Input" //#define LOG_NDEBUG 0 -#include #include #include @@ -434,7 +433,7 @@ void MotionEvent::transform(const float matrix[9]) { transformPoint(matrix, 0, 0, &originX, &originY); // Apply the transformation to cursor position. - if (!isnan(mXCursorPosition) && !isnan(mYCursorPosition)) { + if (isValidCursorPosition(mXCursorPosition, mYCursorPosition)) { float x = mXCursorPosition + oldXOffset; float y = mYCursorPosition + oldYOffset; transformPoint(matrix, x, y, &x, &y); diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index ec34f3e652..b879de6a74 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -603,9 +603,13 @@ TEST_F(MotionEventTest, Transform) { ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1); } - // Check cursor positions. - ASSERT_NEAR(sinf(PI_180 * (90 + ROTATION)) * RADIUS, event.getXCursorPosition(), 0.001); - ASSERT_NEAR(-cosf(PI_180 * (90 + ROTATION)) * RADIUS, event.getYCursorPosition(), 0.001); + // Check cursor positions. The original cursor position is at (3 + RADIUS, 2), where the center + // of the circle is (3, 2), so the cursor position is to the right of the center of the circle. + // The choice of triangular functions in this test defines the angle of rotation clockwise + // relative to the y-axis. Therefore the cursor position's angle is 90 degrees. Here we swap the + // triangular function so that we don't have to add the 90 degrees. + ASSERT_NEAR(cosf(PI_180 * ROTATION) * RADIUS, event.getXCursorPosition(), 0.001); + ASSERT_NEAR(sinf(PI_180 * ROTATION) * RADIUS, event.getYCursorPosition(), 0.001); // Applying the transformation should preserve the raw X and Y of the first point. ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001); diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index be1370747c..1d8c365702 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -2766,7 +2766,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { ", policyFlags=0x%x, " "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, " "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, " - "mYCursorPosition=%f, downTime=%" PRId64, + "yCursorPosition=%f, downTime=%" PRId64, args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, args->action, args->actionButton, args->flags, args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, arg->xCursorPosition, -- GitLab From c5ae0dc56d828a85b8b609ca29923e58dea3b807 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 10 Jul 2019 15:51:18 -0700 Subject: [PATCH 0073/1255] Improve input devices changed logs Currently, "reconfiguring input devices" log is hard to read, because it dumps the values as hex. That means, the reader has to go into code to understand what the actual changes are. Furthermore, if the defines are added/removed/modified between releases, it's even harder to debug. To improve this, convert to the actual values before printing. This will also help confirm that these are only ever invoked with a single change. Maybe we can change to enum class then. Bug: 137212522 Test: adb logcat | grep -i "input devices" Change-Id: I6b40d1c785df8a57c9e2619210906d326844d69d Before: InputReader: Reconfiguring input devices. changes=0x00000010 After: InputReader: Reconfiguring input devices, changes=KEYBOARD_LAYOUTS | --- services/inputflinger/InputReader.cpp | 3 +- services/inputflinger/InputReaderBase.cpp | 38 +++++++++++++++++++ .../inputflinger/include/InputReaderBase.h | 2 + 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index b4c6b3326c..eee49d5e2a 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -559,7 +559,8 @@ void InputReader::refreshConfigurationLocked(uint32_t changes) { mEventHub->setExcludedDevices(mConfig.excludedDeviceNames); if (changes) { - ALOGI("Reconfiguring input devices. changes=0x%08x", changes); + ALOGI("Reconfiguring input devices, changes=%s", + InputReaderConfiguration::changesToString(changes).c_str()); nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) { diff --git a/services/inputflinger/InputReaderBase.cpp b/services/inputflinger/InputReaderBase.cpp index f48a64551e..bc53cf52cc 100644 --- a/services/inputflinger/InputReaderBase.cpp +++ b/services/inputflinger/InputReaderBase.cpp @@ -49,6 +49,44 @@ bool InputReaderThread::threadLoop() { // --- InputReaderConfiguration --- +std::string InputReaderConfiguration::changesToString(uint32_t changes) { + if (changes == 0) { + return ""; + } + std::string result; + if (changes & CHANGE_POINTER_SPEED) { + result += "POINTER_SPEED | "; + } + if (changes & CHANGE_POINTER_GESTURE_ENABLEMENT) { + result += "POINTER_GESTURE_ENABLEMENT | "; + } + if (changes & CHANGE_DISPLAY_INFO) { + result += "DISPLAY_INFO | "; + } + if (changes & CHANGE_SHOW_TOUCHES) { + result += "SHOW_TOUCHES | "; + } + if (changes & CHANGE_KEYBOARD_LAYOUTS) { + result += "KEYBOARD_LAYOUTS | "; + } + if (changes & CHANGE_DEVICE_ALIAS) { + result += "DEVICE_ALIAS | "; + } + if (changes & CHANGE_TOUCH_AFFINE_TRANSFORMATION) { + result += "TOUCH_AFFINE_TRANSFORMATION | "; + } + if (changes & CHANGE_EXTERNAL_STYLUS_PRESENCE) { + result += "EXTERNAL_STYLUS_PRESENCE | "; + } + if (changes & CHANGE_ENABLED_STATE) { + result += "ENABLED_STATE | "; + } + if (changes & CHANGE_MUST_REOPEN) { + result += "MUST_REOPEN | "; + } + return result; +} + std::optional InputReaderConfiguration::getDisplayViewportByUniqueId( const std::string& uniqueDisplayId) const { if (uniqueDisplayId.empty()) { diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 8ad5dd0785..c7720cbf59 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -270,6 +270,8 @@ struct InputReaderConfiguration { pointerGestureZoomSpeedRatio(0.3f), showTouches(false), pointerCapture(false) { } + static std::string changesToString(uint32_t changes); + std::optional getDisplayViewportByType(ViewportType type) const; std::optional getDisplayViewportByUniqueId(const std::string& uniqueDisplayId) const; -- GitLab From a03f0debad92921ba52d33e7e06f0064703e85ad Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 10 Jul 2019 15:54:34 -0700 Subject: [PATCH 0074/1255] Use std::set instead of SortedVector We only care whether a certain input device is present in a list or not. For that, we can just use an std::set and not have to use custom SortedVector data structure. This makes it easier for someone already familiar with c++ but not necessarily Android to follow the code. It also ensures that the data structure is properly maintained going forward. Bug: 137212522 Test: atest libinput_tests inputflinger_tests Change-Id: I7808b41524ae0b87dbf1aaf7a49afa64b14b3eb9 --- services/inputflinger/InputReader.cpp | 4 ++-- services/inputflinger/include/InputReaderBase.h | 6 +++--- services/inputflinger/tests/InputReader_test.cpp | 16 ++-------------- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index eee49d5e2a..2de5ffa0eb 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -1094,8 +1094,8 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config } if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) { - ssize_t index = config->disabledDevices.indexOf(mId); - bool enabled = index < 0; + auto it = config->disabledDevices.find(mId); + bool enabled = it == config->disabledDevices.end(); setEnabled(enabled, when); } diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index c7720cbf59..271051499c 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -27,11 +27,11 @@ #include #include #include -#include -#include #include #include +#include +#include #include #include @@ -250,7 +250,7 @@ struct InputReaderConfiguration { bool pointerCapture; // The set of currently disabled input devices. - SortedVector disabledDevices; + std::set disabledDevices; InputReaderConfiguration() : virtualKeyQuietTime(0), diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index e10883485a..541de99623 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -202,21 +202,9 @@ public: mConfig.portAssociations.insert({inputPort, displayPort}); } - void addDisabledDevice(int32_t deviceId) { - ssize_t index = mConfig.disabledDevices.indexOf(deviceId); - bool currentlyEnabled = index < 0; - if (currentlyEnabled) { - mConfig.disabledDevices.add(deviceId); - } - } + void addDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.insert(deviceId); } - void removeDisabledDevice(int32_t deviceId) { - ssize_t index = mConfig.disabledDevices.indexOf(deviceId); - bool currentlyEnabled = index < 0; - if (!currentlyEnabled) { - mConfig.disabledDevices.remove(deviceId); - } - } + void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); } void setPointerController(int32_t deviceId, const sp& controller) { mPointerControllers.add(deviceId, controller); -- GitLab From 6fd1c77faa58db2bc607da2fc5a19e5d3aa59734 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 10 Jul 2019 16:52:31 -0700 Subject: [PATCH 0075/1255] Remove unused include The include is no longer needed. Bug: none Test: none Change-Id: I4eb97f3423a93d51c8fb4f7067dccdf28cce8434 --- services/inputflinger/include/InputReaderBase.h | 1 - 1 file changed, 1 deletion(-) diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 271051499c..5d576b94f3 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -24,7 +24,6 @@ #include #include #include -#include #include #include -- GitLab From 8dce9d78e7aedd614cec867a8dbcd9d9e2f3ea1c Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan Date: Thu, 11 Jul 2019 14:26:04 -0700 Subject: [PATCH 0076/1255] Generate Vulkan framework from Vulkan registry (Part 4) Instead of using the manually created vulkan.api file for generating the Vulkan driver framework, we generate it directly from the vulkan registry (vk.xml) Bug: 134711355 Test: Build and flash, dEQP tests Change-Id: Ie38d93c51ff16d2108cbe9a9a717a0bea24947df --- vulkan/README.md | 17 +- vulkan/api/platform.api | 61 - vulkan/api/templates/vulkan_common.tmpl | 223 - vulkan/api/vulkan.api | 12163 ---------------------- vulkan/libvulkan/api_gen.cpp | 420 +- vulkan/libvulkan/api_gen.h | 46 +- vulkan/libvulkan/code-generator.tmpl | 1197 --- vulkan/libvulkan/driver_gen.cpp | 52 +- vulkan/libvulkan/driver_gen.h | 8 +- vulkan/nulldrv/null_driver.tmpl | 211 - vulkan/nulldrv/null_driver_gen.cpp | 4 +- vulkan/nulldrv/null_driver_gen.h | 56 +- vulkan/scripts/api_generator.py | 8 +- vulkan/scripts/driver_generator.py | 9 +- vulkan/scripts/generator_common.py | 6 + vulkan/scripts/null_generator.py | 8 +- 16 files changed, 319 insertions(+), 14170 deletions(-) delete mode 100644 vulkan/api/platform.api delete mode 100644 vulkan/api/templates/vulkan_common.tmpl delete mode 100644 vulkan/api/vulkan.api delete mode 100644 vulkan/libvulkan/code-generator.tmpl delete mode 100644 vulkan/nulldrv/null_driver.tmpl diff --git a/vulkan/README.md b/vulkan/README.md index 9fba7281fd..0f660977f9 100644 --- a/vulkan/README.md +++ b/vulkan/README.md @@ -10,19 +10,8 @@ Use "clang-format -style=file" to format all C/C++ code, except code imported ve ## Code Generation -We generate several parts of the loader and tools from a Vulkan API description file, stored in `api/vulkan.api`. Code generation must be done manually because the generator tools aren't part of the platform toolchain (yet?). Files named `foo_gen.*` are generated from the API file and a template file named `foo.tmpl`. +We generate several parts of the loader and tools driectly from the Vulkan Registry (external/vulkan-headers/registry/vk.xml). Code generation must be done manually because the generator is not part of the platform toolchain (yet?). Files named `foo_gen.*` are generated by the code generator. To run the generator: - -### One-time setup -- Install [golang](https://golang.org/), if you don't have it already. -- Create a directory (e.g. `$HOME/lib/go`) for local go sources and binaries and add it to `$GOPATH`. -- `$ git clone https://android.googlesource.com/platform/tools/gpu $GOPATH/src/android.googlesource.com/platform/tools/gpu` -- `$ go get android.googlesource.com/platform/tools/gpu/api/...` -- You should now have `$GOPATH/bin/apic`. You might want to add `$GOPATH/bin` to your `$PATH`. - -### Generating code -To generate `libvulkan/*_gen.*`, -- `$ cd libvulkan` -- `$ apic template ../api/vulkan.api code-generator.tmpl` -Similar for `nulldrv/null_driver_gen.*`. +- Install Python3 (if not already installed) +- `$ .//frameworks/native/vulkan/scripts/code_generator.py` diff --git a/vulkan/api/platform.api b/vulkan/api/platform.api deleted file mode 100644 index a7c4c30b5e..0000000000 --- a/vulkan/api/platform.api +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2015 The Khronos Group Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and/or associated documentation files (the -// "Materials"), to deal in the Materials without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Materials, and to -// permit persons to whom the Materials are furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Materials. -// -// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - -// Platform types, as defined or included in vk_platform.h - -type u64 size_t - -// VK_USE_PLATFORM_XLIB_KHR -@internal class Display {} -@internal class Window {} -@internal type u64 VisualID - -// VK_USE_PLATFORM_XCB_KHR -@internal class xcb_connection_t {} -@internal type u32 xcb_window_t -@internal type u32 xcb_visualid_t - -// VK_USE_PLATFORM_WAYLAND_KHR -@internal class wl_display {} -@internal class wl_surface {} - -// VK_USE_PLATFORM_MIR_KHR -@internal class MirConnection {} -@internal class MirSurface {} - -// VK_USE_PLATFORM_ANDROID_KHR -@internal class ANativeWindow {} -@internal class AHardwareBuffer {} -@internal type void* buffer_handle_t - -// VK_USE_PLATFORM_WIN32_KHR -@internal type void* HINSTANCE -@internal type void* HWND -@internal type void* HANDLE -@internal type u32 DWORD -@internal type u16* LPCWSTR -@internal class SECURITY_ATTRIBUTES {} - -// VK_USE_PLATFORM_XLIB_XRANDR_EXT -@internal type u64 RROutput - -// VK_USE_PLATFORM_FUCHSIA -@internal type u32 zx_handle_t \ No newline at end of file diff --git a/vulkan/api/templates/vulkan_common.tmpl b/vulkan/api/templates/vulkan_common.tmpl deleted file mode 100644 index f694c56238..0000000000 --- a/vulkan/api/templates/vulkan_common.tmpl +++ /dev/null @@ -1,223 +0,0 @@ -{{$clang_style := "{BasedOnStyle: Google, AccessModifierOffset: -4, ColumnLimit: 200, ContinuationIndentWidth: 8, IndentWidth: 4, AlignOperands: true, CommentPragmas: '.*'}"}} -{{Global "clang-format" (Strings "clang-format" "-style" $clang_style)}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C translation for the specified type. -------------------------------------------------------------------------------- -*/}} -{{define "Type.Class" }}{{if GetAnnotation $.Type "internal"}}struct {{end}}{{Macro "StructName" $.Type}}{{end}} -{{define "Type.Pseudonym" }}{{$.Type.Name}}{{end}} -{{define "Type.Enum" }}{{$.Type.Name}}{{end}} -{{define "Type.StaticArray"}}{{Node "Type" $.Type.ValueType}}{{end}} -{{define "Type.Pointer" }}{{if $.Type.Const}}{{Node "ConstType" $.Type.To}}{{else}}{{Node "Type" $.Type.To}}{{end}}*{{end}} -{{define "Type.Slice" }}{{Log "%T %+v" $.Node $.Node}}{{Node "Type" $.Type.To}}*{{end}} -{{define "Type#bool" }}bool{{end}} -{{define "Type#int" }}int{{end}} -{{define "Type#uint" }}unsigned int{{end}} -{{define "Type#s8" }}int8_t{{end}} -{{define "Type#u8" }}uint8_t{{end}} -{{define "Type#s16" }}int16_t{{end}} -{{define "Type#u16" }}uint16_t{{end}} -{{define "Type#s32" }}int32_t{{end}} -{{define "Type#u32" }}uint32_t{{end}} -{{define "Type#f32" }}float{{end}} -{{define "Type#s64" }}int64_t{{end}} -{{define "Type#u64" }}uint64_t{{end}} -{{define "Type#f64" }}double{{end}} -{{define "Type#void" }}void{{end}} -{{define "Type#char" }}char{{end}} - -{{define "ConstType_Default"}}const {{Node "Type" $.Type}}{{end}} -{{define "ConstType.Pointer"}}{{Node "Type" $.Type}} const{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C translation for the specified documentation block (string array). -------------------------------------------------------------------------------- -*/}} -{{define "Docs"}} - {{if $}}// {{$ | JoinWith "\n// "}}{{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the name of a bitfield entry. -------------------------------------------------------------------------------- -*/}} -{{define "BitfieldEntryName"}} - {{AssertType $ "EnumEntry"}} - - {{Macro "EnumEntry" $}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the name of an enum type. -------------------------------------------------------------------------------- -*/}} -{{define "EnumName"}}{{AssertType $ "Enum"}}{{$.Name}}{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the name of an enum entry. -------------------------------------------------------------------------------- -*/}} -{{define "EnumEntry"}} - {{AssertType $.Owner "Enum"}} - {{AssertType $.Name "string"}} - - {{$.Name}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the name of the first entry of an enum. -------------------------------------------------------------------------------- -*/}} -{{define "EnumFirstEntry"}} - {{AssertType $ "Enum"}} - - {{range $i, $e := $.Entries}} - {{if not $i}}{{$e.Name}}{{end}} - {{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the name of the last entry of an enum. -------------------------------------------------------------------------------- -*/}}{{define "EnumLastEntry"}} - {{AssertType $ "Enum"}} - - {{range $i, $e := $.Entries}} - {{if not (HasMore $i $.Entries)}}{{$e.Name}}{{end}} - {{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the name of a struct (class) type. -------------------------------------------------------------------------------- -*/}} -{{define "StructName"}}{{AssertType $ "Class"}}{{$.Name}}{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the name of a function. -------------------------------------------------------------------------------- -*/}} -{{define "FunctionName"}}{{AssertType $ "Function"}}{{$.Name}}{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the fixed-size-array postfix for pseudonym types annotated with @array -------------------------------------------------------------------------------- -*/}} -{{define "ArrayPostfix"}}{{Node "ArrayPostfix" $}}{{end}} -{{define "ArrayPostfix.StaticArray"}}[{{$.Type.Size}}]{{end}} -{{define "ArrayPostfix_Default"}}{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits a C type and name for the given parameter -------------------------------------------------------------------------------- -*/}} -{{define "Parameter"}} - {{AssertType $ "Parameter"}} - - {{if GetAnnotation $ "readonly"}}const {{end}}{{Macro "ParameterType" $}} {{$.Name}}{{Macro "ArrayPostfix" $}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits a C name for the given parameter -------------------------------------------------------------------------------- -*/}} -{{define "ParameterName"}} - {{AssertType $ "Parameter"}} - - {{$.Name}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits a C type for the given parameter -------------------------------------------------------------------------------- -*/}} -{{define "ParameterType"}}{{AssertType $ "Parameter"}}{{Node "Type" $}}{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits a comma-separated list of C type-name paired parameters for the given - command. -------------------------------------------------------------------------------- -*/}} -{{define "Parameters"}} - {{AssertType $ "Function"}} - - {{ForEach $.CallParameters "Parameter" | JoinWith ", "}} - {{if not $.CallParameters}}void{{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C function pointer name for the specified command. -------------------------------------------------------------------------------- -*/}} -{{define "FunctionPtrName"}} - {{AssertType $ "Function"}} - - PFN_{{$.Name}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Parses const variables as text Globals. -------------------------------------------------------------------------------- -*/}} -{{define "DefineGlobals"}} - {{AssertType $ "API"}} - - {{range $d := $.Definitions}} - {{Global $d.Name $d.Expression}} - {{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Given a function, return "Global", "Instance", or "Device" depending on which - dispatch table the function belongs to. -------------------------------------------------------------------------------- -*/}} -{{define "Vtbl#VkInstance" }}Instance{{end}} -{{define "Vtbl#VkPhysicalDevice"}}Instance{{end}} -{{define "Vtbl#VkDevice" }}Device{{end}} -{{define "Vtbl#VkQueue" }}Device{{end}} -{{define "Vtbl#VkCommandBuffer" }}Device{{end}} -{{define "Vtbl_Default" }}Global{{end}} -{{define "Vtbl"}} - {{AssertType $ "Function"}} - - {{if gt (len $.CallParameters) 0}} - {{Node "Vtbl" (index $.CallParameters 0)}} - {{else}}Global - {{end}} -{{end}} diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api deleted file mode 100644 index 76503c8c17..0000000000 --- a/vulkan/api/vulkan.api +++ /dev/null @@ -1,12163 +0,0 @@ -// Copyright (c) 2015 The Khronos Group Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and/or associated documentation files (the -// "Materials"), to deal in the Materials without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Materials, and to -// permit persons to whom the Materials are furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Materials. -// -// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. - -import platform "platform.api" - -/////////////// -// Constants // -/////////////// - -// API version (major.minor.patch) -define VERSION_MAJOR 1 -define VERSION_MINOR 1 -define VERSION_PATCH 96 - -// API limits -define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 -define VK_UUID_SIZE 16 -define VK_MAX_EXTENSION_NAME_SIZE 256 -define VK_MAX_DESCRIPTION_SIZE 256 -define VK_MAX_MEMORY_TYPES 32 -define VK_MAX_MEMORY_HEAPS 16 /// The maximum number of unique memory heaps, each of which supporting 1 or more memory types. -@vulkan1_1 -define VK_MAX_DEVICE_GROUP_SIZE 32 -@vulkan1_1 -define VK_LUID_SIZE 8 -@vulkan1_1 -define VK_QUEUE_FAMILY_EXTERNAL -2 -@extension("VK_EXT_queue_family_foreign") -define VK_QUEUE_FAMILY_FOREIGN_EXT -3 -@extension("VK_MAX_DRIVER_NAME_SIZE_KHR") // 197 -define VK_MAX_DRIVER_NAME_SIZE_KHR 256 -@extension("VK_MAX_DRIVER_NAME_SIZE_KHR") // 197 -define VK_MAX_DRIVER_INFO_SIZE_KHR 256 - -// API keywords -define VK_TRUE 1 -define VK_FALSE 0 - -// API keyword, but needs special handling by some templates -define NULL_HANDLE 0 - -// 1 -@extension("VK_KHR_surface") define VK_KHR_SURFACE_SPEC_VERSION 25 -@extension("VK_KHR_surface") define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" - -// 2 -@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_SPEC_VERSION 70 -@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" - -// 3 -@extension("VK_KHR_display") define VK_KHR_DISPLAY_SPEC_VERSION 21 -@extension("VK_KHR_display") define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display" - -// 4 -@extension("VK_KHR_display_swapchain") define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9 -@extension("VK_KHR_display_swapchain") define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain" - -// 5 -@extension("VK_KHR_xlib_surface") define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6 -@extension("VK_KHR_xlib_surface") define VK_KHR_XLIB_SURFACE_NAME "VK_KHR_xlib_surface" - -// 6 -@extension("VK_KHR_xcb_surface") define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 -@extension("VK_KHR_xcb_surface") define VK_KHR_XCB_SURFACE_NAME "VK_KHR_xcb_surface" - -// 7 -@extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6 -@extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_NAME "VK_KHR_wayland_surface" - -// 8 - VK_KHR_mir_surface removed - -// 9 -@extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 -@extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_NAME "VK_KHR_android_surface" - -// 10 -@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6 -@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_NAME "VK_KHR_win32_surface" - -// 11 -@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 8 -@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME "VK_ANDROID_native_buffer" - -// 12 -@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 9 -@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME "VK_EXT_debug_report" - -// 13 -@extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_SPEC_VERSION 1 -@extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_NAME "VK_NV_glsl_shader" - -// 14 -@extension("VK_EXT_depth_range_unrestricted") define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION 1 -@extension("VK_EXT_depth_range_unrestricted") define VK_EXT_DEPTH_RANGE_UNRESTRICTED_NAME "VK_EXT_depth_range_unrestricted" - -// 15 -@extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1 -@extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_NAME "VK_KHR_sampler_mirror_clamp_to_edge" - -// 16 -@extension("VK_IMG_filter_cubic") define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 -@extension("VK_IMG_filter_cubic") define VK_IMG_FILTER_CUBIC_NAME "VK_IMG_filter_cubic" - -// 19 -@extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1 -@extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_NAME "VK_AMD_rasterization_order" - -// 21 -@extension("VK_AMD_shader_trinary_minmax") define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1 -@extension("VK_AMD_shader_trinary_minmax") define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax" - -// 22 -@extension("VK_AMD_shader_explicit_vertex_parameter") define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1 -@extension("VK_AMD_shader_explicit_vertex_parameter") define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter" - -// 23 -@extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_SPEC_VERSION 4 -@extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_NAME "VK_EXT_debug_marker" - -// 26 -@extension("VK_AMD_gcn_shader") define VK_AMD_GCN_SHADER_SPEC_VERSION 1 -@extension("VK_AMD_gcn_shader") define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader" - -// 27 -@extension("VK_NV_dedicated_allocation") define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1 -@extension("VK_NV_dedicated_allocation") define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation" - -// 28 -@extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 -@extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" - -// 29 -@extension("VK_EXT_transform_feedback") define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1 -@extension("VK_EXT_transform_feedback") define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback" - -// 34 -@extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 -@extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count" - -// 36 -@extension("VK_AMD_negative_viewport_height") define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1 -@extension("VK_AMD_negative_viewport_height") define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height" - -// 37 -@extension("VK_AMD_gpu_shader_half_float") define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 1 -@extension("VK_AMD_gpu_shader_half_float") define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float" - -// 38 -@extension("VK_AMD_shader_ballot") define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1 -@extension("VK_AMD_shader_ballot") define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot" - -// 42 -@extension("VK_AMD_texture_gather_bias_lod") define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1 -@extension("VK_AMD_texture_gather_bias_lod") define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod" - -// 43 -@extension("VK_AMD_shader_info") define VK_AMD_SHADER_INFO_SPEC_VERSION 1 -@extension("VK_AMD_shader_info") define VK_AMD_SHADER_INFO_EXTENSION_NAME "VK_AMD_shader_info" - -// 47 -@extension("VK_AMD_shader_image_load_store_lod") define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_SPEC_VERSION 1 -@extension("VK_AMD_shader_image_load_store_lod") define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME "VK_AMD_shader_image_load_store_lod" - -// 51 -@extension("VK_NV_corner_sampled_image") define VK_NV_CORNER_SAMPLED_IMAGE_SPEC_VERSION 2 -@extension("VK_NV_corner_sampled_image") define VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME "VK_NV_corner_sampled_image" - -// 54 -@extension("VK_KHR_multiview") define VK_KHR_MULTIVIEW_SPEC_VERSION 1 -@extension("VK_KHR_multiview") define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview" - -// 56 -@extension("VK_NV_external_memory_capabilities") define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 -@extension("VK_NV_external_memory_capabilities") define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities" - -// 57 -@extension("VK_NV_external_memory") define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1 -@extension("VK_NV_external_memory") define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory" - -// 58 -@extension("VK_NV_external_memory_win32") define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 -@extension("VK_NV_external_memory_win32") define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32" - -// 59 -@extension("VK_NV_win32_keyed_mutex") define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 1 -@extension("VK_NV_win32_keyed_mutex") define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex" - -// 60 -@extension("VK_KHR_get_physical_device_properties2") define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1 -@extension("VK_KHR_get_physical_device_properties2") define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2" - -// 61 -@extension("VK_KHR_device_group") define VK_KHR_DEVICE_GROUP_SPEC_VERSION 3 -@extension("VK_KHR_device_group") define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group" - -// 62 -@extension("VK_EXT_validation_flags") define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1 -@extension("VK_EXT_validation_flags") define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags" - -// 63 -@extension("VK_NN_vi_surface") define VK_NN_VI_SURFACE_SPEC_VERSION 1 -@extension("VK_NN_vi_surface") define VK_NN_VI_SURFACE_EXTENSION_NAME "VK_NN_vi_surface" - -// 64 -@extension("VK_KHR_shader_draw_parameters") define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1 -@extension("VK_KHR_shader_draw_parameters") define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters" - -// 65 -@extension("VK_EXT_shader_subgroup_ballot") define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1 -@extension("VK_EXT_shader_subgroup_ballot") define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot" - -// 66 -@extension("VK_EXT_shader_subgroup_vote") define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1 -@extension("VK_EXT_shader_subgroup_vote") define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote" - -// 68 -@extension("VK_EXT_astc_decode_mode") define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1 -@extension("VK_EXT_astc_decode_mode") define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode" - -// 70 -@extension("VK_KHR_maintenance1") define VK_KHR_MAINTENANCE1_SPEC_VERSION 2 -@extension("VK_KHR_maintenance1") define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1" - -// 71 -@extension("VK_KHR_device_group_creation") define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1 -@extension("VK_KHR_device_group_creation") define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation" - -// 72 -@extension("VK_KHR_external_memory_capabilities") define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 -@extension("VK_KHR_external_memory_capabilities") define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities" - -// 73 -@extension("VK_KHR_external_memory") define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1 -@extension("VK_KHR_external_memory") define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHR_external_memory" - -// 74 -@extension("VK_KHR_external_memory_win32") define VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 -@extension("VK_KHR_external_memory_win32") define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32" - -// 75 -@extension("VK_KHR_external_memory_fd") define VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION 1 -@extension("VK_KHR_external_memory_fd") define VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHR_external_memory_fd" - -// 76 -@extension("VK_KHR_win32_keyed_mutex") define VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION 1 -@extension("VK_KHR_win32_keyed_mutex") define VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHR_win32_keyed_mutex" - -// 77 -@extension("VK_KHR_external_semaphore_capabilities") define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1 -@extension("VK_KHR_external_semaphore_capabilities") define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities" - -// 78 -@extension("VK_KHR_external_semaphore") define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 -@extension("VK_KHR_external_semaphore") define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHR_external_semaphore" - -// 79 -@extension("VK_KHR_external_semaphore_win32") define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1 -@extension("VK_KHR_external_semaphore_win32") define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHR_external_semaphore_win32" - -// 80 -@extension("VK_KHR_external_semaphore_fd") define VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1 -@extension("VK_KHR_external_semaphore_fd") define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd" - -// 81 -@extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2 -@extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor" - -// 82 -@extension("VK_EXT_conditional_rendering") define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 1 -@extension("VK_EXT_conditional_rendering") define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering" - -// 83 -@extension("VK_KHR_shader_float16_int8") define VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION 1 -@extension("VK_KHR_shader_float16_int8") define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME "VK_KHR_shader_float16_int8" - -// 84 -@extension("VK_KHR_16bit_storage") define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1 -@extension("VK_KHR_16bit_storage") define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage" - -// 85 -@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1 -@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present" - -// 86 -@extension("VK_KHR_descriptor_update_template") define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1 -@extension("VK_KHR_descriptor_update_template") define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template" - -// 87 -@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3 -@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands" - -// 88 -@extension("VK_NV_clip_space_w_scaling") define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1 -@extension("VK_NV_clip_space_w_scaling") define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling" - -// 89 -@extension("VK_EXT_direct_mode_display") define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1 -@extension("VK_EXT_direct_mode_display") define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display" - -// 90 -@extension("VK_EXT_acquire_xlib_display") define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1 -@extension("VK_EXT_acquire_xlib_display") define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display" - -// 91 -@extension("VK_EXT_display_surface_counter") define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1 -@extension("VK_EXT_display_surface_counter") define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter" - -// 92 -@extension("VK_EXT_display_control") define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1 -@extension("VK_EXT_display_control") define VK_EXT_DISPLAY_CONTROL_COUNTER_EXTENSION_NAME "VK_EXT_display_control" - -// 93 -@extension("VK_GOOGLE_display_timing") define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1 -@extension("VK_GOOGLE_display_timing") define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME "VK_GOOGLE_display_timing" - -// 95 -@extension("VK_NV_sample_mask_override_coverage") define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1 -@extension("VK_NV_sample_mask_override_coverage") define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage" - -// 96 -@extension("VK_NV_geometry_shader_passthrough") define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1 -@extension("VK_NV_geometry_shader_passthrough") define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough" - -// 97 -@extension("VK_NV_viewport_array2") define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION 1 -@extension("VK_NV_viewport_array2") define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME "VK_NV_viewport_array2" - -// 98 -@extension("VK_NVX_multiview_per_view_attributes") define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1 -@extension("VK_NVX_multiview_per_view_attributes") define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME "VK_NVX_multiview_per_view_attributes" - -// 99 -@extension("VK_NV_viewport_swizzle") define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1 -@extension("VK_NV_viewport_swizzle") define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle" - -// 100 -@extension("VK_EXT_discard_rectangles") define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1 -@extension("VK_EXT_discard_rectangles") define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles" - -// 102 -@extension("VK_EXT_conservative_rasterization") define VK_EXT_CONSERVATIVE_RASTERIZATION_SPEC_VERSION 1 -@extension("VK_EXT_conservative_rasterization") define VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME "VK_EXT_conservative_rasterization" - -// 105 -@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_SPEC_VERSION 3 -@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" - -// 106 -@extension("VK_EXT_hdr_metadata") define VK_EXT_HDR_METADATA_SPEC_VERSION 1 -@extension("VK_EXT_hdr_metadata") define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata" - -// 110 -@extension("VK_KHR_create_renderpass2") define VK_KHR_CREATE_RENDERPASS2_SPEC_VERSION 1 -@extension("VK_KHR_create_renderpass2") define VK_KHR_CREATE_RENDERPASS2_EXTENSION_NAME "VK_KHR_create_renderpass2" - -// 112 -@extension("VK_KHR_shared_presentable_image") define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1 -@extension("VK_KHR_shared_presentable_image") define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image" - -// 113 -@extension("VK_KHR_external_fence_capabilities") define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1 -@extension("VK_KHR_external_fence_capabilities") define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities" - -// 114 -@extension("VK_KHR_external_fence") define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1 -@extension("VK_KHR_external_fence") define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence" - -// 115 -@extension("VK_KHR_external_fence_win32") define VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION 1 -@extension("VK_KHR_external_fence_win32") define VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME "VK_KHR_external_fence_win32" - -// 116 -@extension("VK_KHR_external_fence_fd") define VK_KHR_EXTERNAL_FENCE_FD_SPEC_VERSION 1 -@extension("VK_KHR_external_fence_fd") define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME "VK_KHR_external_fence_fd" - -// 118 -@extension("VK_KHR_maintenance2") define VK_KHR_MAINTENANCE2_SPEC_VERSION 1 -@extension("VK_KHR_maintenance2") define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2" - -// 120 -@extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1 -@extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2" - -// 121 -@extension("VK_KHR_variable_pointers") define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1 -@extension("VK_KHR_variable_pointers") define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers" - -// 122 -@extension("VK_KHR_get_display_properties2") define VK_KHR_GET_DISPLAY_PROPERTIES_2_SPEC_VERSION 1 -@extension("VK_KHR_get_display_properties2") define VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_display_properties2" - -// 123 -@extension("VK_MVK_ios_surface") define VK_MVK_IOS_SURFACE_SPEC_VERSION 1 -@extension("VK_MVK_ios_surface") define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface" - -// 124 -@extension("VK_MVK_macos_surface") define VK_MVK_MACOS_SURFACE_SPEC_VERSION 1 -@extension("VK_MVK_macos_surface") define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface" - -// 126 -@extension("VK_EXT_external_memory_dma_buf") define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_SPEC_VERSION 1 -@extension("VK_EXT_external_memory_dma_buf") define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME "VK_EXT_external_memory_dma_buf" - -// 127 -@extension("VK_EXT_queue_family_foreign") define VK_EXT_QUEUE_FAMILY_FOREIGN_SPEC_VERSION 1 -@extension("VK_EXT_queue_family_foreign") define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME "VK_EXT_queue_family_foreign" - -// 128 -@extension("VK_KHR_dedicated_allocation") define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3 -@extension("VK_KHR_dedicated_allocation") define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation" - -// 128 -@extension("VK_EXT_debug_utils") define VK_EXT_DEBUG_UTILS_SPEC_VERSION 1 -@extension("VK_EXT_debug_utils") define VK_EXT_DEBUG_UTILS_EXTENSION_NAME "VK_EXT_debug_utils" - -// 130 -@extension("VK_ANDROID_external_memory_android_hardware_buffer") define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 3 -@extension("VK_ANDROID_external_memory_android_hardware_buffer") define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer" - -// 131 -@extension("VK_EXT_sampler_filter_minmax") define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 1 -@extension("VK_EXT_sampler_filter_minmax") define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax" - -// 132 -@extension("VK_KHR_storage_buffer_storage_class") define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION 1 -@extension("VK_KHR_storage_buffer_storage_class") define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME "VK_KHR_storage_buffer_storage_class" - -// 133 -@extension("VK_AMD_gpu_shader_int16") define VK_AMD_GPU_SHADER_INT16_SPEC_VERSION 1 -@extension("VK_AMD_gpu_shader_int16") define VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME "VK_AMD_gpu_shader_int16" - -// 137 -@extension("VK_AMD_mixed_attachment_samples") define VK_AMD_MIXED_ATTACHMENT_SAMPLES_SPEC_VERSION 1 -@extension("VK_AMD_mixed_attachment_samples") define VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME "VK_AMD_mixed_attachment_samples" - -// 138 -@extension("VK_AMD_shader_fragment_mask") define VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION 1 -@extension("VK_AMD_shader_fragment_mask") define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask" - -// 139 -@extension("VK_EXT_inline_uniform_block") define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1 -@extension("VK_EXT_inline_uniform_block") define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block" - -// 141 -@extension("VK_EXT_shader_stencil_export") define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1 -@extension("VK_EXT_shader_stencil_export") define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export" - -// 144 -@extension("VK_EXT_sample_locations") define VK_EXT_SAMPLE_LOCATIONS_SPEC_VERSION 1 -@extension("VK_EXT_sample_locations") define VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME "VK_EXT_sample_locations" - -// 145 -@extension("VK_KHR_relaxed_block_layout") define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1 -@extension("VK_KHR_relaxed_block_layout") define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout" - -// 147 -@extension("VK_KHR_get_memory_requirements2") define VK_KHR_GET_MEMORY_REQUIREMENTS2_SPEC_VERSION 1 -@extension("VK_KHR_get_memory_requirements2") define VK_KHR_GET_MEMORY_REQUIREMENTS2_EXTENSION_NAME "VK_KHR_get_memory_requirements2" - -// 148 -@extension("VK_KHR_image_format_list") define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1 -@extension("VK_KHR_image_format_list") define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list" - -// 149 -@extension("VK_EXT_blend_operation_advanced") define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2 -@extension("VK_EXT_blend_operation_advanced") define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced" - -// 150 -@extension("VK_NV_fragment_coverage_to_color") define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1 -@extension("VK_NV_fragment_coverage_to_color") define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME "VK_NV_fragment_coverage_to_color" - -// 153 -@extension("VK_NV_framebuffer_mixed_samples") define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1 -@extension("VK_NV_framebuffer_mixed_samples") define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples" - -// 154 -@extension("VK_NV_fill_rectangle") define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1 -@extension("VK_NV_fill_rectangle") define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle" - -// 156 -@extension("VK_EXT_post_depth_coverage") define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1 -@extension("VK_EXT_post_depth_coverage") define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage" - -// 157 -@extension("VK_KHR_sampler_ycbcr_conversion") define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 1 -@extension("VK_KHR_sampler_ycbcr_conversion") define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion" - -// 158 -@extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_SPEC_VERSION 1 -@extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_EXTENSION_NAME "VK_KHR_bind_memory2" - -// 159 -@extension("VK_EXT_image_drm_format_modifier") define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1 -@extension("VK_EXT_image_drm_format_modifier") define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier" - -// 161 -@extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1 -@extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache" - -// 162 -@extension("VK_EXT_descriptor_indexing") define VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION 2 -@extension("VK_EXT_descriptor_indexing") define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME "VK_EXT_descriptor_indexing" - -// 163 -@extension("VK_EXT_shader_viewport_index_layer") define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1 -@extension("VK_EXT_shader_viewport_index_layer") define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer" - -// 165 -@extension("VK_NV_shading_rate_image") define VK_NV_SHADING_RATE_IMAGE_SPEC_VERSION 3 -@extension("VK_NV_shading_rate_image") define VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME "VK_NV_shading_rate_image" - -// 166 -@extension("VK_NV_ray_tracing") define VK_NV_RAY_TRACING_SPEC_VERSION 3 -@extension("VK_NV_ray_tracing") define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing" - -// 167 -@extension("VK_NV_representative_fragment_test") define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 1 -@extension("VK_NV_representative_fragment_test") define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME "VK_NV_representative_fragment_test" - -// 169 -@extension("VK_KHR_maintenance3") define VK_KHR_MAINTENANCE3_SPEC_VERSION 1 -@extension("VK_KHR_maintenance3") define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3" - -// 170 -@extension("VK_KHR_draw_indirect_count") define VK_KHR_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 -@extension("VK_KHR_draw_indirect_count") define VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_KHR_draw_indirect_count" - -// 175 -@extension("VK_EXT_global_priority") define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 1 -@extension("VK_EXT_global_priority") define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority" - -// 178 -@extension("VK_KHR_8bit_storage") define VK_KHR_8BIT_STORAGE_SPEC_VERSION 1 -@extension("VK_KHR_8bit_storage") define VK_KHR_8BIT_STORAGE_EXTENSION_NAME "VK_KHR_8bit_storage" - -// 179 -@extension("VK_EXT_external_memory_host") define VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION 1 -@extension("VK_EXT_external_memory_host") define VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME "VK_EXT_external_memory_host" - -// 180 -@extension("VK_AMD_buffer_marker") define VK_AMD_BUFFER_MARKER_SPEC_VERSION 1 -@extension("VK_AMD_buffer_marker") define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_AMD_buffer_marker" - -// 181 -@extension("VK_KHR_shader_atomic_int64") define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1 -@extension("VK_KHR_shader_atomic_int64") define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64" - -// 186 -@extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1 -@extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties" - -// 190 -@extension("VK_AMD_memory_overallocation_behavior") define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1 -@extension("VK_AMD_memory_overallocation_behavior") define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior" - -// 191 -@extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2 -@extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor" - -// 197 -@extension("VK_KHR_driver_properties") define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1 -@extension("VK_KHR_driver_properties") define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties" - -// 198 -@extension("VK_KHR_shader_float_controls") define VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION 1 -@extension("VK_KHR_shader_float_controls") define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME "VK_KHR_shader_float_controls" - -// 199 -@extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1 -@extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned" - -// 201 -@extension("VK_KHR_swapchain_mutable_format") define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION 1 -@extension("VK_KHR_swapchain_mutable_format") define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME "VK_KHR_swapchain_mutable_format" - -// 202 -@extension("VK_NV_compute_shader_derivatives") define VK_NV_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION 1 -@extension("VK_NV_compute_shader_derivatives") define VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME "VK_NV_compute_shader_derivatives" - -// 203 -@extension("VK_NV_mesh_shader") define VK_NV_MESH_SHADER_SPEC_VERSION 1 -@extension("VK_NV_mesh_shader") define VK_NV_MESH_SHADER_EXTENSION_NAME "VK_NV_mesh_shader" - -// 204 -@extension("VK_NV_fragment_shader_barycentric") define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 -@extension("VK_NV_fragment_shader_barycentric") define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_NV_fragment_shader_barycentric" - -// 205 -@extension("VK_NV_shader_image_footprint") define VK_NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION 1 -@extension("VK_NV_shader_image_footprint") define VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME "VK_NV_shader_image_footprint" - -// 206 -@extension("VK_NV_scissor_exclusive") define VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION 1 -@extension("VK_NV_scissor_exclusive") define VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME "VK_NV_scissor_exclusive" - -// 207 -@extension("VK_NV_device_diagnostic_checkpoints") define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2 -@extension("VK_NV_device_diagnostic_checkpoints") define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints" - -// 212 -@extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2 -@extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model" - -// 213 -@extension("VK_EXT_pci_bus_info") define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 2 -@extension("VK_EXT_pci_bus_info") define VK_EXT_PCI_BUS_INFO_EXENSION_NAME "VK_EXT_pci_bus_info" - -// 215 -@extension("VK_FUCHSIA_imagepipe_surface") define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1 -@extension("VK_FUCHSIA_imagepipe_surface") define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface" - -// 219 -@extension("VK_EXT_fragment_density_map") define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 1 -@extension("VK_EXT_fragment_density_map") define VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME "VK_EXT_fragment_density_map" - -// 222 -@extension("VK_EXT_scalar_block_layout") define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1 -@extension("VK_EXT_scalar_block_layout") define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME "VK_EXT_scalar_block_layout" - -// 224 -@extension("VK_GOOGLE_hlsl_functionality1") define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 1 -@extension("VK_GOOGLE_hlsl_functionality1") define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" - -// 225 -@extension("VK_GOOGLE_decorate_string") define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 1 -@extension("VK_GOOGLE_decorate_string") define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string" - -// 247 -@extension("VK_EXT_separate_stencil_usage") define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1 -@extension("VK_EXT_separate_stencil_usage") define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage" - -///////////// -// Types // -///////////// - -type u32 VkBool32 -type u32 VkFlags -type u64 VkDeviceSize -type u32 VkSampleMask - -/// Dispatchable handle types. -@dispatchHandle type u64 VkInstance -@dispatchHandle type u64 VkPhysicalDevice -@dispatchHandle type u64 VkDevice -@dispatchHandle type u64 VkQueue -@dispatchHandle type u64 VkCommandBuffer - -/// Non dispatchable handle types. -@nonDispatchHandle type u64 VkDeviceMemory -@nonDispatchHandle type u64 VkCommandPool -@nonDispatchHandle type u64 VkBuffer -@nonDispatchHandle type u64 VkBufferView -@nonDispatchHandle type u64 VkImage -@nonDispatchHandle type u64 VkImageView -@nonDispatchHandle type u64 VkShaderModule -@nonDispatchHandle type u64 VkPipeline -@nonDispatchHandle type u64 VkPipelineLayout -@nonDispatchHandle type u64 VkSampler -@nonDispatchHandle type u64 VkDescriptorSet -@nonDispatchHandle type u64 VkDescriptorSetLayout -@nonDispatchHandle type u64 VkDescriptorPool -@nonDispatchHandle type u64 VkFence -@nonDispatchHandle type u64 VkSemaphore -@nonDispatchHandle type u64 VkEvent -@nonDispatchHandle type u64 VkQueryPool -@nonDispatchHandle type u64 VkFramebuffer -@nonDispatchHandle type u64 VkRenderPass -@nonDispatchHandle type u64 VkPipelineCache - -@vulkan1_1 -@nonDispatchHandle type u64 VkSamplerYcbcrConversion -@nonDispatchHandle type u64 VkDescriptorUpdateTemplate - -// 1 -@extension("VK_KHR_surface") @nonDispatchHandle type u64 VkSurfaceKHR - -// 2 -@extension("VK_KHR_swapchain") @nonDispatchHandle type u64 VkSwapchainKHR - -// 3 -@extension("VK_KHR_display") @nonDispatchHandle type u64 VkDisplayKHR -@extension("VK_KHR_display") @nonDispatchHandle type u64 VkDisplayModeKHR - -// 12 -@extension("VK_EXT_debug_report") @nonDispatchHandle type u64 VkDebugReportCallbackEXT - -// 86 -@extension("VK_KHR_descriptor_update_template") @nonDispatchHandle type u64 VkDescriptorUpdateTemplateKHR - -// 87 -@extension("VK_NVX_device_generated_commands") @nonDispatchHandle type u64 VkObjectTableNVX -@extension("VK_NVX_device_generated_commands") @nonDispatchHandle type u64 VkIndirectCommandsLayoutNVX - -// 129 -@extension("VK_EXT_debug_utils") @nonDispatchHandle type u64 VkDebugUtilsMessengerEXT - -// 157 -@extension("VK_KHR_sampler_ycbcr_conversion") @nonDispatchHandle type u64 VkSamplerYcbcrConversionKHR - -// 161 -@extension("VK_EXT_validation_cache") @nonDispatchHandle type u64 VkValidationCacheEXT - -// 166 -@extension("VK_NV_ray_tracing") @nonDispatchHandle type u64 VkAccelerationStructureNV - -///////////// -// Enums // -///////////// - -enum VkImageLayout { - VK_IMAGE_LAYOUT_UNDEFINED = 0x00000000, /// Implicit layout an image is when its contents are undefined due to various reasons (e.g. right after creation) - VK_IMAGE_LAYOUT_GENERAL = 0x00000001, /// General layout when image can be used for any kind of access - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 0x00000002, /// Optimal layout when image is only used for color attachment read/write - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 0x00000003, /// Optimal layout when image is only used for depth/stencil attachment read/write - VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 0x00000004, /// Optimal layout when image is used for read only depth/stencil attachment and shader access - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 0x00000005, /// Optimal layout when image is used for read only shader access - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 0x00000006, /// Optimal layout when image is used only as source of transfer operations - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 0x00000007, /// Optimal layout when image is used only as destination of transfer operations - VK_IMAGE_LAYOUT_PREINITIALIZED = 0x00000008, /// Initial layout used when the data is populated by the CPU - - //@vulkan1_1 - VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000, - VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001, - - //@extension("VK_KHR_swapchain") // 2 - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, - - //@extension("VK_KHR_shared_presentable_image") // 112 - VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000, - - //@extension("VK_KHR_maintenance2") // 118 - VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = 1000117000, - VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = 1000117001, - - //@extension("VK_NV_shading_rate_image") // 165 - VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV = 1000164003, - - //@extension("VK_EXT_fragment_density_map") // 219 - VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT = 1000218000, -} - -enum VkAttachmentLoadOp { - VK_ATTACHMENT_LOAD_OP_LOAD = 0x00000000, - VK_ATTACHMENT_LOAD_OP_CLEAR = 0x00000001, - VK_ATTACHMENT_LOAD_OP_DONT_CARE = 0x00000002, -} - -enum VkAttachmentStoreOp { - VK_ATTACHMENT_STORE_OP_STORE = 0x00000000, - VK_ATTACHMENT_STORE_OP_DONT_CARE = 0x00000001, -} - -enum VkImageType { - VK_IMAGE_TYPE_1D = 0x00000000, - VK_IMAGE_TYPE_2D = 0x00000001, - VK_IMAGE_TYPE_3D = 0x00000002, -} - -enum VkImageTiling { - VK_IMAGE_TILING_OPTIMAL = 0x00000000, - VK_IMAGE_TILING_LINEAR = 0x00000001, - - //@extension("VK_EXT_image_drm_format_modifier") // 159 - VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000, -} - -enum VkImageViewType { - VK_IMAGE_VIEW_TYPE_1D = 0x00000000, - VK_IMAGE_VIEW_TYPE_2D = 0x00000001, - VK_IMAGE_VIEW_TYPE_3D = 0x00000002, - VK_IMAGE_VIEW_TYPE_CUBE = 0x00000003, - VK_IMAGE_VIEW_TYPE_1D_ARRAY = 0x00000004, - VK_IMAGE_VIEW_TYPE_2D_ARRAY = 0x00000005, - VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 0x00000006, -} - -enum VkCommandBufferLevel { - VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0x00000000, - VK_COMMAND_BUFFER_LEVEL_SECONDARY = 0x00000001, -} - -enum VkComponentSwizzle { - VK_COMPONENT_SWIZZLE_IDENTITY = 0x00000000, - VK_COMPONENT_SWIZZLE_ZERO = 0x00000001, - VK_COMPONENT_SWIZZLE_ONE = 0x00000002, - VK_COMPONENT_SWIZZLE_R = 0x00000003, - VK_COMPONENT_SWIZZLE_G = 0x00000004, - VK_COMPONENT_SWIZZLE_B = 0x00000005, - VK_COMPONENT_SWIZZLE_A = 0x00000006, -} - -enum VkDescriptorType { - VK_DESCRIPTOR_TYPE_SAMPLER = 0x00000000, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 0x00000001, - VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 0x00000002, - VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 0x00000003, - VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 0x00000004, - VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 0x00000005, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 0x00000006, - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 0x00000007, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 0x00000008, - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 0x00000009, - VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 0x0000000a, - - //@extension("VK_EXT_inline_uniform_block") // 139 - VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000, - - //@extension("VK_NV_ray_tracing") // 166 - VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, -} - -enum VkQueryType { - VK_QUERY_TYPE_OCCLUSION = 0x00000000, - VK_QUERY_TYPE_PIPELINE_STATISTICS = 0x00000001, /// Optional - VK_QUERY_TYPE_TIMESTAMP = 0x00000002, - - //@extension("VK_EXT_transform_feedback") // 29 - VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004, - - //@extension("VK_NV_ray_tracing") // 166 - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, -} - -enum VkBorderColor { - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0x00000000, - VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 0x00000001, - VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 0x00000002, - VK_BORDER_COLOR_INT_OPAQUE_BLACK = 0x00000003, - VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 0x00000004, - VK_BORDER_COLOR_INT_OPAQUE_WHITE = 0x00000005, -} - -enum VkPipelineBindPoint { - VK_PIPELINE_BIND_POINT_GRAPHICS = 0x00000000, - VK_PIPELINE_BIND_POINT_COMPUTE = 0x00000001, - - //@extension("VK_NV_ray_tracing") // 166 - VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = 1000165000, -} - -enum VkPrimitiveTopology { - VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0x00000000, - VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 0x00000001, - VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 0x00000002, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 0x00000003, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 0x00000004, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 0x00000005, - VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 0x00000006, - VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 0x00000007, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 0x00000008, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 0x00000009, - VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 0x0000000a, -} - -enum VkSharingMode { - VK_SHARING_MODE_EXCLUSIVE = 0x00000000, - VK_SHARING_MODE_CONCURRENT = 0x00000001, -} - -enum VkIndexType { - VK_INDEX_TYPE_UINT16 = 0x00000000, - VK_INDEX_TYPE_UINT32 = 0x00000001, - - //@extension("VK_NV_ray_tracing") // 166 - VK_INDEX_TYPE_NONE_NV = 1000165000, -} - -enum VkFilter { - VK_FILTER_NEAREST = 0x00000000, - VK_FILTER_LINEAR = 0x00000001, - - //@extension("VK_IMG_filter_cubic") // 16 - VK_FILTER_CUBIC_IMG = 1000015000, -} - -enum VkSamplerMipmapMode { - VK_SAMPLER_MIPMAP_MODE_NEAREST = 0x00000001, /// Choose nearest mip level - VK_SAMPLER_MIPMAP_MODE_LINEAR = 0x00000002, /// Linear filter between mip levels -} - -enum VkSamplerAddressMode { - VK_SAMPLER_ADDRESS_MODE_REPEAT = 0x00000000, - VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 0x00000001, - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 0x00000002, - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 0x00000003, - VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 0x00000004, -} - -enum VkCompareOp { - VK_COMPARE_OP_NEVER = 0x00000000, - VK_COMPARE_OP_LESS = 0x00000001, - VK_COMPARE_OP_EQUAL = 0x00000002, - VK_COMPARE_OP_LESS_OR_EQUAL = 0x00000003, - VK_COMPARE_OP_GREATER = 0x00000004, - VK_COMPARE_OP_NOT_EQUAL = 0x00000005, - VK_COMPARE_OP_GREATER_OR_EQUAL = 0x00000006, - VK_COMPARE_OP_ALWAYS = 0x00000007, -} - -enum VkPolygonMode { - VK_POLYGON_MODE_FILL = 0x00000000, - VK_POLYGON_MODE_LINE = 0x00000001, - VK_POLYGON_MODE_POINT = 0x00000002, - - //@extension("VK_NV_fill_rectangle") // 154 - VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000, -} - -enum VkFrontFace { - VK_FRONT_FACE_COUNTER_CLOCKWISE = 0x00000000, - VK_FRONT_FACE_CLOCKWISE = 0x00000001, -} - -enum VkBlendFactor { - VK_BLEND_FACTOR_ZERO = 0x00000000, - VK_BLEND_FACTOR_ONE = 0x00000001, - VK_BLEND_FACTOR_SRC_COLOR = 0x00000002, - VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 0x00000003, - VK_BLEND_FACTOR_DST_COLOR = 0x00000004, - VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 0x00000005, - VK_BLEND_FACTOR_SRC_ALPHA = 0x00000006, - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 0x00000007, - VK_BLEND_FACTOR_DST_ALPHA = 0x00000008, - VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 0x00000009, - VK_BLEND_FACTOR_CONSTANT_COLOR = 0x0000000a, - VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 0x0000000b, - VK_BLEND_FACTOR_CONSTANT_ALPHA = 0x0000000c, - VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 0x0000000d, - VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 0x0000000e, - VK_BLEND_FACTOR_SRC1_COLOR = 0x0000000f, - VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 0x00000010, - VK_BLEND_FACTOR_SRC1_ALPHA = 0x00000011, - VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 0x00000012, -} - -enum VkBlendOp { - VK_BLEND_OP_ADD = 0x00000000, - VK_BLEND_OP_SUBTRACT = 0x00000001, - VK_BLEND_OP_REVERSE_SUBTRACT = 0x00000002, - VK_BLEND_OP_MIN = 0x00000003, - VK_BLEND_OP_MAX = 0x00000004, - - //@extension("VK_EXT_blend_operation_advanced") // 149 - VK_BLEND_OP_ZERO_EXT = 1000148000, - VK_BLEND_OP_SRC_EXT = 1000148001, - VK_BLEND_OP_DST_EXT = 1000148002, - VK_BLEND_OP_SRC_OVER_EXT = 1000148003, - VK_BLEND_OP_DST_OVER_EXT = 1000148004, - VK_BLEND_OP_SRC_IN_EXT = 1000148005, - VK_BLEND_OP_DST_IN_EXT = 1000148006, - VK_BLEND_OP_SRC_OUT_EXT = 1000148007, - VK_BLEND_OP_DST_OUT_EXT = 1000148008, - VK_BLEND_OP_SRC_ATOP_EXT = 1000148009, - VK_BLEND_OP_DST_ATOP_EXT = 1000148010, - VK_BLEND_OP_XOR_EXT = 1000148011, - VK_BLEND_OP_MULTIPLY_EXT = 1000148012, - VK_BLEND_OP_SCREEN_EXT = 1000148013, - VK_BLEND_OP_OVERLAY_EXT = 1000148014, - VK_BLEND_OP_DARKEN_EXT = 1000148015, - VK_BLEND_OP_LIGHTEN_EXT = 1000148016, - VK_BLEND_OP_COLORDODGE_EXT = 1000148017, - VK_BLEND_OP_COLORBURN_EXT = 1000148018, - VK_BLEND_OP_HARDLIGHT_EXT = 1000148019, - VK_BLEND_OP_SOFTLIGHT_EXT = 1000148020, - VK_BLEND_OP_DIFFERENCE_EXT = 1000148021, - VK_BLEND_OP_EXCLUSION_EXT = 1000148022, - VK_BLEND_OP_INVERT_EXT = 1000148023, - VK_BLEND_OP_INVERT_RGB_EXT = 1000148024, - VK_BLEND_OP_LINEARDODGE_EXT = 1000148025, - VK_BLEND_OP_LINEARBURN_EXT = 1000148026, - VK_BLEND_OP_VIVIDLIGHT_EXT = 1000148027, - VK_BLEND_OP_LINEARLIGHT_EXT = 1000148028, - VK_BLEND_OP_PINLIGHT_EXT = 1000148029, - VK_BLEND_OP_HARDMIX_EXT = 1000148030, - VK_BLEND_OP_HSL_HUE_EXT = 1000148031, - VK_BLEND_OP_HSL_SATURATION_EXT = 1000148032, - VK_BLEND_OP_HSL_COLOR_EXT = 1000148033, - VK_BLEND_OP_HSL_LUMINOSITY_EXT = 1000148034, - VK_BLEND_OP_PLUS_EXT = 1000148035, - VK_BLEND_OP_PLUS_CLAMPED_EXT = 1000148036, - VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT = 1000148037, - VK_BLEND_OP_PLUS_DARKER_EXT = 1000148038, - VK_BLEND_OP_MINUS_EXT = 1000148039, - VK_BLEND_OP_MINUS_CLAMPED_EXT = 1000148040, - VK_BLEND_OP_CONTRAST_EXT = 1000148041, - VK_BLEND_OP_INVERT_OVG_EXT = 1000148042, - VK_BLEND_OP_RED_EXT = 1000148043, - VK_BLEND_OP_GREEN_EXT = 1000148044, - VK_BLEND_OP_BLUE_EXT = 1000148045, -} - -enum VkStencilOp { - VK_STENCIL_OP_KEEP = 0x00000000, - VK_STENCIL_OP_ZERO = 0x00000001, - VK_STENCIL_OP_REPLACE = 0x00000002, - VK_STENCIL_OP_INCREMENT_AND_CLAMP = 0x00000003, - VK_STENCIL_OP_DECREMENT_AND_CLAMP = 0x00000004, - VK_STENCIL_OP_INVERT = 0x00000005, - VK_STENCIL_OP_INCREMENT_AND_WRAP = 0x00000006, - VK_STENCIL_OP_DECREMENT_AND_WRAP = 0x00000007, -} - -enum VkLogicOp { - VK_LOGIC_OP_CLEAR = 0x00000000, - VK_LOGIC_OP_AND = 0x00000001, - VK_LOGIC_OP_AND_REVERSE = 0x00000002, - VK_LOGIC_OP_COPY = 0x00000003, - VK_LOGIC_OP_AND_INVERTED = 0x00000004, - VK_LOGIC_OP_NO_OP = 0x00000005, - VK_LOGIC_OP_XOR = 0x00000006, - VK_LOGIC_OP_OR = 0x00000007, - VK_LOGIC_OP_NOR = 0x00000008, - VK_LOGIC_OP_EQUIVALENT = 0x00000009, - VK_LOGIC_OP_INVERT = 0x0000000a, - VK_LOGIC_OP_OR_REVERSE = 0x0000000b, - VK_LOGIC_OP_COPY_INVERTED = 0x0000000c, - VK_LOGIC_OP_OR_INVERTED = 0x0000000d, - VK_LOGIC_OP_NAND = 0x0000000e, - VK_LOGIC_OP_SET = 0x0000000f, -} - -enum VkSystemAllocationScope { - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0x00000000, - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 0x00000001, - VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 0x00000002, - VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 0x00000003, - VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 0x00000004, -} - -enum VkInternalAllocationType { - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0x00000000, -} - -enum VkPhysicalDeviceType { - VK_PHYSICAL_DEVICE_TYPE_OTHER = 0x00000000, - VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 0x00000001, - VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 0x00000002, - VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 0x00000003, - VK_PHYSICAL_DEVICE_TYPE_CPU = 0x00000004, -} - -enum VkVertexInputRate { - VK_VERTEX_INPUT_RATE_VERTEX = 0x00000000, - VK_VERTEX_INPUT_RATE_INSTANCE = 0x00000001, -} - -/// Vulkan format definitions -enum VkFormat { - VK_FORMAT_UNDEFINED = 0, - VK_FORMAT_R4G4_UNORM_PACK8 = 1, - VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2, - VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3, - VK_FORMAT_R5G6B5_UNORM_PACK16 = 4, - VK_FORMAT_B5G6R5_UNORM_PACK16 = 5, - VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6, - VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7, - VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8, - VK_FORMAT_R8_UNORM = 9, - VK_FORMAT_R8_SNORM = 10, - VK_FORMAT_R8_USCALED = 11, - VK_FORMAT_R8_SSCALED = 12, - VK_FORMAT_R8_UINT = 13, - VK_FORMAT_R8_SINT = 14, - VK_FORMAT_R8_SRGB = 15, - VK_FORMAT_R8G8_UNORM = 16, - VK_FORMAT_R8G8_SNORM = 17, - VK_FORMAT_R8G8_USCALED = 18, - VK_FORMAT_R8G8_SSCALED = 19, - VK_FORMAT_R8G8_UINT = 20, - VK_FORMAT_R8G8_SINT = 21, - VK_FORMAT_R8G8_SRGB = 22, - VK_FORMAT_R8G8B8_UNORM = 23, - VK_FORMAT_R8G8B8_SNORM = 24, - VK_FORMAT_R8G8B8_USCALED = 25, - VK_FORMAT_R8G8B8_SSCALED = 26, - VK_FORMAT_R8G8B8_UINT = 27, - VK_FORMAT_R8G8B8_SINT = 28, - VK_FORMAT_R8G8B8_SRGB = 29, - VK_FORMAT_B8G8R8_UNORM = 30, - VK_FORMAT_B8G8R8_SNORM = 31, - VK_FORMAT_B8G8R8_USCALED = 32, - VK_FORMAT_B8G8R8_SSCALED = 33, - VK_FORMAT_B8G8R8_UINT = 34, - VK_FORMAT_B8G8R8_SINT = 35, - VK_FORMAT_B8G8R8_SRGB = 36, - VK_FORMAT_R8G8B8A8_UNORM = 37, - VK_FORMAT_R8G8B8A8_SNORM = 38, - VK_FORMAT_R8G8B8A8_USCALED = 39, - VK_FORMAT_R8G8B8A8_SSCALED = 40, - VK_FORMAT_R8G8B8A8_UINT = 41, - VK_FORMAT_R8G8B8A8_SINT = 42, - VK_FORMAT_R8G8B8A8_SRGB = 43, - VK_FORMAT_B8G8R8A8_UNORM = 44, - VK_FORMAT_B8G8R8A8_SNORM = 45, - VK_FORMAT_B8G8R8A8_USCALED = 46, - VK_FORMAT_B8G8R8A8_SSCALED = 47, - VK_FORMAT_B8G8R8A8_UINT = 48, - VK_FORMAT_B8G8R8A8_SINT = 49, - VK_FORMAT_B8G8R8A8_SRGB = 50, - VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51, - VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52, - VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53, - VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54, - VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55, - VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56, - VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57, - VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58, - VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59, - VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60, - VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61, - VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62, - VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63, - VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64, - VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65, - VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66, - VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67, - VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68, - VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69, - VK_FORMAT_R16_UNORM = 70, - VK_FORMAT_R16_SNORM = 71, - VK_FORMAT_R16_USCALED = 72, - VK_FORMAT_R16_SSCALED = 73, - VK_FORMAT_R16_UINT = 74, - VK_FORMAT_R16_SINT = 75, - VK_FORMAT_R16_SFLOAT = 76, - VK_FORMAT_R16G16_UNORM = 77, - VK_FORMAT_R16G16_SNORM = 78, - VK_FORMAT_R16G16_USCALED = 79, - VK_FORMAT_R16G16_SSCALED = 80, - VK_FORMAT_R16G16_UINT = 81, - VK_FORMAT_R16G16_SINT = 82, - VK_FORMAT_R16G16_SFLOAT = 83, - VK_FORMAT_R16G16B16_UNORM = 84, - VK_FORMAT_R16G16B16_SNORM = 85, - VK_FORMAT_R16G16B16_USCALED = 86, - VK_FORMAT_R16G16B16_SSCALED = 87, - VK_FORMAT_R16G16B16_UINT = 88, - VK_FORMAT_R16G16B16_SINT = 89, - VK_FORMAT_R16G16B16_SFLOAT = 90, - VK_FORMAT_R16G16B16A16_UNORM = 91, - VK_FORMAT_R16G16B16A16_SNORM = 92, - VK_FORMAT_R16G16B16A16_USCALED = 93, - VK_FORMAT_R16G16B16A16_SSCALED = 94, - VK_FORMAT_R16G16B16A16_UINT = 95, - VK_FORMAT_R16G16B16A16_SINT = 96, - VK_FORMAT_R16G16B16A16_SFLOAT = 97, - VK_FORMAT_R32_UINT = 98, - VK_FORMAT_R32_SINT = 99, - VK_FORMAT_R32_SFLOAT = 100, - VK_FORMAT_R32G32_UINT = 101, - VK_FORMAT_R32G32_SINT = 102, - VK_FORMAT_R32G32_SFLOAT = 103, - VK_FORMAT_R32G32B32_UINT = 104, - VK_FORMAT_R32G32B32_SINT = 105, - VK_FORMAT_R32G32B32_SFLOAT = 106, - VK_FORMAT_R32G32B32A32_UINT = 107, - VK_FORMAT_R32G32B32A32_SINT = 108, - VK_FORMAT_R32G32B32A32_SFLOAT = 109, - VK_FORMAT_R64_UINT = 110, - VK_FORMAT_R64_SINT = 111, - VK_FORMAT_R64_SFLOAT = 112, - VK_FORMAT_R64G64_UINT = 113, - VK_FORMAT_R64G64_SINT = 114, - VK_FORMAT_R64G64_SFLOAT = 115, - VK_FORMAT_R64G64B64_UINT = 116, - VK_FORMAT_R64G64B64_SINT = 117, - VK_FORMAT_R64G64B64_SFLOAT = 118, - VK_FORMAT_R64G64B64A64_UINT = 119, - VK_FORMAT_R64G64B64A64_SINT = 120, - VK_FORMAT_R64G64B64A64_SFLOAT = 121, - VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122, - VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123, - VK_FORMAT_D16_UNORM = 124, - VK_FORMAT_X8_D24_UNORM_PACK32 = 125, - VK_FORMAT_D32_SFLOAT = 126, - VK_FORMAT_S8_UINT = 127, - VK_FORMAT_D16_UNORM_S8_UINT = 128, - VK_FORMAT_D24_UNORM_S8_UINT = 129, - VK_FORMAT_D32_SFLOAT_S8_UINT = 130, - VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131, - VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132, - VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133, - VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134, - VK_FORMAT_BC2_UNORM_BLOCK = 135, - VK_FORMAT_BC2_SRGB_BLOCK = 136, - VK_FORMAT_BC3_UNORM_BLOCK = 137, - VK_FORMAT_BC3_SRGB_BLOCK = 138, - VK_FORMAT_BC4_UNORM_BLOCK = 139, - VK_FORMAT_BC4_SNORM_BLOCK = 140, - VK_FORMAT_BC5_UNORM_BLOCK = 141, - VK_FORMAT_BC5_SNORM_BLOCK = 142, - VK_FORMAT_BC6H_UFLOAT_BLOCK = 143, - VK_FORMAT_BC6H_SFLOAT_BLOCK = 144, - VK_FORMAT_BC7_UNORM_BLOCK = 145, - VK_FORMAT_BC7_SRGB_BLOCK = 146, - VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147, - VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148, - VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149, - VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150, - VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151, - VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152, - VK_FORMAT_EAC_R11_UNORM_BLOCK = 153, - VK_FORMAT_EAC_R11_SNORM_BLOCK = 154, - VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155, - VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156, - VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157, - VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158, - VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159, - VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160, - VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161, - VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162, - VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163, - VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164, - VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165, - VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166, - VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167, - VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168, - VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169, - VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170, - VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171, - VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172, - VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173, - VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174, - VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175, - VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176, - VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177, - VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178, - VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179, - VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180, - VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181, - VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, - VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, - VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, - - //@vulkan1_1 - VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000, - VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001, - VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002, - VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003, - VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004, - VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005, - VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006, - VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007, - VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008, - VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009, - VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010, - VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016, - VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017, - VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018, - VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019, - VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020, - VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026, - VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027, - VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028, - VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029, - VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030, - VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, - VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, - VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033, - - //@extension("VK_IMG_format_pvrtc") // 28 - VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, - VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, - VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, - VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003, - VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004, - VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, - VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, - VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, - - //@extension("VK_KHR_sampler_ycbcr_conversion") // 157 - VK_FORMAT_G8B8G8R8_422_UNORM_KHR = 1000156000, - VK_FORMAT_B8G8R8G8_422_UNORM_KHR = 1000156001, - VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = 1000156002, - VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR = 1000156003, - VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR = 1000156004, - VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR = 1000156005, - VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR = 1000156006, - VK_FORMAT_R10X6_UNORM_PACK16_KHR = 1000156007, - VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR = 1000156008, - VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR = 1000156009, - VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR = 1000156010, - VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR = 1000156011, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR = 1000156012, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR = 1000156013, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR = 1000156014, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR = 1000156015, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR = 1000156016, - VK_FORMAT_R12X4_UNORM_PACK16_KHR = 1000156017, - VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR = 1000156018, - VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR = 1000156019, - VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR = 1000156020, - VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR = 1000156021, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR = 1000156022, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR = 1000156023, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR = 1000156024, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR = 1000156025, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR = 1000156026, - VK_FORMAT_G16B16G16R16_422_UNORM_KHR = 1000156027, - VK_FORMAT_B16G16R16G16_422_UNORM_KHR = 1000156028, - VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR = 1000156029, - VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR = 1000156030, - VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = 1000156031, - VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = 1000156032, - VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = 1000156033, -} - -/// Structure type enumerant -enum VkStructureType { - VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2, - VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3, - VK_STRUCTURE_TYPE_SUBMIT_INFO = 4, - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5, - VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6, - VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7, - VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8, - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9, - VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10, - VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11, - VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12, - VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13, - VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14, - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15, - VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16, - VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17, - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18, - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, - VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, - VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, - VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28, - VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29, - VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30, - VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35, - VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36, - VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37, - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38, - VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42, - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45, - VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46, - VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, - VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, - - //@vulkan1_1 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001, - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000, - VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003, - VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005, - VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000, - VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001, - VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002, - VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001, - VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000, - VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001, - VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002, - VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003, - VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = 1000120000, - VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001, - VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002, - VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005, - VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000, - VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002, - VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000, - VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001, - VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000, - VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000, - VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = 1000063000, - VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, - - //@extension("VK_KHR_swapchain") // 2 - VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, - VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, - // added as interaction from VK_KHR_device_group / VK 1.1 - VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009, - VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010, - VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012, - - //@extension("VK_KHR_display") // 3 - VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000, - VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001, - - //@extension("VK_KHR_display_swapchain") // 4 - VK_STRUCTURE_TYPE_DISPLAY_DISPLAY_PRESENT_INFO_KHR = 1000003000, - - //@extension("VK_KHR_xlib_surface") // 5 - VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, - - //@extension("VK_KHR_xcb_surface") // 6 - VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, - - //@extension("VK_KHR_wayland_surface") // 7 - VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, - - //@extension("VK_KHR_android_surface") // 9 - VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, - - //@extension("VK_KHR_win32_surface") // 10 - VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, - - //@extension("VK_ANDROID_native_buffer") // 11 - VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID = 1000010000, - VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID = 1000010001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID = 1000010002, - - //@extension("VK_EXT_debug_report") // 12 - VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, - - //@extension("VK_AMD_rasterization_order") // 19 - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000, - - //@extension("VK_EXT_debug_marker") // 23 - VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000, - VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001, - VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002, - - //@extension("VK_NV_dedicated_allocation") // 27 - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, - - //@extension("VK_EXT_transform_feedback") // 29 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, - - //@extension("VK_AMD_texture_gather_bias_lod") // 42 - VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, - - //@extension("VK_NV_corner_sampled_image") // 51 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, - - //@extension("VK_KHR_multiview") // 54 - VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = 1000053000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = 1000053001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = 1000053002, - - //@extension("VK_NV_external_memory") // 57 - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001, - - //@extension("VK_NV_external_memory_win32") // 58 - VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001, - - //@extension("VK_NV_win32_keyed_mutex") // 59 - VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000, - - //@extension("VK_KHR_get_physical_device_properties2") // 60 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = 1000059000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = 1000059001, - VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = 1000059002, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = 1000059004, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000059005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = 1000059006, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008, - - //@extension("VK_KHR_device_group") // 61 - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR = 1000060000, - VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR = 1000060003, - VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = 1000060004, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR = 1000060005, - VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR = 1000060006, - VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, - // tokens 08-12 are listed with VK_KHR_swapchain - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = 1000060013, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = 1000060014, - - //@extension("VK_EXT_validation_flags") // 62 - VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, - - //@extension("VK_NN_vi_surface") // 63 - VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, - - //@extension("VK_EXT_astc_decode_mode") // 68 - VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001, - - //@extension("VK_KHR_device_group_creation") // 71 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = 1000070000, - VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = 1000070001, - - //@extension("VK_KHR_external_memory_capabilities") // 72 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = 1000071000, - VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = 1000071001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = 1000071002, - VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR = 1000071003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR = 1000071004, - - //@extension("VK_KHR_external_memory") // 73 - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = 1000072000, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = 1000072001, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR = 1000072002, - - //@extension("VK_KHR_external_memory_win32") // 74 - VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001, - VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002, - - //@extension("VK_KHR_external_memory_fd") // 75 - VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR = 1000074000, - VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR = 1000074001, - - //@extension("VK_KHR_win32_keyed_mutex") // 76 - VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000, - - //@extension("VK_KHR_external_semaphore_capabilities") // 77 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = 1000076000, - VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR = 1000076001, - - //@extension("VK_KHR_external_semaphore") // 78 - VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = 1000077000, - - //@extension("VK_KHR_external_semaphore_win32") // 79 - VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000, - VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001, - VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002, - - //@extension("VK_KHR_external_semaphore_fd") // 80 - VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000, - VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001, - - //@extension("VK_KHR_push_descriptor") // 81 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000, - - //@extension("VK_KHR_16bit_storage") // 84 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = 1000083000, - - //@extension("VK_KHR_incremental_present") // 85 - VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000, - - //@extension("VK_EXT_conditional_rendering") // 82 - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001, - VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002, - - //@extension("VK_KHR_shader_float16_int8") // 83 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = 1000082000, - - //@extension("VK_KHR_descriptor_update_template") // 86 - VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = 1000085000, - - //@extension("VK_NVX_device_generated_commands") // 87 - VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000, - VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001, - VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002, - VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003, - VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004, - VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005, - - //@extension("VK_NV_clip_space_w_scaling") // 88 - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000, - - //@extension("VK_EXT_display_surface_counter") // 91 - VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT = 1000090000, - - //@extension("VK_EXT_display_control") // 92 - VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000, - VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001, - VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002, - VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003, - - //@extension("VK_GOOGLE_display_timing") // 93 - VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000, - - //@extension("VK_NVX_multiview_per_view_attributes") // 98 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000, - - //@extension("VK_NV_viewport_swizzle") // 99 - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000, - - //@extension("VK_EXT_discard_rectangles") // 100 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000, - VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001, - - //@extension("VK_EXT_conservative_rasterization") // 102 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT = 1000101000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT = 1000101001, - - //@extension("VK_KHR_create_renderpass2") // 110 - VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR = 1000109000, - VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR = 1000109001, - VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR = 1000109002, - VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR = 1000109003, - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR = 1000109004, - VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR = 1000109005, - VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR = 1000109006, - - //@extension("VK_EXT_hdr_metadata") // 106 - VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000, - - //@extension("VK_KHR_shared_presentable_image") // 112 - VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, - - //@extension("VK_KHR_external_fence_capabilities") // 113 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = 1000112000, - VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = 1000112001, - - //@extension("VK_KHR_external_fence") // 114 - VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = 1000113000, - - //@extension("VK_KHR_external_fence_win32") // 115 - VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000, - VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001, - VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002, - - //@extension("VK_KHR_external_fence_fd") // 117 - VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR = 1000115000, - VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR = 1000115001, - - //@extension("VK_KHR_maintenance2") // 118 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = 1000117000, - VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = 1000117001, - VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = 1000117002, - VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = 1000117003, - - //@extension("VK_KHR_get_surface_capabilities2") // 120 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000, - VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001, - VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002, - - //@extension("VK_KHR_variable_pointers") // 121 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = 1000120000, - - //@extension("VK_KHR_display_properties2") // 122 - VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR = 1000121000, - VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR = 1000121001, - VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR = 1000121002, - VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR = 1000121003, - VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR = 1000121004, - - //@extension("VK_MVK_ios_surface") // 123 - VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000, - - //@extension("VK_MVK_macos_surface") // 124 - VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000, - - //@extension("VK_KHR_dedicated_allocation") // 128 - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR = 1000127000, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = 1000127001, - - //@extension("VK_EXT_debug_utils") // 129 - VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000128000, - VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT = 1000128001, - VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT = 1000128002, - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000128003, - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000128004, - - //@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130 - VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID = 1000129000, - VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID = 1000129001, - VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID = 1000129002, - VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003, - VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004, - VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID = 1000129005, - - //@extension("VK_EXT_sampler_filter_minmax") // 131 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000, - VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001, - - //@extension("VK_EXT_inline_uniform_block") // 139 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = 1000138000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = 1000138001, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = 1000138002, - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = 1000138003, - - //@extension("VK_EXT_sample_locations") // 144 - VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000, - VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001, - VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003, - VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT = 1000143004, - - //@extension("VK_KHR_get_memory_requirements2") // 147 - VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146000, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146001, - VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146002, - VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR = 1000146003, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = 1000146004, - - //@extension("VK_KHR_image_format_list") // 148 - VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = 1000147000, - - //@extension("VK_EXT_blend_operation_advanced") // 149 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001, - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, - - //@extension("VK_NV_fragment_coverage_to_color") // 150 - VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, - - //@extension("VK_NV_framebuffer_mixed_samples") // 153 - VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, - - //@extension("VK_KHR_sampler_ycbcr_conversion") // 157 - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = 1000156000, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR = 1000156001, - VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR = 1000156002, - VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR = 1000156003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = 1000156004, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = 1000156005, - - //@extension("VK_EXT_image_drm_format_modifier") // 159 - VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000, - VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002, - VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003, - VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004, - VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, - - //@extension("VK_KHR_bind_memory2") // 158 - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = 1000157000, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = 1000157001, - - //@extension("VK_EXT_validation_cache") // 161 - VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, - VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, - - //@extension("VK_EXT_descriptor_indexing") // 162 - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = 1000161000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT = 1000161001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = 1000161002, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = 1000161003, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = 1000161004, - - //@extension("VK_NV_shading_rate_image") // 165 - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV = 1000164000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005, - - //@extension("VK_NV_ray_tracing") // 166 - VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001, - VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003, - VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004, - VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005, - VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, - VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012, - - //@extension("VK_NV_representative_fragment_test") // 167 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000, - VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001, - - //@extension("VK_KHR_maintenance3") // 169 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = 1000168000, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = 1000168001, - - //@extension("VK_EXT_global_priority") // 175 - VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000, - - //@extension("VK_KHR_8bit_storage") // 178 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = 1000177000, - - //@extension("VK_EXT_external_memory_host") // 179 - VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, - VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, - - //@extension("VK_KHR_shader_atomic_int64") // 181 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000, - - //@extension("VK_EXT_calibrated_timestamps") // 185 - VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, - - //@extension("VK_KHR_driver_properties") // 197 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = 1000196000, - - //@extension("VK_KHR_shader_float_controls") // 198 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = 1000197000, - - //@extension("VK_AMD_shader_core_properties") // 186 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, - - //@extension("VK_AMD_memory_overallocation_behavior") // 190 - VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, - - //@extension("VK_EXT_vertex_attribute_divisor") // 191 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, - - //@extension("VK_NV_device_diagnostic_checkpoints") // 207 - VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001, - - //@extension("VK_KHR_vulkan_memory_model") // 212 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000, - - //@extension("VK_EXT_pci_bus_info") // 213 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000, - - //@extension("VK_FUCHSIA_imagepipe_surface") // 215 - VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000, - - //@extension("VK_EXT_fragment_density_map") // 219 - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001, - VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002, - - //@extension("VK_EXT_scalar_block_layout") - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = 1000221000, - - //@extension("VK_EXT_separate_stencil_usage") // 247 - VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = 1000246000, -} - -enum VkSubpassContents { - VK_SUBPASS_CONTENTS_INLINE = 0x00000000, - VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 0x00000001, -} - -enum VkPipelineCacheHeaderVersion { - VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, -} - -@lastUnused(-11) -/// Error and return codes -enum VkResult { - // Return codes for successful operation execution (positive values) - VK_SUCCESS = 0, - VK_NOT_READY = 1, - VK_TIMEOUT = 2, - VK_EVENT_SET = 3, - VK_EVENT_RESET = 4, - VK_INCOMPLETE = 5, - - //@extension("VK_KHR_swapchain") // 2 - VK_SUBOPTIMAL_KHR = 1000001003, - - // Error codes (negative values) - VK_ERROR_OUT_OF_HOST_MEMORY = 0xFFFFFFFF, // -1 - VK_ERROR_OUT_OF_DEVICE_MEMORY = 0xFFFFFFFE, // -2 - VK_ERROR_INITIALIZATION_FAILED = 0xFFFFFFFD, // -3 - VK_ERROR_DEVICE_LOST = 0xFFFFFFFC, // -4 - VK_ERROR_MEMORY_MAP_FAILED = 0xFFFFFFFB, // -5 - VK_ERROR_LAYER_NOT_PRESENT = 0xFFFFFFFA, // -6 - VK_ERROR_EXTENSION_NOT_PRESENT = 0xFFFFFFF9, // -7 - VK_ERROR_FEATURE_NOT_PRESENT = 0xFFFFFFF8, // -8 - VK_ERROR_INCOMPATIBLE_DRIVER = 0xFFFFFFF7, // -9 - VK_ERROR_TOO_MANY_OBJECTS = 0xFFFFFFF6, // -10 - VK_ERROR_FORMAT_NOT_SUPPORTED = 0xFFFFFFF5, // -11 - VK_ERROR_FRAGMENTED_POOL = 0xFFFFFFF4, // -12 - - //@vulkan1_1 - VK_ERROR_OUT_OF_POOL_MEMORY = 0xC4642878, // -1000069000 - VK_ERROR_INVALID_EXTERNAL_HANDLE = 0xC4641CBD, // -1000072003 - - //@extension("VK_KHR_surface") // 1 - VK_ERROR_SURFACE_LOST_KHR = 0xC4653600, // -1000000000 - VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = 0xC46535FF, // -1000000001 - - //@extension("VK_KHR_swapchain") // 2 - VK_ERROR_OUT_OF_DATE_KHR = 0xC4653214, // -1000001004 - - //@extension("VK_KHR_display_swapchain") // 4 - VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = 0xC4652A47, // -1000003001 - - //@extension("VK_EXT_debug_report") // 12 - VK_ERROR_VALIDATION_FAILED_EXT = 0xC4650B07, // -1000011001 - - //@extension("VK_NV_glsl_shader") // 13 - VK_ERROR_INVALID_SHADER_NV = 0xC4650720, // -1000012000 - - //@extension("VK_KHR_maintenance1") // 70 - VK_ERROR_OUT_OF_POOL_MEMORY_KHR = 0xC4642878, // -1000069000 - - //@extension("VK_KHR_external_memory") // 73 - VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = 0xC4641CBD, // -1000072003 - - //@extension("VK_EXT_image_drm_format_modifier") // 159 - VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = 0xC462CCD0, // -1000158000 - - //@extension("VK_EXT_descriptor_indexing") // 162 - VK_ERROR_FRAGMENTATION_EXT = 0xc462c118, // -1000161000 - - //@extension("VK_EXT_global_priority") // 175 - VK_ERROR_NOT_PERMITTED_EXT = 0xC4628E4F, // -1000174001 -} - -enum VkDynamicState { - VK_DYNAMIC_STATE_VIEWPORT = 0x00000000, - VK_DYNAMIC_STATE_SCISSOR = 0x00000001, - VK_DYNAMIC_STATE_LINE_WIDTH = 0x00000002, - VK_DYNAMIC_STATE_DEPTH_BIAS = 0x00000003, - VK_DYNAMIC_STATE_BLEND_CONSTANTS = 0x00000004, - VK_DYNAMIC_STATE_DEPTH_BOUNDS = 0x00000005, - VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 0x00000006, - VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 0x00000007, - VK_DYNAMIC_STATE_STENCIL_REFERENCE = 0x00000008, - - //@extension("VK_NV_clip_space_w_scaling") // 88 - VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000, - - //@extension("VK_EXT_discard_rectangles") // 100 - VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000, - - //@extension("VK_EXT_sample_locations") // 144 - VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000, - - //@extension("VK_NV_shading_rate_image") // 165 - VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV = 1000164004, - VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV = 1000164006, - - //@extension("VK_NV_scissor_exclusive") // 206 - VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV = 1000205001, -} - -enum VkObjectType { - VK_OBJECT_TYPE_UNKNOWN = 0, - VK_OBJECT_TYPE_INSTANCE = 1, - VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2, - VK_OBJECT_TYPE_DEVICE = 3, - VK_OBJECT_TYPE_QUEUE = 4, - VK_OBJECT_TYPE_SEMAPHORE = 5, - VK_OBJECT_TYPE_COMMAND_BUFFER = 6, - VK_OBJECT_TYPE_FENCE = 7, - VK_OBJECT_TYPE_DEVICE_MEMORY = 8, - VK_OBJECT_TYPE_BUFFER = 9, - VK_OBJECT_TYPE_IMAGE = 10, - VK_OBJECT_TYPE_EVENT = 11, - VK_OBJECT_TYPE_QUERY_POOL = 12, - VK_OBJECT_TYPE_BUFFER_VIEW = 13, - VK_OBJECT_TYPE_IMAGE_VIEW = 14, - VK_OBJECT_TYPE_SHADER_MODULE = 15, - VK_OBJECT_TYPE_PIPELINE_CACHE = 16, - VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17, - VK_OBJECT_TYPE_RENDER_PASS = 18, - VK_OBJECT_TYPE_PIPELINE = 19, - VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20, - VK_OBJECT_TYPE_SAMPLER = 21, - VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22, - VK_OBJECT_TYPE_DESCRIPTOR_SET = 23, - VK_OBJECT_TYPE_FRAMEBUFFER = 24, - VK_OBJECT_TYPE_COMMAND_POOL = 25, - - //@vulkan1_1 - VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000, - VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000, - - //@extension("VK_KHR_surface") // 1 - VK_OBJECT_TYPE_SURFACE_KHR = 1000000000, - - //@extension("VK_KHR_swapchain") // 2 - VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000, - - //@extension("VK_KHR_display") // 3 - VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000, - VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001, - - //@extension("VK_KHR_debug_report") // 12 - VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000, - - //@extension("VK_KHR_descriptor_update_template") // 86 - VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = 1000085000, - - //@extension("VK_NVX_device_generated_commands") // 87 - VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000, - VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001, - - //@extension("VK_EXT_debug_utils") // 129 - VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000, - - //@extension("VK_KHR_sampler_ycbcr_conversion") // 157 - VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = 1000156000, - - //@extension("VK_EXT_validation_cache") // 161 - VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, - - //@extension("VK_NV_ray_tracing") // 166 - VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, -} - - -//@vulkan1_1 enums - -enum VkPointClippingBehavior { - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0, - VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1, -} - -enum VkTessellationDomainOrigin { - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0, - VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1, -} - -enum VkSamplerYcbcrModelConversion { - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4, -} - -enum VkSamplerYcbcrRange { - VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, - VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1, -} - -enum VkChromaLocation { - VK_CHROMA_LOCATION_COSITED_EVEN = 0, - VK_CHROMA_LOCATION_MIDPOINT = 1, -} - -enum VkDescriptorUpdateTemplateType { - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1, -} - -enum VkVendorId { - VK_VENDOR_ID_VIV = 0x10001, - VK_VENDOR_ID_VSI = 0x10002, - VK_VENDOR_ID_KAZAN = 0x10003, -} - -@extension("VK_KHR_surface") // 1 -enum VkPresentModeKHR { - VK_PRESENT_MODE_IMMEDIATE_KHR = 0x00000000, - VK_PRESENT_MODE_MAILBOX_KHR = 0x00000001, - VK_PRESENT_MODE_FIFO_KHR = 0x00000002, - VK_PRESENT_MODE_FIFO_RELAXED_KHR = 0x00000003, - - //@extension("VK_KHR_shared_presentable_image") // 112 - VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000, - VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001, -} - -@extension("VK_KHR_surface") // 1 -enum VkColorSpaceKHR { - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0x00000000, - - //@extension("VK_EXT_swapchain_colorspace") // 105 - VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001, - VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002, - VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104003, - VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004, - VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005, - VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006, - VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007, - VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008, - VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009, - VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010, - VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011, - VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, - VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, - VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014, -} - -@extension("VK_EXT_debug_report") // 12 -enum VkDebugReportObjectTypeEXT { - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, - VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, - VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3, - VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4, - VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6, - VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8, - VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9, - VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10, - VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11, - VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12, - VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13, - VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14, - VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15, - VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16, - VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17, - VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18, - VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20, - VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23, - VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25, - VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26, - VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27, - VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28, - VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29, - VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30, - VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31, - VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32, - - //extension("VK_EXT_validation_cache") // 161 - VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33, - - //extension("VK_KHR_descriptor_update_template") // 86 - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000, - - //@extension("VK_KHR_sampler_ycbcr_conversion") // 157 - VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = 1000156000, - - //@extension("VK_NV_ray_tracing") // 166 - VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, -} - -@extension("VK_AMD_rasterization_order") // 19 -enum VkRasterizationOrderAMD { - VK_RASTERIZATION_ORDER_STRICT_AMD = 0, - VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, -} - -@extension("VK_AMD_shader_info") // 43 -enum VkShaderInfoTypeAMD { - VK_SHADER_INFO_TYPE_STATISTICS_AMD = 0, - VK_SHADER_INFO_TYPE_BINARY_AMD = 1, - VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2, -} - -@extension("VK_EXT_validation_flags") // 62 -enum VkValidationCheckEXT { - VK_VALIDATION_CHECK_ALL_EXT = 0, - VK_VALIDATION_CHECK_SHADERS_EXT = 1, -} - -@extension("VK_KHR_descriptor_update_template") // 86 -enum VkDescriptorUpdateTemplateTypeKHR { - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = 0, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1, -} - -@extension("VK_NVX_device_generated_commands") // 87 -enum VkIndirectCommandsTokenTypeNVX { - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX = 0, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DESCRIPTOR_SET_NVX = 1, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NVX = 2, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NVX = 3, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NVX = 4, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NVX = 5, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NVX = 6, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX = 7, -} - -@extension("VK_NVX_device_generated_commands") // 87 -enum VkObjectEntryTypeNVX { - VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX = 0, - VK_OBJECT_ENTRY_TYPE_PIPELINE_NVX = 1, - VK_OBJECT_ENTRY_TYPE_INDEX_BUFFER_NVX = 2, - VK_OBJECT_ENTRY_TYPE_VERTEX_BUFFER_NVX = 3, - VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX = 4, -} - -@extension("VK_EXT_display_control") // 92 -enum VkDisplayPowerStateEXT { - VK_DISPLAY_POWER_STATE_OFF_EXT = 0, - VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1, - VK_DISPLAY_POWER_STATE_ON_EXT = 2, -} - -@extension("VK_EXT_display_control") // 92 -enum VkDeviceEventTypeEXT { - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0, -} - -@extension("VK_EXT_display_control") // 92 -enum VkDisplayEventTypeEXT { - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0, -} - -@extension("VK_NV_viewport_swizzle") // 99 -enum VkViewportCoordinateSwizzleNV { - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1, - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3, - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5, - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7, -} - -@extension("VK_EXT_discard_rectangles") // 100 -enum VkDiscardRectangleModeEXT { - VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0, - VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1, -} - -@extension("VK_EXT_conservative_rasterization") // 102 -enum VkConservativeRasterizationModeEXT { - VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT = 0, - VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT = 1, - VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2, -} - -@extension("VK_KHR_maintenance2") // 118 -enum VkPointClippingBehaviorKHR { - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = 0, - VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = 1, -} - -@extension("VK_KHR_maintenance2") // 118 -enum VkTessellationDomainOriginKHR { - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = 0, - VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = 1, -} - -@extension("VK_EXT_sampler_filter_minmax") // 131 -enum VkSamplerReductionModeEXT { - VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = 0, - VK_SAMPLER_REDUCTION_MODE_MIN_EXT = 1, - VK_SAMPLER_REDUCTION_MODE_MAX_EXT = 2, -} - -@extension("VK_EXT_blend_operation_advanced") // 149 -enum VkBlendOverlapEXT { - VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0, - VK_BLEND_OVERLAP_DISJOINT_EXT = 1, - VK_BLEND_OVERLAP_CONJOINT_EXT = 2, -} - -@extension("VK_NV_framebuffer_mixed_samples") // 153 -enum VkCoverageModulationModeNV { - VK_COVERAGE_MODULATION_MODE_NONE_NV = 0, - VK_COVERAGE_MODULATION_MODE_RGB_NV = 1, - VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2, - VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3, -} - -@extension("VK_KHR_sampler_ycbcr_conversion") // 157 -enum VkSamplerYcbcrModelConversionKHR { - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR = 0, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR = 1, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = 2, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = 3, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = 4, -} - -@extension("VK_KHR_sampler_ycbcr_conversion") // 157 -enum VkSamplerYcbcrRangeKHR { - VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = 0, - VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = 1, -} - -@extension("VK_KHR_sampler_ycbcr_conversion") // 157 -enum VkChromaLocationKHR { - VK_CHROMA_LOCATION_COSITED_EVEN_KHR = 0, - VK_CHROMA_LOCATION_MIDPOINT_KHR = 1, -} - -@extension("VK_EXT_validation_cache") // 161 -enum VkValidationCacheHeaderVersionEXT { - VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1, -} - -@extension("VK_NV_shading_rate_image") // 165 -enum VkShadingRatePaletteEntryNV { - VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV = 0, - VK_SHADING_RATE_PALETTE_ENTRY_16_INVOCATIONS_PER_PIXEL_NV = 1, - VK_SHADING_RATE_PALETTE_ENTRY_8_INVOCATIONS_PER_PIXEL_NV = 2, - VK_SHADING_RATE_PALETTE_ENTRY_4_INVOCATIONS_PER_PIXEL_NV = 3, - VK_SHADING_RATE_PALETTE_ENTRY_2_INVOCATIONS_PER_PIXEL_NV = 4, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV = 5, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X1_PIXELS_NV = 6, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV = 7, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV = 8, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV = 9, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV = 10, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV = 11, -} - -@extension("VK_NV_shading_rate_image") // 165 -enum VkCoarseSampleOrderTypeNV { - VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV = 0, - VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV = 1, - VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV = 2, - VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3, -} - -@extension("VK_NV_ray_tracing") // 166 -enum VkRayTracingShaderGroupTypeNV { - VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = 0, - VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = 1, - VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = 2, -} - -@extension("VK_NV_ray_tracing") // 166 -enum VkGeometryTypeNV { - VK_GEOMETRY_TYPE_TRIANGLES_NV = 0, - VK_GEOMETRY_TYPE_AABBS_NV = 1, -} - -@extension("VK_NV_ray_tracing") // 166 -enum VkAccelerationStructureTypeNV { - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0, - VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1, -} - -@extension("VK_NV_ray_tracing") // 166 -enum VkCopyAccelerationStructureModeNV { - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = 0, - VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = 1, -} - -@extension("VK_NV_ray_tracing") // 166 -enum VkAccelerationStructureMemoryRequirementsTypeNV { - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2, -} - -@extension("VK_EXT_global_priority") // 175 -enum VkQueueGlobalPriorityEXT { - VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = 128, - VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = 256, - VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = 512, - VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = 1024, -} - -@extension("VK_EXT_calibrated_timestamps") // 185 -enum VkTimeDomainEXT { - VK_TIME_DOMAIN_DEVICE_EXT = 0, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2, - VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3, -} - -@extension("VK_AMD_memory_overallocation_behavior") // 190 -enum VkMemoryOverallocationBehaviorAMD { - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2, -} - -@extension("VK_KHR_driver_properties") // 197 -enum VkDriverIdKHR { - VK_DRIVER_ID_AMD_PROPRIETARY_KHR = 1, - VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = 2, - VK_DRIVER_ID_MESA_RADV_KHR = 3, - VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = 4, - VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = 5, - VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = 6, - VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = 7, - VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = 8, - VK_DRIVER_ID_ARM_PROPRIETARY_KHR = 9, - VK_DRIVER_ID_GOOGLE_PASTEL_KHR = 10, -} - -///////////////// -// Bitfields // -///////////////// - -/// Queue capabilities -type VkFlags VkQueueFlags -bitfield VkQueueFlagBits { - VK_QUEUE_GRAPHICS_BIT = 0x00000001, /// Queue supports graphics operations - VK_QUEUE_COMPUTE_BIT = 0x00000002, /// Queue supports compute operations - VK_QUEUE_TRANSFER_BIT = 0x00000004, /// Queue supports transfer operations - VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, /// Queue supports sparse resource memory management operations - - //@vulkan1_1 - VK_QUEUE_PROTECTED_BIT = 0x00000010, -} - -/// Memory properties passed into vkAllocMemory(). -type VkFlags VkMemoryPropertyFlags -bitfield VkMemoryPropertyFlagBits { - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002, - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, - VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, - VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, - - //@vulkan1_1 - VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020, -} - -/// Memory heap flags -type VkFlags VkMemoryHeapFlags -bitfield VkMemoryHeapFlagBits { - VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, - - //@vulkan1_1 - VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002, - - //@extension("VK_KHR_device_group_creation") // 71 - VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = 0x00000002, -} - -/// Access flags -type VkFlags VkAccessFlags -bitfield VkAccessFlagBits { - VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001, - VK_ACCESS_INDEX_READ_BIT = 0x00000002, - VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004, - VK_ACCESS_UNIFORM_READ_BIT = 0x00000008, - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010, - VK_ACCESS_SHADER_READ_BIT = 0x00000020, - VK_ACCESS_SHADER_WRITE_BIT = 0x00000040, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400, - VK_ACCESS_TRANSFER_READ_BIT = 0x00000800, - VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000, - VK_ACCESS_HOST_READ_BIT = 0x00002000, - VK_ACCESS_HOST_WRITE_BIT = 0x00004000, - VK_ACCESS_MEMORY_READ_BIT = 0x00008000, - VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, - - //@extension("VK_NVX_device_generated_commands") // 87 - VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000, - VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000, - - //@extension("VK_EXT_blend_operation_advanced") // 149 - VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000, - - //@extension("VK_EXT_conditional_rendering") // 82 - VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000, - - //@extension("VK_NV_shading_rate_image") // 165 - VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000, - - //@extension("VK_NV_ray_tracing") // 166 - VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000, - VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000, - - //@extension("VK_EXT_fragment_density_map") // 219 - VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000, - - //@extension("VK_EXT_transform_feedback") // 29 - VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000, - VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000, - VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000, -} - -/// Buffer usage flags -type VkFlags VkBufferUsageFlags -bitfield VkBufferUsageFlagBits { - VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001, /// Can be used as a source of transfer operations - VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002, /// Can be used as a destination of transfer operations - VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004, /// Can be used as TBO - VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008, /// Can be used as IBO - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010, /// Can be used as UBO - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020, /// Can be used as SSBO - VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, /// Can be used as source of fixed function index fetch (index buffer) - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, /// Can be used as source of fixed function vertex fetch (VBO) - VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, /// Can be the source of indirect parameters (e.g. indirect buffer, parameter buffer) - - //@extension("VK_EXT_conditional_rendering") // 82 - VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200, - - //@extension("VK_NV_ray_tracing") // 166 - VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = 0x00000400, - - //@extension("VK_EXT_transform_feedback") // 29 - VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800, - VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000, -} - -/// Buffer creation flags -type VkFlags VkBufferCreateFlags -bitfield VkBufferCreateFlagBits { - VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, /// Buffer should support sparse backing - VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, /// Buffer should support sparse backing with partial residency - VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, /// Buffer should support constent data access to physical memory blocks mapped into multiple locations of sparse buffers - - //@vulkan1_1 - VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008, -} - -/// Shader stage flags -type VkFlags VkShaderStageFlags -bitfield VkShaderStageFlagBits { - VK_SHADER_STAGE_VERTEX_BIT = 0x00000001, - VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002, - VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004, - VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, - VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, - VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, - VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, - - VK_SHADER_STAGE_ALL = 0x7FFFFFFF, - - //@extension("VK_NV_ray_tracing") // 166 - VK_SHADER_STAGE_RAYGEN_BIT_NV = 0x00000100, - VK_SHADER_STAGE_ANY_HIT_BIT_NV = 0x00000200, - VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = 0x00000400, - VK_SHADER_STAGE_MISS_BIT_NV = 0x00000800, - VK_SHADER_STAGE_INTERSECTION_BIT_NV = 0x00001000, - VK_SHADER_STAGE_CALLABLE_BIT_NV = 0x00002000, - - //@extension("VK_NV_mesh_shader") // 203 - VK_SHADER_STAGE_TASK_BIT_NV = 0x00000040, - VK_SHADER_STAGE_MESH_BIT_NV = 0x00000080, -} - -/// Descriptor pool create flags -type VkFlags VkDescriptorPoolCreateFlags -bitfield VkDescriptorPoolCreateFlagBits { - VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, - - //@extension("VK_EXT_descriptor_indexing") // 162 - VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = 0x00000002, -} - -/// Descriptor pool reset flags -type VkFlags VkDescriptorPoolResetFlags -//bitfield VkDescriptorPoolResetFlagBits { -//} - -/// Image usage flags -type VkFlags VkImageUsageFlags -bitfield VkImageUsageFlagBits { - VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001, /// Can be used as a source of transfer operations - VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, /// Can be used as a destination of transfer operations - VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, /// Can be sampled from (SAMPLED_IMAGE and COMBINED_IMAGE_SAMPLER descriptor types) - VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, /// Can be used as storage image (STORAGE_IMAGE descriptor type) - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, /// Can be used as framebuffer color attachment - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, /// Can be used as framebuffer depth/stencil attachment - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, /// Image data not needed outside of rendering - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, /// Can be used as framebuffer input attachment - - //@extension("VK_NV_shading_rate_image") // 165 - VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00000100, - - //@extension("VK_EXT_fragment_density_map") // 219 - VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x00000200, -} - -/// Image creation flags -type VkFlags VkImageCreateFlags -bitfield VkImageCreateFlagBits { - VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001, /// Image should support sparse backing - VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, /// Image should support sparse backing with partial residency - VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, /// Image should support constent data access to physical memory blocks mapped into multiple locations of sparse images - VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, /// Allows image views to have different format than the base image - VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, /// Allows creating image views with cube type from the created image - - //@vulkan1_1 - VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 0x00000020, - VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT = 0x00000040, - VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 0x00000080, - VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100, - VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200, - VK_IMAGE_CREATE_ALIAS_BIT = 0x00000400, - VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800, - - //@extension("VK_KHR_maintenance1") // 70 - VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020, - - //@extension("VK_KHR_device_group") // 61 - VK_IMAGE_CREATE_BIND_SFR_BIT_KHR = 0x00000040, - - //@extension("VK_KHR_maintenance2") // 118 - VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = 0x00000080, - VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR = 0x00000100, - - //@extension("VK_KHR_sampler_ycbcr_conversion") // 157 - VK_IMAGE_CREATE_DISJOINT_BIT_KHR = 0x00000200, - - //@extension("VK_KHR_bind_memory2") // 158 - VK_IMAGE_CREATE_ALIAS_BIT_KHR = 0x00000400, - - //@extension("VK_EXT_sample_locations") // 144 - VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000, - - //@extension("VK_NV_corner_sampled_image") // 51 - VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV = 0x00002000, - - //@extension("VK_EXT_fragment_density_map") // 219 - VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 0x00004000, -} - -/// Image view creation flags -type VkFlags VkImageViewCreateFlags -bitfield VkImageViewCreateFlagBits { - //@extension("VK_EXT_fragment_density_map") // 219 - VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT = 0x00000001, -} - -/// Pipeline creation flags -type VkFlags VkPipelineCreateFlags -bitfield VkPipelineCreateFlagBits { - VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, - VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, - VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, - - //@vulkan1_1 - VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008, - VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010, - - //@extension("VK_KHR_device_group") // 61 - VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = 0x00000008, - VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = 0x00000010, - - //@extension("VK_NV_ray_tracing") // 166 - VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020, -} - -/// Color component flags -type VkFlags VkColorComponentFlags -bitfield VkColorComponentFlagBits { - VK_COLOR_COMPONENT_R_BIT = 0x00000001, - VK_COLOR_COMPONENT_G_BIT = 0x00000002, - VK_COLOR_COMPONENT_B_BIT = 0x00000004, - VK_COLOR_COMPONENT_A_BIT = 0x00000008, -} - -/// Fence creation flags -type VkFlags VkFenceCreateFlags -bitfield VkFenceCreateFlagBits { - VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, -} - -/// Semaphore creation flags -type VkFlags VkSemaphoreCreateFlags -//bitfield VkSemaphoreCreateFlagBits { -//} - -/// Format capability flags -type VkFlags VkFormatFeatureFlags -bitfield VkFormatFeatureFlagBits { - VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001, /// Format can be used for sampled images (SAMPLED_IMAGE and COMBINED_IMAGE_SAMPLER descriptor types) - VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002, /// Format can be used for storage images (STORAGE_IMAGE descriptor type) - VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004, /// Format supports atomic operations in case it's used for storage images - VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008, /// Format can be used for uniform texel buffers (TBOs) - VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010, /// Format can be used for storage texel buffers (IBOs) - VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020, /// Format supports atomic operations in case it's used for storage texel buffers - VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040, /// Format can be used for vertex buffers (VBOs) - VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080, /// Format can be used for color attachment images - VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100, /// Format supports blending in case it's used for color attachment images - VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200, /// Format can be used for depth/stencil attachment images - VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, /// Format can be used as the source image of blits with vkCommandBlitImage - VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, /// Format can be used as the destination image of blits with vkCommandBlitImage - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, - - //@vulkan1_1 - VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 0x00004000, - VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 0x00008000, - VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000, - VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000, - VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000, - - //@extension("VK_IMG_filter_cubic") // 16 - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000, - - //@extension("VK_KHR_maintenance1") // 70 - VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = 0x00004000, - VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = 0x00008000, - - //@extension("VK_EXT_sampler_filter_minmax") // 131 - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = 0x00010000, - - //@extension("VK_KHR_sampler_ycbcr_conversion") // 157 - VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = 0x00020000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = 0x00040000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = 0x00080000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = 0x00100000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = 0x00200000, - VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = 0x00400000, - VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = 0x00800000, -} - -/// Query control flags -type VkFlags VkQueryControlFlags -bitfield VkQueryControlFlagBits { - VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001, -} - -/// Query result flags -type VkFlags VkQueryResultFlags -bitfield VkQueryResultFlagBits { - VK_QUERY_RESULT_64_BIT = 0x00000001, /// Results of the queries are written to the destination buffer as 64-bit values - VK_QUERY_RESULT_WAIT_BIT = 0x00000002, /// Results of the queries are waited on before proceeding with the result copy - VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, /// Besides the results of the query, the availability of the results is also written - VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, /// Copy the partial results of the query even if the final results aren't available -} - -/// Shader module creation flags -type VkFlags VkShaderModuleCreateFlags -//bitfield VkShaderModuleCreateFlagBits { -//} - -/// Event creation flags -type VkFlags VkEventCreateFlags -//bitfield VkEventCreateFlagBits { -//} - -/// Command buffer usage flags -type VkFlags VkCommandBufferUsageFlags -bitfield VkCommandBufferUsageFlagBits { - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001, - VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004, -} - -/// Pipeline statistics flags -type VkFlags VkQueryPipelineStatisticFlags -bitfield VkQueryPipelineStatisticFlagBits { - VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001, /// Optional - VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002, /// Optional - VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004, /// Optional - VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008, /// Optional - VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010, /// Optional - VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020, /// Optional - VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040, /// Optional - VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080, /// Optional - VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, /// Optional - VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, /// Optional - VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, /// Optional -} - -/// Memory mapping flags -type VkFlags VkMemoryMapFlags -//bitfield VkMemoryMapFlagBits { -//} - -/// Bitfield of image aspects -type VkFlags VkImageAspectFlags -bitfield VkImageAspectFlagBits { - VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001, - VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, - VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, - VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, - - //@vulkan1_1 - VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, - VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, - VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040, - - //@extension("VK_KHR_sampler_ycbcr_conversion") // 157 - VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = 0x00000010, - VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = 0x00000020, - VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = 0x00000040, - - //@extension("VK_EXT_transform_feedback") // 29 - VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080, - VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100, - VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200, - VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400, -} - -/// Sparse memory bind flags -type VkFlags VkSparseMemoryBindFlags -bitfield VkSparseMemoryBindFlagBits { - VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001, -} - -/// Sparse image memory requirements flags -type VkFlags VkSparseImageFormatFlags -bitfield VkSparseImageFormatFlagBits { - VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, /// Image uses a single miptail region for all array slices - VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, /// Image requires mip levels to be an exact multiple of the sparse iamge block size for non-mip-tail levels. - VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, /// Image uses a non-standard sparse block size -} - -/// Pipeline stages -type VkFlags VkPipelineStageFlags -bitfield VkPipelineStageFlagBits { - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001, /// Before subsequent commands are processed - VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002, /// Draw/DispatchIndirect command fetch - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004, /// Vertex/index fetch - VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008, /// Vertex shading - VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010, /// Tessellation control shading - VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020, /// Tessellation evaluation shading - VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040, /// Geometry shading - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080, /// Fragment shading - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100, /// Early fragment (depth/stencil) tests - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200, /// Late fragment (depth/stencil) tests - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400, /// Color attachment writes - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800, /// Compute shading - VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000, /// Transfer/copy operations - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000, - VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, /// Indicates host (CPU) is a source/sink of the dependency - - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, /// All stages of the graphics pipeline - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, /// All graphics, compute, copy, and transition commands - - //@extension("VK_NVX_device_generated_commands") // 87 - VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000, - - //@extension("VK_EXT_conditional_rendering") // 82 - VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000, - - //@extension("VK_NV_mesh_shader") // 203 - VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000, - VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000, - - //@extension("VK_NV_ray_tracing") // 166 - VK_PIPELINE_STAGE_RAY_TRACING_BIT_NV = 0x00200000, - - //@extension("VK_NV_shading_rate_image") // 165 - VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00400000, - - //@extension("VK_EXT_fragment_density_map") // 219 - VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000, - - //@extension("VK_EXT_transform_feedback") // 29 - VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000, - - //@extension("VK_NV_ray_tracing") // 166 - VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000, -} - -/// Render pass attachment description flags -type VkFlags VkAttachmentDescriptionFlags -bitfield VkAttachmentDescriptionFlagBits { - VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, /// The attachment may alias physical memory of another attachment in the same renderpass -} - -/// Subpass description flags -type VkFlags VkSubpassDescriptionFlags -bitfield VkSubpassDescriptionFlagBits { - //@extension("VK_NVX_multiview_per_view_attributes") // 98 - VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 0x00000001, - VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002, -} - -/// Command pool creation flags -type VkFlags VkCommandPoolCreateFlags -bitfield VkCommandPoolCreateFlagBits { - VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, /// Command buffers have a short lifetime - VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, /// Command buffers may release their memory individually - - //@vulkan1_1 - VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004, -} - -/// Command pool reset flags -type VkFlags VkCommandPoolResetFlags -bitfield VkCommandPoolResetFlagBits { - VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, /// Release resources owned by the pool -} - -type VkFlags VkCommandBufferResetFlags -bitfield VkCommandBufferResetFlagBits { - VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, /// Release resources owned by the buffer -} - -type VkFlags VkSampleCountFlags -bitfield VkSampleCountFlagBits { - VK_SAMPLE_COUNT_1_BIT = 0x00000001, - VK_SAMPLE_COUNT_2_BIT = 0x00000002, - VK_SAMPLE_COUNT_4_BIT = 0x00000004, - VK_SAMPLE_COUNT_8_BIT = 0x00000008, - VK_SAMPLE_COUNT_16_BIT = 0x00000010, - VK_SAMPLE_COUNT_32_BIT = 0x00000020, - VK_SAMPLE_COUNT_64_BIT = 0x00000040, -} - -type VkFlags VkStencilFaceFlags -bitfield VkStencilFaceFlagBits { - VK_STENCIL_FACE_FRONT_BIT = 0x00000001, /// Front face - VK_STENCIL_FACE_BACK_BIT = 0x00000002, /// Back face - VK_STENCIL_FRONT_AND_BACK = 0x00000003, -} - -/// Instance creation flags -type VkFlags VkInstanceCreateFlags -//bitfield VkInstanceCreateFlagBits { -//} - -/// Device creation flags -type VkFlags VkDeviceCreateFlags -//bitfield VkDeviceCreateFlagBits { -//} - -/// Device queue creation flags -type VkFlags VkDeviceQueueCreateFlags -@vulkan1_1 -bitfield VkDeviceQueueCreateFlagBits { - VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001, -} - -/// Query pool creation flags -type VkFlags VkQueryPoolCreateFlags -//bitfield VkQueryPoolCreateFlagBits { -//} - -/// Buffer view creation flags -type VkFlags VkBufferViewCreateFlags -//bitfield VkBufferViewCreateFlagBits { -//} - -/// Pipeline cache creation flags -type VkFlags VkPipelineCacheCreateFlags -//bitfield VkPipelineCacheCreateFlagBits { -//} - -/// Pipeline shader stage creation flags -type VkFlags VkPipelineShaderStageCreateFlags -//bitfield VkPipelineShaderStageCreateFlagBits { -//} - -/// Descriptor set layout creation flags -type VkFlags VkDescriptorSetLayoutCreateFlags -bitfield VkDescriptorSetLayoutCreateFlagBits { - //@extension("VK_KHR_push_descriptor") // 81 - VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001, - - //@extension("VK_EXT_descriptor_indexing") // 162 - VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = 0x00000002, -} - -/// Pipeline vertex input state creation flags -type VkFlags VkPipelineVertexInputStateCreateFlags -//bitfield VkPipelineVertexInputStateCreateFlagBits { -//} - -/// Pipeline input assembly state creation flags -type VkFlags VkPipelineInputAssemblyStateCreateFlags -//bitfield VkPipelineInputAssemblyStateCreateFlagBits { -//} - -/// Tessellation state creation flags -type VkFlags VkPipelineTessellationStateCreateFlags -//bitfield VkPipelineTessellationStateCreateFlagBits { -//} - -/// Viewport state creation flags -type VkFlags VkPipelineViewportStateCreateFlags -//bitfield VkPipelineViewportStateCreateFlagBits { -//} - -/// Rasterization state creation flags -type VkFlags VkPipelineRasterizationStateCreateFlags -//bitfield VkPipelineRasterizationStateCreateFlagBits { -//} - -/// Multisample state creation flags -type VkFlags VkPipelineMultisampleStateCreateFlags -//bitfield VkPipelineMultisampleStateCreateFlagBits { -//} - -/// Color blend state creation flags -type VkFlags VkPipelineColorBlendStateCreateFlags -//bitfield VkPipelineColorBlendStateCreateFlagBits { -//} - -/// Depth/stencil state creation flags -type VkFlags VkPipelineDepthStencilStateCreateFlags -//bitfield VkPipelineDepthStencilStateCreateFlagBits { -//} - -/// Dynamic state creation flags -type VkFlags VkPipelineDynamicStateCreateFlags -//bitfield VkPipelineDynamicStateCreateFlagBits { -//} - -/// Pipeline layout creation flags -type VkFlags VkPipelineLayoutCreateFlags -//bitfield VkPipelineLayoutCreateFlagBits { -//} - -/// Sampler creation flags -type VkFlags VkSamplerCreateFlags -bitfield VkSamplerCreateFlagBits { - //@extension("VK_EXT_fragment_density_map") // 219 - VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT = 0x00000001, - VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT = 0x00000002, -} - -/// Render pass creation flags -type VkFlags VkRenderPassCreateFlags -//bitfield VkRenderPassCreateFlagBits { -//} - -/// Framebuffer creation flags -type VkFlags VkFramebufferCreateFlags -//bitfield VkFramebufferCreateFlagBits { -//} - -/// Dependency flags -type VkFlags VkDependencyFlags -bitfield VkDependencyFlagBits { - VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, - - //@vulkan1_1 - VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004, - VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002, - - //@extension("VK_KHR_multiview") // 54 - VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = 0x00000002, - - //@extension("VK_KHR_device_group") // 61 - VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = 0x00000004, -} - -/// Cull mode flags -type VkFlags VkCullModeFlags -bitfield VkCullModeFlagBits { - VK_CULL_MODE_NONE = 0x00000000, - VK_CULL_MODE_FRONT_BIT = 0x00000001, - VK_CULL_MODE_BACK_BIT = 0x00000002, - VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, -} - -//@vulkan1_1 flags - -/// Subgroup feature flags -type VkFlags VkSubgroupFeatureFlags -bitfield VkSubgroupFeatureFlagBits { - VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, - VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, - VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, - VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, - VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, - VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, - VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, - VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, - - //@extension("VK_NV_shader_subgroup_partitioned") // 199 - VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, -} - -/// Peer memory feature flags -type VkFlags VkPeerMemoryFeatureFlags -bitfield VkPeerMemoryFeatureFlagBits { - VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001, - VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002, - VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004, - VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008, -} - -/// Memory allocation flags -type VkFlags VkMemoryAllocateFlags -bitfield VkMemoryAllocateFlagBits { - VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001, -} - -type VkFlags VkCommandPoolTrimFlags -//bitfield VkCommandPoolTrimFlagBits { -//} - -type VkFlags VkDescriptorUpdateTemplateCreateFlags -//bitfield VkDescriptorUpdateTemplateCreateFlagBits { -//} - -/// External memory handle type flags -type VkFlags VkExternalMemoryHandleTypeFlags -bitfield VkExternalMemoryHandleTypeFlagBits { - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 0x00000008, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 0x00000010, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040, - - //@extension("VK_EXT_external_memory_host") // 179 - VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT = 0x00000080, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 0x00000100, - - //@extension("VK_EXT_external_memory_dma_buf") // 126 - VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT = 0x00000200, - - //@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130 - VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID = 0x00000400, -} - -/// External memory feature flags -type VkFlags VkExternalMemoryFeatureFlags -bitfield VkExternalMemoryFeatureFlagBits { - VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 0x00000001, - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 0x00000002, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 0x00000004, -} - -/// External fence handle type flags -type VkFlags VkExternalFenceHandleTypeFlags -bitfield VkExternalFenceHandleTypeFlagBits { - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000008, -} - -/// External fence feature flags -type VkFlags VkExternalFenceFeatureFlags -bitfield VkExternalFenceFeatureFlagBits { - VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 0x00000001, - VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 0x00000002, -} - -/// Fence import flags -type VkFlags VkFenceImportFlags -bitfield VkFenceImportFlagBits { - VK_FENCE_IMPORT_TEMPORARY_BIT = 0x00000001, -} - -/// Semaphore import flags -type VkFlags VkSemaphoreImportFlags -bitfield VkSemaphoreImportFlagBits { - VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 0x00000001, -} - -/// External semaphore handle type flags -type VkFlags VkExternalSemaphoreHandleTypeFlags -bitfield VkExternalSemaphoreHandleTypeFlagBits { - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 0x00000008, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000010, -} - -/// External semaphore feature flags -type VkFlags VkExternalSemaphoreFeatureFlags -bitfield VkExternalSemaphoreFeatureFlagBits { - VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 0x00000001, - VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 0x00000002, -} - -@extension("VK_KHR_surface") // 1 -type VkFlags VkSurfaceTransformFlagsKHR -@extension("VK_KHR_surface") // 1 -bitfield VkSurfaceTransformFlagBitsKHR { - VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001, - VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, - VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004, - VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080, - VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, -} - -@extension("VK_KHR_surface") // 1 -type VkFlags VkCompositeAlphaFlagsKHR -@extension("VK_KHR_surface") // 1 -bitfield VkCompositeAlphaFlagBitsKHR { - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, - VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002, - VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, -} - -@extension("VK_KHR_swapchain") // 2 -type VkFlags VkSwapchainCreateFlagsKHR -@extension("VK_KHR_swapchain") // 2 -bitfield VkSwapchainCreateFlagBitsKHR { - //@vulkan1_1 - VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 0x00000001, - VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002, - - //@extension("VK_KHR_swapchain_mutable_format") // 201 - VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR = 0x00000004, -} - -@vulkan1_1 -@extension("VK_KHR_swapchain") // 2 -type VkFlags VkDeviceGroupPresentModeFlagsKHR -@vulkan1_1 -@extension("VK_KHR_swapchain") // 2 -bitfield VkDeviceGroupPresentModeFlagBitsKHR { - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 0x00000001, - VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 0x00000002, - VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 0x00000004, - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008, -} - -@extension("VK_KHR_display") // 3 -type VkFlags VkDisplayPlaneAlphaFlagsKHR -@extension("VK_KHR_display") // 3 -bitfield VkDisplayPlaneAlphaFlagBitsKHR { - VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, - VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002, - VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004, - VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008, -} - -@extension("VK_KHR_display") // 3 -type VkFlags VkDisplaySurfaceCreateFlagsKHR -//@extension("VK_KHR_display") // 3 -//bitfield VkDisplaySurfaceCreateFlagBitsKHR { -//} - -@extension("VK_KHR_display") // 3 -type VkFlags VkDisplayModeCreateFlagsKHR -//@extension("VK_KHR_display") // 3 -//bitfield VkDisplayModeCreateFlagBitsKHR { -//} - -@extension("VK_KHR_xlib_surface") // 5 -type VkFlags VkXlibSurfaceCreateFlagsKHR -//@extension("VK_KHR_xlib_surface") // 5 -//bitfield VkXlibSurfaceCreateFlagBitsKHR { -//} - -@extension("VK_KHR_xcb_surface") // 6 -type VkFlags VkXcbSurfaceCreateFlagsKHR -//@extension("VK_KHR_xcb_surface") // 6 -//bitfield VkXcbSurfaceCreateFlagBitsKHR { -//} - -@extension("VK_KHR_wayland_surface") // 7 -type VkFlags VkWaylandSurfaceCreateFlagsKHR -//@extension("VK_KHR_wayland_surface") // 7 -//bitfield VkWaylandSurfaceCreateFlagBitsKHR { -//} - -@extension("VK_KHR_android_surface") // 9 -type VkFlags VkAndroidSurfaceCreateFlagsKHR -//@extension("VK_KHR_android_surface") // 9 -//bitfield VkAndroidSurfaceCreateFlagBitsKHR { -//} - -@extension("VK_KHR_win32_surface") // 10 -type VkFlags VkWin32SurfaceCreateFlagsKHR -//@extension("VK_KHR_win32_surface") // 10 -//bitfield VkWin32SurfaceCreateFlagBitsKHR { -//} - -@extension("VK_ANDROID_native_buffer") // 11 -type VkFlags VkSwapchainImageUsageFlagsANDROID -@extension("VK_ANDROID_native_buffer") // 11 -bitfield VkSwapchainImageUsageFlagBitsANDROID { - VK_SWAPCHAIN_IMAGE_USAGE_FLAGS_SHARED_BIT_ANDROID = 0x00000001, -} - -@extension("VK_EXT_debug_report") // 12 -type VkFlags VkDebugReportFlagsEXT -@extension("VK_EXT_debug_report") // 12 -bitfield VkDebugReportFlagBitsEXT { - VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001, - VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002, - VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004, - VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008, - VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, -} - -@extension("VK_EXT_transform_feedback") // 29 -type VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT -//@extension("VK_EXT_transform_feedback") // 29 -//bitfield VkPipelineRasterizationStateStreamCreateFlagBitsEXT { -//} - -@extension("VK_NV_external_memory_capabilities") // 56 -type VkFlags VkExternalMemoryHandleTypeFlagsNV -@extension("VK_NV_external_memory_capabilities") // 56 -bitfield VkExternalMemoryHandleTypeFlagBitsNV { - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008, -} - -@extension("VK_NV_external_memory_capabilities") // 56 -type VkFlags VkExternalMemoryFeatureFlagsNV -@extension("VK_NV_external_memory_capabilities") // 56 -bitfield VkExternalMemoryFeatureFlagBitsNV { - VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001, - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004, -} - -@extension("VK_KHR_device_group") // 61 -type VkFlags VkPeerMemoryFeatureFlagsKHR -@extension("VK_KHR_device_group") // 61 -bitfield VkPeerMemoryFeatureFlagBitsKHR { - VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = 0x00000001, - VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = 0x00000002, - VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = 0x00000004, - VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = 0x00000008, -} - -@extension("VK_KHR_device_group") // 61 -type VkFlags VkMemoryAllocateFlagsKHR -@extension("VK_KHR_device_group") // 61 -bitfield VkMemoryAllocateFlagBitsKHR { - VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = 0x00000001, -} - -@extension("VK_NN_vi_surface") // 63 -type VkFlags VkViSurfaceCreateFlagsNN -//@extension("VK_NN_vi_surface") // 63 -//bitfield VkViSurfaceCreateFlagBitsNN { -//} - -@extension("VK_KHR_maintenance1") // 70 -type VkFlags VkCommandPoolTrimFlagsKHR -//@extension("VK_KHR_maintenance1") // 70 -//bitfield VkCommandPoolTrimFlagBitsKHR { -//} - -@extension("VK_KHR_external_memory_capabilities") // 72 -type VkFlags VkExternalMemoryHandleTypeFlagsKHR -@extension("VK_KHR_external_memory_capabilities") // 72 -bitfield VkExternalMemoryHandleTypeFlagBitsKHR { - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR = 0x00000008, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR = 0x00000010, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR = 0x00000020, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR = 0x00000040, -} - -@extension("VK_KHR_external_memory_capabilities") // 72 -type VkFlags VkExternalMemoryFeatureFlagsKHR -@extension("VK_KHR_external_memory_capabilities") // 72 -bitfield VkExternalMemoryFeatureFlagBitsKHR { - VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = 0x00000001, - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = 0x00000002, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = 0x00000004, -} - -@extension("VK_KHR_external_semaphore_capabilities") // 77 -type VkFlags VkExternalSemaphoreHandleTypeFlagsKHR -@extension("VK_KHR_external_semaphore_capabilities") // 77 -bitfield VkExternalSemaphoreHandleTypeFlagBitsKHR { - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001 - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002 - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004 - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = 0x00000008 - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHR = 0x00000010 -} - -@extension("VK_KHR_external_semaphore_capabilities") // 77 -type VkFlags VkExternalSemaphoreFeatureFlagsKHR -@extension("VK_KHR_external_semaphore_capabilities") // 77 -bitfield VkExternalSemaphoreFeatureFlagBitsKHR { - VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = 0x00000001, - VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = 0x00000002, -} - -@extension("VK_KHR_external_semaphore") // 78 -type VkFlags VkSemaphoreImportFlagsKHR -@extension("VK_KHR_external_semaphore") // 78 -bitfield VkSemaphoreImportFlagBitsKHR { - VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = 0x00000001, -} - -@extension("VK_EXT_conditional_rendering") // 82 -type VkFlags VkConditionalRenderingFlagsEXT -@extension("VK_EXT_conditional_rendering") // 82 -bitfield VkConditionalRenderingFlagBitsEXT { - VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT = 0x00000001, -} - -@extension("VK_KHR_descriptor_update_template") // 86 -type VkFlags VkDescriptorUpdateTemplateCreateFlagsKHR -//@extension("VK_KHR_descriptor_update_template") // 86 -//bitfield VkDescriptorUpdateTemplateCreateFlagBitsKHR { -//} - -@extension("VK_NVX_device_generated_commands") // 87 -type VkFlags VkIndirectCommandsLayoutUsageFlagsNVX -@extension("VK_NVX_device_generated_commands") // 87 -bitfield VkIndirectCommandsLayoutUsageFlagBitsNVX { - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008, -} - -@extension("VK_NVX_device_generated_commands") // 87 -type VkFlags VkObjectEntryUsageFlagsNVX -@extension("VK_NVX_device_generated_commands") // 87 -bitfield VkObjectEntryUsageFlagBitsNVX { - VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001, - VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002, -} - -@extension("VK_EXT_display_surface_counter") // 91 -type VkFlags VkSurfaceCounterFlagsEXT -@extension("VK_EXT_display_surface_counter") // 91 -bitfield VkSurfaceCounterFlagBitsEXT { - VK_SURFACE_COUNTER_VBLANK_EXT = 0x00000001, -} - -@extension("VK_NV_viewport_swizzle") // 99 -type VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV -//@extension("VK_NV_viewport_swizzle") // 99 -//bitfield VkPipelineViewportSwizzleStateCreateFlagBitsNV { -//} - -@extension("VK_EXT_discard_rectangles") // 100 -type VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT -//@extension("VK_EXT_discard_rectangles") // 100 -//bitfield VkPipelineDiscardRectangleStateCreateFlagBitsEXT { -//} - -@extension("VK_EXT_conservative_rasterization") // 102 -type VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT -//@extension("VK_EXT_conservative_rasterization") // 102 -//bitfield VkPipelineRasterizationConservativeStateCreateFlagBitsEXT { -//} - -@extension("VK_KHR_external_fence_capabilities") // 113 -type VkFlags VkExternalFenceHandleTypeFlagsKHR -@extension("VK_KHR_external_fence_capabilities") // 113 -bitfield VkExternalFenceHandleTypeFlagBitsKHR { - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = 0x00000008, -} - -@extension("VK_KHR_external_fence_capabilities") // 113 -type VkFlags VkExternalFenceFeatureFlagsKHR -@extension("VK_KHR_external_fence_capabilities") // 113 -bitfield VkExternalFenceFeatureFlagBitsKHR { - VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = 0x00000001, - VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = 0x00000002, -} - -@extension("VK_KHR_external_fence") // 114 -type VkFlags VkFenceImportFlagsKHR -@extension("VK_KHR_external_fence") // 114 -bitfield VkFenceImportFlagBitsKHR { - VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = 0x00000001, -} - -@extension("VK_MVK_ios_surface") // 123 -type VkFlags VkIOSSurfaceCreateFlagsMVK -//@extension("VK_MVK_ios_surface") // 123 -//bitfield VkIOSSurfaceCreateFlagBitsMVK { -//} - -@extension("VK_MVK_macos_surface") // 124 -type VkFlags VkMacOSSurfaceCreateFlagsMVK -//@extension("VK_MVK_macos_surface") // 124 -//bitfield VkMacOSSurfaceCreateFlagBitsMVK { -//} - -@extension("VK_EXT_debug_utils") // 129 -type VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT -//@extension("VK_EXT_debug_utils") // 129 -//bitfield VkDebugUtilsMessengerCallbackDataFlagBitsEXT { -//} - -@extension("VK_EXT_debug_utils") // 129 -type VkFlags VkDebugUtilsMessengerCreateFlagsEXT -//@extension("VK_EXT_debug_utils") // 129 -//bitfield VkDebugUtilsMessengerCreateFlagBitsEXT { -//} - -@extension("VK_EXT_debug_utils") // 129 -type VkFlags VkDebugUtilsMessageSeverityFlagsEXT -@extension("VK_EXT_debug_utils") // 129 -bitfield VkDebugUtilsMessageSeverityFlagBitsEXT { - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000, -} - -@extension("VK_EXT_debug_utils") // 129 -type VkFlags VkDebugUtilsMessageTypeFlagsEXT -@extension("VK_EXT_debug_utils") // 129 -bitfield VkDebugUtilsMessageTypeFlagBitsEXT { - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001, - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002, - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004, -} - -@extension("VK_NV_fragment_coverage_to_color") // 150 -type VkFlags VkPipelineCoverageToColorStateCreateFlagsNV -@extension("VK_NV_fragment_coverage_to_color") // 150 -//bitfield VkPipelineCoverageToColorStateCreateFlagBitsNV { -//} - -@extension("VK_NV_framebuffer_mixed_samples") // 153 -type VkFlags VkPipelineCoverageModulationStateCreateFlagsNV -@extension("VK_NV_framebuffer_mixed_samples") // 153 -//bitfield VkPipelineCoverageModulationStateCreateFlagBitsNV { -//} - -@extension("VK_EXT_validation_cache") // 161 -type VkFlags VkValidationCacheCreateFlagsEXT -@extension("VK_EXT_validation_cache") // 161 -//bitfield VkValidationCacheCreateFlagBitsEXT { -//} - -@extension("VK_EXT_descriptor_indexing") // 162 -type VkFlags VkDescriptorBindingFlagsEXT -@extension("VK_EXT_descriptor_indexing") // 162 -bitfield VkDescriptorBindingFlagBitsEXT { - VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = 0x00000001, - VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = 0x00000002, - VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = 0x00000004, - VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = 0x00000008, -} - -@extension("VK_NV_ray_tracing") // 166 -type VkFlags VkGeometryFlagsNV -@extension("VK_NV_ray_tracing") // 166 -bitfield VkGeometryFlagBitsNV { - VK_GEOMETRY_OPAQUE_BIT_NV = 0x00000001, - VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = 0x00000002, -} - -@extension("VK_NV_ray_tracing") // 166 -type VkFlags VkGeometryInstanceFlagsNV -@extension("VK_NV_ray_tracing") // 166 -bitfield VkGeometryInstanceFlagBitsNV { - VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = 0x00000001, - VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = 0x00000002, - VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = 0x00000004, - VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = 0x00000008, -} - -@extension("VK_NV_ray_tracing") // 166 -type VkFlags VkBuildAccelerationStructureFlagsNV -@extension("VK_NV_ray_tracing") // 166 -bitfield VkBuildAccelerationStructureFlagBitsNV { - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = 0x00000001, - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = 0x00000002, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = 0x00000004, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = 0x00000008, - VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = 0x00000010, -} - -@extension("VK_FUCHSIA_imagepipe_surface") // 215 -type VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA -//@extension("VK_FUCHSIA_imagepipe_surface") // 215 -//bitfield VkImagePipeSurfaceCreateFlagBitsFUCHSIA { -//} - -////////////////// -// Structures // -////////////////// - -class VkOffset2D { - s32 x - s32 y -} - -class VkOffset3D { - s32 x - s32 y - s32 z -} - -class VkExtent2D { - u32 width - u32 height -} - -class VkExtent3D { - u32 width - u32 height - u32 depth -} - -class VkViewport { - f32 x - f32 y - f32 width - f32 height - f32 minDepth - f32 maxDepth -} - -class VkRect2D { - VkOffset2D offset - VkExtent2D extent -} - -class VkClearRect { - VkRect2D rect - u32 baseArrayLayer - u32 layerCount -} - -class VkComponentMapping { - VkComponentSwizzle r - VkComponentSwizzle g - VkComponentSwizzle b - VkComponentSwizzle a -} - -class VkPhysicalDeviceProperties { - u32 apiVersion - u32 driverVersion - u32 vendorID - u32 deviceID - VkPhysicalDeviceType deviceType - char[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE] deviceName - u8[VK_UUID_SIZE] pipelineCacheUUID - VkPhysicalDeviceLimits limits - VkPhysicalDeviceSparseProperties sparseProperties -} - -class VkExtensionProperties { - char[VK_MAX_EXTENSION_NAME_SIZE] extensionName /// extension name - u32 specVersion /// version of the extension specification implemented -} - -class VkLayerProperties { - char[VK_MAX_EXTENSION_NAME_SIZE] layerName /// layer name - u32 specVersion /// version of the layer specification implemented - u32 implementationVersion /// build or release version of the layer's library - char[VK_MAX_DESCRIPTION_SIZE] description /// Free-form description of the layer -} - -class VkSubmitInfo { - VkStructureType sType /// Type of structure. Should be VK_STRUCTURE_TYPE_SUBMIT_INFO - const void* pNext /// Next structure in chain - u32 waitSemaphoreCount - const VkSemaphore* pWaitSemaphores - const VkPipelineStageFlags* pWaitDstStageMask - u32 commandBufferCount - const VkCommandBuffer* pCommandBuffers - u32 signalSemaphoreCount - const VkSemaphore* pSignalSemaphores -} - -class VkApplicationInfo { - VkStructureType sType /// Type of structure. Should be VK_STRUCTURE_TYPE_APPLICATION_INFO - const void* pNext /// Next structure in chain - const char* pApplicationName - u32 applicationVersion - const char* pEngineName - u32 engineVersion - u32 apiVersion -} - -class VkAllocationCallbacks { - void* pUserData - PFN_vkAllocationFunction pfnAllocation - PFN_vkReallocationFunction pfnReallocation - PFN_vkFreeFunction pfnFree - PFN_vkInternalAllocationNotification pfnInternalAllocation - PFN_vkInternalFreeNotification pfnInternalFree -} - -class VkDeviceQueueCreateInfo { - VkStructureType sStype /// Should be VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkDeviceQueueCreateFlags flags - u32 queueFamilyIndex - u32 queueCount - const f32* pQueuePriorities -} - -class VkDeviceCreateInfo { - VkStructureType sType /// Should be VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkDeviceCreateFlags flags - u32 queueCreateInfoCount - const VkDeviceQueueCreateInfo* pQueueCreateInfos - u32 enabledLayerCount - const char* const* ppEnabledLayerNames /// Ordered list of layer names to be enabled - u32 enabledExtensionCount - const char* const* ppEnabledExtensionNames - const VkPhysicalDeviceFeatures* pEnabledFeatures -} - -class VkInstanceCreateInfo { - VkStructureType sType /// Should be VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkInstanceCreateFlags flags - const VkApplicationInfo* pApplicationInfo - u32 enabledLayerCount - const char* const* ppEnabledLayerNames /// Ordered list of layer names to be enabled - u32 enabledExtensionCount - const char* const* ppEnabledExtensionNames /// Extension names to be enabled -} - -class VkQueueFamilyProperties { - VkQueueFlags queueFlags /// Queue flags - u32 queueCount - u32 timestampValidBits - VkExtent3D minImageTransferGranularity -} - -class VkPhysicalDeviceMemoryProperties { - u32 memoryTypeCount - VkMemoryType[VK_MAX_MEMORY_TYPES] memoryTypes - u32 memoryHeapCount - VkMemoryHeap[VK_MAX_MEMORY_HEAPS] memoryHeaps -} - -class VkMemoryAllocateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO - const void* pNext /// Pointer to next structure - VkDeviceSize allocationSize /// Size of memory allocation - u32 memoryTypeIndex /// Index of the of the memory type to allocate from -} - -class VkMemoryRequirements { - VkDeviceSize size /// Specified in bytes - VkDeviceSize alignment /// Specified in bytes - u32 memoryTypeBits /// Bitfield of the allowed memory type indices into memoryTypes[] for this object -} - -class VkSparseImageFormatProperties { - VkImageAspectFlagBits aspectMask - VkExtent3D imageGranularity - VkSparseImageFormatFlags flags -} - -class VkSparseImageMemoryRequirements { - VkSparseImageFormatProperties formatProperties - u32 imageMipTailFirstLod - VkDeviceSize imageMipTailSize /// Specified in bytes, must be a multiple of image block size / alignment - VkDeviceSize imageMipTailOffset /// Specified in bytes, must be a multiple of image block size / alignment - VkDeviceSize imageMipTailStride /// Specified in bytes, must be a multiple of image block size / alignment -} - -class VkMemoryType { - VkMemoryPropertyFlags propertyFlags /// Memory properties of this memory type - u32 heapIndex /// Index of the memory heap allocations of this memory type are taken from -} - -class VkMemoryHeap { - VkDeviceSize size /// Available memory in the heap - VkMemoryHeapFlags flags /// Flags for the heap -} - -class VkMappedMemoryRange { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE - const void* pNext /// Pointer to next structure - VkDeviceMemory memory /// Mapped memory object - VkDeviceSize offset /// Offset within the mapped memory the range starts from - VkDeviceSize size /// Size of the range within the mapped memory -} - -class VkFormatProperties { - VkFormatFeatureFlags linearTilingFeatures /// Format features in case of linear tiling - VkFormatFeatureFlags optimalTilingFeatures /// Format features in case of optimal tiling - VkFormatFeatureFlags bufferFeatures /// Format features supported by buffers -} - -class VkImageFormatProperties { - VkExtent3D maxExtent /// max image dimensions for this resource type - u32 maxMipLevels /// max number of mipmap levels for this resource type - u32 maxArrayLayers /// max array layers for this resource type - VkSampleCountFlags sampleCounts /// supported sample counts for this resource type - VkDeviceSize maxResourceSize /// max size (in bytes) of this resource type -} - -class VkDescriptorImageInfo { - VkSampler sampler - VkImageView imageView - VkImageLayout imageLayout -} - -class VkDescriptorBufferInfo { - VkBuffer buffer /// Buffer used for this descriptor when the descriptor is UNIFORM_BUFFER[_DYNAMIC] - VkDeviceSize offset /// Base offset from buffer start in bytes to update in the descriptor set. - VkDeviceSize range /// Size in bytes of the buffer resource for this descriptor update. -} - -class VkWriteDescriptorSet { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET - const void* pNext /// Pointer to next structure - VkDescriptorSet dstSet /// Destination descriptor set - u32 dstBinding /// Binding within the destination descriptor set to write - u32 dstArrayElement /// Array element within the destination binding to write - u32 descriptorCount /// Number of descriptors to write (determines the size of the array pointed by ) - VkDescriptorType descriptorType /// Descriptor type to write (determines which fields of the array pointed by are going to be used) - const VkDescriptorImageInfo* pImageInfo - const VkDescriptorBufferInfo* pBufferInfo - const VkBufferView* pTexelBufferView -} - -class VkCopyDescriptorSet { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET - const void* pNext /// Pointer to next structure - VkDescriptorSet srcSet /// Source descriptor set - u32 srcBinding /// Binding within the source descriptor set to copy from - u32 srcArrayElement /// Array element within the source binding to copy from - VkDescriptorSet dstSet /// Destination descriptor set - u32 dstBinding /// Binding within the destination descriptor set to copy to - u32 dstArrayElement /// Array element within the destination binding to copy to - u32 descriptorCount /// Number of descriptors to copy -} - -class VkBufferCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO - const void* pNext /// Pointer to next structure. - VkBufferCreateFlags flags /// Buffer creation flags - VkDeviceSize size /// Specified in bytes - VkBufferUsageFlags usage /// Buffer usage flags - VkSharingMode sharingMode - u32 queueFamilyIndexCount - const u32* pQueueFamilyIndices -} - -class VkBufferViewCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO - const void* pNext /// Pointer to next structure. - VkBufferViewCreateFlags flags - VkBuffer buffer - VkFormat format /// Optionally specifies format of elements - VkDeviceSize offset /// Specified in bytes - VkDeviceSize range /// View size specified in bytes -} - -class VkImageSubresource { - VkImageAspectFlagBits aspectMask - u32 mipLevel - u32 arrayLayer -} - -class VkImageSubresourceRange { - VkImageAspectFlags aspectMask - u32 baseMipLevel - u32 levelCount - u32 baseArrayLayer - u32 layerCount -} - -class VkMemoryBarrier { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_MEMORY_BARRIER - const void* pNext /// Pointer to next structure. - VkAccessFlags srcAccessMask - VkAccessFlags dstAccessMask -} - -class VkBufferMemoryBarrier { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER - const void* pNext /// Pointer to next structure. - VkAccessFlags srcAccessMask - VkAccessFlags dstAccessMask - u32 srcQueueFamilyIndex /// Queue family to transition ownership from - u32 dstQueueFamilyIndex /// Queue family to transition ownership to - VkBuffer buffer /// Buffer to sync - VkDeviceSize offset /// Offset within the buffer to sync - VkDeviceSize size /// Amount of bytes to sync -} - -class VkImageMemoryBarrier { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER - const void* pNext /// Pointer to next structure. - VkAccessFlags srcAccessMask - VkAccessFlags dstAccessMask - VkImageLayout oldLayout /// Current layout of the image - VkImageLayout newLayout /// New layout to transition the image to - u32 srcQueueFamilyIndex /// Queue family to transition ownership from - u32 dstQueueFamilyIndex /// Queue family to transition ownership to - VkImage image /// Image to sync - VkImageSubresourceRange subresourceRange /// Subresource range to sync -} - -class VkImageCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO - const void* pNext /// Pointer to next structure. - VkImageCreateFlags flags /// Image creation flags - VkImageType imageType - VkFormat format - VkExtent3D extent - u32 mipLevels - u32 arrayLayers - VkSampleCountFlagBits samples - VkImageTiling tiling - VkImageUsageFlags usage /// Image usage flags - VkSharingMode sharingMode /// Cross-queue-family sharing mode - u32 queueFamilyIndexCount /// Number of queue families to share across - const u32* pQueueFamilyIndices /// Array of queue family indices to share across - VkImageLayout initialLayout /// Initial image layout for all subresources -} - -class VkSubresourceLayout { - VkDeviceSize offset /// Specified in bytes - VkDeviceSize size /// Specified in bytes - VkDeviceSize rowPitch /// Specified in bytes - VkDeviceSize arrayPitch /// Specified in bytes - VkDeviceSize depthPitch /// Specified in bytes -} - -class VkImageViewCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO - const void* pNext /// Pointer to next structure - VkImageViewCreateFlags flags - VkImage image - VkImageViewType viewType - VkFormat format - VkComponentMapping components - VkImageSubresourceRange subresourceRange -} - -class VkBufferCopy { - VkDeviceSize srcOffset /// Specified in bytes - VkDeviceSize dstOffset /// Specified in bytes - VkDeviceSize size /// Specified in bytes -} - -class VkSparseMemoryBind { - VkDeviceSize resourceOffset /// Specified in bytes - VkDeviceSize size /// Specified in bytes - VkDeviceMemory memory - VkDeviceSize memoryOffset /// Specified in bytes - VkSparseMemoryBindFlags flags -} - -class VkSparseImageMemoryBind { - VkImageSubresource subresource - VkOffset3D offset - VkExtent3D extent - VkDeviceMemory memory - VkDeviceSize memoryOffset /// Specified in bytes - VkSparseMemoryBindFlags flags -} - -class VkSparseBufferMemoryBindInfo { - VkBuffer buffer - u32 bindCount - const VkSparseMemoryBind* pBinds -} - -class VkSparseImageOpaqueMemoryBindInfo { - VkImage image - u32 bindCount - const VkSparseMemoryBind* pBinds -} - -class VkSparseImageMemoryBindInfo { - VkImage image - u32 bindCount - const VkSparseMemoryBind* pBinds -} - -class VkBindSparseInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_BIND_SPARSE_INFO - const void* pNext - u32 waitSemaphoreCount - const VkSemaphore* pWaitSemaphores - u32 numBufferBinds - const VkSparseBufferMemoryBindInfo* pBufferBinds - u32 numImageOpaqueBinds - const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds - u32 numImageBinds - const VkSparseImageMemoryBindInfo* pImageBinds - u32 signalSemaphoreCount - const VkSemaphore* pSignalSemaphores -} - -class VkImageSubresourceLayers { - VkImageAspectFlags aspectMask - u32 mipLevel - u32 baseArrayLayer - u32 layerCount -} - -class VkImageCopy { - VkImageSubresourceLayers srcSubresource - VkOffset3D srcOffset /// Specified in pixels for both compressed and uncompressed images - VkImageSubresourceLayers dstSubresource - VkOffset3D dstOffset /// Specified in pixels for both compressed and uncompressed images - VkExtent3D extent /// Specified in pixels for both compressed and uncompressed images -} - -class VkImageBlit { - VkImageSubresourceLayers srcSubresource - VkOffset3D[2] srcOffsets - VkImageSubresourceLayers dstSubresource - VkOffset3D[2] dstOffsets -} - -class VkBufferImageCopy { - VkDeviceSize bufferOffset /// Specified in bytes - u32 bufferRowLength /// Specified in texels - u32 bufferImageHeight - VkImageSubresourceLayers imageSubresource - VkOffset3D imageOffset /// Specified in pixels for both compressed and uncompressed images - VkExtent3D imageExtent /// Specified in pixels for both compressed and uncompressed images -} - -class VkImageResolve { - VkImageSubresourceLayers srcSubresource - VkOffset3D srcOffset - VkImageSubresourceLayers dstSubresource - VkOffset3D dstOffset - VkExtent3D extent -} - -class VkShaderModuleCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkShaderModuleCreateFlags flags /// Reserved - platform.size_t codeSize /// Specified in bytes - const u32* pCode /// Binary code of size codeSize -} - -class VkDescriptorSetLayoutBinding { - u32 binding - VkDescriptorType descriptorType /// Type of the descriptors in this binding - u32 descriptorCount /// Number of descriptors in this binding - VkShaderStageFlags stageFlags /// Shader stages this binding is visible to - const VkSampler* pImmutableSamplers /// Immutable samplers (used if descriptor type is SAMPLER or COMBINED_IMAGE_SAMPLER, is either NULL or contains number of elements) -} - -class VkDescriptorSetLayoutCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO - const void* pNext /// Pointer to next structure - VkDescriptorSetLayoutCreateFlags flags - u32 bindingCount /// Number of bindings in the descriptor set layout - const VkDescriptorSetLayoutBinding* pBindings /// Array of descriptor set layout bindings -} - -class VkDescriptorPoolSize { - VkDescriptorType type - u32 descriptorCount -} - -class VkDescriptorPoolCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO - const void* pNext /// Pointer to next structure - VkDescriptorPoolCreateFlags flags - u32 maxSets - u32 poolSizeCount - const VkDescriptorPoolSize* pPoolSizes -} - -class VkDescriptorSetAllocateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO - const void* pNext /// Pointer to next structure - VkDescriptorPool descriptorPool - u32 setCount - const VkDescriptorSetLayout* pSetLayouts -} - -class VkSpecializationMapEntry { - u32 constantID /// The SpecConstant ID specified in the BIL - u32 offset /// Offset of the value in the data block - platform.size_t size /// Size in bytes of the SpecConstant -} - -class VkSpecializationInfo { - u32 mapEntryCount /// Number of entries in the map - const VkSpecializationMapEntry* pMapEntries /// Array of map entries - platform.size_t dataSize /// Size in bytes of pData - const void* pData /// Pointer to SpecConstant data -} - -class VkPipelineShaderStageCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineShaderStageCreateFlags flags - VkShaderStageFlagBits stage - VkShaderModule module - const char* pName - const VkSpecializationInfo* pSpecializationInfo -} - -class VkComputePipelineCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineCreateFlags flags /// Pipeline creation flags - VkPipelineShaderStageCreateInfo stage - VkPipelineLayout layout /// Interface layout of the pipeline - VkPipeline basePipelineHandle /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of - s32 basePipelineIndex /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of -} - -class VkVertexInputBindingDescription { - u32 binding /// Vertex buffer binding id - u32 stride /// Distance between vertices in bytes (0 = no advancement) - VkVertexInputRate inputRate /// Rate at which binding is incremented -} - -class VkVertexInputAttributeDescription { - u32 location /// location of the shader vertex attrib - u32 binding /// Vertex buffer binding id - VkFormat format /// format of source data - u32 offset /// Offset of first element in bytes from base of vertex -} - -class VkPipelineVertexInputStateCreateInfo { - VkStructureType sType /// Should be VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineVertexInputStateCreateFlags flags - u32 vertexBindingDescriptionCount /// number of bindings - const VkVertexInputBindingDescription* pVertexBindingDescriptions - u32 vertexAttributeDescriptionCount /// number of attributes - const VkVertexInputAttributeDescription* pVertexAttributeDescriptions -} - -class VkPipelineInputAssemblyStateCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineInputAssemblyStateCreateFlags flags - VkPrimitiveTopology topology - VkBool32 primitiveRestartEnable -} - -class VkPipelineTessellationStateCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineTessellationStateCreateFlags flags - u32 patchControlPoints -} - -class VkPipelineViewportStateCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineViewportStateCreateFlags flags - u32 viewportCount - const VkViewport* pViewports - u32 scissorCount - const VkRect2D* pScissors -} - -class VkPipelineRasterizationStateCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineRasterizationStateCreateFlags flags - VkBool32 depthClampEnable - VkBool32 rasterizerDiscardEnable - VkPolygonMode polygonMode /// optional (GL45) - VkCullModeFlags cullMode - VkFrontFace frontFace - VkBool32 depthBiasEnable - f32 depthBiasConstantFactor - f32 depthBiasClamp - f32 depthBiasSlopeFactor - f32 lineWidth -} - -class VkPipelineMultisampleStateCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineMultisampleStateCreateFlags flags - VkSampleCountFlagBits rasterizationSamples /// Number of samples used for rasterization - VkBool32 sampleShadingEnable /// optional (GL45) - f32 minSampleShading /// optional (GL45) - const VkSampleMask* pSampleMask - VkBool32 alphaToCoverageEnable - VkBool32 alphaToOneEnable -} - -class VkPipelineColorBlendAttachmentState { - VkBool32 blendEnable - VkBlendFactor srcColorBlendFactor - VkBlendFactor dstColorBlendFactor - VkBlendOp colorBlendOp - VkBlendFactor srcAlphaBlendFactor - VkBlendFactor dstAlphaBlendFactor - VkBlendOp alphaBlendOp - VkColorComponentFlags colorWriteMask -} - -class VkPipelineColorBlendStateCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineColorBlendStateCreateFlags flags - VkBool32 logicOpEnable - VkLogicOp logicOp - u32 attachmentCount /// # of pAttachments - const VkPipelineColorBlendAttachmentState* pAttachments - f32[4] blendConstants -} - -class VkStencilOpState { - VkStencilOp failOp - VkStencilOp passOp - VkStencilOp depthFailOp - VkCompareOp compareOp - u32 compareMask - u32 writeMask - u32 reference -} - -class VkPipelineDepthStencilStateCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineDepthStencilStateCreateFlags flags - VkBool32 depthTestEnable - VkBool32 depthWriteEnable - VkCompareOp depthCompareOp - VkBool32 depthBoundsTestEnable /// optional (depth_bounds_test) - VkBool32 stencilTestEnable - VkStencilOpState front - VkStencilOpState back - f32 minDepthBounds - f32 maxDepthBounds -} - -class VkPipelineDynamicStateCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineDynamicStateCreateFlags flags - u32 dynamicStateCount - const VkDynamicState* pDynamicStates -} - -class VkGraphicsPipelineCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineCreateFlags flags /// Pipeline creation flags - u32 stageCount - const VkPipelineShaderStageCreateInfo* pStages /// One entry for each active shader stage - const VkPipelineVertexInputStateCreateInfo* pVertexInputState - const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState - const VkPipelineTessellationStateCreateInfo* pTessellationState - const VkPipelineViewportStateCreateInfo* pViewportState - const VkPipelineRasterizationStateCreateInfo* pRasterizationState - const VkPipelineMultisampleStateCreateInfo* pMultisampleState - const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState - const VkPipelineColorBlendStateCreateInfo* pColorBlendState - const VkPipelineDynamicStateCreateInfo* pDynamicState - VkPipelineLayout layout /// Interface layout of the pipeline - VkRenderPass renderPass - u32 subpass - VkPipeline basePipelineHandle /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of - s32 basePipelineIndex /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of -} - -class VkPipelineCacheCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineCacheCreateFlags flags - platform.size_t initialDataSize /// Size of initial data to populate cache, in bytes - const void* pInitialData /// Initial data to populate cache -} - -class VkPushConstantRange { - VkShaderStageFlags stageFlags /// Which stages use the range - u32 offset /// Start of the range, in bytes - u32 size /// Length of the range, in bytes -} - -class VkPipelineLayoutCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO - const void* pNext /// Pointer to next structure - VkPipelineLayoutCreateFlags flags - u32 descriptorSetCount /// Number of descriptor sets interfaced by the pipeline - const VkDescriptorSetLayout* pSetLayouts /// Array of number of descriptor set layout objects defining the layout of the - u32 pushConstantRangeCount /// Number of push-constant ranges used by the pipeline - const VkPushConstantRange* pPushConstantRanges /// Array of pushConstantRangeCount number of ranges used by various shader stages -} - -class VkSamplerCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO - const void* pNext /// Pointer to next structure - VkSamplerCreateFlags flags - VkFilter magFilter /// Filter mode for magnification - VkFilter minFilter /// Filter mode for minifiation - VkSamplerMipmapMode mipmapMode /// Mipmap selection mode - VkSamplerAddressMode addressModeU - VkSamplerAddressMode addressModeV - VkSamplerAddressMode addressModeW - f32 mipLodBias - VkBool32 anisotropyEnable - f32 maxAnisotropy - VkBool32 compareEnable - VkCompareOp compareOp - f32 minLod - f32 maxLod - VkBorderColor borderColor - VkBool32 unnormalizedCoordinates -} - -class VkCommandPoolCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO - const void* pNext /// Pointer to next structure - VkCommandPoolCreateFlags flags /// Command pool creation flags - u32 queueFamilyIndex -} - -class VkCommandBufferAllocateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO - const void* pNext /// Pointer to next structure - VkCommandPool commandPool - VkCommandBufferLevel level - u32 commandBufferCount -} - -class VkCommandBufferInheritanceInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO - const void* pNext /// Pointer to next structure - VkRenderPass renderPass /// Render pass for secondary command buffers - u32 subpass - VkFramebuffer framebuffer /// Framebuffer for secondary command buffers - VkBool32 occlusionQueryEnable - VkQueryControlFlags queryFlags - VkQueryPipelineStatisticFlags pipelineStatistics -} - -class VkCommandBufferBeginInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO - const void* pNext /// Pointer to next structure - VkCommandBufferUsageFlags flags /// Command buffer usage flags - const VkCommandBufferInheritanceInfo* pInheritanceInfo -} - -class VkRenderPassBeginInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO - const void* pNext /// Pointer to next structure - VkRenderPass renderPass - VkFramebuffer framebuffer - VkRect2D renderArea - u32 clearValueCount - const VkClearValue* pClearValues -} - -@union -/// Union allowing specification of floating point, integer, or unsigned integer color data. Actual value selected is based on image/attachment being cleared. -class VkClearColorValue { - f32[4] float32 - s32[4] int32 - u32[4] uint32 -} - -class VkClearDepthStencilValue { - f32 depth - u32 stencil -} - -@union -/// Union allowing specification of color, depth, and stencil color values. Actual value selected is based on attachment being cleared. -class VkClearValue { - VkClearColorValue color - VkClearDepthStencilValue depthStencil -} - -class VkClearAttachment { - VkImageAspectFlags aspectMask - u32 colorAttachment - VkClearValue clearValue -} - -class VkAttachmentDescription { - VkAttachmentDescriptionFlags flags - VkFormat format - VkSampleCountFlagBits samples - VkAttachmentLoadOp loadOp /// Load op for color or depth data - VkAttachmentStoreOp storeOp /// Store op for color or depth data - VkAttachmentLoadOp stencilLoadOp /// Load op for stencil data - VkAttachmentStoreOp stencilStoreOp /// Store op for stencil data - VkImageLayout initialLayout - VkImageLayout finalLayout -} - -class VkAttachmentReference { - u32 attachment - VkImageLayout layout -} - -class VkSubpassDescription { - VkSubpassDescriptionFlags flags - VkPipelineBindPoint pipelineBindPoint /// Must be VK_PIPELINE_BIND_POINT_GRAPHICS for now - u32 inputAttachmentCount - const VkAttachmentReference* pInputAttachments - u32 colorAttachmentCount - const VkAttachmentReference* pColorAttachments - const VkAttachmentReference* pResolveAttachments - const VkAttachmentReference* pDepthStencilAttachment - u32 preserveAttachmentCount - const u32* pPreserveAttachments -} - -class VkSubpassDependency { - u32 srcSubpass - u32 dstSubpass - VkPipelineStageFlags srcStageMask - VkPipelineStageFlags dstStageMask - VkAccessFlags srcAccessMask - VkAccessFlags dstAccessMask - VkDependencyFlags dependencyFlags -} - -class VkRenderPassCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO - const void* pNext /// Pointer to next structure - VkRenderPassCreateFlags flags - u32 attachmentCount - const VkAttachmentDescription* pAttachments - u32 subpassCount - const VkSubpassDescription* pSubpasses - u32 dependencyCount - const VkSubpassDependency* pDependencies -} - -class VkEventCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_EVENT_CREATE_INFO - const void* pNext /// Pointer to next structure - VkEventCreateFlags flags /// Event creation flags -} - -class VkFenceCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_FENCE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkFenceCreateFlags flags /// Fence creation flags -} - -class VkPhysicalDeviceFeatures { - VkBool32 robustBufferAccess /// out of bounds buffer accesses are well defined - VkBool32 fullDrawIndexUint32 /// full 32-bit range of indices for indexed draw calls - VkBool32 imageCubeArray /// image views which are arrays of cube maps - VkBool32 independentBlend /// blending operations are controlled per-attachment - VkBool32 geometryShader /// geometry stage - VkBool32 tessellationShader /// tessellation control and evaluation stage - VkBool32 sampleRateShading /// per-sample shading and interpolation - VkBool32 dualSrcBlend /// blend operations which take two sources - VkBool32 logicOp /// logic operations - VkBool32 multiDrawIndirect /// multi draw indirect - VkBool32 drawIndirectFirstInstance - VkBool32 depthClamp /// depth clamping - VkBool32 depthBiasClamp /// depth bias clamping - VkBool32 fillModeNonSolid /// point and wireframe fill modes - VkBool32 depthBounds /// depth bounds test - VkBool32 wideLines /// lines with width greater than 1 - VkBool32 largePoints /// points with size greater than 1 - VkBool32 alphaToOne /// The fragment alpha channel can be forced to maximum representable alpha value - VkBool32 multiViewport - VkBool32 samplerAnisotropy - VkBool32 textureCompressionETC2 /// ETC texture compression formats - VkBool32 textureCompressionASTC_LDR /// ASTC LDR texture compression formats - VkBool32 textureCompressionBC /// BC1-7 texture compressed formats - VkBool32 occlusionQueryPrecise - VkBool32 pipelineStatisticsQuery /// pipeline statistics query - VkBool32 vertexPipelineStoresAndAtomics - VkBool32 fragmentStoresAndAtomics - VkBool32 shaderTessellationAndGeometryPointSize - VkBool32 shaderImageGatherExtended /// texture gather with run-time values and independent offsets - VkBool32 shaderStorageImageExtendedFormats /// the extended set of formats can be used for storage images - VkBool32 shaderStorageImageMultisample /// multisample images can be used for storage images - VkBool32 shaderStorageImageReadWithoutFormat - VkBool32 shaderStorageImageWriteWithoutFormat - VkBool32 shaderUniformBufferArrayDynamicIndexing /// arrays of uniform buffers can be accessed with dynamically uniform indices - VkBool32 shaderSampledImageArrayDynamicIndexing /// arrays of sampled images can be accessed with dynamically uniform indices - VkBool32 shaderStorageBufferArrayDynamicIndexing /// arrays of storage buffers can be accessed with dynamically uniform indices - VkBool32 shaderStorageImageArrayDynamicIndexing /// arrays of storage images can be accessed with dynamically uniform indices - VkBool32 shaderClipDistance /// clip distance in shaders - VkBool32 shaderCullDistance /// cull distance in shaders - VkBool32 shaderFloat64 /// 64-bit floats (doubles) in shaders - VkBool32 shaderInt64 /// 64-bit integers in shaders - VkBool32 shaderInt16 /// 16-bit integers in shaders - VkBool32 shaderResourceResidency /// shader can use texture operations that return resource residency information (requires sparseNonResident support) - VkBool32 shaderResourceMinLod /// shader can use texture operations that specify minimum resource LOD - VkBool32 sparseBinding /// Sparse resources support: Resource memory can be managed at opaque page level rather than object level - VkBool32 sparseResidencyBuffer /// Sparse resources support: GPU can access partially resident buffers - VkBool32 sparseResidencyImage2D /// Sparse resources support: GPU can access partially resident 2D (non-MSAA non-DepthStencil) images - VkBool32 sparseResidencyImage3D /// Sparse resources support: GPU can access partially resident 3D images - VkBool32 sparseResidency2Samples /// Sparse resources support: GPU can access partially resident MSAA 2D images with 2 samples - VkBool32 sparseResidency4Samples /// Sparse resources support: GPU can access partially resident MSAA 2D images with 4 samples - VkBool32 sparseResidency8Samples /// Sparse resources support: GPU can access partially resident MSAA 2D images with 8 samples - VkBool32 sparseResidency16Samples /// Sparse resources support: GPU can access partially resident MSAA 2D images with 16 samples - VkBool32 sparseResidencyAliased /// Sparse resources support: GPU can correctly access data aliased into multiple locations (opt-in) - VkBool32 variableMultisampleRate - VkBool32 inheritedQueries -} - -class VkPhysicalDeviceLimits { - /// resource maximum sizes - u32 maxImageDimension1D /// max 1D image dimension - u32 maxImageDimension2D /// max 2D image dimension - u32 maxImageDimension3D /// max 3D image dimension - u32 maxImageDimensionCube /// max cubemap image dimension - u32 maxImageArrayLayers /// max layers for image arrays - u32 maxTexelBufferElements - u32 maxUniformBufferRange /// max uniform buffer size (bytes) - u32 maxStorageBufferRange /// max storage buffer size (bytes) - u32 maxPushConstantsSize /// max size of the push constants pool (bytes) - /// memory limits - u32 maxMemoryAllocationCount /// max number of device memory allocations supported - u32 maxSamplerAllocationCount - VkDeviceSize bufferImageGranularity /// Granularity (in bytes) at which buffers and images can be bound to adjacent memory for simultaneous usage - VkDeviceSize sparseAddressSpaceSize /// Total address space available for sparse allocations (bytes) - /// descriptor set limits - u32 maxBoundDescriptorSets /// max number of descriptors sets that can be bound to a pipeline - u32 maxPerStageDescriptorSamplers /// max num of samplers allowed per-stage in a descriptor set - u32 maxPerStageDescriptorUniformBuffers /// max num of uniform buffers allowed per-stage in a descriptor set - u32 maxPerStageDescriptorStorageBuffers /// max num of storage buffers allowed per-stage in a descriptor set - u32 maxPerStageDescriptorSampledImages /// max num of sampled images allowed per-stage in a descriptor set - u32 maxPerStageDescriptorStorageImages /// max num of storage images allowed per-stage in a descriptor set - u32 maxPerStageDescriptorInputAttachments - u32 maxPerStageResources - u32 maxDescriptorSetSamplers /// max num of samplers allowed in all stages in a descriptor set - u32 maxDescriptorSetUniformBuffers /// max num of uniform buffers allowed in all stages in a descriptor set - u32 maxDescriptorSetUniformBuffersDynamic /// max num of dynamic uniform buffers allowed in all stages in a descriptor set - u32 maxDescriptorSetStorageBuffers /// max num of storage buffers allowed in all stages in a descriptor set - u32 maxDescriptorSetStorageBuffersDynamic /// max num of dynamic storage buffers allowed in all stages in a descriptor set - u32 maxDescriptorSetSampledImages /// max num of sampled images allowed in all stages in a descriptor set - u32 maxDescriptorSetStorageImages /// max num of storage images allowed in all stages in a descriptor set - u32 maxDescriptorSetInputAttachments - /// vertex stage limits - u32 maxVertexInputAttributes /// max num of vertex input attribute slots - u32 maxVertexInputBindings /// max num of vertex input binding slots - u32 maxVertexInputAttributeOffset /// max vertex input attribute offset added to vertex buffer offset - u32 maxVertexInputBindingStride /// max vertex input binding stride - u32 maxVertexOutputComponents /// max num of output components written by vertex shader - /// tessellation control stage limits - u32 maxTessellationGenerationLevel /// max level supported by tess primitive generator - u32 maxTessellationPatchSize /// max patch size (vertices) - u32 maxTessellationControlPerVertexInputComponents /// max num of input components per-vertex in TCS - u32 maxTessellationControlPerVertexOutputComponents /// max num of output components per-vertex in TCS - u32 maxTessellationControlPerPatchOutputComponents /// max num of output components per-patch in TCS - u32 maxTessellationControlTotalOutputComponents /// max total num of per-vertex and per-patch output components in TCS - u32 maxTessellationEvaluationInputComponents /// max num of input components per vertex in TES - u32 maxTessellationEvaluationOutputComponents /// max num of output components per vertex in TES - /// geometry stage limits - u32 maxGeometryShaderInvocations /// max invocation count supported in geometry shader - u32 maxGeometryInputComponents /// max num of input components read in geometry stage - u32 maxGeometryOutputComponents /// max num of output components written in geometry stage - u32 maxGeometryOutputVertices /// max num of vertices that can be emitted in geometry stage - u32 maxGeometryTotalOutputComponents /// max total num of components (all vertices) written in geometry stage - /// fragment stage limits - u32 maxFragmentInputComponents /// max num of input compontents read in fragment stage - u32 maxFragmentOutputAttachments /// max num of output attachments written in fragment stage - u32 maxFragmentDualSrcAttachments /// max num of output attachments written when using dual source blending - u32 maxFragmentCombinedOutputResources /// max total num of storage buffers, storage images and output buffers - /// compute stage limits - u32 maxComputeSharedMemorySize /// max total storage size of work group local storage (bytes) - u32[3] maxComputeWorkGroupCount /// max num of compute work groups that may be dispatched by a single command (x,y,z) - u32 maxComputeWorkGroupInvocations /// max total compute invocations in a single local work group - u32[3] maxComputeWorkGroupSize /// max local size of a compute work group (x,y,z) - - u32 subPixelPrecisionBits /// num bits of subpixel precision in screen x and y - u32 subTexelPrecisionBits /// num bits of subtexel precision - u32 mipmapPrecisionBits /// num bits of mipmap precision - - u32 maxDrawIndexedIndexValue /// max index value for indexed draw calls (for 32-bit indices) - u32 maxDrawIndirectCount - - f32 maxSamplerLodBias /// max absolute sampler level of detail bias - f32 maxSamplerAnisotropy /// max degree of sampler anisotropy - - u32 maxViewports /// max number of active viewports - u32[2] maxViewportDimensions /// max viewport dimensions (x,y) - f32[2] viewportBoundsRange /// viewport bounds range (min,max) - u32 viewportSubPixelBits /// num bits of subpixel precision for viewport - - platform.size_t minMemoryMapAlignment /// min required alignment of pointers returned by MapMemory (bytes) - VkDeviceSize minTexelBufferOffsetAlignment /// min required alignment for texel buffer offsets (bytes) - VkDeviceSize minUniformBufferOffsetAlignment /// min required alignment for uniform buffer sizes and offsets (bytes) - VkDeviceSize minStorageBufferOffsetAlignment /// min required alignment for storage buffer offsets (bytes) - - s32 minTexelOffset /// min texel offset for OpTextureSampleOffset - u32 maxTexelOffset /// max texel offset for OpTextureSampleOffset - s32 minTexelGatherOffset /// min texel offset for OpTextureGatherOffset - u32 maxTexelGatherOffset /// max texel offset for OpTextureGatherOffset - f32 minInterpolationOffset /// furthest negative offset for interpolateAtOffset - f32 maxInterpolationOffset /// furthest positive offset for interpolateAtOffset - u32 subPixelInterpolationOffsetBits /// num of subpixel bits for interpolateAtOffset - - u32 maxFramebufferWidth /// max width for a framebuffer - u32 maxFramebufferHeight /// max height for a framebuffer - u32 maxFramebufferLayers /// max layer count for a layered framebuffer - VkSampleCountFlags framebufferColorSampleCounts - VkSampleCountFlags framebufferDepthSampleCounts - VkSampleCountFlags framebufferStencilSampleCounts - VkSampleCountFlags framebufferNoAttachmentSampleCounts - u32 maxColorAttachments /// max num of framebuffer color attachments - - VkSampleCountFlags sampledImageColorSampleCounts - VkSampleCountFlags sampledImageIntegerSampleCounts - VkSampleCountFlags sampledImageDepthSampleCounts - VkSampleCountFlags sampledImageStencilSampleCounts - VkSampleCountFlags storageImageSampleCounts - u32 maxSampleMaskWords /// max num of sample mask words - VkBool32 timestampComputeAndGraphics - - f32 timestampPeriod - - u32 maxClipDistances /// max number of clip distances - u32 maxCullDistances /// max number of cull distances - u32 maxCombinedClipAndCullDistances /// max combined number of user clipping - - u32 discreteQueuePriorities - - f32[2] pointSizeRange /// range (min,max) of supported point sizes - f32[2] lineWidthRange /// range (min,max) of supported line widths - f32 pointSizeGranularity /// granularity of supported point sizes - f32 lineWidthGranularity /// granularity of supported line widths - VkBool32 strictLines - VkBool32 standardSampleLocations - - VkDeviceSize optimalBufferCopyOffsetAlignment - VkDeviceSize optimalBufferCopyRowPitchAlignment - VkDeviceSize nonCoherentAtomSize -} - -class VkPhysicalDeviceSparseProperties { - VkBool32 residencyStandard2DBlockShape /// Sparse resources support: GPU will access all 2D (single sample) sparse resources using the standard block shapes (based on pixel format) - VkBool32 residencyStandard2DMultisampleBlockShape /// Sparse resources support: GPU will access all 2D (multisample) sparse resources using the standard block shapes (based on pixel format) - VkBool32 residencyStandard3DBlockShape /// Sparse resources support: GPU will access all 3D sparse resources using the standard block shapes (based on pixel format) - VkBool32 residencyAlignedMipSize /// Sparse resources support: Images with mip-level dimensions that are NOT a multiple of the block size will be placed in the mip tail - VkBool32 residencyNonResidentStrict /// Sparse resources support: GPU can safely access non-resident regions of a resource, all reads return as if data is 0, writes are discarded -} - -class VkSemaphoreCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO - const void* pNext /// Pointer to next structure - VkSemaphoreCreateFlags flags /// Semaphore creation flags -} - -class VkQueryPoolCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO - const void* pNext /// Pointer to next structure - VkQueryPoolCreateFlags flags - VkQueryType queryType - u32 queryCount - VkQueryPipelineStatisticFlags pipelineStatistics /// Optional -} - -class VkFramebufferCreateInfo { - VkStructureType sType /// Must be VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO - const void* pNext /// Pointer to next structure - VkFramebufferCreateFlags flags - VkRenderPass renderPass - u32 attachmentCount - const VkImageView* pAttachments - u32 width - u32 height - u32 layers -} - -class VkDrawIndirectCommand { - u32 vertexCount - u32 instanceCount - u32 firstVertex - u32 firstInstance -} - -class VkDrawIndexedIndirectCommand { - u32 indexCount - u32 instanceCount - u32 firstIndex - s32 vertexOffset - u32 firstInstance -} - -class VkDispatchIndirectCommand { - u32 x - u32 y - u32 z -} - -class VkBaseOutStructure { - VkStructureType sType - void* pNext -} - -class VkBaseInStructure { - VkStructureType sType - const void* pNext -} - -//@vulkan1_1 structures - -class VkPhysicalDeviceSubgroupProperties { - VkStructureType sType - void* pNext - u32 subgroupSize - VkShaderStageFlags supportedStages - VkSubgroupFeatureFlags supportedOperations - VkBool32 quadOperationsInAllStages -} - -class VkBindBufferMemoryInfo { - VkStructureType sType - const void* pNext - VkBuffer buffer - VkDeviceMemory memory - VkDeviceSize memoryOffset -} - -class VkBindImageMemoryInfo { - VkStructureType sType - const void* pNext - VkImage image - VkDeviceMemory memory - VkDeviceSize memoryOffset -} - -class VkPhysicalDevice16BitStorageFeatures { - VkStructureType sType - void* pNext - VkBool32 storageBuffer16BitAccess - VkBool32 uniformAndStorageBuffer16BitAccess - VkBool32 storagePushConstant16 - VkBool32 storageInputOutput16 -} - -class VkMemoryDedicatedRequirements { - VkStructureType sType - void* pNext - VkBool32 prefersDedicatedAllocation - VkBool32 requiresDedicatedAllocation -} - -class VkMemoryDedicatedAllocateInfo { - VkStructureType sType - const void* pNext - VkImage image - VkBuffer buffer -} - -class VkMemoryAllocateFlagsInfo { - VkStructureType sType - const void* pNext - VkMemoryAllocateFlags flags - u32 deviceMask -} - -class VkDeviceGroupRenderPassBeginInfo { - VkStructureType sType - const void* pNext - u32 deviceMask - u32 deviceRenderAreaCount - const VkRect2D* pDeviceRenderAreas -} - -class VkDeviceGroupCommandBufferBeginInfo { - VkStructureType sType - const void* pNext - u32 deviceMask -} - -class VkDeviceGroupSubmitInfo { - VkStructureType sType - const void* pNext - u32 waitSemaphoreCount - const u32* pWaitSemaphoreDeviceIndices - u32 commandBufferCount - const u32* pCommandBufferDeviceMasks - u32 signalSemaphoreCount - const u32* pSignalSemaphoreDeviceIndices -} - -class VkDeviceGroupBindSparseInfo { - VkStructureType sType - const void* pNext - u32 resourceDeviceIndex - u32 memoryDeviceIndex -} - -class VkBindBufferMemoryDeviceGroupInfo { - VkStructureType sType - const void* pNext - u32 deviceIndexCount - const u32* pDeviceIndices -} - -class VkBindImageMemoryDeviceGroupInfo { - VkStructureType sType - const void* pNext - u32 deviceIndexCount - const u32* pDeviceIndices - u32 splitInstanceBindRegionCount - const VkRect2D* pSplitInstanceBindRegions -} - -class VkPhysicalDeviceGroupProperties { - VkStructureType sType - void* pNext - u32 physicalDeviceCount - VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE] physicalDevices - VkBool32 subsetAllocation -} - -class VkDeviceGroupDeviceCreateInfo { - VkStructureType sType - const void* pNext - u32 physicalDeviceCount - const VkPhysicalDevice* pPhysicalDevices -} - -class VkBufferMemoryRequirementsInfo2 { - VkStructureType sType - const void* pNext - VkBuffer buffer -} - -class VkImageMemoryRequirementsInfo2 { - VkStructureType sType - const void* pNext - VkImage image -} - -class VkImageSparseMemoryRequirementsInfo2 { - VkStructureType sType - const void* pNext - VkImage image -} - -class VkMemoryRequirements2 { - VkStructureType sType - void* pNext - VkMemoryRequirements memoryRequirements -} - -class VkSparseImageMemoryRequirements2 { - VkStructureType sType - void* pNext - VkSparseImageMemoryRequirements memoryRequirements -} - -class VkPhysicalDeviceFeatures2 { - VkStructureType sType - void* pNext - VkPhysicalDeviceFeatures features -} - -class VkPhysicalDeviceProperties2 { - VkStructureType sType - void* pNext - VkPhysicalDeviceProperties properties -} - -class VkFormatProperties2 { - VkStructureType sType - void* pNext - VkFormatProperties formatProperties -} - -class VkImageFormatProperties2 { - VkStructureType sType - void* pNext - VkImageFormatProperties imageFormatProperties -} - -class VkPhysicalDeviceImageFormatInfo2 { - VkStructureType sType - const void* pNext - VkFormat format - VkImageType type - VkImageTiling tiling - VkImageUsageFlags usage - VkImageCreateFlags flags -} - -class VkQueueFamilyProperties2 { - VkStructureType sType - void* pNext - VkQueueFamilyProperties queueFamilyProperties -} - -class VkPhysicalDeviceMemoryProperties2 { - VkStructureType sType - void* pNext - VkPhysicalDeviceMemoryProperties memoryProperties -} - -class VkSparseImageFormatProperties2 { - VkStructureType sType - void* pNext - VkSparseImageFormatProperties properties -} - -class VkPhysicalDeviceSparseImageFormatInfo2 { - VkStructureType sType - const void* pNext - VkFormat format - VkImageType type - VkSampleCountFlagBits samples - VkImageUsageFlags usage - VkImageTiling tiling -} - -class VkPhysicalDevicePointClippingProperties { - VkStructureType sType - void* pNext - VkPointClippingBehavior pointClippingBehavior -} - -class VkInputAttachmentAspectReference { - u32 subpass - u32 inputAttachmentIndex - VkImageAspectFlags aspectMask -} - -class VkRenderPassInputAttachmentAspectCreateInfo { - VkStructureType sType - const void* pNext - u32 aspectReferenceCount - const VkInputAttachmentAspectReference* pAspectReferences -} - -class VkImageViewUsageCreateInfo { - VkStructureType sType - const void* pNext - VkImageUsageFlags usage -} - -class VkPipelineTessellationDomainOriginStateCreateInfo { - VkStructureType sType - const void* pNext - VkTessellationDomainOrigin domainOrigin -} - -class VkRenderPassMultiviewCreateInfo { - VkStructureType sType - const void* pNext - u32 subpassCount - const u32* pViewMasks - u32 dependencyCount - const s32* pViewOffsets - u32 correlationMaskCount - const u32* pCorrelationMasks -} - -class VkPhysicalDeviceMultiviewFeatures { - VkStructureType sType - void* pNext - VkBool32 multiview - VkBool32 multiviewGeometryShader - VkBool32 multiviewTessellationShader -} - -class VkPhysicalDeviceMultiviewProperties { - VkStructureType sType - void* pNext - u32 maxMultiviewViewCount - u32 maxMultiviewInstanceIndex -} - -class VkPhysicalDeviceVariablePointerFeatures { - VkStructureType sType - void* pNext - VkBool32 variablePointersStorageBuffer - VkBool32 variablePointers -} - -class VkPhysicalDeviceProtectedMemoryFeatures { - VkStructureType sType - void* pNext - VkBool32 protectedMemory -} - -class VkPhysicalDeviceProtectedMemoryProperties { - VkStructureType sType - void* pNext - VkBool32 protectedNoFault -} - -class VkDeviceQueueInfo2 { - VkStructureType sType - const void* pNext - VkDeviceQueueCreateFlags flags - u32 queueFamilyIndex - u32 queueIndex -} - -class VkProtectedSubmitInfo { - VkStructureType sType - const void* pNext - VkBool32 protectedSubmit -} - -class VkSamplerYcbcrConversionCreateInfo { - VkStructureType sType - const void* pNext - VkFormat format - VkSamplerYcbcrModelConversion ycbcrModel - VkSamplerYcbcrRange ycbcrRange - VkComponentMapping components - VkChromaLocation xChromaOffset - VkChromaLocation yChromaOffset - VkFilter chromaFilter - VkBool32 forceExplicitReconstruction -} - -class VkSamplerYcbcrConversionInfo { - VkStructureType sType - const void* pNext - VkSamplerYcbcrConversion conversion -} - -class VkBindImagePlaneMemoryInfo { - VkStructureType sType - const void* pNext - VkImageAspectFlagBits planeAspect -} - -class VkImagePlaneMemoryRequirementsInfo { - VkStructureType sType - const void* pNext - VkImageAspectFlagBits planeAspect -} - -class VkPhysicalDeviceSamplerYcbcrConversionFeatures { - VkStructureType sType - void* pNext - VkBool32 samplerYcbcrConversion -} - -class VkSamplerYcbcrConversionImageFormatProperties { - VkStructureType sType - void* pNext - u32 combinedImageSamplerDescriptorCount -} - -class VkDescriptorUpdateTemplateEntry { - u32 dstBinding - u32 dstArrayElement - u32 descriptorCount - VkDescriptorType descriptorType - platform.size_t offset - platform.size_t stride -} - -class VkDescriptorUpdateTemplateCreateInfo { - VkStructureType sType - const void* pNext - VkDescriptorUpdateTemplateCreateFlags flags - u32 descriptorUpdateEntryCount - const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries - VkDescriptorUpdateTemplateType templateType - VkDescriptorSetLayout descriptorSetLayout - VkPipelineBindPoint pipelineBindPoint - VkPipelineLayout pipelineLayout - u32 set -} - -class VkExternalMemoryProperties { - VkExternalMemoryFeatureFlags externalMemoryFeatures - VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes - VkExternalMemoryHandleTypeFlags compatibleHandleTypes -} - -class VkPhysicalDeviceExternalImageFormatInfo { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlagBits handleType -} - -class VkExternalImageFormatProperties { - VkStructureType sType - void* pNext - VkExternalMemoryProperties externalMemoryProperties -} - -class VkPhysicalDeviceExternalBufferInfo { - VkStructureType sType - const void* pNext - VkBufferCreateFlags flags - VkBufferUsageFlags usage - VkExternalMemoryHandleTypeFlagBits handleType -} - -class VkExternalBufferProperties { - VkStructureType sType - void* pNext - VkExternalMemoryProperties externalMemoryProperties -} - -class VkPhysicalDeviceIDProperties { - VkStructureType sType - void* pNext - u8[VK_UUID_SIZE] deviceUUID - u8[VK_UUID_SIZE] driverUUID - u8[VK_LUID_SIZE] deviceLUID - u32 deviceNodeMask - VkBool32 deviceLUIDValid -} - -class VkExternalMemoryImageCreateInfo { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlags handleTypes -} - -class VkExternalMemoryBufferCreateInfo { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlags handleTypes -} - -class VkExportMemoryAllocateInfo { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlags handleTypes -} - -class VkPhysicalDeviceExternalFenceInfo { - VkStructureType sType - const void* pNext - VkExternalFenceHandleTypeFlagBits handleType -} - -class VkExternalFenceProperties { - VkStructureType sType - void* pNext - VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes - VkExternalFenceHandleTypeFlags compatibleHandleTypes - VkExternalFenceFeatureFlags externalFenceFeatures -} - -class VkExportFenceCreateInfo { - VkStructureType sType - const void* pNext - VkExternalFenceHandleTypeFlags handleTypes -} - -class VkExportSemaphoreCreateInfo { - VkStructureType sType - const void* pNext - VkExternalSemaphoreHandleTypeFlags handleTypes -} - -class VkPhysicalDeviceExternalSemaphoreInfo { - VkStructureType sType - const void* pNext - VkExternalSemaphoreHandleTypeFlagBits handleType -} - -class VkExternalSemaphoreProperties { - VkStructureType sType - void* pNext - VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes - VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes - VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures -} - -class VkPhysicalDeviceMaintenance3Properties { - VkStructureType sType - void* pNext - u32 maxPerSetDescriptors - VkDeviceSize maxMemoryAllocationSize -} - -class VkDescriptorSetLayoutSupport { - VkStructureType sType - void* pNext - VkBool32 supported -} - -class VkPhysicalDeviceShaderDrawParameterFeatures { - VkStructureType sType - void* pNext - VkBool32 shaderDrawParameters -} - - -@extension("VK_KHR_surface") // 1 -class VkSurfaceCapabilitiesKHR { - u32 minImageCount - u32 maxImageCount - VkExtent2D currentExtent - VkExtent2D minImageExtent - VkExtent2D maxImageExtent - u32 maxImageArrayLayers - VkSurfaceTransformFlagsKHR supportedTransforms - VkSurfaceTransformFlagBitsKHR currentTransform - VkCompositeAlphaFlagsKHR supportedCompositeAlpha - VkImageUsageFlags supportedUsageFlags -} - -@extension("VK_KHR_surface") // 1 -class VkSurfaceFormatKHR { - VkFormat format - VkColorSpaceKHR colorSpace -} - -@extension("VK_KHR_swapchain") // 2 -class VkSwapchainCreateInfoKHR { - VkStructureType sType - const void* pNext - VkSwapchainCreateFlagsKHR flags - VkSurfaceKHR surface - u32 minImageCount - VkFormat imageFormat - VkColorSpaceKHR imageColorSpace - VkExtent2D imageExtent - u32 imageArrayLayers - VkImageUsageFlags imageUsage - VkSharingMode sharingMode - u32 queueFamilyIndexCount - const u32* pQueueFamilyIndices - VkSurfaceTransformFlagBitsKHR preTransform - VkCompositeAlphaFlagBitsKHR compositeAlpha - VkPresentModeKHR presentMode - VkBool32 clipped - VkSwapchainKHR oldSwapchain -} - -@extension("VK_KHR_swapchain") // 2 -class VkPresentInfoKHR { - VkStructureType sType - const void* pNext - u32 waitSemaphoreCount - const VkSemaphore* pWaitSemaphores - u32 swapchainCount - const VkSwapchainKHR* pSwapchains - const u32* pImageIndices - VkResult* pResults -} - -@vulkan1_1 -@extension("VK_KHR_swapchain") // 2 -class VkImageSwapchainCreateInfoKHR { - VkStructureType sType - const void* pNext - VkSwapchainKHR swapchain -} - -@vulkan1_1 -@extension("VK_KHR_swapchain") // 2 -class VkBindImageMemorySwapchainInfoKHR { - VkStructureType sType - const void* pNext - VkSwapchainKHR swapchain - u32 imageIndex -} - -@vulkan1_1 -@extension("VK_KHR_swapchain") // 2 -class VkAcquireNextImageInfoKHR { - VkStructureType sType - const void* pNext - VkSwapchainKHR swapchain - u64 timeout - VkSemaphore semaphore - VkFence fence - u32 deviceMask -} - -@vulkan1_1 -@extension("VK_KHR_swapchain") // 2 -class VkDeviceGroupPresentCapabilitiesKHR { - VkStructureType sType - const void* pNext - u32[VK_MAX_DEVICE_GROUP_SIZE] presentMask - VkDeviceGroupPresentModeFlagsKHR modes -} - -@vulkan1_1 -@extension("VK_KHR_swapchain") // 2 -class VkDeviceGroupPresentInfoKHR { - VkStructureType sType - const void* pNext - u32 swapchainCount - const u32* pDeviceMasks - VkDeviceGroupPresentModeFlagBitsKHR mode -} - -@vulkan1_1 -@extension("VK_KHR_swapchain") // 2 -class VkDeviceGroupSwapchainCreateInfoKHR { - VkStructureType sType - const void* pNext - VkDeviceGroupPresentModeFlagsKHR modes -} - -@extension("VK_KHR_display") // 3 -class VkDisplayPropertiesKHR { - VkDisplayKHR display - const char* displayName - VkExtent2D physicalDimensions - VkExtent2D physicalResolution - VkSurfaceTransformFlagsKHR supportedTransforms - VkBool32 planeReorderPossible - VkBool32 persistentContent -} - -@extension("VK_KHR_display") // 3 -class VkDisplayModeParametersKHR { - VkExtent2D visibleRegion - u32 refreshRate -} - -@extension("VK_KHR_display") // 3 -class VkDisplayModePropertiesKHR { - VkDisplayModeKHR displayMode - VkDisplayModeParametersKHR parameters -} - -@extension("VK_KHR_display") // 3 -class VkDisplayModeCreateInfoKHR { - VkStructureType sType - const void* pNext - VkDisplayModeCreateFlagsKHR flags - VkDisplayModeParametersKHR parameters -} - -@extension("VK_KHR_display") // 3 -class VkDisplayPlanePropertiesKHR { - VkDisplayKHR currentDisplay - u32 currentStackIndex -} - -@extension("VK_KHR_display") // 3 -class VkDisplayPlaneCapabilitiesKHR { - VkDisplayPlaneAlphaFlagsKHR supportedAlpha - VkOffset2D minSrcPosition - VkOffset2D maxSrcPosition - VkExtent2D minSrcExtent - VkExtent2D maxSrcExtent - VkOffset2D minDstPosition - VkOffset2D maxDstPosition - VkExtent2D minDstExtent - VkExtent2D maxDstExtent -} - -@extension("VK_KHR_display") // 3 -class VkDisplaySurfaceCreateInfoKHR { - VkStructureType sType - const void* pNext - VkDisplaySurfaceCreateFlagsKHR flags - VkDisplayModeKHR displayMode - u32 planeIndex - u32 planeStackIndex - VkSurfaceTransformFlagBitsKHR transform - f32 globalAlpha - VkDisplayPlaneAlphaFlagBitsKHR alphaMode - VkExtent2D imageExtent -} - -@extension("VK_KHR_display_swapchain") // 4 -class VkDisplayPresentInfoKHR { - VkStructureType sType - const void* pNext - VkRect2D srcRect - VkRect2D dstRect - VkBool32 persistent -} - -@extension("VK_KHR_xlib_surface") // 5 -class VkXlibSurfaceCreateInfoKHR { - VkStructureType sType - const void* pNext - VkXlibSurfaceCreateFlagsKHR flags - platform.Display* dpy - platform.Window window -} - -@extension("VK_KHR_xcb_surface") // 6 -class VkXcbSurfaceCreateInfoKHR { - VkStructureType sType - const void* pNext - VkXcbSurfaceCreateFlagsKHR flags - platform.xcb_connection_t* connection - platform.xcb_window_t window -} - -@extension("VK_KHR_wayland_surface") // 7 -class VkWaylandSurfaceCreateInfoKHR { - VkStructureType sType - const void* pNext - VkWaylandSurfaceCreateFlagsKHR flags - platform.wl_display* display - platform.wl_surface* surface -} - -@extension("VK_KHR_android_surface") // 9 -class VkAndroidSurfaceCreateInfoKHR { - VkStructureType sType - const void* pNext - VkAndroidSurfaceCreateFlagsKHR flags - platform.ANativeWindow* window -} - -@extension("VK_KHR_win32_surface") // 10 -class VkWin32SurfaceCreateInfoKHR { - VkStructureType sType - const void* pNext - VkWin32SurfaceCreateFlagsKHR flags - platform.HINSTANCE hinstance - platform.HWND hwnd -} - -@extension("VK_ANDROID_native_buffer") // 11 -@internal class Gralloc1Usage { - u64 consumer - u64 producer -} - -@extension("VK_ANDROID_native_buffer") // 11 -class VkNativeBufferANDROID { - VkStructureType sType - const void* pNext - platform.buffer_handle_t handle - s32 stride - s32 format - s32 usage - Gralloc1Usage usage2 -} - -@extension("VK_ANDROID_native_buffer") // 11 -class VkSwapchainImageCreateInfoANDROID { - VkStructureType sType - const void* pNext - VkSwapchainImageUsageFlagsANDROID flags -} - -@extension("VK_ANDROID_native_buffer") // 11 -class VkPhysicalDevicePresentationPropertiesANDROID { - VkStructureType sType - void* pNext - VkBool32 sharedImage -} - -@extension("VK_EXT_debug_report") // 12 -class VkDebugReportCallbackCreateInfoEXT { - VkStructureType sType - const void* pNext - VkDebugReportFlagsEXT flags - PFN_vkDebugReportCallbackEXT pfnCallback - void* pUserData -} - -@extension("VK_AMD_rasterization_order") // 19 -class VkPipelineRasterizationStateRasterizationOrderAMD { - VkStructureType sType - const void* pNext - VkRasterizationOrderAMD rasterizationOrder -} - -@extension("VK_EXT_debug_marker") // 23 -class VkDebugMarkerObjectNameInfoEXT { - VkStructureType sType - const void* pNext - VkDebugReportObjectTypeEXT objectType - u64 object - const char* pObjectName -} - -@extension("VK_EXT_debug_marker") // 23 -class VkDebugMarkerObjectTagInfoEXT { - VkStructureType sType - const void* pNext - VkDebugReportObjectTypeEXT objectType - u64 object - u64 tagName - platform.size_t tagSize - const void* pTag -} - -@extension("VK_EXT_debug_marker") // 23 -class VkDebugMarkerMarkerInfoEXT { - VkStructureType sType - const void* pNext - const char* pMarkerName - f32[4] color -} - -@extension("VK_NV_dedicated_allocation") // 27 -class VkDedicatedAllocationImageCreateInfoNV { - VkStructureType sType - const void* pNext - VkBool32 dedicatedAllocation -} - -@extension("VK_NV_dedicated_allocation") // 27 -class VkDedicatedAllocationBufferCreateInfoNV { - VkStructureType sType - const void* pNext - VkBool32 dedicatedAllocation -} - -@extension("VK_NV_dedicated_allocation") // 27 -class VkDedicatedAllocationMemoryAllocateInfoNV { - VkStructureType sType - const void* pNext - VkImage image - VkBuffer buffer -} - -@extension("VK_EXT_transform_feedback") // 29 -class VkPhysicalDeviceTransformFeedbackFeaturesEXT { - VkStructureType sType - void* pNext - VkBool32 transformFeedback - VkBool32 geometryStreams -} - -@extension("VK_EXT_transform_feedback") // 29 -class VkPhysicalDeviceTransformFeedbackPropertiesEXT { - VkStructureType sType - void* pNext - u32 maxTransformFeedbackStreams - u32 maxTransformFeedbackBuffers - VkDeviceSize maxTransformFeedbackBufferSize - u32 maxTransformFeedbackStreamDataSize - u32 maxTransformFeedbackBufferDataSize - u32 maxTransformFeedbackBufferDataStride - VkBool32 transformFeedbackQueries - VkBool32 transformFeedbackStreamsLinesTriangles - VkBool32 transformFeedbackRasterizationStreamSelect - VkBool32 transformFeedbackDraw -} - -@extension("VK_EXT_transform_feedback") // 29 -class VkPipelineRasterizationStateStreamCreateInfoEXT { - VkStructureType sType - const void* pNext - VkPipelineRasterizationStateStreamCreateFlagsEXT flags - u32 rasterizationStream -} - -@extension("VK_AMD_texture_gather_bias_lod") // 42 -class VkTextureLODGatherFormatPropertiesAMD { - VkStructureType sType - void* pNext - VkBool32 supportsTextureGatherLODBiasAMD -} - -@extension("VK_AMD_shader_info") // 43 -class VkShaderResourceUsageAMD { - u32 numUsedVgprs - u32 numUsedSgprs - u32 ldsSizePerLocalWorkGroup - platform.size_t ldsUsageSizeInBytes - platform.size_t scratchMemUsageInBytes -} - -@extension("VK_AMD_shader_info") // 43 -class VkShaderStatisticsInfoAMD { - VkShaderStageFlags shaderStageMask - VkShaderResourceUsageAMD resourceUsage - u32 numPhysicalVgprs - u32 numPhysicalSgprs - u32 numAvailableVgprs - u32 numAvailableSgprs - u32[3] computeWorkGroupSize -} - -@extension("VK_NV_corner_sampled_image") // 51 -class VkPhysicalDeviceCornerSampledImageFeaturesNV { - VkStructureType sType - void* pNext - VkBool32 cornerSampledImage -} - -@extension("VK_KHR_multiview") // 54 -class VkRenderPassMultiviewCreateInfoKHR { - VkStructureType sType - const void* pNext - u32 subpassCount - const u32* pViewMasks - u32 dependencyCount - const s32* pViewOffsets - u32 correlationMaskCount - const u32* pCorrelationMasks -} - -@extension("VK_KHR_multiview") // 54 -class VkPhysicalDeviceMultiviewFeaturesKHR { - VkStructureType sType - void* pNext - VkBool32 multiview - VkBool32 multiviewGeometryShader - VkBool32 multiviewTessellationShader -} - -@extension("VK_KHR_multiview") // 54 -class VkPhysicalDeviceMultiviewPropertiesKHR { - VkStructureType sType - void* pNext - u32 maxMultiviewViewCount - u32 maxMultiviewInstanceIndex -} - -@extension("VK_NV_external_memory_capabilities") // 56 -class VkExternalImageFormatPropertiesNV { - VkImageFormatProperties imageFormatProperties - VkExternalMemoryFeatureFlagsNV externalMemoryFeatures - VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes - VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes -} - -@extension("VK_NV_external_memory") // 57 -class VkExternalMemoryImageCreateInfoNV { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlagsNV handleTypes -} - -@extension("VK_NV_external_memory") // 57 -class VkExportMemoryAllocateInfoNV { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlagsNV handleTypes -} - -@extension("VK_NV_external_memory_win32") // 58 -class VkImportMemoryWin32HandleInfoNV { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlagsNV handleType - platform.HANDLE handle -} - -@extension("VK_NV_external_memory_win32") // 58 -class VkExportMemoryWin32HandleInfoNV { - VkStructureType sType - const void* pNext - const platform.SECURITY_ATTRIBUTES* pAttributes - platform.DWORD dwAccess -} - -@extension("VK_NV_win32_keyed_mutex") // 59 -class VkWin32KeyedMutexAcquireReleaseInfoNV { - VkStructureType sType - const void* pNext - u32 acquireCount - const VkDeviceMemory* pAcquireSyncs - const u64* pAcquireKeys - const u32* pAcquireTimeoutMilliseconds - u32 releaseCount - const VkDeviceMemory* pReleaseSyncs - const u64* pReleaseKeys -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -class VkPhysicalDeviceFeatures2KHR { - VkStructureType sType - void* pNext - VkPhysicalDeviceFeatures features -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -class VkPhysicalDeviceProperties2KHR { - VkStructureType sType - void* pNext - VkPhysicalDeviceProperties properties -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -class VkFormatProperties2KHR { - VkStructureType sType - void* pNext - VkFormatProperties formatProperties -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -class VkImageFormatProperties2KHR { - VkStructureType sType - void* pNext - VkImageFormatProperties imageFormatProperties -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -class VkPhysicalDeviceImageFormatInfo2KHR { - VkStructureType sType - const void* pNext - VkFormat format - VkImageType type - VkImageTiling tiling - VkImageUsageFlags usage - VkImageCreateFlags flags -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -class VkQueueFamilyProperties2KHR { - VkStructureType sType - void* pNext - VkQueueFamilyProperties queueFamilyProperties -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -class VkPhysicalDeviceMemoryProperties2KHR { - VkStructureType sType - void* pNext - VkPhysicalDeviceMemoryProperties memoryProperties -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -class VkSparseImageFormatProperties2KHR { - VkStructureType sType - void* pNext - VkSparseImageFormatProperties properties -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -class VkPhysicalDeviceSparseImageFormatInfo2KHR { - VkStructureType sType - const void* pNext - VkFormat format - VkImageType type - VkSampleCountFlagBits samples - VkImageUsageFlags usage - VkImageTiling tiling -} - -@extension("VK_KHR_device_group") // 61 -class VkMemoryAllocateFlagsInfoKHR { - VkStructureType sType - const void* pNext - VkMemoryAllocateFlagsKHR flags - u32 deviceMask -} - -@extension("VK_KHR_device_group") // 61 -class VkBindBufferMemoryDeviceGroupInfoKHR { - VkStructureType sType - const void* pNext - u32 deviceIndexCount - const u32* pDeviceIndices -} - -@extension("VK_KHR_device_group") // 61 -class VkBindImageMemoryDeviceGroupInfoKHR { - VkStructureType sType - const void* pNext - u32 deviceIndexCount - const u32* pDeviceIndices - u32 SFRRectCount - const VkRect2D* pSFRRects -} - -@extension("VK_KHR_device_group") // 61 -class VkDeviceGroupRenderPassBeginInfoKHR { - VkStructureType sType - const void* pNext - u32 deviceMask - u32 deviceRenderAreaCount - const VkRect2D* pDeviceRenderAreas -} - -@extension("VK_KHR_device_group") // 61 -class VkDeviceGroupCommandBufferBeginInfoKHR { - VkStructureType sType - const void* pNext - u32 deviceMask -} - -@extension("VK_KHR_device_group") // 61 -class VkDeviceGroupSubmitInfoKHR { - VkStructureType sType - const void* pNext - u32 waitSemaphoreCount - const u32* pWaitSemaphoreDeviceIndices - u32 commandBufferCount - const u32* pCommandBufferDeviceMasks - u32 signalSemaphoreCount - const u32* pSignalSemaphoreDeviceIndices -} - -@extension("VK_KHR_device_group") // 61 -class VkDeviceGroupBindSparseInfoKHR { - VkStructureType sType - const void* pNext - u32 resourceDeviceIndex - u32 memoryDeviceIndex -} - -@extension("VK_EXT_validation_flags") // 62 -class VkValidationFlagsEXT { - VkStructureType sType - const void* pNext - u32 disabledValidationCheckCount - const VkValidationCheckEXT* pDisabledValidationChecks -} - -@extension("VK_NN_vi_surface") // 63 -class VkViSurfaceCreateInfoNN { - VkStructureType sType - const void* pNext - VkViSurfaceCreateFlagsNN flags - void* window -} - -@extension("VK_EXT_astc_decode_mode") // 68 -class VkImageViewASTCDecodeModeEXT { - VkStructureType sType - const void* pNext - VkFormat decodeMode -} - -@extension("VK_EXT_astc_decode_mode") // 68 -class VkPhysicalDeviceASTCDecodeFeaturesEXT { - VkStructureType sType - void* pNext - VkBool32 decodeModeSharedExponent -} - -@extension("VK_KHR_device_group_creation") // 71 -class VkPhysicalDeviceGroupPropertiesKHR { - VkStructureType sType - void* pNext - u32 physicalDeviceCount - VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE] physicalDevices - VkBool32 subsetAllocation -} - -@extension("VK_KHR_device_group_creation") // 71 -class VkDeviceGroupDeviceCreateInfoKHR { - VkStructureType sType - const void* pNext - u32 physicalDeviceCount - const VkPhysicalDevice* pPhysicalDevices -} - -@extension("VK_KHR_external_memory_capabilities") // 72 -class VkExternalMemoryPropertiesKHR { - VkExternalMemoryFeatureFlagsKHR externalMemoryFeatures - VkExternalMemoryHandleTypeFlagsKHR exportFromImportedHandleTypes - VkExternalMemoryHandleTypeFlagsKHR compatibleHandleTypes -} - -@extension("VK_KHR_external_memory_capabilities") // 72 -class VkPhysicalDeviceExternalImageFormatInfoKHR { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlagBitsKHR handleType -} - -@extension("VK_KHR_external_memory_capabilities") // 72 -class VkExternalImageFormatPropertiesKHR { - VkStructureType sType - void* pNext - VkExternalMemoryPropertiesKHR externalMemoryProperties -} - -@extension("VK_KHR_external_memory_capabilities") // 72 -class VkPhysicalDeviceExternalBufferInfoKHR { - VkStructureType sType - const void* pNext - VkBufferCreateFlags flags - VkBufferUsageFlags usage - VkExternalMemoryHandleTypeFlagBitsKHR handleType -} - -@extension("VK_KHR_external_memory_capabilities") // 72 -class VkExternalBufferPropertiesKHR { - VkStructureType sType - void* pNext - VkExternalMemoryPropertiesKHR externalMemoryProperties -} - -@extension("VK_KHR_external_memory_capabilities") // 72 -class VkPhysicalDeviceIDPropertiesKHR { - VkStructureType sType - void* pNext - u8[VK_UUID_SIZE] deviceUUID - u8[VK_UUID_SIZE] driverUUID - u8[VK_LUID_SIZE] deviceLUID - u32 deviceNodeMask - VkBool32 deviceLUIDValid -} - -@extension("VK_KHR_external_memory") // 73 -class VkExternalMemoryImageCreateInfoKHR { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlagsKHR handleTypes -} - -@extension("VK_KHR_external_memory") // 73 -class VkExternalMemoryBufferCreateInfoKHR { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlagsKHR handleTypes -} - -@extension("VK_KHR_external_memory") // 73 -class VkExportMemoryAllocateInfoKHR { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlagsKHR handleTypes -} - -@extension("VK_KHR_external_memory_win32") // 74 -class VkImportMemoryWin32HandleInfoKHR { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlagBitsKHR handleType - platform.HANDLE handle - platform.LPCWSTR name -} - -@extension("VK_KHR_external_memory_win32") // 74 -class VkExportMemoryWin32HandleInfoKHR { - VkStructureType sType - const void* pNext - const platform.SECURITY_ATTRIBUTES* pAttributes - platform.DWORD dwAccess - platform.LPCWSTR name -} - -@extension("VK_KHR_external_memory_win32") // 74 -class VkMemoryWin32HandlePropertiesKHR { - VkStructureType sType - void* pNext - u32 memoryTypeBits -} - -@extension("VK_KHR_external_memory_win32") // 74 -class VkMemoryGetWin32HandleInfoKHR { - VkStructureType sType - void* pNext - VkDeviceMemory memory - VkExternalMemoryHandleTypeFlagBitsKHR handleType -} - -@extension("VK_KHR_external_memory_fd") // 75 -class VkImportMemoryFdInfoKHR { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlagBitsKHR handleType - int fd -} - -@extension("VK_KHR_external_memory_fd") // 75 -class VkMemoryFdPropertiesKHR { - VkStructureType sType - void* pNext - u32 memoryTypeBits -} - -@extension("VK_KHR_external_memory_fd") // 75 -class VkMemoryGetFdInfoKHR { - VkStructureType sType - void* pNext - VkDeviceMemory memory - VkExternalMemoryHandleTypeFlagBitsKHR handleType -} - -@extension("VK_KHR_win32_keyed_mutex") // 76 -class VkWin32KeyedMutexAcquireReleaseInfoKHR { - VkStructureType sType - const void* pNext - u32 acquireCount - const VkDeviceMemory* pAcquireSyncs - const u64* pAcquireKeys - const u32* pAcquireTimeouts - u32 releaseCount - const VkDeviceMemory* pReleaseSyncs - const u64* pReleaseKeys -} - -@extension("VK_KHR_external_semaphore_capabilities") // 77 -class VkPhysicalDeviceExternalSemaphoreInfoKHR { - VkStructureType sType - const void* pNext - VkExternalSemaphoreHandleTypeFlagBitsKHR handleType -} - -@extension("VK_KHR_external_semaphore_capabilities") // 77 -class VkExternalSemaphorePropertiesKHR { - VkStructureType sType - void* pNext - VkExternalSemaphoreHandleTypeFlagsKHR exportFromImportedHandleTypes - VkExternalSemaphoreHandleTypeFlagsKHR compatibleHandleTypes - VkExternalSemaphoreFeatureFlagsKHR externalSemaphoreFeatures -} - -@extension("VK_KHR_external_semaphore") // 78 -class VkExportSemaphoreCreateInfoKHR { - VkStructureType sType - const void* pNext - VkExternalSemaphoreHandleTypeFlagsKHR handleTypes -} - -@extension("VK_KHR_external_semaphore_win32") // 79 -class VkImportSemaphoreWin32HandleInfoKHR { - VkStructureType sType - const void* pNext - VkSemaphore semaphore - VkSemaphoreImportFlagsKHR flags - VkExternalSemaphoreHandleTypeFlagsKHR handleType - platform.HANDLE handle - platform.LPCWSTR name -} - -@extension("VK_KHR_external_semaphore_win32") // 79 -class VkExportSemaphoreWin32HandleInfoKHR { - VkStructureType sType - const void* pNext - const platform.SECURITY_ATTRIBUTES* pAttributes - platform.DWORD dwAccess - platform.LPCWSTR name -} - -@extension("VK_KHR_external_semaphore_win32") // 79 -class VkD3D12FenceSubmitInfoKHR { - VkStructureType sType - const void* pNext - u32 waitSemaphoreValuesCount - const u64* pWaitSemaphoreValues - u32 signalSemaphoreValuesCount - const u64* pSignalSemaphoreValues -} - -@extension("VK_KHR_external_semaphore_win32") // 79 -class VkSemaphoreGetWin32HandleInfoKHR { - VkStructureType sType - const void* pNext - VkSemaphore semaphore - VkExternalSemaphoreHandleTypeFlagBitsKHR handleType -} - -@extension("VK_KHR_external_semaphore_fd") // 80 -class VkImportSemaphoreFdInfoKHR { - VkStructureType sType - const void* pNext - VkSemaphore semaphore - VkSemaphoreImportFlagsKHR flags - VkExternalSemaphoreHandleTypeFlagBitsKHR handleType - s32 fd -} - -@extension("VK_KHR_external_semaphore_fd") // 80 -class VkSemaphoreGetFdInfoKHR { - VkStructureType sType - const void* pNext - VkSemaphore semaphore - VkExternalSemaphoreHandleTypeFlagBitsKHR handleType -} - -@extension("VK_KHR_push_descriptor") // 81 -class VkPhysicalDevicePushDescriptorPropertiesKHR { - VkStructureType sType - void* pNext - u32 maxPushDescriptors -} - -@extension("VK_EXT_conditional_rendering") // 82 -class VkConditionalRenderingBeginInfoEXT { - VkStructureType sType - const void* pNext - VkBuffer buffer - VkDeviceSize offset - VkConditionalRenderingFlagsEXT flags -} - -@extension("VK_EXT_conditional_rendering") // 82 -class VkPhysicalDeviceConditionalRenderingFeaturesEXT { - VkStructureType sType - void* pNext - VkBool32 conditionalRendering - VkBool32 inheritedConditionalRendering -} - -@extension("VK_EXT_conditional_rendering") // 82 -class VkCommandBufferInheritanceConditionalRenderingInfoEXT { - VkStructureType sType - const void* pNext - VkBool32 conditionalRenderingEnable -} - -@extension("VK_KHR_shader_float16_int8") // 83 -class VkPhysicalDeviceFloat16Int8FeaturesKHR { - VkStructureType sType - void* pNext - VkBool32 shaderFloat16 - VkBool32 shaderInt8 -} - -@extension("VK_KHR_16bit_storage") // 84 -class VkPhysicalDevice16BitStorageFeaturesKHR { - VkStructureType sType - void* pNext - VkBool32 storageBuffer16BitAccess - VkBool32 uniformAndStorageBuffer16BitAccess - VkBool32 storagePushConstant16 - VkBool32 storageInputOutput16 -} - -@extension("VK_KHR_incremental_present") // 85 -class VkRectLayerKHR { - VkOffset2D offset - VkExtent2D extent - u32 layer -} - -@extension("VK_KHR_incremental_present") // 85 -class VkPresentRegionKHR { - u32 rectangleCount - const VkRectLayerKHR* pRectangles -} - -@extension("VK_KHR_incremental_present") // 85 -class VkPresentRegionsKHR { - VkStructureType sType - const void* pNext - u32 swapchainCount - const VkPresentRegionKHR* pRegions -} - -@extension("VK_KHR_descriptor_update_template") // 86 -class VkDescriptorUpdateTemplateEntryKHR { - u32 dstBinding - u32 dstArrayElement - u32 descriptorCount - VkDescriptorType descriptorType - platform.size_t offset - platform.size_t stride -} - -@extension("VK_KHR_descriptor_update_template") // 86 -class VkDescriptorUpdateTemplateCreateInfoKHR { - VkStructureType sType - void* pNext - VkDescriptorUpdateTemplateCreateFlagsKHR flags - u32 descriptorUpdateEntryCount - const VkDescriptorUpdateTemplateEntryKHR* pDescriptorUpdateEntries - VkDescriptorUpdateTemplateTypeKHR templateType - VkDescriptorSetLayout descriptorSetLayout - VkPipelineBindPoint pipelineBindPoint - VkPipelineLayout pipelineLayout - u32 set -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkDeviceGeneratedCommandsFeaturesNVX { - VkStructureType sType - const void* pNext - VkBool32 computeBindingPointSupport -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkDeviceGeneratedCommandsLimitsNVX { - VkStructureType sType - const void* pNext - u32 maxIndirectCommandsLayoutTokenCount - u32 maxObjectEntryCounts - u32 minSequenceCountBufferOffsetAlignment - u32 minSequenceIndexBufferOffsetAlignment - u32 minCommandsTokenBufferOffsetAlignment -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkIndirectCommandsTokenNVX { - VkIndirectCommandsTokenTypeNVX tokenType - VkBuffer buffer - VkDeviceSize offset -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkIndirectCommandsLayoutTokenNVX { - VkIndirectCommandsTokenTypeNVX tokenType - u32 bindingUnit - u32 dynamicCount - u32 divisor -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkIndirectCommandsLayoutCreateInfoNVX { - VkStructureType sType - const void* pNext - VkPipelineBindPoint pipelineBindPoint - VkIndirectCommandsLayoutUsageFlagsNVX flags - u32 tokenCount - const VkIndirectCommandsLayoutTokenNVX* pTokens -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkCmdProcessCommandsInfoNVX { - VkStructureType sType - const void* pNext - VkObjectTableNVX objectTable - VkIndirectCommandsLayoutNVX indirectCommandsLayout - u32 indirectCommandsTokenCount - const VkIndirectCommandsTokenNVX* pIndirectCommandsTokens - u32 maxSequencesCount - VkCommandBuffer targetCommandBuffer - VkBuffer sequencesCountBuffer - VkDeviceSize sequencesCountOffset - VkBuffer sequencesIndexBuffer - VkDeviceSize sequencesIndexOffset -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkCmdReserveSpaceForCommandsInfoNVX { - VkStructureType sType - const void* pNext - VkObjectTableNVX objectTable - VkIndirectCommandsLayoutNVX indirectCommandsLayout - u32 maxSequencesCount -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkObjectTableCreateInfoNVX { - VkStructureType sType - const void* pNext - u32 objectCount - const VkObjectEntryTypeNVX* pObjectEntryTypes - const u32* pObjectEntryCounts - const VkObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags - u32 maxUniformBuffersPerDescriptor - u32 maxStorageBuffersPerDescriptor - u32 maxStorageImagesPerDescriptor - u32 maxSampledImagesPerDescriptor - u32 maxPipelineLayouts -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkObjectTableEntryNVX { - VkObjectEntryTypeNVX type - VkObjectEntryUsageFlagsNVX flags -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkObjectTablePipelineEntryNVX { - VkObjectEntryTypeNVX type - VkObjectEntryUsageFlagsNVX flags - VkPipeline pipeline -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkObjectTableDescriptorSetEntryNVX { - VkObjectEntryTypeNVX type - VkObjectEntryUsageFlagsNVX flags - VkPipelineLayout pipelineLayout - VkDescriptorSet descriptorSet -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkObjectTableVertexBufferEntryNVX { - VkObjectEntryTypeNVX type - VkObjectEntryUsageFlagsNVX flags - VkBuffer buffer -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkObjectTableIndexBufferEntryNVX { - VkObjectEntryTypeNVX type - VkObjectEntryUsageFlagsNVX flags - VkBuffer buffer - VkIndexType indexType -} - -@extension("VK_NVX_device_generated_commands") // 87 -class VkObjectTablePushConstantEntryNVX { - VkObjectEntryTypeNVX type - VkObjectEntryUsageFlagsNVX flags - VkPipelineLayout pipelineLayout - VkShaderStageFlags stageFlags -} - -@extension("VK_NV_clip_space_w_scaling") // 88 -class VkViewportWScalingNV { - f32 xcoeff - f32 ycoeff -} - -@extension("VK_NV_clip_space_w_scaling") // 88 -class VkPipelineViewportWScalingStateCreateInfoNV { - VkStructureType sType - const void* pNext - VkBool32 viewportWScalingEnable - u32 viewportCount - const VkViewportWScalingNV* pViewportWScalings -} - -@extension("VK_EXT_display_surface_counter") // 91 -class VkSurfaceCapabilities2EXT { - VkStructureType sType - void* pNext - u32 minImageCount - u32 maxImageCount - VkExtent2D currentExtent - VkExtent2D minImageExtent - VkExtent2D maxImageExtent - u32 maxImageArrayLayers - VkSurfaceTransformFlagsKHR supportedTransforms - VkSurfaceTransformFlagBitsKHR currentTransform - VkCompositeAlphaFlagsKHR supportedCompositeAlpha - VkImageUsageFlags supportedUsageFlags - VkSurfaceCounterFlagsEXT supportedSurfaceCounters -} - -@extension("VK_EXT_display_control") // 92 -class VkDisplayPowerInfoEXT { - VkStructureType sType - const void* pNext - VkDisplayPowerStateEXT powerState -} - -@extension("VK_EXT_display_control") // 92 -class VkDeviceEventInfoEXT { - VkStructureType sType - const void* pNext - VkDeviceEventTypeEXT deviceEvent -} - -@extension("VK_EXT_display_control") // 92 -class VkDisplayEventInfoEXT { - VkStructureType sType - const void* pNext - VkDisplayEventTypeEXT displayEvent -} - -@extension("VK_EXT_display_control") // 92 -class VkSwapchainCounterCreateInfoEXT { - VkStructureType sType - const void* pNext - VkSurfaceCounterFlagsEXT surfaceCounters -} - -@extension("VK_GOOGLE_display_timing") // 93 -class VkRefreshCycleDurationGOOGLE { - u64 refreshDuration -} - -@extension("VK_GOOGLE_display_timing") // 93 -class VkPastPresentationTimingGOOGLE { - u32 presentID - u64 desiredPresentTime - u64 actualPresentTime - u64 earliestPresentTime - u64 presentMargin -} - -@extension("VK_GOOGLE_display_timing") // 93 -class VkPresentTimeGOOGLE { - u32 presentID - u64 desiredPresentTime -} - -@extension("VK_GOOGLE_display_timing") // 93 -class VkPresentTimesInfoGOOGLE { - VkStructureType sType - const void* pNext - u32 swapchainCount - const VkPresentTimeGOOGLE* pTimes -} - -@extension("VK_NVX_multiview_per_view_attributes") // 98 -class VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX { - VkStructureType sType - void* pNext - VkBool32 perViewPositionAllComponents -} - -@extension("VK_NV_viewport_swizzle") // 99 -class VkViewportSwizzleNV { - VkViewportCoordinateSwizzleNV x - VkViewportCoordinateSwizzleNV y - VkViewportCoordinateSwizzleNV z - VkViewportCoordinateSwizzleNV w -} - -@extension("VK_NV_viewport_swizzle") // 99 -class VkPipelineViewportSwizzleStateCreateInfoNV { - VkStructureType sType - const void* pNext - VkPipelineViewportSwizzleStateCreateFlagsNV flags - u32 viewportCount - const VkViewportSwizzleNV* pViewportSwizzles -} - -@extension("VK_EXT_discard_rectangles") // 100 -class VkPhysicalDeviceDiscardRectanglePropertiesEXT { - VkStructureType sType - void* pNext - u32 maxDiscardRectangles -} - -@extension("VK_EXT_discard_rectangles") // 100 -class VkPipelineDiscardRectangleStateCreateInfoEXT { - VkStructureType sType - const void* pNext - VkPipelineDiscardRectangleStateCreateFlagsEXT flags - VkDiscardRectangleModeEXT discardRectangleMode - u32 discardRectangleCount - const VkRect2D* pDiscardRectangles -} - -@extension("VK_EXT_conservative_rasterization") // 102 -class VkPhysicalDeviceConservativeRasterizationPropertiesEXT { - VkStructureType sType - void* pNext - f32 primitiveOverestimationSize - f32 maxExtraPrimitiveOverestimationSize - f32 extraPrimitiveOverestimationSizeGranularity - VkBool32 primitiveUnderestimation - VkBool32 conservativePointAndLineRasterization - VkBool32 degenerateTrianglesRasterized - VkBool32 degenerateLinesRasterized - VkBool32 fullyCoveredFragmentShaderInputVariable - VkBool32 conservativeRasterizationPostDepthCoverage -} - -@extension("VK_EXT_conservative_rasterization") // 102 -class VkPipelineRasterizationConservativeStateCreateInfoEXT { - VkStructureType sType - const void* pNext - VkPipelineRasterizationConservativeStateCreateFlagsEXT flags - VkConservativeRasterizationModeEXT conservativeRasterizationMode - f32 extraPrimitiveOverestimationSize -} - -@extension("VK_EXT_hdr_metadata") // 106 -class VkXYColorEXT { - f32 x - f32 y -} - -@extension("VK_EXT_hdr_metadata") // 106 -class VkHdrMetadataEXT { - VkStructureType sType - const void* pNext - VkXYColorEXT displayPrimaryRed - VkXYColorEXT displayPrimaryGreen - VkXYColorEXT displayPrimaryBlue - VkXYColorEXT whitePoint - f32 maxLuminance - f32 minLuminance - f32 maxContentLightLevel - f32 maxFrameAverageLightLevel -} - -@extension("VK_KHR_create_renderpass2") // 110 -class VkAttachmentDescription2KHR { - VkStructureType sType - const void* pNext - VkAttachmentDescriptionFlags flags - VkFormat format - VkSampleCountFlagBits samples - VkAttachmentLoadOp loadOp - VkAttachmentStoreOp storeOp - VkAttachmentLoadOp stencilLoadOp - VkAttachmentStoreOp stencilStoreOp - VkImageLayout initialLayout - VkImageLayout finalLayout -} - -@extension("VK_KHR_create_renderpass2") // 110 -class VkAttachmentReference2KHR { - VkStructureType sType - const void* pNext - u32 attachment - VkImageLayout layout - VkImageAspectFlags aspectMask -} - -@extension("VK_KHR_create_renderpass2") // 110 -class VkSubpassDescription2KHR { - VkStructureType sType - const void* pNext - VkSubpassDescriptionFlags flags - VkPipelineBindPoint pipelineBindPoint - u32 viewMask - u32 inputAttachmentCount - const VkAttachmentReference2KHR* pInputAttachments - u32 colorAttachmentCount - const VkAttachmentReference2KHR* pColorAttachments - const VkAttachmentReference2KHR* pResolveAttachments - const VkAttachmentReference2KHR* pDepthStencilAttachment - u32 preserveAttachmentCount - const u32* pPreserveAttachments -} - -@extension("VK_KHR_create_renderpass2") // 110 -class VkSubpassDependency2KHR { - VkStructureType sType - const void* pNext - u32 srcSubpass - u32 dstSubpass - VkPipelineStageFlags srcStageMask - VkPipelineStageFlags dstStageMask - VkAccessFlags srcAccessMask - VkAccessFlags dstAccessMask - VkDependencyFlags dependencyFlags - s32 viewOffset -} - -@extension("VK_KHR_create_renderpass2") // 110 -class VkRenderPassCreateInfo2KHR { - VkStructureType sType - const void* pNext - VkRenderPassCreateFlags flags - u32 attachmentCount - const VkAttachmentDescription2KHR* pAttachments - u32 subpassCount - const VkSubpassDescription2KHR* pSubpasses - u32 dependencyCount - const VkSubpassDependency2KHR* pDependencies - u32 correlatedViewMaskCount - const u32* pCorrelatedViewMasks -} - -@extension("VK_KHR_create_renderpass2") // 110 -class VkSubpassBeginInfoKHR { - VkStructureType sType - const void* pNext - VkSubpassContents contents -} - -@extension("VK_KHR_create_renderpass2") // 110 -class VkSubpassEndInfoKHR { - VkStructureType sType - const void* pNext -} - -@extension("VK_KHR_shared_presentable_image") // 112 -class VkSharedPresentSurfaceCapabilitiesKHR { - VkStructureType sType - const void* pNext - VkImageUsageFlags sharedPresentSupportedUsageFlags -} - -@extension("VK_KHR_external_fence_capabilities") // 113 -class VkPhysicalDeviceExternalFenceInfoKHR { - VkStructureType sType - const void* pNext - VkExternalFenceHandleTypeFlagBitsKHR handleType -} - -@extension("VK_KHR_external_fence_capabilities") // 113 -class VkExternalFencePropertiesKHR { - VkStructureType sType - void* pNext - VkExternalFenceHandleTypeFlagsKHR exportFromImportedHandleTypes - VkExternalFenceHandleTypeFlagsKHR compatibleHandleTypes - VkExternalFenceFeatureFlagsKHR externalFenceFeatures -} - -@extension("VK_KHR_external_fence") // 114 -class VkExportFenceCreateInfoKHR { - VkStructureType sType - const void* pNext - VkExternalFenceHandleTypeFlagsKHR handleTypes -} - -@extension("VK_KHR_external_fence_win32") // 115 -class VkImportFenceWin32HandleInfoKHR { - VkStructureType sType - const void* pNext - VkFence fence - VkFenceImportFlagsKHR flags - VkExternalFenceHandleTypeFlagBitsKHR handleType - platform.HANDLE handle - platform.LPCWSTR name -} - -@extension("VK_KHR_external_fence_win32") // 115 -class VkExportFenceWin32HandleInfoKHR { - VkStructureType sType - const void* pNext - const platform.SECURITY_ATTRIBUTES* pAttributes - platform.DWORD dwAccess - platform.LPCWSTR name -} - -@extension("VK_KHR_external_fence_win32") // 115 -class VkFenceGetWin32HandleInfoKHR { - VkStructureType sType - const void* pNext - VkFence fence - VkExternalFenceHandleTypeFlagBitsKHR handleType -} - -@extension("VK_KHR_external_fence_fd") // 116 -class VkImportFenceFdInfoKHR { - VkStructureType sType - const void* pNext - VkFence fence - VkFenceImportFlagsKHR flags - VkExternalFenceHandleTypeFlagBitsKHR handleType - int fd -} - -@extension("VK_KHR_external_fence_fd") // 116 -class VkFenceGetFdInfoKHR { - VkStructureType sType - const void* pNext - VkFence fence - VkExternalFenceHandleTypeFlagBitsKHR handleType -} - -@extension("VK_KHR_maintenance2") // 118 -class VkPhysicalDevicePointClippingPropertiesKHR { - VkStructureType sType - void* pNext - VkPointClippingBehaviorKHR pointClippingBehavior -} - -@extension("VK_KHR_maintenance2") // 118 -class VkInputAttachmentAspectReferenceKHR { - u32 subpass - u32 inputAttachmentIndex - VkImageAspectFlags aspectMask -} - -@extension("VK_KHR_maintenance2") // 118 -class VkRenderPassInputAttachmentAspectCreateInfoKHR { - VkStructureType sType - const void* pNext - u32 aspectReferenceCount - const VkInputAttachmentAspectReferenceKHR* pAspectReferences -} - -@extension("VK_KHR_maintenance2") // 118 -class VkImageViewUsageCreateInfoKHR { - VkStructureType sType - const void* pNext - VkImageUsageFlags usage -} - -@extension("VK_KHR_maintenance2") // 118 -class VkPipelineTessellationDomainOriginStateCreateInfoKHR { - VkStructureType sType - const void* pNext - VkTessellationDomainOriginKHR domainOrigin -} - -@extension("VK_KHR_get_surface_capabilities2") // 120 -class VkPhysicalDeviceSurfaceInfo2KHR { - VkStructureType sType - const void* pNext - VkSurfaceKHR surface -} - -@extension("VK_KHR_get_surface_capabilities2") // 120 -class VkSurfaceCapabilities2KHR { - VkStructureType sType - void* pNext - VkSurfaceCapabilitiesKHR surfaceCapabilities -} - -@extension("VK_KHR_get_surface_capabilities2") // 120 -class VkSurfaceFormat2KHR { - VkStructureType sType - void* pNext - VkSurfaceFormatKHR surfaceFormat -} - -@extension("VK_KHR_variable_pointers") // 121 -class VkPhysicalDeviceVariablePointerFeaturesKHR { - VkStructureType sType - void* pNext - VkBool32 variablePointersStorageBuffer - VkBool32 variablePointers -} - -@extension("VK_KHR_display_properties2") // 122 -class VkDisplayProperties2KHR { - VkStructureType sType - void* pNext - VkDisplayPropertiesKHR displayProperties -} - -@extension("VK_KHR_display_properties2") // 122 -class VkDisplayPlaneProperties2KHR { - VkStructureType sType - void* pNext - VkDisplayPlanePropertiesKHR displayPlaneProperties -} - -@extension("VK_KHR_display_properties2") // 122 -class VkDisplayModeProperties2KHR { - VkStructureType sType - void* pNext - VkDisplayModePropertiesKHR displayModeProperties -} - -@extension("VK_KHR_display_properties2") // 122 -class VkDisplayPlaneInfo2KHR { - VkStructureType sType - const void* pNext - VkDisplayModeKHR mode - u32 planeIndex -} - -@extension("VK_KHR_display_properties2") // 122 -class VkDisplayPlaneCapabilities2KHR { - VkStructureType sType - void* pNext - VkDisplayPlaneCapabilitiesKHR capabilities -} - -@extension("VK_MVK_ios_surface") // 123 -class VkIOSSurfaceCreateInfoMVK { - VkStructureType sType - const void* pNext - VkIOSSurfaceCreateFlagsMVK flags - const void* pView -} - -@extension("VK_MVK_macos_surface") // 124 -class VkMacOSSurfaceCreateInfoMVK { - VkStructureType sType - const void* pNext - VkMacOSSurfaceCreateFlagsMVK flags - const void* pView -} - -@extension("VK_KHR_dedicated_allocation") // 128 -class VkMemoryDedicatedRequirementsKHR { - VkStructureType sType - void* pNext - VkBool32 prefersDedicatedAllocation - VkBool32 requiresDedicatedAllocation -} - -@extension("VK_KHR_dedicated_allocation") // 128 -class VkMemoryDedicatedAllocateInfoKHR { - VkStructureType sType - const void* pNext - VkImage image - VkBuffer buffer -} - -@extension("VK_EXT_debug_utils") // 129 -class VkDebugUtilsObjectNameInfoEXT { - VkStructureType sType - const void* pNext - VkObjectType objectType - u64 objectHandle - const char* pObjectName -} - -@extension("VK_EXT_debug_utils") // 129 -class VkDebugUtilsObjectTagInfoEXT { - VkStructureType sType - const void* pNext - VkObjectType objectType - u64 objectHandle - u64 tagName - platform.size_t tagSize - const void* pTag -} - -@extension("VK_EXT_debug_utils") // 129 -class VkDebugUtilsLabelEXT { - VkStructureType sType - const void* pNext - const char* pLabelName - f32[4] color -} - -@extension("VK_EXT_debug_utils") // 129 -class VkDebugUtilsMessengerCallbackDataEXT { - VkStructureType sType - const void* pNext - VkDebugUtilsMessengerCallbackDataFlagsEXT flags - const char* pMessageIdName - s32 messageIdNumber - const char* pMessage - u32 queueLabelCount - const VkDebugUtilsLabelEXT* pQueueLabels - u32 cmdBufLabelCount - const VkDebugUtilsLabelEXT* pCmdBufLabels - u32 objectCount - const VkDebugUtilsObjectNameInfoEXT* pObjects -} - -@extension("VK_EXT_debug_utils") // 129 -class VkDebugUtilsMessengerCreateInfoEXT { - VkStructureType sType - const void* pNext - VkDebugUtilsMessengerCreateFlagsEXT flags - VkDebugUtilsMessageSeverityFlagsEXT messageSeverity - VkDebugUtilsMessageTypeFlagsEXT messageTypes - PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback - void* pUserData -} - -@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 131 -class VkAndroidHardwareBufferUsageANDROID { - VkStructureType sType - void* pNext - u64 androidHardwareBufferUsage -} - -@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130 -class VkAndroidHardwareBufferPropertiesANDROID { - VkStructureType sType - void* pNext - VkDeviceSize allocationSize - u32 memoryTypeBits -} - -@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130 -class VkAndroidHardwareBufferFormatPropertiesANDROID { - VkStructureType sType - void* pNext - VkFormat format - u64 externalFormat - VkFormatFeatureFlags formatFeatures - VkComponentMapping samplerYcbcrConversionComponents - VkSamplerYcbcrModelConversion suggestedYcbcrModel - VkSamplerYcbcrRange suggestedYcbcrRange - VkChromaLocation suggestedXChromaOffset - VkChromaLocation suggestedYChromaOffset -} - -@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130 -class VkImportAndroidHardwareBufferInfoANDROID { - VkStructureType sType - const void* pNext - platform.AHardwareBuffer* buffer -} - -@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130 -class VkMemoryGetAndroidHardwareBufferInfoANDROID { - VkStructureType sType - const void* pNext - VkDeviceMemory memory -} - -@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130 -class VkExternalFormatANDROID { - VkStructureType sType - void* pNext - u64 externalFormat -} - -@extension("VK_EXT_sampler_filter_minmax") // 131 -class VkSamplerReductionModeCreateInfoEXT { - VkStructureType sType - const void* pNext - VkSamplerReductionModeEXT reductionMode -} - -@extension("VK_EXT_sampler_filter_minmax") // 131 -class VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT { - VkStructureType sType - void* pNext - VkBool32 filterMinmaxSingleComponentFormats - VkBool32 filterMinmaxImageComponentMapping -} - -@extension("VK_EXT_inline_uniform_block") // 139 -class VkPhysicalDeviceInlineUniformBlockFeaturesEXT { - VkStructureType sType - void* pNext - VkBool32 inlineUniformBlock - VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind -} - -@extension("VK_EXT_inline_uniform_block") // 139 -class VkPhysicalDeviceInlineUniformBlockPropertiesEXT { - VkStructureType sType - void* pNext - u32 maxInlineUniformBlockSize - u32 maxPerStageDescriptorInlineUniformBlocks - u32 maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks - u32 maxDescriptorSetInlineUniformBlocks - u32 maxDescriptorSetUpdateAfterBindInlineUniformBlocks -} - -@extension("VK_EXT_inline_uniform_block") // 139 -class VkWriteDescriptorSetInlineUniformBlockEXT { - VkStructureType sType - const void* pNext - u32 dataSize - const void* pData -} - -@extension("VK_EXT_inline_uniform_block") // 139 -class VkDescriptorPoolInlineUniformBlockCreateInfoEXT { - VkStructureType sType - const void* pNext - u32 maxInlineUniformBlockBindings -} - -@extension("VK_EXT_sample_locations") // 144 -class VkSampleLocationEXT { - f32 x - f32 y -} - -@extension("VK_EXT_sample_locations") // 144 -class VkSampleLocationsInfoEXT { - VkStructureType sType - const void* pNext - VkSampleCountFlagBits sampleLocationsPerPixel - VkExtent2D sampleLocationGridSize - u32 sampleLocationsCount - const VkSampleLocationEXT* pSampleLocations -} - -@extension("VK_EXT_sample_locations") // 144 -class VkAttachmentSampleLocationsEXT { - u32 attachmentIndex - VkSampleLocationsInfoEXT sampleLocationsInfo -} - -@extension("VK_EXT_sample_locations") // 144 -class VkSubpassSampleLocationsEXT { - u32 subpassIndex - VkSampleLocationsInfoEXT sampleLocationsInfo -} - -@extension("VK_EXT_sample_locations") // 144 -class VkRenderPassSampleLocationsBeginInfoEXT { - VkStructureType sType - const void* pNext - u32 attachmentInitialSampleLocationsCount - const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations - u32 postSubpassSampleLocationsCount - const VkSubpassSampleLocationsEXT* pPostSubpassSampleLocations -} - -@extension("VK_EXT_sample_locations") // 144 -class VkPipelineSampleLocationsStateCreateInfoEXT { - VkStructureType sType - const void* pNext - VkBool32 sampleLocationsEnable - VkSampleLocationsInfoEXT sampleLocationsInfo -} - -@extension("VK_EXT_sample_locations") // 144 -class VkPhysicalDeviceSampleLocationsPropertiesEXT { - VkStructureType sType - void* pNext - VkSampleCountFlags sampleLocationSampleCounts - VkExtent2D maxSampleLocationGridSize - f32[2] sampleLocationCoordinateRange - u32 sampleLocationSubPixelBits - VkBool32 variableSampleLocations -} - -@extension("VK_EXT_sample_locations") // 144 -class VkMultisamplePropertiesEXT { - VkStructureType sType - void* pNext - VkExtent2D maxSampleLocationGridSize -} - -@extension("VK_KHR_get_memory_requirements2") // 147 -class VkBufferMemoryRequirementsInfo2KHR { - VkStructureType sType - const void* pNext - VkBuffer buffer -} - -@extension("VK_KHR_get_memory_requirements2") // 147 -class VkImageMemoryRequirementsInfo2KHR { - VkStructureType sType - const void* pNext - VkImage image -} - -@extension("VK_KHR_get_memory_requirements2") // 147 -class VkImageSparseMemoryRequirementsInfo2KHR { - VkStructureType sType - const void* pNext - VkImage image -} - -@extension("VK_KHR_get_memory_requirements2") // 147 -class VkMemoryRequirements2KHR { - VkStructureType sType - void* pNext - VkMemoryRequirements memoryRequirements -} - -@extension("VK_KHR_get_memory_requirements2") // 147 -class VkSparseImageMemoryRequirements2KHR { - VkStructureType sType - void* pNext - VkSparseImageMemoryRequirements memoryRequirements -} - -@extension("VK_KHR_image_format_list") // 148 -class VkImageFormatListCreateInfoKHR { - VkStructureType sType - const void* pNext - u32 viewFormatCount - const VkFormat* pViewFormats -} - -@extension("VK_EXT_blend_operation_advanced") // 149 -class VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT { - VkStructureType sType - void* pNext - VkBool32 advancedBlendCoherentOperations -} - -@extension("VK_EXT_blend_operation_advanced") // 149 -class VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT { - VkStructureType sType - void* pNext - u32 advancedBlendMaxColorAttachments - VkBool32 advancedBlendIndependentBlend - VkBool32 advancedBlendNonPremultipliedSrcColor - VkBool32 advancedBlendNonPremultipliedDstColor - VkBool32 advancedBlendCorrelatedOverlap - VkBool32 advancedBlendAllOperations -} - -@extension("VK_EXT_blend_operation_advanced") // 149 -class VkPipelineColorBlendAdvancedStateCreateInfoEXT { - VkStructureType sType - const void* pNext - VkBool32 srcPremultiplied - VkBool32 dstPremultiplied - VkBlendOverlapEXT blendOverlap -} - -@extension("VK_NV_fragment_coverage_to_color") // 150 -class VkPipelineCoverageToColorStateCreateInfoNV { - VkStructureType sType - const void* pNext - VkPipelineCoverageToColorStateCreateFlagsNV flags - VkBool32 coverageToColorEnable - u32 coverageToColorLocation -} - -@extension("VK_NV_framebuffer_mixed_samples") // 153 -class VkPipelineCoverageModulationStateCreateInfoNV { - VkStructureType sType - const void* pNext - VkPipelineCoverageModulationStateCreateFlagsNV flags - VkCoverageModulationModeNV coverageModulationMode - VkBool32 coverageModulationTableEnable - u32 coverageModulationTableCount - const f32* pCoverageModulationTable -} - -@extension("VK_KHR_sampler_ycbcr_conversion") // 157 -class VkSamplerYcbcrConversionCreateInfoKHR { - VkStructureType sType - const void* pNext - VkFormat format - VkSamplerYcbcrModelConversionKHR ycbcrModel - VkSamplerYcbcrRangeKHR ycbcrRange - VkComponentMapping components - VkChromaLocationKHR xChromaOffset - VkChromaLocationKHR yChromaOffset - VkFilter chromaFilter - VkBool32 forceExplicitReconstruction -} - -@extension("VK_KHR_sampler_ycbcr_conversion") // 157 -class VkSamplerYcbcrConversionInfoKHR { - VkStructureType sType - const void* pNext - VkSamplerYcbcrConversionKHR conversion -} - -@extension("VK_KHR_sampler_ycbcr_conversion") // 157 -class VkBindImagePlaneMemoryInfoKHR { - VkStructureType sType - const void* pNext - VkImageAspectFlagBits planeAspect -} - -@extension("VK_KHR_sampler_ycbcr_conversion") // 157 -class VkImagePlaneMemoryRequirementsInfoKHR { - VkStructureType sType - const void* pNext - VkImageAspectFlagBits planeAspect -} - -@extension("VK_KHR_sampler_ycbcr_conversion") // 157 -class VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR { - VkStructureType sType - void* pNext - VkBool32 samplerYcbcrConversion -} - -@extension("VK_KHR_sampler_ycbcr_conversion") // 157 -class VkSamplerYcbcrConversionImageFormatPropertiesKHR { - VkStructureType sType - void* pNext - u32 combinedImageSamplerDescriptorCount -} - -@extension("VK_KHR_bind_memory2") // 158 -class VkBindBufferMemoryInfoKHR { - VkStructureType sType - const void* pNext - VkBuffer buffer - VkDeviceMemory memory - VkDeviceSize memoryOffset -} - -@extension("VK_KHR_bind_memory2") // 158 -class VkBindImageMemoryInfoKHR { - VkStructureType sType - const void* pNext - VkImage image - VkDeviceMemory memory - VkDeviceSize memoryOffset -} - -@extension("VK_EXT_image_drm_format_modifier") // 159 -class VkDrmFormatModifierPropertiesEXT { - u64 drmFormatModifier - u32 drmFormatModifierPlaneCount - VkFormatFeatureFlags drmFormatModifierTilingFeatures -} - -@extension("VK_EXT_image_drm_format_modifier") // 159 -class VkDrmFormatModifierPropertiesListEXT { - VkStructureType sType - void* pNext - u32 drmFormatModifierCount - VkDrmFormatModifierPropertiesEXT* pDrmFormatModifierProperties -} - -@extension("VK_EXT_image_drm_format_modifier") // 159 -class VkPhysicalDeviceImageDrmFormatModifierInfoEXT { - VkStructureType sType - const void* pNext - u64 drmFormatModifier - VkSharingMode sharingMode - u32 queueFamilyIndexCount - const u32* pQueueFamilyIndices -} - -@extension("VK_EXT_image_drm_format_modifier") // 159 -class VkImageDrmFormatModifierListCreateInfoEXT { - VkStructureType sType - const void* pNext - u32 drmFormatModifierCount - const u64* pDrmFormatModifiers -} - -@extension("VK_EXT_image_drm_format_modifier") // 159 -class VkImageDrmFormatModifierExplicitCreateInfoEXT { - VkStructureType sType - const void* pNext - u64 drmFormatModifier - u32 drmFormatModifierPlaneCount - const VkSubresourceLayout* pPlaneLayouts -} - -@extension("VK_EXT_image_drm_format_modifier") // 159 -class VkImageDrmFormatModifierPropertiesEXT { - VkStructureType sType - void* pNext - u64 drmFormatModifier -} - -@extension("VK_EXT_validation_cache") // 161 -class VkValidationCacheCreateInfoEXT { - VkStructureType sType - const void* pNext - VkValidationCacheCreateFlagsEXT flags - platform.size_t initialDataSize - const void* pInitialData -} - -@extension("VK_EXT_validation_cache") // 161 -class VkShaderModuleValidationCacheCreateInfoEXT { - VkStructureType sType - const void* pNext - VkValidationCacheEXT validationCache -} - -@extension("VK_EXT_descriptor_indexing") // 162 -class VkDescriptorSetLayoutBindingFlagsCreateInfoEXT { - VkStructureType sType - const void* pNext - u32 bindingCount - const VkDescriptorBindingFlagsEXT* pBindingFlags -} - -@extension("VK_EXT_descriptor_indexing") // 162 -class VkPhysicalDeviceDescriptorIndexingFeaturesEXT { - VkStructureType sType - void* pNext - VkBool32 shaderInputAttachmentArrayDynamicIndexing - VkBool32 shaderUniformTexelBufferArrayDynamicIndexing - VkBool32 shaderStorageTexelBufferArrayDynamicIndexing - VkBool32 shaderUniformBufferArrayNonUniformIndexing - VkBool32 shaderSampledImageArrayNonUniformIndexing - VkBool32 shaderStorageBufferArrayNonUniformIndexing - VkBool32 shaderStorageImageArrayNonUniformIndexing - VkBool32 shaderInputAttachmentArrayNonUniformIndexing - VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing - VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing - VkBool32 descriptorBindingUniformBufferUpdateAfterBind - VkBool32 descriptorBindingSampledImageUpdateAfterBind - VkBool32 descriptorBindingStorageImageUpdateAfterBind - VkBool32 descriptorBindingStorageBufferUpdateAfterBind - VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind - VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind - VkBool32 descriptorBindingUpdateUnusedWhilePending - VkBool32 descriptorBindingPartiallyBound - VkBool32 descriptorBindingVariableDescriptorCount - VkBool32 runtimeDescriptorArray -} - -@extension("VK_EXT_descriptor_indexing") // 162 -class VkPhysicalDeviceDescriptorIndexingPropertiesEXT { - VkStructureType sType - void* pNext - u32 maxUpdateAfterBindDescriptorsInAllPools - VkBool32 shaderUniformBufferArrayNonUniformIndexingNative - VkBool32 shaderSampledImageArrayNonUniformIndexingNative - VkBool32 shaderStorageBufferArrayNonUniformIndexingNative - VkBool32 shaderStorageImageArrayNonUniformIndexingNative - VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative - VkBool32 robustBufferAccessUpdateAfterBind - VkBool32 quadDivergentImplicitLod - u32 maxPerStageDescriptorUpdateAfterBindSamplers - u32 maxPerStageDescriptorUpdateAfterBindUniformBuffers - u32 maxPerStageDescriptorUpdateAfterBindStorageBuffers - u32 maxPerStageDescriptorUpdateAfterBindSampledImages - u32 maxPerStageDescriptorUpdateAfterBindStorageImages - u32 maxPerStageDescriptorUpdateAfterBindInputAttachments - u32 maxPerStageUpdateAfterBindResources - u32 maxDescriptorSetUpdateAfterBindSamplers - u32 maxDescriptorSetUpdateAfterBindUniformBuffers - u32 maxDescriptorSetUpdateAfterBindUniformBuffersDynamic - u32 maxDescriptorSetUpdateAfterBindStorageBuffers - u32 maxDescriptorSetUpdateAfterBindStorageBuffersDynamic - u32 maxDescriptorSetUpdateAfterBindSampledImages - u32 maxDescriptorSetUpdateAfterBindStorageImages - u32 maxDescriptorSetUpdateAfterBindInputAttachments -} - -@extension("VK_EXT_descriptor_indexing") // 162 -class VkDescriptorSetVariableDescriptorCountAllocateInfoEXT { - VkStructureType sType - const void* pNext - u32 descriptorSetCount - const u32* pDescriptorCounts -} - -@extension("VK_EXT_descriptor_indexing") // 162 -class VkDescriptorSetVariableDescriptorCountLayoutSupportEXT { - VkStructureType sType - void* pNext - u32 maxVariableDescriptorCount -} - -@extension("VK_NV_shading_rate_image") // 165 -class VkShadingRatePaletteNV { - u32 shadingRatePaletteEntryCount - const VkShadingRatePaletteEntryNV* pShadingRatePaletteEntries -} - -@extension("VK_NV_shading_rate_image") // 165 -class VkPipelineViewportShadingRateImageStateCreateInfoNV { - VkStructureType sType - const void* pNext - VkBool32 shadingRateImageEnable - u32 viewportCount - const VkShadingRatePaletteNV* pShadingRatePalettes -} - -@extension("VK_NV_shading_rate_image") // 165 -class VkPhysicalDeviceShadingRateImageFeaturesNV { - VkStructureType sType - void* pNext - VkBool32 shadingRateImage - VkBool32 shadingRateCoarseSampleOrder -} - -@extension("VK_NV_shading_rate_image") // 165 -class VkPhysicalDeviceShadingRateImagePropertiesNV { - VkStructureType sType - void* pNext - VkExtent2D shadingRateTexelSize - u32 shadingRatePaletteSize - u32 shadingRateMaxCoarseSamples -} - -@extension("VK_NV_shading_rate_image") // 165 -class VkCoarseSampleLocationNV { - u32 pixelX - u32 pixelY - u32 sample -} - -@extension("VK_NV_shading_rate_image") // 165 -class VkCoarseSampleOrderCustomNV { - VkShadingRatePaletteEntryNV shadingRate - u32 sampleCount - u32 sampleLocationCount - const VkCoarseSampleLocationNV* pSampleLocations -} - -@extension("VK_NV_shading_rate_image") // 165 -class VkPipelineViewportCoarseSampleOrderStateCreateInfoNV { - VkStructureType sType - const void* pNext - VkCoarseSampleOrderTypeNV sampleOrderType - u32 customSampleOrderCount - const VkCoarseSampleOrderCustomNV* pCustomSampleOrders -} - -@extension("VK_NV_ray_tracing") // 166 -class VkRayTracingShaderGroupCreateInfoNV { - VkStructureType sType - const void* pNext - VkRayTracingShaderGroupTypeNV type - u32 generalShader - u32 closestHitShader - u32 anyHitShader - u32 intersectionShader -} - -@extension("VK_NV_ray_tracing") // 166 -class VkRayTracingPipelineCreateInfoNV { - VkStructureType sType - const void* pNext - VkPipelineCreateFlags flags - u32 stageCount - const VkPipelineShaderStageCreateInfo* pStages - u32 groupCount - const VkRayTracingShaderGroupCreateInfoNV* pGroups - u32 maxRecursionDepth - VkPipelineLayout layout - VkPipeline basePipelineHandle - s32 basePipelineIndex -} - -@extension("VK_NV_ray_tracing") // 166 -class VkGeometryTrianglesNV { - VkStructureType sType - const void* pNext - VkBuffer vertexData - VkDeviceSize vertexOffset - u32 vertexCount - VkDeviceSize vertexStride - VkFormat vertexFormat - VkBuffer indexData - VkDeviceSize indexOffset - u32 indexCount - VkIndexType indexType - VkBuffer transformData - VkDeviceSize transformOffset -} - -@extension("VK_NV_ray_tracing") // 166 -class VkGeometryAABBNV { - VkStructureType sType - const void* pNext - VkBuffer aabbData - u32 numAABBs - u32 stride - VkDeviceSize offset -} - -@extension("VK_NV_ray_tracing") // 166 -class VkGeometryDataNV { - VkGeometryTrianglesNV triangles - VkGeometryAABBNV aabbs -} - -@extension("VK_NV_ray_tracing") // 166 -class VkGeometryNV { - VkStructureType sType - const void* pNext - VkGeometryTypeNV geometryType - VkGeometryDataNV geometry - VkGeometryFlagsNV flags -} - -@extension("VK_NV_ray_tracing") // 166 -class VkAccelerationStructureInfoNV { - VkStructureType sType - const void* pNext - VkAccelerationStructureTypeNV type - VkBuildAccelerationStructureFlagsNV flags - u32 instanceCount - u32 geometryCount - const VkGeometryNV* pGeometries -} - -@extension("VK_NV_ray_tracing") // 166 -class VkAccelerationStructureCreateInfoNV { - VkStructureType sType - const void* pNext - VkDeviceSize compactedSize - VkAccelerationStructureInfoNV info -} - -@extension("VK_NV_ray_tracing") // 166 -class VkBindAccelerationStructureMemoryInfoNV { - VkStructureType sType - const void* pNext - VkAccelerationStructureNV accelerationStructure - VkDeviceMemory memory - VkDeviceSize memoryOffset - u32 deviceIndexCount - const u32* pDeviceIndices -} - -@extension("VK_NV_ray_tracing") // 166 -class VkDescriptorAccelerationStructureInfoNV { - VkStructureType sType - const void* pNext - u32 accelerationStructureCount - const VkAccelerationStructureNV* pAccelerationStructures -} - -@extension("VK_NV_ray_tracing") // 166 -class VkAccelerationStructureMemoryRequirementsInfoNV { - VkStructureType sType - const void* pNext - VkAccelerationStructureMemoryRequirementsTypeNV type - VkAccelerationStructureNV accelerationStructure -} - -@extension("VK_NV_ray_tracing") // 166 -class VkPhysicalDeviceRaytracingPropertiesNV { - VkStructureType sType - void* pNext - u32 shaderGroupHandleSize - u32 maxRecursionDepth - u32 maxShaderGroupStride - u32 shaderGroupBaseAlignment - u64 maxGeometryCount - u64 maxInstanceCount - u64 maxTriangleCount - u32 maxDescriptorSetAccelerationStructures -} - -@extension("VK_NV_representative_fragment_test") // 167 -class VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV { - VkStructureType sType - void* pNext - VkBool32 representativeFragmentTest -} - -@extension("VK_NV_representative_fragment_test") // 167 -class VkPipelineRepresentativeFragmentTestStateCreateInfoNV { - VkStructureType sType - const void* pNext - VkBool32 representativeFragmentTestEnable -} - -@extension("VK_KHR_maintenance3") // 169 -class VkPhysicalDeviceMaintenance3PropertiesKHR { - VkStructureType sType - void* pNext - u32 maxPerSetDescriptors - VkDeviceSize maxMemoryAllocationSize -} - -@extension("VK_KHR_maintenance3") // 169 -class VkDescriptorSetLayoutSupportKHR { - VkStructureType sType - void* pNext - VkBool32 supported -} - -@extension("VK_EXT_global_priority") // 175 -class VkDeviceQueueGlobalPriorityCreateInfoEXT { - VkStructureType sType - const void* pNext - VkQueueGlobalPriorityEXT globalPriority -} - -@extension("VK_KHR_8bit_storage") // 178 -class VkPhysicalDevice8BitStorageFeaturesKHR { - VkStructureType sType - void* pNext - VkBool32 storageBuffer8BitAccess - VkBool32 uniformAndStorageBuffer8BitAccess - VkBool32 storagePushConstant8 -} - -@extension("VK_EXT_external_memory_host") // 179 -class VkImportMemoryHostPointerInfoEXT { - VkStructureType sType - const void* pNext - VkExternalMemoryHandleTypeFlagBits handleType - void* pHostPointer -} - -@extension("VK_EXT_external_memory_host") // 179 -class VkMemoryHostPointerPropertiesEXT { - VkStructureType sType - void* pNext - u32 memoryTypeBits -} - -@extension("VK_EXT_external_memory_host") // 179 -class VkPhysicalDeviceExternalMemoryHostPropertiesEXT { - VkStructureType sType - void* pNext - VkDeviceSize minImportedHostPointerAlignment -} - -@extension("VK_KHR_shader_atomic_int64") // 181 -class VkPhysicalDeviceShaderAtomicInt64FeaturesKHR { - VkStructureType sType - void* pNext - VkBool32 shaderBufferInt64Atomics - VkBool32 shaderSharedInt64Atomics -} - -@extension("VK_EXT_calibrated_timestamps") // 185 -class VkCalibratedTimestampInfoEXT { - VkStructureType sType - const void* pNext - VkTimeDomainEXT timeDomain -} - -@extension("VK_AMD_shader_core_properties") // 186 -class VkPhysicalDeviceShaderCorePropertiesAMD { - VkStructureType sType - void* pNext - u32 shaderEngineCount - u32 shaderArraysPerEngineCount - u32 computeUnitsPerShaderArray - u32 simdPerComputeUnit - u32 wavefrontsPerSimd - u32 wavefrontSize - u32 sgprsPerSimd - u32 minSgprAllocation - u32 maxSgprAllocation - u32 sgprAllocationGranularity - u32 vgprsPerSimd - u32 minVgprAllocation - u32 maxVgprAllocation - u32 vgprAllocationGranularity -} - -@extension("VK_AMD_memory_overallocation_behavior") // 190 -class VkDeviceMemoryOverallocationCreateInfoAMD { - VkStructureType sType - const void* pNext - VkMemoryOverallocationBehaviorAMD overallocationBehavior -} - -@extension("VK_EXT_vertex_attribute_divisor") // 191 -class VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT { - VkStructureType sType - void* pNext - u32 maxVertexAttribDivisor -} - -@extension("VK_EXT_vertex_attribute_divisor") // 191 -class VkVertexInputBindingDivisorDescriptionEXT { - u32 binding - u32 divisor -} - -@extension("VK_EXT_vertex_attribute_divisor") // 191 -class VkPipelineVertexInputDivisorStateCreateInfoEXT { - VkStructureType sType - const void* pNext - u32 vertexBindingDivisorCount - const VkVertexInputBindingDivisorDescriptionEXT* pVertexBindingDivisors -} - -@extension("VK_EXT_vertex_attribute_divisor") // 191 -class VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT { - VkStructureType sType - void* pNext - VkBool32 vertexAttributeInstanceRateDivisor - VkBool32 vertexAttributeInstanceRateZeroDivisor -} - -@extension("VK_KHR_driver_properties") // 197 -class VkConformanceVersionKHR { - u8 major - u8 minor - u8 subminor - u8 patch -} - -@extension("VK_KHR_driver_properties") // 197 -class VkPhysicalDeviceDriverPropertiesKHR { - VkStructureType sType - void* pNext - VkDriverIdKHR driverID - char[VK_MAX_DRIVER_NAME_SIZE_KHR] driverName - char[VK_MAX_DRIVER_INFO_SIZE_KHR] driverInfo - VkConformanceVersionKHR conformanceVersion -} - -@extension("VK_KHR_shader_float_controls") // 198 -class VkPhysicalDeviceFloatControlsPropertiesKHR { - VkStructureType sType - void* pNext - VkBool32 separateDenormSettings - VkBool32 separateRoundingModeSettings - VkBool32 shaderSignedZeroInfNanPreserveFloat16 - VkBool32 shaderSignedZeroInfNanPreserveFloat32 - VkBool32 shaderSignedZeroInfNanPreserveFloat64 - VkBool32 shaderDenormPreserveFloat16 - VkBool32 shaderDenormPreserveFloat32 - VkBool32 shaderDenormPreserveFloat64 - VkBool32 shaderDenormFlushToZeroFloat16 - VkBool32 shaderDenormFlushToZeroFloat32 - VkBool32 shaderDenormFlushToZeroFloat64 - VkBool32 shaderRoundingModeRTEFloat16 - VkBool32 shaderRoundingModeRTEFloat32 - VkBool32 shaderRoundingModeRTEFloat64 - VkBool32 shaderRoundingModeRTZFloat16 - VkBool32 shaderRoundingModeRTZFloat32 - VkBool32 shaderRoundingModeRTZFloat64 -} - -@extension("VK_NV_compute_shader_derivatives") // 202 -class VkPhysicalDeviceComputeShaderDerivativesFeaturesNV { - VkStructureType sType - void* pNext - VkBool32 computeDerivativeGroupQuads - VkBool32 computeDerivativeGroupLinear -} - -@extension("VK_NV_mesh_shader") // 203 -class VkPhysicalDeviceMeshShaderFeaturesNV { - VkStructureType sType - void* pNext - VkBool32 taskShader - VkBool32 meshShader -} - -@extension("VK_NV_mesh_shader") // 203 -class VkPhysicalDeviceMeshShaderPropertiesNV { - VkStructureType sType - void* pNext - u32 maxDrawMeshTasksCount - u32 maxTaskWorkGroupInvocations - u32[3] maxTaskWorkGroupSize - u32 maxTaskTotalMemorySize - u32 maxTaskOutputCount - u32 maxMeshWorkGroupInvocations - u32[3] maxMeshWorkGroupSize - u32 maxMeshTotalMemorySize - u32 maxMeshOutputVertices - u32 maxMeshOutputPrimitives - u32 maxMeshMultiviewViewCount - u32 meshOutputPerVertexGranularity - u32 meshOutputPerPrimitiveGranularity -} - -@extension("VK_NV_mesh_shader") // 203 -class VkDrawMeshTasksIndirectCommandNV { - u32 taskCount - u32 firstTask -} - -@extension("VK_NV_fragment_shader_barycentric") // 204 -class VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV { - VkStructureType sType - void* pNext - VkBool32 fragmentShaderBarycentric -} - -@extension("VK_NV_shader_image_footprint") // 205 -class VkPhysicalDeviceShaderImageFootprintFeaturesNV { - VkStructureType sType - void* pNext - VkBool32 imageFootprint -} - -@extension("VK_NV_scissor_exclusive") // 206 -class VkPipelineViewportExclusiveScissorStateCreateInfoNV { - VkStructureType sType - const void* pNext - u32 exclusiveScissorCount - const VkRect2D* pExclusiveScissors -} - -@extension("VK_NV_scissor_exclusive") // 206 -class VkPhysicalDeviceExclusiveScissorFeaturesNV { - VkStructureType sType - void* pNext - VkBool32 exclusiveScissor -} - -@extension("VK_NV_device_diagnostic_checkpoints") // 207 -class VkQueueFamilyCheckpointPropertiesNV { - VkStructureType sType - void* pNext - VkPipelineStageFlags checkpointExecutionStageMask -} - -@extension("VK_NV_device_diagnostic_checkpoints") // 207 -class VkCheckpointDataNV { - VkStructureType sType - void* pNext - VkPipelineStageFlagBits stage - void* pCheckpointMarker -} - -@extension("VK_KHR_vulkan_memory_model") // 212 -class VkPhysicalDeviceVulkanMemoryModelFeaturesKHR { - VkStructureType sType - void* pNext - VkBool32 vulkanMemoryModel - VkBool32 vulkanMemoryModelDeviceScope -} - -@extension("VK_EXT_pci_bus_info") // 213 -class VkPhysicalDevicePCIBusInfoPropertiesEXT { - VkStructureType sType - void* pNext - u32 pciDomain - u32 pciBus - u32 pciDevice - u32 pciFunction -} - -@extension("VK_FUCHSIA_imagepipe_surface") // 215 -class VkImagePipeSurfaceCreateInfoFUCHSIA { - VkStructureType sType - const void* pNext - VkImagePipeSurfaceCreateFlagsFUCHSIA flags - platform.zx_handle_t imagePipeHandle -} - -@extension("VK_EXT_fragment_density_map") // 219 -class VkPhysicalDeviceFragmentDensityMapFeaturesEXT { - VkStructureType sType - void* pNext - VkBool32 fragmentDensityMap - VkBool32 fragmentDensityMapDynamic - VkBool32 fragmentDensityMapNonSubsampledImages -} - -@extension("VK_EXT_fragment_density_map") // 219 -class VkPhysicalDeviceFragmentDensityMapPropertiesEXT { - VkStructureType sType - void* pNext - VkExtent2D minFragmentDensityTexelSize - VkExtent2D maxFragmentDensityTexelSize - VkBool32 fragmentDensityInvocations -} - -@extension("VK_EXT_fragment_density_map") // 219 -class VkRenderPassFragmentDensityMapCreateInfoEXT { - VkStructureType sType - const void* pNext - VkAttachmentReference fragmentDensityMapAttachment -} - -@extension("VK_EXT_scalar_block_layout") // 222 -class VkPhysicalDeviceScalarBlockLayoutFeaturesEXT { - VkStructureType sType - void* pNext - VkBool32 scalarBlockLayout -} - -@extension("VK_EXT_separate_stencil_usage") // 247 -class VkImageStencilUsageCreateInfoEXT { - VkStructureType sType - const void* pNext - VkImageUsageFlags stencilUsage -} - - -//////////////// -// Commands // -//////////////// - -// Function pointers. TODO: add support for function pointers. - -@external type void* PFN_vkVoidFunction -@pfn cmd void vkVoidFunction() { -} - -@external type void* PFN_vkAllocationFunction -@pfn cmd void* vkAllocationFunction( - void* pUserData, - platform.size_t size, - platform.size_t alignment, - VkSystemAllocationScope allocationScope) { - return ? -} - -@external type void* PFN_vkReallocationFunction -@pfn cmd void* vkReallocationFunction( - void* pUserData, - void* pOriginal, - platform.size_t size, - platform.size_t alignment, - VkSystemAllocationScope allocationScope) { - return ? -} - -@external type void* PFN_vkFreeFunction -@pfn cmd void vkFreeFunction( - void* pUserData, - void* pMemory) { -} - -@external type void* PFN_vkInternalAllocationNotification -@pfn cmd void vkInternalAllocationNotification( - void* pUserData, - platform.size_t size, - VkInternalAllocationType allocationType, - VkSystemAllocationScope allocationScope) { -} - -@external type void* PFN_vkInternalFreeNotification -@pfn cmd void vkInternalFreeNotification( - void* pUserData, - platform.size_t size, - VkInternalAllocationType allocationType, - VkSystemAllocationScope allocationScope) { -} - -// Global functions - -@threadSafety("system") -cmd VkResult vkCreateInstance( - const VkInstanceCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkInstance* pInstance) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO) - - instance := ? - pInstance[0] = instance - State.Instances[instance] = new!InstanceObject() - - layers := pCreateInfo.ppEnabledLayerNames[0:pCreateInfo.enabledLayerCount] - extensions := pCreateInfo.ppEnabledExtensionNames[0:pCreateInfo.enabledExtensionCount] - - return ? -} - -@threadSafety("system") -cmd void vkDestroyInstance( - VkInstance instance, - const VkAllocationCallbacks* pAllocator) { - instanceObject := GetInstance(instance) - - State.Instances[instance] = null -} - -@threadSafety("system") -cmd VkResult vkEnumeratePhysicalDevices( - VkInstance instance, - u32* pPhysicalDeviceCount, - VkPhysicalDevice* pPhysicalDevices) { - instanceObject := GetInstance(instance) - - physicalDeviceCount := as!u32(?) - pPhysicalDeviceCount[0] = physicalDeviceCount - physicalDevices := pPhysicalDevices[0:physicalDeviceCount] - - for i in (0 .. physicalDeviceCount) { - physicalDevice := ? - physicalDevices[i] = physicalDevice - if !(physicalDevice in State.PhysicalDevices) { - State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance) - } - } - - return ? -} - -cmd PFN_vkVoidFunction vkGetDeviceProcAddr( - VkDevice device, - const char* pName) { - if device != NULL_HANDLE { - device := GetDevice(device) - } - - return ? -} - -cmd PFN_vkVoidFunction vkGetInstanceProcAddr( - VkInstance instance, - const char* pName) { - if instance != NULL_HANDLE { - instanceObject := GetInstance(instance) - } - - return ? -} - -cmd void vkGetPhysicalDeviceProperties( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties* pProperties) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - - properties := ? - pProperties[0] = properties -} - -cmd void vkGetPhysicalDeviceQueueFamilyProperties( - VkPhysicalDevice physicalDevice, - u32* pQueueFamilyPropertyCount, - VkQueueFamilyProperties* pQueueFamilyProperties) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - // TODO: Figure out how to express fetch-count-or-properties - // This version fails 'apic validate' with 'fence not allowed in - // *semantic.Branch'. Other attempts have failed with the same or other - // errors. - // if pQueueFamilyProperties != null { - // queuesProperties := pQueueFamilyProperties[0:pCount[0]] - // for i in (0 .. pCount[0]) { - // queueProperties := as!VkQueueFamilyProperties(?) - // queuesProperties[i] = queueProperties - // } - // } else { - // count := ? - // pCount[0] = count - // } -} - -cmd void vkGetPhysicalDeviceMemoryProperties( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties* pMemoryProperties) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - - memoryProperties := ? - pMemoryProperties[0] = memoryProperties -} - -cmd void vkGetPhysicalDeviceFeatures( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures* pFeatures) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - - features := ? - pFeatures[0] = features -} - -cmd void vkGetPhysicalDeviceFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkFormatProperties* pFormatProperties) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - - formatProperties := ? - pFormatProperties[0] = formatProperties -} - -cmd VkResult vkGetPhysicalDeviceImageFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageCreateFlags flags, - VkImageFormatProperties* pImageFormatProperties) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - - imageFormatProperties := ? - pImageFormatProperties[0] = imageFormatProperties - - return ? -} - - -// Device functions - -@threadSafety("system") -cmd VkResult vkCreateDevice( - VkPhysicalDevice physicalDevice, - const VkDeviceCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDevice* pDevice) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO) - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - - device := ? - pDevice[0] = device - State.Devices[device] = new!DeviceObject(physicalDevice: physicalDevice) - - return ? -} - -@threadSafety("system") -cmd void vkDestroyDevice( - VkDevice device, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - - State.Devices[device] = null -} - - -// Extension discovery functions - -cmd VkResult vkEnumerateInstanceLayerProperties( - u32* pPropertyCount, - VkLayerProperties* pProperties) { - count := as!u32(?) - pPropertyCount[0] = count - - properties := pProperties[0:count] - for i in (0 .. count) { - property := ? - properties[i] = property - } - - return ? -} - -cmd VkResult vkEnumerateInstanceExtensionProperties( - const char* pLayerName, - u32* pPropertyCount, - VkExtensionProperties* pProperties) { - count := as!u32(?) - pPropertyCount[0] = count - - properties := pProperties[0:count] - for i in (0 .. count) { - property := ? - properties[i] = property - } - - return ? -} - -cmd VkResult vkEnumerateDeviceLayerProperties( - VkPhysicalDevice physicalDevice, - u32* pPropertyCount, - VkLayerProperties* pProperties) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - count := as!u32(?) - pPropertyCount[0] = count - - properties := pProperties[0:count] - for i in (0 .. count) { - property := ? - properties[i] = property - } - - return ? -} - -cmd VkResult vkEnumerateDeviceExtensionProperties( - VkPhysicalDevice physicalDevice, - const char* pLayerName, - u32* pPropertyCount, - VkExtensionProperties* pProperties) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - - count := as!u32(?) - pPropertyCount[0] = count - - properties := pProperties[0:count] - for i in (0 .. count) { - property := ? - properties[i] = property - } - - return ? -} - - -// Queue functions - -@threadSafety("system") -cmd void vkGetDeviceQueue( - VkDevice device, - u32 queueFamilyIndex, - u32 queueIndex, - VkQueue* pQueue) { - deviceObject := GetDevice(device) - - queue := ? - pQueue[0] = queue - - if !(queue in State.Queues) { - State.Queues[queue] = new!QueueObject(device: device) - } -} - -@threadSafety("app") -cmd VkResult vkQueueSubmit( - VkQueue queue, - u32 submitCount, - const VkSubmitInfo* pSubmits, - VkFence fence) { - queueObject := GetQueue(queue) - - if fence != NULL_HANDLE { - fenceObject := GetFence(fence) - assert(fenceObject.device == queueObject.device) - } - - // commandBuffers := pcommandBuffers[0:commandBufferCount] - // for i in (0 .. commandBufferCount) { - // commandBuffer := commandBuffers[i] - // commandBufferObject := GetCommandBuffer(commandBuffer) - // assert(commandBufferObject.device == queueObject.device) - // - // validate("QueueCheck", commandBufferObject.queueFlags in queueObject.flags, - // "vkQueueSubmit: enqueued commandBuffer requires missing queue capabilities.") - // } - - return ? -} - -@threadSafety("system") -cmd VkResult vkQueueWaitIdle( - VkQueue queue) { - queueObject := GetQueue(queue) - - return ? -} - -@threadSafety("system") -cmd VkResult vkDeviceWaitIdle( - VkDevice device) { - deviceObject := GetDevice(device) - - return ? -} - - -// Memory functions - -@threadSafety("system") -cmd VkResult vkAllocateMemory( - VkDevice device, - const VkMemoryAllocateInfo* pAllocateInfo, - const VkAllocationCallbacks* pAllocator, - VkDeviceMemory* pMemory) { - assert(pAllocateInfo.sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO) - deviceObject := GetDevice(device) - - memory := ? - pMemory[0] = memory - State.DeviceMemories[memory] = new!DeviceMemoryObject( - device: device, - allocationSize: pAllocateInfo[0].allocationSize) - - return ? -} - -@threadSafety("system") -cmd void vkFreeMemory( - VkDevice device, - VkDeviceMemory memory, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - memoryObject := GetDeviceMemory(memory) - assert(memoryObject.device == device) - - // Check that no objects are still bound before freeing. - validate("MemoryCheck", len(memoryObject.boundObjects) == 0, - "vkFreeMemory: objects still bound") - validate("MemoryCheck", len(memoryObject.boundCommandBuffers) == 0, - "vkFreeMemory: commandBuffers still bound") - State.DeviceMemories[memory] = null -} - -@threadSafety("app") -cmd VkResult vkMapMemory( - VkDevice device, - VkDeviceMemory memory, - VkDeviceSize offset, - VkDeviceSize size, - VkMemoryMapFlags flags, - void** ppData) { - deviceObject := GetDevice(device) - memoryObject := GetDeviceMemory(memory) - assert(memoryObject.device == device) - - assert(flags == as!VkMemoryMapFlags(0)) - assert((offset + size) <= memoryObject.allocationSize) - - return ? -} - -@threadSafety("app") -cmd void vkUnmapMemory( - VkDevice device, - VkDeviceMemory memory) { - deviceObject := GetDevice(device) - memoryObject := GetDeviceMemory(memory) - assert(memoryObject.device == device) -} - -cmd VkResult vkFlushMappedMemoryRanges( - VkDevice device, - u32 memoryRangeCount - const VkMappedMemoryRange* pMemoryRanges) { - deviceObject := GetDevice(device) - - memoryRanges := pMemoryRanges[0:memoryRangeCount] - for i in (0 .. memoryRangeCount) { - memoryRange := memoryRanges[i] - memoryObject := GetDeviceMemory(memoryRange.memory) - assert(memoryObject.device == device) - assert((memoryRange.offset + memoryRange.size) <= memoryObject.allocationSize) - } - - return ? -} - -cmd VkResult vkInvalidateMappedMemoryRanges( - VkDevice device, - u32 memoryRangeCount, - const VkMappedMemoryRange* pMemoryRanges) { - deviceObject := GetDevice(device) - - memoryRanges := pMemoryRanges[0:memoryRangeCount] - for i in (0 .. memoryRangeCount) { - memoryRange := memoryRanges[i] - memoryObject := GetDeviceMemory(memoryRange.memory) - assert(memoryObject.device == device) - assert((memoryRange.offset + memoryRange.size) <= memoryObject.allocationSize) - } - - return ? -} - - -// Memory management API functions - -cmd void vkGetDeviceMemoryCommitment( - VkDevice device, - VkDeviceMemory memory, - VkDeviceSize* pCommittedMemoryInBytes) { - deviceObject := GetDevice(device) - - if memory != NULL_HANDLE { - memoryObject := GetDeviceMemory(memory) - assert(memoryObject.device == device) - } - - committedMemoryInBytes := ? - pCommittedMemoryInBytes[0] = committedMemoryInBytes -} - -cmd void vkGetBufferMemoryRequirements( - VkDevice device, - VkBuffer buffer, - VkMemoryRequirements* pMemoryRequirements) { - deviceObject := GetDevice(device) - bufferObject := GetBuffer(buffer) - assert(bufferObject.device == device) -} - -cmd VkResult vkBindBufferMemory( - VkDevice device, - VkBuffer buffer, - VkDeviceMemory memory, - VkDeviceSize memoryOffset) { - deviceObject := GetDevice(device) - bufferObject := GetBuffer(buffer) - assert(bufferObject.device == device) - - // Unbind buffer from previous memory object, if not VK_NULL_HANDLE. - if bufferObject.memory != NULL_HANDLE { - memoryObject := GetDeviceMemory(bufferObject.memory) - memoryObject.boundObjects[as!u64(buffer)] = null - } - - // Bind buffer to given memory object, if not VK_NULL_HANDLE. - if memory != NULL_HANDLE { - memoryObject := GetDeviceMemory(memory) - assert(memoryObject.device == device) - memoryObject.boundObjects[as!u64(buffer)] = memoryOffset - } - bufferObject.memory = memory - bufferObject.memoryOffset = memoryOffset - - return ? -} - -cmd void vkGetImageMemoryRequirements( - VkDevice device, - VkImage image, - VkMemoryRequirements* pMemoryRequirements) { - deviceObject := GetDevice(device) - imageObject := GetImage(image) - assert(imageObject.device == device) -} - -cmd VkResult vkBindImageMemory( - VkDevice device, - VkImage image, - VkDeviceMemory memory, - VkDeviceSize memoryOffset) { - deviceObject := GetDevice(device) - imageObject := GetImage(image) - assert(imageObject.device == device) - - // Unbind image from previous memory object, if not VK_NULL_HANDLE. - if imageObject.memory != NULL_HANDLE { - memoryObject := GetDeviceMemory(imageObject.memory) - memoryObject.boundObjects[as!u64(image)] = null - } - - // Bind image to given memory object, if not VK_NULL_HANDLE. - if memory != NULL_HANDLE { - memoryObject := GetDeviceMemory(memory) - assert(memoryObject.device == device) - memoryObject.boundObjects[as!u64(image)] = memoryOffset - } - imageObject.memory = memory - imageObject.memoryOffset = memoryOffset - - return ? -} - -cmd void vkGetImageSparseMemoryRequirements( - VkDevice device, - VkImage image, - u32* pSparseMemoryRequirementCount, - VkSparseImageMemoryRequirements* pSparseMemoryRequirements) { - deviceObject := GetDevice(device) - imageObject := GetImage(image) - assert(imageObject.device == device) -} - -cmd void vkGetPhysicalDeviceSparseImageFormatProperties( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - VkSampleCountFlagBits samples, - VkImageUsageFlags usage, - VkImageTiling tiling, - u32* pPropertyCount, - VkSparseImageFormatProperties* pProperties) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) -} - -cmd VkResult vkQueueBindSparse( - VkQueue queue, - u32 bindInfoCount, - const VkBindSparseInfo* pBindInfo, - VkFence fence) { - queueObject := GetQueue(queue) - - return ? -} - - -// Fence functions - -@threadSafety("system") -cmd VkResult vkCreateFence( - VkDevice device, - const VkFenceCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkFence* pFence) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO) - deviceObject := GetDevice(device) - - fence := ? - pFence[0] = fence - State.Fences[fence] = new!FenceObject( - device: device, signaled: (pCreateInfo.flags == as!VkFenceCreateFlags(VK_FENCE_CREATE_SIGNALED_BIT))) - - return ? -} - -@threadSafety("system") -cmd void vkDestroyFence( - VkDevice device, - VkFence fence, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - fenceObject := GetFence(fence) - assert(fenceObject.device == device) - - State.Fences[fence] = null -} - -@threadSafety("system") -cmd VkResult vkResetFences( - VkDevice device, - u32 fenceCount, - const VkFence* pFences) { - deviceObject := GetDevice(device) - - fences := pFences[0:fenceCount] - for i in (0 .. fenceCount) { - fence := fences[i] - fenceObject := GetFence(fence) - assert(fenceObject.device == device) - fenceObject.signaled = false - } - - return ? -} - -@threadSafety("system") -cmd VkResult vkGetFenceStatus( - VkDevice device, - VkFence fence) { - deviceObject := GetDevice(device) - fenceObject := GetFence(fence) - assert(fenceObject.device == device) - - return ? -} - -@threadSafety("system") -cmd VkResult vkWaitForFences( - VkDevice device, - u32 fenceCount, - const VkFence* pFences, - VkBool32 waitAll, - u64 timeout) { /// timeout in nanoseconds - deviceObject := GetDevice(device) - - fences := pFences[0:fenceCount] - for i in (0 .. fenceCount) { - fence := fences[i] - fenceObject := GetFence(fence) - assert(fenceObject.device == device) - } - - return ? -} - - -// Queue semaphore functions - -@threadSafety("system") -cmd VkResult vkCreateSemaphore( - VkDevice device, - const VkSemaphoreCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSemaphore* pSemaphore) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO) - deviceObject := GetDevice(device) - - semaphore := ? - pSemaphore[0] = semaphore - State.Semaphores[semaphore] = new!SemaphoreObject(device: device) - - return ? -} - -@threadSafety("system") -cmd void vkDestroySemaphore( - VkDevice device, - VkSemaphore semaphore, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - semaphoreObject := GetSemaphore(semaphore) - assert(semaphoreObject.device == device) - - State.Semaphores[semaphore] = null -} - - -// Event functions - -@threadSafety("system") -cmd VkResult vkCreateEvent( - VkDevice device, - const VkEventCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkEvent* pEvent) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_EVENT_CREATE_INFO) - deviceObject := GetDevice(device) - - event := ? - pEvent[0] = event - State.Events[event] = new!EventObject(device: device) - - return ? -} - -@threadSafety("system") -cmd void vkDestroyEvent( - VkDevice device, - VkEvent event, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - eventObject := GetEvent(event) - assert(eventObject.device == device) - - State.Events[event] = null -} - -@threadSafety("system") -cmd VkResult vkGetEventStatus( - VkDevice device, - VkEvent event) { - deviceObject := GetDevice(device) - eventObject := GetEvent(event) - assert(eventObject.device == device) - - return ? -} - -@threadSafety("system") -cmd VkResult vkSetEvent( - VkDevice device, - VkEvent event) { - deviceObject := GetDevice(device) - eventObject := GetEvent(event) - assert(eventObject.device == device) - - return ? -} - -@threadSafety("system") -cmd VkResult vkResetEvent( - VkDevice device, - VkEvent event) { - deviceObject := GetDevice(device) - eventObject := GetEvent(event) - assert(eventObject.device == device) - - return ? -} - - -// Query functions - -@threadSafety("system") -cmd VkResult vkCreateQueryPool( - VkDevice device, - const VkQueryPoolCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkQueryPool* pQueryPool) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO) - deviceObject := GetDevice(device) - - queryPool := ? - pQueryPool[0] = queryPool - State.QueryPools[queryPool] = new!QueryPoolObject(device: device) - - return ? -} - -@threadSafety("system") -cmd void vkDestroyQueryPool( - VkDevice device, - VkQueryPool queryPool, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - queryPoolObject := GetQueryPool(queryPool) - assert(queryPoolObject.device == device) - - State.QueryPools[queryPool] = null -} - -@threadSafety("system") -cmd VkResult vkGetQueryPoolResults( - VkDevice device, - VkQueryPool queryPool, - u32 firstQuery, - u32 queryCount, - platform.size_t dataSize, - void* pData, - VkDeviceSize stride, - VkQueryResultFlags flags) { - deviceObject := GetDevice(device) - queryPoolObject := GetQueryPool(queryPool) - assert(queryPoolObject.device == device) - - data := pData[0:dataSize] - - return ? -} - -// Buffer functions - -@threadSafety("system") -cmd VkResult vkCreateBuffer( - VkDevice device, - const VkBufferCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkBuffer* pBuffer) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO) - deviceObject := GetDevice(device) - - buffer := ? - pBuffer[0] = buffer - State.Buffers[buffer] = new!BufferObject(device: device) - - return ? -} - -@threadSafety("system") -cmd void vkDestroyBuffer( - VkDevice device, - VkBuffer buffer, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - bufferObject := GetBuffer(buffer) - assert(bufferObject.device == device) - - assert(bufferObject.memory == 0) - State.Buffers[buffer] = null -} - - -// Buffer view functions - -@threadSafety("system") -cmd VkResult vkCreateBufferView( - VkDevice device, - const VkBufferViewCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkBufferView* pView) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO) - deviceObject := GetDevice(device) - - bufferObject := GetBuffer(pCreateInfo.buffer) - assert(bufferObject.device == device) - - view := ? - pView[0] = view - State.BufferViews[view] = new!BufferViewObject(device: device, buffer: pCreateInfo.buffer) - - return ? -} - -@threadSafety("system") -cmd void vkDestroyBufferView( - VkDevice device, - VkBufferView bufferView, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - bufferViewObject := GetBufferView(bufferView) - assert(bufferViewObject.device == device) - - State.BufferViews[bufferView] = null -} - - -// Image functions - -@threadSafety("system") -cmd VkResult vkCreateImage( - VkDevice device, - const VkImageCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkImage* pImage) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO) - deviceObject := GetDevice(device) - - image := ? - pImage[0] = image - State.Images[image] = new!ImageObject(device: device) - - return ? -} - -@threadSafety("system") -cmd void vkDestroyImage( - VkDevice device, - VkImage image, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - imageObject := GetImage(image) - assert(imageObject.device == device) - - assert(imageObject.memory == 0) - State.Images[image] = null -} - -cmd void vkGetImageSubresourceLayout( - VkDevice device, - VkImage image, - const VkImageSubresource* pSubresource, - VkSubresourceLayout* pLayout) { - deviceObject := GetDevice(device) - imageObject := GetImage(image) - assert(imageObject.device == device) -} - - -// Image view functions - -@threadSafety("system") -cmd VkResult vkCreateImageView( - VkDevice device, - const VkImageViewCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkImageView* pView) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO) - deviceObject := GetDevice(device) - - imageObject := GetImage(pCreateInfo.image) - assert(imageObject.device == device) - - view := ? - pView[0] = view - State.ImageViews[view] = new!ImageViewObject(device: device, image: pCreateInfo.image) - - return ? -} - -@threadSafety("system") -cmd void vkDestroyImageView( - VkDevice device, - VkImageView imageView, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - imageViewObject := GetImageView(imageView) - assert(imageViewObject.device == device) - - State.ImageViews[imageView] = null -} - - -// Shader functions - -cmd VkResult vkCreateShaderModule( - VkDevice device, - const VkShaderModuleCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkShaderModule* pShaderModule) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO) - deviceObject := GetDevice(device) - - shaderModule := ? - pShaderModule[0] = shaderModule - State.ShaderModules[shaderModule] = new!ShaderModuleObject(device: device) - - return ? -} - -cmd void vkDestroyShaderModule( - VkDevice device, - VkShaderModule shaderModule, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - shaderModuleObject := GetShaderModule(shaderModule) - assert(shaderModuleObject.device == device) - - State.ShaderModules[shaderModule] = null -} - - -// Pipeline functions - -cmd VkResult vkCreatePipelineCache( - VkDevice device, - const VkPipelineCacheCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkPipelineCache* pPipelineCache) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO) - deviceObject := GetDevice(device) - - pipelineCache := ? - pPipelineCache[0] = pipelineCache - State.PipelineCaches[pipelineCache] = new!PipelineCacheObject(device: device) - - return ? -} - -cmd void vkDestroyPipelineCache( - VkDevice device, - VkPipelineCache pipelineCache, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - pipelineCacheObject := GetPipelineCache(pipelineCache) - assert(pipelineCacheObject.device == device) - - State.PipelineCaches[pipelineCache] = null -} - -cmd VkResult vkGetPipelineCacheData( - VkDevice device, - VkPipelineCache pipelineCache, - platform.size_t* pDataSize, - void* pData) { - deviceObject := GetDevice(device) - pipelineCacheObject := GetPipelineCache(pipelineCache) - assert(pipelineCacheObject.device == device) - - return ? -} - -cmd VkResult vkMergePipelineCaches( - VkDevice device, - VkPipelineCache dstCache, - u32 srcCacheCount, - const VkPipelineCache* pSrcCaches) { - deviceObject := GetDevice(device) - dstCacheObject := GetPipelineCache(dstCache) - assert(dstCacheObject.device == device) - - srcCaches := pSrcCaches[0:srcCacheCount] - for i in (0 .. srcCacheCount) { - srcCache := srcCaches[i] - srcCacheObject := GetPipelineCache(srcCache) - assert(srcCacheObject.device == device) - } - - return ? -} - -cmd VkResult vkCreateGraphicsPipelines( - VkDevice device, - VkPipelineCache pipelineCache, - u32 createInfoCount, - const VkGraphicsPipelineCreateInfo* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkPipeline* pPipelines) { - deviceObject := GetDevice(device) - if pipelineCache != NULL_HANDLE { - pipelineCacheObject := GetPipelineCache(pipelineCache) - assert(pipelineCacheObject.device == device) - } - - createInfos := pCreateInfos[0:createInfoCount] - pipelines := pPipelines[0:createInfoCount] - for i in (0 .. createInfoCount) { - pipeline := ? - pipelines[i] = pipeline - State.Pipelines[pipeline] = new!PipelineObject(device: device) - } - - return ? -} - -cmd VkResult vkCreateComputePipelines( - VkDevice device, - VkPipelineCache pipelineCache, - u32 createInfoCount, - const VkComputePipelineCreateInfo* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkPipeline* pPipelines) { - deviceObject := GetDevice(device) - if pipelineCache != NULL_HANDLE { - pipelineCacheObject := GetPipelineCache(pipelineCache) - assert(pipelineCacheObject.device == device) - } - - createInfos := pCreateInfos[0:createInfoCount] - pipelines := pPipelines[0:createInfoCount] - for i in (0 .. createInfoCount) { - pipeline := ? - pipelines[i] = pipeline - State.Pipelines[pipeline] = new!PipelineObject(device: device) - } - - return ? -} - -@threadSafety("system") -cmd void vkDestroyPipeline( - VkDevice device, - VkPipeline pipeline, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - pipelineObjects := GetPipeline(pipeline) - assert(pipelineObjects.device == device) - - State.Pipelines[pipeline] = null -} - - -// Pipeline layout functions - -@threadSafety("system") -cmd VkResult vkCreatePipelineLayout( - VkDevice device, - const VkPipelineLayoutCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkPipelineLayout* pPipelineLayout) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO) - deviceObject := GetDevice(device) - - pipelineLayout := ? - pPipelineLayout[0] = pipelineLayout - State.PipelineLayouts[pipelineLayout] = new!PipelineLayoutObject(device: device) - - return ? -} - -@threadSafety("system") -cmd void vkDestroyPipelineLayout( - VkDevice device, - VkPipelineLayout pipelineLayout, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - pipelineLayoutObjects := GetPipelineLayout(pipelineLayout) - assert(pipelineLayoutObjects.device == device) - - State.PipelineLayouts[pipelineLayout] = null -} - - -// Sampler functions - -@threadSafety("system") -cmd VkResult vkCreateSampler( - VkDevice device, - const VkSamplerCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSampler* pSampler) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO) - deviceObject := GetDevice(device) - - sampler := ? - pSampler[0] = sampler - State.Samplers[sampler] = new!SamplerObject(device: device) - - return ? -} - -@threadSafety("system") -cmd void vkDestroySampler( - VkDevice device, - VkSampler sampler, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - samplerObject := GetSampler(sampler) - assert(samplerObject.device == device) - - State.Samplers[sampler] = null -} - - -// Descriptor set functions - -@threadSafety("system") -cmd VkResult vkCreateDescriptorSetLayout( - VkDevice device, - const VkDescriptorSetLayoutCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorSetLayout* pSetLayout) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO) - deviceObject := GetDevice(device) - - setLayout := ? - pSetLayout[0] = setLayout - State.DescriptorSetLayouts[setLayout] = new!DescriptorSetLayoutObject(device: device) - - return ? -} - -@threadSafety("system") -cmd void vkDestroyDescriptorSetLayout( - VkDevice device, - VkDescriptorSetLayout descriptorSetLayout, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - descriptorSetLayoutObject := GetDescriptorSetLayout(descriptorSetLayout) - assert(descriptorSetLayoutObject.device == device) - - State.DescriptorSetLayouts[descriptorSetLayout] = null -} - -@threadSafety("system") -cmd VkResult vkCreateDescriptorPool( - VkDevice device, - const VkDescriptorPoolCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorPool* pDescriptorPool) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO) - deviceObject := GetDevice(device) - - descriptorPool := ? - pDescriptorPool[0] = descriptorPool - State.DescriptorPools[descriptorPool] = new!DescriptorPoolObject(device: device) - - return ? -} - -@threadSafety("system") -cmd void vkDestroyDescriptorPool( - VkDevice device, - VkDescriptorPool descriptorPool, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - descriptorPoolObject := GetDescriptorPool(descriptorPool) - assert(descriptorPoolObject.device == device) - - State.DescriptorPools[descriptorPool] = null -} - -@threadSafety("app") -cmd VkResult vkResetDescriptorPool( - VkDevice device, - VkDescriptorPool descriptorPool, - VkDescriptorPoolResetFlags flags) { - deviceObject := GetDevice(device) - descriptorPoolObject := GetDescriptorPool(descriptorPool) - assert(descriptorPoolObject.device == device) - - return ? -} - -@threadSafety("app") -cmd VkResult vkAllocateDescriptorSets( - VkDevice device, - const VkDescriptorSetAllocateInfo* pAllocateInfo, - VkDescriptorSet* pDescriptorSets) { - deviceObject := GetDevice(device) - allocInfo := pAllocateInfo[0] - descriptorPoolObject := GetDescriptorPool(allocInfo.descriptorPool) - - setLayouts := allocInfo.pSetLayouts[0:allocInfo.setCount] - for i in (0 .. allocInfo.setCount) { - setLayout := setLayouts[i] - setLayoutObject := GetDescriptorSetLayout(setLayout) - assert(setLayoutObject.device == device) - } - - descriptorSets := pDescriptorSets[0:allocInfo.setCount] - for i in (0 .. allocInfo.setCount) { - descriptorSet := ? - descriptorSets[i] = descriptorSet - State.DescriptorSets[descriptorSet] = new!DescriptorSetObject(device: device) - } - - return ? -} - -cmd VkResult vkFreeDescriptorSets( - VkDevice device, - VkDescriptorPool descriptorPool, - u32 descriptorSetCount, - const VkDescriptorSet* pDescriptorSets) { - deviceObject := GetDevice(device) - descriptorPoolObject := GetDescriptorPool(descriptorPool) - - descriptorSets := pDescriptorSets[0:descriptorSetCount] - for i in (0 .. descriptorSetCount) { - descriptorSet := descriptorSets[i] - descriptorSetObject := GetDescriptorSet(descriptorSet) - assert(descriptorSetObject.device == device) - State.DescriptorSets[descriptorSet] = null - } - - return ? -} - -cmd void vkUpdateDescriptorSets( - VkDevice device, - u32 descriptorWriteCount, - const VkWriteDescriptorSet* pDescriptorWrites, - u32 descriptorCopyCount, - const VkCopyDescriptorSet* pDescriptorCopies) { - deviceObject := GetDevice(device) - - descriptorWrites := pDescriptorWrites[0:descriptorWriteCount] - for i in (0 .. descriptorWriteCount) { - descriptorWrite := descriptorWrites[i] - descriptorWriteObject := GetDescriptorSet(descriptorWrite.dstSet) - assert(descriptorWriteObject.device == device) - } - - descriptorCopies := pDescriptorCopies[0:descriptorCopyCount] - for i in (0 .. descriptorCopyCount) { - descriptorCopy := descriptorCopies[i] - descriptorCopyObject := GetDescriptorSet(descriptorCopy.dstSet) - assert(descriptorCopyObject.device == device) - } -} - - -// Framebuffer functions - -@threadSafety("system") -cmd VkResult vkCreateFramebuffer( - VkDevice device, - const VkFramebufferCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkFramebuffer* pFramebuffer) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO) - deviceObject := GetDevice(device) - - framebuffer := ? - pFramebuffer[0] = framebuffer - State.Framebuffers[framebuffer] = new!FramebufferObject(device: device) - - return ? -} - -@threadSafety("system") -cmd void vkDestroyFramebuffer( - VkDevice device, - VkFramebuffer framebuffer, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - framebufferObject := GetFramebuffer(framebuffer) - assert(framebufferObject.device == device) - - State.Framebuffers[framebuffer] = null -} - - -// Renderpass functions - -@threadSafety("system") -cmd VkResult vkCreateRenderPass( - VkDevice device, - const VkRenderPassCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkRenderPass* pRenderPass) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO) - deviceObject := GetDevice(device) - - renderpass := ? - pRenderPass[0] = renderpass - State.RenderPasses[renderpass] = new!RenderPassObject(device: device) - - return ? -} - -@threadSafety("system") -cmd void vkDestroyRenderPass( - VkDevice device, - VkRenderPass renderPass, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - renderPassObject := GetRenderPass(renderPass) - assert(renderPassObject.device == device) - - State.RenderPasses[renderPass] = null -} - -cmd void vkGetRenderAreaGranularity( - VkDevice device, - VkRenderPass renderPass, - VkExtent2D* pGranularity) { - deviceObject := GetDevice(device) - renderPassObject := GetRenderPass(renderPass) - - granularity := ? - pGranularity[0] = granularity -} - -// Command pool functions - -cmd VkResult vkCreateCommandPool( - VkDevice device, - const VkCommandPoolCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkCommandPool* pCommandPool) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO) - deviceObject := GetDevice(device) - - commandPool := ? - pCommandPool[0] = commandPool - State.CommandPools[commandPool] = new!CommandPoolObject(device: device) - - return ? -} - -cmd void vkDestroyCommandPool( - VkDevice device, - VkCommandPool commandPool, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - commandPoolObject := GetCommandPool(commandPool) - assert(commandPoolObject.device == device) - - State.CommandPools[commandPool] = null -} - -cmd VkResult vkResetCommandPool( - VkDevice device, - VkCommandPool commandPool, - VkCommandPoolResetFlags flags) { - deviceObject := GetDevice(device) - commandPoolObject := GetCommandPool(commandPool) - assert(commandPoolObject.device == device) - - return ? -} - -// Command buffer functions - -macro void bindCommandBuffer(VkCommandBuffer commandBuffer, any obj, VkDeviceMemory memory) { - memoryObject := GetDeviceMemory(memory) - memoryObject.boundCommandBuffers[commandBuffer] = commandBuffer - - commandBufferObject := GetCommandBuffer(commandBuffer) - commandBufferObject.boundObjects[as!u64(obj)] = memory -} - -macro void unbindCommandBuffer(VkCommandBuffer commandBuffer, any obj, VkDeviceMemory memory) { - memoryObject := GetDeviceMemory(memory) - memoryObject.boundCommandBuffers[commandBuffer] = null - - commandBufferObject := GetCommandBuffer(commandBuffer) - commandBufferObject.boundObjects[as!u64(obj)] = null -} - -@threadSafety("system") -cmd VkResult vkAllocateCommandBuffers( - VkDevice device, - const VkCommandBufferAllocateInfo* pAllocateInfo, - VkCommandBuffer* pCommandBuffers) { - assert(pAllocateInfo[0].sType == VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO) - - count := pAllocateInfo[0].commandBufferCount - commandBuffers := pCommandBuffers[0:count] - for i in (0 .. count) { - commandBuffer := ? - commandBuffers[i] = commandBuffer - State.CommandBuffers[commandBuffer] = new!CommandBufferObject(device: device) - } - - return ? -} - -@threadSafety("system") -cmd void vkFreeCommandBuffers( - VkDevice device, - VkCommandPool commandPool, - u32 commandBufferCount, - const VkCommandBuffer* pCommandBuffers) { - deviceObject := GetDevice(device) - - commandBuffers := pCommandBuffers[0:commandBufferCount] - for i in (0 .. commandBufferCount) { - commandBufferObject := GetCommandBuffer(commandBuffers[i]) - assert(commandBufferObject.device == device) - // TODO: iterate over boundObjects and clear memory bindings - State.CommandBuffers[commandBuffers[i]] = null - } -} - -@threadSafety("app") -cmd VkResult vkBeginCommandBuffer( - VkCommandBuffer commandBuffer, - const VkCommandBufferBeginInfo* pBeginInfo) { - assert(pBeginInfo.sType == VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO) - commandBufferObject := GetCommandBuffer(commandBuffer) - - // TODO: iterate over boundObjects and clear memory bindings - - return ? -} - -@threadSafety("app") -cmd VkResult vkEndCommandBuffer( - VkCommandBuffer commandBuffer) { - commandBufferObject := GetCommandBuffer(commandBuffer) - - return ? -} - -@threadSafety("app") -cmd VkResult vkResetCommandBuffer( - VkCommandBuffer commandBuffer, - VkCommandBufferResetFlags flags) { - commandBufferObject := GetCommandBuffer(commandBuffer) - - // TODO: iterate over boundObjects and clear memory bindings - - return ? -} - - -// Command buffer building functions - -@threadSafety("app") -cmd void vkCmdBindPipeline( - VkCommandBuffer commandBuffer, - VkPipelineBindPoint pipelineBindPoint, - VkPipeline pipeline) { - commandBufferObject := GetCommandBuffer(commandBuffer) - pipelineObject := GetPipeline(pipeline) - assert(commandBufferObject.device == pipelineObject.device) - - queue := switch (pipelineBindPoint) { - case VK_PIPELINE_BIND_POINT_COMPUTE: VK_QUEUE_COMPUTE_BIT - case VK_PIPELINE_BIND_POINT_GRAPHICS: VK_QUEUE_GRAPHICS_BIT - } - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, queue) -} - -@threadSafety("app") -cmd void vkCmdSetViewport( - VkCommandBuffer commandBuffer, - u32 firstViewport, - u32 viewportCount, - const VkViewport* pViewports) { - commandBufferObject := GetCommandBuffer(commandBuffer) - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdSetScissor( - VkCommandBuffer commandBuffer, - u32 firstScissor, - u32 scissorCount, - const VkRect2D* pScissors) { - commandBufferObject := GetCommandBuffer(commandBuffer) - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdSetLineWidth( - VkCommandBuffer commandBuffer, - f32 lineWidth) { - commandBufferObject := GetCommandBuffer(commandBuffer) - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdSetDepthBias( - VkCommandBuffer commandBuffer, - f32 depthBiasConstantFactor, - f32 depthBiasClamp, - f32 depthBiasSlopeFactor) { - commandBufferObject := GetCommandBuffer(commandBuffer) - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdSetBlendConstants( - VkCommandBuffer commandBuffer, - // TODO(jessehall): apic only supports 'const' on pointer types. Using - // an annotation as a quick hack to pass this to the template without - // having to modify the AST and semantic model. - @readonly f32[4] blendConstants) { - commandBufferObject := GetCommandBuffer(commandBuffer) - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdSetDepthBounds( - VkCommandBuffer commandBuffer, - f32 minDepthBounds, - f32 maxDepthBounds) { - commandBufferObject := GetCommandBuffer(commandBuffer) - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdSetStencilCompareMask( - VkCommandBuffer commandBuffer, - VkStencilFaceFlags faceMask, - u32 compareMask) { - commandBufferObject := GetCommandBuffer(commandBuffer) - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdSetStencilWriteMask( - VkCommandBuffer commandBuffer, - VkStencilFaceFlags faceMask, - u32 writeMask) { - commandBufferObject := GetCommandBuffer(commandBuffer) - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdSetStencilReference( - VkCommandBuffer commandBuffer, - VkStencilFaceFlags faceMask, - u32 reference) { - commandBufferObject := GetCommandBuffer(commandBuffer) - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdBindDescriptorSets( - VkCommandBuffer commandBuffer, - VkPipelineBindPoint pipelineBindPoint, - VkPipelineLayout layout, - u32 firstSet, - u32 descriptorSetCount, - const VkDescriptorSet* pDescriptorSets, - u32 dynamicOffsetCount, - const u32* pDynamicOffsets) { - commandBufferObject := GetCommandBuffer(commandBuffer) - - descriptorSets := pDescriptorSets[0:descriptorSetCount] - for i in (0 .. descriptorSetCount) { - descriptorSet := descriptorSets[i] - descriptorSetObject := GetDescriptorSet(descriptorSet) - assert(commandBufferObject.device == descriptorSetObject.device) - } - - dynamicOffsets := pDynamicOffsets[0:dynamicOffsetCount] - for i in (0 .. dynamicOffsetCount) { - dynamicOffset := dynamicOffsets[i] - } - - queue := switch (pipelineBindPoint) { - case VK_PIPELINE_BIND_POINT_COMPUTE: VK_QUEUE_COMPUTE_BIT - case VK_PIPELINE_BIND_POINT_GRAPHICS: VK_QUEUE_GRAPHICS_BIT - } - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, queue) -} - -@threadSafety("app") -cmd void vkCmdBindIndexBuffer( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkIndexType indexType) { - commandBufferObject := GetCommandBuffer(commandBuffer) - bufferObject := GetBuffer(buffer) - assert(commandBufferObject.device == bufferObject.device) - - bindCommandBuffer(commandBuffer, buffer, bufferObject.memory) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdBindVertexBuffers( - VkCommandBuffer commandBuffer, - u32 firstBinding, - u32 bindingCount, - const VkBuffer* pBuffers, - const VkDeviceSize* pOffsets) { - commandBufferObject := GetCommandBuffer(commandBuffer) - - // TODO: check if not [firstBinding:firstBinding+bindingCount] - buffers := pBuffers[0:bindingCount] - offsets := pOffsets[0:bindingCount] - for i in (0 .. bindingCount) { - buffer := buffers[i] - offset := offsets[i] - bufferObject := GetBuffer(buffer) - assert(commandBufferObject.device == bufferObject.device) - - bindCommandBuffer(commandBuffer, buffer, bufferObject.memory) - } - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdDraw( - VkCommandBuffer commandBuffer, - u32 vertexCount, - u32 instanceCount, - u32 firstVertex, - u32 firstInstance) { - commandBufferObject := GetCommandBuffer(commandBuffer) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdDrawIndexed( - VkCommandBuffer commandBuffer, - u32 indexCount, - u32 instanceCount, - u32 firstIndex, - s32 vertexOffset, - u32 firstInstance) { - commandBufferObject := GetCommandBuffer(commandBuffer) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdDrawIndirect( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - u32 drawCount, - u32 stride) { - commandBufferObject := GetCommandBuffer(commandBuffer) - bufferObject := GetBuffer(buffer) - assert(commandBufferObject.device == bufferObject.device) - - bindCommandBuffer(commandBuffer, buffer, bufferObject.memory) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdDrawIndexedIndirect( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - u32 drawCount, - u32 stride) { - commandBufferObject := GetCommandBuffer(commandBuffer) - bufferObject := GetBuffer(buffer) - assert(commandBufferObject.device == bufferObject.device) - - bindCommandBuffer(commandBuffer, buffer, bufferObject.memory) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdDispatch( - VkCommandBuffer commandBuffer, - u32 groupCountX, - u32 groupCountY, - u32 groupCountZ) { - commandBufferObject := GetCommandBuffer(commandBuffer) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_COMPUTE_BIT) -} - -@threadSafety("app") -cmd void vkCmdDispatchIndirect( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset) { - commandBufferObject := GetCommandBuffer(commandBuffer) - bufferObject := GetBuffer(buffer) - assert(commandBufferObject.device == bufferObject.device) - - bindCommandBuffer(commandBuffer, buffer, bufferObject.memory) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_COMPUTE_BIT) -} - -@threadSafety("app") -cmd void vkCmdCopyBuffer( - VkCommandBuffer commandBuffer, - VkBuffer srcBuffer, - VkBuffer dstBuffer, - u32 regionCount, - const VkBufferCopy* pRegions) { - commandBufferObject := GetCommandBuffer(commandBuffer) - srcBufferObject := GetBuffer(srcBuffer) - dstBufferObject := GetBuffer(dstBuffer) - assert(commandBufferObject.device == srcBufferObject.device) - assert(commandBufferObject.device == dstBufferObject.device) - - regions := pRegions[0:regionCount] - for i in (0 .. regionCount) { - region := regions[i] - } - - bindCommandBuffer(commandBuffer, srcBuffer, srcBufferObject.memory) - bindCommandBuffer(commandBuffer, dstBuffer, dstBufferObject.memory) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT) -} - -@threadSafety("app") -cmd void vkCmdCopyImage( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - u32 regionCount, - const VkImageCopy* pRegions) { - commandBufferObject := GetCommandBuffer(commandBuffer) - srcImageObject := GetImage(srcImage) - dstImageObject := GetImage(dstImage) - assert(commandBufferObject.device == srcImageObject.device) - assert(commandBufferObject.device == dstImageObject.device) - - regions := pRegions[0:regionCount] - for i in (0 .. regionCount) { - region := regions[i] - } - - bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory) - bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT) -} - -@threadSafety("app") -cmd void vkCmdBlitImage( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - u32 regionCount, - const VkImageBlit* pRegions, - VkFilter filter) { - commandBufferObject := GetCommandBuffer(commandBuffer) - srcImageObject := GetImage(srcImage) - dstImageObject := GetImage(dstImage) - assert(commandBufferObject.device == srcImageObject.device) - assert(commandBufferObject.device == dstImageObject.device) - - regions := pRegions[0:regionCount] - for i in (0 .. regionCount) { - region := regions[i] - } - - bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory) - bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdCopyBufferToImage( - VkCommandBuffer commandBuffer, - VkBuffer srcBuffer, - VkImage dstImage, - VkImageLayout dstImageLayout, - u32 regionCount, - const VkBufferImageCopy* pRegions) { - commandBufferObject := GetCommandBuffer(commandBuffer) - srcBufferObject := GetBuffer(srcBuffer) - dstImageObject := GetImage(dstImage) - assert(commandBufferObject.device == srcBufferObject.device) - assert(commandBufferObject.device == dstImageObject.device) - - regions := pRegions[0:regionCount] - for i in (0 .. regionCount) { - region := regions[i] - } - - bindCommandBuffer(commandBuffer, srcBuffer, srcBufferObject.memory) - bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT) -} - -@threadSafety("app") -cmd void vkCmdCopyImageToBuffer( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkBuffer dstBuffer, - u32 regionCount, - const VkBufferImageCopy* pRegions) { - commandBufferObject := GetCommandBuffer(commandBuffer) - srcImageObject := GetImage(srcImage) - dstBufferObject := GetBuffer(dstBuffer) - assert(commandBufferObject.device == srcImageObject.device) - assert(commandBufferObject.device == dstBufferObject.device) - - regions := pRegions[0:regionCount] - for i in (0 .. regionCount) { - region := regions[i] - } - - bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory) - bindCommandBuffer(commandBuffer, dstBuffer, dstBufferObject.memory) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT) -} - -@threadSafety("app") -cmd void vkCmdUpdateBuffer( - VkCommandBuffer commandBuffer, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize dataSize, - const void* pData) { - commandBufferObject := GetCommandBuffer(commandBuffer) - dstBufferObject := GetBuffer(dstBuffer) - assert(commandBufferObject.device == dstBufferObject.device) - - data := pData[0:dataSize] - - bindCommandBuffer(commandBuffer, dstBuffer, dstBufferObject.memory) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT) -} - -@threadSafety("app") -cmd void vkCmdFillBuffer( - VkCommandBuffer commandBuffer, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize size, - u32 data) { - commandBufferObject := GetCommandBuffer(commandBuffer) - dstBufferObject := GetBuffer(dstBuffer) - assert(commandBufferObject.device == dstBufferObject.device) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT) -} - -@threadSafety("app") -cmd void vkCmdClearColorImage( - VkCommandBuffer commandBuffer, - VkImage image, - VkImageLayout imageLayout, - const VkClearColorValue* pColor, - u32 rangeCount, - const VkImageSubresourceRange* pRanges) { - commandBufferObject := GetCommandBuffer(commandBuffer) - imageObject := GetImage(image) - assert(commandBufferObject.device == imageObject.device) - - ranges := pRanges[0:rangeCount] - for i in (0 .. rangeCount) { - range := ranges[i] - } - - bindCommandBuffer(commandBuffer, image, imageObject.memory) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdClearDepthStencilImage( - VkCommandBuffer commandBuffer, - VkImage image, - VkImageLayout imageLayout, - const VkClearDepthStencilValue* pDepthStencil, - u32 rangeCount, - const VkImageSubresourceRange* pRanges) { - commandBufferObject := GetCommandBuffer(commandBuffer) - imageObject := GetImage(image) - assert(commandBufferObject.device == imageObject.device) - - ranges := pRanges[0:rangeCount] - for i in (0 .. rangeCount) { - range := ranges[i] - } - - bindCommandBuffer(commandBuffer, image, imageObject.memory) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdClearAttachments( - VkCommandBuffer commandBuffer, - u32 attachmentCount, - const VkClearAttachment* pAttachments, - u32 rectCount, - const VkClearRect* pRects) { - commandBufferObject := GetCommandBuffer(commandBuffer) - - rects := pRects[0:rectCount] - for i in (0 .. rectCount) { - rect := rects[i] - } - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdResolveImage( - VkCommandBuffer commandBuffer, - VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - u32 regionCount, - const VkImageResolve* pRegions) { - commandBufferObject := GetCommandBuffer(commandBuffer) - srcImageObject := GetImage(srcImage) - dstImageObject := GetImage(dstImage) - assert(commandBufferObject.device == srcImageObject.device) - assert(commandBufferObject.device == dstImageObject.device) - - regions := pRegions[0:regionCount] - for i in (0 .. regionCount) { - region := regions[i] - } - - bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory) - bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -@threadSafety("app") -cmd void vkCmdSetEvent( - VkCommandBuffer commandBuffer, - VkEvent event, - VkPipelineStageFlags stageMask) { - commandBufferObject := GetCommandBuffer(commandBuffer) - eventObject := GetEvent(event) - assert(commandBufferObject.device == eventObject.device) -} - -@threadSafety("app") -cmd void vkCmdResetEvent( - VkCommandBuffer commandBuffer, - VkEvent event, - VkPipelineStageFlags stageMask) { - commandBufferObject := GetCommandBuffer(commandBuffer) - eventObject := GetEvent(event) - assert(commandBufferObject.device == eventObject.device) -} - -@threadSafety("app") -cmd void vkCmdWaitEvents( - VkCommandBuffer commandBuffer, - u32 eventCount, - const VkEvent* pEvents, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - u32 memoryBarrierCount, - const VkMemoryBarrier* pMemoryBarriers, - u32 bufferMemoryBarrierCount, - const VkBufferMemoryBarrier* pBufferMemoryBarriers, - u32 imageMemoryBarrierCount, - const VkImageMemoryBarrier* pImageMemoryBarriers) { - commandBufferObject := GetCommandBuffer(commandBuffer) - - events := pEvents[0:eventCount] - for i in (0 .. eventCount) { - event := events[i] - eventObject := GetEvent(event) - assert(commandBufferObject.device == eventObject.device) - } - - memoryBarriers := pMemoryBarriers[0:memoryBarrierCount] - for i in (0 .. memoryBarrierCount) { - memoryBarrier := memoryBarriers[i] - } - bufferMemoryBarriers := pBufferMemoryBarriers[0:bufferMemoryBarrierCount] - for i in (0 .. bufferMemoryBarrierCount) { - bufferMemoryBarrier := bufferMemoryBarriers[i] - bufferObject := GetBuffer(bufferMemoryBarrier.buffer) - assert(bufferObject.device == commandBufferObject.device) - } - imageMemoryBarriers := pImageMemoryBarriers[0:imageMemoryBarrierCount] - for i in (0 .. imageMemoryBarrierCount) { - imageMemoryBarrier := imageMemoryBarriers[i] - imageObject := GetImage(imageMemoryBarrier.image) - assert(imageObject.device == commandBufferObject.device) - } -} - -@threadSafety("app") -cmd void vkCmdPipelineBarrier( - VkCommandBuffer commandBuffer, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - VkDependencyFlags dependencyFlags, - u32 memoryBarrierCount, - const VkMemoryBarrier* pMemoryBarriers, - u32 bufferMemoryBarrierCount, - const VkBufferMemoryBarrier* pBufferMemoryBarriers, - u32 imageMemoryBarrierCount, - const VkImageMemoryBarrier* pImageMemoryBarriers) { - commandBufferObject := GetCommandBuffer(commandBuffer) - - memoryBarriers := pMemoryBarriers[0:memoryBarrierCount] - for i in (0 .. memoryBarrierCount) { - memoryBarrier := memoryBarriers[i] - } - bufferMemoryBarriers := pBufferMemoryBarriers[0:bufferMemoryBarrierCount] - for i in (0 .. bufferMemoryBarrierCount) { - bufferMemoryBarrier := bufferMemoryBarriers[i] - bufferObject := GetBuffer(bufferMemoryBarrier.buffer) - assert(bufferObject.device == commandBufferObject.device) - } - imageMemoryBarriers := pImageMemoryBarriers[0:imageMemoryBarrierCount] - for i in (0 .. imageMemoryBarrierCount) { - imageMemoryBarrier := imageMemoryBarriers[i] - imageObject := GetImage(imageMemoryBarrier.image) - assert(imageObject.device == commandBufferObject.device) - } -} - -@threadSafety("app") -cmd void vkCmdBeginQuery( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - u32 query, - VkQueryControlFlags flags) { - commandBufferObject := GetCommandBuffer(commandBuffer) - queryPoolObject := GetQueryPool(queryPool) - assert(commandBufferObject.device == queryPoolObject.device) -} - -@threadSafety("app") -cmd void vkCmdEndQuery( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - u32 query) { - commandBufferObject := GetCommandBuffer(commandBuffer) - queryPoolObject := GetQueryPool(queryPool) - assert(commandBufferObject.device == queryPoolObject.device) -} - -@threadSafety("app") -cmd void vkCmdResetQueryPool( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - u32 firstQuery, - u32 queryCount) { - commandBufferObject := GetCommandBuffer(commandBuffer) - queryPoolObject := GetQueryPool(queryPool) - assert(commandBufferObject.device == queryPoolObject.device) -} - -@threadSafety("app") -cmd void vkCmdWriteTimestamp( - VkCommandBuffer commandBuffer, - VkPipelineStageFlagBits pipelineStage, - VkQueryPool queryPool, - u32 query) { - commandBufferObject := GetCommandBuffer(commandBuffer) - queryPoolObject := GetQueryPool(queryPool) - assert(commandBufferObject.device == queryPoolObject.device) -} - -@threadSafety("app") -cmd void vkCmdCopyQueryPoolResults( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - u32 firstQuery, - u32 queryCount, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize stride, - VkQueryResultFlags flags) { - commandBufferObject := GetCommandBuffer(commandBuffer) - queryPoolObject := GetQueryPool(queryPool) - dstBufferObject := GetBuffer(dstBuffer) - assert(commandBufferObject.device == queryPoolObject.device) - assert(commandBufferObject.device == dstBufferObject.device) -} - -cmd void vkCmdPushConstants( - VkCommandBuffer commandBuffer, - VkPipelineLayout layout, - VkShaderStageFlags stageFlags, - u32 offset, - u32 size, - const void* pValues) { - commandBufferObject := GetCommandBuffer(commandBuffer) - layoutObject := GetPipelineLayout(layout) - assert(commandBufferObject.device == layoutObject.device) -} - -@threadSafety("app") -cmd void vkCmdBeginRenderPass( - VkCommandBuffer commandBuffer, - const VkRenderPassBeginInfo* pRenderPassBegin, - VkSubpassContents contents) { - commandBufferObject := GetCommandBuffer(commandBuffer) - renderPassObject := GetRenderPass(pRenderPassBegin.renderPass) - framebufferObject := GetFramebuffer(pRenderPassBegin.framebuffer) - assert(commandBufferObject.device == renderPassObject.device) - assert(commandBufferObject.device == framebufferObject.device) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -cmd void vkCmdNextSubpass( - VkCommandBuffer commandBuffer, - VkSubpassContents contents) { - commandBufferObject := GetCommandBuffer(commandBuffer) -} - -@threadSafety("app") -cmd void vkCmdEndRenderPass( - VkCommandBuffer commandBuffer) { - commandBufferObject := GetCommandBuffer(commandBuffer) - - commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT) -} - -cmd void vkCmdExecuteCommands( - VkCommandBuffer commandBuffer, - u32 commandBufferCount, - const VkCommandBuffer* pCommandBuffers) { - commandBufferObject := GetCommandBuffer(commandBuffer) - - commandBuffers := pCommandBuffers[0:commandBufferCount] - for i in (0 .. commandBufferCount) { - secondaryCommandBuffer := commandBuffers[i] - secondaryCommandBufferObject := GetCommandBuffer(secondaryCommandBuffer) - assert(commandBufferObject.device == secondaryCommandBufferObject.device) - } -} - -//@vulkan1_1 functions - -@vulkan1_1 -cmd VkResult vkEnumerateInstanceVersion( - u32* pApiVersion) { - return ? -} - -@vulkan1_1 -cmd VkResult vkBindBufferMemory2( - VkDevice device, - u32 bindInfoCount, - const VkBindBufferMemoryInfo* pBindInfos) { - return ? -} - -@vulkan1_1 -cmd VkResult vkBindImageMemory2( - VkDevice device, - u32 bindInfoCount, - const VkBindImageMemoryInfo* pBindInfos) { - return ? -} - -@vulkan1_1 -cmd void vkGetDeviceGroupPeerMemoryFeatures( - VkDevice device, - u32 heapIndex, - u32 localDeviceIndex, - u32 remoteDeviceIndex, - VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) { -} - -@vulkan1_1 -cmd void vkCmdSetDeviceMask( - VkCommandBuffer commandBuffer, - u32 deviceMask) { -} - -@vulkan1_1 -cmd void vkCmdDispatchBase( - VkCommandBuffer commandBuffer, - u32 baseGroupX, - u32 baseGroupY, - u32 baseGroupZ, - u32 groupCountX, - u32 groupCountY, - u32 groupCountZ) { -} - -@threadSafety("system") -@vulkan1_1 -cmd VkResult vkEnumeratePhysicalDeviceGroups( - VkInstance instance, - u32* pPhysicalDeviceGroupCount, - VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) { - instanceObject := GetInstance(instance) - - physicalDeviceGroupCount := as!u32(?) - pPhysicalDeviceGroupCount[0] = physicalDeviceGroupCount - physicalDevices := pPhysicalDeviceGroupProperties[0:physicalDeviceGroupCount] - - for i in (0 .. physicalDeviceGroupCount) { - physicalDevice := ? - physicalDevices[i] = physicalDevice - if !(physicalDevice in State.PhysicalDevices) { - State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance) - } - } - - return ? -} - -@vulkan1_1 -cmd void vkGetImageMemoryRequirements2( - VkDevice device, - const VkImageMemoryRequirementsInfo2* pInfo, - VkMemoryRequirements2* pMemoryRequirements) { -} - -@vulkan1_1 -cmd void vkGetBufferMemoryRequirements2( - VkDevice device, - const VkBufferMemoryRequirementsInfo2* pInfo, - VkMemoryRequirements2* pMemoryRequirements) { -} - -@vulkan1_1 -cmd void vkGetImageSparseMemoryRequirements2( - VkDevice device, - const VkImageSparseMemoryRequirementsInfo2* pInfo, - u32* pSparseMemoryRequirementCount, - VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) { -} - -@vulkan1_1 -cmd void vkGetPhysicalDeviceFeatures2( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures2* pFeatures) { -} - -@vulkan1_1 -cmd void vkGetPhysicalDeviceProperties2( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties2* pProperties) { -} - -@vulkan1_1 -cmd void vkGetPhysicalDeviceFormatProperties2( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkFormatProperties2* pFormatProperties) { -} - -@vulkan1_1 -cmd VkResult vkGetPhysicalDeviceImageFormatProperties2( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, - VkImageFormatProperties2* pImageFormatProperties) { - return ? -} - -@vulkan1_1 -cmd void vkGetPhysicalDeviceQueueFamilyProperties2( - VkPhysicalDevice physicalDevice, - u32* pQueueFamilyPropertyCount, - VkQueueFamilyProperties2* pQueueFamilyProperties) { -} - -@vulkan1_1 -cmd void vkGetPhysicalDeviceMemoryProperties2( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties2* pMemoryProperties) { -} - -@vulkan1_1 -cmd void vkGetPhysicalDeviceSparseImageFormatProperties2( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, - u32* pPropertyCount, - VkSparseImageFormatProperties2* pProperties) { -} - -@vulkan1_1 -cmd void vkTrimCommandPool( - VkDevice device, - VkCommandPool commandPool, - VkCommandPoolTrimFlags flags) { -} - - -@vulkan1_1 -cmd void vkGetDeviceQueue2( - VkDevice device, - const VkDeviceQueueInfo2* pQueueInfo, - VkQueue* pQueue) { - deviceObject := GetDevice(device) - - queue := ? - pQueue[0] = queue - - if !(queue in State.Queues) { - State.Queues[queue] = new!QueueObject(device: device) - } -} - -@vulkan1_1 -cmd VkResult vkCreateSamplerYcbcrConversion( - VkDevice device, - const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSamplerYcbcrConversion* pYcbcrConversion) { - return ? -} - -@vulkan1_1 -cmd void vkDestroySamplerYcbcrConversion( - VkDevice device, - VkSamplerYcbcrConversion ycbcrConversion, - const VkAllocationCallbacks* pAllocator) { -} - -@vulkan1_1 -cmd VkResult vkCreateDescriptorUpdateTemplate( - VkDevice device, - const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) { - return ? -} - -@vulkan1_1 -cmd void vkDestroyDescriptorUpdateTemplate( - VkDevice device, - VkDescriptorUpdateTemplate descriptorUpdateTemplate, - const VkAllocationCallbacks* pAllocator) { -} - -@vulkan1_1 -cmd void vkUpdateDescriptorSetWithTemplate( - VkDevice device, - VkDescriptorSet descriptorSet, - VkDescriptorUpdateTemplate descriptorUpdateTemplate, - const void* pData) { -} - -@vulkan1_1 -cmd void vkGetPhysicalDeviceExternalBufferProperties( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, - VkExternalBufferProperties* pExternalBufferProperties) { -} - -@vulkan1_1 -cmd void vkGetPhysicalDeviceExternalFenceProperties( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, - VkExternalFenceProperties* pExternalFenceProperties) { -} - -@vulkan1_1 -cmd void vkGetPhysicalDeviceExternalSemaphoreProperties( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, - VkExternalSemaphoreProperties* pExternalSemaphoreProperties) { -} - -@vulkan1_1 -cmd void vkGetDescriptorSetLayoutSupport( - VkDevice device, - const VkDescriptorSetLayoutCreateInfo* pCreateInfo, - VkDescriptorSetLayoutSupport* pSupport) { -} - - -@extension("VK_KHR_surface") // 1 -cmd void vkDestroySurfaceKHR( - VkInstance instance, - VkSurfaceKHR surface, - const VkAllocationCallbacks* pAllocator) { - instanceObject := GetInstance(instance) - surfaceObject := GetSurface(surface) - assert(surfaceObject.instance == instance) - - State.Surfaces[surface] = null -} - -@extension("VK_KHR_surface") // 1 -cmd VkResult vkGetPhysicalDeviceSurfaceSupportKHR( - VkPhysicalDevice physicalDevice, - u32 queueFamilyIndex, - VkSurfaceKHR surface, - VkBool32* pSupported) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - - return ? -} - -@extension("VK_KHR_surface") // 1 -cmd VkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - - surfaceCapabilities := ? - pSurfaceCapabilities[0] = surfaceCapabilities - - return ? -} - -@extension("VK_KHR_surface") // 1 -cmd VkResult vkGetPhysicalDeviceSurfaceFormatsKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - u32* pSurfaceFormatCount, - VkSurfaceFormatKHR* pSurfaceFormats) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - - count := as!u32(?) - pSurfaceFormatCount[0] = count - surfaceFormats := pSurfaceFormats[0:count] - - for i in (0 .. count) { - surfaceFormat := ? - surfaceFormats[i] = surfaceFormat - } - - return ? -} - -@extension("VK_KHR_surface") // 1 -cmd VkResult vkGetPhysicalDeviceSurfacePresentModesKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - u32* pPresentModeCount, - VkPresentModeKHR* pPresentModes) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - - count := as!u32(?) - pPresentModeCount[0] = count - presentModes := pPresentModes[0:count] - - for i in (0 .. count) { - presentMode := ? - presentModes[i] = presentMode - } - - return ? -} - -@extension("VK_KHR_swapchain") // 2 -cmd VkResult vkCreateSwapchainKHR( - VkDevice device, - const VkSwapchainCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSwapchainKHR* pSwapchain) { - assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR) - deviceObject := GetDevice(device) - - swapchain := ? - pSwapchain[0] = swapchain - State.Swapchains[swapchain] = new!SwapchainObject(device: device) - - return ? -} - -@extension("VK_KHR_swapchain") // 2 -cmd void vkDestroySwapchainKHR( - VkDevice device, - VkSwapchainKHR swapchain, - const VkAllocationCallbacks* pAllocator) { - deviceObject := GetDevice(device) - swapchainObject := GetSwapchain(swapchain) - assert(swapchainObject.device == device) - - State.Swapchains[swapchain] = null -} - -@extension("VK_KHR_swapchain") // 2 -cmd VkResult vkGetSwapchainImagesKHR( - VkDevice device, - VkSwapchainKHR swapchain, - u32* pSwapchainImageCount, - VkImage* pSwapchainImages) { - deviceObject := GetDevice(device) - - count := as!u32(?) - pSwapchainImageCount[0] = count - swapchainImages := pSwapchainImages[0:count] - - for i in (0 .. count) { - swapchainImage := ? - swapchainImages[i] = swapchainImage - State.Images[swapchainImage] = new!ImageObject(device: device) - } - - return ? -} - -@extension("VK_KHR_swapchain") // 2 -cmd VkResult vkAcquireNextImageKHR( - VkDevice device, - VkSwapchainKHR swapchain, - u64 timeout, - VkSemaphore semaphore, - VkFence fence, - u32* pImageIndex) { - deviceObject := GetDevice(device) - swapchainObject := GetSwapchain(swapchain) - - imageIndex := ? - pImageIndex[0] = imageIndex - - return ? -} - -@extension("VK_KHR_swapchain") // 2 -cmd VkResult vkQueuePresentKHR( - VkQueue queue, - const VkPresentInfoKHR* pPresentInfo) { - queueObject := GetQueue(queue) - - presentInfo := ? - pPresentInfo[0] = presentInfo - - return ? -} - -@vulkan1_1 -@extension("VK_KHR_swapchain") // 2 -cmd VkResult vkGetDeviceGroupPresentCapabilitiesKHR( - VkDevice device, - VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) { - return ? -} - -@vulkan1_1 -@extension("VK_KHR_swapchain") // 2 -cmd VkResult vkGetDeviceGroupSurfacePresentModesKHR( - VkDevice device, - VkSurfaceKHR surface, - VkDeviceGroupPresentModeFlagsKHR* pModes) { - return ? -} - -@vulkan1_1 -@extension("VK_KHR_swapchain") // 2 -cmd VkResult vkGetPhysicalDevicePresentRectanglesKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - u32* pRectCount, - VkRect2D* pRects) { - return ? -} - -@vulkan1_1 -@extension("VK_KHR_swapchain") // 2 -cmd VkResult vkAcquireNextImage2KHR( - VkDevice device, - const VkAcquireNextImageInfoKHR* pAcquireInfo, - u32* pImageIndex) { - return ? -} - -@extension("VK_KHR_display") // 3 -cmd VkResult vkGetPhysicalDeviceDisplayPropertiesKHR( - VkPhysicalDevice physicalDevice, - u32* pPropertyCount, - VkDisplayPropertiesKHR* pProperties) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - return ? -} - -@extension("VK_KHR_display") // 3 -cmd VkResult vkGetPhysicalDeviceDisplayPlanePropertiesKHR( - VkPhysicalDevice physicalDevice, - u32* pPropertyCount, - VkDisplayPlanePropertiesKHR* pProperties) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - return ? -} - -@extension("VK_KHR_display") // 3 -cmd VkResult vkGetDisplayPlaneSupportedDisplaysKHR( - VkPhysicalDevice physicalDevice, - u32 planeIndex, - u32* pDisplayCount, - VkDisplayKHR* pDisplays) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - return ? -} - -@extension("VK_KHR_display") // 3 -cmd VkResult vkGetDisplayModePropertiesKHR( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display, - u32* pPropertyCount, - VkDisplayModePropertiesKHR* pProperties) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - return ? -} - -@extension("VK_KHR_display") // 3 -cmd VkResult vkCreateDisplayModeKHR( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display, - const VkDisplayModeCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDisplayModeKHR* pMode) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - return ? -} - -@extension("VK_KHR_display") // 3 -cmd VkResult vkGetDisplayPlaneCapabilitiesKHR( - VkPhysicalDevice physicalDevice, - VkDisplayModeKHR mode, - u32 planeIndex, - VkDisplayPlaneCapabilitiesKHR* pCapabilities) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - return ? -} - -@extension("VK_KHR_display") // 3 -cmd VkResult vkCreateDisplayPlaneSurfaceKHR( - VkInstance instance, - const VkDisplaySurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface) { - return ? -} - -@extension("VK_KHR_display_swapchain") // 4 -cmd VkResult vkCreateSharedSwapchainsKHR( - VkDevice device, - u32 swapchainCount, - const VkSwapchainCreateInfoKHR* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkSwapchainKHR* pSwapchains) { - return ? -} - -@extension("VK_KHR_xlib_surface") // 5 -cmd VkResult vkCreateXlibSurfaceKHR( - VkInstance instance, - const VkXlibSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface) { - instanceObject := GetInstance(instance) - return ? -} - -@extension("VK_KHR_xlib_surface") // 5 -cmd VkBool32 vkGetPhysicalDeviceXlibPresentationSupportKHR( - VkPhysicalDevice physicalDevice, - u32 queueFamilyIndex, - platform.Display* dpy, - platform.VisualID visualID) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - return ? -} - -@extension("VK_KHR_xcb_surface") // 6 -cmd VkResult vkCreateXcbSurfaceKHR( - VkInstance instance, - const VkXcbSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface) { - instanceObject := GetInstance(instance) - return ? -} - -@extension("VK_KHR_xcb_surface") // 6 -cmd VkBool32 vkGetPhysicalDeviceXcbPresentationSupportKHR( - VkPhysicalDevice physicalDevice, - u32 queueFamilyIndex, - platform.xcb_connection_t* connection, - platform.xcb_visualid_t visual_id) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - return ? -} - -@extension("VK_KHR_wayland_surface") // 7 -cmd VkResult vkCreateWaylandSurfaceKHR( - VkInstance instance, - const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface) { - instanceObject := GetInstance(instance) - return ? -} - -@extension("VK_KHR_wayland_surface") // 7 -cmd VkBool32 vkGetPhysicalDeviceWaylandPresentationSupportKHR( - VkPhysicalDevice physicalDevice, - u32 queueFamilyIndex, - platform.wl_display* display) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - return ? -} - -@extension("VK_KHR_android_surface") // 9 -cmd VkResult vkCreateAndroidSurfaceKHR( - VkInstance instance, - const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface) { - instanceObject := GetInstance(instance) - return ? -} - -@extension("VK_KHR_win32_surface") // 10 -cmd VkResult vkCreateWin32SurfaceKHR( - VkInstance instance, - const VkWin32SurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface) { - instanceObject := GetInstance(instance) - return ? -} - -@extension("VK_KHR_win32_surface") // 10 -cmd VkResult vkGetPhysicalDeviceWin32PresentationSupportKHR( - VkPhysicalDevice physicalDevice, - u32 queueFamilyIndex) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - return ? -} - -@extension("VK_ANDROID_native_buffer") // 11 -@optional -cmd VkResult vkGetSwapchainGrallocUsageANDROID( - VkDevice device, - VkFormat format, - VkImageUsageFlags imageUsage, - s32* grallocUsage) { - return ? -} - -@extension("VK_ANDROID_native_buffer") // 11 -@optional -cmd VkResult vkGetSwapchainGrallocUsage2ANDROID( - VkDevice device, - VkFormat format, - VkImageUsageFlags imageUsage, - VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, - u64* grallocConsumerUsage, - u64* grallocProducerUsage) { - return ? -} - -@extension("VK_ANDROID_native_buffer") // 11 -cmd VkResult vkAcquireImageANDROID( - VkDevice device, - VkImage image, - int nativeFenceFd, - VkSemaphore semaphore, - VkFence fence) { - return ? -} - -@extension("VK_ANDROID_native_buffer") // 11 -cmd VkResult vkQueueSignalReleaseImageANDROID( - VkQueue queue, - u32 waitSemaphoreCount, - const VkSemaphore* pWaitSemaphores, - VkImage image, - int* pNativeFenceFd) { - return ? -} - -@extension("VK_EXT_debug_report") // 12 -@external type void* PFN_vkDebugReportCallbackEXT -@extension("VK_EXT_debug_report") // 12 -@pfn cmd VkBool32 vkDebugReportCallbackEXT( - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - u64 object, - platform.size_t location, - s32 messageCode, - const char* pLayerPrefix, - const char* pMessage, - void* pUserData) { - return ? -} - -@extension("VK_EXT_debug_report") // 12 -cmd VkResult vkCreateDebugReportCallbackEXT( - VkInstance instance, - const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDebugReportCallbackEXT* pCallback) { - return ? -} - -@extension("VK_EXT_debug_report") // 12 -cmd void vkDestroyDebugReportCallbackEXT( - VkInstance instance, - VkDebugReportCallbackEXT callback, - const VkAllocationCallbacks* pAllocator) { -} - -@extension("VK_EXT_debug_report") // 12 -cmd void vkDebugReportMessageEXT( - VkInstance instance, - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - u64 object, - platform.size_t location, - s32 messageCode, - const char* pLayerPrefix, - const char* pMessage) { -} - -@extension("VK_EXT_debug_marker") // 23 -cmd VkResult vkDebugMarkerSetObjectTagEXT( - VkDevice device, - const VkDebugMarkerObjectTagInfoEXT* pTagInfo) { - return ? -} - -@extension("VK_EXT_debug_marker") // 23 -cmd VkResult vkDebugMarkerSetObjectNameEXT( - VkDevice device, - const VkDebugMarkerObjectNameInfoEXT* pNameInfo) { - return ? -} - -@extension("VK_EXT_debug_marker") // 23 -cmd void vkCmdDebugMarkerBeginEXT( - VkCommandBuffer commandBuffer, - const VkDebugMarkerMarkerInfoEXT* pMarkerInfo) { -} - -@extension("VK_EXT_debug_marker") // 23 -cmd void vkCmdDebugMarkerEndEXT( - VkCommandBuffer commandBuffer) { -} - -@extension("VK_EXT_debug_marker") // 23 -cmd void vkCmdDebugMarkerInsertEXT( - VkCommandBuffer commandBuffer, - const VkDebugMarkerMarkerInfoEXT* pMarkerInfo) { -} - -@extension("VK_EXT_transform_feedback") // 29 -cmd void vkCmdBindTransformFeedbackBuffersEXT( - VkCommandBuffer commandBuffer, - u32 firstBinding, - u32 bindingCount, - const VkBuffer* pBuffers, - const VkDeviceSize* pOffsets, - const VkDeviceSize* pSizes) { -} - -@extension("VK_EXT_transform_feedback") // 29 -cmd void vkCmdBeginTransformFeedbackEXT( - VkCommandBuffer commandBuffer, - u32 firstCounterBuffer, - u32 counterBufferCount, - const VkBuffer* pCounterBuffers, - const VkDeviceSize* pCounterBufferOffsets) { -} - -@extension("VK_EXT_transform_feedback") // 29 -cmd void vkCmdEndTransformFeedbackEXT( - VkCommandBuffer commandBuffer, - u32 firstCounterBuffer, - u32 counterBufferCount, - const VkBuffer* pCounterBuffers, - const VkDeviceSize* pCounterBufferOffsets) { -} - -@extension("VK_EXT_transform_feedback") // 29 -cmd void vkCmdBeginQueryIndexedEXT( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - u32 query, - VkQueryControlFlags flags, - u32 index) { -} - -@extension("VK_EXT_transform_feedback") // 29 -cmd void vkCmdEndQueryIndexedEXT( - VkCommandBuffer commandBuffer, - VkQueryPool queryPool, - u32 query, - u32 index) { -} - -@extension("VK_EXT_transform_feedback") // 29 -cmd void vkCmdDrawIndirectByteCountEXT( - VkCommandBuffer commandBuffer, - u32 instanceCount, - u32 firstInstance, - VkBuffer counterBuffer, - VkDeviceSize counterBufferOffset, - u32 counterOffset, - u32 vertexStride) { -} - -@extension("VK_AMD_draw_indirect_count") // 34 -cmd void vkCmdDrawIndirectCountAMD( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - u32 maxDrawCount, - u32 stride) { -} - -@extension("VK_AMD_draw_indirect_count") // 34 -cmd void vkCmdDrawIndexedIndirectCountAMD( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - u32 maxDrawCount, - u32 stride) { -} - -@extension("VK_AMD_shader_info") // 43 -cmd VkResult vkGetShaderInfoAMD( - VkDevice device, - VkPipeline pipeline, - VkShaderStageFlagBits shaderStage, - VkShaderInfoTypeAMD infoType, - platform.size_t* pInfoSize, - void* pInfo) { - return ? -} - -@extension("VK_NV_external_memory_capabilities") // 56 -cmd VkResult vkGetPhysicalDeviceExternalImageFormatPropertiesNV( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkImageType type, - VkImageTiling tiling, - VkImageUsageFlags usage, - VkImageCreateFlags flags, - VkExternalMemoryHandleTypeFlagsNV externalHandleType, - VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties) { - return ? -} - -@extension("VK_NV_external_memory_win32") // 58 -cmd VkResult vkGetMemoryWin32HandleNV( - VkDevice device, - VkDeviceMemory memory, - VkExternalMemoryHandleTypeFlagsNV handleType, - platform.HANDLE* pHandle) { - return ? -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -cmd void vkGetPhysicalDeviceFeatures2KHR( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures2KHR* pFeatures) { -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -cmd void vkGetPhysicalDeviceProperties2KHR( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceProperties2KHR* pProperties) { -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -cmd void vkGetPhysicalDeviceFormatProperties2KHR( - VkPhysicalDevice physicalDevice, - VkFormat format, - VkFormatProperties2KHR* pFormatProperties) { -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -cmd VkResult vkGetPhysicalDeviceImageFormatProperties2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, - VkImageFormatProperties2KHR* pImageFormatProperties) { - return ? -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -cmd void vkGetPhysicalDeviceQueueFamilyProperties2KHR( - VkPhysicalDevice physicalDevice, - u32* pQueueFamilyPropertyCount, - VkQueueFamilyProperties2KHR* pQueueFamilyProperties) { -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -cmd void vkGetPhysicalDeviceMemoryProperties2KHR( - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties) { -} - -@extension("VK_KHR_get_physical_device_properties2") // 60 -cmd void vkGetPhysicalDeviceSparseImageFormatProperties2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, - u32* pPropertyCount, - VkSparseImageFormatProperties2KHR* pProperties) { -} - -@extension("VK_KHR_device_group") // 61 -cmd void vkGetDeviceGroupPeerMemoryFeaturesKHR( - VkDevice device, - u32 heapIndex, - u32 localDeviceIndex, - u32 remoteDeviceIndex, - VkPeerMemoryFeatureFlagsKHR* pPeerMemoryFeatures) { -} - -@extension("VK_KHR_device_group") // 61 -cmd void vkCmdSetDeviceMaskKHR( - VkCommandBuffer commandBuffer, - u32 deviceMask) { -} - - -@extension("VK_KHR_device_group") // 61 -cmd void vkCmdDispatchBaseKHR( - VkCommandBuffer commandBuffer, - u32 baseGroupX, - u32 baseGroupY, - u32 baseGroupZ, - u32 groupCountX, - u32 groupCountY, - u32 groupCountZ) { -} - -@extension("VK_NN_vi_surface") // 63 -cmd VkResult vkCreateViSurfaceNN( - VkInstance instance, - const VkViSurfaceCreateInfoNN* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface) { - return ? -} - -@extension("VK_KHR_maintenance1") // 70 -cmd void vkTrimCommandPoolKHR( - VkDevice device, - VkCommandPool commandPool, - VkCommandPoolTrimFlagsKHR flags) { -} - -@extension("VK_KHR_device_group_creation") // 71 -@threadSafety("system") -cmd VkResult vkEnumeratePhysicalDeviceGroupsKHR( - VkInstance instance, - u32* pPhysicalDeviceGroupCount, - VkPhysicalDeviceGroupPropertiesKHR* pPhysicalDeviceGroupProperties) { - instanceObject := GetInstance(instance) - - physicalDeviceGroupCount := as!u32(?) - pPhysicalDeviceGroupCount[0] = physicalDeviceGroupCount - physicalDevices := pPhysicalDeviceGroupProperties[0:physicalDeviceGroupCount] - - for i in (0 .. physicalDeviceGroupCount) { - physicalDevice := ? - physicalDevices[i] = physicalDevice - if !(physicalDevice in State.PhysicalDevices) { - State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance) - } - } - - return ? -} - -@extension("VK_KHR_external_memory_capabilities") // 72 -cmd void vkGetPhysicalDeviceExternalBufferPropertiesKHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalBufferInfoKHR* pExternalBufferInfo, - VkExternalBufferPropertiesKHR* pExternalBufferProperties) { -} - -@extension("VK_KHR_external_memory_win32") // 74 -cmd VkResult vkGetMemoryWin32HandleKHR( - VkDevice device, - const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo, - platform.HANDLE* pHandle) { - return ? -} - -@extension("VK_KHR_external_memory_win32") // 74 -cmd VkResult vkGetMemoryWin32HandlePropertiesKHR( - VkDevice device, - VkExternalMemoryHandleTypeFlagBitsKHR handleType, - platform.HANDLE handle, - VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties) { - return ? -} - -@extension("VK_KHR_external_memory_fd") // 75 -cmd VkResult vkGetMemoryFdKHR( - VkDevice device, - const VkMemoryGetFdInfoKHR* pGetFdInfo, - s32* pFd) { - return ? -} - -@extension("VK_KHR_external_memory_fd") // 75 -cmd VkResult vkGetMemoryFdPropertiesKHR( - VkDevice device, - VkExternalMemoryHandleTypeFlagBitsKHR handleType, - s32 fd, - VkMemoryFdPropertiesKHR* pMemoryFdProperties) { - return ? -} - -@extension("VK_KHR_external_semaphore_capabilities") // 77 -cmd void vkGetPhysicalDeviceExternalSemaphorePropertiesKHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalSemaphoreInfoKHR* pExternalSemaphoreInfo, - VkExternalSemaphorePropertiesKHR* pExternalSemaphoreProperties) { -} - -@extension("VK_KHR_external_semaphore_win32") // 79 -cmd VkResult vkImportSemaphoreWin32HandleKHR( - VkDevice device, - const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo) { - return ? -} - -@extension("VK_KHR_external_semaphore_win32") // 79 -cmd VkResult vkGetSemaphoreWin32HandleKHR( - VkDevice device, - const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo, - platform.HANDLE* pHandle) { - return ? -} - -@extension("VK_KHR_external_semaphore_fd") // 80 -cmd VkResult vkImportSemaphoreFdKHR( - VkDevice device, - const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo) { - return ? -} - -@extension("VK_KHR_external_semaphore_fd") // 80 -cmd VkResult vkGetSemaphoreFdKHR( - VkDevice device, - const VkSemaphoreGetFdInfoKHR* pGetFdInfo, - s32* pFd) { - return ? -} - -@extension("VK_KHR_push_descriptor") // 81 -cmd void vkCmdPushDescriptorSetKHR( - VkCommandBuffer commandBuffer, - VkPipelineBindPoint pipelineBindPoint, - VkPipelineLayout layout, - u32 set, - u32 descriptorWriteCount, - const VkWriteDescriptorSet* pDescriptorWrites) { -} - -@extension("VK_EXT_conditional_rendering") // 82 -cmd void vkCmdBeginConditionalRenderingEXT( - VkCommandBuffer commandBuffer, - const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin) { -} - -@extension("VK_EXT_conditional_rendering") // 82 -cmd void vkCmdEndConditionalRenderingEXT( - VkCommandBuffer commandBuffer) { -} - -@extension("VK_KHR_descriptor_update_template") // 86 -cmd VkResult vkCreateDescriptorUpdateTemplateKHR( - VkDevice device, - const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate) { - return ? -} - -@extension("VK_KHR_descriptor_update_template") // 86 -cmd void vkDestroyDescriptorUpdateTemplateKHR( - VkDevice device, - VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, - const VkAllocationCallbacks* pAllocator) { -} - -@extension("VK_KHR_descriptor_update_template") // 86 -cmd void vkUpdateDescriptorSetWithTemplateKHR( - VkDevice device, - VkDescriptorSet descriptorSet, - VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, - const void* pData) { -} - -@extension("VK_KHR_descriptor_update_template") // 86 -cmd void vkCmdPushDescriptorSetWithTemplateKHR( - VkCommandBuffer commandBuffer, - VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, - VkPipelineLayout layout, - u32 set, - const void* pData) { -} - -@extension("VK_NVX_device_generated_commands") // 87 -cmd void vkCmdProcessCommandsNVX( - VkCommandBuffer commandBuffer, - const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo) { -} - -@extension("VK_NVX_device_generated_commands") // 87 -cmd void vkCmdReserveSpaceForCommandsNVX( - VkCommandBuffer commandBuffer, - const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo) { -} - -@extension("VK_NVX_device_generated_commands") // 87 -cmd VkResult vkCreateIndirectCommandsLayoutNVX( - VkDevice device, - const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout) { - return ? -} - -@extension("VK_NVX_device_generated_commands") // 87 -cmd void vkDestroyIndirectCommandsLayoutNVX( - VkDevice device, - VkIndirectCommandsLayoutNVX indirectCommandsLayout, - const VkAllocationCallbacks* pAllocator) { -} - -@extension("VK_NVX_device_generated_commands") // 87 -cmd VkResult vkCreateObjectTableNVX( - VkDevice device, - const VkObjectTableCreateInfoNVX* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkObjectTableNVX* pObjectTable) { - return ? -} - -@extension("VK_NVX_device_generated_commands") // 87 -cmd void vkDestroyObjectTableNVX( - VkDevice device, - VkObjectTableNVX objectTable, - const VkAllocationCallbacks* pAllocator) { -} - -@extension("VK_NVX_device_generated_commands") // 87 -cmd VkResult vkRegisterObjectsNVX( - VkDevice device, - VkObjectTableNVX objectTable, - u32 objectCount, - const VkObjectTableEntryNVX* const* ppObjectTableEntries, - const u32* pObjectIndices) { - return ? -} - -@extension("VK_NVX_device_generated_commands") // 87 -cmd VkResult vkUnregisterObjectsNVX( - VkDevice device, - VkObjectTableNVX objectTable, - u32 objectCount, - const VkObjectEntryTypeNVX* pObjectEntryTypes, - const u32* pObjectIndices) { - return ? -} - -@extension("VK_NVX_device_generated_commands") // 87 -cmd void vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX( - VkPhysicalDevice physicalDevice, - VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, - VkDeviceGeneratedCommandsLimitsNVX* pLimits) { -} - -@extension("VK_NV_clip_space_w_scaling") // 88 -cmd void vkCmdSetViewportWScalingNV( - VkCommandBuffer commandBuffer, - u32 firstViewport, - u32 viewportCount, - const VkViewportWScalingNV* pViewportWScalings) { -} - -@extension("VK_EXT_direct_mode_display") // 89 -cmd VkResult vkReleaseDisplayEXT( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display) { - return ? -} - -@extension("VK_EXT_acquire_xlib_display") // 90 -cmd VkResult vkAcquireXlibDisplayEXT( - VkPhysicalDevice physicalDevice, - platform.Display* dpy, - VkDisplayKHR display) { - return ? -} - -@extension("VK_EXT_acquire_xlib_display") // 90 -cmd VkResult vkGetRandROutputDisplayEXT( - VkPhysicalDevice physicalDevice, - platform.Display* dpy, - platform.RROutput rrOutput, - VkDisplayKHR* pDisplay) { - return ? -} - -@extension("VK_EXT_display_surface_counter") // 91 -cmd VkResult vkGetPhysicalDeviceSurfaceCapabilities2EXT( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - VkSurfaceCapabilities2EXT* pSurfaceCapabilities) { - return ? -} - -@extension("VK_EXT_display_control") // 92 -cmd VkResult vkDisplayPowerControlEXT( - VkDevice device, - VkDisplayKHR display, - const VkDisplayPowerInfoEXT* pDisplayPowerInfo) { - return ? -} - -@extension("VK_EXT_display_control") // 92 -cmd VkResult vkRegisterDeviceEventEXT( - VkDevice device, - const VkDeviceEventInfoEXT* pDeviceEventInfo, - const VkAllocationCallbacks* pAllocator, - VkFence* pFence) { - return ? -} - -@extension("VK_EXT_display_control") // 92 -cmd VkResult vkRegisterDisplayEventEXT( - VkDevice device, - VkDisplayKHR display, - const VkDisplayEventInfoEXT* pDisplayEventInfo, - const VkAllocationCallbacks* pAllocator, - VkFence* pFence) { - return ? -} - -@extension("VK_EXT_display_control") // 92 -cmd VkResult vkGetSwapchainCounterEXT( - VkDevice device, - VkSwapchainKHR swapchain, - VkSurfaceCounterFlagBitsEXT counter, - u64* pCounterValue) { - return ? -} - -@extension("VK_GOOGLE_display_timing") // 93 -cmd VkResult vkGetRefreshCycleDurationGOOGLE( - VkDevice device, - VkSwapchainKHR swapchain, - VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) { - deviceObject := GetDevice(device) - swapchainObject := GetSwapchain(swapchain) - - displayTimingProperties := ? - pDisplayTimingProperties[0] = displayTimingProperties - - return ? -} - -@extension("VK_GOOGLE_display_timing") // 93 -cmd VkResult vkGetPastPresentationTimingGOOGLE( - VkDevice device, - VkSwapchainKHR swapchain, - u32* pPresentationTimingCount, - VkPastPresentationTimingGOOGLE* pPresentationTimings) { - return ? -} - -@extension("VK_EXT_discard_rectangles") // 100 -cmd void vkCmdSetDiscardRectangleEXT( - VkCommandBuffer commandBuffer, - u32 firstDiscardRectangle, - u32 discardRectangleCount, - const VkRect2D* pDiscardRectangles) { -} - -@extension("VK_EXT_hdr_metadata") // 106 -cmd void vkSetHdrMetadataEXT( - VkDevice device, - u32 swapchainCount, - const VkSwapchainKHR* pSwapchains, - const VkHdrMetadataEXT* pMetadata) { -} - -@extension("VK_KHR_create_renderpass2") // 110 -cmd VkResult vkCreateRenderPass2KHR( - VkDevice device, - const VkRenderPassCreateInfo2KHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkRenderPass* pRenderPass) { - return ? -} - -@extension("VK_KHR_create_renderpass2") // 110 -cmd void vkCmdBeginRenderPass2KHR( - VkCommandBuffer commandBuffer, - const VkRenderPassBeginInfo* pRenderPassBegin, - const VkSubpassBeginInfoKHR* pSubpassBeginInfo) { -} - -@extension("VK_KHR_create_renderpass2") // 110 -cmd void vkCmdNextSubpass2KHR( - VkCommandBuffer commandBuffer, - const VkSubpassBeginInfoKHR* pSubpassBeginInfo, - const VkSubpassEndInfoKHR* pSubpassEndInfo) { -} - -@extension("VK_KHR_create_renderpass2") // 110 -cmd void vkCmdEndRenderPass2KHR( - VkCommandBuffer commandBuffer, - const VkSubpassEndInfoKHR* pSubpassEndInfo) { -} - -@extension("VK_KHR_shared_presentable_image") // 112 -cmd VkResult vkGetSwapchainStatusKHR( - VkDevice device, - VkSwapchainKHR swapchain) { - return ? -} - -@extension("VK_KHR_external_fence_capabilities") // 113 -cmd void vkGetPhysicalDeviceExternalFencePropertiesKHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceExternalFenceInfoKHR* pExternalFenceInfo, - VkExternalFencePropertiesKHR* pExternalFenceProperties) { -} - -@extension("VK_KHR_external_fence_win32") // 115 -cmd VkResult vkImportFenceWin32HandleKHR( - VkDevice device, - const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo) { - return ? -} - -@extension("VK_KHR_external_fence_win32") // 115 -cmd VkResult vkGetFenceWin32HandleKHR( - VkDevice device, - const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo, - platform.HANDLE* pHandle) { - return ? -} - -@extension("VK_KHR_external_fence_fd") // 116 -cmd VkResult vkImportFenceFdKHR( - VkDevice device, - const VkImportFenceFdInfoKHR* pImportFenceFdInfo) { - return ? -} - -@extension("VK_KHR_external_fence_fd") // 116 -cmd VkResult vkGetFenceFdKHR( - VkDevice device, - const VkFenceGetFdInfoKHR* pGetFdInfo, - int* pFd) { - return ? -} - -@extension("VK_KHR_get_surface_capabilities2") // 120 -cmd VkResult vkGetPhysicalDeviceSurfaceCapabilities2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, - VkSurfaceCapabilities2KHR* pSurfaceCapabilities) { - return ? -} - -@extension("VK_KHR_get_surface_capabilities2") // 120 -cmd VkResult vkGetPhysicalDeviceSurfaceFormats2KHR( - VkPhysicalDevice physicalDevice, - const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, - u32* pSurfaceFormatCount, - VkSurfaceFormat2KHR* pSurfaceFormats) { - return ? -} - -@extension("VK_KHR_display_properties2") // 122 -cmd VkResult vkGetPhysicalDeviceDisplayProperties2KHR( - VkPhysicalDevice physicalDevice, - u32* pPropertyCount, - VkDisplayProperties2KHR* pProperties) { - return ? -} - -@extension("VK_KHR_display_properties2") // 122 -cmd VkResult vkGetPhysicalDeviceDisplayPlaneProperties2KHR( - VkPhysicalDevice physicalDevice, - u32* pPropertyCount, - VkDisplayPlaneProperties2KHR* pProperties) { - return ? -} - -@extension("VK_KHR_display_properties2") // 122 -cmd VkResult vkGetDisplayModeProperties2KHR( - VkPhysicalDevice physicalDevice, - VkDisplayKHR display, - u32* pPropertyCount, - VkDisplayModeProperties2KHR* pProperties) { - return ? -} - -@extension("VK_KHR_display_properties2") // 122 -cmd VkResult vkGetDisplayPlaneCapabilities2KHR( - VkPhysicalDevice physicalDevice, - const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo, - VkDisplayPlaneCapabilities2KHR* pCapabilities) { - return ? -} - -@extension("VK_MVK_ios_surface") // 123 -cmd VkResult vkCreateIOSSurfaceMVK( - VkInstance instance, - const VkIOSSurfaceCreateInfoMVK* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface) { - return ? -} - -@extension("VK_MVK_macos_surface") // 124 -cmd VkResult vkCreateMacOSSurfaceMVK( - VkInstance instance, - const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface) { - return ? -} - -@extension("VK_EXT_debug_utils") // 129 -@external type void* PFN_vkDebugUtilsMessengerCallbackEXT -@extension("VK_EXT_debug_utils") // 129 -@pfn cmd VkBool32 vkDebugUtilsMessengerCallbackEXT( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData) { - return ? -} - -@extension("VK_EXT_debug_utils") // 129 -cmd VkResult vkSetDebugUtilsObjectNameEXT( - VkDevice device, - const VkDebugUtilsObjectNameInfoEXT* pNameInfo) { - return ? -} - -@extension("VK_EXT_debug_utils") // 129 -cmd VkResult vkSetDebugUtilsObjectTagEXT( - VkDevice device, - const VkDebugUtilsObjectTagInfoEXT* pTagInfo) { - return ? -} - -@extension("VK_EXT_debug_utils") // 129 -cmd void vkQueueBeginDebugUtilsLabelEXT( - VkQueue queue, - const VkDebugUtilsLabelEXT* pLabelInfo) { -} - -@extension("VK_EXT_debug_utils") // 129 -cmd void vkQueueEndDebugUtilsLabelEXT(VkQueue queue) { -} - -@extension("VK_EXT_debug_utils") // 129 -cmd void vkQueueInsertDebugUtilsLabelEXT( - VkQueue queue, - const VkDebugUtilsLabelEXT* pLabelInfo) { -} - -@extension("VK_EXT_debug_utils") // 129 -cmd void vkCmdBeginDebugUtilsLabelEXT( - VkCommandBuffer commandBuffer, - const VkDebugUtilsLabelEXT* pLabelInfo) { -} - -@extension("VK_EXT_debug_utils") // 129 -cmd void vkCmdEndDebugUtilsLabelEXT(VkCommandBuffer commandBuffer) { -} - -@extension("VK_EXT_debug_utils") // 129 -cmd void vkCmdInsertDebugUtilsLabelEXT( - VkCommandBuffer commandBuffer, - const VkDebugUtilsLabelEXT* pLabelInfo) { -} - -@extension("VK_EXT_debug_utils") // 129 -cmd VkResult vkCreateDebugUtilsMessengerEXT( - VkInstance instance, - const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkDebugUtilsMessengerEXT* pMessenger) { - return ? -} - -@extension("VK_EXT_debug_utils") // 129 -cmd void vkDestroyDebugUtilsMessengerEXT( - VkInstance instance, - VkDebugUtilsMessengerEXT messenger, - const VkAllocationCallbacks* pAllocator) { -} - -@extension("VK_EXT_debug_utils") // 129 -cmd void vkSubmitDebugUtilsMessageEXT( - VkInstance instance, - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageTypes, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData) { -} - -@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130 -@vulkan1_1 // extension requires 1.1, and should become non-optional when 1.1 does -cmd VkResult vkGetAndroidHardwareBufferPropertiesANDROID( - VkDevice device, - const platform.AHardwareBuffer* buffer, - VkAndroidHardwareBufferPropertiesANDROID* pProperties) { - return ? -} - -@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130 -@vulkan1_1 // extension requires 1.1, and should become non-optional when 1.1 does -cmd VkResult vkGetMemoryAndroidHardwareBufferANDROID( - VkDevice device, - const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, - platform.AHardwareBuffer** pBuffer) { - return ? -} - -@extension("VK_EXT_sample_locations") // 144 -cmd void vkCmdSetSampleLocationsEXT( - VkCommandBuffer commandBuffer, - const VkSampleLocationsInfoEXT* pSampleLocationsInfo) { -} - -@extension("VK_EXT_sample_locations") // 144 -cmd void vkGetPhysicalDeviceMultisamplePropertiesEXT( - VkPhysicalDevice physicalDevice, - VkSampleCountFlagBits samples, - VkMultisamplePropertiesEXT* pMultisampleProperties) { -} - -@extension("VK_KHR_get_memory_requirements2") // 147 -cmd void vkGetImageMemoryRequirements2KHR( - VkDevice device, - const VkImageMemoryRequirementsInfo2KHR* pInfo, - VkMemoryRequirements2KHR* pMemoryRequirements) { -} - -@extension("VK_KHR_get_memory_requirements2") // 147 -cmd void vkGetBufferMemoryRequirements2KHR( - VkDevice device, - const VkBufferMemoryRequirementsInfo2KHR* pInfo, - VkMemoryRequirements2KHR* pMemoryRequirements) { -} - -@extension("VK_KHR_get_memory_requirements2") // 147 -cmd void vkGetImageSparseMemoryRequirements2KHR( - VkDevice device, - const VkImageSparseMemoryRequirementsInfo2KHR* pInfo, - u32* pSparseMemoryRequirementCount, - VkSparseImageMemoryRequirements2KHR* pSparseMemoryRequirements) { -} - -@extension("VK_KHR_sampler_ycbcr_conversion") // 157 -cmd VkResult vkCreateSamplerYcbcrConversionKHR( - VkDevice device, - const VkSamplerYcbcrConversionCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSamplerYcbcrConversionKHR* pYcbcrConversion) { - return ? -} - -@extension("VK_KHR_sampler_ycbcr_conversion") // 157 -cmd void vkDestroySamplerYcbcrConversionKHR( - VkDevice device, - VkSamplerYcbcrConversionKHR ycbcrConversion, - const VkAllocationCallbacks* pAllocator) { -} - -@extension("VK_KHR_bind_memory2") // 158 -cmd VkResult vkBindBufferMemory2KHR( - VkDevice device, - u32 bindInfoCount, - const VkBindBufferMemoryInfoKHR* pBindInfos) { - return ? -} - -@extension("VK_KHR_bind_memory2") // 158 -cmd VkResult vkBindImageMemory2KHR( - VkDevice device, - u32 bindInfoCount, - const VkBindImageMemoryInfoKHR* pBindInfos) { - return ? -} - -@extension("VK_EXT_image_drm_format_modifier") // 159 -cmd VkResult vkGetImageDrmFormatModifierPropertiesEXT( - VkDevice device, - VkImage image, - VkImageDrmFormatModifierPropertiesEXT* pProperties) { - return ? -} - -@extension("VK_EXT_validation_cache") // 161 -cmd VkResult vkCreateValidationCacheEXT( - VkDevice device, - const VkValidationCacheCreateInfoEXT* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkValidationCacheEXT* pValidationCache) { - return ? -} - -@extension("VK_EXT_validation_cache") // 161 -cmd void vkDestroyValidationCacheEXT( - VkDevice device, - VkValidationCacheEXT validationCache, - const VkAllocationCallbacks* pAllocator) { -} - -@extension("VK_EXT_validation_cache") // 161 -cmd VkResult vkMergeValidationCachesEXT( - VkDevice device, - VkValidationCacheEXT dstCache, - u32 srcCacheCount, - const VkValidationCacheEXT* pSrcCaches) { - return ? -} - -@extension("VK_EXT_validation_cache") // 161 -cmd VkResult vkGetValidationCacheDataEXT( - VkDevice device, - VkValidationCacheEXT validationCache, - platform.size_t* pDataSize, - void* pData) { - return ? -} - -@extension("VK_NV_shading_rate_image") // 165 -cmd void vkCmdBindShadingRateImageNV( - VkCommandBuffer commandBuffer, - VkImageView imageView, - VkImageLayout imageLayout) { -} - -@extension("VK_NV_shading_rate_image") // 165 -cmd void vkCmdSetViewportShadingRatePaletteNV( - VkCommandBuffer commandBuffer, - u32 firstViewport, - u32 viewportCount, - const VkShadingRatePaletteNV* pShadingRatePalettes) { -} - -@extension("VK_NV_shading_rate_image") // 165 -cmd void vkCmdSetCoarseSampleOrderNV( - VkCommandBuffer commandBuffer, - VkCoarseSampleOrderTypeNV sampleOrderType, - u32 customSampleOrderCount, - const VkCoarseSampleOrderCustomNV* pCustomSampleOrders) { -} - -@extension("VK_NV_ray_tracing") // 166 -cmd VkResult vkCreateAccelerationStructureNV( - VkDevice device, - const VkAccelerationStructureCreateInfoNV* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkAccelerationStructureNV* pAccelerationStructure) { - return ? -} - -@extension("VK_NV_ray_tracing") // 166 -cmd void vkDestroyAccelerationStructureNV( - VkDevice device, - VkAccelerationStructureNV accelerationStructure, - const VkAllocationCallbacks* pAllocator) { -} - -@extension("VK_NV_ray_tracing") // 166 -cmd void vkGetAccelerationStructureMemoryRequirementsNV( - VkDevice device, - const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, - VkMemoryRequirements2KHR* pMemoryRequirements) { -} - -@extension("VK_NV_ray_tracing") // 166 -cmd VkResult vkBindAccelerationStructureMemoryNV( - VkDevice device, - u32 bindInfoCount, - const VkBindAccelerationStructureMemoryInfoNV* pBindInfos) { - return ? -} - -@extension("VK_NV_ray_tracing") // 166 -cmd void vkCmdBuildAccelerationStructureNV( - VkCommandBuffer commandBuffer, - const VkAccelerationStructureInfoNV* pInfo, - VkBuffer instanceData, - VkDeviceSize instanceOffset, - VkBool32 update, - VkAccelerationStructureNV dst, - VkAccelerationStructureNV src, - VkBuffer scratch, - VkDeviceSize scratchOffset) { -} - -@extension("VK_NV_ray_tracing") // 166 -cmd void vkCmdCopyAccelerationStructureNV( - VkCommandBuffer commandBuffer, - VkAccelerationStructureNV dst, - VkAccelerationStructureNV src, - VkCopyAccelerationStructureModeNV mode) { -} - -@extension("VK_NV_ray_tracing") // 166 -cmd void vkCmdTraceRaysNV( - VkCommandBuffer commandBuffer, - VkBuffer raygenShaderBindingTableBuffer, - VkDeviceSize raygenShaderBindingOffset, - VkBuffer missShaderBindingTableBuffer, - VkDeviceSize missShaderBindingOffset, - VkDeviceSize missShaderBindingStride, - VkBuffer hitShaderBindingTableBuffer, - VkDeviceSize hitShaderBindingOffset, - VkDeviceSize hitShaderBindingStride, - VkBuffer callableShaderBindingTableBuffer, - VkDeviceSize callableShaderBindingOffset, - VkDeviceSize callableShaderBindingStride, - u32 width, - u32 height, - u32 depth) { -} - -@extension("VK_NV_ray_tracing") // 166 -cmd VkResult vkCreateRaytracingPipelinesNV( - VkDevice device, - VkPipelineCache pipelineCache, - u32 createInfoCount, - const VkRayTracingPipelineCreateInfoNV* pCreateInfos, - const VkAllocationCallbacks* pAllocator, - VkPipeline* pPipelines) { - return ? -} - -@extension("VK_NV_ray_tracing") // 166 -cmd VkResult vkGetRaytracingShaderHandlesNV( - VkDevice device, - VkPipeline pipeline, - u32 firstGroup, - u32 groupCount, - platform.size_t dataSize, - void* pData) { - return ? -} - -@extension("VK_NV_ray_tracing") // 166 -cmd VkResult vkGetAccelerationStructureHandleNV( - VkDevice device, - VkAccelerationStructureNV accelerationStructure, - platform.size_t dataSize, - void* pData) { - return ? -} - -@extension("VK_NV_ray_tracing") // 166 -cmd void vkCmdWriteAccelerationStructurePropertiesNV( - VkCommandBuffer commandBuffer, - u32 accelerationStructureCount, - const VkAccelerationStructureNV* pAccelerationStructures, - VkQueryType queryType, - VkQueryPool queryPool, - u32 firstQuery) { -} - -@extension("VK_NV_ray_tracing") // 166 -cmd VkResult vkCompileDeferredNV( - VkDevice device, - VkPipeline pipeline, - u32 shader) { - return ? -} - -@extension("VK_KHR_maintenance3") // 169 -cmd void vkGetDescriptorSetLayoutSupportKHR( - VkDevice device, - const VkDescriptorSetLayoutCreateInfo* pCreateInfo, - VkDescriptorSetLayoutSupportKHR* pSupport) { -} - -@extension("VK_KHR_draw_indirect_count") // 170 -cmd void vkCmdDrawIndirectCountKHR( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - u32 maxDrawCount, - u32 stride) { -} - -@extension("VK_KHR_draw_indirect_count") // 170 -cmd void vkCmdDrawIndexedIndirectCountKHR( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - u32 maxDrawCount, - u32 stride) { -} - -@extension("VK_EXT_external_memory_host") // 179 -cmd VkResult vkGetMemoryHostPointerPropertiesEXT( - VkDevice device, - VkExternalMemoryHandleTypeFlagBits handleType, - const void* pHostPointer, - VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties) { - return ? -} - -@extension("VK_AMD_buffer_marker") // 180 -cmd void vkCmdWriteBufferMarkerAMD( - VkCommandBuffer commandBuffer, - VkPipelineStageFlagBits pipelineStage, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - u32 marker) { -} - -@extension("VK_EXT_calibrated_timestamps") // 185 -cmd VkResult vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( - VkPhysicalDevice physicalDevice, - u32* pTimeDomainCount, - VkTimeDomainEXT* pTimeDomains) { - return ? -} - -@extension("VK_EXT_calibrated_timestamps") // 185 -cmd VkResult vkGetCalibratedTimestampsEXT( - VkDevice device, - u32 timestampCount, - const VkCalibratedTimestampInfoEXT* pTimestampInfos, - u64* pTimestamps, - u64* pMaxDeviation) { - return ? -} - -@extension("VK_NV_mesh_shader") // 203 -cmd void vkCmdDrawMeshTasksNV( - VkCommandBuffer commandBuffer, - u32 taskCount, - u32 firstTask) { -} - -@extension("VK_NV_mesh_shader") // 203 -cmd void vkCmdDrawMeshTasksIndirectNV( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - u32 drawCount, - u32 stride) { -} - -@extension("VK_NV_mesh_shader") // 203 -cmd void vkCmdDrawMeshTasksIndirectCountNV( - VkCommandBuffer commandBuffer, - VkBuffer buffer, - VkDeviceSize offset, - VkBuffer countBuffer, - VkDeviceSize countBufferOffset, - u32 maxDrawCount, - u32 stride) { -} - -@extension("VK_NV_scissor_exclusive") // 206 -cmd void vkCmdSetExclusiveScissorNV( - VkCommandBuffer commandBuffer, - u32 firstExclusiveScissor, - u32 exclusiveScissorCount, - const VkRect2D* pExclusiveScissors) { -} - -@extension("VK_NV_device_diagnostic_checkpoints") // 207 -cmd void vkCmdSetCheckpointNV( - VkCommandBuffer commandBuffer, - const void* pCheckpointMarker) { -} - -@extension("VK_NV_device_diagnostic_checkpoints") // 207 -cmd void vkGetQueueCheckpointDataNV( - VkQueue queue, - u32* pCheckpointDataCount, - VkCheckpointDataNV* pCheckpointData) { -} - -@extension("VK_FUCHSIA_imagepipe_surface") // 215 -cmd VkResult vkCreateImagePipeSurfaceFUCHSIA( - VkInstance instance, - const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface) { - return ? -} - - -//////////////// -// Validation // -//////////////// - -extern void validate(string layerName, bool condition, string message) - - -///////////////////////////// -// Internal State Tracking // -///////////////////////////// - -StateObject State - -@internal class StateObject { - // Dispatchable objects. - map!(VkInstance, ref!InstanceObject) Instances - map!(VkPhysicalDevice, ref!PhysicalDeviceObject) PhysicalDevices - map!(VkDevice, ref!DeviceObject) Devices - map!(VkQueue, ref!QueueObject) Queues - map!(VkCommandBuffer, ref!CommandBufferObject) CommandBuffers - - // Non-dispatchable objects. - map!(VkDeviceMemory, ref!DeviceMemoryObject) DeviceMemories - map!(VkBuffer, ref!BufferObject) Buffers - map!(VkBufferView, ref!BufferViewObject) BufferViews - map!(VkImage, ref!ImageObject) Images - map!(VkImageView, ref!ImageViewObject) ImageViews - map!(VkShaderModule, ref!ShaderModuleObject) ShaderModules - map!(VkPipeline, ref!PipelineObject) Pipelines - map!(VkPipelineLayout, ref!PipelineLayoutObject) PipelineLayouts - map!(VkSampler, ref!SamplerObject) Samplers - map!(VkDescriptorSet, ref!DescriptorSetObject) DescriptorSets - map!(VkDescriptorSetLayout, ref!DescriptorSetLayoutObject) DescriptorSetLayouts - map!(VkDescriptorPool, ref!DescriptorPoolObject) DescriptorPools - map!(VkFence, ref!FenceObject) Fences - map!(VkSemaphore, ref!SemaphoreObject) Semaphores - map!(VkEvent, ref!EventObject) Events - map!(VkQueryPool, ref!QueryPoolObject) QueryPools - map!(VkFramebuffer, ref!FramebufferObject) Framebuffers - map!(VkRenderPass, ref!RenderPassObject) RenderPasses - map!(VkPipelineCache, ref!PipelineCacheObject) PipelineCaches - map!(VkCommandPool, ref!CommandPoolObject) CommandPools - map!(VkSurfaceKHR, ref!SurfaceObject) Surfaces - map!(VkSwapchainKHR, ref!SwapchainObject) Swapchains -} - -@internal class InstanceObject { -} - -@internal class PhysicalDeviceObject { - VkInstance instance -} - -@internal class DeviceObject { - VkPhysicalDevice physicalDevice -} - -@internal class QueueObject { - VkDevice device - VkQueueFlags flags -} - -@internal class CommandBufferObject { - VkDevice device - map!(u64, VkDeviceMemory) boundObjects - VkQueueFlags queueFlags -} - -@internal class DeviceMemoryObject { - VkDevice device - VkDeviceSize allocationSize - map!(u64, VkDeviceSize) boundObjects - map!(VkCommandBuffer, VkCommandBuffer) boundCommandBuffers -} - -@internal class BufferObject { - VkDevice device - VkDeviceMemory memory - VkDeviceSize memoryOffset -} - -@internal class BufferViewObject { - VkDevice device - VkBuffer buffer -} - -@internal class ImageObject { - VkDevice device - VkDeviceMemory memory - VkDeviceSize memoryOffset -} - -@internal class ImageViewObject { - VkDevice device - VkImage image -} - -@internal class ShaderObject { - VkDevice device -} - -@internal class ShaderModuleObject { - VkDevice device -} - -@internal class PipelineObject { - VkDevice device -} - -@internal class PipelineLayoutObject { - VkDevice device -} - -@internal class SamplerObject { - VkDevice device -} - -@internal class DescriptorSetObject { - VkDevice device -} - -@internal class DescriptorSetLayoutObject { - VkDevice device -} - -@internal class DescriptorPoolObject { - VkDevice device -} - -@internal class FenceObject { - VkDevice device - bool signaled -} - -@internal class SemaphoreObject { - VkDevice device -} - -@internal class EventObject { - VkDevice device -} - -@internal class QueryPoolObject { - VkDevice device -} - -@internal class FramebufferObject { - VkDevice device -} - -@internal class RenderPassObject { - VkDevice device -} - -@internal class PipelineCacheObject { - VkDevice device -} - -@internal class CommandPoolObject { - VkDevice device -} - -@internal class SurfaceObject { - VkInstance instance -} - -@internal class SwapchainObject { - VkDevice device -} - -macro ref!InstanceObject GetInstance(VkInstance instance) { - assert(instance in State.Instances) - return State.Instances[instance] -} - -macro ref!PhysicalDeviceObject GetPhysicalDevice(VkPhysicalDevice physicalDevice) { - assert(physicalDevice in State.PhysicalDevices) - return State.PhysicalDevices[physicalDevice] -} - -macro ref!DeviceObject GetDevice(VkDevice device) { - assert(device in State.Devices) - return State.Devices[device] -} - -macro ref!QueueObject GetQueue(VkQueue queue) { - assert(queue in State.Queues) - return State.Queues[queue] -} - -macro ref!CommandBufferObject GetCommandBuffer(VkCommandBuffer commandBuffer) { - assert(commandBuffer in State.CommandBuffers) - return State.CommandBuffers[commandBuffer] -} - -macro ref!DeviceMemoryObject GetDeviceMemory(VkDeviceMemory memory) { - assert(memory in State.DeviceMemories) - return State.DeviceMemories[memory] -} - -macro ref!BufferObject GetBuffer(VkBuffer buffer) { - assert(buffer in State.Buffers) - return State.Buffers[buffer] -} - -macro ref!BufferViewObject GetBufferView(VkBufferView bufferView) { - assert(bufferView in State.BufferViews) - return State.BufferViews[bufferView] -} - -macro ref!ImageObject GetImage(VkImage image) { - assert(image in State.Images) - return State.Images[image] -} - -macro ref!ImageViewObject GetImageView(VkImageView imageView) { - assert(imageView in State.ImageViews) - return State.ImageViews[imageView] -} - -macro ref!ShaderModuleObject GetShaderModule(VkShaderModule shaderModule) { - assert(shaderModule in State.ShaderModules) - return State.ShaderModules[shaderModule] -} - -macro ref!PipelineObject GetPipeline(VkPipeline pipeline) { - assert(pipeline in State.Pipelines) - return State.Pipelines[pipeline] -} - -macro ref!PipelineLayoutObject GetPipelineLayout(VkPipelineLayout pipelineLayout) { - assert(pipelineLayout in State.PipelineLayouts) - return State.PipelineLayouts[pipelineLayout] -} - -macro ref!SamplerObject GetSampler(VkSampler sampler) { - assert(sampler in State.Samplers) - return State.Samplers[sampler] -} - -macro ref!DescriptorSetObject GetDescriptorSet(VkDescriptorSet descriptorSet) { - assert(descriptorSet in State.DescriptorSets) - return State.DescriptorSets[descriptorSet] -} - -macro ref!DescriptorSetLayoutObject GetDescriptorSetLayout(VkDescriptorSetLayout descriptorSetLayout) { - assert(descriptorSetLayout in State.DescriptorSetLayouts) - return State.DescriptorSetLayouts[descriptorSetLayout] -} - -macro ref!DescriptorPoolObject GetDescriptorPool(VkDescriptorPool descriptorPool) { - assert(descriptorPool in State.DescriptorPools) - return State.DescriptorPools[descriptorPool] -} - -macro ref!FenceObject GetFence(VkFence fence) { - assert(fence in State.Fences) - return State.Fences[fence] -} - -macro ref!SemaphoreObject GetSemaphore(VkSemaphore semaphore) { - assert(semaphore in State.Semaphores) - return State.Semaphores[semaphore] -} - -macro ref!EventObject GetEvent(VkEvent event) { - assert(event in State.Events) - return State.Events[event] -} - -macro ref!QueryPoolObject GetQueryPool(VkQueryPool queryPool) { - assert(queryPool in State.QueryPools) - return State.QueryPools[queryPool] -} - -macro ref!FramebufferObject GetFramebuffer(VkFramebuffer framebuffer) { - assert(framebuffer in State.Framebuffers) - return State.Framebuffers[framebuffer] -} - -macro ref!RenderPassObject GetRenderPass(VkRenderPass renderPass) { - assert(renderPass in State.RenderPasses) - return State.RenderPasses[renderPass] -} - -macro ref!PipelineCacheObject GetPipelineCache(VkPipelineCache pipelineCache) { - assert(pipelineCache in State.PipelineCaches) - return State.PipelineCaches[pipelineCache] -} - -macro ref!CommandPoolObject GetCommandPool(VkCommandPool commandPool) { - assert(commandPool in State.CommandPools) - return State.CommandPools[commandPool] -} - -macro ref!SurfaceObject GetSurface(VkSurfaceKHR surface) { - assert(surface in State.Surfaces) - return State.Surfaces[surface] -} - -macro ref!SwapchainObject GetSwapchain(VkSwapchainKHR swapchain) { - assert(swapchain in State.Swapchains) - return State.Swapchains[swapchain] -} - -macro VkQueueFlags AddQueueFlag(VkQueueFlags flags, VkQueueFlagBits bit) { - return as!VkQueueFlags(as!u32(flags) | as!u32(bit)) -} diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp index ad46c3bf93..37b5368452 100644 --- a/vulkan/libvulkan/api_gen.cpp +++ b/vulkan/libvulkan/api_gen.cpp @@ -54,6 +54,11 @@ namespace { // clang-format off +VKAPI_ATTR VkResult disabledCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*) { + driver::Logger(instance).Err(instance, "VK_KHR_android_surface not enabled. Exported vkCreateAndroidSurfaceKHR not executed."); + return VK_SUCCESS; +} + VKAPI_ATTR void disabledDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR, const VkAllocationCallbacks*) { driver::Logger(instance).Err(instance, "VK_KHR_surface not enabled. Exported vkDestroySurfaceKHR not executed."); } @@ -112,18 +117,13 @@ VKAPI_ATTR VkResult disabledGetDeviceGroupSurfacePresentModesKHR(VkDevice device return VK_SUCCESS; } -VKAPI_ATTR VkResult disabledGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR, uint32_t*, VkRect2D*) { - driver::Logger(physicalDevice).Err(physicalDevice, "VK_KHR_swapchain not enabled. Exported vkGetPhysicalDevicePresentRectanglesKHR not executed."); - return VK_SUCCESS; -} - VKAPI_ATTR VkResult disabledAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR*, uint32_t*) { driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkAcquireNextImage2KHR not executed."); return VK_SUCCESS; } -VKAPI_ATTR VkResult disabledCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*) { - driver::Logger(instance).Err(instance, "VK_KHR_android_surface not enabled. Exported vkCreateAndroidSurfaceKHR not executed."); +VKAPI_ATTR VkResult disabledGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR, uint32_t*, VkRect2D*) { + driver::Logger(physicalDevice).Err(physicalDevice, "VK_KHR_swapchain not enabled. Exported vkGetPhysicalDevicePresentRectanglesKHR not executed."); return VK_SUCCESS; } @@ -161,7 +161,12 @@ bool InitDispatchTable( INIT_PROC(true, instance, CreateDevice); INIT_PROC(true, instance, EnumerateDeviceExtensionProperties); INIT_PROC(true, instance, GetPhysicalDeviceSparseImageFormatProperties); - INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups); + INIT_PROC_EXT(KHR_android_surface, true, instance, CreateAndroidSurfaceKHR); + INIT_PROC_EXT(KHR_surface, true, instance, DestroySurfaceKHR); + INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceSupportKHR); + INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceCapabilitiesKHR); + INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceFormatsKHR); + INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfacePresentModesKHR); INIT_PROC(false, instance, GetPhysicalDeviceFeatures2); INIT_PROC(false, instance, GetPhysicalDeviceProperties2); INIT_PROC(false, instance, GetPhysicalDeviceFormatProperties2); @@ -170,15 +175,10 @@ bool InitDispatchTable( INIT_PROC(false, instance, GetPhysicalDeviceMemoryProperties2); INIT_PROC(false, instance, GetPhysicalDeviceSparseImageFormatProperties2); INIT_PROC(false, instance, GetPhysicalDeviceExternalBufferProperties); - INIT_PROC(false, instance, GetPhysicalDeviceExternalFenceProperties); INIT_PROC(false, instance, GetPhysicalDeviceExternalSemaphoreProperties); - INIT_PROC_EXT(KHR_surface, true, instance, DestroySurfaceKHR); - INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceSupportKHR); - INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceCapabilitiesKHR); - INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceFormatsKHR); - INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfacePresentModesKHR); + INIT_PROC(false, instance, GetPhysicalDeviceExternalFenceProperties); + INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups); INIT_PROC_EXT(KHR_swapchain, false, instance, GetPhysicalDevicePresentRectanglesKHR); - INIT_PROC_EXT(KHR_android_surface, true, instance, CreateAndroidSurfaceKHR); // clang-format on return success; @@ -313,32 +313,32 @@ bool InitDispatchTable( INIT_PROC(true, dev, CmdNextSubpass); INIT_PROC(true, dev, CmdEndRenderPass); INIT_PROC(true, dev, CmdExecuteCommands); + INIT_PROC_EXT(KHR_swapchain, true, dev, CreateSwapchainKHR); + INIT_PROC_EXT(KHR_swapchain, true, dev, DestroySwapchainKHR); + INIT_PROC_EXT(KHR_swapchain, true, dev, GetSwapchainImagesKHR); + INIT_PROC_EXT(KHR_swapchain, true, dev, AcquireNextImageKHR); + INIT_PROC_EXT(KHR_swapchain, true, dev, QueuePresentKHR); + INIT_PROC(false, dev, TrimCommandPool); + INIT_PROC(false, dev, GetDeviceGroupPeerMemoryFeatures); INIT_PROC(false, dev, BindBufferMemory2); INIT_PROC(false, dev, BindImageMemory2); - INIT_PROC(false, dev, GetDeviceGroupPeerMemoryFeatures); INIT_PROC(false, dev, CmdSetDeviceMask); + INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupPresentCapabilitiesKHR); + INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupSurfacePresentModesKHR); + INIT_PROC_EXT(KHR_swapchain, false, dev, AcquireNextImage2KHR); INIT_PROC(false, dev, CmdDispatchBase); - INIT_PROC(false, dev, GetImageMemoryRequirements2); + INIT_PROC(false, dev, CreateDescriptorUpdateTemplate); + INIT_PROC(false, dev, DestroyDescriptorUpdateTemplate); + INIT_PROC(false, dev, UpdateDescriptorSetWithTemplate); INIT_PROC(false, dev, GetBufferMemoryRequirements2); + INIT_PROC(false, dev, GetImageMemoryRequirements2); INIT_PROC(false, dev, GetImageSparseMemoryRequirements2); - INIT_PROC(false, dev, TrimCommandPool); - INIT_PROC(false, dev, GetDeviceQueue2); INIT_PROC(false, dev, CreateSamplerYcbcrConversion); INIT_PROC(false, dev, DestroySamplerYcbcrConversion); - INIT_PROC(false, dev, CreateDescriptorUpdateTemplate); - INIT_PROC(false, dev, DestroyDescriptorUpdateTemplate); - INIT_PROC(false, dev, UpdateDescriptorSetWithTemplate); + INIT_PROC(false, dev, GetDeviceQueue2); INIT_PROC(false, dev, GetDescriptorSetLayoutSupport); - INIT_PROC_EXT(KHR_swapchain, true, dev, CreateSwapchainKHR); - INIT_PROC_EXT(KHR_swapchain, true, dev, DestroySwapchainKHR); - INIT_PROC_EXT(KHR_swapchain, true, dev, GetSwapchainImagesKHR); - INIT_PROC_EXT(KHR_swapchain, true, dev, AcquireNextImageKHR); - INIT_PROC_EXT(KHR_swapchain, true, dev, QueuePresentKHR); - INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupPresentCapabilitiesKHR); - INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupSurfacePresentModesKHR); - INIT_PROC_EXT(KHR_swapchain, false, dev, AcquireNextImage2KHR); - INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, false, dev, GetAndroidHardwareBufferPropertiesANDROID); - INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, false, dev, GetMemoryAndroidHardwareBufferANDROID); + INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, true, dev, GetAndroidHardwareBufferPropertiesANDROID); + INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, true, dev, GetMemoryAndroidHardwareBufferANDROID); // clang-format on return success; @@ -478,33 +478,7 @@ VKAPI_ATTR void CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRender VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents); VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer); VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); -VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); -VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); -VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); -VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask); -VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); -VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); -VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); -VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); -VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); -VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); -VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); -VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); -VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); -VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); -VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); -VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); -VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); -VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue); -VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); -VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); -VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); -VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); -VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); -VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); -VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); -VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); -VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); +VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported); VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities); @@ -515,11 +489,37 @@ VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, c VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages); VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex); VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo); +VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); +VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); +VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); +VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); +VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); +VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); +VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); +VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); +VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); +VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); +VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); +VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); +VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); +VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); +VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); +VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask); VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities); VKAPI_ATTR VkResult GetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes); -VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects); VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex); -VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects); +VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); +VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); +VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); +VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); +VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); +VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue); +VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties); VKAPI_ATTR VkResult GetMemoryAndroidHardwareBufferANDROID(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer); @@ -621,9 +621,9 @@ VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const cha // global functions if (instance == VK_NULL_HANDLE) { if (strcmp(pName, "vkCreateInstance") == 0) return reinterpret_cast(CreateInstance); + if (strcmp(pName, "vkEnumerateInstanceVersion") == 0) return reinterpret_cast(EnumerateInstanceVersion); if (strcmp(pName, "vkEnumerateInstanceLayerProperties") == 0) return reinterpret_cast(EnumerateInstanceLayerProperties); if (strcmp(pName, "vkEnumerateInstanceExtensionProperties") == 0) return reinterpret_cast(EnumerateInstanceExtensionProperties); - if (strcmp(pName, "vkEnumerateInstanceVersion") == 0) return reinterpret_cast(EnumerateInstanceVersion); ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \"%s\") call", pName); return nullptr; @@ -1312,40 +1312,48 @@ VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t comma GetData(commandBuffer).dispatch.CmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers); } -VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) { - return GetData(device).dispatch.BindBufferMemory2(device, bindInfoCount, pBindInfos); +VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { + return GetData(instance).dispatch.CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); } -VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) { - return GetData(device).dispatch.BindImageMemory2(device, bindInfoCount, pBindInfos); +VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) { + GetData(instance).dispatch.DestroySurfaceKHR(instance, surface, pAllocator); } -VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) { - GetData(device).dispatch.GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures); +VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported) { + return GetData(physicalDevice).dispatch.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported); } -VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) { - GetData(commandBuffer).dispatch.CmdSetDeviceMask(commandBuffer, deviceMask); +VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) { + return GetData(physicalDevice).dispatch.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities); } -VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) { - GetData(commandBuffer).dispatch.CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ); +VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats) { + return GetData(physicalDevice).dispatch.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount, pSurfaceFormats); } -VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) { - return GetData(instance).dispatch.EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties); +VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes) { + return GetData(physicalDevice).dispatch.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount, pPresentModes); } -VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { - GetData(device).dispatch.GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements); +VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) { + return GetData(device).dispatch.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); } -VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { - GetData(device).dispatch.GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements); +VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) { + GetData(device).dispatch.DestroySwapchainKHR(device, swapchain, pAllocator); } -VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) { - GetData(device).dispatch.GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements); +VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages) { + return GetData(device).dispatch.GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages); +} + +VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex) { + return GetData(device).dispatch.AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex); +} + +VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo) { + return GetData(queue).dispatch.QueuePresentKHR(queue, pPresentInfo); } VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) { @@ -1380,104 +1388,96 @@ VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCo GetData(device).dispatch.TrimCommandPool(device, commandPool, flags); } -VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) { - GetData(device).dispatch.GetDeviceQueue2(device, pQueueInfo, pQueue); -} - -VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) { - return GetData(device).dispatch.CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion); -} - -VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) { - GetData(device).dispatch.DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator); +VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) { + GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties); } -VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) { - return GetData(device).dispatch.CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate); +VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) { + GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties); } -VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) { - GetData(device).dispatch.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator); +VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) { + GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties); } -VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) { - GetData(device).dispatch.UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData); +VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) { + return GetData(instance).dispatch.EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties); } -VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) { - GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties); +VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) { + GetData(device).dispatch.GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures); } -VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) { - GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties); +VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) { + return GetData(device).dispatch.BindBufferMemory2(device, bindInfoCount, pBindInfos); } -VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) { - GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties); +VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) { + return GetData(device).dispatch.BindImageMemory2(device, bindInfoCount, pBindInfos); } -VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) { - GetData(device).dispatch.GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport); +VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) { + GetData(commandBuffer).dispatch.CmdSetDeviceMask(commandBuffer, deviceMask); } -VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) { - GetData(instance).dispatch.DestroySurfaceKHR(instance, surface, pAllocator); +VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) { + return GetData(device).dispatch.GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities); } -VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported) { - return GetData(physicalDevice).dispatch.GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported); +VKAPI_ATTR VkResult GetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes) { + return GetData(device).dispatch.GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes); } -VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) { - return GetData(physicalDevice).dispatch.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities); +VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) { + return GetData(device).dispatch.AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex); } -VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats) { - return GetData(physicalDevice).dispatch.GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount, pSurfaceFormats); +VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) { + GetData(commandBuffer).dispatch.CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ); } -VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes) { - return GetData(physicalDevice).dispatch.GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount, pPresentModes); +VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) { + return GetData(physicalDevice).dispatch.GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects); } -VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) { - return GetData(device).dispatch.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); +VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) { + return GetData(device).dispatch.CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate); } -VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) { - GetData(device).dispatch.DestroySwapchainKHR(device, swapchain, pAllocator); +VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) { + GetData(device).dispatch.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator); } -VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages) { - return GetData(device).dispatch.GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages); +VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) { + GetData(device).dispatch.UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData); } -VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex) { - return GetData(device).dispatch.AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex); +VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { + GetData(device).dispatch.GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements); } -VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo) { - return GetData(queue).dispatch.QueuePresentKHR(queue, pPresentInfo); +VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { + GetData(device).dispatch.GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements); } -VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) { - return GetData(device).dispatch.GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities); +VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) { + GetData(device).dispatch.GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements); } -VKAPI_ATTR VkResult GetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes) { - return GetData(device).dispatch.GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes); +VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) { + return GetData(device).dispatch.CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion); } -VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) { - return GetData(physicalDevice).dispatch.GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects); +VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) { + GetData(device).dispatch.DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator); } -VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) { - return GetData(device).dispatch.AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex); +VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) { + GetData(device).dispatch.GetDeviceQueue2(device, pQueueInfo, pQueue); } -VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { - return GetData(instance).dispatch.CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); +VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) { + GetData(device).dispatch.GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport); } VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties) { @@ -1563,6 +1563,11 @@ VKAPI_ATTR void vkDestroyDevice(VkDevice device, const VkAllocationCallbacks* pA vulkan::api::DestroyDevice(device, pAllocator); } +__attribute__((visibility("default"))) +VKAPI_ATTR VkResult vkEnumerateInstanceVersion(uint32_t* pApiVersion) { + return vulkan::api::EnumerateInstanceVersion(pApiVersion); +} + __attribute__((visibility("default"))) VKAPI_ATTR VkResult vkEnumerateInstanceLayerProperties(uint32_t* pPropertyCount, VkLayerProperties* pProperties) { return vulkan::api::EnumerateInstanceLayerProperties(pPropertyCount, pProperties); @@ -2184,53 +2189,58 @@ VKAPI_ATTR void vkCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t com } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkEnumerateInstanceVersion(uint32_t* pApiVersion) { - return vulkan::api::EnumerateInstanceVersion(pApiVersion); +VKAPI_ATTR VkResult vkCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { + return vulkan::api::CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) { - return vulkan::api::BindBufferMemory2(device, bindInfoCount, pBindInfos); +VKAPI_ATTR void vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) { + vulkan::api::DestroySurfaceKHR(instance, surface, pAllocator); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) { - return vulkan::api::BindImageMemory2(device, bindInfoCount, pBindInfos); +VKAPI_ATTR VkResult vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported) { + return vulkan::api::GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkGetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) { - vulkan::api::GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures); +VKAPI_ATTR VkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) { + return vulkan::api::GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkCmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) { - vulkan::api::CmdSetDeviceMask(commandBuffer, deviceMask); +VKAPI_ATTR VkResult vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats) { + return vulkan::api::GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount, pSurfaceFormats); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) { - vulkan::api::CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ); +VKAPI_ATTR VkResult vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes) { + return vulkan::api::GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount, pPresentModes); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) { - return vulkan::api::EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties); +VKAPI_ATTR VkResult vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) { + return vulkan::api::CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { - vulkan::api::GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements); +VKAPI_ATTR void vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) { + vulkan::api::DestroySwapchainKHR(device, swapchain, pAllocator); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkGetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { - vulkan::api::GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements); +VKAPI_ATTR VkResult vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages) { + return vulkan::api::GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkGetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) { - vulkan::api::GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements); +VKAPI_ATTR VkResult vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex) { + return vulkan::api::AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex); +} + +__attribute__((visibility("default"))) +VKAPI_ATTR VkResult vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo) { + return vulkan::api::QueuePresentKHR(queue, pPresentInfo); } __attribute__((visibility("default"))) @@ -2274,128 +2284,118 @@ VKAPI_ATTR void vkTrimCommandPool(VkDevice device, VkCommandPool commandPool, Vk } __attribute__((visibility("default"))) -VKAPI_ATTR void vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) { - vulkan::api::GetDeviceQueue2(device, pQueueInfo, pQueue); -} - -__attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) { - return vulkan::api::CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion); -} - -__attribute__((visibility("default"))) -VKAPI_ATTR void vkDestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) { - vulkan::api::DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator); +VKAPI_ATTR void vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) { + vulkan::api::GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkCreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) { - return vulkan::api::CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate); +VKAPI_ATTR void vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) { + vulkan::api::GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkDestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) { - vulkan::api::DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator); +VKAPI_ATTR void vkGetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) { + vulkan::api::GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) { - vulkan::api::UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData); +VKAPI_ATTR VkResult vkEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) { + return vulkan::api::EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) { - vulkan::api::GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties); +VKAPI_ATTR void vkGetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) { + vulkan::api::GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkGetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) { - vulkan::api::GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties); +VKAPI_ATTR VkResult vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) { + return vulkan::api::BindBufferMemory2(device, bindInfoCount, pBindInfos); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) { - vulkan::api::GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties); +VKAPI_ATTR VkResult vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) { + return vulkan::api::BindImageMemory2(device, bindInfoCount, pBindInfos); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkGetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) { - vulkan::api::GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport); +VKAPI_ATTR void vkCmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) { + vulkan::api::CmdSetDeviceMask(commandBuffer, deviceMask); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) { - vulkan::api::DestroySurfaceKHR(instance, surface, pAllocator); +VKAPI_ATTR VkResult vkGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) { + return vulkan::api::GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported) { - return vulkan::api::GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported); +VKAPI_ATTR VkResult vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes) { + return vulkan::api::GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) { - return vulkan::api::GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities); +VKAPI_ATTR VkResult vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) { + return vulkan::api::AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pSurfaceFormatCount, VkSurfaceFormatKHR* pSurfaceFormats) { - return vulkan::api::GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount, pSurfaceFormats); +VKAPI_ATTR void vkCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) { + vulkan::api::CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pPresentModeCount, VkPresentModeKHR* pPresentModes) { - return vulkan::api::GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount, pPresentModes); +VKAPI_ATTR VkResult vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) { + return vulkan::api::GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) { - return vulkan::api::CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); +VKAPI_ATTR VkResult vkCreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) { + return vulkan::api::CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate); } __attribute__((visibility("default"))) -VKAPI_ATTR void vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) { - vulkan::api::DestroySwapchainKHR(device, swapchain, pAllocator); +VKAPI_ATTR void vkDestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) { + vulkan::api::DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages) { - return vulkan::api::GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages); +VKAPI_ATTR void vkUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) { + vulkan::api::UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex) { - return vulkan::api::AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex); +VKAPI_ATTR void vkGetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { + vulkan::api::GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo) { - return vulkan::api::QueuePresentKHR(queue, pPresentInfo); +VKAPI_ATTR void vkGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) { + vulkan::api::GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) { - return vulkan::api::GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities); +VKAPI_ATTR void vkGetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) { + vulkan::api::GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes) { - return vulkan::api::GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes); +VKAPI_ATTR VkResult vkCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) { + return vulkan::api::CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) { - return vulkan::api::GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects); +VKAPI_ATTR void vkDestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) { + vulkan::api::DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) { - return vulkan::api::AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex); +VKAPI_ATTR void vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) { + vulkan::api::GetDeviceQueue2(device, pQueueInfo, pQueue); } __attribute__((visibility("default"))) -VKAPI_ATTR VkResult vkCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { - return vulkan::api::CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); +VKAPI_ATTR void vkGetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) { + vulkan::api::GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport); } __attribute__((visibility("default"))) diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h index f5822249b3..21958454f5 100644 --- a/vulkan/libvulkan/api_gen.h +++ b/vulkan/libvulkan/api_gen.h @@ -42,7 +42,12 @@ struct InstanceDispatchTable { PFN_vkCreateDevice CreateDevice; PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties; PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties; - PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups; + PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR; + PFN_vkDestroySurfaceKHR DestroySurfaceKHR; + PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR; + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR; + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR; + PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR; PFN_vkGetPhysicalDeviceFeatures2 GetPhysicalDeviceFeatures2; PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2; PFN_vkGetPhysicalDeviceFormatProperties2 GetPhysicalDeviceFormatProperties2; @@ -51,15 +56,10 @@ struct InstanceDispatchTable { PFN_vkGetPhysicalDeviceMemoryProperties2 GetPhysicalDeviceMemoryProperties2; PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 GetPhysicalDeviceSparseImageFormatProperties2; PFN_vkGetPhysicalDeviceExternalBufferProperties GetPhysicalDeviceExternalBufferProperties; - PFN_vkGetPhysicalDeviceExternalFenceProperties GetPhysicalDeviceExternalFenceProperties; PFN_vkGetPhysicalDeviceExternalSemaphoreProperties GetPhysicalDeviceExternalSemaphoreProperties; - PFN_vkDestroySurfaceKHR DestroySurfaceKHR; - PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR; - PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR; - PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR; - PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR; + PFN_vkGetPhysicalDeviceExternalFenceProperties GetPhysicalDeviceExternalFenceProperties; + PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups; PFN_vkGetPhysicalDevicePresentRectanglesKHR GetPhysicalDevicePresentRectanglesKHR; - PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR; // clang-format on }; @@ -186,30 +186,30 @@ struct DeviceDispatchTable { PFN_vkCmdNextSubpass CmdNextSubpass; PFN_vkCmdEndRenderPass CmdEndRenderPass; PFN_vkCmdExecuteCommands CmdExecuteCommands; + PFN_vkCreateSwapchainKHR CreateSwapchainKHR; + PFN_vkDestroySwapchainKHR DestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR AcquireNextImageKHR; + PFN_vkQueuePresentKHR QueuePresentKHR; + PFN_vkTrimCommandPool TrimCommandPool; + PFN_vkGetDeviceGroupPeerMemoryFeatures GetDeviceGroupPeerMemoryFeatures; PFN_vkBindBufferMemory2 BindBufferMemory2; PFN_vkBindImageMemory2 BindImageMemory2; - PFN_vkGetDeviceGroupPeerMemoryFeatures GetDeviceGroupPeerMemoryFeatures; PFN_vkCmdSetDeviceMask CmdSetDeviceMask; + PFN_vkGetDeviceGroupPresentCapabilitiesKHR GetDeviceGroupPresentCapabilitiesKHR; + PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR; + PFN_vkAcquireNextImage2KHR AcquireNextImage2KHR; PFN_vkCmdDispatchBase CmdDispatchBase; - PFN_vkGetImageMemoryRequirements2 GetImageMemoryRequirements2; + PFN_vkCreateDescriptorUpdateTemplate CreateDescriptorUpdateTemplate; + PFN_vkDestroyDescriptorUpdateTemplate DestroyDescriptorUpdateTemplate; + PFN_vkUpdateDescriptorSetWithTemplate UpdateDescriptorSetWithTemplate; PFN_vkGetBufferMemoryRequirements2 GetBufferMemoryRequirements2; + PFN_vkGetImageMemoryRequirements2 GetImageMemoryRequirements2; PFN_vkGetImageSparseMemoryRequirements2 GetImageSparseMemoryRequirements2; - PFN_vkTrimCommandPool TrimCommandPool; - PFN_vkGetDeviceQueue2 GetDeviceQueue2; PFN_vkCreateSamplerYcbcrConversion CreateSamplerYcbcrConversion; PFN_vkDestroySamplerYcbcrConversion DestroySamplerYcbcrConversion; - PFN_vkCreateDescriptorUpdateTemplate CreateDescriptorUpdateTemplate; - PFN_vkDestroyDescriptorUpdateTemplate DestroyDescriptorUpdateTemplate; - PFN_vkUpdateDescriptorSetWithTemplate UpdateDescriptorSetWithTemplate; + PFN_vkGetDeviceQueue2 GetDeviceQueue2; PFN_vkGetDescriptorSetLayoutSupport GetDescriptorSetLayoutSupport; - PFN_vkCreateSwapchainKHR CreateSwapchainKHR; - PFN_vkDestroySwapchainKHR DestroySwapchainKHR; - PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR; - PFN_vkAcquireNextImageKHR AcquireNextImageKHR; - PFN_vkQueuePresentKHR QueuePresentKHR; - PFN_vkGetDeviceGroupPresentCapabilitiesKHR GetDeviceGroupPresentCapabilitiesKHR; - PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR; - PFN_vkAcquireNextImage2KHR AcquireNextImage2KHR; PFN_vkGetAndroidHardwareBufferPropertiesANDROID GetAndroidHardwareBufferPropertiesANDROID; PFN_vkGetMemoryAndroidHardwareBufferANDROID GetMemoryAndroidHardwareBufferANDROID; // clang-format on diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl deleted file mode 100644 index 940b747f1b..0000000000 --- a/vulkan/libvulkan/code-generator.tmpl +++ /dev/null @@ -1,1197 +0,0 @@ -{{define "Copyright"}} -/* -•* Copyright 2016 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. -•*/ -¶{{end}} - -{{Include "../api/templates/vulkan_common.tmpl"}} -{{Global "clang-format" (Strings "clang-format" "-style=file")}} -{{Macro "DefineGlobals" $}} -{{$ | Macro "api_gen.h" | Format (Global "clang-format") | Write "api_gen.h" }} -{{$ | Macro "api_gen.cpp" | Format (Global "clang-format") | Write "api_gen.cpp"}} -{{$ | Macro "driver_gen.h" | Format (Global "clang-format") | Write "driver_gen.h"}} -{{$ | Macro "driver_gen.cpp" | Format (Global "clang-format") | Write "driver_gen.cpp"}} - -{{/* -------------------------------------------------------------------------------- - api_gen.h -------------------------------------------------------------------------------- -*/}} -{{define "api_gen.h"}} -{{Macro "Copyright"}} -¶ -// WARNING: This file is generated. See ../README.md for instructions. -¶ -#ifndef LIBVULKAN_API_GEN_H -#define LIBVULKAN_API_GEN_H -¶ -#include -¶ -#include -¶ -#include "driver_gen.h" -¶ -namespace vulkan {« -namespace api {« -¶ -struct InstanceDispatchTable { - // clang-format off - {{range $f := AllCommands $}} - {{if (Macro "api.IsInstanceDispatchTableEntry" $f)}} - {{Macro "C++.DeclareTableEntry" $f}}; - {{end}} - {{end}} - // clang-format on -}; -¶ -struct DeviceDispatchTable { - // clang-format off - {{range $f := AllCommands $}} - {{if (Macro "api.IsDeviceDispatchTableEntry" $f)}} - {{Macro "C++.DeclareTableEntry" $f}}; - {{end}} - {{end}} - // clang-format on -}; -¶ -bool InitDispatchTable( - VkInstance instance, - PFN_vkGetInstanceProcAddr get_proc, - const std::bitset &extensions); -bool InitDispatchTable( - VkDevice dev, - PFN_vkGetDeviceProcAddr get_proc, - const std::bitset &extensions); -¶ -»} // namespace api -»} // namespace vulkan -¶ -#endif // LIBVULKAN_API_GEN_H -¶{{end}} - - -{{/* -------------------------------------------------------------------------------- - api_gen.cpp -------------------------------------------------------------------------------- -*/}} -{{define "api_gen.cpp"}} -{{Macro "Copyright"}} -¶ -// WARNING: This file is generated. See ../README.md for instructions. -¶ -#include -#include -¶ -#include -¶ -// to catch mismatches between vulkan.h and this file -#undef VK_NO_PROTOTYPES -#include "api.h" -¶ -namespace vulkan {« -namespace api {« -¶ -{{Macro "C++.DefineInitProcMacro" "dispatch"}} -¶ -{{Macro "api.C++.DefineInitProcExtMacro"}} -¶ -namespace {« -¶ -// clang-format off -¶ -{{range $f := AllCommands $}} - {{Macro "api.C++.DefineExtensionStub" $f}} -{{end}} -// clang-format on -¶ -»} // anonymous -¶ -bool InitDispatchTable( - VkInstance instance, - PFN_vkGetInstanceProcAddr get_proc, - const std::bitset &extensions) { - auto& data = GetData(instance); - bool success = true; - ¶ - // clang-format off - {{range $f := AllCommands $}} - {{if (Macro "api.IsInstanceDispatchTableEntry" $f)}} - {{Macro "C++.InitProc" $f}} - {{end}} - {{end}} - // clang-format on - ¶ - return success; -} -¶ -bool InitDispatchTable( - VkDevice dev, - PFN_vkGetDeviceProcAddr get_proc, - const std::bitset &extensions) { - auto& data = GetData(dev); - bool success = true; - ¶ - // clang-format off - {{range $f := AllCommands $}} - {{if (Macro "api.IsDeviceDispatchTableEntry" $f)}} - {{Macro "C++.InitProc" $f}} - {{end}} - {{end}} - // clang-format on - ¶ - return success; -} -¶ -// clang-format off -¶ -namespace {« -¶ -// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr -{{range $f := AllCommands $}} - {{if and (Macro "IsFunctionExported" $f) (not (Macro "api.IsIntercepted" $f))}} - VKAPI_ATTR {{Node "Type" $f.Return}} {{Macro "BaseName" $f}}({{Macro "Parameters" $f}}); - {{end}} -{{end}} -¶ -{{range $f := AllCommands $}} - {{if and (Macro "IsFunctionExported" $f) (not (Macro "api.IsIntercepted" $f))}} - VKAPI_ATTR {{Node "Type" $f.Return}} {{Macro "BaseName" $f}}({{Macro "Parameters" $f}}) { - {{ if eq $f.Name "vkGetInstanceProcAddr"}} - {{Macro "api.C++.InterceptInstanceProcAddr" $}} - {{else if eq $f.Name "vkGetDeviceProcAddr"}} - {{Macro "api.C++.InterceptDeviceProcAddr" $}} - {{end}} - - {{Macro "api.C++.Dispatch" $f}} - } - ¶ - {{end}} -{{end}} -¶ -»} // anonymous namespace -¶ -// clang-format on -¶ -»} // namespace api -»} // namespace vulkan -¶ -// clang-format off -¶ -{{range $f := AllCommands $}} - {{if (Macro "IsFunctionExported" $f)}} - __attribute__((visibility("default"))) - VKAPI_ATTR {{Node "Type" $f.Return}} {{$f.Name}}({{Macro "Parameters" $f}}) { - {{if not (IsVoid $f.Return.Type)}}return §{{end}} - vulkan::api::{{Macro "BaseName" $f}}({{Macro "Arguments" $f}}); - } - ¶ - {{end}} -{{end}} -¶ -// clang-format on -¶{{end}} - - -{{/* -------------------------------------------------------------------------------- - driver_gen.h -------------------------------------------------------------------------------- -*/}} -{{define "driver_gen.h"}} -{{Macro "Copyright"}} -¶ -// WARNING: This file is generated. See ../README.md for instructions. -¶ -#ifndef LIBVULKAN_DRIVER_GEN_H -#define LIBVULKAN_DRIVER_GEN_H -¶ -#include -#include -¶ -#include -¶ -namespace vulkan {« -namespace driver {« -¶ -{{Macro "driver.C++.DefineProcHookType"}} -¶ -struct InstanceDriverTable { - // clang-format off - {{range $f := AllCommands $}} - {{if (Macro "driver.IsInstanceDriverTableEntry" $f)}} - {{Macro "C++.DeclareTableEntry" $f}}; - {{end}} - {{end}} - // clang-format on -}; -¶ -struct DeviceDriverTable { - // clang-format off - {{range $f := AllCommands $}} - {{if (Macro "driver.IsDeviceDriverTableEntry" $f)}} - {{Macro "C++.DeclareTableEntry" $f}}; - {{end}} - {{end}} - // clang-format on -}; -¶ -const ProcHook* GetProcHook(const char* name); -ProcHook::Extension GetProcHookExtension(const char* name); -¶ -bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc, - const std::bitset &extensions); -bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, - const std::bitset &extensions); -¶ -»} // namespace driver -»} // namespace vulkan -¶ -#endif // LIBVULKAN_DRIVER_TABLE_H -¶{{end}} - - -{{/* -------------------------------------------------------------------------------- - driver_gen.cpp -------------------------------------------------------------------------------- -*/}} -{{define "driver_gen.cpp"}} -{{Macro "Copyright"}} -¶ -// WARNING: This file is generated. See ../README.md for instructions. -¶ -#include -#include -¶ -#include -¶ -#include "driver.h" -¶ -namespace vulkan {« -namespace driver {« -¶ -namespace {« -¶ -// clang-format off -¶ -{{range $f := AllCommands $}} - {{Macro "driver.C++.DefineProcHookStub" $f}} -{{end}} -// clang-format on -¶ -const ProcHook g_proc_hooks[] = { - // clang-format off - {{range $f := SortBy (AllCommands $) "FunctionName"}} - {{if (Macro "driver.IsIntercepted" $f)}} - {{ if (Macro "IsGloballyDispatched" $f)}} - {{Macro "driver.C++.DefineGlobalProcHook" $f}} - {{else if (Macro "IsInstanceDispatched" $f)}} - {{Macro "driver.C++.DefineInstanceProcHook" $f}} - {{else if (Macro "IsDeviceDispatched" $f)}} - {{Macro "driver.C++.DefineDeviceProcHook" $f}} - {{end}} - {{end}} - {{end}} - // clang-format on -}; -¶ -»} // anonymous -¶ -const ProcHook* GetProcHook(const char* name) { - const auto& begin = g_proc_hooks; - const auto& end = g_proc_hooks + - sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]); - const auto hook = std::lower_bound(begin, end, name, - [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; }); - return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr; -} -¶ -ProcHook::Extension GetProcHookExtension(const char* name) { - {{$exts := Strings (Macro "driver.KnownExtensions") | SplitOn "\n"}} - // clang-format off - {{range $e := $exts}} - if (strcmp(name, "{{$e}}") == 0) return ProcHook::{{TrimPrefix "VK_" $e}}; - {{end}} - // clang-format on - return ProcHook::EXTENSION_UNKNOWN; -} -¶ -{{Macro "C++.DefineInitProcMacro" "driver"}} -¶ -{{Macro "driver.C++.DefineInitProcExtMacro"}} -¶ -bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc, - const std::bitset &extensions) -{ - auto& data = GetData(instance); - bool success = true; - ¶ - // clang-format off - {{range $f := AllCommands $}} - {{if (Macro "driver.IsInstanceDriverTableEntry" $f)}} - {{Macro "C++.InitProc" $f}} - {{end}} - {{end}} - // clang-format on - ¶ - return success; -} -¶ -bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, - const std::bitset &extensions) -{ - auto& data = GetData(dev); - bool success = true; - ¶ - // clang-format off - {{range $f := AllCommands $}} - {{if (Macro "driver.IsDeviceDriverTableEntry" $f)}} - {{Macro "C++.InitProc" $f}} - {{end}} - {{end}} - // clang-format on - ¶ - return success; -} -¶ -»} // namespace driver -»} // namespace vulkan -¶ -// clang-format on -¶{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits a declaration of a dispatch/driver table entry. ------------------------------------------------------------------------------- -*/}} -{{define "C++.DeclareTableEntry"}} - {{AssertType $ "Function"}} - - {{Macro "FunctionPtrName" $}} {{Macro "BaseName" $}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits INIT_PROC macro. -------------------------------------------------------------------------------- -*/}} -{{define "C++.DefineInitProcMacro"}} - #define UNLIKELY(expr) __builtin_expect((expr), 0) - ¶ - #define INIT_PROC(required, obj, proc) do { \ - data.{{$}}.proc = reinterpret_cast( \ - get_proc(obj, "vk" # proc)); \ - if (UNLIKELY(required && !data.{{$}}.proc)) { \ - ALOGE("missing " # obj " proc: vk" # proc); \ - success = false; \ - } \ - } while(0) -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits code to invoke INIT_PROC or INIT_PROC_EXT. -------------------------------------------------------------------------------- -*/}} -{{define "C++.InitProc"}} - {{AssertType $ "Function"}} - - {{$ext := GetAnnotation $ "extension"}} - {{if $ext}} - INIT_PROC_EXT({{Macro "BaseName" $ext}}, § - {{else}} - INIT_PROC(§ - {{end}} - - {{if GetAnnotation $ "optional"}}false{{else if GetAnnotation $ "vulkan1_1"}}false{{else}}true{{end}}, § - - {{if (Macro "IsInstanceDispatched" $)}} - instance, § - {{else}} - dev, § - {{end}} - - {{Macro "BaseName" $}}); -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits true if a function is exported and instance-dispatched. ------------------------------------------------------------------------------- -*/}} -{{define "api.IsInstanceDispatchTableEntry"}} - {{AssertType $ "Function"}} - - {{if and (Macro "IsFunctionExported" $) (Macro "IsInstanceDispatched" $)}} - {{/* deprecated and unused internally */}} - {{if not (eq $.Name "vkEnumerateDeviceLayerProperties")}} - true - {{end}} - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits true if a function is exported and device-dispatched. ------------------------------------------------------------------------------- -*/}} -{{define "api.IsDeviceDispatchTableEntry"}} - {{AssertType $ "Function"}} - - {{if and (Macro "IsFunctionExported" $) (Macro "IsDeviceDispatched" $)}} - true - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits true if a function is intercepted by vulkan::api. ------------------------------------------------------------------------------- -*/}} -{{define "api.IsIntercepted"}} - {{AssertType $ "Function"}} - - {{if (Macro "IsFunctionSupported" $)}} - {{/* Global functions cannot be dispatched at all */}} - {{ if (Macro "IsGloballyDispatched" $)}}true - - {{/* VkPhysicalDevice functions that manage device layers */}} - {{else if eq $.Name "vkCreateDevice"}}true - {{else if eq $.Name "vkEnumerateDeviceLayerProperties"}}true - {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true - - {{/* Destroy functions of dispatchable objects */}} - {{else if eq $.Name "vkDestroyInstance"}}true - {{else if eq $.Name "vkDestroyDevice"}}true - - {{end}} - {{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits INIT_PROC_EXT macro for vulkan::api. -------------------------------------------------------------------------------- -*/}} -{{define "api.C++.DefineInitProcExtMacro"}} - // Exported extension functions may be invoked even when their extensions - // are disabled. Dispatch to stubs when that happens. - #define INIT_PROC_EXT(ext, required, obj, proc) do { \ - if (extensions[driver::ProcHook::ext]) \ - INIT_PROC(required, obj, proc); \ - else \ - data.dispatch.proc = disabled ## proc; \ - } while(0) -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits a stub for an exported extension function. -------------------------------------------------------------------------------- -*/}} -{{define "api.C++.DefineExtensionStub"}} - {{AssertType $ "Function"}} - - {{$ext := GetAnnotation $ "extension"}} - {{if and $ext (Macro "IsFunctionExported" $)}} - {{$ext_name := index $ext.Arguments 0}} - - {{$base := (Macro "BaseName" $)}} - - {{$p0 := (index $.CallParameters 0)}} - {{$ptail := (Tail 1 $.CallParameters)}} - - {{$first_type := (Macro "Parameter" $p0)}} - {{$tail_types := (ForEach $ptail "ParameterType" | JoinWith ", ")}} - - VKAPI_ATTR {{Node "Type" $.Return}} disabled{{$base}}({{$first_type}}, {{$tail_types}}) { - driver::Logger({{$p0.Name}}).Err({{$p0.Name}}, § - "{{$ext_name}} not enabled. Exported {{$.Name}} not executed."); - {{if not (IsVoid $.Return.Type)}}return VK_SUCCESS;{{end}} - } - ¶ - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits code for vkGetInstanceProcAddr for function interception. ------------------------------------------------------------------------------- -*/}} -{{define "api.C++.InterceptInstanceProcAddr"}} - {{AssertType $ "API"}} - - // global functions - if (instance == VK_NULL_HANDLE) { - {{range $f := AllCommands $}} - {{if (Macro "IsGloballyDispatched" $f)}} - if (strcmp(pName, "{{$f.Name}}") == 0) return § - reinterpret_cast({{Macro "BaseName" $f}}); - {{end}} - {{end}} - ¶ - ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \"%s\") call", pName); - return nullptr; - } - ¶ - static const struct Hook { - const char* name; - PFN_vkVoidFunction proc; - } hooks[] = { - {{range $f := SortBy (AllCommands $) "FunctionName"}} - {{if (Macro "IsFunctionExported" $f)}} - {{/* hide global functions */}} - {{if (Macro "IsGloballyDispatched" $f)}} - { "{{$f.Name}}", nullptr }, - - {{/* redirect intercepted functions */}} - {{else if (Macro "api.IsIntercepted" $f)}} - { "{{$f.Name}}", reinterpret_cast(§ - {{Macro "BaseName" $f}}) }, - - {{/* redirect vkGetInstanceProcAddr to itself */}} - {{else if eq $f.Name "vkGetInstanceProcAddr"}} - { "{{$f.Name}}", reinterpret_cast({{Macro "BaseName" $f}}) }, - - {{/* redirect device functions to themselves as a workaround for - layers that do not intercept in their vkGetInstanceProcAddr */}} - {{else if (Macro "IsDeviceDispatched" $f)}} - { "{{$f.Name}}", reinterpret_cast({{Macro "BaseName" $f}}) }, - - {{end}} - {{end}} - {{end}} - }; - // clang-format on - constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]); - auto hook = std::lower_bound( - hooks, hooks + count, pName, - [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; }); - if (hook < hooks + count && strcmp(hook->name, pName) == 0) { - if (!hook->proc) { - vulkan::driver::Logger(instance).Err( - instance, "invalid vkGetInstanceProcAddr(%p, \"%s\") call", - instance, pName); - } - return hook->proc; - } - // clang-format off - ¶ -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits code for vkGetDeviceProcAddr for function interception. ------------------------------------------------------------------------------- -*/}} -{{define "api.C++.InterceptDeviceProcAddr"}} - {{AssertType $ "API"}} - - if (device == VK_NULL_HANDLE) { - ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call"); - return nullptr; - } - ¶ - static const char* const known_non_device_names[] = { - {{range $f := SortBy (AllCommands $) "FunctionName"}} - {{if (Macro "IsFunctionSupported" $f)}} - {{if not (Macro "IsDeviceDispatched" $f)}} - "{{$f.Name}}", - {{end}} - {{end}} - {{end}} - }; - // clang-format on - constexpr size_t count = sizeof(known_non_device_names) / - sizeof(known_non_device_names[0]); - if (!pName || - std::binary_search( - known_non_device_names, known_non_device_names + count, pName, - [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) { - vulkan::driver::Logger(device).Err(§ - device, "invalid vkGetDeviceProcAddr(%p, \"%s\") call", device,§ - (pName) ? pName : "(null)"); - return nullptr; - } - // clang-format off - ¶ - {{range $f := AllCommands $}} - {{if (Macro "IsDeviceDispatched" $f)}} - {{ if (Macro "api.IsIntercepted" $f)}} - if (strcmp(pName, "{{$f.Name}}") == 0) return § - reinterpret_cast(§ - {{Macro "BaseName" $f}}); - {{else if eq $f.Name "vkGetDeviceProcAddr"}} - if (strcmp(pName, "{{$f.Name}}") == 0) return § - reinterpret_cast(§ - {{Macro "BaseName" $f}}); - {{end}} - {{end}} - {{end}} - ¶ -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits code to dispatch a function. ------------------------------------------------------------------------------- -*/}} -{{define "api.C++.Dispatch"}} - {{AssertType $ "Function"}} - {{if (Macro "api.IsIntercepted" $)}} - {{Error "$.Name should not be generated"}} - {{end}} - - {{if not (IsVoid $.Return.Type)}}return §{{end}} - - {{$p0 := index $.CallParameters 0}} - GetData({{$p0.Name}}).dispatch.§ - {{Macro "BaseName" $}}({{Macro "Arguments" $}}); -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits a list of extensions intercepted by vulkan::driver. ------------------------------------------------------------------------------- -*/}} -{{define "driver.InterceptedExtensions"}} -VK_ANDROID_native_buffer -VK_EXT_debug_report -VK_EXT_hdr_metadata -VK_EXT_swapchain_colorspace -VK_GOOGLE_display_timing -VK_KHR_android_surface -VK_KHR_incremental_present -VK_KHR_shared_presentable_image -VK_KHR_surface -VK_KHR_swapchain -VK_KHR_get_surface_capabilities2 -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits a list of extensions known to vulkan::driver. ------------------------------------------------------------------------------- -*/}} -{{define "driver.KnownExtensions"}} -{{Macro "driver.InterceptedExtensions"}} -VK_KHR_get_physical_device_properties2 -VK_ANDROID_external_memory_android_hardware_buffer -VK_KHR_bind_memory2 -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits true if an extension is intercepted by vulkan::driver. ------------------------------------------------------------------------------- -*/}} -{{define "driver.IsExtensionIntercepted"}} - {{$ext_name := index $.Arguments 0}} - {{$filters := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}} - - {{range $f := $filters}} - {{if eq $ext_name $f}}true{{end}} - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits true if a function is intercepted by vulkan::driver. ------------------------------------------------------------------------------- -*/}} -{{define "driver.IsIntercepted"}} - {{AssertType $ "Function"}} - - {{if (Macro "IsFunctionSupported" $)}} - {{/* Create functions of dispatchable objects */}} - {{ if eq $.Name "vkCreateInstance"}}true - {{else if eq $.Name "vkCreateDevice"}}true - {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true - {{else if eq $.Name "vkEnumeratePhysicalDeviceGroups"}}true - {{else if eq $.Name "vkGetDeviceQueue"}}true - {{else if eq $.Name "vkGetDeviceQueue2"}}true - {{else if eq $.Name "vkAllocateCommandBuffers"}}true - - {{/* Destroy functions of dispatchable objects */}} - {{else if eq $.Name "vkDestroyInstance"}}true - {{else if eq $.Name "vkDestroyDevice"}}true - - {{/* Enumeration of extensions */}} - {{else if eq $.Name "vkEnumerateInstanceExtensionProperties"}}true - {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true - - {{else if eq $.Name "vkGetInstanceProcAddr"}}true - {{else if eq $.Name "vkGetDeviceProcAddr"}}true - - {{/* VK_KHR_swapchain v69 requirement */}} - {{else if eq $.Name "vkBindImageMemory2"}}true - {{else if eq $.Name "vkBindImageMemory2KHR"}}true - {{end}} - - {{$ext := GetAnnotation $ "extension"}} - {{if $ext}} - {{Macro "driver.IsExtensionIntercepted" $ext}} - {{end}} - - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits true if a function needs a ProcHook stub. ------------------------------------------------------------------------------- -*/}} -{{define "driver.NeedProcHookStub"}} - {{AssertType $ "Function"}} - - {{if and (Macro "driver.IsIntercepted" $) (Macro "IsDeviceDispatched" $)}} - {{$ext := GetAnnotation $ "extension"}} - {{if $ext}} - {{if not (Macro "IsExtensionInternal" $ext)}}true{{end}} - {{end}} - {{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits definition of struct ProcHook. -------------------------------------------------------------------------------- -*/}} -{{define "driver.C++.DefineProcHookType"}} - struct ProcHook { - enum Type { - GLOBAL, - INSTANCE, - DEVICE, - }; - - enum Extension { - {{$exts := Strings (Macro "driver.KnownExtensions") | SplitOn "\n"}} - {{range $e := $exts}} - {{TrimPrefix "VK_" $e}}, - {{end}} - ¶ - EXTENSION_CORE, // valid bit - EXTENSION_COUNT, - EXTENSION_UNKNOWN, - }; - ¶ - const char* name; - Type type; - Extension extension; - ¶ - PFN_vkVoidFunction proc; - PFN_vkVoidFunction checked_proc; // always nullptr for non-device hooks - }; -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits INIT_PROC_EXT macro for vulkan::driver. -------------------------------------------------------------------------------- -*/}} -{{define "driver.C++.DefineInitProcExtMacro"}} - #define INIT_PROC_EXT(ext, required, obj, proc) do { \ - if (extensions[ProcHook::ext]) \ - INIT_PROC(required, obj, proc); \ - } while(0) -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits a stub for ProcHook::checked_proc. -------------------------------------------------------------------------------- -*/}} -{{define "driver.C++.DefineProcHookStub"}} - {{AssertType $ "Function"}} - - {{if (Macro "driver.NeedProcHookStub" $)}} - {{$ext := GetAnnotation $ "extension"}} - {{$ext_name := index $ext.Arguments 0}} - - {{$base := (Macro "BaseName" $)}} - - VKAPI_ATTR {{Node "Type" $.Return}} checked{{$base}}({{Macro "Parameters" $}}) { - {{$p0 := index $.CallParameters 0}} - {{$ext_hook := Strings ("ProcHook::") (Macro "BaseName" $ext)}} - - if (GetData({{$p0.Name}}).hook_extensions[{{$ext_hook}}]) { - {{if not (IsVoid $.Return.Type)}}return §{{end}} - {{$base}}({{Macro "Arguments" $}}); - } else { - Logger({{$p0.Name}}).Err({{$p0.Name}}, "{{$ext_name}} not enabled. {{$.Name}} not executed."); - {{if not (IsVoid $.Return.Type)}}return VK_SUCCESS;{{end}} - } - } - ¶ - {{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits definition of a global ProcHook. -------------------------------------------------------------------------------- -*/}} -{{define "driver.C++.DefineGlobalProcHook"}} - {{AssertType $ "Function"}} - - {{$base := (Macro "BaseName" $)}} - - {{$ext := GetAnnotation $ "extension"}} - {{if $ext}} - {{Error "invalid global extension"}} - {{end}} - - { - "{{$.Name}}", - ProcHook::GLOBAL, - ProcHook::EXTENSION_CORE, - reinterpret_cast({{$base}}), - nullptr, - }, -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits definition of an instance ProcHook. -------------------------------------------------------------------------------- -*/}} -{{define "driver.C++.DefineInstanceProcHook"}} - {{AssertType $ "Function"}} - - {{$base := (Macro "BaseName" $)}} - - { - "{{$.Name}}", - ProcHook::INSTANCE, - - {{$ext := GetAnnotation $ "extension"}} - {{if $ext}} - ProcHook::{{Macro "BaseName" $ext}}, - - {{if (Macro "IsExtensionInternal" $ext)}} - nullptr, - nullptr, - {{else}} - reinterpret_cast({{$base}}), - nullptr, - {{end}} - {{else}} - ProcHook::EXTENSION_CORE, - reinterpret_cast({{$base}}), - nullptr, - {{end}} - }, -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits definition of a device ProcHook. -------------------------------------------------------------------------------- -*/}} -{{define "driver.C++.DefineDeviceProcHook"}} - {{AssertType $ "Function"}} - - {{$base := (Macro "BaseName" $)}} - - { - "{{$.Name}}", - ProcHook::DEVICE, - - {{$ext := GetAnnotation $ "extension"}} - {{if $ext}} - ProcHook::{{Macro "BaseName" $ext}}, - - {{if (Macro "IsExtensionInternal" $ext)}} - nullptr, - nullptr, - {{else}} - reinterpret_cast({{$base}}), - reinterpret_cast(checked{{$base}}), - {{end}} - {{else}} - ProcHook::EXTENSION_CORE, - reinterpret_cast({{$base}}), - nullptr, - {{end}} - }, -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits true if a function is needed by vulkan::driver. -------------------------------------------------------------------------------- -*/}} -{{define "driver.IsDriverTableEntry"}} - {{AssertType $ "Function"}} - - {{if (Macro "IsFunctionSupported" $)}} - {{/* Create functions of dispatchable objects */}} - {{ if eq $.Name "vkCreateDevice"}}true - {{else if eq $.Name "vkGetDeviceQueue"}}true - {{else if eq $.Name "vkGetDeviceQueue2"}}true - {{else if eq $.Name "vkAllocateCommandBuffers"}}true - - {{/* Destroy functions of dispatchable objects */}} - {{else if eq $.Name "vkDestroyInstance"}}true - {{else if eq $.Name "vkDestroyDevice"}}true - - {{/* Enumeration of extensions */}} - {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true - - {{/* We cache physical devices in loader.cpp */}} - {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true - {{else if eq $.Name "vkEnumeratePhysicalDeviceGroups"}}true - - {{else if eq $.Name "vkGetInstanceProcAddr"}}true - {{else if eq $.Name "vkGetDeviceProcAddr"}}true - - {{/* VK_KHR_swapchain->VK_ANDROID_native_buffer translation */}} - {{else if eq $.Name "vkCreateImage"}}true - {{else if eq $.Name "vkDestroyImage"}}true - - {{else if eq $.Name "vkGetPhysicalDeviceProperties"}}true - {{else if eq $.Name "vkGetPhysicalDeviceProperties2"}}true - {{else if eq $.Name "vkGetPhysicalDeviceProperties2KHR"}}true - - {{/* VK_KHR_swapchain v69 requirement */}} - {{else if eq $.Name "vkBindImageMemory2"}}true - {{else if eq $.Name "vkBindImageMemory2KHR"}}true - {{end}} - - {{$ext := GetAnnotation $ "extension"}} - {{if $ext}} - {{$ext_name := index $ext.Arguments 0}} - {{ if eq $ext_name "VK_ANDROID_native_buffer"}}true - {{else if eq $ext_name "VK_EXT_debug_report"}}true - {{end}} - {{end}} - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits true if an instance-dispatched function is needed by vulkan::driver. ------------------------------------------------------------------------------- -*/}} -{{define "driver.IsInstanceDriverTableEntry"}} - {{AssertType $ "Function"}} - - {{if and (Macro "driver.IsDriverTableEntry" $) (Macro "IsInstanceDispatched" $)}} - true - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits true if a device-dispatched function is needed by vulkan::driver. ------------------------------------------------------------------------------- -*/}} -{{define "driver.IsDeviceDriverTableEntry"}} - {{AssertType $ "Function"}} - - {{if and (Macro "driver.IsDriverTableEntry" $) (Macro "IsDeviceDispatched" $)}} - true - {{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits a function/extension name without the "vk"/"VK_" prefix. -------------------------------------------------------------------------------- -*/}} -{{define "BaseName"}} - {{ if IsFunction $}}{{TrimPrefix "vk" $.Name}} - {{else if eq $.Name "extension"}}{{TrimPrefix "VK_" (index $.Arguments 0)}} - {{else}}{{Error "invalid use of BaseName"}} - {{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits a comma-separated list of C parameter names for the given command. -------------------------------------------------------------------------------- -*/}} -{{define "Arguments"}} - {{AssertType $ "Function"}} - - {{ForEach $.CallParameters "ParameterName" | JoinWith ", "}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- -*/}} -{{define "IsGloballyDispatched"}} - {{AssertType $ "Function"}} - {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Global")}} - true - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emit "true" for supported functions that undergo table dispatch. Only global - functions and functions handled in the loader top without calling into - lower layers are not dispatched. ------------------------------------------------------------------------------- -*/}} -{{define "IsInstanceDispatched"}} - {{AssertType $ "Function"}} - {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Instance")}} - true - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emit "true" for supported functions that can have device-specific dispatch. ------------------------------------------------------------------------------- -*/}} -{{define "IsDeviceDispatched"}} - {{AssertType $ "Function"}} - {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Device")}} - true - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emit "true" if a function is core or from a supportable extension. ------------------------------------------------------------------------------- -*/}} -{{define "IsFunctionSupported"}} - {{AssertType $ "Function"}} - {{if not (GetAnnotation $ "pfn")}} - {{$ext := GetAnnotation $ "extension"}} - {{if not $ext}}true - {{else if not (Macro "IsExtensionBlacklisted" $ext)}}true - {{end}} - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Decides whether a function should be exported from the Android Vulkan - library. Functions in the core API and in loader extensions are exported. ------------------------------------------------------------------------------- -*/}} -{{define "IsFunctionExported"}} - {{AssertType $ "Function"}} - - {{if (Macro "IsFunctionSupported" $)}} - {{$ext := GetAnnotation $ "extension"}} - {{if $ext}} - {{Macro "IsExtensionExported" $ext}} - {{else}} - true - {{end}} - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emit "true" if an extension is unsupportable on Android. ------------------------------------------------------------------------------- -*/}} -{{define "IsExtensionBlacklisted"}} - {{$ext := index $.Arguments 0}} - {{ if eq $ext "VK_KHR_display"}}true - {{else if eq $ext "VK_KHR_display_swapchain"}}true - {{else if eq $ext "VK_KHR_mir_surface"}}true - {{else if eq $ext "VK_KHR_xcb_surface"}}true - {{else if eq $ext "VK_KHR_xlib_surface"}}true - {{else if eq $ext "VK_KHR_wayland_surface"}}true - {{else if eq $ext "VK_KHR_win32_surface"}}true - {{else if eq $ext "VK_KHR_external_memory_win32"}}true - {{else if eq $ext "VK_KHR_win32_keyed_mutex"}}true - {{else if eq $ext "VK_KHR_external_semaphore_win32"}}true - {{else if eq $ext "VK_KHR_external_fence_win32"}}true - {{else if eq $ext "VK_EXT_acquire_xlib_display"}}true - {{else if eq $ext "VK_EXT_direct_mode_display"}}true - {{else if eq $ext "VK_EXT_display_surface_counter"}}true - {{else if eq $ext "VK_EXT_display_control"}}true - {{else if eq $ext "VK_FUCHSIA_imagepipe_surface"}}true - {{else if eq $ext "VK_MVK_ios_surface"}}true - {{else if eq $ext "VK_MVK_macos_surface"}}true - {{else if eq $ext "VK_NN_vi_surface"}}true - {{else if eq $ext "VK_NV_external_memory_win32"}}true - {{else if eq $ext "VK_NV_win32_keyed_mutex"}}true - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Reports whether an extension has functions exported by the loader. - E.g. applications can directly link to an extension function. ------------------------------------------------------------------------------- -*/}} -{{define "IsExtensionExported"}} - {{$ext := index $.Arguments 0}} - {{ if eq $ext "VK_KHR_surface"}}true - {{else if eq $ext "VK_KHR_swapchain"}}true - {{else if eq $ext "VK_KHR_android_surface"}}true - {{else if eq $ext "VK_ANDROID_external_memory_android_hardware_buffer"}}true - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Reports whether an extension is internal to the loader and drivers, - so the loader should not enumerate it. ------------------------------------------------------------------------------- -*/}} -{{define "IsExtensionInternal"}} - {{$ext := index $.Arguments 0}} - {{ if eq $ext "VK_ANDROID_native_buffer"}}true - {{end}} -{{end}} diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp index 7020be1eda..3495861d35 100644 --- a/vulkan/libvulkan/driver_gen.cpp +++ b/vulkan/libvulkan/driver_gen.cpp @@ -74,6 +74,15 @@ VKAPI_ATTR VkResult checkedQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR } } +VKAPI_ATTR VkResult checkedBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) { + if (GetData(device).hook_extensions[ProcHook::KHR_bind_memory2]) { + return BindImageMemory2KHR(device, bindInfoCount, pBindInfos); + } else { + Logger(device).Err(device, "VK_KHR_bind_memory2 not enabled. vkBindImageMemory2KHR not executed."); + return VK_SUCCESS; + } +} + VKAPI_ATTR VkResult checkedGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) { if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) { return GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities); @@ -101,24 +110,6 @@ VKAPI_ATTR VkResult checkedAcquireNextImage2KHR(VkDevice device, const VkAcquire } } -VKAPI_ATTR VkResult checkedGetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) { - if (GetData(device).hook_extensions[ProcHook::GOOGLE_display_timing]) { - return GetRefreshCycleDurationGOOGLE(device, swapchain, pDisplayTimingProperties); - } else { - Logger(device).Err(device, "VK_GOOGLE_display_timing not enabled. vkGetRefreshCycleDurationGOOGLE not executed."); - return VK_SUCCESS; - } -} - -VKAPI_ATTR VkResult checkedGetPastPresentationTimingGOOGLE(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings) { - if (GetData(device).hook_extensions[ProcHook::GOOGLE_display_timing]) { - return GetPastPresentationTimingGOOGLE(device, swapchain, pPresentationTimingCount, pPresentationTimings); - } else { - Logger(device).Err(device, "VK_GOOGLE_display_timing not enabled. vkGetPastPresentationTimingGOOGLE not executed."); - return VK_SUCCESS; - } -} - VKAPI_ATTR void checkedSetHdrMetadataEXT(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pMetadata) { if (GetData(device).hook_extensions[ProcHook::EXT_hdr_metadata]) { SetHdrMetadataEXT(device, swapchainCount, pSwapchains, pMetadata); @@ -136,11 +127,20 @@ VKAPI_ATTR VkResult checkedGetSwapchainStatusKHR(VkDevice device, VkSwapchainKHR } } -VKAPI_ATTR VkResult checkedBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfoKHR* pBindInfos) { - if (GetData(device).hook_extensions[ProcHook::KHR_bind_memory2]) { - return BindImageMemory2KHR(device, bindInfoCount, pBindInfos); +VKAPI_ATTR VkResult checkedGetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) { + if (GetData(device).hook_extensions[ProcHook::GOOGLE_display_timing]) { + return GetRefreshCycleDurationGOOGLE(device, swapchain, pDisplayTimingProperties); } else { - Logger(device).Err(device, "VK_KHR_bind_memory2 not enabled. vkBindImageMemory2KHR not executed."); + Logger(device).Err(device, "VK_GOOGLE_display_timing not enabled. vkGetRefreshCycleDurationGOOGLE not executed."); + return VK_SUCCESS; + } +} + +VKAPI_ATTR VkResult checkedGetPastPresentationTimingGOOGLE(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings) { + if (GetData(device).hook_extensions[ProcHook::GOOGLE_display_timing]) { + return GetPastPresentationTimingGOOGLE(device, swapchain, pPresentationTimingCount, pPresentationTimings); + } else { + Logger(device).Err(device, "VK_GOOGLE_display_timing not enabled. vkGetPastPresentationTimingGOOGLE not executed."); return VK_SUCCESS; } } @@ -516,12 +516,12 @@ bool InitDriverTable(VkInstance instance, INIT_PROC(true, instance, GetPhysicalDeviceProperties); INIT_PROC(true, instance, CreateDevice); INIT_PROC(true, instance, EnumerateDeviceExtensionProperties); - INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups); - INIT_PROC(false, instance, GetPhysicalDeviceProperties2); INIT_PROC_EXT(EXT_debug_report, true, instance, CreateDebugReportCallbackEXT); INIT_PROC_EXT(EXT_debug_report, true, instance, DestroyDebugReportCallbackEXT); INIT_PROC_EXT(EXT_debug_report, true, instance, DebugReportMessageEXT); + INIT_PROC(false, instance, GetPhysicalDeviceProperties2); INIT_PROC_EXT(KHR_get_physical_device_properties2, true, instance, GetPhysicalDeviceProperties2KHR); + INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups); // clang-format on return success; @@ -541,12 +541,12 @@ bool InitDriverTable(VkDevice dev, INIT_PROC(true, dev, DestroyImage); INIT_PROC(true, dev, AllocateCommandBuffers); INIT_PROC(false, dev, BindImageMemory2); + INIT_PROC_EXT(KHR_bind_memory2, true, dev, BindImageMemory2KHR); INIT_PROC(false, dev, GetDeviceQueue2); INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsageANDROID); - INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage2ANDROID); INIT_PROC_EXT(ANDROID_native_buffer, true, dev, AcquireImageANDROID); INIT_PROC_EXT(ANDROID_native_buffer, true, dev, QueueSignalReleaseImageANDROID); - INIT_PROC_EXT(KHR_bind_memory2, true, dev, BindImageMemory2KHR); + INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage2ANDROID); // clang-format on return success; diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h index c299549dae..79f070c72d 100644 --- a/vulkan/libvulkan/driver_gen.h +++ b/vulkan/libvulkan/driver_gen.h @@ -70,12 +70,12 @@ struct InstanceDriverTable { PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties; PFN_vkCreateDevice CreateDevice; PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties; - PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups; - PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2; PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT; PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT; PFN_vkDebugReportMessageEXT DebugReportMessageEXT; + PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2; PFN_vkGetPhysicalDeviceProperties2KHR GetPhysicalDeviceProperties2KHR; + PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups; // clang-format on }; @@ -88,12 +88,12 @@ struct DeviceDriverTable { PFN_vkDestroyImage DestroyImage; PFN_vkAllocateCommandBuffers AllocateCommandBuffers; PFN_vkBindImageMemory2 BindImageMemory2; + PFN_vkBindImageMemory2KHR BindImageMemory2KHR; PFN_vkGetDeviceQueue2 GetDeviceQueue2; PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID; - PFN_vkGetSwapchainGrallocUsage2ANDROID GetSwapchainGrallocUsage2ANDROID; PFN_vkAcquireImageANDROID AcquireImageANDROID; PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID; - PFN_vkBindImageMemory2KHR BindImageMemory2KHR; + PFN_vkGetSwapchainGrallocUsage2ANDROID GetSwapchainGrallocUsage2ANDROID; // clang-format on }; diff --git a/vulkan/nulldrv/null_driver.tmpl b/vulkan/nulldrv/null_driver.tmpl deleted file mode 100644 index 0f5301595c..0000000000 --- a/vulkan/nulldrv/null_driver.tmpl +++ /dev/null @@ -1,211 +0,0 @@ -{{/* - * Copyright 2015 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 "../api/templates/vulkan_common.tmpl"}} -{{Global "clang-format" (Strings "clang-format" "-style=file")}} -{{Macro "DefineGlobals" $}} -{{$ | Macro "null_driver_gen.h" | Format (Global "clang-format") | Write "null_driver_gen.h" }} -{{$ | Macro "null_driver_gen.cpp" | Format (Global "clang-format") | Write "null_driver_gen.cpp"}} - - -{{/* -------------------------------------------------------------------------------- - null_driver_gen.h -------------------------------------------------------------------------------- -*/}} -{{define "null_driver_gen.h"}} -/* -•* Copyright 2015 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. -•*/ -¶ -// WARNING: This file is generated. See ../README.md for instructions. -¶ -#ifndef NULLDRV_NULL_DRIVER_H -#define NULLDRV_NULL_DRIVER_H 1 -¶ -#include -#include -¶ -namespace null_driver {« -¶ -PFN_vkVoidFunction GetGlobalProcAddr(const char* name); -PFN_vkVoidFunction GetInstanceProcAddr(const char* name); -¶ -// clang-format off - {{range $f := AllCommands $}} - {{if (Macro "IsDriverFunction" $f)}} -VKAPI_ATTR {{Node "Type" $f.Return}} {{Macro "BaseName" $f}}({{Macro "Parameters" $f}}); - {{end}} - {{end}} -VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage); -VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence); -VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd); -// clang-format on -¶ -»} // namespace null_driver -¶ -#endif // NULLDRV_NULL_DRIVER_H -¶{{end}} - - -{{/* -------------------------------------------------------------------------------- - null_driver_gen.cpp -------------------------------------------------------------------------------- -*/}} -{{define "null_driver_gen.cpp"}} -/* -•* Copyright 2015 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. -•*/ -¶ -// WARNING: This file is generated. See ../README.md for instructions. -¶ -#include -¶ -#include "null_driver_gen.h" -¶ -using namespace null_driver; -¶ -namespace { -¶ -struct NameProc { - const char* name; - PFN_vkVoidFunction proc; -}; -¶ -PFN_vkVoidFunction Lookup(const char* name, - const NameProc* begin, - const NameProc* end) { - const auto& entry = std::lower_bound( - begin, end, name, - [](const NameProc& e, const char* n) { return strcmp(e.name, n) < 0; }); - if (entry == end || strcmp(entry->name, name) != 0) - return nullptr; - return entry->proc; -} -¶ -template -PFN_vkVoidFunction Lookup(const char* name, const NameProc (&procs)[N]) { - return Lookup(name, procs, procs + N); -} -¶ -const NameProc kGlobalProcs[] = {« - // clang-format off - {{range $f := SortBy (AllCommands $) "FunctionName"}} - {{if and (Macro "IsDriverFunction" $f) (eq (Macro "Vtbl" $f) "Global")}} - {"{{$f.Name}}", reinterpret_cast(§ - static_cast<{{Macro "FunctionPtrName" $f}}>(§ - {{Macro "BaseName" $f}}))}, - {{end}} - {{end}} - // clang-format on -»}; -¶ -const NameProc kInstanceProcs[] = {« - // clang-format off - {{range $f := SortBy (AllCommands $) "FunctionName"}} - {{if (Macro "IsDriverFunction" $f)}} - {"{{$f.Name}}", reinterpret_cast(§ - static_cast<{{Macro "FunctionPtrName" $f}}>(§ - {{Macro "BaseName" $f}}))}, - {{end}} - {{end}} - // clang-format on -»}; -¶ -} // namespace -¶ -namespace null_driver { -¶ -PFN_vkVoidFunction GetGlobalProcAddr(const char* name) { - return Lookup(name, kGlobalProcs); -} -¶ -PFN_vkVoidFunction GetInstanceProcAddr(const char* name) {« - return Lookup(name, kInstanceProcs); -»} -¶ -} // namespace null_driver -¶ -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits a function name without the "vk" prefix. -------------------------------------------------------------------------------- -*/}} -{{define "BaseName"}} - {{AssertType $ "Function"}} - {{TrimPrefix "vk" $.Name}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Emits 'true' if the API function is implemented by the driver. ------------------------------------------------------------------------------- -*/}} -{{define "IsDriverFunction"}} - {{AssertType $ "Function"}} - - {{if not (GetAnnotation $ "pfn")}} - {{$ext := GetAnnotation $ "extension"}} - {{if $ext}} - {{Macro "IsDriverExtension" $ext}} - {{else}} - true - {{end}} - {{end}} -{{end}} - - -{{/* ------------------------------------------------------------------------------- - Reports whether an extension is implemented by the driver. ------------------------------------------------------------------------------- -*/}} -{{define "IsDriverExtension"}} - {{$ext := index $.Arguments 0}} - {{ if eq $ext "VK_ANDROID_native_buffer"}}true - {{else if eq $ext "VK_EXT_debug_report"}}true - {{else if eq $ext "VK_KHR_get_physical_device_properties2"}}true - {{end}} -{{end}} diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp index b8d7d2b643..7c9b0c05c7 100644 --- a/vulkan/nulldrv/null_driver_gen.cpp +++ b/vulkan/nulldrv/null_driver_gen.cpp @@ -16,10 +16,10 @@ // WARNING: This file is generated. See ../README.md for instructions. -#include - #include "null_driver_gen.h" +#include + using namespace null_driver; namespace { diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h index c6ad537cb8..70ef340bcf 100644 --- a/vulkan/nulldrv/null_driver_gen.h +++ b/vulkan/nulldrv/null_driver_gen.h @@ -41,6 +41,7 @@ VKAPI_ATTR void GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevic VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties); VKAPI_ATTR VkResult CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); VKAPI_ATTR void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator); +VKAPI_ATTR VkResult EnumerateInstanceVersion(uint32_t* pApiVersion); VKAPI_ATTR VkResult EnumerateInstanceLayerProperties(uint32_t* pPropertyCount, VkLayerProperties* pProperties); VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties); VKAPI_ATTR VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties); @@ -165,48 +166,47 @@ VKAPI_ATTR void CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRender VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents); VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer); VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers); -VKAPI_ATTR VkResult EnumerateInstanceVersion(uint32_t* pApiVersion); -VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); -VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); -VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); -VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask); -VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); -VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); -VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); -VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); -VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +VKAPI_ATTR VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); +VKAPI_ATTR void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); +VKAPI_ATTR void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); +VKAPI_ATTR void GetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures); VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); +VKAPI_ATTR void GetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties); VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); +VKAPI_ATTR void GetPhysicalDeviceFormatProperties2KHR(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties); VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); +VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties); VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); +VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties); VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); +VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties); VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); +VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties); VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); -VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue); -VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); -VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); +VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); +VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); +VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); +VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties); +VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures); +VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos); +VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos); +VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask); +VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate); VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator); VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData); -VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties); -VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties); -VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties); +VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements); +VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements); +VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion); +VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator); +VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue); VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport); -VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int32_t* grallocUsage); -VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage); +VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage); VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence); VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd); -VKAPI_ATTR VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback); -VKAPI_ATTR void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator); -VKAPI_ATTR void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage); -VKAPI_ATTR void GetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR* pFeatures); -VKAPI_ATTR void GetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2KHR* pProperties); -VKAPI_ATTR void GetPhysicalDeviceFormatProperties2KHR(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2KHR* pFormatProperties); -VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, VkImageFormatProperties2KHR* pImageFormatProperties); -VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR* pQueueFamilyProperties); -VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties); -VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2KHR* pProperties); +VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage); VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage); VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence); VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd); diff --git a/vulkan/scripts/api_generator.py b/vulkan/scripts/api_generator.py index 05dc9957b0..a0c648cc90 100644 --- a/vulkan/scripts/api_generator.py +++ b/vulkan/scripts/api_generator.py @@ -63,7 +63,7 @@ bool InitDispatchTable( #endif // LIBVULKAN_API_GEN_H """ - genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen2.h') + genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen.h') with open(genfile, 'w') as f: instanceDispatchTableEntries = [] deviceDispatchTableEntries = [] @@ -93,6 +93,7 @@ bool InitDispatchTable( f.write (tail) f.close() + gencom.runClangFormat(genfile) def defineInitProc(name, f): f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n') @@ -233,7 +234,7 @@ def apiDispatch(functionName, f): def api_gencpp(): - genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen2.cpp') + genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen.cpp') header = """#include #include @@ -341,4 +342,5 @@ namespace api {\n\n""") f.write ('}\n\n') gencom.clang_on(f, 0) - + f.close() + gencom.runClangFormat(genfile) diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py index 92326caf46..04d9f239e7 100644 --- a/vulkan/scripts/driver_generator.py +++ b/vulkan/scripts/driver_generator.py @@ -132,7 +132,7 @@ def driver_genh(): namespace vulkan { namespace driver {\n\n""" - genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen2.h') + genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen.h') with open(genfile, 'w') as f: f.write (gencom.copyright) f.write (gencom.warning) @@ -166,6 +166,8 @@ bool InitDriverTable(VkDevice dev, } // namespace vulkan #endif // LIBVULKAN_DRIVER_TABLE_H\n""") + f.close() + gencom.runClangFormat(genfile) def isIntercepted(functionName): switchCase = { @@ -317,7 +319,7 @@ namespace { // clang-format off\n\n""" - genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen2.cpp') + genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen.cpp') with open(genfile, 'w') as f: f.write (gencom.copyright) @@ -390,4 +392,5 @@ namespace { f.write ('\n' + gencom.clang_off_spaces + 'return success;\n') f.write ('}\n\n} // namespace driver\n} // namespace vulkan\n\n') gencom.clang_on(f, 0) - + f.close() + gencom.runClangFormat(genfile) diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py index 163fba3462..d9f97e1760 100644 --- a/vulkan/scripts/generator_common.py +++ b/vulkan/scripts/generator_common.py @@ -17,6 +17,8 @@ # This script provides the common functions for generating the # vulkan framework directly from the vulkan registry (vk.xml). +from subprocess import check_call + copyright = """/* * Copyright 2016 The Android Open Source Project * @@ -75,6 +77,10 @@ exportedExtensions = [ 'VK_ANDROID_external_memory_android_hardware_buffer' ] +def runClangFormat(args): + clang_call = ["clang-format", "--style", "file", "-i", args] + check_call (clang_call) + def isExtensionInternal(extensionName): if extensionName == 'VK_ANDROID_native_buffer': return True diff --git a/vulkan/scripts/null_generator.py b/vulkan/scripts/null_generator.py index fcbaf393a5..ee8762e3b4 100644 --- a/vulkan/scripts/null_generator.py +++ b/vulkan/scripts/null_generator.py @@ -67,7 +67,7 @@ PFN_vkVoidFunction GetGlobalProcAddr(const char* name); PFN_vkVoidFunction GetInstanceProcAddr(const char* name); """ - genfile = os.path.join(os.path.dirname(__file__),'..','nulldrv','null_driver_gen2.h') + genfile = os.path.join(os.path.dirname(__file__),'..','nulldrv','null_driver_gen.h') with open(genfile, 'w') as f: f.write (copyright) f.write (gencom.warning) @@ -85,6 +85,8 @@ VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitS f.write ('\n} // namespace null_driver\n') f.write ('\n#endif // NULLDRV_NULL_DRIVER_H\n') + f.close() + gencom.runClangFormat(genfile) def null_driver_gencpp(): header = """#include @@ -118,7 +120,7 @@ PFN_vkVoidFunction Lookup(const char* name, const NameProc (&procs)[N]) { const NameProc kGlobalProcs[] = { """ - genfile = os.path.join(os.path.dirname(__file__),'..','nulldrv','null_driver_gen2.cpp') + genfile = os.path.join(os.path.dirname(__file__),'..','nulldrv','null_driver_gen.cpp') with open(genfile, 'w') as f: f.write (copyright) f.write (gencom.warning) @@ -151,4 +153,6 @@ PFN_vkVoidFunction GetInstanceProcAddr(const char* name) { } } // namespace null_driver\n""") + f.close() + gencom.runClangFormat(genfile) -- GitLab From 6fe2c17ee04210489f6f561755021cbd59153176 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 12 Jul 2019 12:37:57 -0700 Subject: [PATCH 0077/1255] SurfaceFlinger: add display power state timer Coming out of DOZE mode might result in unstable HWVsync which may confuse FPS detection logic to set the desired refresh rate. To mitigate that, this change introduces a new timer that will provide a grace period when coming out of DOZE while in this grace period refresh rate will stay in PERFORMANCE. Test: Toggle DOZE by hitting the power button and collect systrace Bug: 135550670 Change-Id: Ib8ec3c9550336d691dd3868405d20b98aa983302 --- .../surfaceflinger/Scheduler/Scheduler.cpp | 79 ++++++++++++------- services/surfaceflinger/Scheduler/Scheduler.h | 22 +++++- services/surfaceflinger/SurfaceFlinger.cpp | 1 + .../SurfaceFlingerProperties.cpp | 8 ++ .../surfaceflinger/SurfaceFlingerProperties.h | 2 + .../sysprop/SurfaceFlingerProperties.sysprop | 12 +++ .../sysprop/api/system-current.txt | 1 + 7 files changed, 93 insertions(+), 32 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 27f42d23a3..9435193d05 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -76,6 +76,7 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, mSupportKernelTimer = support_kernel_idle_timer(false); mSetTouchTimerMs = set_touch_timer_ms(0); + mSetDisplayPowerTimerMs = set_display_power_timer_ms(0); char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.set_idle_timer_ms", value, "0"); @@ -105,10 +106,19 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, [this] { expiredTouchTimerCallback(); }); mTouchTimer->start(); } + + if (mSetDisplayPowerTimerMs > 0) { + mDisplayPowerTimer = std::make_unique( + std::chrono::milliseconds(mSetDisplayPowerTimerMs), + [this] { resetDisplayPowerTimerCallback(); }, + [this] { expiredDisplayPowerTimerCallback(); }); + mDisplayPowerTimer->start(); + } } Scheduler::~Scheduler() { // Ensure the OneShotTimer threads are joined before we start destroying state. + mDisplayPowerTimer.reset(); mTouchTimer.reset(); mIdleTimer.reset(); } @@ -414,8 +424,23 @@ void Scheduler::notifyTouchEvent() { mLayerHistory.clearHistory(); } +void Scheduler::setDisplayPowerState(bool normal) { + { + std::lock_guard lock(mFeatureStateLock); + mIsDisplayPowerStateNormal = normal; + } + + if (mDisplayPowerTimer) { + mDisplayPowerTimer->reset(); + } + + // Display Power event will boost the refresh rate to performance. + // Clear Layer History to get fresh FPS detection + mLayerHistory.clearHistory(); +} + void Scheduler::resetTimerCallback() { - timerChangeRefreshRate(IdleTimerState::RESET); + handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::RESET, false); ATRACE_INT("ExpiredIdleTimer", 0); } @@ -428,22 +453,30 @@ void Scheduler::resetKernelTimerCallback() { } void Scheduler::expiredTimerCallback() { - timerChangeRefreshRate(IdleTimerState::EXPIRED); + handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::EXPIRED, false); ATRACE_INT("ExpiredIdleTimer", 1); } void Scheduler::resetTouchTimerCallback() { - // We do not notify the applications about config changes when idle timer is reset. - touchChangeRefreshRate(TouchState::ACTIVE); + handleTimerStateChanged(&mCurrentTouchState, TouchState::ACTIVE, true); ATRACE_INT("TouchState", 1); } void Scheduler::expiredTouchTimerCallback() { - // We do not notify the applications about config changes when idle timer expires. - touchChangeRefreshRate(TouchState::INACTIVE); + handleTimerStateChanged(&mCurrentTouchState, TouchState::INACTIVE, true); ATRACE_INT("TouchState", 0); } +void Scheduler::resetDisplayPowerTimerCallback() { + handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::RESET, true); + ATRACE_INT("ExpiredDisplayPowerTimer", 0); +} + +void Scheduler::expiredDisplayPowerTimerCallback() { + handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::EXPIRED, true); + ATRACE_INT("ExpiredDisplayPowerTimer", 1); +} + void Scheduler::expiredKernelTimerCallback() { ATRACE_INT("ExpiredKernelIdleTimer", 1); // Disable HW Vsync if the timer expired, as we don't need it @@ -458,39 +491,23 @@ std::string Scheduler::doDump() { return stream.str(); } -void Scheduler::timerChangeRefreshRate(IdleTimerState idleTimerState) { - RefreshRateType newRefreshRateType; - { - std::lock_guard lock(mFeatureStateLock); - if (mCurrentIdleTimerState == idleTimerState) { - return; - } - mCurrentIdleTimerState = idleTimerState; - newRefreshRateType = calculateRefreshRateType(); - if (mRefreshRateType == newRefreshRateType) { - return; - } - mRefreshRateType = newRefreshRateType; - } - changeRefreshRate(newRefreshRateType, ConfigEvent::None); -} - -void Scheduler::touchChangeRefreshRate(TouchState touchState) { +template +void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) { ConfigEvent event = ConfigEvent::None; RefreshRateType newRefreshRateType; { std::lock_guard lock(mFeatureStateLock); - if (mCurrentTouchState == touchState) { + if (*currentState == newState) { return; } - mCurrentTouchState = touchState; + *currentState = newState; newRefreshRateType = calculateRefreshRateType(); if (mRefreshRateType == newRefreshRateType) { return; } mRefreshRateType = newRefreshRateType; - // Send an event in case that content detection is on as touch has a higher priority - if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) { + if (eventOnContentDetection && + mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) { event = ConfigEvent::Changed; } } @@ -503,6 +520,12 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { return RefreshRateType::DEFAULT; } + // 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 (!mIsDisplayPowerStateNormal || mDisplayPowerTimerState == DisplayPowerTimerState::RESET) { + return RefreshRateType::PERFORMANCE; + } + // As long as touch is active we want to be in performance mode if (mCurrentTouchState == TouchState::ACTIVE) { return RefreshRateType::PERFORMANCE; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index a30776059f..33f96b6f79 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -177,6 +177,9 @@ public: // Function that resets the touch timer. void notifyTouchEvent(); + // Function that sets whether display power mode is normal or not. + void setDisplayPowerState(bool normal); + // Returns relevant information about Scheduler for dumpsys purposes. std::string doDump(); @@ -197,6 +200,7 @@ private: enum class ContentFeatureState { CONTENT_DETECTION_ON, CONTENT_DETECTION_OFF }; enum class IdleTimerState { EXPIRED, RESET }; enum class TouchState { INACTIVE, ACTIVE }; + enum class DisplayPowerTimerState { EXPIRED, RESET }; // Creates a connection on the given EventThread and forwards the given callbacks. sp createConnectionInternal(EventThread*, ResyncCallback&&, @@ -221,12 +225,15 @@ private: void resetTouchTimerCallback(); // Function that is called when the touch timer expires. void expiredTouchTimerCallback(); + // Function that is called when the display power timer resets. + void resetDisplayPowerTimerCallback(); + // Function that is called when the display power timer expires. + void expiredDisplayPowerTimerCallback(); // Sets vsync period. void setVsyncPeriod(const nsecs_t period); - // Idle timer feature's function to change the refresh rate. - void timerChangeRefreshRate(IdleTimerState idleTimerState); - // Touch timer feature's function to change the refresh rate. - void touchChangeRefreshRate(TouchState touchState); + // handles various timer features to change the refresh rate. + template + void handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection); // Calculate the new refresh rate type RefreshRateType calculateRefreshRateType() REQUIRES(mFeatureStateLock); // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters. @@ -282,6 +289,10 @@ private: int64_t mSetTouchTimerMs = 0; std::unique_ptr mTouchTimer; + // Timer used to monitor display power mode. + int64_t mSetDisplayPowerTimerMs = 0; + std::unique_ptr mDisplayPowerTimer; + std::mutex mCallbackLock; ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock); GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock); @@ -293,9 +304,12 @@ private: ContentFeatureState::CONTENT_DETECTION_OFF; IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET; TouchState mCurrentTouchState GUARDED_BY(mFeatureStateLock) = TouchState::INACTIVE; + DisplayPowerTimerState mDisplayPowerTimerState GUARDED_BY(mFeatureStateLock) = + DisplayPowerTimerState::EXPIRED; uint32_t mContentRefreshRate GUARDED_BY(mFeatureStateLock); RefreshRateType mRefreshRateType GUARDED_BY(mFeatureStateLock); bool mIsHDRContent GUARDED_BY(mFeatureStateLock) = false; + bool mIsDisplayPowerStateNormal GUARDED_BY(mFeatureStateLock) = true; const scheduler::RefreshRateConfigs& mRefreshRateConfigs; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f1e3971811..9333de3202 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4542,6 +4542,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, int if (display->isPrimary()) { mTimeStats->setPowerMode(mode); mRefreshRateStats.setPowerMode(mode); + mScheduler->setDisplayPowerState(mode == HWC_POWER_MODE_NORMAL); } ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str()); diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 237208d39f..768074a6cd 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -242,6 +242,14 @@ int32_t set_touch_timer_ms(int32_t defaultValue) { return defaultValue; } +int32_t set_display_power_timer_ms(int32_t defaultValue) { + auto temp = SurfaceFlingerProperties::set_display_power_timer_ms(); + if (temp.has_value()) { + return *temp; + } + return defaultValue; +} + bool use_smart_90_for_video(bool defaultValue) { auto temp = SurfaceFlingerProperties::use_smart_90_for_video(); if (temp.has_value()) { diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index b5418d6538..5f88322f71 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -77,6 +77,8 @@ int32_t set_idle_timer_ms(int32_t defaultValue); int32_t set_touch_timer_ms(int32_t defaultValue); +int32_t set_display_power_timer_ms(int32_t defaultValue); + bool use_smart_90_for_video(bool defaultValue); bool enable_protected_contents(bool defaultValue); diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index 565df9a8f4..56ab4e3f33 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -323,6 +323,18 @@ prop { prop_name: "ro.surface_flinger.set_touch_timer_ms" } +# setDisplayPowerTimerMs indicates what is considered a timeout in milliseconds for Scheduler. +# This value is used by the Scheduler to trigger display power inactivity callbacks that will +# keep the display in peak refresh rate as long as display power is not in normal mode. +# Setting this property to 0 means there is no timer. +prop { + api_name: "set_display_power_timer_ms" + type: Integer + scope: System + access: Readonly + prop_name: "ro.surface_flinger.set_display_power_timer_ms" +} + # useSmart90ForVideo indicates whether Scheduler should detect content FPS, and try to adjust the # screen refresh rate based on that. prop { diff --git a/services/surfaceflinger/sysprop/api/system-current.txt b/services/surfaceflinger/sysprop/api/system-current.txt index 89323c2ad0..79854b36a2 100644 --- a/services/surfaceflinger/sysprop/api/system-current.txt +++ b/services/surfaceflinger/sysprop/api/system-current.txt @@ -18,6 +18,7 @@ package android.sysprop { method public static java.util.Optional present_time_offset_from_vsync_ns(); method public static java.util.Optional primary_display_orientation(); method public static java.util.Optional running_without_sync_framework(); + method public static java.util.Optional set_display_power_timer_ms(); method public static java.util.Optional set_idle_timer_ms(); method public static java.util.Optional set_touch_timer_ms(); method public static java.util.Optional start_graphics_allocator_service(); -- GitLab From ef44c2d08f0a7c04511b7fd027e2528919e15658 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 15 Jul 2019 15:27:22 -0700 Subject: [PATCH 0078/1255] [RenderEngine] Add cache contents to dumpsys We've had some high EGL utilization attributed to SurfaceFlinger recently, so adding info to dumpsys to hopefully catch a leak. Bug: 137514000 Test: dumpsys Change-Id: I22cf9eb01162d341c44dbe1440f74865dbf960fb --- libs/renderengine/gl/GLESRenderEngine.cpp | 21 ++++++++++++++++++++- libs/renderengine/gl/GLESRenderEngine.h | 15 +++++++++++---- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 6e7ec336e9..bf22e5cd60 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -837,6 +837,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer bool useFramebufferCache) { sp graphicBuffer = GraphicBuffer::from(nativeBuffer); if (useFramebufferCache) { + std::lock_guard lock(mFramebufferImageCacheMutex); for (const auto& image : mFramebufferImageCache) { if (image.first == graphicBuffer->getId()) { return image.second; @@ -852,6 +853,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer nativeBuffer, attributes); if (useFramebufferCache) { if (image != EGL_NO_IMAGE_KHR) { + std::lock_guard lock(mFramebufferImageCacheMutex); if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) { EGLImageKHR expired = mFramebufferImageCache.front().second; mFramebufferImageCache.pop_front(); @@ -1266,6 +1268,23 @@ void GLESRenderEngine::dump(std::string& result) { StringAppendF(&result, "RenderEngine last dataspace conversion: (%s) to (%s)\n", dataspaceDetails(static_cast(mDataSpace)).c_str(), dataspaceDetails(static_cast(mOutputDataSpace)).c_str()); + { + std::lock_guard lock(mRenderingMutex); + StringAppendF(&result, "RenderEngine image cache size: %zu\n", mImageCache.size()); + StringAppendF(&result, "Dumping buffer ids...\n"); + for (const auto& [id, unused] : mImageCache) { + StringAppendF(&result, "0x%" PRIx64 "\n", id); + } + } + { + std::lock_guard lock(mFramebufferImageCacheMutex); + StringAppendF(&result, "RenderEngine framebuffer image cache size: %zu\n", + mFramebufferImageCache.size()); + StringAppendF(&result, "Dumping buffer ids...\n"); + for (const auto& [id, unused] : mFramebufferImageCache) { + StringAppendF(&result, "0x%" PRIx64 "\n", id); + } + } } GLESRenderEngine::GlesVersion GLESRenderEngine::parseGlesVersion(const char* str) { @@ -1392,7 +1411,7 @@ bool GLESRenderEngine::isImageCachedForTesting(uint64_t bufferId) { } bool GLESRenderEngine::isFramebufferImageCachedForTesting(uint64_t bufferId) { - std::lock_guard lock(mRenderingMutex); + std::lock_guard lock(mFramebufferImageCacheMutex); return std::any_of(mFramebufferImageCache.cbegin(), mFramebufferImageCache.cend(), [=](std::pair image) { return image.first == bufferId; diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 70b704abce..2eebf9af85 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -79,17 +79,20 @@ public: EGLDisplay getEGLDisplay() const { return mEGLDisplay; } // Creates an output image for rendering to EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected, - bool useFramebufferCache); + bool useFramebufferCache) + EXCLUDES(mFramebufferImageCacheMutex); // Test-only methods // Returns true iff mImageCache contains an image keyed by bufferId bool isImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex); // Returns true iff mFramebufferImageCache contains an image keyed by bufferId - bool isFramebufferImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex); + bool isFramebufferImageCachedForTesting(uint64_t bufferId) + EXCLUDES(mFramebufferImageCacheMutex); protected: Framebuffer* getFramebufferForDrawing() override; - void dump(std::string& result) override; + void dump(std::string& result) override EXCLUDES(mRenderingMutex) + EXCLUDES(mFramebufferImageCacheMutex); size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; @@ -191,7 +194,11 @@ private: uint32_t mFramebufferImageCacheSize = 0; // Cache of output images, keyed by corresponding GraphicBuffer ID. - std::deque> mFramebufferImageCache; + std::deque> mFramebufferImageCache + GUARDED_BY(mFramebufferImageCacheMutex); + // The only reason why we have this mutex is so that we don't segfault when + // dumping info. + std::mutex mFramebufferImageCacheMutex; // Current dataspace of layer being rendered ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN; -- GitLab From fd712afb49fd1a44d3270e090876b8b9faf8388f Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 16 Jul 2019 08:44:16 -0700 Subject: [PATCH 0079/1255] Fix whitespace errors Change-Id: I2ac1f097aa84a2a5241fb7521c869b7416265ca0 --- cmds/service/service.cpp | 128 +++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp index d5dc6b741d..543357c564 100644 --- a/cmds/service/service.cpp +++ b/cmds/service/service.cpp @@ -70,7 +70,7 @@ int main(int argc, char* const argv[]) { bool wantsUsage = false; int result = 0; - + while (1) { int ic = getopt(argc, argv, "h?"); if (ic < 0) @@ -97,7 +97,7 @@ int main(int argc, char* const argv[]) aerr << "service: Unable to get default service manager!" << endl; return 20; } - + if (optind >= argc) { wantsUsage = true; } else if (!wantsUsage) { @@ -119,8 +119,8 @@ int main(int argc, char* const argv[]) for (unsigned i = 0; i < services.size(); i++) { String16 name = services[i]; sp service = sm->checkService(name); - aout << i - << "\t" << good_old_string(name) + aout << i + << "\t" << good_old_string(name) << ": [" << good_old_string(get_interface_name(service)) << "]" << endl; } @@ -188,68 +188,68 @@ int main(int argc, char* const argv[]) optind++; data.writeStrongBinder(nullptr); } else if (strcmp(argv[optind], "intent") == 0) { - - char* action = nullptr; - char* dataArg = nullptr; - char* type = nullptr; - int launchFlags = 0; - char* component = nullptr; - int categoryCount = 0; - char* categories[16]; - - char* context1 = nullptr; - + + char* action = nullptr; + char* dataArg = nullptr; + char* type = nullptr; + int launchFlags = 0; + char* component = nullptr; + int categoryCount = 0; + char* categories[16]; + + char* context1 = nullptr; + optind++; - - while (optind < argc) - { - char* key = strtok_r(argv[optind], "=", &context1); - char* value = strtok_r(nullptr, "=", &context1); - + + while (optind < argc) + { + char* key = strtok_r(argv[optind], "=", &context1); + char* value = strtok_r(nullptr, "=", &context1); + // we have reached the end of the XXX=XXX args. if (key == nullptr) break; - - if (strcmp(key, "action") == 0) - { - action = value; - } - else if (strcmp(key, "data") == 0) - { - dataArg = value; - } - else if (strcmp(key, "type") == 0) - { - type = value; - } - else if (strcmp(key, "launchFlags") == 0) - { - launchFlags = atoi(value); - } - else if (strcmp(key, "component") == 0) - { - component = value; - } - else if (strcmp(key, "categories") == 0) - { - char* context2 = nullptr; - categories[categoryCount] = strtok_r(value, ",", &context2); - - while (categories[categoryCount] != nullptr) - { - categoryCount++; - categories[categoryCount] = strtok_r(nullptr, ",", &context2); - } - } - + + if (strcmp(key, "action") == 0) + { + action = value; + } + else if (strcmp(key, "data") == 0) + { + dataArg = value; + } + else if (strcmp(key, "type") == 0) + { + type = value; + } + else if (strcmp(key, "launchFlags") == 0) + { + launchFlags = atoi(value); + } + else if (strcmp(key, "component") == 0) + { + component = value; + } + else if (strcmp(key, "categories") == 0) + { + char* context2 = nullptr; + categories[categoryCount] = strtok_r(value, ",", &context2); + + while (categories[categoryCount] != nullptr) + { + categoryCount++; + categories[categoryCount] = strtok_r(nullptr, ",", &context2); + } + } + optind++; - } - + } + writeString16(data, action); writeString16(data, dataArg); writeString16(data, type); - data.writeInt32(launchFlags); + data.writeInt32(launchFlags); writeString16(data, component); - + if (categoryCount > 0) { data.writeInt32(categoryCount); @@ -261,10 +261,10 @@ int main(int argc, char* const argv[]) else { data.writeInt32(0); - } - + } + // for now just set the extra field to be null. - data.writeInt32(-1); + data.writeInt32(-1); } else { aerr << "service: unknown option " << argv[optind] << endl; wantsUsage = true; @@ -272,7 +272,7 @@ int main(int argc, char* const argv[]) break; } } - + service->transact(code, data, &reply); aout << "Result: " << reply << endl; } else { @@ -295,7 +295,7 @@ int main(int argc, char* const argv[]) result = 10; } } - + if (wantsUsage) { aout << "Usage: service [-h|-?]\n" " service list\n" @@ -311,7 +311,7 @@ int main(int argc, char* const argv[]) // " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n"; return result; } - + return result; } -- GitLab From 996bc421ea90965e384c947f5a68394afb95bd88 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 16 Jul 2019 14:15:33 -0700 Subject: [PATCH 0080/1255] Properly merge flags when merging transactions Test: atest SurfaceFlinger_test Change-Id: Ib1446c5afe00fd2588f7682f33cbbc6d6eb6a1ea --- libs/gui/LayerState.cpp | 5 ++-- .../surfaceflinger/tests/Transaction_test.cpp | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 6066421faf..aa07cbe0ab 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -267,8 +267,9 @@ void layer_state_t::merge(const layer_state_t& other) { } if (other.what & eFlagsChanged) { what |= eFlagsChanged; - flags = other.flags; - mask = other.mask; + flags &= ~other.mask; + flags |= (other.flags & other.mask); + mask |= other.mask; } if (other.what & eLayerStackChanged) { what |= eLayerStackChanged; diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index d5f65348d8..aed7b40872 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -4427,6 +4427,30 @@ TEST_F(LayerUpdateTest, MergingTransactions) { } } +TEST_F(LayerUpdateTest, MergingTransactionFlags) { + Transaction().hide(mFGSurfaceControl).apply(); + std::unique_ptr sc; + { + SCOPED_TRACE("before merge"); + ScreenCapture::captureScreen(&sc); + sc->expectBGColor(0, 12); + sc->expectBGColor(75, 75); + sc->expectBGColor(145, 145); + } + + Transaction t1, t2; + t1.show(mFGSurfaceControl); + t2.setFlags(mFGSurfaceControl, 0 /* flags */, layer_state_t::eLayerSecure /* mask */); + t1.merge(std::move(t2)); + t1.apply(); + + { + SCOPED_TRACE("after merge"); + ScreenCapture::captureScreen(&sc); + sc->expectFGColor(75, 75); + } +} + class ChildLayerTest : public LayerUpdateTest { protected: void SetUp() override { -- GitLab From f03652dd9df88182518a7046cf542076ea10d5ea Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 16 Jul 2019 17:56:56 -0700 Subject: [PATCH 0081/1255] Store layer state changes by layer handle in Transaction objects Layer state changes are stored in an unordered map with the surface control as the key and state changes as the value. This causes a few problems when merging the transactions. If transactions contained state changes from a cloned surface control then it will not be merged. This will cause ordering issues when the transaction is applied since the changes are stored in and unordered map. When parcelling transactions, a new surface control is created from the existing one and this surfaces the problem more frequently. Instead we store the layer changes by the layer handle which is consistent across processes. Test: atest SurfaceFlinger_test Test: go/wm-smoke Change-Id: I2e041d70ae24db2c1f26ada003532ad97f667167 --- libs/gui/LayerState.cpp | 2 - libs/gui/SurfaceComposerClient.cpp | 40 ++++++++++---------- libs/gui/SurfaceControl.cpp | 4 +- libs/gui/include/gui/LayerState.h | 3 -- libs/gui/include/gui/SurfaceComposerClient.h | 25 ++++++------ services/surfaceflinger/SurfaceFlinger.cpp | 28 +------------- services/surfaceflinger/SurfaceFlinger.h | 1 - 7 files changed, 36 insertions(+), 67 deletions(-) diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 6066421faf..a09ceae7c6 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -169,12 +169,10 @@ status_t layer_state_t::read(const Parcel& input) } status_t ComposerState::write(Parcel& output) const { - output.writeStrongBinder(IInterface::asBinder(client)); return state.write(output); } status_t ComposerState::read(const Parcel& input) { - client = interface_cast(input.readStrongBinder()); return state.read(input); } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index c59fddfb9d..de36511a5b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -202,7 +202,8 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener * callbackIds to generate one super map that contains all the sp to sp * that could possibly exist for the callbacks. */ - std::unordered_map, sp, IBinderHash> surfaceControls; + std::unordered_map, sp, SurfaceComposerClient::IBinderHash> + surfaceControls; for (const auto& transactionStats : listenerStats.transactionStats) { for (auto callbackId : transactionStats.callbackIds) { auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId]; @@ -365,16 +366,16 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel if (count > parcel->dataSize()) { return BAD_VALUE; } - std::unordered_map, ComposerState, SCHash> composerStates; + std::unordered_map, ComposerState, IBinderHash> composerStates; composerStates.reserve(count); for (size_t i = 0; i < count; i++) { - sp surfaceControl = SurfaceControl::readFromParcel(parcel); + sp surfaceControlHandle = parcel->readStrongBinder(); ComposerState composerState; if (composerState.read(*parcel) == BAD_VALUE) { return BAD_VALUE; } - composerStates[surfaceControl] = composerState; + composerStates[surfaceControlHandle] = composerState; } InputWindowCommands inputWindowCommands; @@ -408,8 +409,8 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const } parcel->writeUint32(static_cast(mComposerStates.size())); - for (auto const& [surfaceControl, composerState] : mComposerStates) { - surfaceControl->writeToParcel(parcel); + for (auto const& [surfaceHandle, composerState] : mComposerStates) { + parcel->writeStrongBinder(surfaceHandle); composerState.write(*parcel); } @@ -418,11 +419,11 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { - for (auto const& kv : other.mComposerStates) { - if (mComposerStates.count(kv.first) == 0) { - mComposerStates[kv.first] = kv.second; + for (auto const& [surfaceHandle, composerState] : other.mComposerStates) { + if (mComposerStates.count(surfaceHandle) == 0) { + mComposerStates[surfaceHandle] = composerState; } else { - mComposerStates[kv.first].state.merge(kv.second.state); + mComposerStates[surfaceHandle].state.merge(composerState.state); } } @@ -465,14 +466,12 @@ void SurfaceComposerClient::Transaction::clear() { mDesiredPresentTime = -1; } -void SurfaceComposerClient::doDropReferenceTransaction(const sp& handle, - const sp& client) { +void SurfaceComposerClient::doDropReferenceTransaction(const sp& handle) { sp sf(ComposerService::getComposerService()); Vector composerStates; Vector displayStates; ComposerState s; - s.client = client; s.state.surface = handle; s.state.what |= layer_state_t::eReparent; s.state.parentHandleForChild = nullptr; @@ -499,8 +498,8 @@ void SurfaceComposerClient::Transaction::cacheBuffers() { } size_t count = 0; - for (auto& [sc, cs] : mComposerStates) { - layer_state_t* s = getLayerState(sc); + for (auto& [handle, cs] : mComposerStates) { + layer_state_t* s = getLayerState(handle); if (!(s->what & layer_state_t::eBufferChanged)) { continue; } @@ -639,16 +638,15 @@ void SurfaceComposerClient::Transaction::setEarlyWakeup() { mEarlyWakeup = true; } -layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp& sc) { - if (mComposerStates.count(sc) == 0) { +layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp& handle) { + if (mComposerStates.count(handle) == 0) { // we don't have it, add an initialized layer_state to our list ComposerState s; - s.client = sc->getClient()->mClient; - s.state.surface = sc->getHandle(); - mComposerStates[sc] = s; + s.state.surface = handle; + mComposerStates[handle] = s; } - return &(mComposerStates[sc].state); + return &(mComposerStates[handle].state); } void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback( diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index b9defdd120..071314f082 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -65,8 +65,8 @@ SurfaceControl::~SurfaceControl() { // Avoid reparenting the server-side surface to null if we are not the owner of it, // meaning that we retrieved it from another process. - if (mClient != nullptr && mHandle != nullptr && mOwned) { - SurfaceComposerClient::doDropReferenceTransaction(mHandle, mClient->getClient()); + if (mHandle != nullptr && mOwned) { + SurfaceComposerClient::doDropReferenceTransaction(mHandle); } release(); } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index f438eb3d01..cbd1c8553b 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -206,7 +206,6 @@ struct layer_state_t { }; struct ComposerState { - sp client; layer_state_t state; status_t write(Parcel& output) const; status_t read(const Parcel& input); @@ -274,8 +273,6 @@ struct InputWindowCommands { }; static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) { - if (lhs.client < rhs.client) return -1; - if (lhs.client > rhs.client) return 1; if (lhs.state.surface < rhs.state.surface) return -1; if (lhs.state.surface > rhs.state.surface) return 1; return 0; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 4dda97f5e1..22ab62da44 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -163,8 +163,7 @@ public: * Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it * to null), but without needing an sp to avoid infinite ressurection. */ - static void doDropReferenceTransaction(const sp& handle, - const sp& client); + static void doDropReferenceTransaction(const sp& handle); /** * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is @@ -270,6 +269,12 @@ public: } }; + struct IBinderHash { + std::size_t operator()(const sp& iBinder) const { + return std::hash{}(iBinder.get()); + } + }; + struct TCLHash { std::size_t operator()(const sp& tcl) const { return std::hash{}((tcl) ? IInterface::asBinder(tcl).get() : nullptr); @@ -286,7 +291,7 @@ public: }; class Transaction : Parcelable { - std::unordered_map, ComposerState, SCHash> mComposerStates; + std::unordered_map, ComposerState, IBinderHash> mComposerStates; SortedVector mDisplayStates; std::unordered_map, CallbackInfo, TCLHash> mListenerCallbacks; @@ -314,7 +319,10 @@ public: InputWindowCommands mInputWindowCommands; int mStatus = NO_ERROR; - layer_state_t* getLayerState(const sp& sc); + layer_state_t* getLayerState(const sp& surfaceHandle); + layer_state_t* getLayerState(const sp& sc) { + return getLayerState(sc->getHandle()); + } DisplayState& getDisplayState(const sp& token); void cacheBuffers(); @@ -560,15 +568,10 @@ class TransactionCompletedListener : public BnTransactionCompletedListener { CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1; - struct IBinderHash { - std::size_t operator()(const sp& iBinder) const { - return std::hash{}(iBinder.get()); - } - }; - struct CallbackTranslation { TransactionCompletedCallback callbackFunction; - std::unordered_map, sp, IBinderHash> surfaceControls; + std::unordered_map, sp, SurfaceComposerClient::IBinderHash> + surfaceControls; }; std::unordered_map mCallbacks GUARDED_BY(mMutex); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f1e3971811..9c612b459b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3655,27 +3655,6 @@ bool SurfaceFlinger::transactionFlushNeeded() { return !mTransactionQueues.empty(); } -bool SurfaceFlinger::containsAnyInvalidClientState(const Vector& states) { - for (const ComposerState& state : states) { - // Here we need to check that the interface we're given is indeed - // one of our own. A malicious client could give us a nullptr - // IInterface, or one of its own or even one of our own but a - // different type. All these situations would cause us to crash. - if (state.client == nullptr) { - return true; - } - - sp binder = IInterface::asBinder(state.client); - if (binder == nullptr) { - return true; - } - - if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) == nullptr) { - return true; - } - } - return false; -} bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, const Vector& states) { @@ -3714,10 +3693,6 @@ void SurfaceFlinger::setTransactionState(const Vector& states, Mutex::Autolock _l(mStateLock); - if (containsAnyInvalidClientState(states)) { - return; - } - // If its TransactionQueue already has a pending TransactionState or if it is pending auto itr = mTransactionQueues.find(applyToken); // if this is an animation frame, wait until prior animation frame has @@ -3929,9 +3904,8 @@ uint32_t SurfaceFlinger::setClientStateLocked( const std::vector& listenerCallbacks, int64_t postTime, bool privileged) { const layer_state_t& s = composerState.state; - sp client(static_cast(composerState.client.get())); - sp layer(client->getLayerUser(s.surface)); + sp layer(fromHandle(s.surface)); if (layer == nullptr) { for (auto& listenerCallback : listenerCallbacks) { mTransactionCompletedThread.registerUnpresentedCallbackHandle( diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index fa801afff8..30b6b69b17 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -582,7 +582,6 @@ private: void latchAndReleaseBuffer(const sp& layer); void commitTransaction() REQUIRES(mStateLock); void commitOffscreenLayers(); - bool containsAnyInvalidClientState(const Vector& states); bool transactionIsReadyToBeApplied(int64_t desiredPresentTime, const Vector& states); uint32_t setClientStateLocked(const ComposerState& composerState, int64_t desiredPresentTime, -- GitLab From da6c1596fde6f691906eb8b980354ddc070b7fff Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 16 Jul 2019 13:45:06 -0700 Subject: [PATCH 0082/1255] Allow AID_MEDIA to capture layer for video thumbnails bug: 135717526 bug: 113609172 Change-Id: I7ab76f914e2f10c45aa25c7babc0a382f2d63597 --- services/surfaceflinger/SurfaceFlinger.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f1e3971811..fbe409f4bc 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5188,7 +5188,18 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case SET_DISPLAY_BRIGHTNESS: { return OK; } - case CAPTURE_LAYERS: + case CAPTURE_LAYERS: { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + // allow media to capture layer for video thumbnails + if ((uid != AID_GRAPHICS && uid != AID_MEDIA) && + !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { + ALOGE("Permission Denial: can't capture layer pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + return OK; + } case CAPTURE_SCREEN: case ADD_REGION_SAMPLING_LISTENER: case REMOVE_REGION_SAMPLING_LISTENER: { -- GitLab From 928dabf4d6a9796794323561f3eb5fd18dd82a9f Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan Date: Tue, 16 Jul 2019 15:28:22 -0700 Subject: [PATCH 0083/1255] Move the nested struct inside VkNativeBufferANDROID outside. The nested struct of VkNativeBufferANDROID in vk_android_native_buffer.h needs to be moved outside to properly update the vulkan registry as there is no way of specifying nested structs in the registry yet. Bug: 136570819 Test: Build and flash, dEQP tests Change-Id: I8b0db3f0729215f29ba82b6352010c7dd7f47f4e --- vulkan/include/vulkan/vk_android_native_buffer.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h index 23006fa6be..9ffe83ba2e 100644 --- a/vulkan/include/vulkan/vk_android_native_buffer.h +++ b/vulkan/include/vulkan/vk_android_native_buffer.h @@ -61,6 +61,11 @@ typedef enum VkSwapchainImageUsageFlagBitsANDROID { } VkSwapchainImageUsageFlagBitsANDROID; typedef VkFlags VkSwapchainImageUsageFlagsANDROID; +typedef struct { + uint64_t consumer; + uint64_t producer; +} VkNativeBufferUsage2ANDROID; + typedef struct { VkStructureType sType; // must be VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID const void* pNext; @@ -73,10 +78,7 @@ typedef struct { int format; int usage; // DEPRECATED in SPEC_VERSION 6 // -- Added in SPEC_VERSION 6 -- - struct { - uint64_t consumer; - uint64_t producer; - } usage2; + VkNativeBufferUsage2ANDROID usage2; } VkNativeBufferANDROID; typedef struct { -- GitLab From 87edb95cbba91c28fb9c0bc4977b50c5e1c04940 Mon Sep 17 00:00:00 2001 From: Adam Bodnar Date: Wed, 17 Jul 2019 12:35:53 -0700 Subject: [PATCH 0084/1255] Check if Vulkan layers have a valid looking GIPA Bug: 137862180 Test: flash, remove vkGetInstanceProcAddr from layer symbols, run Change-Id: I4d4d75585623d2c15c57b4d8ad0243a2fc347fce --- vulkan/libvulkan/api.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp index 71048db920..368130d13b 100644 --- a/vulkan/libvulkan/api.cpp +++ b/vulkan/libvulkan/api.cpp @@ -664,6 +664,12 @@ VkResult LayerChain::LoadLayer(ActiveLayer& layer, const char* name) { return VK_ERROR_LAYER_NOT_PRESENT; } + if (!layer.ref.GetGetInstanceProcAddr()) { + ALOGW("Failed to locate vkGetInstanceProcAddr in layer %s", name); + layer.ref.~LayerRef(); + return VK_ERROR_LAYER_NOT_PRESENT; + } + ALOGI("Loaded layer %s", name); return VK_SUCCESS; -- GitLab From f527548dd751bd62b1302cf357fdb4840bc115a9 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Tue, 29 Jan 2019 18:42:42 -0800 Subject: [PATCH 0085/1255] SF: Move/Refactor Layer::setPerFrameData Moves functionality out of ColorLayer, BufferLayer, BufferStateLayer and BufferQueueLayer related to setting the per-frame data. Instead each of the front-end classes now implements a minimal function to set the per-frame state into the LayerFECompositionState structure. compositionengine::OutputLayer now takes care of sending the state to the HWC, and in particular with detecting when client composition needs to be forced due to lack of HWC support (though the front-end can also set a flag to force client composition for a few things it knows about). SurfaceFlinger::calculateWorkingSet is also refactored to work with the changes made, and prepare it to be moved over to CompositionEngine. Test: atest libsurfaceflinger_unittest libcompositionengine_test Test: atest CtsColorModeTestCases Test: atest CtsDisplayTestCases Test: atest CtsGraphicsTestCases Test: atest CtsUiRenderingTestCases Test: atest CtsViewTestCases Test: atest android.media.cts.EncodeVirtualDisplayWithCompositionTest Bug: 121291683 Change-Id: I2cb0442f68ec5c5f65f5b4cb418dda4c42e5dc39 --- services/surfaceflinger/BufferLayer.cpp | 91 +----- services/surfaceflinger/BufferLayer.h | 8 +- services/surfaceflinger/BufferQueueLayer.cpp | 34 +-- services/surfaceflinger/BufferQueueLayer.h | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 25 +- services/surfaceflinger/BufferStateLayer.h | 6 +- services/surfaceflinger/ColorLayer.cpp | 77 +---- services/surfaceflinger/ColorLayer.h | 6 +- .../compositionengine/DisplayColorProfile.h | 8 + .../LayerFECompositionState.h | 17 +- .../include/compositionengine/Output.h | 3 +- .../include/compositionengine/OutputLayer.h | 2 +- .../include/compositionengine/impl/Display.h | 2 +- .../impl/DisplayColorProfile.h | 2 + .../include/compositionengine/impl/Output.h | 2 +- .../impl/OutputCompositionState.h | 5 +- .../compositionengine/impl/OutputLayer.h | 19 +- .../impl/OutputLayerCompositionState.h | 6 +- .../mock/DisplayColorProfile.h | 3 + .../include/compositionengine/mock/Output.h | 11 +- .../compositionengine/mock/OutputLayer.h | 2 +- .../CompositionEngine/src/Display.cpp | 11 +- .../src/DisplayColorProfile.cpp | 40 ++- .../src/LayerCompositionState.cpp | 8 +- .../CompositionEngine/src/Output.cpp | 10 +- .../src/OutputCompositionState.cpp | 1 + .../CompositionEngine/src/OutputLayer.cpp | 266 +++++++++++++++--- .../src/OutputLayerCompositionState.cpp | 1 + .../tests/DisplayColorProfileTest.cpp | 61 ++++ .../CompositionEngine/tests/DisplayTest.cpp | 27 +- .../tests/OutputLayerTest.cpp | 214 +++++++++++++- .../CompositionEngine/tests/OutputTest.cpp | 16 +- services/surfaceflinger/ContainerLayer.cpp | 3 - services/surfaceflinger/ContainerLayer.h | 4 - services/surfaceflinger/Layer.cpp | 70 ++--- services/surfaceflinger/Layer.h | 16 +- services/surfaceflinger/SurfaceFlinger.cpp | 156 ++++------ .../tests/unittests/CompositionTest.cpp | 4 +- 38 files changed, 776 insertions(+), 463 deletions(-) diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index f51fbb45f6..c3b171847c 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -253,90 +254,20 @@ bool BufferLayer::isHdrY410() const { mActiveBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102); } -void BufferLayer::setPerFrameData(const sp& displayDevice, - const ui::Transform& transform, const Rect& viewport, - int32_t supportedPerFrameMetadata, - const ui::Dataspace targetDataspace) { - RETURN_IF_NO_HWC_LAYER(displayDevice); - - // Apply this display's projection's viewport to the visible region - // before giving it to the HWC HAL. - Region visible = transform.transform(visibleRegion.intersect(viewport)); - - const auto outputLayer = findOutputLayerForDisplay(displayDevice); - LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc); - - auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer; - auto error = hwcLayer->setVisibleRegion(visible); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(), - to_string(error).c_str(), static_cast(error)); - visible.dump(LOG_TAG); - } - outputLayer->editState().visibleRegion = visible; - - auto& layerCompositionState = getCompositionLayer()->editState().frontEnd; - - error = hwcLayer->setSurfaceDamage(surfaceDamageRegion); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(), - to_string(error).c_str(), static_cast(error)); - surfaceDamageRegion.dump(LOG_TAG); - } - layerCompositionState.surfaceDamage = surfaceDamageRegion; +void BufferLayer::latchPerFrameState( + compositionengine::LayerFECompositionState& compositionState) const { + Layer::latchPerFrameState(compositionState); // Sideband layers - if (layerCompositionState.sidebandStream.get()) { - setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::SIDEBAND); - ALOGV("[%s] Requesting Sideband composition", mName.string()); - error = hwcLayer->setSidebandStream(layerCompositionState.sidebandStream->handle()); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(), - layerCompositionState.sidebandStream->handle(), to_string(error).c_str(), - static_cast(error)); - } - layerCompositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND; - return; - } - - // Device or Cursor layers - if (mPotentialCursor) { - ALOGV("[%s] Requesting Cursor composition", mName.string()); - setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::CURSOR); + if (compositionState.sidebandStream.get()) { + compositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND; } else { - ALOGV("[%s] Requesting Device composition", mName.string()); - setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::DEVICE); + // Normal buffer layers + compositionState.hdrMetadata = getDrawingHdrMetadata(); + compositionState.compositionType = mPotentialCursor + ? Hwc2::IComposerClient::Composition::CURSOR + : Hwc2::IComposerClient::Composition::DEVICE; } - - ui::Dataspace dataspace = isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN - ? targetDataspace - : mCurrentDataSpace; - error = hwcLayer->setDataspace(dataspace); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace, - to_string(error).c_str(), static_cast(error)); - } - - const HdrMetadata& metadata = getDrawingHdrMetadata(); - error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata, metadata); - if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) { - ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(), - to_string(error).c_str(), static_cast(error)); - } - - error = hwcLayer->setColorTransform(getColorTransform()); - if (error == HWC2::Error::Unsupported) { - // If per layer color transform is not supported, we use GPU composition. - setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::CLIENT); - } else if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(), - to_string(error).c_str(), static_cast(error)); - } - layerCompositionState.dataspace = mCurrentDataSpace; - layerCompositionState.colorTransform = getColorTransform(); - layerCompositionState.hdrMetadata = metadata; - - setHwcLayerBuffer(displayDevice); } bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) { diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index b679380b79..6bde7b45fd 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -82,10 +82,6 @@ public: bool isHdrY410() const override; - void setPerFrameData(const sp& display, const ui::Transform& transform, - const Rect& viewport, int32_t supportedPerFrameMetadata, - const ui::Dataspace targetDataspace) override; - bool onPreComposition(nsecs_t refreshStartTime) override; bool onPostComposition(const std::optional& displayId, const std::shared_ptr& glDoneFence, @@ -147,9 +143,9 @@ private: virtual status_t updateActiveBuffer() = 0; virtual status_t updateFrameNumber(nsecs_t latchTime) = 0; - virtual void setHwcLayerBuffer(const sp& displayDevice) = 0; - protected: + void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const override; + // Loads the corresponding system property once per process static bool latchUnsignaledBuffers(); diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index d6853661a5..2c3da1aa21 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -377,7 +377,6 @@ status_t BufferQueueLayer::updateActiveBuffer() { mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence); auto& layerCompositionState = getCompositionLayer()->editState().frontEnd; layerCompositionState.buffer = mActiveBuffer; - layerCompositionState.bufferSlot = mActiveBufferSlot; if (mActiveBuffer == nullptr) { // this can only happen if the very first buffer was rejected. @@ -397,32 +396,17 @@ status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) { return NO_ERROR; } -void BufferQueueLayer::setHwcLayerBuffer(const sp& display) { - const auto outputLayer = findOutputLayerForDisplay(display); - LOG_FATAL_IF(!outputLayer); - LOG_FATAL_IF(!outputLayer->getState.hwc); - auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer; - - uint32_t hwcSlot = 0; - sp hwcBuffer; - - // INVALID_BUFFER_SLOT is used to identify BufferStateLayers. Default to 0 - // for BufferQueueLayers - int slot = (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot; - (*outputLayer->editState().hwc) - .hwcBufferCache.getHwcBuffer(slot, mActiveBuffer, &hwcSlot, &hwcBuffer); - - auto acquireFence = mConsumer->getCurrentFence(); - auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), mActiveBuffer->handle, - to_string(error).c_str(), static_cast(error)); +void BufferQueueLayer::latchPerFrameState( + compositionengine::LayerFECompositionState& compositionState) const { + BufferLayer::latchPerFrameState(compositionState); + if (compositionState.compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) { + return; } - auto& layerCompositionState = getCompositionLayer()->editState().frontEnd; - layerCompositionState.bufferSlot = mActiveBufferSlot; - layerCompositionState.buffer = mActiveBuffer; - layerCompositionState.acquireFence = acquireFence; + compositionState.buffer = mActiveBuffer; + compositionState.bufferSlot = + (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot; + compositionState.acquireFence = mConsumer->getCurrentFence(); } // ----------------------------------------------------------------------- diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 7def33ad78..9c537ad689 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -94,7 +94,7 @@ private: status_t updateActiveBuffer() override; status_t updateFrameNumber(nsecs_t latchTime) override; - void setHwcLayerBuffer(const sp& displayDevice) override; + void latchPerFrameState(compositionengine::LayerFECompositionState&) const override; // ----------------------------------------------------------------------- // Interface implementation for BufferLayerConsumer::ContentsChangedListener diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 4b01301467..d0fa2e0088 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -569,7 +569,6 @@ status_t BufferStateLayer::updateActiveBuffer() { mActiveBufferFence = s.acquireFence; auto& layerCompositionState = getCompositionLayer()->editState().frontEnd; layerCompositionState.buffer = mActiveBuffer; - layerCompositionState.bufferSlot = 0; return NO_ERROR; } @@ -580,24 +579,18 @@ status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) { return NO_ERROR; } -void BufferStateLayer::setHwcLayerBuffer(const sp& display) { - const auto outputLayer = findOutputLayerForDisplay(display); - LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc); - auto& hwcInfo = *outputLayer->editState().hwc; - auto& hwcLayer = hwcInfo.hwcLayer; +void BufferStateLayer::latchPerFrameState( + compositionengine::LayerFECompositionState& compositionState) const { + BufferLayer::latchPerFrameState(compositionState); + if (compositionState.compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) { + return; + } const State& s(getDrawingState()); - uint32_t hwcSlot; - sp buffer; - hwcInfo.hwcBufferCache.getHwcBuffer(mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId), - s.buffer, &hwcSlot, &buffer); - - auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), - s.buffer->handle, to_string(error).c_str(), static_cast(error)); - } + compositionState.buffer = s.buffer; + compositionState.bufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId); + compositionState.acquireFence = s.acquireFence; mFrameNumber++; } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index db8ae0d337..75c855200b 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -136,7 +136,7 @@ private: status_t updateActiveBuffer() override; status_t updateFrameNumber(nsecs_t latchTime) override; - void setHwcLayerBuffer(const sp& display) override; + void latchPerFrameState(compositionengine::LayerFECompositionState&) const override; private: friend class SlotGenerationTest; @@ -151,11 +151,11 @@ private: std::atomic mSidebandStreamChanged{false}; - uint32_t mFrameNumber{0}; + mutable uint32_t mFrameNumber{0}; sp mPreviousReleaseFence; - bool mCurrentStateModified = false; + mutable bool mCurrentStateModified = false; bool mReleasePreviousBuffer = false; nsecs_t mCallbackHandleAcquireTime = -1; diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp index fcc2d97ca3..f15957adf9 100644 --- a/services/surfaceflinger/ColorLayer.cpp +++ b/services/surfaceflinger/ColorLayer.cpp @@ -18,6 +18,8 @@ #undef LOG_TAG #define LOG_TAG "ColorLayer" +#include "ColorLayer.h" + #include #include #include @@ -26,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +37,6 @@ #include #include -#include "ColorLayer.h" #include "DisplayDevice.h" #include "SurfaceFlinger.h" @@ -91,75 +93,12 @@ bool ColorLayer::setDataspace(ui::Dataspace dataspace) { return true; } -void ColorLayer::setPerFrameData(const sp& display, - const ui::Transform& transform, const Rect& viewport, - int32_t /* supportedPerFrameMetadata */, - const ui::Dataspace targetDataspace) { - RETURN_IF_NO_HWC_LAYER(display); - - Region visible = transform.transform(visibleRegion.intersect(viewport)); - - const auto outputLayer = findOutputLayerForDisplay(display); - LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc); - - auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer; - - auto error = hwcLayer->setVisibleRegion(visible); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(), - to_string(error).c_str(), static_cast(error)); - visible.dump(LOG_TAG); - } - outputLayer->editState().visibleRegion = visible; - - setCompositionType(display, Hwc2::IComposerClient::Composition::SOLID_COLOR); +void ColorLayer::latchPerFrameState( + compositionengine::LayerFECompositionState& compositionState) const { + Layer::latchPerFrameState(compositionState); - const ui::Dataspace dataspace = - isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN ? targetDataspace - : mCurrentDataSpace; - error = hwcLayer->setDataspace(dataspace); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace, - to_string(error).c_str(), static_cast(error)); - } - - auto& layerCompositionState = getCompositionLayer()->editState().frontEnd; - layerCompositionState.dataspace = mCurrentDataSpace; - - half4 color = getColor(); - error = hwcLayer->setColor({static_cast(std::round(255.0f * color.r)), - static_cast(std::round(255.0f * color.g)), - static_cast(std::round(255.0f * color.b)), 255}); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(), - static_cast(error)); - } - layerCompositionState.color = {static_cast(std::round(255.0f * color.r)), - static_cast(std::round(255.0f * color.g)), - static_cast(std::round(255.0f * color.b)), 255}; - - // Clear out the transform, because it doesn't make sense absent a source buffer - error = hwcLayer->setTransform(HWC2::Transform::None); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(), - static_cast(error)); - } - outputLayer->editState().bufferTransform = static_cast(0); - - error = hwcLayer->setColorTransform(getColorTransform()); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(), - to_string(error).c_str(), static_cast(error)); - } - layerCompositionState.colorTransform = getColorTransform(); - - error = hwcLayer->setSurfaceDamage(surfaceDamageRegion); - if (error != HWC2::Error::None) { - ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(), - to_string(error).c_str(), static_cast(error)); - surfaceDamageRegion.dump(LOG_TAG); - } - layerCompositionState.surfaceDamage = surfaceDamageRegion; + compositionState.color = getColor(); + compositionState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; } void ColorLayer::commitTransaction(const State& stateToCommit) { diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h index 53d5b5b605..2483ff0bfb 100644 --- a/services/surfaceflinger/ColorLayer.h +++ b/services/surfaceflinger/ColorLayer.h @@ -37,10 +37,6 @@ public: bool setDataspace(ui::Dataspace dataspace) override; - void setPerFrameData(const sp& display, const ui::Transform& transform, - const Rect& viewport, int32_t supportedPerFrameMetadata, - const ui::Dataspace targetDataspace) override; - void commitTransaction(const State& stateToCommit) override; bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; } @@ -52,6 +48,8 @@ protected: renderengine::LayerSettings& layer); private: + void latchPerFrameState(compositionengine::LayerFECompositionState&) const override; + std::shared_ptr mCompositionLayer; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h index e2a0d42640..d93bfa30cc 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include @@ -75,6 +76,13 @@ public: // Gets the supported HDR capabilities for the profile virtual const HdrCapabilities& getHdrCapabilities() const = 0; + // Returns true if HWC for this profile supports the dataspace + virtual bool isDataspaceSupported(ui::Dataspace) const = 0; + + // Returns the target dataspace for picked color mode and dataspace + virtual ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace, + ui::Dataspace colorSpaceAgnosticDataspace) const = 0; + // Debugging virtual void dump(std::string&) const = 0; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index e6ee078624..d96d58c1fa 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -36,9 +36,9 @@ namespace android::compositionengine { * Used by LayerFE::getCompositionState */ struct LayerFECompositionState { - // TODO(lpique): b/121291683 Remove this one we are sure we don't need the - // value recomputed / set every frame. - Region geomVisibleRegion; + // If set to true, forces client composition on all output layers until + // the next geometry change. + bool forceClientComposition{false}; /* * Geometry state @@ -56,6 +56,10 @@ struct LayerFECompositionState { Region geomActiveTransparentRegion; FloatRect geomLayerBounds; + // TODO(lpique): b/121291683 Remove this one we are sure we don't need the + // value recomputed / set every frame. + Region geomVisibleRegion; + /* * Presentation */ @@ -93,12 +97,16 @@ struct LayerFECompositionState { sp sidebandStream; // The color for this layer - Hwc2::IComposerClient::Color color; + half4 color; /* * Per-frame presentation state */ + // If true, this layer will use the dataspace chosen for the output and + // ignore the dataspace value just below + bool isColorspaceAgnostic{false}; + // The dataspace for this layer ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; @@ -107,6 +115,7 @@ struct LayerFECompositionState { // The color transform mat4 colorTransform; + bool colorTransformIsIdentity{true}; }; } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 54e6bd6af7..591382dcd9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -71,7 +71,8 @@ public: virtual void setColorTransform(const mat4&) = 0; // Sets the output color mode - virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) = 0; + virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, + ui::Dataspace colorSpaceAgnosticDataspace) = 0; // Outputs a string with a state dump virtual void dump(std::string&) const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index cd63b57d86..d3a4e09ec7 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -71,7 +71,7 @@ public: // Writes the geometry state to the HWC, or does nothing if this layer does // not use the HWC. If includeGeometry is false, the geometry state can be // skipped. - virtual void writeStateToHWC(bool includeGeometry) const = 0; + virtual void writeStateToHWC(bool includeGeometry) = 0; // Debugging virtual void dump(std::string& result) const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index 0e20c43321..1265533449 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -39,7 +39,7 @@ public: // compositionengine::Output overrides void dump(std::string&) const override; void setColorTransform(const mat4&) override; - void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override; + void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override; // compositionengine::Display overrides const std::optional& getId() const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h index 49c2d2c0ea..e84a36ee67 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h @@ -54,6 +54,8 @@ public: bool hasDolbyVisionSupport() const override; const HdrCapabilities& getHdrCapabilities() const override; + bool isDataspaceSupported(ui::Dataspace) const override; + ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace) const override; void dump(std::string&) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index b1d1f42f46..f245936744 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -45,7 +45,7 @@ public: void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override; void setColorTransform(const mat4&) override; - void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override; + void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override; void dump(std::string&) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 0c47eb5a01..45b8308f44 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -88,9 +88,12 @@ struct OutputCompositionState { // Current active render intent ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC}; - // Current active dstaspace + // Current active dataspace ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; + // Current target dataspace + ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN}; + // Debugging void dump(std::string& result) const; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index 6a4818f10f..708f3a1b3e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -26,7 +26,11 @@ #include "DisplayHardware/DisplayIdentification.h" -namespace android::compositionengine::impl { +namespace android::compositionengine { + +struct LayerFECompositionState; + +namespace impl { class OutputLayer : public compositionengine::OutputLayer { public: @@ -44,7 +48,7 @@ public: OutputLayerCompositionState& editState() override; void updateCompositionState(bool) override; - void writeStateToHWC(bool) const override; + void writeStateToHWC(bool) override; void dump(std::string& result) const override; @@ -54,6 +58,14 @@ public: private: Rect calculateInitialCrop() const; + void writeOutputDependentGeometryStateToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition); + void writeOutputIndependentGeometryStateToHWC(HWC2::Layer*, const LayerFECompositionState&); + void writeOutputDependentPerFrameStateToHWC(HWC2::Layer*); + void writeOutputIndependentPerFrameStateToHWC(HWC2::Layer*, const LayerFECompositionState&); + void writeSolidColorStateToHWC(HWC2::Layer*, const LayerFECompositionState&); + void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&); + void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&); + void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition); const compositionengine::Output& mOutput; std::shared_ptr mLayer; @@ -66,4 +78,5 @@ std::unique_ptr createOutputLayer( const CompositionEngine&, std::optional, const compositionengine::Output&, std::shared_ptr, sp); -} // namespace android::compositionengine::impl +} // namespace impl +} // namespace android::compositionengine \ No newline at end of file diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index b78e9e0076..de0f08ace8 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,9 @@ struct OutputLayerCompositionState { // The buffer transform to use for this layer o on this output. Hwc2::Transform bufferTransform{static_cast(0)}; + // The dataspace for this layer + ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; + // The Z order index of this layer on this output uint32_t z; @@ -70,7 +74,7 @@ struct OutputLayerCompositionState { // The HWC Layer backing this layer std::shared_ptr hwcLayer; - // The HWC composition type for this layer + // The most recently set HWC composition type for this layer Hwc2::IComposerClient::Composition hwcCompositionType{ Hwc2::IComposerClient::Composition::INVALID}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h index 8056c9d290..1aaebea295 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h @@ -42,6 +42,9 @@ public: MOCK_CONST_METHOD0(hasDolbyVisionSupport, bool()); MOCK_CONST_METHOD0(getHdrCapabilities, const HdrCapabilities&()); + MOCK_CONST_METHOD1(isDataspaceSupported, bool(ui::Dataspace)); + MOCK_CONST_METHOD3(getTargetDataspace, + ui::Dataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace)); MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index d0e7b195a8..cf82107194 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -41,17 +41,18 @@ public: MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool)); MOCK_METHOD1(setColorTransform, void(const mat4&)); - MOCK_METHOD3(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent)); + MOCK_METHOD4(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace)); MOCK_CONST_METHOD1(dump, void(std::string&)); MOCK_CONST_METHOD0(getName, const std::string&()); MOCK_METHOD1(setName, void(const std::string&)); - MOCK_CONST_METHOD0(getDisplayColorProfile, DisplayColorProfile*()); - MOCK_METHOD1(setDisplayColorProfile, void(std::unique_ptr)); + MOCK_CONST_METHOD0(getDisplayColorProfile, compositionengine::DisplayColorProfile*()); + MOCK_METHOD1(setDisplayColorProfile, + void(std::unique_ptr)); - MOCK_CONST_METHOD0(getRenderSurface, RenderSurface*()); - MOCK_METHOD1(setRenderSurface, void(std::unique_ptr)); + MOCK_CONST_METHOD0(getRenderSurface, compositionengine::RenderSurface*()); + MOCK_METHOD1(setRenderSurface, void(std::unique_ptr)); MOCK_CONST_METHOD0(getState, const OutputCompositionState&()); MOCK_METHOD0(editState, OutputCompositionState&()); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h index 29cd08a681..dab8b9da0e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -39,7 +39,7 @@ public: MOCK_METHOD0(editState, impl::OutputLayerCompositionState&()); MOCK_METHOD1(updateCompositionState, void(bool)); - MOCK_CONST_METHOD1(writeStateToHWC, void(bool)); + MOCK_METHOD1(writeStateToHWC, void(bool)); MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index f9d70e3c91..8520d70c71 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -74,9 +74,14 @@ void Display::setColorTransform(const mat4& transform) { } void Display::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace, - ui::RenderIntent renderIntent) { + ui::RenderIntent renderIntent, + ui::Dataspace colorSpaceAgnosticDataspace) { + ui::Dataspace targetDataspace = + getDisplayColorProfile()->getTargetDataspace(mode, dataspace, + colorSpaceAgnosticDataspace); + if (mode == getState().colorMode && dataspace == getState().dataspace && - renderIntent == getState().renderIntent) { + renderIntent == getState().renderIntent && targetDataspace == getState().targetDataspace) { return; } @@ -85,7 +90,7 @@ void Display::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace, return; } - Output::setColorMode(mode, dataspace, renderIntent); + Output::setColorMode(mode, dataspace, renderIntent, colorSpaceAgnosticDataspace); auto& hwc = getCompositionEngine().getHwComposer(); hwc.setActiveColorMode(*mId, mode, renderIntent); diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp index 130ab1dd54..5ef9097bff 100644 --- a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp @@ -64,6 +64,12 @@ const std::array sHdrRenderIntents = { RenderIntent::TONE_MAP_COLORIMETRIC, }; +// Returns true if the given colorMode is considered an HDR color mode +bool isHdrColorMode(const ColorMode colorMode) { + return std::any_of(std::begin(sHdrColorModes), std::end(sHdrColorModes), + [colorMode](ColorMode hdrColorMode) { return hdrColorMode == colorMode; }); +} + // map known color mode to dataspace Dataspace colorModeToDataspace(ColorMode mode) { switch (mode) { @@ -90,13 +96,7 @@ std::vector getColorModeCandidates(ColorMode mode) { candidates.push_back(mode); // check if mode is HDR - bool isHdr = false; - for (auto hdrMode : sHdrColorModes) { - if (hdrMode == mode) { - isHdr = true; - break; - } - } + bool isHdr = isHdrColorMode(mode); // add other HDR candidates when mode is HDR if (isHdr) { @@ -376,6 +376,32 @@ void DisplayColorProfile::getBestColorMode(Dataspace dataspace, RenderIntent int } } +bool DisplayColorProfile::isDataspaceSupported(Dataspace dataspace) const { + switch (dataspace) { + case Dataspace::BT2020_PQ: + case Dataspace::BT2020_ITU_PQ: + return hasHDR10Support(); + + case Dataspace::BT2020_HLG: + case Dataspace::BT2020_ITU_HLG: + return hasHLGSupport(); + + default: + return true; + } +} + +ui::Dataspace DisplayColorProfile::getTargetDataspace(ColorMode mode, Dataspace dataspace, + Dataspace colorSpaceAgnosticDataspace) const { + if (isHdrColorMode(mode)) { + return Dataspace::UNKNOWN; + } + if (colorSpaceAgnosticDataspace != ui::Dataspace::UNKNOWN) { + return colorSpaceAgnosticDataspace; + } + return dataspace; +} + void DisplayColorProfile::dump(std::string& out) const { out.append(" Composition Display Color State:"); diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp index 40c4da97a8..37d6eaa2f2 100644 --- a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp @@ -24,9 +24,10 @@ namespace { using android::compositionengine::impl::dumpVal; -void dumpVal(std::string& out, const char* name, Hwc2::IComposerClient::Color value) { +void dumpVal(std::string& out, const char* name, half4 value) { using android::base::StringAppendF; - StringAppendF(&out, "%s=[%d %d %d] ", name, value.r, value.g, value.b); + StringAppendF(&out, "%s=[%f %f %f] ", name, static_cast(value.r), + static_cast(value.g), static_cast(value.b)); } void dumpFrontEnd(std::string& out, const LayerFECompositionState& state) { @@ -60,8 +61,8 @@ void dumpFrontEnd(std::string& out, const LayerFECompositionState& state) { dumpVal(out, "composition type", toString(state.compositionType), state.compositionType); out.append("\n buffer: "); + dumpVal(out, "bufferSlot", state.bufferSlot); dumpVal(out, "buffer", state.buffer.get()); - dumpVal(out, "slot", state.bufferSlot); out.append("\n "); dumpVal(out, "sideband stream", state.sidebandStream.get()); @@ -70,6 +71,7 @@ void dumpFrontEnd(std::string& out, const LayerFECompositionState& state) { dumpVal(out, "color", state.color); out.append("\n "); + dumpVal(out, "isColorspaceAgnostic", state.isColorspaceAgnostic); dumpVal(out, "dataspace", toString(state.dataspace), state.dataspace); dumpVal(out, "hdr metadata types", state.hdrMetadata.validTypes); dumpVal(out, "colorTransform", state.colorTransform); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 01b5781987..0725926be4 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -104,15 +104,21 @@ void Output::setColorTransform(const mat4& transform) { } void Output::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace, - ui::RenderIntent renderIntent) { + ui::RenderIntent renderIntent, + ui::Dataspace colorSpaceAgnosticDataspace) { + ui::Dataspace targetDataspace = + getDisplayColorProfile()->getTargetDataspace(mode, dataspace, + colorSpaceAgnosticDataspace); + if (mState.colorMode == mode && mState.dataspace == dataspace && - mState.renderIntent == renderIntent) { + mState.renderIntent == renderIntent && mState.targetDataspace == targetDataspace) { return; } mState.colorMode = mode; mState.dataspace = dataspace; mState.renderIntent = renderIntent; + mState.targetDataspace = targetDataspace; mRenderSurface->setBufferDataspace(dataspace); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index 9549054bd6..0b15dad6cd 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -44,6 +44,7 @@ void OutputCompositionState::dump(std::string& out) const { dumpVal(out, "renderIntent", toString(renderIntent), renderIntent); dumpVal(out, "dataspace", toString(dataspace), dataspace); dumpVal(out, "colorTransform", colorTransform); + dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace); out.append("\n"); } diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 5ce72b0879..ebfc70489e 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -290,20 +291,43 @@ uint32_t OutputLayer::calculateOutputRelativeBufferTransform() const { } // namespace impl void OutputLayer::updateCompositionState(bool includeGeometry) { + const auto& layerFEState = mLayer->getState().frontEnd; + const auto& outputState = mOutput.getState(); + const auto& profile = *mOutput.getDisplayColorProfile(); + if (includeGeometry) { mState.displayFrame = calculateOutputDisplayFrame(); mState.sourceCrop = calculateOutputSourceCrop(); mState.bufferTransform = static_cast(calculateOutputRelativeBufferTransform()); - if ((mLayer->getState().frontEnd.isSecure && !mOutput.getState().isSecure) || + if ((layerFEState.isSecure && !outputState.isSecure) || (mState.bufferTransform & ui::Transform::ROT_INVALID)) { mState.forceClientComposition = true; } } + + // 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. + mState.dataspace = layerFEState.isColorspaceAgnostic && + outputState.targetDataspace != ui::Dataspace::UNKNOWN + ? outputState.targetDataspace + : layerFEState.dataspace; + + // TODO(lpique): b/121291683 Remove this one we are sure we don't need the + // value recomputed / set every frame. + mState.visibleRegion = outputState.transform.transform( + layerFEState.geomVisibleRegion.intersect(outputState.viewport)); + + // These are evaluated every frame as they can potentially change at any + // time. + if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(mState.dataspace)) { + mState.forceClientComposition = true; + } } -void OutputLayer::writeStateToHWC(bool includeGeometry) const { +void OutputLayer::writeStateToHWC(bool includeGeometry) { // Skip doing this if there is no HWC interface if (!mState.hwc) { return; @@ -316,62 +340,212 @@ void OutputLayer::writeStateToHWC(bool includeGeometry) const { return; } + const auto& outputIndependentState = mLayer->getState().frontEnd; + auto requestedCompositionType = outputIndependentState.compositionType; + if (includeGeometry) { - // Output dependent state + writeOutputDependentGeometryStateToHWC(hwcLayer.get(), requestedCompositionType); + writeOutputIndependentGeometryStateToHWC(hwcLayer.get(), outputIndependentState); + } - if (auto error = hwcLayer->setDisplayFrame(mState.displayFrame); - error != HWC2::Error::None) { - ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)", - mLayerFE->getDebugName(), mState.displayFrame.left, mState.displayFrame.top, - mState.displayFrame.right, mState.displayFrame.bottom, to_string(error).c_str(), - static_cast(error)); - } + writeOutputDependentPerFrameStateToHWC(hwcLayer.get()); + writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), outputIndependentState); - if (auto error = hwcLayer->setSourceCrop(mState.sourceCrop); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: " - "%s (%d)", - mLayerFE->getDebugName(), mState.sourceCrop.left, mState.sourceCrop.top, - mState.sourceCrop.right, mState.sourceCrop.bottom, to_string(error).c_str(), - static_cast(error)); - } + writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType); +} + +void OutputLayer::writeOutputDependentGeometryStateToHWC( + HWC2::Layer* hwcLayer, Hwc2::IComposerClient::Composition requestedCompositionType) { + const auto& outputDependentState = getState(); + + if (auto error = hwcLayer->setDisplayFrame(outputDependentState.displayFrame); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)", + mLayerFE->getDebugName(), outputDependentState.displayFrame.left, + outputDependentState.displayFrame.top, outputDependentState.displayFrame.right, + outputDependentState.displayFrame.bottom, to_string(error).c_str(), + static_cast(error)); + } + + if (auto error = hwcLayer->setSourceCrop(outputDependentState.sourceCrop); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: " + "%s (%d)", + mLayerFE->getDebugName(), outputDependentState.sourceCrop.left, + outputDependentState.sourceCrop.top, outputDependentState.sourceCrop.right, + outputDependentState.sourceCrop.bottom, to_string(error).c_str(), + static_cast(error)); + } - if (auto error = hwcLayer->setZOrder(mState.z); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set Z %u: %s (%d)", mLayerFE->getDebugName(), mState.z, + if (auto error = hwcLayer->setZOrder(outputDependentState.z); error != HWC2::Error::None) { + ALOGE("[%s] Failed to set Z %u: %s (%d)", mLayerFE->getDebugName(), outputDependentState.z, + to_string(error).c_str(), static_cast(error)); + } + + // Solid-color layers should always use an identity transform. + const auto bufferTransform = + requestedCompositionType != Hwc2::IComposerClient::Composition::SOLID_COLOR + ? outputDependentState.bufferTransform + : static_cast(0); + if (auto error = hwcLayer->setTransform(static_cast(bufferTransform)); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set transform %s: %s (%d)", mLayerFE->getDebugName(), + toString(outputDependentState.bufferTransform).c_str(), to_string(error).c_str(), + static_cast(error)); + } +} + +void OutputLayer::writeOutputIndependentGeometryStateToHWC( + HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) { + if (auto error = hwcLayer->setBlendMode( + static_cast(outputIndependentState.blendMode)); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set blend mode %s: %s (%d)", mLayerFE->getDebugName(), + toString(outputIndependentState.blendMode).c_str(), to_string(error).c_str(), + static_cast(error)); + } + + if (auto error = hwcLayer->setPlaneAlpha(outputIndependentState.alpha); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set plane alpha %.3f: %s (%d)", mLayerFE->getDebugName(), + outputIndependentState.alpha, to_string(error).c_str(), static_cast(error)); + } + + if (auto error = hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set info %s (%d)", mLayerFE->getDebugName(), to_string(error).c_str(), + static_cast(error)); + } +} + +void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) { + const auto& outputDependentState = getState(); + + // TODO(lpique): b/121291683 visibleRegion is output-dependent geometry + // state and should not change every frame. + if (auto error = hwcLayer->setVisibleRegion(outputDependentState.visibleRegion); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set visible region: %s (%d)", mLayerFE->getDebugName(), + to_string(error).c_str(), static_cast(error)); + outputDependentState.visibleRegion.dump(LOG_TAG); + } + + if (auto error = hwcLayer->setDataspace(outputDependentState.dataspace); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mLayerFE->getDebugName(), + outputDependentState.dataspace, to_string(error).c_str(), + static_cast(error)); + } +} + +void OutputLayer::writeOutputIndependentPerFrameStateToHWC( + HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) { + switch (auto error = hwcLayer->setColorTransform(outputIndependentState.colorTransform)) { + case HWC2::Error::None: + break; + case HWC2::Error::Unsupported: + editState().forceClientComposition = true; + break; + default: + ALOGE("[%s] Failed to set color transform: %s (%d)", mLayerFE->getDebugName(), to_string(error).c_str(), static_cast(error)); - } + } - if (auto error = - hwcLayer->setTransform(static_cast(mState.bufferTransform)); - error != HWC2::Error::None) { - ALOGE("[%s] Failed to set transform %s: %s (%d)", mLayerFE->getDebugName(), - toString(mState.bufferTransform).c_str(), to_string(error).c_str(), - static_cast(error)); - } + if (auto error = hwcLayer->setSurfaceDamage(outputIndependentState.surfaceDamage); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set surface damage: %s (%d)", mLayerFE->getDebugName(), + to_string(error).c_str(), static_cast(error)); + outputIndependentState.surfaceDamage.dump(LOG_TAG); + } - // Output independent state + // Content-specific per-frame state + switch (outputIndependentState.compositionType) { + case Hwc2::IComposerClient::Composition::SOLID_COLOR: + writeSolidColorStateToHWC(hwcLayer, outputIndependentState); + break; + case Hwc2::IComposerClient::Composition::SIDEBAND: + writeSidebandStateToHWC(hwcLayer, outputIndependentState); + break; + case Hwc2::IComposerClient::Composition::CURSOR: + case Hwc2::IComposerClient::Composition::DEVICE: + writeBufferStateToHWC(hwcLayer, outputIndependentState); + break; + case Hwc2::IComposerClient::Composition::INVALID: + case Hwc2::IComposerClient::Composition::CLIENT: + // Ignored + break; + } +} - const auto& outputIndependentState = mLayer->getState().frontEnd; +void OutputLayer::writeSolidColorStateToHWC(HWC2::Layer* hwcLayer, + const LayerFECompositionState& outputIndependentState) { + hwc_color_t color = {static_cast(std::round(255.0f * outputIndependentState.color.r)), + static_cast(std::round(255.0f * outputIndependentState.color.g)), + static_cast(std::round(255.0f * outputIndependentState.color.b)), + 255}; - if (auto error = hwcLayer->setBlendMode( - static_cast(outputIndependentState.blendMode)); - error != HWC2::Error::None) { - ALOGE("[%s] Failed to set blend mode %s: %s (%d)", mLayerFE->getDebugName(), - toString(outputIndependentState.blendMode).c_str(), to_string(error).c_str(), - static_cast(error)); - } + if (auto error = hwcLayer->setColor(color); error != HWC2::Error::None) { + ALOGE("[%s] Failed to set color: %s (%d)", mLayerFE->getDebugName(), + to_string(error).c_str(), static_cast(error)); + } +} - if (auto error = hwcLayer->setPlaneAlpha(outputIndependentState.alpha); - error != HWC2::Error::None) { - ALOGE("[%s] Failed to set plane alpha %.3f: %s (%d)", mLayerFE->getDebugName(), - outputIndependentState.alpha, to_string(error).c_str(), - static_cast(error)); - } +void OutputLayer::writeSidebandStateToHWC(HWC2::Layer* hwcLayer, + const LayerFECompositionState& outputIndependentState) { + if (auto error = hwcLayer->setSidebandStream(outputIndependentState.sidebandStream->handle()); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mLayerFE->getDebugName(), + outputIndependentState.sidebandStream->handle(), to_string(error).c_str(), + static_cast(error)); + } +} - if (auto error = - hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId); +void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer, + const LayerFECompositionState& outputIndependentState) { + auto supportedPerFrameMetadata = + mOutput.getDisplayColorProfile()->getSupportedPerFrameMetadata(); + if (auto error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata, + outputIndependentState.hdrMetadata); + error != HWC2::Error::None && error != HWC2::Error::Unsupported) { + ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mLayerFE->getDebugName(), + to_string(error).c_str(), static_cast(error)); + } + + uint32_t hwcSlot = 0; + sp hwcBuffer; + // We need access to the output-dependent state for the buffer cache there, + // though otherwise the buffer is not output-dependent. + editState().hwc->hwcBufferCache.getHwcBuffer(outputIndependentState.bufferSlot, + outputIndependentState.buffer, &hwcSlot, + &hwcBuffer); + + if (auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, outputIndependentState.acquireFence); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set buffer %p: %s (%d)", mLayerFE->getDebugName(), + outputIndependentState.buffer->handle, to_string(error).c_str(), + static_cast(error)); + } +} + +void OutputLayer::writeCompositionTypeToHWC( + HWC2::Layer* hwcLayer, Hwc2::IComposerClient::Composition requestedCompositionType) { + auto& outputDependentState = editState(); + + // If we are forcing client composition, we need to tell the HWC + if (outputDependentState.forceClientComposition) { + requestedCompositionType = Hwc2::IComposerClient::Composition::CLIENT; + } + + // Set the requested composition type with the HWC whenever it changes + if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType) { + outputDependentState.hwc->hwcCompositionType = requestedCompositionType; + + if (auto error = hwcLayer->setCompositionType( + static_cast(requestedCompositionType)); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set info %s (%d)", mLayerFE->getDebugName(), - to_string(error).c_str(), static_cast(error)); + ALOGE("[%s] Failed to set composition type %s: %s (%d)", mLayerFE->getDebugName(), + toString(requestedCompositionType).c_str(), to_string(error).c_str(), + static_cast(error)); } } } diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp index 861ea5757b..e320bee4e1 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp @@ -47,6 +47,7 @@ void OutputLayerCompositionState::dump(std::string& out) const { dumpVal(out, "displayFrame", displayFrame); dumpVal(out, "sourceCrop", sourceCrop); dumpVal(out, "bufferTransform", toString(bufferTransform), bufferTransform); + dumpVal(out, "dataspace", toString(dataspace), dataspace); dumpVal(out, "z-index", z); if (hwc) { diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp index 9215884f58..c07dfbb38d 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp @@ -638,5 +638,66 @@ TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHa checkGetBestColorMode(profile, expectedResults); } +/* + * RenderSurface::isDataspaceSupported() + */ + +TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithNoHdrSupport) { + auto profile = ProfileFactory::createProfileWithNoColorModeSupport(); + + EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN)); + EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB)); + EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_PQ)); + EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ)); + EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_HLG)); + EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG)); +} + +TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithHdr10Support) { + auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport(); + + EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN)); + EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB)); + EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_PQ)); + EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ)); + EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_HLG)); + EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG)); +} + +TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithHlgSupport) { + auto profile = ProfileFactory::createProfileWithBT2100PQSupport(); + + EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN)); + EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB)); + EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_PQ)); + EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ)); + EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_HLG)); + EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG)); +} + +/* + * RenderSurface::getTargetDataspace() + */ + +TEST_F(DisplayColorProfileTest, getTargetDataspaceWorks) { + auto profile = ProfileFactory::createProfileWithNoColorModeSupport(); + + // For a non-HDR colorspace with no colorSpaceAgnosticDataspace override, + // the input dataspace should be returned. + EXPECT_EQ(Dataspace::DISPLAY_P3, + profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3, + Dataspace::UNKNOWN)); + + // If colorSpaceAgnosticDataspace is set, its value should be returned + EXPECT_EQ(Dataspace::V0_SRGB, + profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3, + Dataspace::V0_SRGB)); + + // For an HDR colorspace, Dataspace::UNKNOWN should be returned. + EXPECT_EQ(Dataspace::UNKNOWN, + profile.getTargetDataspace(ColorMode::BT2100_PQ, Dataspace::BT2020_PQ, + Dataspace::UNKNOWN)); +} + } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 33444a5df1..f0aea25566 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,7 @@ namespace android::compositionengine { namespace { +using testing::_; using testing::Return; using testing::ReturnRef; using testing::StrictMock; @@ -140,21 +142,27 @@ TEST_F(DisplayTest, setColorTransformSetsTransform) { TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) { mock::RenderSurface* renderSurface = new StrictMock(); mDisplay.setRenderSurfaceForTest(std::unique_ptr(renderSurface)); + mock::DisplayColorProfile* colorProfile = new StrictMock(); + mDisplay.setDisplayColorProfileForTest(std::unique_ptr(colorProfile)); EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer)); + EXPECT_CALL(*colorProfile, getTargetDataspace(_, _, _)) + .WillRepeatedly(Return(ui::Dataspace::UNKNOWN)); // These values are expected to be the initial state. ASSERT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode); ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace); ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent); + ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace); - // Otherwise if the values are unchanged, nothing happens + // If the set values are unchanged, nothing happens mDisplay.setColorMode(ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, - ui::RenderIntent::COLORIMETRIC); + ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN); EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode); EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace); EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent); + EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace); // Otherwise if the values are different, updates happen EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1); @@ -164,23 +172,34 @@ TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) { .Times(1); mDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC); + ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN); EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mDisplay.getState().colorMode); EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mDisplay.getState().dataspace); EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay.getState().renderIntent); + EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace); } TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) { impl::Display virtualDisplay{mCompositionEngine, DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}}; + mock::DisplayColorProfile* colorProfile = new StrictMock(); + virtualDisplay.setDisplayColorProfileForTest( + std::unique_ptr(colorProfile)); + + EXPECT_CALL(*colorProfile, + getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, + ui::Dataspace::UNKNOWN)) + .WillOnce(Return(ui::Dataspace::UNKNOWN)); + virtualDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC); + ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN); EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode); EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay.getState().dataspace); EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay.getState().renderIntent); + EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace); } /* ------------------------------------------------------------------------ diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index ae906cd525..7b9528be9c 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include "MockHWC2.h" #include "MockHWComposer.h" #include "RectMatcher.h" +#include "RegionMatcher.h" namespace android::compositionengine { namespace { @@ -45,6 +47,15 @@ constexpr auto TR_ROT_270 = TR_ROT_90 | TR_ROT_180; const std::string kOutputName{"Test Output"}; +MATCHER_P(ColorEq, expected, "") { + *result_listener << "Colors are not equal\n"; + *result_listener << "expected " << expected.r << " " << expected.g << " " << expected.b << " " + << expected.a << "\n"; + *result_listener << "actual " << arg.r << " " << arg.g << " " << arg.b << " " << arg.a << "\n"; + + return expected.r == arg.r && expected.g == arg.g && expected.b == arg.b && expected.a == arg.a; +} + class OutputLayerTest : public testing::Test { public: OutputLayerTest() { @@ -429,6 +440,9 @@ public: OutputLayerUpdateCompositionStateTest() { EXPECT_CALL(*mLayer, getState()).WillRepeatedly(ReturnRef(mLayerState)); EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState)); + EXPECT_CALL(mOutput, getDisplayColorProfile()) + .WillRepeatedly(Return(&mDisplayColorProfile)); + EXPECT_CALL(mDisplayColorProfile, isDataspaceSupported(_)).WillRepeatedly(Return(true)); } ~OutputLayerUpdateCompositionStateTest() = default; @@ -453,6 +467,7 @@ public: using OutputLayer = OutputLayerPartialMockForUpdateCompositionState; StrictMock mOutputLayer{mOutput, mLayer, mLayerFE}; + StrictMock mDisplayColorProfile; }; TEST_F(OutputLayerUpdateCompositionStateTest, setsStateNormally) { @@ -498,12 +513,50 @@ TEST_F(OutputLayerUpdateCompositionStateTest, EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition); } +TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceCorrectly) { + mLayerState.frontEnd.dataspace = ui::Dataspace::DISPLAY_P3; + mOutputState.targetDataspace = ui::Dataspace::V0_SCRGB; + + // If the layer is not colorspace agnostic, the output layer dataspace + // should use the layers requested colorspace. + mLayerState.frontEnd.isColorspaceAgnostic = false; + + mOutputLayer.updateCompositionState(false); + + EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutputLayer.getState().dataspace); + + // If the layer is colorspace agnostic, the output layer dataspace + // should use the colorspace chosen for the whole output. + mLayerState.frontEnd.isColorspaceAgnostic = true; + + mOutputLayer.updateCompositionState(false); + + EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace); +} + TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) { mOutputLayer.updateCompositionState(false); EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition); } +TEST_F(OutputLayerUpdateCompositionStateTest, clientCompositionForcedFromFrontEndFlagAtAnyTime) { + mLayerState.frontEnd.forceClientComposition = true; + + mOutputLayer.updateCompositionState(false); + + EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition); +} + +TEST_F(OutputLayerUpdateCompositionStateTest, + clientCompositionForcedFromUnsupportedDataspaceAtAnyTime) { + EXPECT_CALL(mDisplayColorProfile, isDataspaceSupported(_)).WillRepeatedly(Return(false)); + + mOutputLayer.updateCompositionState(false); + + EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition); +} + /* * OutputLayer::writeStateToHWC() */ @@ -518,8 +571,19 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static constexpr float kAlpha = 51.f; static constexpr uint32_t kType = 61u; static constexpr uint32_t kAppId = 62u; + static constexpr ui::Dataspace kDataspace = static_cast(71); + static constexpr int kSupportedPerFrameMetadata = 101; + static constexpr int kExpectedHwcSlot = 0; + static const half4 kColor; static const Rect kDisplayFrame; + static const Region kVisibleRegion; + static const mat4 kColorTransform; + static const Region kSurfaceDamage; + static const HdrMetadata kHdrMetadata; + static native_handle_t* kSidebandStreamHandle; + static const sp kBuffer; + static const sp kFence; OutputLayerWriteStateToHWCTest() { auto& outputLayerState = mOutputLayer.editState(); @@ -529,13 +593,31 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { outputLayerState.sourceCrop = kSourceCrop; outputLayerState.z = kZOrder; outputLayerState.bufferTransform = static_cast(kBufferTransform); + outputLayerState.visibleRegion = kVisibleRegion; + outputLayerState.dataspace = kDataspace; mLayerState.frontEnd.blendMode = kBlendMode; mLayerState.frontEnd.alpha = kAlpha; mLayerState.frontEnd.type = kType; mLayerState.frontEnd.appId = kAppId; + mLayerState.frontEnd.colorTransform = kColorTransform; + mLayerState.frontEnd.color = kColor; + mLayerState.frontEnd.surfaceDamage = kSurfaceDamage; + mLayerState.frontEnd.hdrMetadata = kHdrMetadata; + mLayerState.frontEnd.sidebandStream = NativeHandle::create(kSidebandStreamHandle, false); + mLayerState.frontEnd.buffer = kBuffer; + mLayerState.frontEnd.bufferSlot = BufferQueue::INVALID_BUFFER_SLOT; + mLayerState.frontEnd.acquireFence = kFence; + + EXPECT_CALL(mOutput, getDisplayColorProfile()) + .WillRepeatedly(Return(&mDisplayColorProfile)); + EXPECT_CALL(mDisplayColorProfile, getSupportedPerFrameMetadata()) + .WillRepeatedly(Return(kSupportedPerFrameMetadata)); } + // Some tests may need to simulate unsupported HWC calls + enum class SimulateUnsupported { None, ColorTransform }; + void expectGeometryCommonCalls() { EXPECT_CALL(*mHwcLayer, setDisplayFrame(kDisplayFrame)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setSourceCrop(kSourceCrop)).WillOnce(Return(kError)); @@ -549,10 +631,62 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { EXPECT_CALL(*mHwcLayer, setInfo(kType, kAppId)).WillOnce(Return(kError)); } + void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None) { + EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(kVisibleRegion))) + .WillOnce(Return(kError)); + EXPECT_CALL(*mHwcLayer, setDataspace(kDataspace)).WillOnce(Return(kError)); + EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform)) + .WillOnce(Return(unsupported == SimulateUnsupported::ColorTransform + ? HWC2::Error::Unsupported + : HWC2::Error::None)); + EXPECT_CALL(*mHwcLayer, setSurfaceDamage(RegionEq(kSurfaceDamage))) + .WillOnce(Return(kError)); + } + + void expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition compositionType) { + EXPECT_CALL(*mHwcLayer, setCompositionType(static_cast(compositionType))) + .WillOnce(Return(kError)); + } + + void expectNoSetCompositionTypeCall() { + EXPECT_CALL(*mHwcLayer, setCompositionType(_)).Times(0); + } + + void expectSetColorCall() { + hwc_color_t color = {static_cast(std::round(kColor.r * 255)), + static_cast(std::round(kColor.g * 255)), + static_cast(std::round(kColor.b * 255)), 255}; + + EXPECT_CALL(*mHwcLayer, setColor(ColorEq(color))).WillOnce(Return(kError)); + } + + void expectSetSidebandHandleCall() { + EXPECT_CALL(*mHwcLayer, setSidebandStream(kSidebandStreamHandle)); + } + + void expectSetHdrMetadataAndBufferCalls() { + EXPECT_CALL(*mHwcLayer, setPerFrameMetadata(kSupportedPerFrameMetadata, kHdrMetadata)); + EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, kBuffer, kFence)); + } + std::shared_ptr mHwcLayer{std::make_shared>()}; + StrictMock mDisplayColorProfile; }; +const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 83.f / 255.f, + 84.f / 255.f}; const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044}; +const Region OutputLayerWriteStateToHWCTest::kVisibleRegion{Rect{1005, 1006, 1007, 1008}}; +const mat4 OutputLayerWriteStateToHWCTest::kColorTransform{ + 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, + 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, +}; +const Region OutputLayerWriteStateToHWCTest::kSurfaceDamage{Rect{1025, 1026, 1027, 1028}}; +const HdrMetadata OutputLayerWriteStateToHWCTest::kHdrMetadata{{/* LightFlattenable */}, 1029}; +native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle = + reinterpret_cast(1031); +const sp OutputLayerWriteStateToHWCTest::kBuffer; +const sp OutputLayerWriteStateToHWCTest::kFence; TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCState) { mOutputLayer.editState().hwc.reset(); @@ -566,11 +700,89 @@ TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCLayer) { mOutputLayer.writeStateToHWC(true); } -TEST_F(OutputLayerWriteStateToHWCTest, canSetsAllState) { +TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) { expectGeometryCommonCalls(); + expectPerFrameCommonCalls(); + + expectNoSetCompositionTypeCall(); mOutputLayer.writeStateToHWC(true); } +TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) { + mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; + + expectPerFrameCommonCalls(); + expectSetColorCall(); + expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SOLID_COLOR); + + mOutputLayer.writeStateToHWC(false); +} + +TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) { + mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND; + + expectPerFrameCommonCalls(); + expectSetSidebandHandleCall(); + expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SIDEBAND); + + mOutputLayer.writeStateToHWC(false); +} + +TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) { + mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::CURSOR; + + expectPerFrameCommonCalls(); + expectSetHdrMetadataAndBufferCalls(); + expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CURSOR); + + mOutputLayer.writeStateToHWC(false); +} + +TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) { + mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + + expectPerFrameCommonCalls(); + expectSetHdrMetadataAndBufferCalls(); + expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + + mOutputLayer.writeStateToHWC(false); +} + +TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) { + (*mOutputLayer.editState().hwc).hwcCompositionType = + Hwc2::IComposerClient::Composition::SOLID_COLOR; + + mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; + + expectPerFrameCommonCalls(); + expectSetColorCall(); + expectNoSetCompositionTypeCall(); + + mOutputLayer.writeStateToHWC(false); +} + +TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransformNotSupported) { + mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; + + expectPerFrameCommonCalls(SimulateUnsupported::ColorTransform); + expectSetColorCall(); + expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT); + + mOutputLayer.writeStateToHWC(false); +} + +TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompositionForced) { + mOutputLayer.editState().forceClientComposition = true; + + mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; + + expectPerFrameCommonCalls(); + expectSetColorCall(); + expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT); + + mOutputLayer.writeStateToHWC(false); +} + } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index fee0c11e25..6f087d9e54 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -205,24 +205,36 @@ TEST_F(OutputTest, setColorTransformSetsTransform) { */ TEST_F(OutputTest, setColorModeSetsStateAndDirtiesOutputIfChanged) { + EXPECT_CALL(*mDisplayColorProfile, + getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, + ui::Dataspace::UNKNOWN)) + .WillOnce(Return(ui::Dataspace::UNKNOWN)); EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1); mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC); + ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN); EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput.getState().colorMode); EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput.getState().dataspace); EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput.getState().renderIntent); + EXPECT_EQ(ui::Dataspace::UNKNOWN, mOutput.getState().targetDataspace); + EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) { + EXPECT_CALL(*mDisplayColorProfile, + getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, + ui::Dataspace::UNKNOWN)) + .WillOnce(Return(ui::Dataspace::UNKNOWN)); + mOutput.editState().colorMode = ui::ColorMode::DISPLAY_P3; mOutput.editState().dataspace = ui::Dataspace::DISPLAY_P3; mOutput.editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC; + mOutput.editState().targetDataspace = ui::Dataspace::UNKNOWN; mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC); + ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN); EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region())); } diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp index 7927fa95b6..3a5f3faa20 100644 --- a/services/surfaceflinger/ContainerLayer.cpp +++ b/services/surfaceflinger/ContainerLayer.cpp @@ -39,7 +39,4 @@ bool ContainerLayer::canReceiveInput() const { return !isHiddenByPolicy(); } -void ContainerLayer::setPerFrameData(const sp&, const ui::Transform&, - const Rect&, int32_t, const ui::Dataspace) {} - } // namespace android diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h index 7222a3e15a..57267c70c8 100644 --- a/services/surfaceflinger/ContainerLayer.h +++ b/services/surfaceflinger/ContainerLayer.h @@ -33,10 +33,6 @@ public: bool canReceiveInput() const override; - void setPerFrameData(const sp& display, const ui::Transform& transform, - const Rect& viewport, int32_t supportedPerFrameMetadata, - const ui::Dataspace targetDataspace) override; - bool isCreatedFromMainThread() const override { return true; } bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 414c8dd23d..c3da65348d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -242,20 +242,6 @@ sp Layer::getHandle() { // h/w composer set-up // --------------------------------------------------------------------------- -bool Layer::hasHwcLayer(const sp& displayDevice) { - auto outputLayer = findOutputLayerForDisplay(displayDevice); - LOG_FATAL_IF(!outputLayer); - return outputLayer->getState().hwc && (*outputLayer->getState().hwc).hwcLayer != nullptr; -} - -HWC2::Layer* Layer::getHwcLayer(const sp& displayDevice) { - auto outputLayer = findOutputLayerForDisplay(displayDevice); - if (!outputLayer || !outputLayer->getState().hwc) { - return nullptr; - } - return (*outputLayer->getState().hwc).hwcLayer.get(); -} - Rect Layer::getContentCrop() const { // this is the crop rectangle that applies to the buffer // itself (as opposed to the window) @@ -454,29 +440,38 @@ void Layer::latchGeometry(compositionengine::LayerFECompositionState& compositio compositionState.appId = appId; } +void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compositionState) const { + compositionState.forceClientComposition = false; + + // TODO(lpique): b/121291683 Remove this one we are sure we don't need the + // value recomputed / set every frame. + compositionState.geomVisibleRegion = visibleRegion; + + compositionState.isColorspaceAgnostic = isColorSpaceAgnostic(); + compositionState.dataspace = mCurrentDataSpace; + compositionState.colorTransform = getColorTransform(); + compositionState.colorTransformIsIdentity = !hasColorTransform(); + compositionState.surfaceDamage = surfaceDamageRegion; + + // Force client composition for special cases known only to the front-end. + if (isHdrY410() || getRoundedCornerState().radius > 0.0f) { + compositionState.forceClientComposition = true; + } +} + void Layer::latchCompositionState(compositionengine::LayerFECompositionState& compositionState, bool includeGeometry) const { if (includeGeometry) { latchGeometry(compositionState); } + + latchPerFrameState(compositionState); } const char* Layer::getDebugName() const { return mName.string(); } -void Layer::forceClientComposition(const sp& display) { - const auto outputLayer = findOutputLayerForDisplay(display); - LOG_FATAL_IF(!outputLayer); - outputLayer->editState().forceClientComposition = true; -} - -bool Layer::getForceClientComposition(const sp& display) { - const auto outputLayer = findOutputLayerForDisplay(display); - LOG_FATAL_IF(!outputLayer); - return outputLayer->getState().forceClientComposition; -} - void Layer::updateCursorPosition(const sp& display) { const auto outputLayer = findOutputLayerForDisplay(display); LOG_FATAL_IF(!outputLayer); @@ -563,29 +558,6 @@ bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& / return true; } -void Layer::setCompositionType(const sp& display, - Hwc2::IComposerClient::Composition type) { - const auto outputLayer = findOutputLayerForDisplay(display); - LOG_FATAL_IF(!outputLayer); - LOG_FATAL_IF(!outputLayer->getState().hwc); - auto& compositionState = outputLayer->editState(); - - ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", ((*compositionState.hwc).hwcLayer)->getId(), - toString(type).c_str(), 1); - if ((*compositionState.hwc).hwcCompositionType != type) { - ALOGV(" actually setting"); - (*compositionState.hwc).hwcCompositionType = type; - - auto error = (*compositionState.hwc) - .hwcLayer->setCompositionType(static_cast(type)); - ALOGE_IF(error != HWC2::Error::None, - "[%s] Failed to set " - "composition type %s: %s (%d)", - mName.string(), toString(type).c_str(), to_string(error).c_str(), - static_cast(error)); - } -} - Hwc2::IComposerClient::Composition Layer::getCompositionType( const sp& display) const { const auto outputLayer = findOutputLayerForDisplay(display); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index b693a47f39..b1ce86b2dc 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -469,23 +469,13 @@ public: protected: void latchGeometry(compositionengine::LayerFECompositionState& outState) const; + virtual void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const; public: virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {} virtual bool isHdrY410() const { return false; } - void forceClientComposition(const sp& display); - bool getForceClientComposition(const sp& display); - virtual void setPerFrameData(const sp& display, - const ui::Transform& transform, const Rect& viewport, - int32_t supportedPerFrameMetadata, - const ui::Dataspace targetDataspace) = 0; - - // callIntoHwc exists so we can update our local state and call - // acceptDisplayChanges without unnecessarily updating the device's state - void setCompositionType(const sp& display, - Hwc2::IComposerClient::Composition type); Hwc2::IComposerClient::Composition getCompositionType( const sp& display) const; bool getClearClientTarget(const sp& display) const; @@ -607,10 +597,6 @@ public: virtual int32_t getQueuedFrameCount() const { return 0; } // ----------------------------------------------------------------------- - - bool hasHwcLayer(const sp& displayDevice); - HWC2::Layer* getHwcLayer(const sp& displayDevice); - inline const State& getDrawingState() const { return mDrawingState; } inline const State& getCurrentState() const { return mCurrentState; } inline State& getCurrentState() { return mCurrentState; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5b8255667b..7230152e1a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -160,28 +160,6 @@ bool isWideColorMode(const ColorMode colorMode) { return false; } -bool isHdrColorMode(const ColorMode colorMode) { - switch (colorMode) { - case ColorMode::BT2100_PQ: - case ColorMode::BT2100_HLG: - return true; - case ColorMode::DISPLAY_P3: - case ColorMode::ADOBE_RGB: - case ColorMode::DCI_P3: - case ColorMode::BT2020: - case ColorMode::DISPLAY_BT2020: - case ColorMode::NATIVE: - case ColorMode::STANDARD_BT601_625: - case ColorMode::STANDARD_BT601_625_UNADJUSTED: - case ColorMode::STANDARD_BT601_525: - case ColorMode::STANDARD_BT601_525_UNADJUSTED: - case ColorMode::STANDARD_BT709: - case ColorMode::SRGB: - return false; - } - return false; -} - ui::Transform::orientation_flags fromSurfaceComposerRotation(ISurfaceComposer::Rotation rotation) { switch (rotation) { case ISurfaceComposer::eRotateNone: @@ -1153,7 +1131,8 @@ status_t SurfaceFlinger::setActiveColorMode(const sp& displayToken, Col decodeColorMode(mode).c_str(), mode); } else { display->getCompositionDisplay()->setColorMode(mode, Dataspace::UNKNOWN, - RenderIntent::COLORIMETRIC); + RenderIntent::COLORIMETRIC, + Dataspace::UNKNOWN); } })); @@ -1853,104 +1832,80 @@ void SurfaceFlinger::calculateWorkingSet() { ATRACE_CALL(); ALOGV(__FUNCTION__); - // build the h/w work list - if (CC_UNLIKELY(mGeometryInvalid)) { - mGeometryInvalid = false; - for (const auto& [token, displayDevice] : mDisplays) { - auto display = displayDevice->getCompositionDisplay(); + const bool updatingGeometryThisFrame = mGeometryInvalid; + mGeometryInvalid = false; - uint32_t zOrder = 0; + { + // Use a map so that we latch the state of each front-end layer once. + std::unordered_map + uniqueVisibleLayers; + // Figure out which frontend layers are being composed, and build the unique + // set of them (and the corresponding composition layer) + for (const auto& [token, displayDevice] : mDisplays) { + auto display = displayDevice->getCompositionDisplay(); for (auto& layer : display->getOutputLayersOrderedByZ()) { - auto& compositionState = layer->editState(); - compositionState.forceClientComposition = false; - if (!compositionState.hwc || mDebugDisableHWC || mDebugRegion) { - compositionState.forceClientComposition = true; - } - - // The output Z order is set here based on a simple counter. - compositionState.z = zOrder++; + uniqueVisibleLayers.insert(std::make_pair(&layer->getLayerFE(), + &layer->getLayer().editState().frontEnd)); + } + } - // Update the display independent composition state. This goes - // to the general composition layer state structure. - // TODO: Do this once per compositionengine::CompositionLayer. - layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd, - true); + // Update the composition state from each front-end layer. + for (auto& [layerFE, state] : uniqueVisibleLayers) { + layerFE->latchCompositionState(*state, updatingGeometryThisFrame); + } + } - // Recalculate the geometry state of the output layer. - layer->updateCompositionState(true); + if (CC_UNLIKELY(updatingGeometryThisFrame)) { + for (const auto& [token, displayDevice] : mDisplays) { + auto display = displayDevice->getCompositionDisplay(); + uint32_t zOrder = 0; - // Write the updated geometry state to the HWC - layer->writeStateToHWC(true); + for (auto& layer : display->getOutputLayersOrderedByZ()) { + // Assign a simple Z order sequence to each visible layer. + layer->editState().z = zOrder++; } } } - // Set the per-frame data + // Determine the color configuration of each output for (const auto& [token, displayDevice] : mDisplays) { auto display = displayDevice->getCompositionDisplay(); - const auto displayId = display->getId(); - if (!displayId) { - continue; - } - auto* profile = display->getDisplayColorProfile(); - if (mDrawingState.colorMatrixChanged) { - display->setColorTransform(mDrawingState.colorMatrix); - } - Dataspace targetDataspace = Dataspace::UNKNOWN; + ColorMode colorMode = ColorMode::NATIVE; + Dataspace dataspace = Dataspace::UNKNOWN; + RenderIntent renderIntent = RenderIntent::COLORIMETRIC; if (useColorManagement) { - ColorMode colorMode; - RenderIntent renderIntent; - pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent); - display->setColorMode(colorMode, targetDataspace, renderIntent); - - if (isHdrColorMode(colorMode)) { - targetDataspace = Dataspace::UNKNOWN; - } else if (mColorSpaceAgnosticDataspace != Dataspace::UNKNOWN) { - targetDataspace = mColorSpaceAgnosticDataspace; - } + pickColorMode(displayDevice, &colorMode, &dataspace, &renderIntent); } + display->setColorMode(colorMode, dataspace, renderIntent, mColorSpaceAgnosticDataspace); + } - for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { - if (layer->isHdrY410()) { - layer->forceClientComposition(displayDevice); - } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ || - layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) && - !profile->hasHDR10Support()) { - layer->forceClientComposition(displayDevice); - } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG || - layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) && - !profile->hasHLGSupport()) { - layer->forceClientComposition(displayDevice); - } - - if (layer->getRoundedCornerState().radius > 0.0f) { - layer->forceClientComposition(displayDevice); - } - - if (layer->getForceClientComposition(displayDevice)) { - ALOGV("[%s] Requesting Client composition", layer->getName().string()); - layer->setCompositionType(displayDevice, - Hwc2::IComposerClient::Composition::CLIENT); - continue; - } + for (const auto& [token, displayDevice] : mDisplays) { + auto display = displayDevice->getCompositionDisplay(); - const auto& displayState = display->getState(); - layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport, - displayDevice->getSupportedPerFrameMetadata(), targetDataspace); + for (auto& layer : display->getOutputLayersOrderedByZ()) { + // Update the composition state of the output layer, as needed + // recomputing it from the state given by the front-end layer. + layer->updateCompositionState(updatingGeometryThisFrame); } } - mDrawingState.colorMatrixChanged = false; - for (const auto& [token, displayDevice] : mDisplays) { auto display = displayDevice->getCompositionDisplay(); - for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { - auto& layerState = layer->getCompositionLayer()->editState().frontEnd; - layerState.compositionType = static_cast( - layer->getCompositionType(displayDevice)); + + for (auto& layer : display->getOutputLayersOrderedByZ()) { + // Send the updated state to the HWC, if appropriate. + layer->writeStateToHWC(updatingGeometryThisFrame); + } + } + + if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) { + for (const auto& [token, displayDevice] : mDisplays) { + auto display = displayDevice->getCompositionDisplay(); + display->setColorTransform(mDrawingState.colorMatrix); } + mDrawingState.colorMatrixChanged = false; } } @@ -2347,7 +2302,8 @@ Dataspace SurfaceFlinger::getBestDataspace(const sp& display, case Dataspace::BT2020_ITU_PQ: bestDataSpace = Dataspace::DISPLAY_P3; *outHdrDataSpace = Dataspace::BT2020_PQ; - *outIsHdrClientComposition = layer->getForceClientComposition(display); + *outIsHdrClientComposition = + layer->getCompositionLayer()->getState().frontEnd.forceClientComposition; break; case Dataspace::BT2020_HLG: case Dataspace::BT2020_ITU_HLG: @@ -2688,7 +2644,7 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( defaultDataSpace = Dataspace::V0_SRGB; } display->getCompositionDisplay()->setColorMode(defaultColorMode, defaultDataSpace, - RenderIntent::COLORIMETRIC); + RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN); if (!state.isVirtual()) { LOG_ALWAYS_FATAL_IF(!displayId); display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId)); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index e6211c488e..38d70262a7 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -988,7 +988,9 @@ struct RECompositionResultVariant : public CompositionResultBaseVariant { struct ForcedClientCompositionResultVariant : public RECompositionResultVariant { static void setupLayerState(CompositionTest* test, sp layer) { - layer->forceClientComposition(test->mDisplay); + const auto outputLayer = layer->findOutputLayerForDisplay(test->mDisplay); + LOG_FATAL_IF(!outputLayer); + outputLayer->editState().forceClientComposition = true; } template -- GitLab From 0e1c05e6195d728aab007bc7e7a27135007c3c51 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Tue, 29 Jan 2019 18:42:48 -0800 Subject: [PATCH 0086/1255] SF: Refactor onPreComposition Adds LayerFE::onPreComposition call, and adjusts the existing implementation inside SurfaceFlinger to use it, in preparation to moving the loop over to CompositionEngine. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: Ibc0fb1e87d37fabba753f265e70982b5ce70f9f2 --- .../include/compositionengine/LayerFE.h | 6 ++++++ .../include/compositionengine/mock/LayerFE.h | 2 ++ services/surfaceflinger/Layer.h | 6 ------ services/surfaceflinger/SurfaceFlinger.cpp | 9 +++++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 9f635b9a35..1f2cae9c2b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -17,6 +17,7 @@ #pragma once #include +#include namespace android { @@ -30,6 +31,11 @@ struct LayerFECompositionState; // of the front-end layer class LayerFE : public virtual RefBase { public: + // Called before composition starts. Should return true if this layer has + // pending updates which would require an extra display refresh cycle to + // process. + virtual bool onPreComposition(nsecs_t refreshStartTime) = 0; + // Latches the output-independent state. If includeGeometry is false, the // geometry state can be skipped. virtual void latchCompositionState(LayerFECompositionState&, bool includeGeometry) const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index aab18db3c9..952f702e1c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -30,6 +30,8 @@ public: LayerFE(); virtual ~LayerFE(); + MOCK_METHOD1(onPreComposition, bool(nsecs_t)); + MOCK_CONST_METHOD2(latchCompositionState, void(LayerFECompositionState&, bool)); MOCK_METHOD1(onLayerDisplayed, void(const sp&)); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index b1ce86b2dc..d5968ba11e 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -484,12 +484,6 @@ public: virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; } virtual void setTransformHint(uint32_t /*orientation*/) const { } - /* - * called before composition. - * returns true if the layer has pending updates. - */ - virtual bool onPreComposition(nsecs_t refreshStartTime) = 0; - /* * called after composition. * returns true if the layer latched a new buffer this frame. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7230152e1a..adc19c8f81 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1962,8 +1962,13 @@ void SurfaceFlinger::preComposition() bool needExtraInvalidate = false; mDrawingState.traverseInZOrder([&](Layer* layer) { - if (layer->onPreComposition(mRefreshStartTime)) { - needExtraInvalidate = true; + auto compositionLayer = layer->getCompositionLayer(); + if (compositionLayer) { + auto layerFE = compositionLayer->getLayerFE(); + + if (layerFE && layerFE->onPreComposition(mRefreshStartTime)) { + needExtraInvalidate = true; + } } }); -- GitLab From c7ef21b0b83f6f215e81f3fd676137cfa820c162 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Tue, 29 Jan 2019 18:43:00 -0800 Subject: [PATCH 0087/1255] SF: Move/Refactor LayersNeedingFences Refactors the logic for handling layers that are being released by the current display refresh. This is in preparation for moving the logic over to CompositionEngine. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: I52725b1310ecb324e2c1367f0cbd2eddafacbc4a --- .../include/compositionengine/Output.h | 7 +++++++ .../include/compositionengine/impl/Output.h | 4 ++++ .../include/compositionengine/mock/Output.h | 4 ++++ .../CompositionEngine/src/Output.cpp | 8 ++++++++ services/surfaceflinger/DisplayDevice.cpp | 8 -------- services/surfaceflinger/DisplayDevice.h | 4 ---- services/surfaceflinger/SurfaceFlinger.cpp | 15 +++++++++------ 7 files changed, 32 insertions(+), 18 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 591382dcd9..5b9e282276 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -46,6 +46,7 @@ struct OutputCompositionState; class Output { public: using OutputLayers = std::vector>; + using ReleasedLayers = std::vector>; virtual ~Output(); @@ -131,6 +132,12 @@ public: // Gets the ordered set of output layers for this output virtual const OutputLayers& getOutputLayersOrderedByZ() const = 0; + // Sets the new set of layers being released this frame. + virtual void setReleasedLayers(ReleasedLayers&&) = 0; + + // Takes (moves) the set of layers being released this frame. + virtual ReleasedLayers takeReleasedLayers() = 0; + protected: virtual void setDisplayColorProfile(std::unique_ptr) = 0; virtual void setRenderSurface(std::unique_ptr) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index f245936744..20812d258b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -72,6 +72,9 @@ public: void setOutputLayersOrderedByZ(OutputLayers&&) override; const OutputLayers& getOutputLayersOrderedByZ() const override; + void setReleasedLayers(ReleasedLayers&&) override; + ReleasedLayers takeReleasedLayers() override; + // Testing void setDisplayColorProfileForTest(std::unique_ptr); void setRenderSurfaceForTest(std::unique_ptr); @@ -93,6 +96,7 @@ private: std::unique_ptr mRenderSurface; OutputLayers mOutputLayersOrderedByZ; + ReleasedLayers mReleasedLayers; }; } // namespace impl diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index cf82107194..924d72cb00 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -66,8 +66,12 @@ public: std::unique_ptr( std::optional, std::shared_ptr, sp)); + MOCK_METHOD1(setOutputLayersOrderedByZ, void(OutputLayers&&)); MOCK_CONST_METHOD0(getOutputLayersOrderedByZ, OutputLayers&()); + + MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&)); + MOCK_METHOD0(takeReleasedLayers, ReleasedLayers()); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 0725926be4..845e3c6500 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -242,6 +242,14 @@ const Output::OutputLayers& Output::getOutputLayersOrderedByZ() const { return mOutputLayersOrderedByZ; } +void Output::setReleasedLayers(Output::ReleasedLayers&& layers) { + mReleasedLayers = std::move(layers); +} + +Output::ReleasedLayers Output::takeReleasedLayers() { + return std::move(mReleasedLayers); +} + void Output::dirtyEntireOutput() { mState.dirtyRegion.set(mState.bounds); } diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 4a13bfb7ae..d1365627cf 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -126,14 +126,6 @@ const Vector< sp >& DisplayDevice::getVisibleLayersSortedByZ() const { return mVisibleLayersSortedByZ; } -void DisplayDevice::setLayersNeedingFences(const Vector< sp >& layers) { - mLayersNeedingFences = layers; -} - -const Vector< sp >& DisplayDevice::getLayersNeedingFences() const { - return mLayersNeedingFences; -} - // ---------------------------------------------------------------------------- void DisplayDevice::setPowerMode(int mode) { mPowerMode = mode; diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 0067b505e3..8bc19d4447 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -88,8 +88,6 @@ public: void setVisibleLayersSortedByZ(const Vector< sp >& layers); const Vector< sp >& getVisibleLayersSortedByZ() const; - void setLayersNeedingFences(const Vector< sp >& layers); - const Vector< sp >& getLayersNeedingFences() const; void setLayerStack(uint32_t stack); void setDisplaySize(const int newWidth, const int newHeight); @@ -182,8 +180,6 @@ private: // list of visible layers on that display Vector< sp > mVisibleLayersSortedByZ; - // list of layers needing fences - Vector< sp > mLayersNeedingFences; /* * Transaction state diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index adc19c8f81..7a9a9a7a7b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2206,8 +2206,8 @@ void SurfaceFlinger::rebuildLayerStacks() { Region opaqueRegion; Region dirtyRegion; compositionengine::Output::OutputLayers layersSortedByZ; + compositionengine::Output::ReleasedLayers releasedLayers; Vector> deprecated_layersSortedByZ; - Vector> layersNeedingFences; const ui::Transform& tr = displayState.transform; const Rect bounds = displayState.bounds; if (displayState.isEnabled) { @@ -2255,16 +2255,16 @@ void SurfaceFlinger::rebuildLayerStacks() { layer) != mLayersWithQueuedFrames.cend(); if (hasExistingOutputLayer && hasQueuedFrames) { - layersNeedingFences.add(layer); + releasedLayers.push_back(layer); } } }); } display->setOutputLayersOrderedByZ(std::move(layersSortedByZ)); + display->setReleasedLayers(std::move(releasedLayers)); displayDevice->setVisibleLayersSortedByZ(deprecated_layersSortedByZ); - displayDevice->setLayersNeedingFences(layersNeedingFences); Region undefinedRegion{bounds}; undefinedRegion.subtractSelf(tr.transform(opaqueRegion)); @@ -2500,11 +2500,14 @@ void SurfaceFlinger::postFramebuffer(const sp& displayDevice) { // We've got a list of layers needing fences, that are disjoint with // display->getVisibleLayersSortedByZ. The best we can do is to // supply them with the present fence. - if (!displayDevice->getLayersNeedingFences().isEmpty()) { + auto releasedLayers = display->takeReleasedLayers(); + if (!releasedLayers.empty()) { sp presentFence = displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE; - for (auto& layer : displayDevice->getLayersNeedingFences()) { - layer->getCompositionLayer()->getLayerFE()->onLayerDisplayed(presentFence); + for (auto& weakLayer : releasedLayers) { + if (auto layer = weakLayer.promote(); layer != nullptr) { + layer->onLayerDisplayed(presentFence); + } } } -- GitLab From 843f2601a70e12db78628ccb1d98c8c5dd088563 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Thu, 18 Jul 2019 12:54:28 -0700 Subject: [PATCH 0088/1255] Remove unnecessary dependencies on libsigchain. surfaceflinger was required to link against libsigchain to dlopen libart.so for a debugging option that was removed in change Ib9a129329f7bd8d67b954e58810807c683b20b48. gpuservice accidentally linked against it, presumably due to copy/paste from the surfaceflinger Android.bp file. Bug: http://b/120782499 Bug: http://b/135284876 Test: treehugger Change-Id: I593c5483c8c096ac95f310c68f53000e06621d8b --- services/gpuservice/Android.bp | 3 --- services/surfaceflinger/Android.bp | 3 --- services/surfaceflinger/version-script32.txt | 12 ------------ services/surfaceflinger/version-script64.txt | 11 ----------- 4 files changed, 29 deletions(-) delete mode 100644 services/surfaceflinger/version-script32.txt delete mode 100644 services/surfaceflinger/version-script64.txt diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp index dbb6ba6719..7b8e0f835c 100644 --- a/services/gpuservice/Android.bp +++ b/services/gpuservice/Android.bp @@ -59,9 +59,6 @@ cc_defaults { cc_defaults { name: "gpuservice_binary", defaults: ["gpuservice_defaults"], - whole_static_libs: [ - "libsigchain", - ], shared_libs: [ "libbinder", "libcutils", diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 6e953f4af6..965d8f4f0e 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -187,9 +187,6 @@ cc_defaults { cflags: [ "-DLOG_TAG=\"SurfaceFlinger\"", ], - whole_static_libs: [ - "libsigchain", - ], shared_libs: [ "android.frameworks.displayservice@1.0", "android.hardware.configstore-utils", diff --git a/services/surfaceflinger/version-script32.txt b/services/surfaceflinger/version-script32.txt deleted file mode 100644 index 2340785c42..0000000000 --- a/services/surfaceflinger/version-script32.txt +++ /dev/null @@ -1,12 +0,0 @@ -{ -global: - EnsureFrontOfChain; - AddSpecialSignalHandlerFn; - RemoveSpecialSignalHandlerFn; - bsd_signal; - sigaction; - signal; - sigprocmask; -local: - *; -}; diff --git a/services/surfaceflinger/version-script64.txt b/services/surfaceflinger/version-script64.txt deleted file mode 100644 index acf36309ea..0000000000 --- a/services/surfaceflinger/version-script64.txt +++ /dev/null @@ -1,11 +0,0 @@ -{ -global: - EnsureFrontOfChain; - AddSpecialSignalHandlerFn; - RemoveSpecialSignalHandlerFn; - sigaction; - signal; - sigprocmask; -local: - *; -}; -- GitLab From 456bbb2a5ecfadbdc639e0a2b671802401d3c663 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 18 Jul 2019 16:02:00 -0700 Subject: [PATCH 0089/1255] Add more layer state changes to SurfaceInterceptor Track flag set and clear state changes. Track reparenting, detach children and relative z changes. Test: run surface interceptor and view results Test: atest SurfaceFlinger_test:SurfaceInterceptorTest#* Change-Id: I0c55e6d45034e180a3c8970c60af21bf8f2bb01c --- cmds/surfacereplayer/proto/src/trace.proto | 21 +++ cmds/surfacereplayer/replayer/Replayer.cpp | 44 ++++++ cmds/surfacereplayer/replayer/Replayer.h | 8 + .../surfaceflinger/SurfaceInterceptor.cpp | 93 ++++++++++-- services/surfaceflinger/SurfaceInterceptor.h | 15 +- .../tests/SurfaceInterceptor_test.cpp | 137 ++++++++++++++++-- 6 files changed, 291 insertions(+), 27 deletions(-) diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto index c70bc3e5c1..a738527fbb 100644 --- a/cmds/surfacereplayer/proto/src/trace.proto +++ b/cmds/surfacereplayer/proto/src/trace.proto @@ -46,6 +46,10 @@ message SurfaceChange { SecureFlagChange secure_flag = 14; DeferredTransactionChange deferred_transaction = 15; CornerRadiusChange corner_radius = 16; + ReparentChange reparent = 17; + RelativeParentChange relative_parent = 18; + DetachChildrenChange detach_children = 19; + ReparentChildrenChange reparent_children = 20; } } @@ -177,3 +181,20 @@ message PowerModeUpdate { required int32 id = 1; required int32 mode = 2; } + +message ReparentChange { + required int32 parent_id = 1; +} + +message ReparentChildrenChange { + required int32 parent_id = 1; +} + +message RelativeParentChange { + required int32 relative_parent_id = 1; + required int32 z = 2; +} + +message DetachChildrenChange { + required bool detach_children = 1; +} diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index 34886a99e9..a4a9b6a6f4 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -412,6 +412,18 @@ status_t Replayer::doSurfaceTransaction( setDeferredTransaction(transaction, change.id(), change.deferred_transaction()); break; + case SurfaceChange::SurfaceChangeCase::kReparent: + setReparentChange(transaction, change.id(), change.reparent()); + break; + case SurfaceChange::SurfaceChangeCase::kReparentChildren: + setReparentChildrenChange(transaction, change.id(), change.reparent_children()); + break; + case SurfaceChange::SurfaceChangeCase::kRelativeParent: + setRelativeParentChange(transaction, change.id(), change.relative_parent()); + break; + case SurfaceChange::SurfaceChangeCase::kDetachChildren: + setDetachChildrenChange(transaction, change.id(), change.detach_children()); + break; default: status = 1; break; @@ -680,3 +692,35 @@ status_t Replayer::loadSurfaceComposerClient() { mComposerClient = new SurfaceComposerClient; return mComposerClient->initCheck(); } + +void Replayer::setReparentChange(SurfaceComposerClient::Transaction& t, + layer_id id, const ReparentChange& c) { + sp newParentHandle = nullptr; + if (mLayers.count(c.parent_id()) != 0 && mLayers[c.parent_id()] != nullptr) { + newParentHandle = mLayers[c.parent_id()]->getHandle(); + } + t.reparent(mLayers[id], newParentHandle); +} + +void Replayer::setRelativeParentChange(SurfaceComposerClient::Transaction& t, + layer_id id, const RelativeParentChange& c) { + if (mLayers.count(c.relative_parent_id()) == 0 || mLayers[c.relative_parent_id()] == nullptr) { + ALOGE("Layer %d not found in set relative parent transaction", c.relative_parent_id()); + return; + } + t.setRelativeLayer(mLayers[id], mLayers[c.relative_parent_id()]->getHandle(), c.z()); +} + +void Replayer::setDetachChildrenChange(SurfaceComposerClient::Transaction& t, + layer_id id, const DetachChildrenChange& c) { + t.detachChildren(mLayers[id]); +} + +void Replayer::setReparentChildrenChange(SurfaceComposerClient::Transaction& t, + layer_id id, const ReparentChildrenChange& c) { + if (mLayers.count(c.parent_id()) == 0 || mLayers[c.parent_id()] == nullptr) { + ALOGE("Layer %d not found in reparent children transaction", c.parent_id()); + return; + } + t.reparentChildren(mLayers[id], mLayers[c.parent_id()]->getHandle()); +} diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h index ad807ee950..d7709cc211 100644 --- a/cmds/surfacereplayer/replayer/Replayer.h +++ b/cmds/surfacereplayer/replayer/Replayer.h @@ -108,6 +108,14 @@ class Replayer { layer_id id, const SecureFlagChange& sfc); void setDeferredTransaction(SurfaceComposerClient::Transaction& t, layer_id id, const DeferredTransactionChange& dtc); + void setReparentChange(SurfaceComposerClient::Transaction& t, + layer_id id, const ReparentChange& c); + void setRelativeParentChange(SurfaceComposerClient::Transaction& t, + layer_id id, const RelativeParentChange& c); + void setDetachChildrenChange(SurfaceComposerClient::Transaction& t, + layer_id id, const DetachChildrenChange& c); + void setReparentChildrenChange(SurfaceComposerClient::Transaction& t, + layer_id id, const ReparentChildrenChange& c); void setDisplaySurface(SurfaceComposerClient::Transaction& t, display_id id, const DispSurfaceChange& dsc); diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index 7bfe0338f7..a02d14cc4d 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -116,7 +116,14 @@ void SurfaceInterceptor::addInitialSurfaceStateLocked(Increment* increment, layer->mCurrentState.frameNumber_legacy); } addOverrideScalingModeLocked(transaction, layerId, layer->getEffectiveScalingMode()); - addFlagsLocked(transaction, layerId, layer->mCurrentState.flags); + addFlagsLocked(transaction, layerId, layer->mCurrentState.flags, + layer_state_t::eLayerHidden | layer_state_t::eLayerOpaque | + layer_state_t::eLayerSecure); + addReparentLocked(transaction, layerId, getLayerIdFromWeakRef(layer->mCurrentParent)); + addDetachChildrenLocked(transaction, layerId, layer->isLayerDetached()); + addRelativeParentLocked(transaction, layerId, + getLayerIdFromWeakRef(layer->mCurrentState.zOrderRelativeOf), + layer->mCurrentState.z); } void SurfaceInterceptor::addInitialDisplayStateLocked(Increment* increment, @@ -150,7 +157,7 @@ status_t SurfaceInterceptor::writeProtoFileLocked() { return NO_ERROR; } -const sp SurfaceInterceptor::getLayer(const wp& weakHandle) { +const sp SurfaceInterceptor::getLayer(const wp& weakHandle) const { const sp& handle(weakHandle.promote()); const auto layerHandle(static_cast(handle.get())); const sp layer(layerHandle->owner.promote()); @@ -158,14 +165,31 @@ const sp SurfaceInterceptor::getLayer(const wp& weak return layer; } -const std::string SurfaceInterceptor::getLayerName(const sp& layer) { +const std::string SurfaceInterceptor::getLayerName(const sp& layer) const { return layer->getName().string(); } -int32_t SurfaceInterceptor::getLayerId(const sp& layer) { +int32_t SurfaceInterceptor::getLayerId(const sp& layer) const { return layer->sequence; } +int32_t SurfaceInterceptor::getLayerIdFromWeakRef(const wp& layer) const { + if (layer == nullptr) { + return -1; + } + auto strongLayer = layer.promote(); + return strongLayer == nullptr ? -1 : getLayerId(strongLayer); +} + +int32_t SurfaceInterceptor::getLayerIdFromHandle(const sp& handle) const { + if (handle == nullptr) { + return -1; + } + const auto layerHandle(static_cast(handle.get())); + const sp layer(layerHandle->owner.promote()); + return layer == nullptr ? -1 : getLayerId(layer); +} + Increment* SurfaceInterceptor::createTraceIncrementLocked() { Increment* increment(mTrace.add_increment()); increment->set_time_stamp(systemTime()); @@ -252,24 +276,23 @@ void SurfaceInterceptor::addTransparentRegionLocked(Transaction* transaction, } } -void SurfaceInterceptor::addFlagsLocked(Transaction* transaction, int32_t layerId, - uint8_t flags) -{ +void SurfaceInterceptor::addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags, + uint8_t mask) { // There can be multiple flags changed - if (flags & layer_state_t::eLayerHidden) { + if (mask & layer_state_t::eLayerHidden) { SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); HiddenFlagChange* flagChange(change->mutable_hidden_flag()); - flagChange->set_hidden_flag(true); + flagChange->set_hidden_flag(flags & layer_state_t::eLayerHidden); } - if (flags & layer_state_t::eLayerOpaque) { + if (mask & layer_state_t::eLayerOpaque) { SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); OpaqueFlagChange* flagChange(change->mutable_opaque_flag()); - flagChange->set_opaque_flag(true); + flagChange->set_opaque_flag(flags & layer_state_t::eLayerOpaque); } - if (flags & layer_state_t::eLayerSecure) { + if (mask & layer_state_t::eLayerSecure) { SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); SecureFlagChange* flagChange(change->mutable_secure_flag()); - flagChange->set_secure_flag(true); + flagChange->set_secure_flag(flags & layer_state_t::eLayerSecure); } } @@ -320,6 +343,35 @@ void SurfaceInterceptor::addOverrideScalingModeLocked(Transaction* transaction, overrideChange->set_override_scaling_mode(overrideScalingMode); } +void SurfaceInterceptor::addReparentLocked(Transaction* transaction, int32_t layerId, + int32_t parentId) { + SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); + ReparentChange* overrideChange(change->mutable_reparent()); + overrideChange->set_parent_id(parentId); +} + +void SurfaceInterceptor::addReparentChildrenLocked(Transaction* transaction, int32_t layerId, + int32_t parentId) { + SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); + ReparentChildrenChange* overrideChange(change->mutable_reparent_children()); + overrideChange->set_parent_id(parentId); +} + +void SurfaceInterceptor::addDetachChildrenLocked(Transaction* transaction, int32_t layerId, + bool detached) { + SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); + DetachChildrenChange* overrideChange(change->mutable_detach_children()); + overrideChange->set_detach_children(detached); +} + +void SurfaceInterceptor::addRelativeParentLocked(Transaction* transaction, int32_t layerId, + int32_t parentId, int z) { + SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); + RelativeParentChange* overrideChange(change->mutable_relative_parent()); + overrideChange->set_relative_parent_id(parentId); + overrideChange->set_z(z); +} + void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction, const layer_state_t& state) { @@ -351,7 +403,7 @@ void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction, addTransparentRegionLocked(transaction, layerId, state.transparentRegion); } if (state.what & layer_state_t::eFlagsChanged) { - addFlagsLocked(transaction, layerId, state.flags); + addFlagsLocked(transaction, layerId, state.flags, state.mask); } if (state.what & layer_state_t::eLayerStackChanged) { addLayerStackLocked(transaction, layerId, state.layerStack); @@ -380,6 +432,19 @@ void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction, if (state.what & layer_state_t::eOverrideScalingModeChanged) { addOverrideScalingModeLocked(transaction, layerId, state.overrideScalingMode); } + if (state.what & layer_state_t::eReparent) { + addReparentLocked(transaction, layerId, getLayerIdFromHandle(state.parentHandleForChild)); + } + if (state.what & layer_state_t::eReparentChildren) { + addReparentChildrenLocked(transaction, layerId, getLayerIdFromHandle(state.reparentHandle)); + } + if (state.what & layer_state_t::eDetachChildren) { + addDetachChildrenLocked(transaction, layerId, true); + } + if (state.what & layer_state_t::eRelativeLayerChanged) { + addRelativeParentLocked(transaction, layerId, + getLayerIdFromHandle(state.relativeLayerHandle), state.z); + } } void SurfaceInterceptor::addDisplayChangesLocked(Transaction* transaction, diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h index 563a44c088..7f86c1423a 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -116,9 +116,11 @@ private: void addInitialDisplayStateLocked(Increment* increment, const DisplayDeviceState& display); status_t writeProtoFileLocked(); - const sp getLayer(const wp& weakHandle); - const std::string getLayerName(const sp& layer); - int32_t getLayerId(const sp& layer); + const sp getLayer(const wp& weakHandle) const; + const std::string getLayerName(const sp& layer) const; + int32_t getLayerId(const sp& layer) const; + int32_t getLayerIdFromWeakRef(const wp& layer) const; + int32_t getLayerIdFromHandle(const sp& weakHandle) const; Increment* createTraceIncrementLocked(); void addSurfaceCreationLocked(Increment* increment, const sp& layer); @@ -141,7 +143,7 @@ private: const layer_state_t::matrix22_t& matrix); void addTransparentRegionLocked(Transaction* transaction, int32_t layerId, const Region& transRegion); - void addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags); + void addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags, uint8_t mask); void addLayerStackLocked(Transaction* transaction, int32_t layerId, uint32_t layerStack); void addCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect); void addCornerRadiusLocked(Transaction* transaction, int32_t layerId, float cornerRadius); @@ -153,6 +155,11 @@ private: void addTransactionLocked(Increment* increment, const Vector& stateUpdates, const DefaultKeyedVector< wp, DisplayDeviceState>& displays, const Vector& changedDisplays, uint32_t transactionFlags); + void addReparentLocked(Transaction* transaction, int32_t layerId, int32_t parentId); + void addReparentChildrenLocked(Transaction* transaction, int32_t layerId, int32_t parentId); + void addDetachChildrenLocked(Transaction* transaction, int32_t layerId, bool detached); + void addRelativeParentLocked(Transaction* transaction, int32_t layerId, int32_t parentId, + int z); // Add display transactions to the trace DisplayChange* createDisplayChangeLocked(Transaction* transaction, int32_t sequenceId); diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 5cc946aa79..26c6da95dd 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -43,14 +43,17 @@ constexpr uint32_t LAYER_UPDATE = INT_MAX - 2; constexpr uint32_t SIZE_UPDATE = 134; constexpr uint32_t STACK_UPDATE = 1; constexpr uint64_t DEFERRED_UPDATE = 0; +constexpr int32_t RELATIVE_Z = 42; constexpr float ALPHA_UPDATE = 0.29f; constexpr float CORNER_RADIUS_UPDATE = 0.2f; constexpr float POSITION_UPDATE = 121; const Rect CROP_UPDATE(16, 16, 32, 32); const String8 DISPLAY_NAME("SurfaceInterceptor Display Test"); -constexpr auto TEST_SURFACE_NAME = "BG Interceptor Test Surface"; -constexpr auto UNIQUE_TEST_SURFACE_NAME = "BG Interceptor Test Surface#0"; +constexpr auto TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface"; +constexpr auto TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface"; +constexpr auto UNIQUE_TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface#0"; +constexpr auto UNIQUE_TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface#0"; constexpr auto LAYER_NAME = "Layer Create and Delete Test"; constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0"; @@ -136,12 +139,15 @@ protected: void TearDown() override { mComposerClient->dispose(); mBGSurfaceControl.clear(); + mFGSurfaceControl.clear(); mComposerClient.clear(); } sp mComposerClient; sp mBGSurfaceControl; + sp mFGSurfaceControl; int32_t mBGLayerId; + int32_t mFGLayerId; public: using TestTransactionAction = void (SurfaceInterceptorTest::*)(Transaction&); @@ -177,6 +183,10 @@ public: bool opaqueFlagUpdateFound(const SurfaceChange& change, bool foundOpaqueFlag); bool secureFlagUpdateFound(const SurfaceChange& change, bool foundSecureFlag); bool deferredTransactionUpdateFound(const SurfaceChange& change, bool foundDeferred); + bool reparentUpdateFound(const SurfaceChange& change, bool found); + bool relativeParentUpdateFound(const SurfaceChange& change, bool found); + bool detachChildrenUpdateFound(const SurfaceChange& change, bool found); + bool reparentChildrenUpdateFound(const SurfaceChange& change, bool found); bool surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase); // Find all of the updates in the single trace @@ -209,6 +219,10 @@ public: void opaqueFlagUpdate(Transaction&); void secureFlagUpdate(Transaction&); void deferredTransactionUpdate(Transaction&); + void reparentUpdate(Transaction&); + void relativeParentUpdate(Transaction&); + void detachChildrenUpdate(Transaction&); + void reparentChildrenUpdate(Transaction&); void surfaceCreation(Transaction&); void displayCreation(Transaction&); void displayDeletion(Transaction&); @@ -250,21 +264,30 @@ void SurfaceInterceptorTest::setupBackgroundSurface() { ssize_t displayHeight = info.h; // Background surface - mBGSurfaceControl = mComposerClient->createSurface( - String8(TEST_SURFACE_NAME), displayWidth, displayHeight, - PIXEL_FORMAT_RGBA_8888, 0); + mBGSurfaceControl = mComposerClient->createSurface(String8(TEST_BG_SURFACE_NAME), displayWidth, + displayHeight, 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); + ASSERT_TRUE(mFGSurfaceControl != nullptr); + ASSERT_TRUE(mFGSurfaceControl->isValid()); + Transaction t; t.setDisplayLayerStack(display, 0); - ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3) - .show(mBGSurfaceControl) - .apply()); + ASSERT_EQ(NO_ERROR, + t.setLayer(mBGSurfaceControl, INT_MAX - 3) + .show(mBGSurfaceControl) + .setLayer(mFGSurfaceControl, INT_MAX - 3) + .show(mFGSurfaceControl) + .apply()); } void SurfaceInterceptorTest::preProcessTrace(const Trace& trace) { - mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_SURFACE_NAME); + mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_BG_SURFACE_NAME); + mFGLayerId = getSurfaceId(trace, UNIQUE_TEST_FG_SURFACE_NAME); } void SurfaceInterceptorTest::captureTest(TestTransactionAction action, @@ -364,6 +387,22 @@ void SurfaceInterceptorTest::deferredTransactionUpdate(Transaction& t) { DEFERRED_UPDATE); } +void SurfaceInterceptorTest::reparentUpdate(Transaction& t) { + t.reparent(mBGSurfaceControl, mFGSurfaceControl->getHandle()); +} + +void SurfaceInterceptorTest::relativeParentUpdate(Transaction& t) { + t.setRelativeLayer(mBGSurfaceControl, mFGSurfaceControl->getHandle(), RELATIVE_Z); +} + +void SurfaceInterceptorTest::detachChildrenUpdate(Transaction& t) { + t.detachChildren(mBGSurfaceControl); +} + +void SurfaceInterceptorTest::reparentChildrenUpdate(Transaction& t) { + t.reparentChildren(mBGSurfaceControl, mFGSurfaceControl->getHandle()); +} + void SurfaceInterceptorTest::displayCreation(Transaction&) { sp testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true); SurfaceComposerClient::destroyDisplay(testDisplay); @@ -389,6 +428,10 @@ void SurfaceInterceptorTest::runAllUpdates() { runInTransaction(&SurfaceInterceptorTest::opaqueFlagUpdate); runInTransaction(&SurfaceInterceptorTest::secureFlagUpdate); runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate); + runInTransaction(&SurfaceInterceptorTest::reparentUpdate); + runInTransaction(&SurfaceInterceptorTest::reparentChildrenUpdate); + runInTransaction(&SurfaceInterceptorTest::detachChildrenUpdate); + runInTransaction(&SurfaceInterceptorTest::relativeParentUpdate); } void SurfaceInterceptorTest::surfaceCreation(Transaction&) { @@ -569,6 +612,46 @@ bool SurfaceInterceptorTest::deferredTransactionUpdateFound(const SurfaceChange& return foundDeferred; } +bool SurfaceInterceptorTest::reparentUpdateFound(const SurfaceChange& change, bool found) { + bool hasId(change.reparent().parent_id() == mFGLayerId); + if (hasId && !found) { + found = true; + } else if (hasId && found) { + []() { FAIL(); }(); + } + return found; +} + +bool SurfaceInterceptorTest::relativeParentUpdateFound(const SurfaceChange& change, bool found) { + bool hasId(change.relative_parent().relative_parent_id() == mFGLayerId); + if (hasId && !found) { + found = true; + } else if (hasId && found) { + []() { FAIL(); }(); + } + return found; +} + +bool SurfaceInterceptorTest::detachChildrenUpdateFound(const SurfaceChange& change, bool found) { + bool detachChildren(change.detach_children().detach_children()); + if (detachChildren && !found) { + found = true; + } else if (detachChildren && found) { + []() { FAIL(); }(); + } + return found; +} + +bool SurfaceInterceptorTest::reparentChildrenUpdateFound(const SurfaceChange& change, bool found) { + bool hasId(change.reparent_children().parent_id() == mFGLayerId); + if (hasId && !found) { + found = true; + } else if (hasId && found) { + []() { FAIL(); }(); + } + return found; +} + bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase) { bool foundUpdate = false; @@ -620,6 +703,18 @@ bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace, case SurfaceChange::SurfaceChangeCase::kDeferredTransaction: foundUpdate = deferredTransactionUpdateFound(change, foundUpdate); break; + case SurfaceChange::SurfaceChangeCase::kReparent: + foundUpdate = reparentUpdateFound(change, foundUpdate); + break; + case SurfaceChange::SurfaceChangeCase::kReparentChildren: + foundUpdate = reparentChildrenUpdateFound(change, foundUpdate); + break; + case SurfaceChange::SurfaceChangeCase::kRelativeParent: + foundUpdate = relativeParentUpdateFound(change, foundUpdate); + break; + case SurfaceChange::SurfaceChangeCase::kDetachChildren: + foundUpdate = detachChildrenUpdateFound(change, foundUpdate); + break; case SurfaceChange::SurfaceChangeCase::SURFACECHANGE_NOT_SET: break; } @@ -644,6 +739,10 @@ void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) { ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kOpaqueFlag)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kSecureFlag)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kDeferredTransaction)); + ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparent)); + ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparentChildren)); + ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kRelativeParent)); + ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kDetachChildren)); } bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) { @@ -798,6 +897,26 @@ TEST_F(SurfaceInterceptorTest, InterceptDeferredTransactionUpdateWorks) { SurfaceChange::SurfaceChangeCase::kDeferredTransaction); } +TEST_F(SurfaceInterceptorTest, InterceptReparentUpdateWorks) { + captureTest(&SurfaceInterceptorTest::reparentUpdate, + SurfaceChange::SurfaceChangeCase::kReparent); +} + +TEST_F(SurfaceInterceptorTest, InterceptReparentChildrenUpdateWorks) { + captureTest(&SurfaceInterceptorTest::reparentChildrenUpdate, + SurfaceChange::SurfaceChangeCase::kReparentChildren); +} + +TEST_F(SurfaceInterceptorTest, InterceptRelativeParentUpdateWorks) { + captureTest(&SurfaceInterceptorTest::relativeParentUpdate, + SurfaceChange::SurfaceChangeCase::kRelativeParent); +} + +TEST_F(SurfaceInterceptorTest, InterceptDetachChildrenUpdateWorks) { + captureTest(&SurfaceInterceptorTest::detachChildrenUpdate, + SurfaceChange::SurfaceChangeCase::kDetachChildren); +} + TEST_F(SurfaceInterceptorTest, InterceptAllUpdatesWorks) { captureTest(&SurfaceInterceptorTest::runAllUpdates, &SurfaceInterceptorTest::assertAllUpdatesFound); -- GitLab From ab039b556453a8f87c597fe48f45237cf2a3b4e7 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Wed, 13 Feb 2019 14:22:42 -0800 Subject: [PATCH 0090/1255] SF: Move preComposition to CompositionEngine This moves SurfaceFlinger::preComposition() to CompositionEngine::preComposition(). As part of the move, CompositionRefreshArgs is also introduced, and to start contains an array of outputs (not yet used), and potentially visible layers. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: I0888bd6de1214381222bbae0da93bf966392b303 --- .../compositionengine/CompositionEngine.h | 9 ++ .../CompositionRefreshArgs.h | 40 ++++++++ .../include/compositionengine/Layer.h | 9 +- .../impl/CompositionEngine.h | 10 ++ .../mock/CompositionEngine.h | 6 ++ .../src/CompositionEngine.cpp | 33 +++++++ .../tests/CompositionEngineTest.cpp | 91 ++++++++++++++++++- services/surfaceflinger/SurfaceFlinger.cpp | 49 ++++------ services/surfaceflinger/SurfaceFlinger.h | 1 - 9 files changed, 207 insertions(+), 41 deletions(-) create mode 100644 services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h index 896f8aaa69..31d6365bf4 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h @@ -18,6 +18,8 @@ #include +#include + namespace android { class HWComposer; @@ -31,6 +33,7 @@ namespace compositionengine { class Display; class Layer; +struct CompositionRefreshArgs; struct DisplayCreationArgs; struct LayerCreationArgs; @@ -51,6 +54,12 @@ public: virtual renderengine::RenderEngine& getRenderEngine() const = 0; virtual void setRenderEngine(std::unique_ptr) = 0; + + virtual bool needsAnotherUpdate() const = 0; + virtual nsecs_t getLastFrameRefreshTimestamp() const = 0; + + // TODO(b/121291683): These will become private/internal + virtual void preComposition(CompositionRefreshArgs&) = 0; }; } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h new file mode 100644 index 0000000000..20f131e56d --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.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 +#include + +namespace android::compositionengine { + +using Layers = std::vector>; +using Outputs = std::vector>; + +/** + * A parameter object for refreshing a set of outputs + */ +struct CompositionRefreshArgs { + // All the outputs being refreshed + Outputs outputs; + + // All the layers that are potentially visible in the outputs. The order of + // the layers is important, and should be in traversal order from back to + // front. + Layers layers; +}; + +} // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h index 8cb92034f6..451608b2ae 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h @@ -21,11 +21,7 @@ #include -namespace android { - -typedef int64_t nsecs_t; - -namespace compositionengine { +namespace android::compositionengine { class Display; class LayerFE; @@ -62,5 +58,4 @@ public: virtual void dump(std::string& result) const = 0; }; -} // namespace compositionengine -} // namespace android +} // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h index b01eb649d8..96e609d1c9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h @@ -36,9 +36,19 @@ public: renderengine::RenderEngine& getRenderEngine() const override; void setRenderEngine(std::unique_ptr) override; + bool needsAnotherUpdate() const override; + nsecs_t getLastFrameRefreshTimestamp() const override; + + void preComposition(CompositionRefreshArgs&) override; + + // Testing + void setNeedsAnotherUpdateForTest(bool); + private: std::unique_ptr mHwComposer; std::unique_ptr mRenderEngine; + bool mNeedsAnotherUpdate = false; + nsecs_t mRefreshStartTime = 0; }; std::unique_ptr createCompositionEngine(); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h index 0f57685861..82ecec502d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include #include @@ -39,6 +40,11 @@ public: MOCK_CONST_METHOD0(getRenderEngine, renderengine::RenderEngine&()); MOCK_METHOD1(setRenderEngine, void(std::unique_ptr)); + + MOCK_CONST_METHOD0(needsAnotherUpdate, bool()); + MOCK_CONST_METHOD0(getLastFrameRefreshTimestamp, nsecs_t()); + + MOCK_METHOD1(preComposition, void(CompositionRefreshArgs&)); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp index cb08b81627..9558266a34 100644 --- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp +++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp @@ -14,10 +14,13 @@ * limitations under the License. */ +#include +#include #include #include #include #include +#include #include "DisplayHardware/HWComposer.h" @@ -59,5 +62,35 @@ void CompositionEngine::setRenderEngine(std::unique_ptr layerFE = layer->getLayerFE(); + if (layerFE && layerFE->onPreComposition(mRefreshStartTime)) { + needsAnotherUpdate = true; + } + } + + mNeedsAnotherUpdate = needsAnotherUpdate; +} + +void CompositionEngine::setNeedsAnotherUpdateForTest(bool value) { + mNeedsAnotherUpdate = value; +} + } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp index 3766f27ce6..0dbf8f0781 100644 --- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp @@ -14,7 +14,11 @@ * limitations under the License. */ +#include #include +#include +#include +#include #include #include @@ -23,19 +27,19 @@ namespace android::compositionengine { namespace { +using ::testing::_; +using ::testing::Return; +using ::testing::SaveArg; using ::testing::StrictMock; class CompositionEngineTest : public testing::Test { public: - ~CompositionEngineTest() override; - mock::HWComposer* mHwc = new StrictMock(); + android::mock::HWComposer* mHwc = new StrictMock(); renderengine::mock::RenderEngine* mRenderEngine = new StrictMock(); impl::CompositionEngine mEngine; }; -CompositionEngineTest::~CompositionEngineTest() = default; - TEST_F(CompositionEngineTest, canInstantiateCompositionEngine) { auto engine = impl::createCompositionEngine(); EXPECT_TRUE(engine.get() != nullptr); @@ -53,5 +57,84 @@ TEST_F(CompositionEngineTest, canSetRenderEngine) { EXPECT_EQ(mRenderEngine, &mEngine.getRenderEngine()); } +/* + * CompositionEngine::preComposition + */ + +class PreCompositionTest : public CompositionEngineTest { +public: + PreCompositionTest() { + 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)); + + mRefreshArgs.outputs = {mOutput}; + mRefreshArgs.layers = {mLayer1, mLayer2, mLayer3, mLayer4}; + } + + std::shared_ptr mOutput{std::make_shared>()}; + std::shared_ptr mLayer1{std::make_shared>()}; + std::shared_ptr mLayer2{std::make_shared>()}; + std::shared_ptr mLayer3{std::make_shared>()}; + std::shared_ptr mLayer4{std::make_shared>()}; + sp> mLayer1FE{new StrictMock()}; + sp> mLayer2FE{new StrictMock()}; + sp> mLayer3FE{new StrictMock()}; + + CompositionRefreshArgs mRefreshArgs; +}; + +TEST_F(PreCompositionTest, preCompositionSetsFrameTimestamp) { + const nsecs_t before = systemTime(SYSTEM_TIME_MONOTONIC); + CompositionRefreshArgs emptyArgs; + mEngine.preComposition(emptyArgs); + const nsecs_t after = systemTime(SYSTEM_TIME_MONOTONIC); + + // The frame timestamp should be between the before and after timestamps + EXPECT_GE(mEngine.getLastFrameRefreshTimestamp(), before); + EXPECT_LE(mEngine.getLastFrameRefreshTimestamp(), after); +} + +TEST_F(PreCompositionTest, preCompositionInvokesLayerPreCompositionWithFrameTimestamp) { + nsecs_t ts1 = 0; + nsecs_t ts2 = 0; + nsecs_t ts3 = 0; + EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts1), Return(false))); + EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts2), Return(false))); + EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts3), Return(false))); + + mEngine.preComposition(mRefreshArgs); + + // Each of the onPreComposition calls should used the same refresh timestamp + EXPECT_EQ(ts1, mEngine.getLastFrameRefreshTimestamp()); + EXPECT_EQ(ts2, mEngine.getLastFrameRefreshTimestamp()); + EXPECT_EQ(ts3, mEngine.getLastFrameRefreshTimestamp()); +} + +TEST_F(PreCompositionTest, preCompositionDefaultsToNoUpdateNeeded) { + EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(false)); + EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false)); + EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false)); + + mEngine.setNeedsAnotherUpdateForTest(true); + + mEngine.preComposition(mRefreshArgs); + + // The call should have cleared the needsAnotherUpdate flag + EXPECT_FALSE(mEngine.needsAnotherUpdate()); +} + +TEST_F(PreCompositionTest, preCompositionSetsNeedsAnotherUpdateIfAtLeastOneLayerRequestsIt) { + EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(true)); + EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false)); + EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false)); + + mEngine.preComposition(mRefreshArgs); + + EXPECT_TRUE(mEngine.needsAnotherUpdate()); +} + } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7a9a9a7a7b..799dd3c8d4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -1772,8 +1773,17 @@ void SurfaceFlinger::handleMessageRefresh() { mRefreshPending = false; + compositionengine::CompositionRefreshArgs refreshArgs; + for (const auto& [_, display] : mDisplays) { + refreshArgs.outputs.push_back(display->getCompositionDisplay()); + } + mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) { + auto compositionLayer = layer->getCompositionLayer(); + if (compositionLayer) refreshArgs.layers.push_back(compositionLayer); + }); + const bool repaintEverything = mRepaintEverything.exchange(false); - preComposition(); + mCompositionEngine->preComposition(refreshArgs); rebuildLayerStacks(); calculateWorkingSet(); for (const auto& [token, display] : mDisplays) { @@ -1808,6 +1818,10 @@ void SurfaceFlinger::handleMessageRefresh() { mTracing.notify("visibleRegionsDirty"); } } + + if (mCompositionEngine->needsAnotherUpdate()) { + signalLayerUpdate(); + } } @@ -1953,30 +1967,6 @@ void SurfaceFlinger::logLayerStats() { } } -void SurfaceFlinger::preComposition() -{ - ATRACE_CALL(); - ALOGV("preComposition"); - - mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC); - - bool needExtraInvalidate = false; - mDrawingState.traverseInZOrder([&](Layer* layer) { - auto compositionLayer = layer->getCompositionLayer(); - if (compositionLayer) { - auto layerFE = compositionLayer->getLayerFE(); - - if (layerFE && layerFE->onPreComposition(mRefreshStartTime)) { - needExtraInvalidate = true; - } - } - }); - - if (needExtraInvalidate) { - signalLayerUpdate(); - } -} - void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime, std::shared_ptr& presentFenceTime) { // Update queue of past composite+present times and determine the @@ -2070,10 +2060,11 @@ void SurfaceFlinger::postComposition() DisplayStatInfo stats; mScheduler->getDisplayStatInfo(&stats); - // We use the mRefreshStartTime which might be sampled a little later than - // when we started doing work for this frame, but that should be okay - // since updateCompositorTiming has snapping logic. - updateCompositorTiming(stats, mRefreshStartTime, presentFenceTime); + // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might + // be sampled a little later than when we started doing work for this frame, + // but that should be okay since updateCompositorTiming has snapping logic. + updateCompositorTiming(stats, mCompositionEngine->getLastFrameRefreshTimestamp(), + presentFenceTime); CompositorTiming compositorTiming; { std::lock_guard lock(getBE().mCompositorTimingLock); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index fa801afff8..13cd137320 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -747,7 +747,6 @@ private: void computeVisibleRegions(const sp& display, Region& dirtyRegion, Region& opaqueRegion); - void preComposition(); void postComposition(); void getCompositorTiming(CompositorTiming* compositorTiming); void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime, -- GitLab From 2d8cc8945eb1c1be5ce6a262613a5aae6e257d06 Mon Sep 17 00:00:00 2001 From: Pin-Yu Huang Date: Fri, 19 Jul 2019 04:00:44 +0000 Subject: [PATCH 0091/1255] Revert "Use std::set instead of SortedVector" This reverts commit a03f0debad92921ba52d33e7e06f0064703e85ad. Reason for revert: cause BB Change-Id: I5531b895947236ff5754334f3cd4660d07513293 --- services/inputflinger/InputReader.cpp | 4 ++-- services/inputflinger/include/InputReaderBase.h | 6 +++--- services/inputflinger/tests/InputReader_test.cpp | 16 ++++++++++++++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index 2de5ffa0eb..eee49d5e2a 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -1094,8 +1094,8 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config } if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) { - auto it = config->disabledDevices.find(mId); - bool enabled = it == config->disabledDevices.end(); + ssize_t index = config->disabledDevices.indexOf(mId); + bool enabled = index < 0; setEnabled(enabled, when); } diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 271051499c..c7720cbf59 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -27,11 +27,11 @@ #include #include #include +#include +#include #include #include -#include -#include #include #include @@ -250,7 +250,7 @@ struct InputReaderConfiguration { bool pointerCapture; // The set of currently disabled input devices. - std::set disabledDevices; + SortedVector disabledDevices; InputReaderConfiguration() : virtualKeyQuietTime(0), diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 541de99623..e10883485a 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -202,9 +202,21 @@ public: mConfig.portAssociations.insert({inputPort, displayPort}); } - void addDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.insert(deviceId); } + void addDisabledDevice(int32_t deviceId) { + ssize_t index = mConfig.disabledDevices.indexOf(deviceId); + bool currentlyEnabled = index < 0; + if (currentlyEnabled) { + mConfig.disabledDevices.add(deviceId); + } + } - void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); } + void removeDisabledDevice(int32_t deviceId) { + ssize_t index = mConfig.disabledDevices.indexOf(deviceId); + bool currentlyEnabled = index < 0; + if (!currentlyEnabled) { + mConfig.disabledDevices.remove(deviceId); + } + } void setPointerController(int32_t deviceId, const sp& controller) { mPointerControllers.add(deviceId, controller); -- GitLab From 9d187830d3121870c1a0fcd0a953ebd0674559c1 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 22 Jul 2019 15:15:47 -0700 Subject: [PATCH 0092/1255] Vulkan: fix the return code for vkGetPastPresentationTimingGOOGLE 1. Return VK_ERROR_OUT_OF_DATE_KHR when the surface is out of date. 2. Return VK_INCOMPLETE per spec describes. Bug: 134185757 Test: CtsDeqpTestCases Change-Id: I34bd1b85b41e61e6123095223471cc25f5e7a960 --- vulkan/libvulkan/swapchain.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index e5ac2de705..d60eaa7c21 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -370,9 +370,6 @@ uint32_t get_num_ready_timings(Swapchain& swapchain) { nullptr, //&first_composition_start_time, nullptr, //&last_composition_start_time, nullptr, //&composition_finish_time, - // TODO(ianelliott): Maybe ask if this one is - // supported, at startup time (since it may not be - // supported): &actual_present_time, nullptr, //&dequeue_ready_time, nullptr /*&reads_done_time*/); @@ -399,7 +396,6 @@ uint32_t get_num_ready_timings(Swapchain& swapchain) { return num_ready; } -// TODO(ianelliott): DEAL WITH RETURN VALUE (e.g. VK_INCOMPLETE)!!! void copy_ready_timings(Swapchain& swapchain, uint32_t* count, VkPastPresentationTimingGOOGLE* timings) { @@ -1773,6 +1769,10 @@ VkResult GetPastPresentationTimingGOOGLE( ATRACE_CALL(); Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle); + if (swapchain.surface.swapchain_handle != swapchain_handle) { + return VK_ERROR_OUT_OF_DATE_KHR; + } + ANativeWindow* window = swapchain.surface.window.get(); VkResult result = VK_SUCCESS; @@ -1783,8 +1783,15 @@ VkResult GetPastPresentationTimingGOOGLE( } if (timings) { - // TODO(ianelliott): plumb return value (e.g. VK_INCOMPLETE) + // Get the latest ready timing count before copying, since the copied + // timing info will be erased in copy_ready_timings function. + uint32_t n = get_num_ready_timings(swapchain); copy_ready_timings(swapchain, count, timings); + // Check the *count here against the recorded ready timing count, since + // *count can be overwritten per spec describes. + if (*count < n) { + result = VK_INCOMPLETE; + } } else { *count = get_num_ready_timings(swapchain); } -- GitLab From fb4c9862b29eb4bdf32e99587b647fb645458e49 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Mon, 22 Jul 2019 15:24:37 -0700 Subject: [PATCH 0093/1255] Fixing overflow bug Client should not be requesting such large buffers. Limit byte size to max(size_t) Bug: 137801859 Test: build, boot Change-Id: Idef0c1e926c180bfaf640b627046adba5d3043c3 --- libs/ui/GraphicBufferAllocator.cpp | 10 +++++++++- libs/ui/tests/GraphicBuffer_test.cpp | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp index 0861a1f9a3..9c7d1fda90 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -20,6 +20,7 @@ #include +#include #include #include @@ -114,6 +115,14 @@ status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height, if (!width || !height) width = height = 1; + const uint32_t bpp = bytesPerPixel(format); + if (std::numeric_limits::max() / width / height < static_cast(bpp)) { + ALOGE("Failed to allocate (%u x %u) layerCount %u format %d " + "usage %" PRIx64 ": Requesting too large a buffer size", + width, height, layerCount, format, usage); + return BAD_VALUE; + } + // Ensure that layerCount is valid. if (layerCount < 1) layerCount = 1; @@ -126,7 +135,6 @@ status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height, if (error == NO_ERROR) { Mutex::Autolock _l(sLock); KeyedVector& list(sAllocList); - uint32_t bpp = bytesPerPixel(format); alloc_rec_t rec; rec.width = width; rec.height = height; diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp index a7c248c105..127f7eedd6 100644 --- a/libs/ui/tests/GraphicBuffer_test.cpp +++ b/libs/ui/tests/GraphicBuffer_test.cpp @@ -35,6 +35,22 @@ constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN; class GraphicBufferTest : public testing::Test {}; +TEST_F(GraphicBufferTest, AllocateNoError) { + PixelFormat format = PIXEL_FORMAT_RGBA_8888; + sp gb(new GraphicBuffer(kTestWidth, kTestHeight, format, kTestLayerCount, + kTestUsage, std::string("test"))); + ASSERT_EQ(NO_ERROR, gb->initCheck()); +} + +TEST_F(GraphicBufferTest, AllocateBadDimensions) { + PixelFormat format = PIXEL_FORMAT_RGBA_8888; + uint32_t width, height; + width = height = std::numeric_limits::max(); + sp gb(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage, + std::string("test"))); + ASSERT_EQ(BAD_VALUE, gb->initCheck()); +} + TEST_F(GraphicBufferTest, CreateFromBufferHubBuffer) { std::unique_ptr b1 = BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat, -- GitLab From 3d14605bbd998aea5dd795315958053d60b7ce6f Mon Sep 17 00:00:00 2001 From: Mikael Pessa Date: Tue, 9 Jul 2019 09:25:38 -0700 Subject: [PATCH 0094/1255] Added gpu memory stats to gpuservice dump Test: adb root adb shell setenforce 0 adb shell dumpsys gpu Change-Id: I6040971d940946f051c6e1349124810eab8d4615 --- services/gpuservice/GpuService.cpp | 209 ++++++++++++++++++++++++++++- services/gpuservice/GpuService.h | 13 ++ 2 files changed, 215 insertions(+), 7 deletions(-) diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index c81ab509c3..e50dfca0a1 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -28,7 +28,12 @@ #include #include +#include +#include +#include +#include #include +#include #include "gpustats/GpuStats.h" @@ -40,6 +45,7 @@ namespace { status_t cmdHelp(int out); status_t cmdVkjson(int out, int err); void dumpGameDriverInfo(std::string* result); +void dumpMemoryInfo(std::string* result, const GpuMemoryMap& memories, uint32_t pid); } // namespace const String16 sDump("android.permission.DUMP"); @@ -72,6 +78,147 @@ void GpuService::setTargetStats(const std::string& appPackageName, const uint64_ mGpuStats->insertTargetStats(appPackageName, driverVersionCode, stats, value); } +bool isExpectedFormat(const char* str) { + // Should match in order: + // gpuaddr useraddr size id flags type usage sglen mapsize eglsrf eglimg + std::istringstream iss; + iss.str(str); + + std::string word; + iss >> word; + if (word != "gpuaddr") { return false; } + iss >> word; + if (word != "useraddr") { return false; } + iss >> word; + if (word != "size") { return false; } + iss >> word; + if (word != "id") { return false; } + iss >> word; + if (word != "flags") { return false; } + iss >> word; + if (word != "type") { return false; } + iss >> word; + if (word != "usage") { return false; } + iss >> word; + if (word != "sglen") { return false; } + iss >> word; + if (word != "mapsize") { return false; } + iss >> word; + if (word != "eglsrf") { return false; } + iss >> word; + if (word != "eglimg") { return false; } + return true; +} + + +// Queries gpu memory via Qualcomm's /d/kgsl/proc/*/mem interface. +status_t GpuService::getQCommGpuMemoryInfo(GpuMemoryMap* memories, std::string* result, int32_t dumpPid) const { + const std::string kDirectoryPath = "/d/kgsl/proc"; + DIR* directory = opendir(kDirectoryPath.c_str()); + if (!directory) { return PERMISSION_DENIED; } + + // File Format: + // gpuaddr useraddr size id flags type usage sglen mapsize eglsrf eglimg + // 0000000000000000 0000000000000000 8359936 23 --w--pY-- gpumem VK/others( 38) 0 0 0 0 + // 0000000000000000 0000000000000000 16293888 24 --wL--N-- ion surface 41 0 0 1 + + const bool dumpAll = dumpPid == 0; + static constexpr size_t kMaxLineLength = 1024; + static char line[kMaxLineLength]; + while(dirent* subdir = readdir(directory)) { + // Skip "." and ".." in directory. + if (strcmp(subdir->d_name, ".") == 0 || strcmp(subdir->d_name, "..") == 0 ) { continue; } + + std::string pid_str(subdir->d_name); + const uint32_t pid(stoi(pid_str)); + + if (!dumpAll && dumpPid != pid) { + continue; + } + + std::string filepath(kDirectoryPath + "/" + pid_str + "/mem"); + std::ifstream file(filepath); + + // Check first line + file.getline(line, kMaxLineLength); + if (!isExpectedFormat(line)) { + continue; + } + + if (result) { + StringAppendF(result, "%d:\n%s\n", pid, line); + } + + while( file.getline(line, kMaxLineLength) ) { + if (result) { + StringAppendF(result, "%s\n", line); + } + + std::istringstream iss; + iss.str(line); + + // Skip gpuaddr, useraddr. + const char delimiter = ' '; + iss >> std::ws; + iss.ignore(kMaxLineLength, delimiter); + iss >> std::ws; + iss.ignore(kMaxLineLength, delimiter); + + // Get size. + int64_t memsize; + iss >> memsize; + + // Skip id, flags. + iss >> std::ws; + iss.ignore(kMaxLineLength, delimiter); + iss >> std::ws; + iss.ignore(kMaxLineLength, delimiter); + + // Get type, usage. + std::string memtype; + std::string usage; + iss >> memtype >> usage; + + // Adjust for the space in VK/others( #) + if (usage == "VK/others(") { + std::string vkTypeEnd; + iss >> vkTypeEnd; + usage.append(vkTypeEnd); + } + + // Skip sglen. + iss >> std::ws; + iss.ignore(kMaxLineLength, delimiter); + + // Get mapsize. + int64_t mapsize; + iss >> mapsize; + + if (memsize == 0 && mapsize == 0) { + continue; + } + + if (memtype == "gpumem") { + (*memories)[pid][usage].gpuMemory += memsize; + } else { + (*memories)[pid][usage].ionMemory += memsize; + } + + if (mapsize > 0) { + (*memories)[pid][usage].mappedMemory += mapsize; + } + } + + if (result) { + StringAppendF(result, "\n"); + } + } + + closedir(directory); + + return OK; +} + status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector& args) { ATRACE_CALL(); @@ -99,24 +246,44 @@ status_t GpuService::doDump(int fd, const Vector& args, bool /*asProto StringAppendF(&result, "Permission Denial: can't dump gpu from pid=%d, uid=%d\n", pid, uid); } else { bool dumpAll = true; - size_t index = 0; + bool dumpDriverInfo = false; + bool dumpStats = false; + bool dumpMemory = false; size_t numArgs = args.size(); + int32_t pid = 0; if (numArgs) { - if ((index < numArgs) && (args[index] == String16("--gpustats"))) { - index++; - mGpuStats->dump(args, &result); - dumpAll = false; + dumpAll = false; + for (size_t index = 0; index < numArgs; ++index) { + if (args[index] == String16("--gpustats")) { + dumpStats = true; + } else if (args[index] == String16("--gpudriverinfo")) { + dumpDriverInfo = true; + } else if (args[index] == String16("--gpumem")) { + dumpMemory = true; + } else if (args[index].compare(String16("--gpumem=")) > 0) { + dumpMemory = true; + pid = atoi(String8(&args[index][9])); + } } } - if (dumpAll) { + if (dumpAll || dumpDriverInfo) { dumpGameDriverInfo(&result); result.append("\n"); - + } + if (dumpAll || dumpStats) { mGpuStats->dump(Vector(), &result); result.append("\n"); } + if (dumpAll || dumpMemory) { + GpuMemoryMap memories; + // Currently only queries Qualcomm gpu memory. More will be added later. + if (getQCommGpuMemoryInfo(&memories, &result, pid) == OK) { + dumpMemoryInfo(&result, memories, pid); + result.append("\n"); + } + } } write(fd, result.c_str(), result.size()); @@ -168,6 +335,34 @@ void dumpGameDriverInfo(std::string* result) { StringAppendF(result, "Pre-release Game Driver: %s\n", preReleaseGameDriver); } +// Read and print all memory info for each process from /d/kgsl/proc//mem. +void dumpMemoryInfo(std::string* result, const GpuMemoryMap& memories, uint32_t pid) { + if (!result) return; + + // Write results. + StringAppendF(result, "GPU Memory Summary:\n"); + for(auto& mem : memories) { + uint32_t process = mem.first; + if (pid != 0 && pid != process) { + continue; + } + + StringAppendF(result, "%d:\n", process); + for(auto& memStruct : mem.second) { + StringAppendF(result, " %s", memStruct.first.c_str()); + + if(memStruct.second.gpuMemory > 0) + StringAppendF(result, ", GPU memory = %" PRId64, memStruct.second.gpuMemory); + if(memStruct.second.mappedMemory > 0) + StringAppendF(result, ", Mapped memory = %" PRId64, memStruct.second.mappedMemory); + if(memStruct.second.ionMemory > 0) + StringAppendF(result, ", Ion memory = %" PRId64, memStruct.second.ionMemory); + + StringAppendF(result, "\n"); + } + } +} + } // anonymous namespace } // namespace android diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h index 525fb4fada..b3dc2e2718 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/GpuService.h @@ -25,11 +25,22 @@ #include #include +#include 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>; + class GpuService : public BnGpuService, public PriorityDumper { public: static const char* const SERVICE_NAME ANDROID_API; @@ -71,6 +82,8 @@ private: status_t doDump(int fd, const Vector& args, bool asProto); + status_t getQCommGpuMemoryInfo(GpuMemoryMap* memories, std::string* result, int32_t dumpPid) const; + /* * Attributes */ -- GitLab From c6f61190e7bb4579047f70f3c66282457c1e68d7 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 23 Jul 2019 18:12:31 +0000 Subject: [PATCH 0095/1255] Revert "Revert "Use std::set instead of SortedVector"" This reverts commit 2d8cc8945eb1c1be5ce6a262613a5aae6e257d06. Reason for revert: Likely build was having issues, and the original CLs were fine. From looking into the issues more closely, it appears that the topic was not merged atomically. Change-Id: I42393e615066b4cf10aa953757a3f43be5676a2f --- services/inputflinger/InputReader.cpp | 4 ++-- services/inputflinger/include/InputReaderBase.h | 6 +++--- services/inputflinger/tests/InputReader_test.cpp | 16 ++-------------- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index eee49d5e2a..2de5ffa0eb 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -1094,8 +1094,8 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config } if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) { - ssize_t index = config->disabledDevices.indexOf(mId); - bool enabled = index < 0; + auto it = config->disabledDevices.find(mId); + bool enabled = it == config->disabledDevices.end(); setEnabled(enabled, when); } diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index c7720cbf59..271051499c 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -27,11 +27,11 @@ #include #include #include -#include -#include #include #include +#include +#include #include #include @@ -250,7 +250,7 @@ struct InputReaderConfiguration { bool pointerCapture; // The set of currently disabled input devices. - SortedVector disabledDevices; + std::set disabledDevices; InputReaderConfiguration() : virtualKeyQuietTime(0), diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index e10883485a..541de99623 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -202,21 +202,9 @@ public: mConfig.portAssociations.insert({inputPort, displayPort}); } - void addDisabledDevice(int32_t deviceId) { - ssize_t index = mConfig.disabledDevices.indexOf(deviceId); - bool currentlyEnabled = index < 0; - if (currentlyEnabled) { - mConfig.disabledDevices.add(deviceId); - } - } + void addDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.insert(deviceId); } - void removeDisabledDevice(int32_t deviceId) { - ssize_t index = mConfig.disabledDevices.indexOf(deviceId); - bool currentlyEnabled = index < 0; - if (!currentlyEnabled) { - mConfig.disabledDevices.remove(deviceId); - } - } + void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); } void setPointerController(int32_t deviceId, const sp& controller) { mPointerControllers.add(deviceId, controller); -- GitLab From e3b57006c2f4604c0b31eaf9228ed336f5c47bf7 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Mon, 22 Jul 2019 17:18:52 +0200 Subject: [PATCH 0096/1255] Mark screen rotation as early (2/2) To decrease jank while rotating. Test: Rotate screen Bug: 138083790 Change-Id: I2b0d63bbf4143b9273a502ced451867f69e42636 Exempt-From-Owner-Approval: Already reviewed on qt-dev --- libs/gui/SurfaceComposerClient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index c59fddfb9d..16a4b353aa 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -448,6 +448,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mInputWindowCommands.merge(other.mInputWindowCommands); mContainsBuffer = other.mContainsBuffer; + mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup; other.clear(); return *this; } -- GitLab From 3bc7e09b2c69ebc70533fe1ce85cef1945133e85 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 24 Jul 2019 17:43:30 -0700 Subject: [PATCH 0097/1255] Do not use RefBase in EventHub Switch to std::unique_ptr instead. Unfortunately, have to also switch to shared_ptr because FakeEventHub implements EventHub but is also used to inject events when testing InputReader. Bug: 117684064 Test: atest inputflinger_tests Change-Id: I789ba0ca255b6a1f179711c61fc9da98a3c6a800 --- services/inputflinger/EventHub.h | 6 +-- services/inputflinger/InputReader.cpp | 17 ++++--- services/inputflinger/InputReader.h | 11 +++-- services/inputflinger/InputReaderFactory.cpp | 2 +- .../inputflinger/tests/InputReader_test.cpp | 44 +++++++++---------- 5 files changed, 41 insertions(+), 39 deletions(-) diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h index eb4e8f2e50..6c3a4a2aa3 100644 --- a/services/inputflinger/EventHub.h +++ b/services/inputflinger/EventHub.h @@ -146,12 +146,11 @@ extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses); * which keys are currently down. Finally, the event hub keeps track of the capabilities of * individual input devices, such as their class and the set of key codes that they support. */ -class EventHubInterface : public virtual RefBase { -protected: +class EventHubInterface { +public: EventHubInterface() { } virtual ~EventHubInterface() { } -public: // Synthetic raw event type codes produced when devices are added or removed. enum { // Sent when a device is added. @@ -319,7 +318,6 @@ public: virtual void dump(std::string& dump); virtual void monitor(); -protected: virtual ~EventHub(); private: diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index 2de5ffa0eb..3e236a93ae 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -260,12 +260,17 @@ static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, // --- InputReader --- -InputReader::InputReader(const sp& eventHub, - const sp& policy, - const sp& listener) : - mContext(this), mEventHub(eventHub), mPolicy(policy), - mNextSequenceNum(1), mGlobalMetaState(0), mGeneration(1), - mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), +InputReader::InputReader(std::shared_ptr eventHub, + const sp& policy, + const sp& listener) + : mContext(this), + mEventHub(eventHub), + mPolicy(policy), + mNextSequenceNum(1), + mGlobalMetaState(0), + mGeneration(1), + mDisableVirtualKeysTimeout(LLONG_MIN), + mNextTimeout(LLONG_MAX), mConfigurationChangesToRefresh(0) { mQueuedListener = new QueuedInputListener(listener); diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index 0c08e7da38..11ef9347dc 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -114,9 +114,9 @@ public: */ class InputReader : public InputReaderInterface { public: - InputReader(const sp& eventHub, - const sp& policy, - const sp& listener); + InputReader(std::shared_ptr eventHub, + const sp& policy, + const sp& listener); virtual ~InputReader(); virtual void dump(std::string& dump); @@ -181,7 +181,10 @@ private: Condition mReaderIsAliveCondition; - sp mEventHub; + // This could be unique_ptr, but due to the way InputReader tests are written, + // it is made shared_ptr here. In the tests, an EventHub reference is retained by the test + // in parallel to passing it to the InputReader. + std::shared_ptr mEventHub; sp mPolicy; sp mQueuedListener; diff --git a/services/inputflinger/InputReaderFactory.cpp b/services/inputflinger/InputReaderFactory.cpp index 3534f6b760..072499b9cd 100644 --- a/services/inputflinger/InputReaderFactory.cpp +++ b/services/inputflinger/InputReaderFactory.cpp @@ -22,7 +22,7 @@ namespace android { sp createInputReader( const sp& policy, const sp& listener) { - return new InputReader(new EventHub(), policy, listener); + return new InputReader(std::make_unique(), policy, listener); } } // namespace android \ No newline at end of file diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 541de99623..d95ac96124 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -325,14 +325,13 @@ class FakeEventHub : public EventHubInterface { List mEvents; std::unordered_map> mVideoFrames; -protected: +public: virtual ~FakeEventHub() { for (size_t i = 0; i < mDevices.size(); i++) { delete mDevices.valueAt(i); } } -public: FakeEventHub() { } void addDevice(int32_t deviceId, const std::string& name, uint32_t classes) { @@ -760,7 +759,7 @@ private: // --- FakeInputReaderContext --- class FakeInputReaderContext : public InputReaderContext { - sp mEventHub; + std::shared_ptr mEventHub; sp mPolicy; sp mListener; int32_t mGlobalMetaState; @@ -769,12 +768,14 @@ class FakeInputReaderContext : public InputReaderContext { uint32_t mNextSequenceNum; public: - FakeInputReaderContext(const sp& eventHub, - const sp& policy, - const sp& listener) : - mEventHub(eventHub), mPolicy(policy), mListener(listener), - mGlobalMetaState(0), mNextSequenceNum(1) { - } + FakeInputReaderContext(std::shared_ptr eventHub, + const sp& policy, + const sp& listener) + : mEventHub(eventHub), + mPolicy(policy), + mListener(listener), + mGlobalMetaState(0), + mNextSequenceNum(1) {} virtual ~FakeInputReaderContext() { } @@ -999,12 +1000,10 @@ class InstrumentedInputReader : public InputReader { InputDevice* mNextDevice; public: - InstrumentedInputReader(const sp& eventHub, - const sp& policy, - const sp& listener) : - InputReader(eventHub, policy, listener), - mNextDevice(nullptr) { - } + InstrumentedInputReader(std::shared_ptr eventHub, + const sp& policy, + const sp& listener) + : InputReader(eventHub, policy, listener), mNextDevice(nullptr) {} virtual ~InstrumentedInputReader() { if (mNextDevice) { @@ -1232,11 +1231,11 @@ class InputReaderTest : public testing::Test { protected: sp mFakeListener; sp mFakePolicy; - sp mFakeEventHub; + std::shared_ptr mFakeEventHub; sp mReader; virtual void SetUp() { - mFakeEventHub = new FakeEventHub(); + mFakeEventHub = std::make_unique(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = new TestInputListener(); @@ -1248,7 +1247,6 @@ protected: mFakeListener.clear(); mFakePolicy.clear(); - mFakeEventHub.clear(); } void addDevice(int32_t deviceId, const std::string& name, uint32_t classes, @@ -1575,7 +1573,7 @@ protected: static const int32_t DEVICE_CONTROLLER_NUMBER; static const uint32_t DEVICE_CLASSES; - sp mFakeEventHub; + std::shared_ptr mFakeEventHub; sp mFakePolicy; sp mFakeListener; FakeInputReaderContext* mFakeContext; @@ -1583,7 +1581,7 @@ protected: InputDevice* mDevice; virtual void SetUp() { - mFakeEventHub = new FakeEventHub(); + mFakeEventHub = std::make_unique(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = new TestInputListener(); mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener); @@ -1601,7 +1599,6 @@ protected: delete mFakeContext; mFakeListener.clear(); mFakePolicy.clear(); - mFakeEventHub.clear(); } }; @@ -1770,14 +1767,14 @@ protected: static const int32_t DEVICE_CONTROLLER_NUMBER; static const uint32_t DEVICE_CLASSES; - sp mFakeEventHub; + std::shared_ptr mFakeEventHub; sp mFakePolicy; sp mFakeListener; FakeInputReaderContext* mFakeContext; InputDevice* mDevice; virtual void SetUp() { - mFakeEventHub = new FakeEventHub(); + mFakeEventHub = std::make_unique(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = new TestInputListener(); mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener); @@ -1795,7 +1792,6 @@ protected: delete mFakeContext; mFakeListener.clear(); mFakePolicy.clear(); - mFakeEventHub.clear(); } void addConfigurationProperty(const char* key, const char* value) { -- GitLab From 937bb83a143631fcb25f0962aa95c1f850fdf023 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Thu, 25 Jul 2019 17:48:31 -0700 Subject: [PATCH 0098/1255] Add setCursorPosition. When source is updated we need to update their values. Also renamed mX/YCursorPosition to mRawX/YCursorPosition to indicate it stores raw values (w/o applying offset). Bug: 134788085 Test: atest libinput_tests Change-Id: I1533d79a7542291974ff572d3aeaf9924e3f0751 --- include/input/Input.h | 14 ++++++----- libs/input/Input.cpp | 35 ++++++++++++++++------------ libs/input/tests/InputEvent_test.cpp | 10 ++++++++ 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index ad8c233577..cbd1a412bf 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -469,14 +469,16 @@ public: inline float getYPrecision() const { return mYPrecision; } - inline float getRawXCursorPosition() const { return mXCursorPosition; } + inline float getRawXCursorPosition() const { return mRawXCursorPosition; } float getXCursorPosition() const; - inline float getRawYCursorPosition() const { return mYCursorPosition; } + inline float getRawYCursorPosition() const { return mRawYCursorPosition; } float getYCursorPosition() const; + void setCursorPosition(float x, float y); + static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } inline nsecs_t getDownTime() const { return mDownTime; } @@ -623,8 +625,8 @@ public: void initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, float xOffset, - float yOffset, float xPrecision, float yPrecision, float mXCursorPosition, - float mYCursorPosition, nsecs_t downTime, nsecs_t eventTime, + float yOffset, float xPrecision, float yPrecision, float rawXCursorPosition, + float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); @@ -676,8 +678,8 @@ protected: float mYOffset; float mXPrecision; float mYPrecision; - float mXCursorPosition; - float mYCursorPosition; + float mRawXCursorPosition; + float mRawYCursorPosition; nsecs_t mDownTime; Vector mPointerProperties; Vector mSampleEventTimes; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index dc4978b836..34b305e548 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -238,8 +238,8 @@ void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, float xOffset, float yOffset, - float xPrecision, float yPrecision, float xCursorPosition, - float yCursorPosition, nsecs_t downTime, nsecs_t eventTime, + float xPrecision, float yPrecision, float rawXCursorPosition, + float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { InputEvent::initialize(deviceId, source, displayId); @@ -254,8 +254,8 @@ void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId mYOffset = yOffset; mXPrecision = xPrecision; mYPrecision = yPrecision; - mXCursorPosition = xCursorPosition; - mYCursorPosition = yCursorPosition; + mRawXCursorPosition = rawXCursorPosition; + mRawYCursorPosition = rawYCursorPosition; mDownTime = downTime; mPointerProperties.clear(); mPointerProperties.appendArray(pointerProperties, pointerCount); @@ -277,8 +277,8 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mYOffset = other->mYOffset; mXPrecision = other->mXPrecision; mYPrecision = other->mYPrecision; - mXCursorPosition = other->mXCursorPosition; - mYCursorPosition = other->mYCursorPosition; + mRawXCursorPosition = other->mRawXCursorPosition; + mRawYCursorPosition = other->mRawYCursorPosition; mDownTime = other->mDownTime; mPointerProperties = other->mPointerProperties; @@ -313,6 +313,11 @@ float MotionEvent::getYCursorPosition() const { return rawY + mYOffset; } +void MotionEvent::setCursorPosition(float x, float y) { + mRawXCursorPosition = x - mXOffset; + mRawYCursorPosition = y - mYOffset; +} + const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const { return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex]; } @@ -433,12 +438,12 @@ void MotionEvent::transform(const float matrix[9]) { transformPoint(matrix, 0, 0, &originX, &originY); // Apply the transformation to cursor position. - if (isValidCursorPosition(mXCursorPosition, mYCursorPosition)) { - float x = mXCursorPosition + oldXOffset; - float y = mYCursorPosition + oldYOffset; + if (isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) { + float x = mRawXCursorPosition + oldXOffset; + float y = mRawYCursorPosition + oldYOffset; transformPoint(matrix, x, y, &x, &y); - mXCursorPosition = x - mXOffset; - mYCursorPosition = y - mYOffset; + mRawXCursorPosition = x - mXOffset; + mRawYCursorPosition = y - mYOffset; } // Apply the transformation to all samples. @@ -480,8 +485,8 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mYOffset = parcel->readFloat(); mXPrecision = parcel->readFloat(); mYPrecision = parcel->readFloat(); - mXCursorPosition = parcel->readFloat(); - mYCursorPosition = parcel->readFloat(); + mRawXCursorPosition = parcel->readFloat(); + mRawYCursorPosition = parcel->readFloat(); mDownTime = parcel->readInt64(); mPointerProperties.clear(); @@ -533,8 +538,8 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeFloat(mYOffset); parcel->writeFloat(mXPrecision); parcel->writeFloat(mYPrecision); - parcel->writeFloat(mXCursorPosition); - parcel->writeFloat(mYCursorPosition); + parcel->writeFloat(mRawXCursorPosition); + parcel->writeFloat(mRawYCursorPosition); parcel->writeInt64(mDownTime); for (size_t i = 0; i < pointerCount; i++) { diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index b879de6a74..b90857c99c 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -665,4 +665,14 @@ TEST_F(MotionEventTest, Initialize_SetsCursorPosition) { ASSERT_EQ(600, event.getYCursorPosition()); } +TEST_F(MotionEventTest, SetCursorPosition) { + MotionEvent event; + initializeEventWithHistory(&event); + event.setSource(AINPUT_SOURCE_MOUSE); + + event.setCursorPosition(3, 4); + ASSERT_EQ(3, event.getXCursorPosition()); + ASSERT_EQ(4, event.getYCursorPosition()); +} + } // namespace android -- GitLab From a8955dd64c0c7fd355a7a3973403c3ba916d6f27 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 10 Jul 2019 10:19:09 -0700 Subject: [PATCH 0099/1255] SF: Factor out expected present time computation Compute expected present time once and pass it to traversed layers instead of calling back into SF for each layer. This will simplify synchronization for per-display refresh. Also, recompute on Binder transaction, since the cached value computed on invalidate may be stale. Bug: 130554049 Bug: 123715322 Test: go/wm-smoke Change-Id: I7153a728360e789dc4f97d2c39c4bdaa14183624 --- services/surfaceflinger/BufferLayer.cpp | 21 +++++------ services/surfaceflinger/BufferLayer.h | 16 +++++---- services/surfaceflinger/BufferQueueLayer.cpp | 15 ++++---- services/surfaceflinger/BufferQueueLayer.h | 7 ++-- services/surfaceflinger/BufferStateLayer.cpp | 17 ++++----- services/surfaceflinger/BufferStateLayer.h | 7 ++-- services/surfaceflinger/Layer.h | 7 ++-- services/surfaceflinger/SurfaceFlinger.cpp | 36 ++++++++++++------- services/surfaceflinger/SurfaceFlinger.h | 21 ++++++----- .../tests/unittests/CompositionTest.cpp | 2 +- 10 files changed, 81 insertions(+), 68 deletions(-) diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index f51fbb45f6..4cf37a4d30 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -395,7 +395,8 @@ bool BufferLayer::onPostComposition(const std::optional& displayId, return true; } -bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) { +bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, + nsecs_t expectedPresentTime) { ATRACE_CALL(); bool refreshRequired = latchSidebandStream(recomputeVisibleRegions); @@ -430,12 +431,12 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) const bool oldOpacity = isOpaque(s); sp oldBuffer = mActiveBuffer; - if (!allTransactionsSignaled()) { + if (!allTransactionsSignaled(expectedPresentTime)) { mFlinger->setTransactionFlags(eTraversalNeeded); return false; } - status_t err = updateTexImage(recomputeVisibleRegions, latchTime); + status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime); if (err != NO_ERROR) { return false; } @@ -540,10 +541,10 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) } // transaction -void BufferLayer::notifyAvailableFrames() { - const auto headFrameNumber = getHeadFrameNumber(); +void BufferLayer::notifyAvailableFrames(nsecs_t expectedPresentTime) { + const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime); const bool headFenceSignaled = fenceHasSignaled(); - const bool presentTimeIsCurrent = framePresentTimeIsCurrent(); + const bool presentTimeIsCurrent = framePresentTimeIsCurrent(expectedPresentTime); Mutex::Autolock lock(mLocalSyncPointMutex); for (auto& point : mLocalSyncPoints) { if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled && @@ -591,8 +592,8 @@ bool BufferLayer::latchUnsignaledBuffers() { } // h/w composer set-up -bool BufferLayer::allTransactionsSignaled() { - auto headFrameNumber = getHeadFrameNumber(); +bool BufferLayer::allTransactionsSignaled(nsecs_t expectedPresentTime) { + const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime); bool matchingFramesFound = false; bool allTransactionsApplied = true; Mutex::Autolock lock(mLocalSyncPointMutex); @@ -658,9 +659,9 @@ bool BufferLayer::needsFiltering(const sp& displayDevice) c sourceCrop.getWidth() != displayFrame.getWidth(); } -uint64_t BufferLayer::getHeadFrameNumber() const { +uint64_t BufferLayer::getHeadFrameNumber(nsecs_t expectedPresentTime) const { if (hasFrameUpdate()) { - return getFrameNumber(); + return getFrameNumber(expectedPresentTime); } else { return mCurrentFrameNumber; } diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index b679380b79..c793550625 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -96,11 +96,12 @@ public: // the visible regions need to be recomputed (this is a fairly heavy // operation, so this should be set only if needed). Typically this is used // to figure out if the content or size of a surface has changed. - bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override; + bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, + nsecs_t expectedPresentTime) override; bool isBufferLatched() const override { return mRefreshPending; } - void notifyAvailableFrames() override; + void notifyAvailableFrames(nsecs_t expectedPresentTime) override; bool hasReadyFrame() const override; @@ -114,7 +115,7 @@ public: // ----------------------------------------------------------------------- private: virtual bool fenceHasSignaled() const = 0; - virtual bool framePresentTimeIsCurrent() const = 0; + virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0; virtual nsecs_t getDesiredPresentTime() = 0; virtual std::shared_ptr getCurrentFenceTime() const = 0; @@ -129,7 +130,7 @@ private: virtual int getDrawingApi() const = 0; virtual PixelFormat getPixelFormat() const = 0; - virtual uint64_t getFrameNumber() const = 0; + virtual uint64_t getFrameNumber(nsecs_t expectedPresentTime) const = 0; virtual bool getAutoRefresh() const = 0; virtual bool getSidebandStreamChanged() const = 0; @@ -142,7 +143,8 @@ private: virtual void setFilteringEnabled(bool enabled) = 0; virtual status_t bindTextureImage() = 0; - virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0; + virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, + nsecs_t expectedPresentTime) = 0; virtual status_t updateActiveBuffer() = 0; virtual status_t updateFrameNumber(nsecs_t latchTime) = 0; @@ -156,7 +158,7 @@ protected: // Check all of the local sync points to ensure that all transactions // which need to have been applied prior to the frame which is about to // be latched have signaled - bool allTransactionsSignaled(); + bool allTransactionsSignaled(nsecs_t expectedPresentTime); static bool getOpacityForFormat(uint32_t format); @@ -175,7 +177,7 @@ private: // Returns true if this layer requires filtering bool needsFiltering(const sp& displayDevice) const; - uint64_t getHeadFrameNumber() const; + uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const; uint32_t mCurrentScalingMode{NATIVE_WINDOW_SCALING_MODE_FREEZE}; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index d6853661a5..fe9edfe895 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -137,13 +137,13 @@ bool BufferQueueLayer::fenceHasSignaled() const { return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; } -bool BufferQueueLayer::framePresentTimeIsCurrent() const { +bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const { if (!hasFrameUpdate() || isRemovedFromCurrentState()) { return true; } Mutex::Autolock lock(mQueueItemLock); - return mQueueItems[0].mTimestamp <= mFlinger->getExpectedPresentTime(); + return mQueueItems[0].mTimestamp <= expectedPresentTime; } nsecs_t BufferQueueLayer::getDesiredPresentTime() { @@ -196,13 +196,11 @@ PixelFormat BufferQueueLayer::getPixelFormat() const { return mFormat; } -uint64_t BufferQueueLayer::getFrameNumber() const { +uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const { Mutex::Autolock lock(mQueueItemLock); uint64_t frameNumber = mQueueItems[0].mFrameNumber; // The head of the queue will be dropped if there are signaled and timely frames behind it - nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime(); - if (isRemovedFromCurrentState()) { expectedPresentTime = 0; } @@ -268,7 +266,8 @@ status_t BufferQueueLayer::bindTextureImage() { return mConsumer->bindTextureImage(); } -status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) { +status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, + nsecs_t expectedPresentTime) { // This boolean is used to make sure that SurfaceFlinger's shadow copy // of the buffer queue isn't modified when the buffer queue is returning // BufferItem's that weren't actually queued. This can happen in shared @@ -279,8 +278,6 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode, getTransformToDisplayInverse(), mFreezeGeometryUpdates); - nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime(); - if (isRemovedFromCurrentState()) { expectedPresentTime = 0; } @@ -432,7 +429,7 @@ void BufferQueueLayer::setHwcLayerBuffer(const sp& display) void BufferQueueLayer::fakeVsync() { mRefreshPending = false; bool ignored = false; - latchBuffer(ignored, systemTime()); + latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */); usleep(16000); releasePendingBuffer(systemTime()); } diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 7def33ad78..e60a083cff 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -61,7 +61,7 @@ public: // ----------------------------------------------------------------------- public: bool fenceHasSignaled() const override; - bool framePresentTimeIsCurrent() const override; + bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override; private: nsecs_t getDesiredPresentTime() override; @@ -77,7 +77,7 @@ private: int getDrawingApi() const override; PixelFormat getPixelFormat() const override; - uint64_t getFrameNumber() const override; + uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override; bool getAutoRefresh() const override; bool getSidebandStreamChanged() const override; @@ -89,7 +89,8 @@ private: void setFilteringEnabled(bool enabled) override; status_t bindTextureImage() override; - status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override; + status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, + nsecs_t expectedPresentTime) override; status_t updateActiveBuffer() override; status_t updateFrameNumber(nsecs_t latchTime) override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 4b01301467..06b2364bcf 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -216,7 +216,7 @@ bool BufferStateLayer::setBuffer(const sp& buffer, nsecs_t postTi mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); - mFlinger->mTimeStats->setPostTime(getSequence(), getFrameNumber(), getName().c_str(), postTime); + mFlinger->mTimeStats->setPostTime(getSequence(), mFrameNumber, getName().c_str(), postTime); mDesiredPresentTime = desiredPresentTime; if (mFlinger->mUseSmart90ForVideo) { @@ -369,12 +369,12 @@ bool BufferStateLayer::fenceHasSignaled() const { return getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled; } -bool BufferStateLayer::framePresentTimeIsCurrent() const { +bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const { if (!hasFrameUpdate() || isRemovedFromCurrentState()) { return true; } - return mDesiredPresentTime <= mFlinger->getExpectedPresentTime(); + return mDesiredPresentTime <= expectedPresentTime; } nsecs_t BufferStateLayer::getDesiredPresentTime() { @@ -446,7 +446,7 @@ PixelFormat BufferStateLayer::getPixelFormat() const { return mActiveBuffer->format; } -uint64_t BufferStateLayer::getFrameNumber() const { +uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const { return mFrameNumber; } @@ -494,7 +494,8 @@ status_t BufferStateLayer::bindTextureImage() { return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence); } -status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime) { +status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime, + nsecs_t /*expectedPresentTime*/) { const State& s(getDrawingState()); if (!s.buffer) { @@ -528,7 +529,7 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse ALOGE("[%s] rejecting buffer: " "bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}", mName.string(), bufferWidth, bufferHeight, s.active.w, s.active.h); - mFlinger->mTimeStats->removeTimeRecord(layerID, getFrameNumber()); + mFlinger->mTimeStats->removeTimeRecord(layerID, mFrameNumber); return BAD_VALUE; } @@ -550,8 +551,8 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse } } - mFlinger->mTimeStats->setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime()); - mFlinger->mTimeStats->setLatchTime(layerID, getFrameNumber(), latchTime); + mFlinger->mTimeStats->setAcquireFence(layerID, mFrameNumber, getCurrentFenceTime()); + mFlinger->mTimeStats->setLatchTime(layerID, mFrameNumber, latchTime); mCurrentStateModified = false; diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index db8ae0d337..18e8cfa481 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -100,7 +100,7 @@ public: // Interface implementation for BufferLayer // ----------------------------------------------------------------------- bool fenceHasSignaled() const override; - bool framePresentTimeIsCurrent() const override; + bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override; // Inherit from ClientCache::ErasedRecipient void bufferErased(const client_cache_t& clientCacheId) override; @@ -119,7 +119,7 @@ private: int getDrawingApi() const override; PixelFormat getPixelFormat() const override; - uint64_t getFrameNumber() const override; + uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override; bool getAutoRefresh() const override; bool getSidebandStreamChanged() const override; @@ -131,7 +131,8 @@ private: void setFilteringEnabled(bool enabled) override; status_t bindTextureImage() override; - status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override; + status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, + nsecs_t expectedPresentTime) override; status_t updateActiveBuffer() override; status_t updateFrameNumber(nsecs_t latchTime) override; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index b693a47f39..f7e188f3ec 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -561,8 +561,9 @@ public: * operation, so this should be set only if needed). Typically this is used * to figure out if the content or size of a surface has changed. */ - virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/) { - return {}; + virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/, + nsecs_t /*expectedPresentTime*/) { + return false; } virtual bool isBufferLatched() const { return false; } @@ -812,7 +813,7 @@ public: // this to be called once. sp getHandle(); const String8& getName() const; - virtual void notifyAvailableFrames() {} + virtual void notifyAvailableFrames(nsecs_t /*expectedPresentTime*/) {} virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; } bool getPremultipledAlpha() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 99440a6d5e..cd80f2b359 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1693,15 +1693,15 @@ bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS { return fence != Fence::NO_FENCE && (fence->getStatus() == Fence::Status::Unsignaled); } -void SurfaceFlinger::populateExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS { +void SurfaceFlinger::populateExpectedPresentTime() { DisplayStatInfo stats; mScheduler->getDisplayStatInfo(&stats); const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(); // Inflate the expected present time if we're targetting the next vsync. - mExpectedPresentTime = - mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync() - ? presentTime - : presentTime + stats.vsyncPeriod; + mExpectedPresentTime.store(mVsyncModulator.getOffsets().sf < + mPhaseOffsets->getOffsetThresholdForNextVsync() + ? presentTime + : presentTime + stats.vsyncPeriod); } void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { @@ -2856,9 +2856,11 @@ void SurfaceFlinger::processDisplayChangesLocked() { void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { + const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); + // Notify all layers of available frames - mCurrentState.traverseInZOrder([](Layer* layer) { - layer->notifyAvailableFrames(); + mCurrentState.traverseInZOrder([expectedPresentTime](Layer* layer) { + layer->notifyAvailableFrames(expectedPresentTime); }); /* @@ -3057,7 +3059,7 @@ void SurfaceFlinger::updateCursorAsync() void SurfaceFlinger::latchAndReleaseBuffer(const sp& layer) { if (layer->hasReadyFrame()) { bool ignored = false; - layer->latchBuffer(ignored, systemTime()); + layer->latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */); } layer->releasePendingBuffer(systemTime()); } @@ -3305,6 +3307,8 @@ bool SurfaceFlinger::handlePageFlip() bool frameQueued = false; bool newDataLatched = false; + const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); + // Store the set of layers that need updates. This set must not change as // buffers are being latched, as this could result in a deadlock. // Example: Two producers share the same command stream and: @@ -3317,7 +3321,6 @@ bool SurfaceFlinger::handlePageFlip() mDrawingState.traverseInZOrder([&](Layer* layer) { if (layer->hasReadyFrame()) { frameQueued = true; - const nsecs_t expectedPresentTime = getExpectedPresentTime(); if (layer->shouldPresentNow(expectedPresentTime)) { mLayersWithQueuedFrames.push_back(layer); } else { @@ -3335,7 +3338,7 @@ bool SurfaceFlinger::handlePageFlip() Mutex::Autolock lock(mStateLock); for (auto& layer : mLayersWithQueuedFrames) { - if (layer->latchBuffer(visibleRegions, latchTime)) { + if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) { mLayersPendingRefresh.push_back(layer); } layer->useSurfaceDamage(); @@ -3656,6 +3659,7 @@ bool SurfaceFlinger::flushTransactionQueues() { while (!transactionQueue.empty()) { const auto& transaction = transactionQueue.front(); if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime, + true /* useCachedExpectedPresentTime */, transaction.states)) { setTransactionFlags(eTransactionFlushNeeded); break; @@ -3708,8 +3712,12 @@ bool SurfaceFlinger::containsAnyInvalidClientState(const Vector& } bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, + bool useCachedExpectedPresentTime, const Vector& states) { - nsecs_t expectedPresentTime = getExpectedPresentTime(); + if (!useCachedExpectedPresentTime) + populateExpectedPresentTime(); + + const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); // Do not present if the desiredPresentTime has not passed unless it is more than one second // in the future. We ignore timestamps more than 1 second in the future for stability reasons. if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime && @@ -3764,8 +3772,10 @@ void SurfaceFlinger::setTransactionState(const Vector& states, itr = mTransactionQueues.find(applyToken); } } - if (itr != mTransactionQueues.end() || - !transactionIsReadyToBeApplied(desiredPresentTime, states)) { + + // Expected present time is computed and cached on invalidate, so it may be stale. + if (itr != mTransactionQueues.end() || !transactionIsReadyToBeApplied( + desiredPresentTime, false /* useCachedExpectedPresentTime */, states)) { mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime, uncacheBuffer, listenerCallbacks, postTime, privileged); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 0e6eacf72b..099ba723ee 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -295,18 +295,13 @@ public: // main thread function to enable/disable h/w composer event void setPrimaryVsyncEnabledInternal(bool enabled); + void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled); // called on the main thread by MessageQueue when an internal message // is received // TODO: this should be made accessible only to MessageQueue void onMessageReceived(int32_t what); - // populates the expected present time for this frame. - // When we are in negative offsets, we perform a correction so that the - // predicted vsync for the *next* frame is used instead. - void populateExpectedPresentTime(); - nsecs_t getExpectedPresentTime() const { return mExpectedPresentTime; } - // for debugging only // TODO: this should be made accessible only to HWComposer const Vector>& getLayerSortedByZForHwcDisplay(DisplayId displayId); @@ -585,6 +580,7 @@ private: void commitOffscreenLayers(); bool containsAnyInvalidClientState(const Vector& states); bool transactionIsReadyToBeApplied(int64_t desiredPresentTime, + bool useCachedExpectedPresentTime, const Vector& states); uint32_t setClientStateLocked(const ComposerState& composerState, int64_t desiredPresentTime, const std::vector& listenerCallbacks, @@ -816,6 +812,12 @@ private: bool isDisplayConfigAllowed(int32_t configId) const REQUIRES(mStateLock); + bool previousFrameMissed(); + + // Populates the expected present time for this frame. For negative offsets, performs a + // correction using the predicted vsync for the next frame instead. + void populateExpectedPresentTime(); + /* * Display identification */ @@ -844,9 +846,6 @@ private: return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt; } - bool previousFrameMissed(); - void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled); - /* * Debugging & dumpsys */ @@ -1135,6 +1134,8 @@ private: scheduler::RefreshRateConfigs mRefreshRateConfigs; scheduler::RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, *mTimeStats}; + std::atomic mExpectedPresentTime = 0; + // All configs are allowed if the set is empty. using DisplayConfigs = std::set; DisplayConfigs mAllowedDisplayConfigs GUARDED_BY(mStateLock); @@ -1188,8 +1189,6 @@ private: // Flags to capture the state of Vsync in HWC HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable; HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable; - - nsecs_t mExpectedPresentTime; }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index e6211c488e..ce67a19c3b 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -502,7 +502,7 @@ struct BaseLayerProperties { EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true)); bool ignoredRecomputeVisibleRegions; - layer->latchBuffer(ignoredRecomputeVisibleRegions, 0); + layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, 0); Mock::VerifyAndClear(test->mRenderEngine); } -- GitLab From eddeda1efaec15229df62d6218c39cb45cfc04c6 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Fri, 19 Jul 2019 11:54:13 -0700 Subject: [PATCH 0100/1255] SF: Clean up VSyncModulator This CL refactors redundant code, removes an unnecessary hash map, and defers construction to obviate ConnectionHandle null checks. Bug: 130554049 Bug: 133854162 Test: Boot Change-Id: I0cce9147aebb61c15104fdad3096d5077fc852c4 --- .../surfaceflinger/Scheduler/PhaseOffsets.cpp | 143 ++++++++---------- .../surfaceflinger/Scheduler/PhaseOffsets.h | 52 +++---- .../Scheduler/VSyncModulator.cpp | 83 +++++----- .../surfaceflinger/Scheduler/VSyncModulator.h | 73 ++++----- services/surfaceflinger/SurfaceFlinger.cpp | 45 +++--- services/surfaceflinger/SurfaceFlinger.h | 12 +- .../tests/unittests/FakePhaseOffsets.h | 44 ++---- 7 files changed, 186 insertions(+), 266 deletions(-) diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 8a2604f4a3..9f8567d0ec 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -18,115 +18,102 @@ #include -#include "SurfaceFlingerProperties.h" - -namespace android { -using namespace android::sysprop; - -namespace scheduler { - -using RefreshRateType = RefreshRateConfigs::RefreshRateType; -PhaseOffsets::~PhaseOffsets() = default; +#include -namespace impl { -PhaseOffsets::PhaseOffsets() { - int64_t vsyncPhaseOffsetNs = vsync_event_phase_offset_ns(1000000); +#include "SurfaceFlingerProperties.h" - int64_t sfVsyncPhaseOffsetNs = vsync_sf_event_phase_offset_ns(1000000); +namespace { +std::optional getProperty(const char* name) { char value[PROPERTY_VALUE_MAX]; - property_get("debug.sf.early_phase_offset_ns", value, "-1"); - const int earlySfOffsetNs = atoi(value); - - property_get("debug.sf.early_gl_phase_offset_ns", value, "-1"); - const int earlyGlSfOffsetNs = atoi(value); - - property_get("debug.sf.early_app_phase_offset_ns", value, "-1"); - const int earlyAppOffsetNs = atoi(value); - - property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1"); - const int earlyGlAppOffsetNs = atoi(value); - - property_get("debug.sf.high_fps_early_phase_offset_ns", value, "-1"); - const int highFpsEarlySfOffsetNs = atoi(value); - - property_get("debug.sf.high_fps_early_gl_phase_offset_ns", value, "-1"); - const int highFpsEarlyGlSfOffsetNs = atoi(value); + property_get(name, value, "-1"); + if (const int i = atoi(value); i != -1) return i; + return std::nullopt; +} - property_get("debug.sf.high_fps_early_app_phase_offset_ns", value, "-1"); - const int highFpsEarlyAppOffsetNs = atoi(value); +} // namespace - property_get("debug.sf.high_fps_early_gl_app_phase_offset_ns", value, "-1"); - const int highFpsEarlyGlAppOffsetNs = atoi(value); +namespace android::scheduler { - // TODO(b/122905996): Define these in device.mk. - property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "2000000"); - const int highFpsLateAppOffsetNs = atoi(value); +PhaseOffsets::~PhaseOffsets() = default; - property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "1000000"); - const int highFpsLateSfOffsetNs = atoi(value); +namespace impl { +PhaseOffsets::PhaseOffsets() { // Below defines the threshold when an offset is considered to be negative, i.e. targeting // for the N+2 vsync instead of N+1. This means that: // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync. // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync. - property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1"); - const int phaseOffsetThresholdForNextVsyncNs = atoi(value); - - Offsets defaultOffsets; - Offsets highFpsOffsets; - defaultOffsets.early = {RefreshRateType::DEFAULT, - earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs, - earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs}; - defaultOffsets.earlyGl = {RefreshRateType::DEFAULT, - earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs, - earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs}; - defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}; - - highFpsOffsets.early = {RefreshRateType::PERFORMANCE, - highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs - : highFpsLateSfOffsetNs, - highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs - : highFpsLateAppOffsetNs}; - highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE, - highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs - : highFpsLateSfOffsetNs, - highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs - : highFpsLateAppOffsetNs}; - highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, - highFpsLateAppOffsetNs}; + const nsecs_t thresholdForNextVsync = + getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns") + .value_or(std::numeric_limits::max()); + + const Offsets defaultOffsets = getDefaultOffsets(thresholdForNextVsync); + const Offsets highFpsOffsets = getHighFpsOffsets(thresholdForNextVsync); mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets}); mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets}); mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets}); - - mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1 - ? phaseOffsetThresholdForNextVsyncNs - : std::numeric_limits::max(); } PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate( - android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const { + RefreshRateType refreshRateType) const { return mOffsets.at(refreshRateType); } void PhaseOffsets::dump(std::string& result) const { - const auto [early, earlyGl, late] = getCurrentOffsets(); + const auto [early, earlyGl, late, threshold] = getCurrentOffsets(); base::StringAppendF(&result, " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n" " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n" - "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n", - late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf); + "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n" + "threshold for next VSYNC: %" PRId64 " ns\n", + late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf, threshold); } -nsecs_t PhaseOffsets::getCurrentAppOffset() { - return getCurrentOffsets().late.app; +PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t thresholdForNextVsync) { + const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000); + const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000); + + const auto earlySfOffsetNs = getProperty("debug.sf.early_phase_offset_ns"); + const auto earlyGlSfOffsetNs = getProperty("debug.sf.early_gl_phase_offset_ns"); + const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns"); + const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns"); + + return {{RefreshRateType::DEFAULT, earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs), + earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs)}, + + {RefreshRateType::DEFAULT, earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs), + earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs)}, + + {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}, + + thresholdForNextVsync}; } -nsecs_t PhaseOffsets::getCurrentSfOffset() { - return getCurrentOffsets().late.sf; +PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t thresholdForNextVsync) { + // TODO(b/122905996): Define these in device.mk. + const int highFpsLateAppOffsetNs = + getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000); + const int highFpsLateSfOffsetNs = + getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000); + + const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns"); + const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns"); + const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns"); + const auto highFpsEarlyGlAppOffsetNs = + getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"); + + return {{RefreshRateType::PERFORMANCE, highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs), + highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs)}, + + {RefreshRateType::PERFORMANCE, highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs), + highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs)}, + + {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}, + + thresholdForNextVsync}; } } // namespace impl -} // namespace scheduler -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h index 2b5c2f10f1..2c52432448 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.h +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h @@ -16,14 +16,12 @@ #pragma once -#include #include #include "RefreshRateConfigs.h" #include "VSyncModulator.h" -namespace android { -namespace scheduler { +namespace android::scheduler { /* * This class encapsulates offsets for different refresh rates. Depending @@ -33,35 +31,33 @@ namespace scheduler { */ class PhaseOffsets { public: - struct Offsets { - VSyncModulator::Offsets early; - VSyncModulator::Offsets earlyGl; - VSyncModulator::Offsets late; - }; + using Offsets = VSyncModulator::OffsetsConfig; + using RefreshRateType = RefreshRateConfigs::RefreshRateType; virtual ~PhaseOffsets(); - virtual nsecs_t getCurrentAppOffset() = 0; - virtual nsecs_t getCurrentSfOffset() = 0; - virtual Offsets getOffsetsForRefreshRate( - RefreshRateConfigs::RefreshRateType refreshRateType) const = 0; + nsecs_t getCurrentAppOffset() const { return getCurrentOffsets().late.app; } + nsecs_t getCurrentSfOffset() const { return getCurrentOffsets().late.sf; } + nsecs_t getOffsetThresholdForNextVsync() const { + return getCurrentOffsets().thresholdForNextVsync; + } + virtual Offsets getCurrentOffsets() const = 0; - virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0; - virtual nsecs_t getOffsetThresholdForNextVsync() const = 0; + virtual Offsets getOffsetsForRefreshRate(RefreshRateType) const = 0; + + virtual void setRefreshRateType(RefreshRateType) = 0; + virtual void dump(std::string& result) const = 0; }; namespace impl { + class PhaseOffsets : public scheduler::PhaseOffsets { public: PhaseOffsets(); - nsecs_t getCurrentAppOffset() override; - nsecs_t getCurrentSfOffset() override; - // Returns early, early GL, and late offsets for Apps and SF for a given refresh rate. - Offsets getOffsetsForRefreshRate( - RefreshRateConfigs::RefreshRateType refreshRateType) const override; + Offsets getOffsetsForRefreshRate(RefreshRateType) const override; // Returns early, early GL, and late offsets for Apps and SF. Offsets getCurrentOffsets() const override { @@ -70,23 +66,21 @@ public: // This function should be called when the device is switching between different // refresh rates, to properly update the offsets. - void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) override { + void setRefreshRateType(RefreshRateType refreshRateType) override { mRefreshRateType = refreshRateType; } - nsecs_t getOffsetThresholdForNextVsync() const override { return mOffsetThresholdForNextVsync; } - // Returns current offsets in human friendly format. void dump(std::string& result) const override; private: - std::atomic mRefreshRateType = - RefreshRateConfigs::RefreshRateType::DEFAULT; + static Offsets getDefaultOffsets(nsecs_t thresholdForNextVsync); + static Offsets getHighFpsOffsets(nsecs_t thresholdForNextVsync); + + std::atomic mRefreshRateType = RefreshRateType::DEFAULT; - std::unordered_map mOffsets; - nsecs_t mOffsetThresholdForNextVsync; + std::unordered_map mOffsets; }; -} // namespace impl -} // namespace scheduler -} // namespace android +} // namespace impl +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp index 7a3bf8edaf..f267c99e15 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp +++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp @@ -24,25 +24,24 @@ #include #include -namespace android { - -using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; -VSyncModulator::VSyncModulator() { +namespace android::scheduler { + +VSyncModulator::VSyncModulator(Scheduler& scheduler, + const sp& appConnectionHandle, + const sp& sfConnectionHandle, + const OffsetsConfig& config) + : mScheduler(scheduler), + mAppConnectionHandle(appConnectionHandle), + mSfConnectionHandle(sfConnectionHandle), + mOffsetsConfig(config) { char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.vsync_trace_detailed_info", value, "0"); mTraceDetailedInfo = atoi(value); - // Populate the offset map with some default offsets. - const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0}; - setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0); } -void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, - nsecs_t thresholdForNextVsync) { +void VSyncModulator::setPhaseOffsets(const OffsetsConfig& config) { std::lock_guard lock(mMutex); - mOffsetMap.insert_or_assign(OffsetType::Early, early); - mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl); - mOffsetMap.insert_or_assign(OffsetType::Late, late); - mThresholdForNextVsync = thresholdForNextVsync; + mOffsetsConfig = config; updateOffsetsLocked(); } @@ -100,25 +99,21 @@ void VSyncModulator::onRefreshed(bool usedRenderEngine) { } } -VSyncModulator::Offsets VSyncModulator::getOffsets() { +VSyncModulator::Offsets VSyncModulator::getOffsets() const { std::lock_guard lock(mMutex); return mOffsets; } -VSyncModulator::Offsets VSyncModulator::getNextOffsets() { - return mOffsetMap.at(getNextOffsetType()); -} - -VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() { +const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const { // Early offsets are used if we're in the middle of a refresh rate // change, or if we recently begin a transaction. if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { - return OffsetType::Early; + return mOffsetsConfig.early; } else if (mRemainingRenderEngineUsageCount > 0) { - return OffsetType::EarlyGl; + return mOffsetsConfig.earlyGl; } else { - return OffsetType::Late; + return mOffsetsConfig.late; } } @@ -128,37 +123,29 @@ void VSyncModulator::updateOffsets() { } void VSyncModulator::updateOffsetsLocked() { - const Offsets desired = getNextOffsets(); - - if (mSfConnectionHandle != nullptr) { - mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); - } + const Offsets& offsets = getNextOffsets(); - if (mAppConnectionHandle != nullptr) { - mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); - } + mScheduler.setPhaseOffset(mSfConnectionHandle, offsets.sf); + mScheduler.setPhaseOffset(mAppConnectionHandle, offsets.app); - flushOffsets(); -} + mOffsets = offsets; -void VSyncModulator::flushOffsets() { - OffsetType type = getNextOffsetType(); - mOffsets = mOffsetMap.at(type); if (!mTraceDetailedInfo) { return; } - ATRACE_INT("Vsync-EarlyOffsetsOn", - mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early); - ATRACE_INT("Vsync-EarlyGLOffsetsOn", - mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl); - ATRACE_INT("Vsync-LateOffsetsOn", - mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late); - ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", - mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early); - ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", - mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl); - ATRACE_INT("Vsync-HighFpsLateOffsetsOn", - mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late); + + const bool isDefault = mOffsets.fpsMode == RefreshRateType::DEFAULT; + const bool isPerformance = mOffsets.fpsMode == RefreshRateType::PERFORMANCE; + const bool isEarly = &offsets == &mOffsetsConfig.early; + const bool isEarlyGl = &offsets == &mOffsetsConfig.earlyGl; + const bool isLate = &offsets == &mOffsetsConfig.late; + + ATRACE_INT("Vsync-EarlyOffsetsOn", isDefault && isEarly); + ATRACE_INT("Vsync-EarlyGLOffsetsOn", isDefault && isEarlyGl); + ATRACE_INT("Vsync-LateOffsetsOn", isDefault && isLate); + ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", isPerformance && isEarly); + ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", isPerformance && isEarlyGl); + ATRACE_INT("Vsync-HighFpsLateOffsetsOn", isPerformance && isLate); } -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index ddbd221ef1..636c8c8b28 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -16,12 +16,11 @@ #pragma once -#include #include #include "Scheduler.h" -namespace android { +namespace android::scheduler { /* * Modulates the vsync-offsets depending on current SurfaceFlinger state. @@ -31,51 +30,36 @@ private: // Number of frames we'll keep the early phase offsets once they are activated for a // transaction. This acts as a low-pass filter in case the client isn't quick enough in // sending new transactions. - const int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2; + static constexpr int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2; // Number of frames we'll keep the early gl phase offsets once they are activated. // This acts as a low-pass filter to avoid scenarios where we rapidly // switch in and out of gl composition. - const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; + static constexpr int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; -public: - VSyncModulator(); + using RefreshRateType = RefreshRateConfigs::RefreshRateType; +public: // Wrapper for a collection of surfaceflinger/app offsets for a particular - // configuration . + // configuration. struct Offsets { - scheduler::RefreshRateConfigs::RefreshRateType fpsMode; + RefreshRateType fpsMode; nsecs_t sf; nsecs_t app; }; - enum class OffsetType { - Early, - EarlyGl, - Late, + struct OffsetsConfig { + Offsets early; // For transactions with the eEarlyWakeup flag. + Offsets earlyGl; // As above but while compositing with GL. + Offsets late; // Default. + + nsecs_t thresholdForNextVsync; }; - // Sets the phase offsets - // - // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction - // as early. May be the same as late, in which case we don't shift offsets. - // sfEarlyGl: Like sfEarly, but only if we used GL composition. If we use both GL composition - // and the transaction was marked as early, we'll use sfEarly. - // sfLate: The regular SF vsync phase offset. - // appEarly: Like sfEarly, but for the app-vsync - // appEarlyGl: Like sfEarlyGl, but for the app-vsync. - // appLate: The regular app vsync phase offset. - void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, - nsecs_t thresholdForNextVsync) EXCLUDES(mMutex); - - // Sets the scheduler and vsync connection handlers. - void setSchedulerAndHandles(Scheduler* scheduler, - Scheduler::ConnectionHandle* appConnectionHandle, - Scheduler::ConnectionHandle* sfConnectionHandle) { - mScheduler = scheduler; - mAppConnectionHandle = appConnectionHandle; - mSfConnectionHandle = sfConnectionHandle; - } + VSyncModulator(Scheduler&, const sp& appConnectionHandle, + const sp& sfConnectionHandle, const OffsetsConfig&); + + void setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex); // Signals that a transaction has started, and changes offsets accordingly. void setTransactionStart(Scheduler::TransactionStart transactionStart); @@ -98,28 +82,23 @@ public: void onRefreshed(bool usedRenderEngine); // Returns the offsets that we are currently using - Offsets getOffsets() EXCLUDES(mMutex); + Offsets getOffsets() const EXCLUDES(mMutex); private: // Returns the next offsets that we should be using - Offsets getNextOffsets() REQUIRES(mMutex); - // Returns the next offset type that we should use. - OffsetType getNextOffsetType(); + const Offsets& getNextOffsets() const REQUIRES(mMutex); // Updates offsets and persists them into the scheduler framework. void updateOffsets() EXCLUDES(mMutex); void updateOffsetsLocked() REQUIRES(mMutex); - // Updates the internal offsets and offset type. - void flushOffsets() REQUIRES(mMutex); - mutable std::mutex mMutex; - std::unordered_map mOffsetMap GUARDED_BY(mMutex); - nsecs_t mThresholdForNextVsync; + Scheduler& mScheduler; + const sp mAppConnectionHandle; + const sp mSfConnectionHandle; - Scheduler* mScheduler = nullptr; - Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr; - Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr; + mutable std::mutex mMutex; + OffsetsConfig mOffsetsConfig GUARDED_BY(mMutex); - Offsets mOffsets GUARDED_BY(mMutex) = {Scheduler::RefreshRateType::DEFAULT, 0, 0}; + Offsets mOffsets GUARDED_BY(mMutex){mOffsetsConfig.late}; std::atomic mTransactionStart = Scheduler::TransactionStart::NORMAL; @@ -130,4 +109,4 @@ private: bool mTraceDetailedInfo = false; }; -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index cd80f2b359..604ad34ebd 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -276,11 +276,11 @@ SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {} SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) : mFactory(factory), - mPhaseOffsets(mFactory.createPhaseOffsets()), mInterceptor(mFactory.createSurfaceInterceptor(this)), mTimeStats(mFactory.createTimeStats()), mEventQueue(mFactory.createMessageQueue()), - mCompositionEngine(mFactory.createCompositionEngine()) {} + mCompositionEngine(mFactory.createCompositionEngine()), + mPhaseOffsets(mFactory.createPhaseOffsets()) {} SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) { ALOGI("SurfaceFlinger is starting"); @@ -386,10 +386,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("debug.sf.luma_sampling", value, "1"); mLumaSampling = atoi(value); - const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late, - mPhaseOffsets->getOffsetThresholdForNextVsync()); - // We should be reading 'persist.sys.sf.color_saturation' here // but since /data may be encrypted, we need to wait until after vold // comes online to attempt to read the property. The property is @@ -616,7 +612,7 @@ void SurfaceFlinger::init() { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); - ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset()); + ALOGI("Phase offset: %" PRId64 " ns", mPhaseOffsets->getCurrentAppOffset()); Mutex::Autolock _l(mStateLock); // start the EventThread @@ -627,20 +623,21 @@ void SurfaceFlinger::init() { mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this)); mAppConnectionHandle = - mScheduler->createConnection("app", mVsyncModulator.getOffsets().app, + mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(), mPhaseOffsets->getOffsetThresholdForNextVsync(), resyncCallback, impl::EventThread::InterceptVSyncsCallback()); mSfConnectionHandle = - mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf, + mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(), mPhaseOffsets->getOffsetThresholdForNextVsync(), resyncCallback, [this](nsecs_t timestamp) { mInterceptor->saveVSyncEvent(timestamp); }); mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle)); - mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(), - mSfConnectionHandle.get()); + + mVSyncModulator.emplace(*mScheduler, mAppConnectionHandle, mSfConnectionHandle, + mPhaseOffsets->getCurrentOffsets()); mRegionSamplingThread = new RegionSamplingThread(*this, *mScheduler, @@ -969,11 +966,9 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); // As we called to set period, we will call to onRefreshRateChangeCompleted once // DispSync model is locked. - mVsyncModulator.onRefreshRateChangeInitiated(); + mVSyncModulator->onRefreshRateChangeInitiated(); mPhaseOffsets->setRefreshRateType(info.type); - const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late, - mPhaseOffsets->getOffsetThresholdForNextVsync()); + mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets()); } mDesiredActiveConfigChanged = true; ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); @@ -1006,9 +1001,7 @@ void SurfaceFlinger::setActiveConfigInternal() { display->setActiveConfig(mUpcomingActiveConfig.configId); mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); - const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late, - mPhaseOffsets->getOffsetThresholdForNextVsync()); + mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets()); ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId); if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) { @@ -1025,9 +1018,7 @@ void SurfaceFlinger::desiredActiveConfigChangeDone() { mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); - const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late, - mPhaseOffsets->getOffsetThresholdForNextVsync()); + mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets()); } bool SurfaceFlinger::performSetActiveConfig() { @@ -1494,7 +1485,7 @@ void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDispl bool periodFlushed = false; mScheduler->addResyncSample(timestamp, &periodFlushed); if (periodFlushed) { - mVsyncModulator.onRefreshRateChangeCompleted(); + mVSyncModulator->onRefreshRateChangeCompleted(); } } @@ -1686,7 +1677,7 @@ bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS { // woken up before the actual vsync but targeting the next vsync, we need to check // fence N-2 const sp& fence = - mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync() + mVSyncModulator->getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync() ? mPreviousPresentFences[0] : mPreviousPresentFences[1]; @@ -1698,7 +1689,7 @@ void SurfaceFlinger::populateExpectedPresentTime() { mScheduler->getDisplayStatInfo(&stats); const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(); // Inflate the expected present time if we're targetting the next vsync. - mExpectedPresentTime.store(mVsyncModulator.getOffsets().sf < + mExpectedPresentTime.store(mVSyncModulator->getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync() ? presentTime : presentTime + stats.vsyncPeriod); @@ -1831,7 +1822,7 @@ void SurfaceFlinger::handleMessageRefresh() { mHadDeviceComposition || getHwComposer().hasDeviceComposition(displayId); } - mVsyncModulator.onRefreshed(mHadClientComposition); + mVSyncModulator->onRefreshed(mHadClientComposition); mLayersWithQueuedFrames.clear(); if (mVisibleRegionsDirty) { @@ -2583,7 +2574,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) // with mStateLock held to guarantee that mCurrentState won't change // until the transaction is committed. - mVsyncModulator.onTransactionHandled(); + mVSyncModulator->onTransactionHandled(); transactionFlags = getTransactionFlags(eTransactionMask); handleTransactionLocked(transactionFlags); @@ -3636,7 +3627,7 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) { uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, Scheduler::TransactionStart transactionStart) { uint32_t old = mTransactionFlags.fetch_or(flags); - mVsyncModulator.setTransactionStart(transactionStart); + mVSyncModulator->setTransactionStart(transactionStart); if ((old & flags)==0) { // wake the server up signalTransaction(); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 099ba723ee..d474eaa353 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -962,11 +963,6 @@ private: std::unique_ptr mInjectorEventThread; std::unique_ptr mVSyncInjector; - // Calculates correct offsets. - VSyncModulator mVsyncModulator; - // Keeps track of all available phase offsets for different refresh types. - const std::unique_ptr mPhaseOffsets; - // Can only accessed from the main thread, these members // don't need synchronization State mDrawingState{LayerVector::StateSet::Drawing}; @@ -1131,6 +1127,12 @@ private: sp mAppConnectionHandle; sp mSfConnectionHandle; + // Stores phase offsets configured per refresh rate. + const std::unique_ptr mPhaseOffsets; + + // Optional to defer construction until scheduler connections are created. + std::optional mVSyncModulator; + scheduler::RefreshRateConfigs mRefreshRateConfigs; scheduler::RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, *mTimeStats}; diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h index 1d7501102e..66c7f6b81f 100644 --- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h +++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h @@ -20,42 +20,22 @@ #include "Scheduler/PhaseOffsets.h" -namespace android { -namespace scheduler { +namespace android::scheduler { -using RefreshRateType = RefreshRateConfigs::RefreshRateType; +struct FakePhaseOffsets : PhaseOffsets { + static constexpr nsecs_t FAKE_PHASE_OFFSET_NS = 0; -class FakePhaseOffsets : public android::scheduler::PhaseOffsets { - nsecs_t FAKE_PHASE_OFFSET_NS = 0; + Offsets getOffsetsForRefreshRate(RefreshRateType) const override { return getCurrentOffsets(); } -public: - FakePhaseOffsets() = default; - ~FakePhaseOffsets() = default; - - nsecs_t getCurrentAppOffset() override { return FAKE_PHASE_OFFSET_NS; } - nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; } - - PhaseOffsets::Offsets getOffsetsForRefreshRate( - RefreshRateType /*refreshRateType*/) const override { - return getCurrentOffsets(); - } - - // Returns early, early GL, and late offsets for Apps and SF. - PhaseOffsets::Offsets getCurrentOffsets() const override { - return Offsets{{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}}; + Offsets getCurrentOffsets() const override { + return {{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + FAKE_PHASE_OFFSET_NS}; } - // This function should be called when the device is switching between different - // refresh rates, to properly update the offsets. - void setRefreshRateType(RefreshRateType /*refreshRateType*/) override {} - - nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; } - - // Returns current offsets in human friendly format. - void dump(std::string& /*result*/) const override {} + void setRefreshRateType(RefreshRateType) override {} + void dump(std::string&) const override {} }; -} // namespace scheduler -} // namespace android +} // namespace android::scheduler -- GitLab From 50204dd25f01100a13cb3db9b33f024c1bee13f6 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 19 Jul 2019 15:47:11 -0700 Subject: [PATCH 0101/1255] SurfaceFlinger: add TracedOrdinal There are few placed in the code where we trace the value of an ordinal to systrace. This change adds TracedOrdinal that automatically trace ordinals when their value change making the code cleaner. Test: collect systrace Bug: 131091080 Change-Id: I53351d090a0764c2f5ba8db8ac02849f78e1109b --- .../surfaceflinger/Scheduler/DispSync.cpp | 11 ++-- .../Scheduler/DispSyncSource.cpp | 19 +----- .../surfaceflinger/Scheduler/DispSyncSource.h | 10 +-- services/surfaceflinger/SurfaceFlinger.cpp | 19 +++--- services/surfaceflinger/SurfaceFlinger.h | 4 +- services/surfaceflinger/TracedOrdinal.h | 64 +++++++++++++++++++ 6 files changed, 85 insertions(+), 42 deletions(-) create mode 100644 services/surfaceflinger/TracedOrdinal.h diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index 0c94052979..ad5eb332c5 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -64,7 +64,7 @@ public: DispSyncThread(const char* name, bool showTraceDetailedInfo) : mName(name), mStop(false), - mModelLocked(false), + mModelLocked("DispSync:ModelLocked", false), mPeriod(0), mPhase(0), mReferenceTime(0), @@ -121,13 +121,11 @@ public: void lockModel() { Mutex::Autolock lock(mMutex); mModelLocked = true; - ATRACE_INT("DispSync:ModelLocked", mModelLocked); } void unlockModel() { Mutex::Autolock lock(mMutex); mModelLocked = false; - ATRACE_INT("DispSync:ModelLocked", mModelLocked); } virtual bool threadLoop() { @@ -431,7 +429,7 @@ private: const char* const mName; bool mStop; - bool mModelLocked; + TracedOrdinal mModelLocked; nsecs_t mPeriod; nsecs_t mPhase; @@ -454,15 +452,14 @@ private: class ZeroPhaseTracer : public DispSync::Callback { public: - ZeroPhaseTracer() : mParity(false) {} + ZeroPhaseTracer() : mParity("ZERO_PHASE_VSYNC", false) {} virtual void onDispSyncEvent(nsecs_t /*when*/) { mParity = !mParity; - ATRACE_INT("ZERO_PHASE_VSYNC", mParity ? 1 : 0); } private: - bool mParity; + TracedOrdinal mParity; }; DispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0) { diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 5faf46e31e..571c9ca362 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -31,19 +31,16 @@ DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, nsecs_t offsetThresholdForNextVsync, bool traceVsync, const char* name) : mName(name), + mValue(base::StringPrintf("VSYNC-%s", name), 0), mTraceVsync(traceVsync), mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)), - mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)), - mVsyncOffsetLabel(base::StringPrintf("VsyncOffset-%s", name)), - mVsyncNegativeOffsetLabel(base::StringPrintf("VsyncNegativeOffset-%s", name)), mDispSync(dispSync), - mPhaseOffset(phaseOffset), + mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset), mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {} void DispSyncSource::setVSyncEnabled(bool enable) { std::lock_guard lock(mVsyncMutex); if (enable) { - tracePhaseOffset(); status_t err = mDispSync->addEventListener(mName, mPhaseOffset, static_cast(this), mLastCallbackTime); @@ -83,7 +80,6 @@ void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) { } mPhaseOffset = phaseOffset; - tracePhaseOffset(); // If we're not enabled, we don't need to mess with the listeners if (!mEnabled) { @@ -106,7 +102,6 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) { if (mTraceVsync) { mValue = (mValue + 1) % 2; - ATRACE_INT(mVsyncEventLabel.c_str(), mValue); } if (callback != nullptr) { @@ -114,14 +109,4 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) { } } -void DispSyncSource::tracePhaseOffset() { - if (mPhaseOffset > 0) { - ATRACE_INT(mVsyncOffsetLabel.c_str(), mPhaseOffset); - ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), 0); - } else { - ATRACE_INT(mVsyncOffsetLabel.c_str(), 0); - ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), -mPhaseOffset); - } -} - } // namespace android diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h index 50560a5a2b..740c8c4ee1 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.h +++ b/services/surfaceflinger/Scheduler/DispSyncSource.h @@ -20,6 +20,7 @@ #include "DispSync.h" #include "EventThread.h" +#include "TracedOrdinal.h" namespace android { @@ -39,16 +40,11 @@ private: // The following method is the implementation of the DispSync::Callback. virtual void onDispSyncEvent(nsecs_t when); - void tracePhaseOffset() REQUIRES(mVsyncMutex); - const char* const mName; - int mValue = 0; + TracedOrdinal mValue; const bool mTraceVsync; const std::string mVsyncOnLabel; - const std::string mVsyncEventLabel; - const std::string mVsyncOffsetLabel; - const std::string mVsyncNegativeOffsetLabel; nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0; DispSync* mDispSync; @@ -57,7 +53,7 @@ private: VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr; std::mutex mVsyncMutex; - nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex); + TracedOrdinal mPhaseOffset GUARDED_BY(mVsyncMutex); const nsecs_t mOffsetThresholdForNextVsync; bool mEnabled GUARDED_BY(mVsyncMutex) = false; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 99440a6d5e..210a28ad4d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -976,7 +976,6 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { mPhaseOffsets->getOffsetThresholdForNextVsync()); } mDesiredActiveConfigChanged = true; - ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); if (mRefreshRateOverlay) { mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type); @@ -1021,7 +1020,6 @@ void SurfaceFlinger::desiredActiveConfigChangeDone() { std::lock_guard lock(mActiveConfigLock); mDesiredActiveConfig.event = Scheduler::ConfigEvent::None; mDesiredActiveConfigChanged = false; - ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); @@ -1713,12 +1711,12 @@ void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { // seeing this same value. populateExpectedPresentTime(); - bool frameMissed = previousFrameMissed(); - bool hwcFrameMissed = mHadDeviceComposition && frameMissed; - bool gpuFrameMissed = mHadClientComposition && frameMissed; - ATRACE_INT("FrameMissed", static_cast(frameMissed)); - ATRACE_INT("HwcFrameMissed", static_cast(hwcFrameMissed)); - ATRACE_INT("GpuFrameMissed", static_cast(gpuFrameMissed)); + const TracedOrdinal frameMissed = {"FrameMissed", previousFrameMissed()}; + const TracedOrdinal hwcFrameMissed = {"HwcFrameMissed", + mHadDeviceComposition && frameMissed}; + const TracedOrdinal gpuFrameMissed = {"GpuFrameMissed", + mHadClientComposition && frameMissed}; + if (frameMissed) { mFrameMissedCount++; mTimeStats->incrementMissedFrames(); @@ -3402,8 +3400,9 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& displayDevice, const Region bounds(displayState.bounds); const DisplayRenderArea renderArea(displayDevice); - const bool hasClientComposition = getHwComposer().hasClientComposition(displayId); - ATRACE_INT("hasClientComposition", hasClientComposition); + const TracedOrdinal hasClientComposition = {"hasClientComposition", + getHwComposer().hasClientComposition( + displayId)}; bool applyColorMatrix = false; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 0e6eacf72b..b34ccd16d6 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -60,6 +60,7 @@ #include "Scheduler/VSyncModulator.h" #include "SurfaceFlingerFactory.h" #include "SurfaceTracing.h" +#include "TracedOrdinal.h" #include "TransactionCompletedThread.h" #include @@ -1148,7 +1149,8 @@ private: ActiveConfigInfo mDesiredActiveConfig GUARDED_BY(mActiveConfigLock); // below flags are set by main thread only - bool mDesiredActiveConfigChanged GUARDED_BY(mActiveConfigLock) = false; + TracedOrdinal mDesiredActiveConfigChanged + GUARDED_BY(mActiveConfigLock) = {"DesiredActiveConfigChanged", false}; bool mCheckPendingFence = false; bool mLumaSampling = true; diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h new file mode 100644 index 0000000000..fb0f02ee1f --- /dev/null +++ b/services/surfaceflinger/TracedOrdinal.h @@ -0,0 +1,64 @@ +/* + * 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 +#include +#include +#include + +template +class TracedOrdinal { +public: + static_assert(std::is_same() || (std::is_signed() && std::is_integral()), + "Type is not supported. Please test it with systrace before adding " + "it to the list."); + + TracedOrdinal(std::string name, T initialValue) + : mName(name), + mNameNegative(android::base::StringPrintf("%sNegative", name.c_str())), + mHasGoneNegative(std::signbit(initialValue)), + mData(initialValue) { + trace(); + } + + operator T() const { return mData; } + + TracedOrdinal& operator=(T other) { + mData = other; + mHasGoneNegative = mHasGoneNegative || std::signbit(mData); + trace(); + return *this; + } + +private: + void trace() { + if (!std::signbit(mData)) { + ATRACE_INT64(mName.c_str(), int64_t(mData)); + if (mHasGoneNegative) { + ATRACE_INT64(mNameNegative.c_str(), 0); + } + } else { + ATRACE_INT64(mNameNegative.c_str(), -int64_t(mData)); + ATRACE_INT64(mName.c_str(), 0); + } + } + + const std::string mName; + const std::string mNameNegative; + bool mHasGoneNegative; + T mData; +}; -- GitLab From 137d4bc90345b79b2051724b06d4d2935b10c61b Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Thu, 25 Jul 2019 16:55:14 -0700 Subject: [PATCH 0102/1255] Add a system prop to control shader cache priming Shader cache priming in surface flinger can take a significant amount of time at system start, during which the device is basically stuck. Add a system property to allow devices to disable shader cache priming if they want. Bug: 136204746 Test: Added logs locally to confirm setting the prop works as expected: 0 = don't do shader cache priming; any other value = do shader cache priming. Default value is 1. Change-Id: Iafd1823bcb6a96d69ca0bc7a4c0b847f8ceb9e77 --- services/surfaceflinger/SurfaceFlinger.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 99440a6d5e..1c8cc35abf 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -703,7 +703,11 @@ void SurfaceFlinger::init() { // set initial conditions (e.g. unblank default device) initializeDisplays(); - getRenderEngine().primeCache(); + char primeShaderCache[PROPERTY_VALUE_MAX]; + property_get("service.sf.prime_shader_cache", primeShaderCache, "1"); + if (atoi(primeShaderCache)) { + getRenderEngine().primeCache(); + } // Inform native graphics APIs whether the present timestamp is supported: -- GitLab From eafa5ccbeba7770b2594c8cb91035466b87151f9 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Fri, 26 Jul 2019 15:06:25 -0700 Subject: [PATCH 0103/1255] Revert "Output additional trace points for each frame" This reverts commit 361ea97e18e3eacbaa34149c881b2aab440615fd. Test: run systrace with timestats enabled --- services/surfaceflinger/TimeStats/TimeStats.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index c97a19b39b..887b733532 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -173,8 +173,8 @@ void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerID) { ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID, timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime); - const std::string& layerName = layerRecord.layerName; if (prevTimeRecord.ready) { + const std::string& layerName = layerRecord.layerName; if (!mTimeStats.stats.count(layerName)) { mTimeStats.stats[layerName].layerName = layerName; mTimeStats.stats[layerName].packageName = getPackageName(layerName); @@ -220,18 +220,6 @@ void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerID) { timeRecords[0].frameTime.frameNumber, presentToPresentMs); timeStatsLayer.deltas["present2present"].insert(presentToPresentMs); } - - // Output additional trace points to track frame time. - ATRACE_INT64(("TimeStats-Post - " + layerName).c_str(), timeRecords[0].frameTime.postTime); - ATRACE_INT64(("TimeStats-Acquire - " + layerName).c_str(), - timeRecords[0].frameTime.acquireTime); - ATRACE_INT64(("TimeStats-Latch - " + layerName).c_str(), - timeRecords[0].frameTime.latchTime); - ATRACE_INT64(("TimeStats-Desired - " + layerName).c_str(), - timeRecords[0].frameTime.desiredTime); - ATRACE_INT64(("TimeStats-Present - " + layerName).c_str(), - timeRecords[0].frameTime.presentTime); - prevTimeRecord = timeRecords[0]; timeRecords.pop_front(); layerRecord.waitData--; -- GitLab From 49a350aedcc199b90a2992e1c59f753cf9843aa1 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 26 Jul 2019 18:44:23 -0700 Subject: [PATCH 0104/1255] Use std::function for commands While refactoring InputDispatcher to use unique_ptr in order to better understand the lifespands of different object, it became necessary to refactor commands into something more comprehensible. Bug: 70668286 Test: presubmit Change-Id: I273b4f75a32b2c4faf6f907de9f85e7323f2f90d --- services/inputflinger/InputDispatcher.cpp | 32 +++++++++++------------ services/inputflinger/InputDispatcher.h | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index fb28d1b380..fc40eafd08 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -715,7 +715,7 @@ bool InputDispatcher::runCommandsLockedInterruptible() { CommandEntry* commandEntry = mCommandQueue.dequeueAtHead(); Command command = commandEntry->command; - (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible' + command(*this, commandEntry); // commands are implicitly 'LockedInterruptible' commandEntry->connection.clear(); delete commandEntry; @@ -809,8 +809,8 @@ bool InputDispatcher::dispatchConfigurationChangedLocked( resetKeyRepeatLocked(); // Enqueue a command to run outside the lock to tell the policy that the configuration changed. - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyConfigurationChangedLockedInterruptible); + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doNotifyConfigurationChangedLockedInterruptible); commandEntry->eventTime = entry->eventTime; return true; } @@ -884,7 +884,7 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); + &InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); sp focusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry)); if (focusedWindowHandle != nullptr) { @@ -1982,8 +1982,8 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { } } - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doPokeUserActivityLockedInterruptible); + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doPokeUserActivityLockedInterruptible); commandEntry->eventTime = eventEntry->eventTime; commandEntry->userActivityEventType = eventType; } @@ -2200,8 +2200,8 @@ void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t a return; } - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible); + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible); commandEntry->newToken = newToken; } @@ -4087,8 +4087,8 @@ ssize_t InputDispatcher::getConnectionIndexLocked(const sp& inputC void InputDispatcher::onDispatchCycleFinishedLocked( nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled) { - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doDispatchCycleFinishedLockedInterruptible); + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doDispatchCycleFinishedLockedInterruptible); commandEntry->connection = connection; commandEntry->eventTime = currentTime; commandEntry->seq = seq; @@ -4100,8 +4100,8 @@ void InputDispatcher::onDispatchCycleBrokenLocked( ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!", connection->getInputChannelName().c_str()); - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); commandEntry->connection = connection; } @@ -4109,8 +4109,8 @@ void InputDispatcher::onFocusChangedLocked(const sp& oldFocus const sp& newFocus) { sp oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr; sp newToken = newFocus != nullptr ? newFocus->getToken() : nullptr; - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyFocusChangedLockedInterruptible); + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doNotifyFocusChangedLockedInterruptible); commandEntry->oldToken = oldToken; commandEntry->newToken = newToken; } @@ -4142,8 +4142,8 @@ void InputDispatcher::onANRLocked( mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason); dumpDispatchStateLocked(mLastANRState); - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyANRLockedInterruptible); + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doNotifyANRLockedInterruptible); commandEntry->inputApplicationHandle = applicationHandle; commandEntry->inputChannel = windowHandle != nullptr ? getInputChannelLocked(windowHandle->getToken()) : nullptr; diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index c30a8d6703..147437c1a2 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -644,7 +644,7 @@ private: // // Commands are implicitly 'LockedInterruptible'. struct CommandEntry; - typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry); + typedef std::function Command; class Connection; struct CommandEntry : Link { -- GitLab From 359b1ff6b4eb4b26fb5acfd25a21c71f0da7929d Mon Sep 17 00:00:00 2001 From: Abhijeet Kaur Date: Fri, 26 Jul 2019 16:01:36 +0100 Subject: [PATCH 0105/1255] Make dumpstate bugreport names as tmp if called by API Since we are migrating away from dumpstate being directly triggered, only API will be calling dumpstate. API would pass final bugreport file fds to dumpstate, that implies dumpstate bugreport files are getting copied over. Marking these files with a suffix of -tmp as: * These (bugreport .zip and screenshot .png) files are eventually getting deleted. * These (bugreport .zip and screenshot .png) file names can be used by API callers (as the final bugreport names) for consistency. Since the files are in the same dir, need to add suffix to differentiate. Bug: 126862297 Test: * Build and flash to the device * Turn on Settings feature flag to use the bugreport API * Take interactive and full bugreports * run `adb shell ls /bugreports` while bugreports are being generated and after the bugreport is captured * Can see tmp files when the bugreport is in progress * Output file names same as before Change-Id: Ia88e373a373d573d9c1e089924290b9526a3d2e1 --- cmds/dumpstate/dumpstate.cpp | 14 +++++++++----- cmds/dumpstate/dumpstate.h | 5 +++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 2bcb17deee..76580c5e73 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1986,12 +1986,12 @@ static void PrepareToWriteToFile() { } if (ds.options_->do_fb) { - ds.screenshot_path_ = ds.GetPath(".png"); + ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png"); } ds.tmp_path_ = ds.GetPath(".tmp"); ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt"); - std::string destination = ds.options_->bugreport_fd.get() != -1 + std::string destination = ds.CalledByApi() ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get()) : ds.bugreport_internal_dir_.c_str(); MYLOGD( @@ -2005,7 +2005,7 @@ static void PrepareToWriteToFile() { ds.tmp_path_.c_str(), ds.screenshot_path_.c_str()); if (ds.options_->do_zip_file) { - ds.path_ = ds.GetPath(".zip"); + ds.path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip"); MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str()); create_parent_dirs(ds.path_.c_str()); ds.zip_file.reset(fopen(ds.path_.c_str(), "wb")); @@ -2040,7 +2040,7 @@ static void FinalizeFile() { MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str()); ds.name_ = name; if (!ds.screenshot_path_.empty()) { - std::string new_screenshot_path = ds.GetPath(".png"); + std::string new_screenshot_path = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png"); if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) { MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(), new_screenshot_path.c_str(), strerror(errno)); @@ -2058,7 +2058,7 @@ static void FinalizeFile() { } else { do_text_file = false; // If the user has changed the suffix, we need to change the zip file name. - std::string new_path = ds.GetPath(".zip"); + std::string new_path = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip"); if (ds.path_ != new_path) { MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str()); if (rename(ds.path_.c_str(), new_path.c_str())) { @@ -2706,6 +2706,10 @@ bool Dumpstate::IsUserConsentDenied() const { ds.consent_callback_->getResult() == UserConsentResult::DENIED; } +bool Dumpstate::CalledByApi() const { + return ds.options_->bugreport_fd.get() != -1 ? true : false; +} + void Dumpstate::CleanupFiles() { android::os::UnlinkAndLogOnError(tmp_path_); android::os::UnlinkAndLogOnError(screenshot_path_); diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index ae6a72171a..fe330df30a 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -340,6 +340,11 @@ class Dumpstate { */ bool IsUserConsentDenied() const; + /* + * Returns true if dumpstate is called by bugreporting API + */ + bool CalledByApi() const; + /* * Structure to hold options that determine the behavior of dumpstate. */ -- GitLab From 5a0187999da051506f43e4cb18a118f66b14f8ba Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Mon, 29 Jul 2019 07:32:35 -0700 Subject: [PATCH 0106/1255] TracedOrdinal: Avoid string copy For a minor performance improvement, we pass our string to the constructor by const reference. Test: TreeHugger Change-Id: Ibc00f02f46fc25243cc4e6c0af4ed2d2805770da --- services/surfaceflinger/TracedOrdinal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h index fb0f02ee1f..c145a396af 100644 --- a/services/surfaceflinger/TracedOrdinal.h +++ b/services/surfaceflinger/TracedOrdinal.h @@ -27,7 +27,7 @@ public: "Type is not supported. Please test it with systrace before adding " "it to the list."); - TracedOrdinal(std::string name, T initialValue) + TracedOrdinal(const std::string& name, T initialValue) : mName(name), mNameNegative(android::base::StringPrintf("%sNegative", name.c_str())), mHasGoneNegative(std::signbit(initialValue)), -- GitLab From cb12994d1e27aca47df6db63f4790055dc8239b6 Mon Sep 17 00:00:00 2001 From: Robert Delgado Date: Tue, 23 Jul 2019 16:28:20 -0700 Subject: [PATCH 0107/1255] Included android surfaceflinger package to the proto. Test: run yarn dev on transaction. Change-Id: Ie4daa5fb037ead2f1339d36032df1ca702fff3b0 --- cmds/surfacereplayer/proto/src/trace.proto | 1 + cmds/surfacereplayer/replayer/Event.cpp | 1 + cmds/surfacereplayer/replayer/Event.h | 2 ++ cmds/surfacereplayer/replayer/Replayer.h | 2 ++ services/surfaceflinger/SurfaceInterceptor.h | 7 +++++++ services/surfaceflinger/tests/SurfaceInterceptor_test.cpp | 4 +++- 6 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto index a738527fbb..792ff91dfa 100644 --- a/cmds/surfacereplayer/proto/src/trace.proto +++ b/cmds/surfacereplayer/proto/src/trace.proto @@ -1,5 +1,6 @@ syntax = "proto2"; option optimize_for = LITE_RUNTIME; +package android.surfaceflinger; message Trace { repeated Increment increment = 1; diff --git a/cmds/surfacereplayer/replayer/Event.cpp b/cmds/surfacereplayer/replayer/Event.cpp index 390d3982ca..64db5f07b1 100644 --- a/cmds/surfacereplayer/replayer/Event.cpp +++ b/cmds/surfacereplayer/replayer/Event.cpp @@ -17,6 +17,7 @@ #include "Event.h" using namespace android; +using Increment = surfaceflinger::Increment; Event::Event(Increment::IncrementCase type) : mIncrementType(type) {} diff --git a/cmds/surfacereplayer/replayer/Event.h b/cmds/surfacereplayer/replayer/Event.h index 44b60f566a..09a7c248d5 100644 --- a/cmds/surfacereplayer/replayer/Event.h +++ b/cmds/surfacereplayer/replayer/Event.h @@ -24,6 +24,8 @@ namespace android { +using Increment = surfaceflinger::Increment; + class Event { public: Event(Increment::IncrementCase); diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h index d7709cc211..3b94618acb 100644 --- a/cmds/surfacereplayer/replayer/Replayer.h +++ b/cmds/surfacereplayer/replayer/Replayer.h @@ -38,6 +38,8 @@ #include #include +using namespace android::surfaceflinger; + namespace android { const auto DEFAULT_PATH = "/data/local/tmp/SurfaceTrace.dat"; diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h index 7f86c1423a..fdc6c580ed 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -39,6 +39,12 @@ struct ComposerState; struct DisplayDeviceState; struct DisplayState; struct layer_state_t; +using Transaction = surfaceflinger::Transaction; +using Trace = surfaceflinger::Trace; +using Rectangle = surfaceflinger::Rectangle; +using SurfaceChange = surfaceflinger::SurfaceChange; +using Increment = surfaceflinger::Increment; +using DisplayChange = surfaceflinger::DisplayChange; constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat"; @@ -183,6 +189,7 @@ private: }; } // namespace impl + } // namespace android #endif // ANDROID_SURFACEINTERCEPTOR_H diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 26c6da95dd..bc5f1aab42 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -36,6 +36,9 @@ namespace android { using Transaction = SurfaceComposerClient::Transaction; +using SurfaceChange = surfaceflinger::SurfaceChange; +using Trace = surfaceflinger::Trace; +using Increment = surfaceflinger::Increment; constexpr int32_t SCALING_UPDATE = 1; constexpr uint32_t BUFFER_UPDATES = 18; @@ -980,5 +983,4 @@ TEST_F(SurfaceInterceptorTest, InterceptSimultaneousUpdatesWorks) { ASSERT_TRUE(bufferUpdatesFound(capturedTrace)); ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation)); } - } -- GitLab From 6c501ea04e486d9bf5c8a08d0d63dadcd9be83a9 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 24 Jul 2019 15:42:11 -0700 Subject: [PATCH 0108/1255] libtimeinstate: fix bug in clearUidCpuFreqTimes In a preallocated bpf hash table, deleting a map element makes it available for reuse without clearing the data it holds. This reuse can occur when a bpf program calls bpf_map_update_elem with a key not already present in the map. If the map is percpu, bpf_map_update_elem will overwrite the reused entry's data for the current CPU but not for other CPUs, resulting in stale data that is now associated with the wrong key. For time in state, this can show up as impossible data (e.g. reporting that a UID ran on one cluster at a frequency only available on a different cluster), which is detected by the SingleAndAllUidConsistent test since getUidCpuFreqTimes() only looks up potentially valid keys while getUidsCpuFreqTimes() iterates through every map entry. Avoid this problem by zeroing out each entry's data prior to deleting it from the map. Also modify getUidCpuFreqTimes and getUidsCpuFreqTimes to check for impossible data and fail if any is detected, since it's a sign that other map entries may also be wrong. Bug: 138317993 Test: libtimeinstate_test can now be run repeatedly without SingleAndAllUidConsistent test eventually failing Signed-off-by: Connor O'Brien Change-Id: I17dd407f897d1e86eb85cc99842a581d88e5bc78 --- libs/cputimeinstate/cputimeinstate.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 0e68e628b6..a02b28551e 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -167,9 +168,12 @@ std::optional>> getUidCpuFreqTimes(uint32_t ui return {}; } for (uint32_t i = 0; i < gNPolicies; ++i) { - if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue; uint64_t time = 0; for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu]; + if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) { + if (time != 0) return {}; + else continue; + } idxs[i] += 1; out[i].emplace_back(time); } @@ -209,10 +213,12 @@ getUidsCpuFreqTimes() { } for (size_t policy = 0; policy < gNPolicies; ++policy) { - for (const auto &cpu : gPolicyCpus[policy]) { - auto freqIdx = policyFreqIdxs[policy][key.freq]; - map[key.uid][policy][freqIdx] += val.ar[cpu]; - } + uint64_t time = 0; + for (const auto &cpu : gPolicyCpus[policy]) time += val.ar[cpu]; + if (!time) continue; + auto it = policyFreqIdxs[policy].find(key.freq); + if (it == policyFreqIdxs[policy].end()) return android::netdutils::Status(-1); + map[key.uid][policy][it->second] += time; } return android::netdutils::status::ok; }; @@ -225,9 +231,10 @@ bool clearUidCpuFreqTimes(uint32_t uid) { if (!gInitialized && !initGlobals()) return false; time_key_t key = {.uid = uid, .freq = 0}; - std::vector idxs(gNPolicies, 0); + std::vector vals(get_nprocs_conf(), 0); for (auto freq : gAllFreqs) { key.freq = freq; + if (writeToMapEntry(gMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT) return false; if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false; } return true; -- GitLab From 9236e872cd315c36bca7625751f16ec0817348c7 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 6 Jun 2019 17:48:20 -0700 Subject: [PATCH 0109/1255] libtimeinstate: support cpufreq fast switching In order to support kernels that use fast frequency switching, the time_in_state BPF program needs to know which CPUs are members of which cpufreq policies. Add logic to startTrackingUidCpuFreqTimes() to write this information into a BPF map in order to make it available to the BPF program. Test: libtimeinstate_test passes Change-Id: I47b38457766d21c2aa0879f156fc90757c0db705 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/cputimeinstate.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index a02b28551e..6f50a1e623 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -141,6 +141,17 @@ static bool attachTracepointProgram(const std::string &eventType, const std::str // This function should *not* be called while tracking is already active; doing so is unnecessary // and can lead to accounting errors. bool startTrackingUidCpuFreqTimes() { + if (!initGlobals()) return false; + + unique_fd fd(bpf_obj_get(BPF_FS_PATH "map_time_in_state_cpu_policy_map")); + if (fd < 0) return false; + + for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) { + for (auto &cpu : gPolicyCpus[i]) { + if (writeToMapEntry(fd, &cpu, &i, BPF_ANY)) return false; + } + } + return attachTracepointProgram("sched", "sched_switch") && attachTracepointProgram("power", "cpu_frequency"); } -- GitLab From 16ab1709fc9bef67fc1655128f54a6bce182de50 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Fri, 7 Jun 2019 16:39:49 -0700 Subject: [PATCH 0110/1255] libtimeinstate: change map format to improve performance By storing times for up to 32 freqs in each map value instead of one time per value, we can drastically reduce the number of syscalls required to get the data for a single UID and for all UIDs. This translates into a better than 3x speedup in getUidsCpuFreqTimes(). Test: libtimeinstate_test passes Bug: 138317993 Change-Id: I0d2d4d5fc99a82179a84a9aa83101bc55ddbc0e4 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/cputimeinstate.cpp | 134 ++++++++++++++---------- libs/cputimeinstate/testtimeinstate.cpp | 6 +- libs/cputimeinstate/timeinstate.h | 11 +- 3 files changed, 91 insertions(+), 60 deletions(-) diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 6f50a1e623..4c8d52efd9 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -49,6 +49,7 @@ namespace bpf { static std::mutex gInitializedMutex; static bool gInitialized = false; static uint32_t gNPolicies = 0; +static uint32_t gNCpus = 0; static std::vector> gPolicyFreqs; static std::vector> gPolicyCpus; static std::set gAllFreqs; @@ -86,6 +87,8 @@ static bool initGlobals() { std::lock_guard guard(gInitializedMutex); if (gInitialized) return true; + gNCpus = get_nprocs_conf(); + struct dirent **dirlist; const char basepath[] = "/sys/devices/system/cpu/cpufreq"; int ret = scandir(basepath, &dirlist, isPolicyFile, comparePolicyFiles); @@ -152,6 +155,21 @@ bool startTrackingUidCpuFreqTimes() { } } + unique_fd fd2(bpf_obj_get(BPF_FS_PATH "map_time_in_state_freq_to_idx_map")); + if (fd2 < 0) return false; + freq_idx_key_t key; + for (uint32_t i = 0; i < gNPolicies; ++i) { + key.policy = i; + for (uint32_t j = 0; j < gPolicyFreqs[i].size(); ++j) { + key.freq = gPolicyFreqs[i][j]; + // Start indexes at 1 so that uninitialized state is distinguishable from lowest freq. + // The uid_times map still uses 0-based indexes, and the sched_switch program handles + // conversion between them, so this does not affect our map reading code. + uint32_t idx = j + 1; + if (writeToMapEntry(fd2, &key, &idx, BPF_ANY)) return false; + } + } + return attachTracepointProgram("sched", "sched_switch") && attachTracepointProgram("power", "cpu_frequency"); } @@ -163,30 +181,33 @@ bool startTrackingUidCpuFreqTimes() { // where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq. std::optional>> getUidCpuFreqTimes(uint32_t uid) { if (!gInitialized && !initGlobals()) return {}; - time_key_t key = {.uid = uid, .freq = 0}; - - std::vector> out(gNPolicies); - std::vector idxs(gNPolicies, 0); - - val_t value; - for (uint32_t freq : gAllFreqs) { - key.freq = freq; - int ret = findMapEntry(gMapFd, &key, &value); - if (ret) { - if (errno == ENOENT) - memset(&value.ar, 0, sizeof(value.ar)); - else - return {}; + + std::vector> out; + uint32_t maxFreqCount = 0; + for (const auto &freqList : gPolicyFreqs) { + if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size(); + out.emplace_back(freqList.size(), 0); + } + + std::vector vals(gNCpus); + time_key_t key = {.uid = uid}; + for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) { + key.bucket = i; + if (findMapEntry(gMapFd, &key, vals.data())) { + if (errno != ENOENT) return {}; + continue; } - for (uint32_t i = 0; i < gNPolicies; ++i) { - uint64_t time = 0; - for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu]; - if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) { - if (time != 0) return {}; - else continue; + + auto offset = i * FREQS_PER_ENTRY; + auto nextOffset = (i + 1) * FREQS_PER_ENTRY; + for (uint32_t j = 0; j < gNPolicies; ++j) { + if (offset >= gPolicyFreqs[j].size()) continue; + auto begin = out[j].begin() + offset; + auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY : out[j].end(); + + for (const auto &cpu : gPolicyCpus[j]) { + std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus()); } - idxs[i] += 1; - out[i].emplace_back(time); } } @@ -202,49 +223,52 @@ std::optional>> getUidCpuFreqTimes(uint32_t ui std::optional>>> getUidsCpuFreqTimes() { if (!gInitialized && !initGlobals()) return {}; + time_key_t key, prevKey; + std::unordered_map>> map; + if (getFirstMapKey(gMapFd, &key)) { + if (errno == ENOENT) return map; + return std::nullopt; + } - int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map"); - if (fd < 0) return {}; - BpfMap m(fd); + std::vector> mapFormat; + for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0); - std::vector> policyFreqIdxs; - for (uint32_t i = 0; i < gNPolicies; ++i) { - std::unordered_map freqIdxs; - for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j; - policyFreqIdxs.emplace_back(freqIdxs); - } - std::unordered_map>> map; - auto fn = [&map, &policyFreqIdxs](const time_key_t &key, const val_t &val, - const BpfMap &) { - if (map.find(key.uid) == map.end()) { - map[key.uid].resize(gNPolicies); - for (uint32_t i = 0; i < gNPolicies; ++i) { - map[key.uid][i].resize(gPolicyFreqs[i].size(), 0); - } - } + std::vector vals(gNCpus); + do { + if (findMapEntry(gMapFd, &key, vals.data())) return {}; + if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat); - for (size_t policy = 0; policy < gNPolicies; ++policy) { - uint64_t time = 0; - for (const auto &cpu : gPolicyCpus[policy]) time += val.ar[cpu]; - if (!time) continue; - auto it = policyFreqIdxs[policy].find(key.freq); - if (it == policyFreqIdxs[policy].end()) return android::netdutils::Status(-1); - map[key.uid][policy][it->second] += time; + auto offset = key.bucket * FREQS_PER_ENTRY; + auto nextOffset = (key.bucket + 1) * FREQS_PER_ENTRY; + for (uint32_t i = 0; i < gNPolicies; ++i) { + if (offset >= gPolicyFreqs[i].size()) continue; + auto begin = map[key.uid][i].begin() + offset; + auto end = nextOffset < gPolicyFreqs[i].size() ? begin + FREQS_PER_ENTRY : + map[key.uid][i].end(); + for (const auto &cpu : gPolicyCpus[i]) { + std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus()); + } } - return android::netdutils::status::ok; - }; - if (isOk(m.iterateWithValue(fn))) return map; - return {}; + prevKey = key; + } while (!getNextMapKey(gMapFd, &prevKey, &key)); + if (errno != ENOENT) return {}; + return map; } // Clear all time in state data for a given uid. Returns false on error, true otherwise. bool clearUidCpuFreqTimes(uint32_t uid) { if (!gInitialized && !initGlobals()) return false; - time_key_t key = {.uid = uid, .freq = 0}; - std::vector vals(get_nprocs_conf(), 0); - for (auto freq : gAllFreqs) { - key.freq = freq; + time_key_t key = {.uid = uid}; + + uint32_t maxFreqCount = 0; + for (const auto &freqList : gPolicyFreqs) { + if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size(); + } + + val_t zeros = {0}; + std::vector vals(gNCpus, zeros); + for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) { if (writeToMapEntry(gMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT) return false; if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false; } diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 6347de166a..39007e4603 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -126,10 +126,10 @@ TEST(TimeInStateTest, RemoveUid) { ASSERT_GE(fd, 0); time_key_t k; ASSERT_FALSE(getFirstMapKey(fd, &k)); - val_t val; - ASSERT_FALSE(findMapEntry(fd, &k, &val)); + std::vector vals(get_nprocs_conf()); + ASSERT_FALSE(findMapEntry(fd, &k, vals.data())); k.uid = uid; - ASSERT_FALSE(writeToMapEntry(fd, &k, &val, BPF_NOEXIST)); + ASSERT_FALSE(writeToMapEntry(fd, &k, vals.data(), BPF_NOEXIST)); } auto times = getUidCpuFreqTimes(uid); ASSERT_TRUE(times.has_value()); diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h index cf66ae7077..41d0af07a2 100644 --- a/libs/cputimeinstate/timeinstate.h +++ b/libs/cputimeinstate/timeinstate.h @@ -18,11 +18,18 @@ #define BPF_FS_PATH "/sys/fs/bpf/" +#define FREQS_PER_ENTRY 32 + struct time_key_t { uint32_t uid; - uint32_t freq; + uint32_t bucket; }; struct val_t { - uint64_t ar[100]; + uint64_t ar[FREQS_PER_ENTRY]; +}; + +struct freq_idx_key_t { + uint32_t policy; + uint32_t freq; }; -- GitLab From f8e4a3430015900205d63748447a946a792e572e Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 29 Jul 2019 13:27:16 -0700 Subject: [PATCH 0111/1255] libgui: remove redundant eglQueryStringImplementationANDROID Test: build, flash and boot Change-Id: I48cbee82015551b5cd502565d76fe6038b2a50c7 --- libs/gui/GLConsumer.cpp | 1 - libs/gui/tests/SurfaceTextureClient_test.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 8199c98582..59f1bcd24e 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -46,7 +46,6 @@ #include #include -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content" #define EGL_PROTECTED_CONTENT_EXT 0x32C0 diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 65e09f2540..c85e84489d 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -28,8 +28,6 @@ #include #include -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); - namespace android { class SurfaceTextureClientTest : public ::testing::Test { -- GitLab From 8406fd785b80ab2fb2b7418ef6e973aace93df92 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 30 Jul 2019 11:29:31 -0700 Subject: [PATCH 0112/1255] Fix locking issues with proto dumps Proto dumps are generated from: - binder threads when generating bugreports or triggering dumpstate - main thread when mLayerStats is enabled - tracing thread when winscope tracing is enabled. The binder thread reads current state while the other threads reads drawing state. The writeToProto function accesses a mix of current and drawing states. mPendingState should only be accessed with the mStateLock held and the visible regions should be read from the main or tracing threads. This causes some invalid access issues. To make the locking requirements clear, this change 1. moves drawing specific data to a new function 2. copies mPendingState so we can dump the copy safely in main thread 3. dumps drawing data from binder threads by posting a message onto the main thread Bug: 138318680 Test: adb shell dumpsys SurfaceFlinger, winscope Change-Id: I8bb93e9b9f81faec59585b770eb7ba0fbcd9b51b --- services/surfaceflinger/Layer.cpp | 113 ++++++++++----------- services/surfaceflinger/Layer.h | 32 ++++-- services/surfaceflinger/SurfaceFlinger.cpp | 43 ++++---- services/surfaceflinger/SurfaceFlinger.h | 8 +- services/surfaceflinger/SurfaceTracing.cpp | 2 +- 5 files changed, 106 insertions(+), 92 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b5f080037b..8150ca7dfc 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -153,7 +153,6 @@ void Layer::removeRemoteSyncPoints() { mRemoteSyncPoints.clear(); { - Mutex::Autolock pendingStateLock(mPendingStateMutex); for (State pendingState : mPendingStates) { pendingState.barrierLayer_legacy = nullptr; } @@ -853,6 +852,7 @@ uint32_t Layer::doTransaction(uint32_t flags) { // Commit the transaction commitTransaction(c); + mPendingStatesSnapshot = mPendingStates; mCurrentState.callbackHandles = {}; return flags; } @@ -1820,14 +1820,61 @@ void Layer::setInputInfo(const InputWindowInfo& info) { setTransactionFlags(eTransactionNeeded); } -void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet, - uint32_t traceFlags) { +void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags) const { + ui::Transform transform = getTransform(); + + if (traceFlags & SurfaceTracing::TRACE_CRITICAL) { + for (const auto& pendingState : mPendingStatesSnapshot) { + auto barrierLayer = pendingState.barrierLayer_legacy.promote(); + if (barrierLayer != nullptr) { + BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer(); + barrierLayerProto->set_id(barrierLayer->sequence); + barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy); + } + } + + auto buffer = mActiveBuffer; + if (buffer != nullptr) { + LayerProtoHelper::writeToProto(buffer, + [&]() { return layerInfo->mutable_active_buffer(); }); + LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform), + layerInfo->mutable_buffer_transform()); + } + layerInfo->set_invalidate(contentDirty); + layerInfo->set_is_protected(isProtected()); + layerInfo->set_dataspace( + dataspaceDetails(static_cast(mCurrentDataSpace))); + layerInfo->set_queued_frames(getQueuedFrameCount()); + layerInfo->set_refresh_pending(isBufferLatched()); + layerInfo->set_curr_frame(mCurrentFrameNumber); + layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); + + layerInfo->set_corner_radius(getRoundedCornerState().radius); + LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform()); + LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), + [&]() { return layerInfo->mutable_position(); }); + LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); + LayerProtoHelper::writeToProto(visibleRegion, + [&]() { return layerInfo->mutable_visible_region(); }); + LayerProtoHelper::writeToProto(surfaceDamageRegion, + [&]() { return layerInfo->mutable_damage_region(); }); + } + + if (traceFlags & SurfaceTracing::TRACE_EXTRA) { + LayerProtoHelper::writeToProto(mSourceBounds, + [&]() { return layerInfo->mutable_source_bounds(); }); + LayerProtoHelper::writeToProto(mScreenBounds, + [&]() { return layerInfo->mutable_screen_bounds(); }); + } +} + +void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet stateSet, + uint32_t traceFlags) const { const bool useDrawing = stateSet == LayerVector::StateSet::Drawing; const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren; const State& state = useDrawing ? mDrawingState : mCurrentState; ui::Transform requestedTransform = state.active_legacy.transform; - ui::Transform transform = getTransform(); if (traceFlags & SurfaceTracing::TRACE_CRITICAL) { layerInfo->set_id(sequence); @@ -1847,17 +1894,10 @@ void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet, LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy, [&]() { return layerInfo->mutable_transparent_region(); }); - LayerProtoHelper::writeToProto(visibleRegion, - [&]() { return layerInfo->mutable_visible_region(); }); - LayerProtoHelper::writeToProto(surfaceDamageRegion, - [&]() { return layerInfo->mutable_damage_region(); }); layerInfo->set_layer_stack(getLayerStack()); layerInfo->set_z(state.z); - LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), - [&]() { return layerInfo->mutable_position(); }); - LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() { return layerInfo->mutable_requested_position(); @@ -1868,15 +1908,9 @@ void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet, LayerProtoHelper::writeToProto(state.crop_legacy, [&]() { return layerInfo->mutable_crop(); }); - layerInfo->set_corner_radius(getRoundedCornerState().radius); layerInfo->set_is_opaque(isOpaque(state)); - layerInfo->set_invalidate(contentDirty); - layerInfo->set_is_protected(isProtected()); - // XXX (b/79210409) mCurrentDataSpace is not protected - layerInfo->set_dataspace( - dataspaceDetails(static_cast(mCurrentDataSpace))); layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat())); LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); }); @@ -1884,7 +1918,6 @@ void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet, [&]() { return layerInfo->mutable_requested_color(); }); layerInfo->set_flags(state.flags); - LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform()); LayerProtoHelper::writeToProto(requestedTransform, layerInfo->mutable_requested_transform()); @@ -1901,29 +1934,6 @@ void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet, } else { layerInfo->set_z_order_relative_of(-1); } - - auto buffer = mActiveBuffer; - if (buffer != nullptr) { - LayerProtoHelper::writeToProto(buffer, - [&]() { return layerInfo->mutable_active_buffer(); }); - LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform), - layerInfo->mutable_buffer_transform()); - } - - layerInfo->set_queued_frames(getQueuedFrameCount()); - layerInfo->set_refresh_pending(isBufferLatched()); - layerInfo->set_curr_frame(mCurrentFrameNumber); - layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); - - for (const auto& pendingState : mPendingStates) { - auto barrierLayer = pendingState.barrierLayer_legacy.promote(); - if (barrierLayer != nullptr) { - BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer(); - barrierLayerProto->set_id(barrierLayer->sequence); - barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy); - } - } - LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); } if (traceFlags & SurfaceTracing::TRACE_INPUT) { @@ -1936,23 +1946,19 @@ void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet, for (const auto& entry : state.metadata.mMap) { (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend()); } - LayerProtoHelper::writeToProto(mEffectiveTransform, - layerInfo->mutable_effective_transform()); - LayerProtoHelper::writeToProto(mSourceBounds, - [&]() { return layerInfo->mutable_source_bounds(); }); - LayerProtoHelper::writeToProto(mScreenBounds, - [&]() { return layerInfo->mutable_screen_bounds(); }); } } -void Layer::writeToProto(LayerProto* layerInfo, const sp& displayDevice, - uint32_t traceFlags) { +void Layer::writeToProtoCompositionState(LayerProto* layerInfo, + const sp& displayDevice, + uint32_t traceFlags) const { auto outputLayer = findOutputLayerForDisplay(displayDevice); if (!outputLayer) { return; } - writeToProto(layerInfo, LayerVector::StateSet::Drawing, traceFlags); + writeToProtoDrawingState(layerInfo, traceFlags); + writeToProtoCommonState(layerInfo, LayerVector::StateSet::Drawing, traceFlags); const auto& compositionState = outputLayer->getState(); @@ -1970,13 +1976,6 @@ void Layer::writeToProto(LayerProto* layerInfo, const sp& display static_cast(compositionState.hwc ? (*compositionState.hwc).hwcCompositionType : Hwc2::IComposerClient::Composition::CLIENT); layerInfo->set_hwc_composition_type(compositionType); - - if (std::strcmp(getTypeId(), "BufferLayer") == 0 && - static_cast(this)->isProtected()) { - layerInfo->set_is_protected(true); - } else { - layerInfo->set_is_protected(false); - } } bool Layer::isRemovedFromCurrentState() const { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index bfc2136725..27a8ca7a73 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -435,11 +435,21 @@ public: bool isRemovedFromCurrentState() const; - void writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet, - uint32_t traceFlags = SurfaceTracing::TRACE_ALL); - - void writeToProto(LayerProto* layerInfo, const sp& displayDevice, - uint32_t traceFlags = SurfaceTracing::TRACE_ALL); + // Write states that are modified by the main thread. This includes drawing + // state as well as buffer data. This should be called in the main or tracing + // thread. + void writeToProtoDrawingState(LayerProto* layerInfo, + uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + // Write states that are modified by the main thread. This includes drawing + // state as well as buffer data and composition data for layers on the specified + // display. This should be called in the main or tracing thread. + void writeToProtoCompositionState(LayerProto* layerInfo, const sp& displayDevice, + uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + // Write drawing or current state. If writing current state, the caller should hold the + // external mStateLock. If writing drawing state, this function should be called on the + // main or tracing thread. + void writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet stateSet, + uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; } virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; } @@ -819,13 +829,15 @@ protected: bool mPrimaryDisplayOnly = false; - // these are protected by an external lock - State mCurrentState; + // These are only accessed by the main thread or the tracing thread. State mDrawingState; - std::atomic mTransactionFlags{0}; + // Store a copy of the pending state so that the drawing thread can access the + // states without a lock. + Vector mPendingStatesSnapshot; - // Accessed from main thread and binder threads - Mutex mPendingStateMutex; + // these are protected by an external lock (mStateLock) + State mCurrentState; + std::atomic mTransactionFlags{0}; Vector mPendingStates; // Timestamp history for UIAutomation. Thread safe. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8bf6b999bb..e8b39cc797 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4578,18 +4578,22 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, if (const auto it = dumpers.find(flag); it != dumpers.end()) { (it->second)(args, asProto, result); - } else { - if (asProto) { - LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current); - result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize()); - } else { - dumpAllLocked(args, result); - } + } else if (!asProto) { + dumpAllLocked(args, result); } if (locked) { mStateLock.unlock(); } + + LayersProto layersProto = dumpProtoFromMainThread(); + if (asProto) { + result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize()); + } else { + auto layerTree = LayerProtoParser::generateLayerTree(layersProto); + result.append(LayerProtoParser::layerTreeToString(layerTree)); + result.append("\n"); + } } write(fd, result.c_str(), result.size()); return NO_ERROR; @@ -4830,19 +4834,23 @@ void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { result.append("\n"); } -LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet, - uint32_t traceFlags) const { +LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { LayersProto layersProto; - const bool useDrawing = stateSet == LayerVector::StateSet::Drawing; - const State& state = useDrawing ? mDrawingState : mCurrentState; - state.traverseInZOrder([&](Layer* layer) { + mDrawingState.traverseInZOrder([&](Layer* layer) { LayerProto* layerProto = layersProto.add_layers(); - layer->writeToProto(layerProto, stateSet, traceFlags); + layer->writeToProtoDrawingState(layerProto, traceFlags); + layer->writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags); }); return layersProto; } +LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) { + LayersProto layersProto; + postMessageSync(new LambdaMessage([&]() { layersProto = dumpDrawingStateProto(traceFlags); })); + return layersProto; +} + LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo( const sp& displayDevice) const { LayersProto layersProto; @@ -4863,7 +4871,7 @@ LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo( mDrawingState.traverseInZOrder([&](Layer* layer) { if (!layer->visibleRegion.isEmpty() && !display->getOutputLayersOrderedByZ().empty()) { LayerProto* layerProto = layersProto.add_layers(); - layer->writeToProto(layerProto, displayDevice); + layer->writeToProtoCompositionState(layerProto, displayDevice); } }); @@ -4927,13 +4935,6 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize); colorizer.reset(result); - { - LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current); - auto layerTree = LayerProtoParser::generateLayerTree(layersProto); - result.append(LayerProtoParser::layerTreeToString(layerTree)); - result.append("\n"); - } - { StringAppendF(&result, "Composition layers\n"); mDrawingState.traverseInZOrder([&](Layer* layer) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b4b5b85e46..a17f6c8867 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -265,7 +265,8 @@ public: status_t postMessageAsync(const sp& msg, nsecs_t reltime = 0, uint32_t flags = 0); // post a synchronous message to the main thread - status_t postMessageSync(const sp& msg, nsecs_t reltime = 0, uint32_t flags = 0); + status_t postMessageSync(const sp& msg, nsecs_t reltime = 0, uint32_t flags = 0) + EXCLUDES(mStateLock); // force full composition on all displays void repaintEverything(); @@ -896,8 +897,9 @@ private: void dumpBufferingStats(std::string& result) const; void dumpDisplayIdentificationData(std::string& result) const; void dumpWideColorInfo(std::string& result) const; - LayersProto dumpProtoInfo(LayerVector::StateSet stateSet, - uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) + EXCLUDES(mStateLock); void withTracingLock(std::function operation) REQUIRES(mStateLock); LayersProto dumpVisibleLayersProtoInfo(const sp& display) const; diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp index c4ab0668e7..9053f2c7de 100644 --- a/services/surfaceflinger/SurfaceTracing.cpp +++ b/services/surfaceflinger/SurfaceTracing.cpp @@ -162,7 +162,7 @@ LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) { LayersTraceProto entry; entry.set_elapsed_realtime_nanos(elapsedRealtimeNano()); entry.set_where(where); - LayersProto layers(mFlinger.dumpProtoInfo(LayerVector::StateSet::Drawing, mTraceFlags)); + LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags)); entry.mutable_layers()->Swap(&layers); return entry; -- GitLab From 20e67fa8a171f7899c754bb7663f5e534d64c322 Mon Sep 17 00:00:00 2001 From: Dillon Cower Date: Tue, 30 Jul 2019 15:39:54 -0700 Subject: [PATCH 0113/1255] Fix typo: chroreographer -> choreographer. --- include/android/choreographer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/android/choreographer.h b/include/android/choreographer.h index 44883cc498..1b589bca72 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -83,7 +83,7 @@ void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer, * Power a callback to be run on the next frame. The data pointer provided will * be passed to the callback function when it's called. */ -void AChoreographer_postFrameCallback64(AChoreographer* chroreographer, +void AChoreographer_postFrameCallback64(AChoreographer* choreographer, AChoreographer_frameCallback64 callback, void* data) __INTRODUCED_IN(29); /** -- GitLab From 2249c88ec56f2524a3c5bee5cbca232eae1357d1 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 30 Jul 2019 14:23:49 -0700 Subject: [PATCH 0114/1255] Fix null pointer deref in libsensor SensorServer When trying to create a senor direct connection, check that native handle resource is not null, and if so return BAD_VALUE error. Bug: 135051254 Test: Load onto device and try "service call sensorservice 5" commands that have no arguments and random arguments. Both throw new error and do not crash system as hoped. Change-Id: Ie2eaf1a17843da89927293e408768bfbaaf86ec8 --- libs/sensor/ISensorServer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp index 5200545a53..8ed09f8ff0 100644 --- a/libs/sensor/ISensorServer.cpp +++ b/libs/sensor/ISensorServer.cpp @@ -199,6 +199,10 @@ status_t BnSensorServer::onTransact( int32_t type = data.readInt32(); int32_t format = data.readInt32(); native_handle_t *resource = data.readNativeHandle(); + // Avoid a crash in native_handle_close if resource is nullptr + if (resource == nullptr) { + return BAD_VALUE; + } sp ch = createSensorDirectConnection(opPackageName, size, type, format, resource); native_handle_close(resource); -- GitLab From 3a80a38f9fb0ee2a6885515a6f2e1634b65e5937 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 25 Jul 2019 11:16:07 -0700 Subject: [PATCH 0115/1255] SF: Deduplicate scheduler timer callbacks Bug: 130554049 Test: Boot Change-Id: I3934b90176b22bbe83480dd4e2c87374876f818b --- .../surfaceflinger/Scheduler/Scheduler.cpp | 86 ++++++++----------- services/surfaceflinger/Scheduler/Scheduler.h | 36 +++----- 2 files changed, 44 insertions(+), 78 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 7acb4701d9..b2b85bcc4b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -89,12 +89,13 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, if (mSupportKernelTimer) { mIdleTimer = std::make_unique( std::chrono::milliseconds(mSetIdleTimerMs), - [this] { resetKernelTimerCallback(); }, - [this] { expiredKernelTimerCallback(); }); + [this] { kernelIdleTimerCallback(TimerState::RESET); }, + [this] { kernelIdleTimerCallback(TimerState::EXPIRED); }); } else { mIdleTimer = std::make_unique( - std::chrono::milliseconds(mSetIdleTimerMs), [this] { resetTimerCallback(); }, - [this] { expiredTimerCallback(); }); + std::chrono::milliseconds(mSetIdleTimerMs), + [this] { idleTimerCallback(TimerState::RESET); }, + [this] { idleTimerCallback(TimerState::EXPIRED); }); } mIdleTimer->start(); } @@ -102,16 +103,17 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, if (mSetTouchTimerMs > 0) { // Touch events are coming to SF every 100ms, so the timer needs to be higher than that mTouchTimer = std::make_unique( - std::chrono::milliseconds(mSetTouchTimerMs), [this] { resetTouchTimerCallback(); }, - [this] { expiredTouchTimerCallback(); }); + std::chrono::milliseconds(mSetTouchTimerMs), + [this] { touchTimerCallback(TimerState::RESET); }, + [this] { touchTimerCallback(TimerState::EXPIRED); }); mTouchTimer->start(); } if (mSetDisplayPowerTimerMs > 0) { mDisplayPowerTimer = std::make_unique( std::chrono::milliseconds(mSetDisplayPowerTimerMs), - [this] { resetDisplayPowerTimerCallback(); }, - [this] { expiredDisplayPowerTimerCallback(); }); + [this] { displayPowerTimerCallback(TimerState::RESET); }, + [this] { displayPowerTimerCallback(TimerState::EXPIRED); }); mDisplayPowerTimer->start(); } } @@ -445,60 +447,40 @@ void Scheduler::setDisplayPowerState(bool normal) { mLayerHistory.clearHistory(); } -void Scheduler::resetTimerCallback() { - handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::RESET, false); - ATRACE_INT("ExpiredIdleTimer", 0); -} +void Scheduler::kernelIdleTimerCallback(TimerState state) { + ATRACE_INT("ExpiredKernelIdleTimer", static_cast(state)); -void Scheduler::resetKernelTimerCallback() { - ATRACE_INT("ExpiredKernelIdleTimer", 0); std::lock_guard lock(mCallbackLock); - if (mGetVsyncPeriod && mGetCurrentRefreshRateTypeCallback) { + if (!mGetCurrentRefreshRateTypeCallback || !mGetVsyncPeriod) return; + + const auto type = mGetCurrentRefreshRateTypeCallback(); + if (state == TimerState::RESET && type == RefreshRateType::PERFORMANCE) { // If we're not in performance mode then the kernel timer shouldn't do // anything, as the refresh rate during DPU power collapse will be the // same. - if (mGetCurrentRefreshRateTypeCallback() == Scheduler::RefreshRateType::PERFORMANCE) { - resyncToHardwareVsync(true, mGetVsyncPeriod()); - } + resyncToHardwareVsync(true /* makeAvailable */, mGetVsyncPeriod()); + } else if (state == TimerState::EXPIRED && type != RefreshRateType::PERFORMANCE) { + // Disable HW VSYNC if the timer expired, as we don't need it enabled if + // we're not pushing frames, and if we're in PERFORMANCE mode then we'll + // need to update the DispSync model anyway. + disableHardwareVsync(false /* makeUnavailable */); } } -void Scheduler::expiredTimerCallback() { - handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::EXPIRED, false); - ATRACE_INT("ExpiredIdleTimer", 1); +void Scheduler::idleTimerCallback(TimerState state) { + handleTimerStateChanged(&mCurrentIdleTimerState, state, false /* eventOnContentDetection */); + ATRACE_INT("ExpiredIdleTimer", static_cast(state)); } -void Scheduler::resetTouchTimerCallback() { - handleTimerStateChanged(&mCurrentTouchState, TouchState::ACTIVE, true); - ATRACE_INT("TouchState", 1); +void Scheduler::touchTimerCallback(TimerState state) { + const TouchState touch = state == TimerState::RESET ? TouchState::ACTIVE : TouchState::INACTIVE; + handleTimerStateChanged(&mCurrentTouchState, touch, true /* eventOnContentDetection */); + ATRACE_INT("TouchState", static_cast(touch)); } -void Scheduler::expiredTouchTimerCallback() { - handleTimerStateChanged(&mCurrentTouchState, TouchState::INACTIVE, true); - ATRACE_INT("TouchState", 0); -} - -void Scheduler::resetDisplayPowerTimerCallback() { - handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::RESET, true); - ATRACE_INT("ExpiredDisplayPowerTimer", 0); -} - -void Scheduler::expiredDisplayPowerTimerCallback() { - handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::EXPIRED, true); - ATRACE_INT("ExpiredDisplayPowerTimer", 1); -} - -void Scheduler::expiredKernelTimerCallback() { - std::lock_guard lock(mCallbackLock); - ATRACE_INT("ExpiredKernelIdleTimer", 1); - if (mGetCurrentRefreshRateTypeCallback) { - if (mGetCurrentRefreshRateTypeCallback() != Scheduler::RefreshRateType::PERFORMANCE) { - // Disable HW Vsync if the timer expired, as we don't need it - // enabled if we're not pushing frames, and if we're in PERFORMANCE - // mode then we'll need to re-update the DispSync model anyways. - disableHardwareVsync(false); - } - } +void Scheduler::displayPowerTimerCallback(TimerState state) { + handleTimerStateChanged(&mDisplayPowerTimerState, state, true /* eventOnContentDetection */); + ATRACE_INT("ExpiredDisplayPowerTimer", static_cast(state)); } std::string Scheduler::doDump() { @@ -539,7 +521,7 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { // 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 (!mIsDisplayPowerStateNormal || mDisplayPowerTimerState == DisplayPowerTimerState::RESET) { + if (!mIsDisplayPowerStateNormal || mDisplayPowerTimerState == TimerState::RESET) { return RefreshRateType::PERFORMANCE; } @@ -549,7 +531,7 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { } // If timer has expired as it means there is no new content on the screen - if (mCurrentIdleTimerState == IdleTimerState::EXPIRED) { + if (mCurrentIdleTimerState == TimerState::EXPIRED) { return RefreshRateType::DEFAULT; } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 123036e0fa..f4db641bbd 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -200,10 +200,9 @@ private: // In order to make sure that the features don't override themselves, we need a state machine // to keep track which feature requested the config change. - enum class ContentFeatureState { CONTENT_DETECTION_ON, CONTENT_DETECTION_OFF }; - enum class IdleTimerState { EXPIRED, RESET }; + enum class ContentFeatureState { CONTENT_DETECTION_OFF, CONTENT_DETECTION_ON }; + enum class TimerState { RESET, EXPIRED }; enum class TouchState { INACTIVE, ACTIVE }; - enum class DisplayPowerTimerState { EXPIRED, RESET }; // Creates a connection on the given EventThread and forwards the given callbacks. sp createConnectionInternal(EventThread*, ResyncCallback&&, @@ -212,26 +211,12 @@ private: nsecs_t calculateAverage() const; void updateFrameSkipping(const int64_t skipCount); - // Function that is called when the timer resets. - void resetTimerCallback(); - // Function that is called when the timer expires. - void expiredTimerCallback(); - // Function that is called when the timer resets when paired with a display - // driver timeout in the kernel. This enables hardware vsync when we move - // out from idle. - void resetKernelTimerCallback(); - // Function that is called when the timer expires when paired with a display - // driver timeout in the kernel. This disables hardware vsync when we move - // into idle. - void expiredKernelTimerCallback(); - // Function that is called when the touch timer resets. - void resetTouchTimerCallback(); - // Function that is called when the touch timer expires. - void expiredTouchTimerCallback(); - // Function that is called when the display power timer resets. - void resetDisplayPowerTimerCallback(); - // Function that is called when the display power timer expires. - void expiredDisplayPowerTimerCallback(); + // Update feature state machine to given state when corresponding timer resets or expires. + void kernelIdleTimerCallback(TimerState); + void idleTimerCallback(TimerState); + void touchTimerCallback(TimerState); + void displayPowerTimerCallback(TimerState); + // Sets vsync period. void setVsyncPeriod(const nsecs_t period); // handles various timer features to change the refresh rate. @@ -306,10 +291,9 @@ private: std::mutex mFeatureStateLock; ContentFeatureState mCurrentContentFeatureState GUARDED_BY(mFeatureStateLock) = ContentFeatureState::CONTENT_DETECTION_OFF; - IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET; + TimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = TimerState::RESET; TouchState mCurrentTouchState GUARDED_BY(mFeatureStateLock) = TouchState::INACTIVE; - DisplayPowerTimerState mDisplayPowerTimerState GUARDED_BY(mFeatureStateLock) = - DisplayPowerTimerState::EXPIRED; + TimerState mDisplayPowerTimerState GUARDED_BY(mFeatureStateLock) = TimerState::EXPIRED; uint32_t mContentRefreshRate GUARDED_BY(mFeatureStateLock); RefreshRateType mRefreshRateType GUARDED_BY(mFeatureStateLock); bool mIsHDRContent GUARDED_BY(mFeatureStateLock) = false; -- GitLab From dd252cdba2045ed66b0db12724ca07ac589dbad2 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Fri, 26 Jul 2019 09:10:16 -0700 Subject: [PATCH 0116/1255] SF: Group mutex-guarded scheduler feature state This also fixes two uninitialized members. Bug: 130554049 Test: Boot Change-Id: I4f7e14be5ec91780e7ac4a49de9f881227b7e8b7 --- .../surfaceflinger/Scheduler/Scheduler.cpp | 79 +++++++++---------- services/surfaceflinger/Scheduler/Scheduler.h | 28 ++++--- 2 files changed, 55 insertions(+), 52 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index b2b85bcc4b..952643ce70 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -89,13 +89,13 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, if (mSupportKernelTimer) { mIdleTimer = std::make_unique( std::chrono::milliseconds(mSetIdleTimerMs), - [this] { kernelIdleTimerCallback(TimerState::RESET); }, - [this] { kernelIdleTimerCallback(TimerState::EXPIRED); }); + [this] { kernelIdleTimerCallback(TimerState::Reset); }, + [this] { kernelIdleTimerCallback(TimerState::Expired); }); } else { mIdleTimer = std::make_unique( std::chrono::milliseconds(mSetIdleTimerMs), - [this] { idleTimerCallback(TimerState::RESET); }, - [this] { idleTimerCallback(TimerState::EXPIRED); }); + [this] { idleTimerCallback(TimerState::Reset); }, + [this] { idleTimerCallback(TimerState::Expired); }); } mIdleTimer->start(); } @@ -104,16 +104,16 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, // Touch events are coming to SF every 100ms, so the timer needs to be higher than that mTouchTimer = std::make_unique( std::chrono::milliseconds(mSetTouchTimerMs), - [this] { touchTimerCallback(TimerState::RESET); }, - [this] { touchTimerCallback(TimerState::EXPIRED); }); + [this] { touchTimerCallback(TimerState::Reset); }, + [this] { touchTimerCallback(TimerState::Expired); }); mTouchTimer->start(); } if (mSetDisplayPowerTimerMs > 0) { mDisplayPowerTimer = std::make_unique( std::chrono::milliseconds(mSetDisplayPowerTimerMs), - [this] { displayPowerTimerCallback(TimerState::RESET); }, - [this] { displayPowerTimerCallback(TimerState::EXPIRED); }); + [this] { displayPowerTimerCallback(TimerState::Reset); }, + [this] { displayPowerTimerCallback(TimerState::Expired); }); mDisplayPowerTimer->start(); } } @@ -365,23 +365,22 @@ void Scheduler::updateFpsBasedOnContent() { RefreshRateType newRefreshRateType; { std::lock_guard lock(mFeatureStateLock); - if (mContentRefreshRate == refreshRateRound && mIsHDRContent == isHDR) { + if (mFeatures.contentRefreshRate == refreshRateRound && mFeatures.isHDRContent == isHDR) { return; } - mContentRefreshRate = refreshRateRound; - ATRACE_INT("ContentFPS", mContentRefreshRate); + mFeatures.contentRefreshRate = refreshRateRound; + ATRACE_INT("ContentFPS", refreshRateRound); - mIsHDRContent = isHDR; - ATRACE_INT("ContentHDR", mIsHDRContent); + mFeatures.isHDRContent = isHDR; + ATRACE_INT("ContentHDR", isHDR); - mCurrentContentFeatureState = refreshRateRound > 0 - ? ContentFeatureState::CONTENT_DETECTION_ON - : ContentFeatureState::CONTENT_DETECTION_OFF; + mFeatures.contentDetection = + refreshRateRound > 0 ? ContentDetectionState::On : ContentDetectionState::Off; newRefreshRateType = calculateRefreshRateType(); - if (mRefreshRateType == newRefreshRateType) { + if (mFeatures.refreshRateType == newRefreshRateType) { return; } - mRefreshRateType = newRefreshRateType; + mFeatures.refreshRateType = newRefreshRateType; } changeRefreshRate(newRefreshRateType, ConfigEvent::Changed); } @@ -435,7 +434,7 @@ void Scheduler::notifyTouchEvent() { void Scheduler::setDisplayPowerState(bool normal) { { std::lock_guard lock(mFeatureStateLock); - mIsDisplayPowerStateNormal = normal; + mFeatures.isDisplayPowerStateNormal = normal; } if (mDisplayPowerTimer) { @@ -454,12 +453,12 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { if (!mGetCurrentRefreshRateTypeCallback || !mGetVsyncPeriod) return; const auto type = mGetCurrentRefreshRateTypeCallback(); - if (state == TimerState::RESET && type == RefreshRateType::PERFORMANCE) { + if (state == TimerState::Reset && type == RefreshRateType::PERFORMANCE) { // If we're not in performance mode then the kernel timer shouldn't do // anything, as the refresh rate during DPU power collapse will be the // same. resyncToHardwareVsync(true /* makeAvailable */, mGetVsyncPeriod()); - } else if (state == TimerState::EXPIRED && type != RefreshRateType::PERFORMANCE) { + } else if (state == TimerState::Expired && type != RefreshRateType::PERFORMANCE) { // Disable HW VSYNC if the timer expired, as we don't need it enabled if // we're not pushing frames, and if we're in PERFORMANCE mode then we'll // need to update the DispSync model anyway. @@ -468,18 +467,19 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { } void Scheduler::idleTimerCallback(TimerState state) { - handleTimerStateChanged(&mCurrentIdleTimerState, state, false /* eventOnContentDetection */); + handleTimerStateChanged(&mFeatures.idleTimer, state, false /* eventOnContentDetection */); ATRACE_INT("ExpiredIdleTimer", static_cast(state)); } void Scheduler::touchTimerCallback(TimerState state) { - const TouchState touch = state == TimerState::RESET ? TouchState::ACTIVE : TouchState::INACTIVE; - handleTimerStateChanged(&mCurrentTouchState, touch, true /* eventOnContentDetection */); + const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive; + handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */); ATRACE_INT("TouchState", static_cast(touch)); } void Scheduler::displayPowerTimerCallback(TimerState state) { - handleTimerStateChanged(&mDisplayPowerTimerState, state, true /* eventOnContentDetection */); + handleTimerStateChanged(&mFeatures.displayPowerTimer, state, + true /* eventOnContentDetection */); ATRACE_INT("ExpiredDisplayPowerTimer", static_cast(state)); } @@ -501,12 +501,11 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO } *currentState = newState; newRefreshRateType = calculateRefreshRateType(); - if (mRefreshRateType == newRefreshRateType) { + if (mFeatures.refreshRateType == newRefreshRateType) { return; } - mRefreshRateType = newRefreshRateType; - if (eventOnContentDetection && - mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) { + mFeatures.refreshRateType = newRefreshRateType; + if (eventOnContentDetection && mFeatures.contentDetection == ContentDetectionState::On) { event = ConfigEvent::Changed; } } @@ -515,37 +514,38 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { // HDR content is not supported on PERFORMANCE mode - if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) { + if (mForceHDRContentToDefaultRefreshRate && mFeatures.isHDRContent) { return RefreshRateType::DEFAULT; } // 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 (!mIsDisplayPowerStateNormal || mDisplayPowerTimerState == TimerState::RESET) { + if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) { return RefreshRateType::PERFORMANCE; } // As long as touch is active we want to be in performance mode - if (mCurrentTouchState == TouchState::ACTIVE) { + if (mFeatures.touch == TouchState::Active) { return RefreshRateType::PERFORMANCE; } // If timer has expired as it means there is no new content on the screen - if (mCurrentIdleTimerState == TimerState::EXPIRED) { + if (mFeatures.idleTimer == TimerState::Expired) { return RefreshRateType::DEFAULT; } // If content detection is off we choose performance as we don't know the content fps - if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_OFF) { + if (mFeatures.contentDetection == ContentDetectionState::Off) { return RefreshRateType::PERFORMANCE; } // Content detection is on, find the appropriate refresh rate with minimal error + const float rate = static_cast(mFeatures.contentRefreshRate); auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(), mRefreshRateConfigs.getRefreshRates().cend(), - [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool { - return std::abs(l.second->fps - static_cast(rate)) < - std::abs(r.second->fps - static_cast(rate)); + [rate](const auto& lhs, const auto& rhs) -> bool { + return std::abs(lhs.second->fps - rate) < + std::abs(rhs.second->fps - rate); }); RefreshRateType currRefreshRateType = iter->first; @@ -553,11 +553,10 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't // align well with both constexpr float MARGIN = 0.05f; - float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / - float(mContentRefreshRate); + float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / rate; if (std::abs(std::round(ratio) - ratio) > MARGIN) { while (iter != mRefreshRateConfigs.getRefreshRates().cend()) { - ratio = iter->second->fps / float(mContentRefreshRate); + ratio = iter->second->fps / rate; if (std::abs(std::round(ratio) - ratio) <= MARGIN) { currRefreshRateType = iter->first; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index f4db641bbd..0d9d7aa3ba 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -200,9 +200,9 @@ private: // In order to make sure that the features don't override themselves, we need a state machine // to keep track which feature requested the config change. - enum class ContentFeatureState { CONTENT_DETECTION_OFF, CONTENT_DETECTION_ON }; - enum class TimerState { RESET, EXPIRED }; - enum class TouchState { INACTIVE, ACTIVE }; + enum class ContentDetectionState { Off, On }; + enum class TimerState { Reset, Expired }; + enum class TouchState { Inactive, Active }; // Creates a connection on the given EventThread and forwards the given callbacks. sp createConnectionInternal(EventThread*, ResyncCallback&&, @@ -289,15 +289,19 @@ private: // In order to make sure that the features don't override themselves, we need a state machine // to keep track which feature requested the config change. std::mutex mFeatureStateLock; - ContentFeatureState mCurrentContentFeatureState GUARDED_BY(mFeatureStateLock) = - ContentFeatureState::CONTENT_DETECTION_OFF; - TimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = TimerState::RESET; - TouchState mCurrentTouchState GUARDED_BY(mFeatureStateLock) = TouchState::INACTIVE; - TimerState mDisplayPowerTimerState GUARDED_BY(mFeatureStateLock) = TimerState::EXPIRED; - uint32_t mContentRefreshRate GUARDED_BY(mFeatureStateLock); - RefreshRateType mRefreshRateType GUARDED_BY(mFeatureStateLock); - bool mIsHDRContent GUARDED_BY(mFeatureStateLock) = false; - bool mIsDisplayPowerStateNormal GUARDED_BY(mFeatureStateLock) = true; + + struct { + ContentDetectionState contentDetection = ContentDetectionState::Off; + TimerState idleTimer = TimerState::Reset; + TouchState touch = TouchState::Inactive; + TimerState displayPowerTimer = TimerState::Expired; + + RefreshRateType refreshRateType = RefreshRateType::DEFAULT; + uint32_t contentRefreshRate = 0; + + bool isHDRContent = false; + bool isDisplayPowerStateNormal = true; + } mFeatures GUARDED_BY(mFeatureStateLock); const scheduler::RefreshRateConfigs& mRefreshRateConfigs; -- GitLab From 66d6860ca6a024649fa56573b4b7e346049db405 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Wed, 13 Feb 2019 14:23:31 -0800 Subject: [PATCH 0117/1255] SF: Move/Refactor prepareFrame to CompositionEngine This refactors both the SurfaceFlinger::prepareFrame() and HWComposer::prepare() logic, moving things to to compositionEngine::Output and compositionEngine::Display. Along the way, the composition related state is moved out of HWComposer up to compositionengine::OutputCompositionState. As there were some subtleties, tests are also added to cover the refactored logic. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: I2713e9e52751ca0523f6348ffdb51ead8bca5235 --- .../include/compositionengine/Output.h | 6 +- .../include/compositionengine/OutputLayer.h | 20 ++ .../include/compositionengine/RenderSurface.h | 2 +- .../include/compositionengine/impl/Display.h | 16 +- .../include/compositionengine/impl/Output.h | 3 + .../impl/OutputCompositionState.h | 10 + .../compositionengine/impl/OutputLayer.h | 10 +- .../compositionengine/impl/RenderSurface.h | 2 +- .../include/compositionengine/mock/Output.h | 3 + .../compositionengine/mock/OutputLayer.h | 6 + .../compositionengine/mock/RenderSurface.h | 2 +- .../CompositionEngine/src/Display.cpp | 89 ++++++ .../CompositionEngine/src/Output.cpp | 20 ++ .../src/OutputCompositionState.cpp | 4 + .../CompositionEngine/src/OutputLayer.cpp | 64 +++++ .../CompositionEngine/src/RenderSurface.cpp | 31 +- .../CompositionEngine/tests/DisplayTest.cpp | 266 +++++++++++++++++- .../CompositionEngine/tests/MockHWComposer.h | 6 +- .../tests/OutputLayerTest.cpp | 99 ++++++- .../CompositionEngine/tests/OutputTest.cpp | 87 +++++- .../tests/RenderSurfaceTest.cpp | 113 +++----- .../DisplayHardware/HWComposer.cpp | 130 +-------- .../DisplayHardware/HWComposer.h | 51 ++-- services/surfaceflinger/SurfaceFlinger.cpp | 45 +-- services/surfaceflinger/SurfaceFlinger.h | 5 - .../tests/unittests/CompositionTest.cpp | 24 +- 26 files changed, 803 insertions(+), 311 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 5b9e282276..1525a096f4 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -132,15 +132,19 @@ public: // Gets the ordered set of output layers for this output virtual const OutputLayers& getOutputLayersOrderedByZ() const = 0; - // Sets the new set of layers being released this frame. + // Sets the new set of layers being released this frame virtual void setReleasedLayers(ReleasedLayers&&) = 0; // Takes (moves) the set of layers being released this frame. virtual ReleasedLayers takeReleasedLayers() = 0; + // Prepares a frame for display + virtual void prepareFrame() = 0; + protected: virtual void setDisplayColorProfile(std::unique_ptr) = 0; virtual void setRenderSurface(std::unique_ptr) = 0; + virtual void chooseCompositionStrategy() = 0; }; } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index d3a4e09ec7..d7f00a978a 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -21,8 +21,13 @@ #include +#include "DisplayHardware/ComposerHal.h" #include "DisplayHardware/DisplayIdentification.h" +namespace HWC2 { +class Layer; +} // namespace HWC2 + namespace android { namespace compositionengine { @@ -73,6 +78,21 @@ public: // skipped. virtual void writeStateToHWC(bool includeGeometry) = 0; + // Returns the HWC2::Layer associated with this layer, if it exists + virtual HWC2::Layer* getHwcLayer() const = 0; + + // Returns true if the current layer state requires client composition + virtual bool requiresClientComposition() const = 0; + + // Applies a HWC device requested composition type change + virtual void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) = 0; + + // Prepares to apply any HWC device layer requests + virtual void prepareForDeviceLayerRequests() = 0; + + // Applies a HWC device layer request + virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0; + // Debugging virtual void dump(std::string& result) const = 0; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index 9bff73e950..6859846faf 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -71,7 +71,7 @@ public: virtual status_t beginFrame(bool mustRecompose) = 0; // Prepares the frame for rendering - virtual status_t prepareFrame() = 0; + virtual void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) = 0; // Allocates a buffer as scratch space for GPU composition virtual sp dequeueBuffer(base::unique_fd* bufferFence) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index 1265533449..8a3f8a79e9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -16,12 +16,13 @@ #pragma once -#include - #include #include +#include + #include "DisplayHardware/DisplayIdentification.h" +#include "DisplayHardware/HWComposer.h" namespace android::compositionengine { @@ -40,6 +41,7 @@ public: void dump(std::string&) const override; void setColorTransform(const mat4&) override; void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override; + void chooseCompositionStrategy() override; // compositionengine::Display overrides const std::optional& getId() const override; @@ -49,6 +51,16 @@ public: void createDisplayColorProfile(compositionengine::DisplayColorProfileCreationArgs&&) override; void createRenderSurface(compositionengine::RenderSurfaceCreationArgs&&) override; + // Internal helpers used by chooseCompositionStrategy() + using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes; + using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests; + using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests; + virtual bool anyLayersRequireClientComposition() const; + virtual bool allLayersRequireClientComposition() const; + virtual void applyChangedTypesToLayers(const ChangedTypes&); + virtual void applyDisplayRequests(const DisplayRequests&); + virtual void applyLayerRequestsToLayers(const LayerRequests&); + private: const bool mIsVirtual; std::optional mId; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 20812d258b..503d2fa2c8 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -75,12 +75,15 @@ public: void setReleasedLayers(ReleasedLayers&&) override; ReleasedLayers takeReleasedLayers() override; + void prepareFrame() override; + // Testing void setDisplayColorProfileForTest(std::unique_ptr); void setRenderSurfaceForTest(std::unique_ptr); protected: const CompositionEngine& getCompositionEngine() const; + void chooseCompositionStrategy() override; void dumpBase(std::string&) const; private: diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 45b8308f44..1078f11c2d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -35,6 +35,16 @@ struct OutputCompositionState { // If false, this output is not considered secure bool isSecure{false}; + // If true, the current frame on this output uses client composition + bool usesClientComposition{false}; + + // If true, the current frame on this output uses device composition + bool usesDeviceComposition{false}; + + // If true, the client target should be flipped when performing client + // composition + bool flipClientTarget{false}; + // If true, this output displays layers that are internal-only bool layerStackInternal{false}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index 708f3a1b3e..d8ad02aca3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -50,6 +50,12 @@ public: void updateCompositionState(bool) override; void writeStateToHWC(bool) override; + HWC2::Layer* getHwcLayer() const override; + bool requiresClientComposition() const override; + void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override; + void prepareForDeviceLayerRequests() override; + void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override; + void dump(std::string& result) const override; virtual FloatRect calculateOutputSourceCrop() const; @@ -66,6 +72,8 @@ private: void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&); void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&); void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition); + void detectDisallowedCompositionTypeChange(Hwc2::IComposerClient::Composition from, + Hwc2::IComposerClient::Composition to) const; const compositionengine::Output& mOutput; std::shared_ptr mLayer; @@ -79,4 +87,4 @@ std::unique_ptr createOutputLayer( std::shared_ptr, sp); } // namespace impl -} // namespace android::compositionengine \ No newline at end of file +} // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index e4c9c80429..0a044629b3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -52,7 +52,7 @@ public: void setDisplaySize(const ui::Size&) override; void setProtected(bool useProtected) override; status_t beginFrame(bool mustRecompose) override; - status_t prepareFrame() override; + void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) override; sp dequeueBuffer(base::unique_fd* bufferFence) override; void queueBuffer(base::unique_fd&& readyFence) override; void onPresentDisplayCompleted() override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 924d72cb00..b8679d8021 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -72,6 +72,9 @@ public: MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&)); MOCK_METHOD0(takeReleasedLayers, ReleasedLayers()); + + MOCK_METHOD0(prepareFrame, void()); + MOCK_METHOD0(chooseCompositionStrategy, void()); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h index dab8b9da0e..195648ff7c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -41,6 +41,12 @@ public: MOCK_METHOD1(updateCompositionState, void(bool)); MOCK_METHOD1(writeStateToHWC, void(bool)); + MOCK_CONST_METHOD0(getHwcLayer, HWC2::Layer*()); + MOCK_CONST_METHOD0(requiresClientComposition, bool()); + MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition)); + MOCK_METHOD0(prepareForDeviceLayerRequests, void()); + MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request)); + MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index 146a2eae64..ba6746abb8 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -37,7 +37,7 @@ public: MOCK_METHOD1(setProtected, void(bool)); MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace)); MOCK_METHOD1(beginFrame, status_t(bool mustRecompose)); - MOCK_METHOD0(prepareFrame, status_t()); + MOCK_METHOD2(prepareFrame, void(bool, bool)); MOCK_METHOD1(dequeueBuffer, sp(base::unique_fd*)); MOCK_METHOD1(queueBuffer, void(base::unique_fd&&)); MOCK_METHOD0(onPresentDisplayCompleted, void()); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 8520d70c71..528a8a63cb 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -21,7 +21,9 @@ #include #include #include +#include #include +#include #include "DisplayHardware/HWComposer.h" @@ -124,4 +126,91 @@ void Display::createRenderSurface(RenderSurfaceCreationArgs&& args) { std::move(args))); } +void Display::chooseCompositionStrategy() { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + + // Default to the base settings -- client composition only. + Output::chooseCompositionStrategy(); + + // If we don't have a HWC display, then we are done + if (!mId) { + return; + } + + // Get any composition changes requested by the HWC device, and apply them. + std::optional changes; + auto& hwc = getCompositionEngine().getHwComposer(); + if (status_t result = hwc.getDeviceCompositionChanges(*mId, anyLayersRequireClientComposition(), + &changes); + result != NO_ERROR) { + ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result, + strerror(-result)); + return; + } + if (changes) { + applyChangedTypesToLayers(changes->changedTypes); + applyDisplayRequests(changes->displayRequests); + applyLayerRequestsToLayers(changes->layerRequests); + } + + // Determine what type of composition we are doing from the final state + auto& state = editState(); + state.usesClientComposition = anyLayersRequireClientComposition(); + state.usesDeviceComposition = !allLayersRequireClientComposition(); +} + +bool Display::anyLayersRequireClientComposition() const { + const auto& layers = getOutputLayersOrderedByZ(); + return std::any_of(layers.cbegin(), layers.cend(), + [](const auto& layer) { return layer->requiresClientComposition(); }); +} + +bool Display::allLayersRequireClientComposition() const { + const auto& layers = getOutputLayersOrderedByZ(); + return std::all_of(layers.cbegin(), layers.cend(), + [](const auto& layer) { return layer->requiresClientComposition(); }); +} + +void Display::applyChangedTypesToLayers(const ChangedTypes& changedTypes) { + if (changedTypes.empty()) { + return; + } + + for (auto& layer : getOutputLayersOrderedByZ()) { + auto hwcLayer = layer->getHwcLayer(); + if (!hwcLayer) { + continue; + } + + if (auto it = changedTypes.find(hwcLayer); it != changedTypes.end()) { + layer->applyDeviceCompositionTypeChange( + static_cast(it->second)); + } + } +} + +void Display::applyDisplayRequests(const DisplayRequests& displayRequests) { + auto& state = editState(); + state.flipClientTarget = (static_cast(displayRequests) & + static_cast(HWC2::DisplayRequest::FlipClientTarget)) != 0; + // Note: HWC2::DisplayRequest::WriteClientTargetToOutput is currently ignored. +} + +void Display::applyLayerRequestsToLayers(const LayerRequests& layerRequests) { + for (auto& layer : getOutputLayersOrderedByZ()) { + layer->prepareForDeviceLayerRequests(); + + auto hwcLayer = layer->getHwcLayer(); + if (!hwcLayer) { + continue; + } + + if (auto it = layerRequests.find(hwcLayer); it != layerRequests.end()) { + layer->applyDeviceLayerRequest( + static_cast(it->second)); + } + } +} + } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 845e3c6500..83195229b2 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace android::compositionengine { @@ -250,9 +251,28 @@ Output::ReleasedLayers Output::takeReleasedLayers() { return std::move(mReleasedLayers); } +void Output::prepareFrame() { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + + if (!mState.isEnabled) { + return; + } + + chooseCompositionStrategy(); + + mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition); +} + void Output::dirtyEntireOutput() { mState.dirtyRegion.set(mState.bounds); } +void Output::chooseCompositionStrategy() { + // The base output implementation can only do client composition + mState.usesClientComposition = true; + mState.usesDeviceComposition = false; +} + } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index 0b15dad6cd..3e47fe2a12 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -24,6 +24,10 @@ void OutputCompositionState::dump(std::string& out) const { dumpVal(out, "isEnabled", isEnabled); dumpVal(out, "isSecure", isSecure); + dumpVal(out, "usesClientComposition", usesClientComposition); + dumpVal(out, "usesDeviceComposition", usesDeviceComposition); + dumpVal(out, "flipClientTarget", flipClientTarget); + dumpVal(out, "layerStack", layerStackId); dumpVal(out, "layerStackInternal", layerStackInternal); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index ebfc70489e..6e744b948f 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -550,6 +550,70 @@ void OutputLayer::writeCompositionTypeToHWC( } } +HWC2::Layer* OutputLayer::getHwcLayer() const { + return mState.hwc ? mState.hwc->hwcLayer.get() : nullptr; +} + +bool OutputLayer::requiresClientComposition() const { + return !mState.hwc || + mState.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT; +} + +void OutputLayer::detectDisallowedCompositionTypeChange( + Hwc2::IComposerClient::Composition from, Hwc2::IComposerClient::Composition to) const { + bool result = false; + switch (from) { + case Hwc2::IComposerClient::Composition::INVALID: + case Hwc2::IComposerClient::Composition::CLIENT: + result = false; + break; + + case Hwc2::IComposerClient::Composition::DEVICE: + case Hwc2::IComposerClient::Composition::SOLID_COLOR: + result = (to == Hwc2::IComposerClient::Composition::CLIENT); + break; + + case Hwc2::IComposerClient::Composition::CURSOR: + case Hwc2::IComposerClient::Composition::SIDEBAND: + result = (to == Hwc2::IComposerClient::Composition::CLIENT || + to == Hwc2::IComposerClient::Composition::DEVICE); + break; + } + + if (!result) { + ALOGE("[%s] Invalid device requested composition type change: %s (%d) --> %s (%d)", + mLayerFE->getDebugName(), toString(from).c_str(), static_cast(from), + toString(to).c_str(), static_cast(to)); + } +} + +void OutputLayer::applyDeviceCompositionTypeChange( + Hwc2::IComposerClient::Composition compositionType) { + LOG_FATAL_IF(!mState.hwc); + auto& hwcState = *mState.hwc; + + detectDisallowedCompositionTypeChange(hwcState.hwcCompositionType, compositionType); + + hwcState.hwcCompositionType = compositionType; +} + +void OutputLayer::prepareForDeviceLayerRequests() { + mState.clearClientTarget = false; +} + +void OutputLayer::applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) { + switch (request) { + case Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET: + mState.clearClientTarget = true; + break; + + default: + ALOGE("[%s] Unknown device layer request %s (%d)", mLayerFE->getDebugName(), + toString(request).c_str(), static_cast(request)); + break; + } +} + void OutputLayer::dump(std::string& out) const { using android::base::StringAppendF; diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 8a91316e65..1ce6b4c1c2 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -110,24 +111,13 @@ status_t RenderSurface::beginFrame(bool mustRecompose) { return mDisplaySurface->beginFrame(mustRecompose); } -status_t RenderSurface::prepareFrame() { - auto& hwc = mCompositionEngine.getHwComposer(); - const auto id = mDisplay.getId(); - if (id) { - status_t error = hwc.prepare(*id, mDisplay); - if (error != NO_ERROR) { - return error; - } - } - +void RenderSurface::prepareFrame(bool usesClientComposition, bool usesDeviceComposition) { DisplaySurface::CompositionType compositionType; - const bool hasClient = hwc.hasClientComposition(id); - const bool hasDevice = hwc.hasDeviceComposition(id); - if (hasClient && hasDevice) { + if (usesClientComposition && usesDeviceComposition) { compositionType = DisplaySurface::COMPOSITION_MIXED; - } else if (hasClient) { + } else if (usesClientComposition) { compositionType = DisplaySurface::COMPOSITION_GLES; - } else if (hasDevice) { + } else if (usesDeviceComposition) { compositionType = DisplaySurface::COMPOSITION_HWC; } else { // Nothing to do -- when turning the screen off we get a frame like @@ -135,7 +125,11 @@ status_t RenderSurface::prepareFrame() { // will do a prepare/set cycle. compositionType = DisplaySurface::COMPOSITION_HWC; } - return mDisplaySurface->prepareFrame(compositionType); + + if (status_t result = mDisplaySurface->prepareFrame(compositionType); result != NO_ERROR) { + ALOGE("updateCompositionType failed for %s: %d (%s)", mDisplay.getName().c_str(), result, + strerror(-result)); + } } sp RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) { @@ -163,10 +157,9 @@ sp RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) { } void RenderSurface::queueBuffer(base::unique_fd&& readyFence) { - auto& hwc = mCompositionEngine.getHwComposer(); - const auto id = mDisplay.getId(); + auto& state = mDisplay.getState(); - if (hwc.hasClientComposition(id) || hwc.hasFlipClientTargetRequest(id)) { + if (state.usesClientComposition || state.flipClientTarget) { // hasFlipClientTargetRequest could return true even if we haven't // dequeued a buffer before. Try dequeueing one if we don't have a // buffer ready. diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index f0aea25566..d0f79f2d81 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -24,33 +24,54 @@ #include #include #include +#include #include #include +#include "MockHWC2.h" #include "MockHWComposer.h" namespace android::compositionengine { namespace { using testing::_; +using testing::DoAll; using testing::Return; using testing::ReturnRef; +using testing::Sequence; +using testing::SetArgPointee; using testing::StrictMock; constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42}; -class DisplayTest : public testing::Test { -public: - ~DisplayTest() override = default; +struct DisplayTest : public testing::Test { + 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)); + + std::vector> layers; + layers.emplace_back(mLayer1); + layers.emplace_back(mLayer2); + layers.emplace_back(mLayer3); + mDisplay.setOutputLayersOrderedByZ(std::move(layers)); + } StrictMock mHwComposer; StrictMock mCompositionEngine; sp mNativeWindow = new StrictMock(); + StrictMock mHWC2Layer1; + StrictMock mHWC2Layer2; + StrictMock mHWC2LayerUnknown; + mock::OutputLayer* mLayer1 = new StrictMock(); + mock::OutputLayer* mLayer2 = new StrictMock(); + mock::OutputLayer* mLayer3 = new StrictMock(); impl::Display mDisplay{mCompositionEngine, DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()}; }; -/* ------------------------------------------------------------------------ +/* * Basic construction */ @@ -90,13 +111,11 @@ TEST_F(DisplayTest, canInstantiateDisplay) { } } -/* ------------------------------------------------------------------------ +/* * Display::disconnect() */ TEST_F(DisplayTest, disconnectDisconnectsDisplay) { - EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer)); - // The first call to disconnect will disconnect the display with the HWC and // set mHwcId to -1. EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(1); @@ -109,7 +128,7 @@ TEST_F(DisplayTest, disconnectDisconnectsDisplay) { EXPECT_FALSE(mDisplay.getId()); } -/* ------------------------------------------------------------------------ +/* * Display::setColorTransform() */ @@ -117,8 +136,6 @@ TEST_F(DisplayTest, setColorTransformSetsTransform) { // Identity matrix sets an identity state value const mat4 identity; - EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer)); - EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, identity)).Times(1); mDisplay.setColorTransform(identity); @@ -135,7 +152,7 @@ TEST_F(DisplayTest, setColorTransformSetsTransform) { EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mDisplay.getState().colorTransform); } -/* ------------------------------------------------------------------------ +/* * Display::setColorMode() */ @@ -145,7 +162,6 @@ TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) { mock::DisplayColorProfile* colorProfile = new StrictMock(); mDisplay.setDisplayColorProfileForTest(std::unique_ptr(colorProfile)); - EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer)); EXPECT_CALL(*colorProfile, getTargetDataspace(_, _, _)) .WillRepeatedly(Return(ui::Dataspace::UNKNOWN)); @@ -202,7 +218,7 @@ TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) { EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace); } -/* ------------------------------------------------------------------------ +/* * Display::createDisplayColorProfile() */ @@ -214,7 +230,7 @@ TEST_F(DisplayTest, createDisplayColorProfileSetsDisplayColorProfile) { EXPECT_TRUE(mDisplay.getDisplayColorProfile() != nullptr); } -/* ------------------------------------------------------------------------ +/* * Display::createRenderSurface() */ @@ -225,5 +241,227 @@ TEST_F(DisplayTest, createRenderSurfaceSetsRenderSurface) { EXPECT_TRUE(mDisplay.getRenderSurface() != nullptr); } +/* + * Display::chooseCompositionStrategy() + */ + +struct DisplayChooseCompositionStrategyTest : public testing::Test { + struct DisplayPartialMock : public impl::Display { + DisplayPartialMock(const compositionengine::CompositionEngine& compositionEngine, + compositionengine::DisplayCreationArgs&& args) + : impl::Display(compositionEngine, std::move(args)) {} + + // Sets up the helper functions called by chooseCompositionStrategy to + // use a mock implementations. + MOCK_CONST_METHOD0(anyLayersRequireClientComposition, bool()); + MOCK_CONST_METHOD0(allLayersRequireClientComposition, bool()); + MOCK_METHOD1(applyChangedTypesToLayers, void(const impl::Display::ChangedTypes&)); + MOCK_METHOD1(applyDisplayRequests, void(const impl::Display::DisplayRequests&)); + MOCK_METHOD1(applyLayerRequestsToLayers, void(const impl::Display::LayerRequests&)); + }; + + DisplayChooseCompositionStrategyTest() { + EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer)); + } + + StrictMock mHwComposer; + StrictMock mCompositionEngine; + StrictMock + mDisplay{mCompositionEngine, + DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()}; +}; + +TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) { + impl::Display nonHwcDisplay{mCompositionEngine, DisplayCreationArgsBuilder().build()}; + EXPECT_FALSE(nonHwcDisplay.getId()); + + nonHwcDisplay.chooseCompositionStrategy(); + + auto& state = nonHwcDisplay.getState(); + EXPECT_TRUE(state.usesClientComposition); + EXPECT_FALSE(state.usesDeviceComposition); +} + +TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutOnHwcError) { + EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).WillOnce(Return(false)); + EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, false, _)) + .WillOnce(Return(INVALID_OPERATION)); + + mDisplay.chooseCompositionStrategy(); + + auto& state = mDisplay.getState(); + EXPECT_TRUE(state.usesClientComposition); + EXPECT_FALSE(state.usesDeviceComposition); +} + +TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { + // Since two calls are made to anyLayersRequireClientComposition with different return values, + // use a Sequence to control the matching so the values are returned in a known order. + Sequence s; + EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()) + .InSequence(s) + .WillOnce(Return(false)); + + EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _)) + .WillOnce(Return(NO_ERROR)); + EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); + + mDisplay.chooseCompositionStrategy(); + + auto& state = mDisplay.getState(); + EXPECT_FALSE(state.usesClientComposition); + EXPECT_TRUE(state.usesDeviceComposition); +} + +TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { + android::HWComposer::DeviceRequestedChanges changes{ + {{nullptr, HWC2::Composition::Client}}, + HWC2::DisplayRequest::FlipClientTarget, + {{nullptr, HWC2::LayerRequest::ClearClientTarget}}, + }; + + // Since two calls are made to anyLayersRequireClientComposition with different return values, + // use a Sequence to control the matching so the values are returned in a known order. + Sequence s; + EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()) + .InSequence(s) + .WillOnce(Return(false)); + + EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _)) + .WillOnce(DoAll(SetArgPointee<2>(changes), Return(NO_ERROR))); + EXPECT_CALL(mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1); + EXPECT_CALL(mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1); + EXPECT_CALL(mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1); + EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); + + mDisplay.chooseCompositionStrategy(); + + auto& state = mDisplay.getState(); + EXPECT_FALSE(state.usesClientComposition); + EXPECT_TRUE(state.usesDeviceComposition); +} + +/* + * Display::anyLayersRequireClientComposition() + */ + +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_FALSE(mDisplay.anyLayersRequireClientComposition()); +} + +TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsTrue) { + EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false)); + EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true)); + + EXPECT_TRUE(mDisplay.anyLayersRequireClientComposition()); +} + +/* + * Display::allLayersRequireClientComposition() + */ + +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_TRUE(mDisplay.allLayersRequireClientComposition()); +} + +TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsFalse) { + EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true)); + EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false)); + + EXPECT_FALSE(mDisplay.allLayersRequireClientComposition()); +} + +/* + * Display::applyChangedTypesToLayers() + */ + +TEST_F(DisplayTest, applyChangedTypesToLayersTakesEarlyOutIfNoChangedLayers) { + mDisplay.applyChangedTypesToLayers(impl::Display::ChangedTypes()); +} + +TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) { + EXPECT_CALL(*mLayer1, + applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT)) + .Times(1); + EXPECT_CALL(*mLayer2, + applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::DEVICE)) + .Times(1); + + mDisplay.applyChangedTypesToLayers(impl::Display::ChangedTypes{ + {&mHWC2Layer1, HWC2::Composition::Client}, + {&mHWC2Layer2, HWC2::Composition::Device}, + {&mHWC2LayerUnknown, HWC2::Composition::SolidColor}, + }); +} + +/* + * Display::applyDisplayRequests() + */ + +TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesNoRequests) { + mDisplay.applyDisplayRequests(static_cast(0)); + + auto& state = mDisplay.getState(); + EXPECT_FALSE(state.flipClientTarget); +} + +TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesFlipClientTarget) { + mDisplay.applyDisplayRequests(HWC2::DisplayRequest::FlipClientTarget); + + auto& state = mDisplay.getState(); + EXPECT_TRUE(state.flipClientTarget); +} + +TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesWriteClientTargetToOutput) { + mDisplay.applyDisplayRequests(HWC2::DisplayRequest::WriteClientTargetToOutput); + + auto& state = mDisplay.getState(); + EXPECT_FALSE(state.flipClientTarget); +} + +TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesAllRequestFlagsSet) { + mDisplay.applyDisplayRequests(static_cast(~0)); + + auto& state = mDisplay.getState(); + EXPECT_TRUE(state.flipClientTarget); +} + +/* + * Display::applyLayerRequestsToLayers() + */ + +TEST_F(DisplayTest, applyLayerRequestsToLayersPreparesAllLayers) { + EXPECT_CALL(*mLayer1, prepareForDeviceLayerRequests()).Times(1); + EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1); + EXPECT_CALL(*mLayer3, 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, + applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET)) + .Times(1); + + mDisplay.applyLayerRequestsToLayers(impl::Display::LayerRequests{ + {&mHWC2Layer1, HWC2::LayerRequest::ClearClientTarget}, + {&mHWC2LayerUnknown, HWC2::LayerRequest::ClearClientTarget}, + }); +} + } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index 94349dea14..5cfec778a4 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -40,7 +40,9 @@ public: std::optional(uint32_t, uint32_t, ui::PixelFormat*)); MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId)); MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*)); - MOCK_METHOD2(prepare, status_t(DisplayId, const compositionengine::Output&)); + MOCK_METHOD3(getDeviceCompositionChanges, + status_t(DisplayId, bool, + std::optional*)); MOCK_METHOD5(setClientTarget, status_t(DisplayId, uint32_t, const sp&, const sp&, ui::Dataspace)); @@ -50,8 +52,6 @@ public: MOCK_METHOD2(setColorTransform, status_t(DisplayId, const mat4&)); MOCK_METHOD1(disconnectDisplay, void(DisplayId)); MOCK_CONST_METHOD1(hasDeviceComposition, bool(const std::optional&)); - MOCK_CONST_METHOD1(hasFlipClientTargetRequest, bool(const std::optional&)); - MOCK_CONST_METHOD1(hasClientComposition, bool(const std::optional&)); MOCK_CONST_METHOD1(getPresentFence, sp(DisplayId)); MOCK_CONST_METHOD2(getLayerReleaseFence, sp(DisplayId, HWC2::Layer*)); MOCK_METHOD3(setOutputBuffer, status_t(DisplayId, const sp&, const sp&)); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 7b9528be9c..a5428ad993 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -56,8 +56,7 @@ MATCHER_P(ColorEq, expected, "") { return expected.r == arg.r && expected.g == arg.g && expected.b == arg.b && expected.a == arg.a; } -class OutputLayerTest : public testing::Test { -public: +struct OutputLayerTest : public testing::Test { OutputLayerTest() { EXPECT_CALL(*mLayerFE, getDebugName()).WillRepeatedly(Return("Test LayerFE")); EXPECT_CALL(mOutput, getName()).WillRepeatedly(ReturnRef(kOutputName)); @@ -66,8 +65,6 @@ public: EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState)); } - ~OutputLayerTest() override = default; - compositionengine::mock::Output mOutput; std::shared_ptr mLayer{ new StrictMock()}; @@ -784,5 +781,99 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompo mOutputLayer.writeStateToHWC(false); } +/* + * OutputLayer::getHwcLayer() + */ + +TEST_F(OutputLayerTest, getHwcLayerHandlesNoHwcState) { + mOutputLayer.editState().hwc.reset(); + + EXPECT_TRUE(mOutputLayer.getHwcLayer() == nullptr); +} + +TEST_F(OutputLayerTest, getHwcLayerHandlesNoHwcLayer) { + mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr}; + + EXPECT_TRUE(mOutputLayer.getHwcLayer() == nullptr); +} + +TEST_F(OutputLayerTest, getHwcLayerReturnsHwcLayer) { + auto hwcLayer = std::make_shared>(); + mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{hwcLayer}; + + EXPECT_EQ(hwcLayer.get(), mOutputLayer.getHwcLayer()); +} + +/* + * OutputLayer::requiresClientComposition() + */ + +TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfNoHWC2State) { + mOutputLayer.editState().hwc.reset(); + + EXPECT_TRUE(mOutputLayer.requiresClientComposition()); +} + +TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfSetToClientComposition) { + mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr}; + mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CLIENT; + + EXPECT_TRUE(mOutputLayer.requiresClientComposition()); +} + +TEST_F(OutputLayerTest, requiresClientCompositionReturnsFalseIfSetToDeviceComposition) { + mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr}; + mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE; + + EXPECT_FALSE(mOutputLayer.requiresClientComposition()); +} + +/* + * OutputLayer::applyDeviceCompositionTypeChange() + */ + +TEST_F(OutputLayerTest, applyDeviceCompositionTypeChangeSetsNewType) { + mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr}; + mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE; + + mOutputLayer.applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT); + + ASSERT_TRUE(mOutputLayer.getState().hwc); + EXPECT_EQ(Hwc2::IComposerClient::Composition::CLIENT, + mOutputLayer.getState().hwc->hwcCompositionType); +} + +/* + * OutputLayer::prepareForDeviceLayerRequests() + */ + +TEST_F(OutputLayerTest, prepareForDeviceLayerRequestsResetsRequestState) { + mOutputLayer.editState().clearClientTarget = true; + + mOutputLayer.prepareForDeviceLayerRequests(); + + EXPECT_FALSE(mOutputLayer.getState().clearClientTarget); +} + +/* + * OutputLayer::applyDeviceLayerRequest() + */ + +TEST_F(OutputLayerTest, applyDeviceLayerRequestHandlesClearClientTarget) { + mOutputLayer.editState().clearClientTarget = false; + + mOutputLayer.applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET); + + EXPECT_TRUE(mOutputLayer.getState().clearClientTarget); +} + +TEST_F(OutputLayerTest, applyDeviceLayerRequestHandlesUnknownRequest) { + mOutputLayer.editState().clearClientTarget = false; + + mOutputLayer.applyDeviceLayerRequest(static_cast(0)); + + EXPECT_FALSE(mOutputLayer.getState().clearClientTarget); +} + } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 6f087d9e54..aa35d2581c 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -37,8 +38,7 @@ using testing::Return; using testing::ReturnRef; using testing::StrictMock; -class OutputTest : public testing::Test { -public: +struct OutputTest : public testing::Test { OutputTest() { mOutput.setDisplayColorProfileForTest( std::unique_ptr(mDisplayColorProfile)); @@ -46,7 +46,6 @@ public: mOutput.editState().bounds = kDefaultDisplaySize; } - ~OutputTest() override = default; static const Rect kDefaultDisplaySize; @@ -58,7 +57,7 @@ public: const Rect OutputTest::kDefaultDisplaySize{100, 200}; -/* ------------------------------------------------------------------------ +/* * Basic construction */ @@ -77,7 +76,7 @@ TEST_F(OutputTest, canInstantiateOutput) { EXPECT_FALSE(mOutput.isValid()); } -/* ------------------------------------------------------------------------ +/* * Output::setCompositionEnabled() */ @@ -108,7 +107,7 @@ TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) { EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } -/* ------------------------------------------------------------------------ +/* * Output::setProjection() */ @@ -130,7 +129,7 @@ TEST_F(OutputTest, setProjectionTriviallyWorks) { EXPECT_EQ(needsFiltering, mOutput.getState().needsFiltering); } -/* ------------------------------------------------------------------------ +/* * Output::setBounds() */ @@ -147,7 +146,7 @@ TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) { EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(Rect(displaySize)))); } -/* ------------------------------------------------------------------------ +/* * Output::setLayerStackFilter() */ @@ -161,7 +160,7 @@ TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) { EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } -/* ------------------------------------------------------------------------ +/* * Output::setColorTransform */ @@ -200,7 +199,7 @@ TEST_F(OutputTest, setColorTransformSetsTransform) { EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } -/* ------------------------------------------------------------------------ +/* * Output::setColorMode */ @@ -239,7 +238,7 @@ TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) { EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region())); } -/* ------------------------------------------------------------------------ +/* * Output::setRenderSurface() */ @@ -254,7 +253,7 @@ TEST_F(OutputTest, setRenderSurfaceResetsBounds) { EXPECT_EQ(Rect(newDisplaySize), mOutput.getState().bounds); } -/* ------------------------------------------------------------------------ +/* * Output::getDirtyRegion() */ @@ -283,7 +282,7 @@ TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) { } } -/* ------------------------------------------------------------------------ +/* * Output::belongsInOutput() */ @@ -310,7 +309,7 @@ TEST_F(OutputTest, belongsInOutputFiltersAsExpected) { EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false)); } -/* ------------------------------------------------------------------------ +/* * Output::getOutputLayerForLayer() */ @@ -342,7 +341,7 @@ TEST_F(OutputTest, getOutputLayerForLayerWorks) { EXPECT_EQ(nullptr, mOutput.getOutputLayerForLayer(&layer)); } -/* ------------------------------------------------------------------------ +/* * Output::getOrCreateOutputLayer() */ @@ -389,5 +388,63 @@ TEST_F(OutputTest, getOrCreateOutputLayerWorks) { } } +/* + * Output::prepareFrame() + */ + +struct OutputPrepareFrameTest : public testing::Test { + struct OutputPartialMock : public impl::Output { + OutputPartialMock(const compositionengine::CompositionEngine& compositionEngine) + : impl::Output(compositionEngine) {} + + // Sets up the helper functions called by prepareFrame to use a mock + // implementations. + MOCK_METHOD0(chooseCompositionStrategy, void()); + }; + + OutputPrepareFrameTest() { + mOutput.setDisplayColorProfileForTest( + std::unique_ptr(mDisplayColorProfile)); + mOutput.setRenderSurfaceForTest(std::unique_ptr(mRenderSurface)); + } + + StrictMock mCompositionEngine; + mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock(); + mock::RenderSurface* mRenderSurface = new StrictMock(); + StrictMock mOutput{mCompositionEngine}; +}; + +TEST_F(OutputPrepareFrameTest, takesEarlyOutIfNotEnabled) { + mOutput.editState().isEnabled = false; + + mOutput.prepareFrame(); +} + +TEST_F(OutputPrepareFrameTest, delegatesToChooseCompositionStrategyAndRenderSurface) { + mOutput.editState().isEnabled = true; + mOutput.editState().usesClientComposition = false; + mOutput.editState().usesDeviceComposition = true; + + EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1); + EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)); + + mOutput.prepareFrame(); +} + +// Note: Use OutputTest and not OutputPrepareFrameTest, so the real +// base chooseCompositionStrategy() is invoked. +TEST_F(OutputTest, prepareFrameSetsClientCompositionOnlyByDefault) { + mOutput.editState().isEnabled = true; + mOutput.editState().usesClientComposition = false; + mOutput.editState().usesDeviceComposition = true; + + EXPECT_CALL(*mRenderSurface, prepareFrame(true, false)); + + mOutput.prepareFrame(); + + EXPECT_TRUE(mOutput.getState().usesClientComposition); + EXPECT_FALSE(mOutput.getState().usesDeviceComposition); +} + } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 87419ea6a8..da3f4fb4cd 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -27,15 +28,9 @@ #include #include -#include "MockHWComposer.h" - namespace android::compositionengine { namespace { -/* ------------------------------------------------------------------------ - * RenderSurfaceTest - */ - constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920; constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080; constexpr std::optional DEFAULT_DISPLAY_ID = std::make_optional(DisplayId{123u}); @@ -55,14 +50,11 @@ public: RenderSurfaceTest() { EXPECT_CALL(mDisplay, getId()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_ID)); EXPECT_CALL(mDisplay, getName()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_NAME)); - EXPECT_CALL(mCompositionEngine, getHwComposer).WillRepeatedly(ReturnRef(mHwComposer)); EXPECT_CALL(mCompositionEngine, getRenderEngine).WillRepeatedly(ReturnRef(mRenderEngine)); EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL)) .WillRepeatedly(Return(NO_ERROR)); } - ~RenderSurfaceTest() override = default; - StrictMock mHwComposer; StrictMock mRenderEngine; StrictMock mCompositionEngine; StrictMock mDisplay; @@ -74,7 +66,7 @@ public: mDisplaySurface}}; }; -/* ------------------------------------------------------------------------ +/* * Basic construction */ @@ -82,7 +74,7 @@ TEST_F(RenderSurfaceTest, canInstantiate) { EXPECT_TRUE(mSurface.isValid()); } -/* ------------------------------------------------------------------------ +/* * RenderSurface::initialize() */ @@ -95,7 +87,7 @@ TEST_F(RenderSurfaceTest, initializeConfiguresNativeWindow) { mSurface.initialize(); } -/* ------------------------------------------------------------------------ +/* * RenderSurface::getSize() */ @@ -105,7 +97,7 @@ TEST_F(RenderSurfaceTest, sizeReturnsConstructedSize) { EXPECT_EQ(expected, mSurface.getSize()); } -/* ------------------------------------------------------------------------ +/* * RenderSurface::getClientTargetAcquireFence() */ @@ -117,7 +109,7 @@ TEST_F(RenderSurfaceTest, getClientTargetAcquireFenceForwardsCall) { EXPECT_EQ(fence.get(), mSurface.getClientTargetAcquireFence().get()); } -/* ------------------------------------------------------------------------ +/* * RenderSurface::setDisplaySize() */ @@ -127,7 +119,7 @@ TEST_F(RenderSurfaceTest, setDisplaySizeAppliesChange) { mSurface.setDisplaySize(ui::Size(640, 480)); } -/* ------------------------------------------------------------------------ +/* * RenderSurface::setBufferDataspace() */ @@ -138,7 +130,7 @@ TEST_F(RenderSurfaceTest, setBufferDataspaceAppliesChange) { mSurface.setBufferDataspace(ui::Dataspace::DISPLAY_P3); } -/* ------------------------------------------------------------------------ +/* * RenderSurface::setProtected() */ @@ -179,7 +171,7 @@ TEST_F(RenderSurfaceTest, setProtectedEnableWithError) { EXPECT_FALSE(mSurface.isProtected()); } -/* ------------------------------------------------------------------------ +/* * RenderSurface::beginFrame() */ @@ -189,73 +181,39 @@ TEST_F(RenderSurfaceTest, beginFrameAppliesChange) { EXPECT_EQ(NO_ERROR, mSurface.beginFrame(true)); } -/* ------------------------------------------------------------------------ +/* * RenderSurface::prepareFrame() */ -TEST_F(RenderSurfaceTest, prepareFramePassesOutputLayersToHwc) { - EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay))) - .WillOnce(Return(INVALID_OPERATION)); - - EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame()); -} - -TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) { - EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay))) - .WillOnce(Return(INVALID_OPERATION)); - - EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame()); -} - TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) { - EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay))) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true)); - EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true)); - EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED)) - .WillOnce(Return(INVALID_OPERATION)); + .WillOnce(Return(NO_ERROR)); - EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame()); + mSurface.prepareFrame(true, true); } TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGlesComposition) { - EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay))) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true)); - EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false)); - EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES)) .WillOnce(Return(NO_ERROR)); - EXPECT_EQ(NO_ERROR, mSurface.prepareFrame()); + mSurface.prepareFrame(true, false); } TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) { - EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay))) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false)); - EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true)); - EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)) .WillOnce(Return(NO_ERROR)); - EXPECT_EQ(NO_ERROR, mSurface.prepareFrame()); + mSurface.prepareFrame(false, true); } TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) { - EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay))) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false)); - EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false)); - EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)) .WillOnce(Return(NO_ERROR)); - EXPECT_EQ(NO_ERROR, mSurface.prepareFrame()); + mSurface.prepareFrame(false, false); } -/* ------------------------------------------------------------------------ +/* * RenderSurface::dequeueBuffer() */ @@ -272,7 +230,7 @@ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) { EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get()); } -/* ------------------------------------------------------------------------ +/* * RenderSurface::queueBuffer() */ @@ -280,9 +238,11 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { sp buffer = new GraphicBuffer(); mSurface.mutableGraphicBufferForTest() = buffer; - EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false)); - EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)) - .WillOnce(Return(false)); + impl::OutputCompositionState state; + state.usesClientComposition = false; + state.flipClientTarget = false; + + EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); mSurface.queueBuffer(base::unique_fd()); @@ -294,7 +254,11 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) { sp buffer = new GraphicBuffer(); mSurface.mutableGraphicBufferForTest() = buffer; - EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true)); + impl::OutputCompositionState state; + state.usesClientComposition = true; + state.flipClientTarget = false; + + EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); @@ -308,8 +272,11 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) { sp buffer = new GraphicBuffer(); mSurface.mutableGraphicBufferForTest() = buffer; - EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false)); - EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true)); + impl::OutputCompositionState state; + state.usesClientComposition = false; + state.flipClientTarget = true; + + EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); @@ -322,8 +289,11 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) { TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) { sp buffer = new GraphicBuffer(); - EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false)); - EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true)); + impl::OutputCompositionState state; + state.usesClientComposition = false; + state.flipClientTarget = true; + + EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _)) .WillOnce( DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR))); @@ -340,7 +310,10 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirt sp buffer = new GraphicBuffer(); mSurface.mutableGraphicBufferForTest() = buffer; - EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true)); + impl::OutputCompositionState state; + state.usesClientComposition = true; + + EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) .WillOnce(Return(INVALID_OPERATION)); EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true)); @@ -353,7 +326,7 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirt EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); } -/* ------------------------------------------------------------------------ +/* * RenderSurface::onPresentDisplayCompleted() */ @@ -363,7 +336,7 @@ TEST_F(RenderSurfaceTest, onPresentDisplayCompletedForwardsSignal) { mSurface.onPresentDisplayCompleted(); } -/* ------------------------------------------------------------------------ +/* * RenderSurface::flip() */ diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 1099041b4b..d480f7ce29 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -20,6 +20,8 @@ #define LOG_TAG "HWComposer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include "HWComposer.h" + #include #include #include @@ -29,12 +31,10 @@ #include #include -#include "HWComposer.h" -#include "HWC2.h" -#include "ComposerHal.h" - -#include "../Layer.h" // needed only for debugging +#include "../Layer.h" // needed only for debugging #include "../SurfaceFlinger.h" +#include "ComposerHal.h" +#include "HWC2.h" #define LOG_HWC_DISPLAY_ERROR(hwcDisplayId, msg) \ ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg) @@ -113,31 +113,6 @@ bool HWComposer::hasDisplayCapability(const std::optional& displayId, return mDisplayData.at(*displayId).hwcDisplay->getCapabilities().count(capability) > 0; } -void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) { - bool valid = true; - switch (from) { - case HWC2::Composition::Client: - valid = false; - break; - case HWC2::Composition::Device: - case HWC2::Composition::SolidColor: - valid = (to == HWC2::Composition::Client); - break; - case HWC2::Composition::Cursor: - case HWC2::Composition::Sideband: - valid = (to == HWC2::Composition::Client || - to == HWC2::Composition::Device); - break; - default: - break; - } - - if (!valid) { - ALOGE("Invalid layer type change: %s --> %s", to_string(from).c_str(), - to_string(to).c_str()); - } -} - std::optional HWComposer::onHotplug(hwc2_display_t hwcDisplayId, HWC2::Connection connection) { std::optional info; @@ -399,7 +374,9 @@ status_t HWComposer::setClientTarget(DisplayId displayId, uint32_t slot, return NO_ERROR; } -status_t HWComposer::prepare(DisplayId displayId, const compositionengine::Output& output) { +status_t HWComposer::getDeviceCompositionChanges( + DisplayId displayId, bool frameUsesClientComposition, + std::optional* outChanges) { ATRACE_CALL(); RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); @@ -419,12 +396,8 @@ status_t HWComposer::prepare(DisplayId displayId, const compositionengine::Outpu // composition. When there is client composition, since we haven't // rendered to the client target yet, we should not attempt to skip // validate. - // - // displayData.hasClientComposition hasn't been updated for this frame. - // The check below is incorrect. We actually rely on HWC here to fall - // back to validate when there is any client layer. displayData.validateWasSkipped = false; - if (!displayData.hasClientComposition) { + if (!frameUsesClientComposition) { sp outPresentFence; uint32_t state = UINT32_MAX; error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state); @@ -449,58 +422,19 @@ status_t HWComposer::prepare(DisplayId displayId, const compositionengine::Outpu RETURN_IF_HWC_ERROR_FOR("validate", error, displayId, BAD_INDEX); } - std::unordered_map changedTypes; + android::HWComposer::DeviceRequestedChanges::ChangedTypes changedTypes; changedTypes.reserve(numTypes); error = hwcDisplay->getChangedCompositionTypes(&changedTypes); RETURN_IF_HWC_ERROR_FOR("getChangedCompositionTypes", error, displayId, BAD_INDEX); - displayData.displayRequests = static_cast(0); - std::unordered_map layerRequests; + auto displayRequests = static_cast(0); + android::HWComposer::DeviceRequestedChanges::LayerRequests layerRequests; layerRequests.reserve(numRequests); - error = hwcDisplay->getRequests(&displayData.displayRequests, - &layerRequests); + error = hwcDisplay->getRequests(&displayRequests, &layerRequests); RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX); - displayData.hasClientComposition = false; - displayData.hasDeviceComposition = false; - for (auto& outputLayer : output.getOutputLayersOrderedByZ()) { - auto& state = outputLayer->editState(); - LOG_FATAL_IF(!state.hwc.); - auto hwcLayer = (*state.hwc).hwcLayer; - - if (auto it = changedTypes.find(hwcLayer.get()); it != changedTypes.end()) { - auto newCompositionType = it->second; - validateChange(static_cast((*state.hwc).hwcCompositionType), - newCompositionType); - (*state.hwc).hwcCompositionType = - static_cast(newCompositionType); - } - - switch ((*state.hwc).hwcCompositionType) { - case Hwc2::IComposerClient::Composition::CLIENT: - displayData.hasClientComposition = true; - break; - case Hwc2::IComposerClient::Composition::DEVICE: - case Hwc2::IComposerClient::Composition::SOLID_COLOR: - case Hwc2::IComposerClient::Composition::CURSOR: - case Hwc2::IComposerClient::Composition::SIDEBAND: - displayData.hasDeviceComposition = true; - break; - default: - break; - } - - state.clearClientTarget = false; - if (auto it = layerRequests.find(hwcLayer.get()); it != layerRequests.end()) { - auto request = it->second; - if (request == HWC2::LayerRequest::ClearClientTarget) { - state.clearClientTarget = true; - } else { - LOG_DISPLAY_ERROR(displayId, - ("Unknown layer request " + to_string(request)).c_str()); - } - } - } + outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests), + std::move(layerRequests)}); error = hwcDisplay->acceptChanges(); RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX); @@ -508,40 +442,6 @@ status_t HWComposer::prepare(DisplayId displayId, const compositionengine::Outpu return NO_ERROR; } -bool HWComposer::hasDeviceComposition(const std::optional& displayId) const { - if (!displayId) { - // Displays without a corresponding HWC display are never composed by - // the device - return false; - } - - RETURN_IF_INVALID_DISPLAY(*displayId, false); - return mDisplayData.at(*displayId).hasDeviceComposition; -} - -bool HWComposer::hasFlipClientTargetRequest(const std::optional& displayId) const { - if (!displayId) { - // Displays without a corresponding HWC display are never composed by - // the device - return false; - } - - RETURN_IF_INVALID_DISPLAY(*displayId, false); - return ((static_cast(mDisplayData.at(*displayId).displayRequests) & - static_cast(HWC2::DisplayRequest::FlipClientTarget)) != 0); -} - -bool HWComposer::hasClientComposition(const std::optional& displayId) const { - if (!displayId) { - // Displays without a corresponding HWC display are always composed by - // the client - return true; - } - - RETURN_IF_INVALID_DISPLAY(*displayId, true); - return mDisplayData.at(*displayId).hasClientComposition; -} - sp HWComposer::getPresentFence(DisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE); return mDisplayData.at(displayId).lastPresentFence; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index de863b8d6c..e87c5c3309 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -71,8 +71,26 @@ public: // Destroy a previously created layer virtual void destroyLayer(DisplayId displayId, HWC2::Layer* layer) = 0; - // Asks the HAL what it can do - virtual status_t prepare(DisplayId displayId, const compositionengine::Output&) = 0; + struct DeviceRequestedChanges { + using ChangedTypes = std::unordered_map; + using DisplayRequests = HWC2::DisplayRequest; + using LayerRequests = std::unordered_map; + + ChangedTypes changedTypes; + DisplayRequests displayRequests; + LayerRequests layerRequests; + }; + + // Gets any required composition change requests from the HWC device. + // + // Note that frameUsesClientComposition must be set correctly based on + // whether the current frame appears to use client composition. If it is + // false some internal optimizations are allowed to present the display + // with fewer handshakes, but this does not work if client composition is + // expected. + virtual status_t getDeviceCompositionChanges( + DisplayId, bool frameUsesClientComposition, + std::optional* outChanges) = 0; virtual status_t setClientTarget(DisplayId displayId, uint32_t slot, const sp& acquireFence, const sp& target, @@ -93,15 +111,6 @@ public: // reset state when an external, non-virtual display is disconnected virtual void disconnectDisplay(DisplayId displayId) = 0; - // does this display have layers handled by HWC - virtual bool hasDeviceComposition(const std::optional& displayId) const = 0; - - // does this display have pending request to flip client target - virtual bool hasFlipClientTargetRequest(const std::optional& displayId) const = 0; - - // does this display have layers handled by GLES - virtual bool hasClientComposition(const std::optional& displayId) const = 0; - // get the present fence received from the last call to present. virtual sp getPresentFence(DisplayId displayId) const = 0; @@ -210,8 +219,9 @@ public: // Destroy a previously created layer void destroyLayer(DisplayId displayId, HWC2::Layer* layer) override; - // Asks the HAL what it can do - status_t prepare(DisplayId displayId, const compositionengine::Output&) override; + status_t getDeviceCompositionChanges( + DisplayId, bool frameUsesClientComposition, + std::optional* outChanges) override; status_t setClientTarget(DisplayId displayId, uint32_t slot, const sp& acquireFence, const sp& target, ui::Dataspace dataspace) override; @@ -231,15 +241,6 @@ public: // reset state when an external, non-virtual display is disconnected void disconnectDisplay(DisplayId displayId) override; - // does this display have layers handled by HWC - bool hasDeviceComposition(const std::optional& displayId) const override; - - // does this display have pending request to flip client target - bool hasFlipClientTargetRequest(const std::optional& displayId) const override; - - // does this display have layers handled by GLES - bool hasClientComposition(const std::optional& displayId) const override; - // get the present fence received from the last call to present. sp getPresentFence(DisplayId displayId) const override; @@ -326,14 +327,10 @@ private: std::optional onHotplugConnect(hwc2_display_t hwcDisplayId); - static void validateChange(HWC2::Composition from, HWC2::Composition to); - struct DisplayData { bool isVirtual = false; - bool hasClientComposition = false; - bool hasDeviceComposition = false; + HWC2::Display* hwcDisplay = nullptr; - HWC2::DisplayRequest displayRequests; sp lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires std::unordered_map> releaseFences; buffer_handle_t outbufHandle = nullptr; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7345e8d56c..017c3d2bb6 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1792,7 +1792,7 @@ void SurfaceFlinger::handleMessageRefresh() { calculateWorkingSet(); for (const auto& [token, display] : mDisplays) { beginFrame(display); - prepareFrame(display); + display->getCompositionDisplay()->prepareFrame(); doDebugFlashRegions(display, repaintEverything); doComposition(display, repaintEverything); } @@ -1802,16 +1802,16 @@ void SurfaceFlinger::handleMessageRefresh() { postFrame(); postComposition(); - mHadClientComposition = false; - mHadDeviceComposition = false; - for (const auto& [token, displayDevice] : mDisplays) { - auto display = displayDevice->getCompositionDisplay(); - const auto displayId = display->getId(); - mHadClientComposition = - mHadClientComposition || getHwComposer().hasClientComposition(displayId); - mHadDeviceComposition = - mHadDeviceComposition || getHwComposer().hasDeviceComposition(displayId); - } + mHadClientComposition = + std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) { + auto& displayDevice = tokenDisplayPair.second; + return displayDevice->getCompositionDisplay()->getState().usesClientComposition; + }); + mHadDeviceComposition = + std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) { + auto& displayDevice = tokenDisplayPair.second; + return displayDevice->getCompositionDisplay()->getState().usesDeviceComposition; + }); mVSyncModulator->onRefreshed(mHadClientComposition); @@ -1954,7 +1954,7 @@ void SurfaceFlinger::doDebugFlashRegions(const sp& displayDevice, usleep(mDebugRegion * 1000); } - prepareFrame(displayDevice); + displayDevice->getCompositionDisplay()->prepareFrame(); } void SurfaceFlinger::logLayerStats() { @@ -2043,7 +2043,7 @@ void SurfaceFlinger::postComposition() getBE().mGlCompositionDoneTimeline.updateSignalTimes(); std::shared_ptr glCompositionDoneFenceTime; - if (displayDevice && getHwComposer().hasClientComposition(displayDevice->getId())) { + if (displayDevice && displayDevice->getCompositionDisplay()->getState().usesClientComposition) { glCompositionDoneFenceTime = std::make_shared(displayDevice->getCompositionDisplay() ->getRenderSurface() @@ -2405,19 +2405,6 @@ void SurfaceFlinger::beginFrame(const sp& displayDevice) { } } -void SurfaceFlinger::prepareFrame(const sp& displayDevice) { - auto display = displayDevice->getCompositionDisplay(); - const auto& displayState = display->getState(); - - if (!displayState.isEnabled) { - return; - } - - status_t result = display->getRenderSurface()->prepareFrame(); - ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)", - displayDevice->getDebugName().c_str(), result, strerror(-result)); -} - void SurfaceFlinger::doComposition(const sp& displayDevice, bool repaintEverything) { ATRACE_CALL(); ALOGV("doComposition"); @@ -3354,9 +3341,7 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& displayDevice, const Region bounds(displayState.bounds); const DisplayRenderArea renderArea(displayDevice); const TracedOrdinal hasClientComposition = {"hasClientComposition", - getHwComposer().hasClientComposition( - displayId)}; - + displayState.usesClientComposition}; bool applyColorMatrix = false; renderengine::DisplaySettings clientCompositionDisplay; @@ -3409,7 +3394,7 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& displayDevice, clientCompositionDisplay.maxLuminance = profile->getHdrCapabilities().getDesiredMaxLuminance(); - const bool hasDeviceComposition = getHwComposer().hasDeviceComposition(displayId); + const bool hasDeviceComposition = displayState.usesDeviceComposition; const bool skipClientColorTransform = getHwComposer() .hasDisplayCapability(displayId, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 04e0c8926c..f2bcd36249 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -769,11 +769,6 @@ private: * CompositionInfo */ void beginFrame(const sp& display); - /* prepareFrame - This function will call into the DisplayDevice to prepare a - * frame after CompositionInfo has been programmed. This provides a mechanism - * to prepare the hardware composer - */ - void prepareFrame(const sp& display); void doComposition(const sp& display, bool repainEverything); void doDebugFlashRegions(const sp& display, bool repaintEverything); void logLayerStats(); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 0f21ad86d8..47243a9595 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -296,7 +296,6 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mComposer, setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY)) .Times(1); - EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1); EXPECT_CALL(*test->mComposer, getDisplayRequests(HWC_DISPLAY, _, _, _)).Times(1); EXPECT_CALL(*test->mComposer, acceptDisplayChanges(HWC_DISPLAY)).Times(1); EXPECT_CALL(*test->mComposer, presentDisplay(HWC_DISPLAY, _)).Times(1); @@ -336,11 +335,21 @@ struct BaseDisplayVariant { } static void setupHwcCompositionCallExpectations(CompositionTest* test) { + EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1); + EXPECT_CALL(*test->mDisplaySurface, prepareFrame(compositionengine::DisplaySurface::COMPOSITION_HWC)) .Times(1); } + static void setupHwcClientCompositionCallExpectations(CompositionTest* test) { + EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1); + } + + static void setupHwcForcedClientCompositionCallExpectations(CompositionTest* test) { + EXPECT_CALL(*test->mComposer, validateDisplay(HWC_DISPLAY, _, _)).Times(1); + } + static void setupRECompositionCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mDisplaySurface, prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GLES)) @@ -414,6 +423,8 @@ struct PoweredOffDisplaySetupVariant : public BaseDisplayVariantmRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true)); @@ -981,18 +992,27 @@ struct RECompositionResultVariant : public CompositionResultBaseVariant { template static void setupCallExpectations(CompositionTest* test) { Case::Display::setupNonEmptyFrameCompositionCallExpectations(test); + Case::Display::setupHwcClientCompositionCallExpectations(test); Case::Display::setupRECompositionCallExpectations(test); Case::Display::template setupRELayerCompositionCallExpectations(test); } }; -struct ForcedClientCompositionResultVariant : public RECompositionResultVariant { +struct ForcedClientCompositionResultVariant : public CompositionResultBaseVariant { static void setupLayerState(CompositionTest* test, sp layer) { const auto outputLayer = layer->findOutputLayerForDisplay(test->mDisplay); LOG_FATAL_IF(!outputLayer); outputLayer->editState().forceClientComposition = true; } + template + static void setupCallExpectations(CompositionTest* test) { + Case::Display::setupNonEmptyFrameCompositionCallExpectations(test); + Case::Display::setupHwcForcedClientCompositionCallExpectations(test); + Case::Display::setupRECompositionCallExpectations(test); + Case::Display::template setupRELayerCompositionCallExpectations(test); + } + template static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {} -- GitLab From 35fca9d4b5f10571c0f76e19b9e43c11bb845da2 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Wed, 13 Feb 2019 14:24:11 -0800 Subject: [PATCH 0118/1255] SF: Move postFrameBuffer to CompositionEngine This moves SurfaceFlinger::postFrameBuffer to compositionengine::Output::postFrameBuffer, with some implementation details in compositionengine::Display::presentAndGetFrameFences. Test: atest libsurfaceflinger_unittest libcompositionengine_test Test: atest CtsColorModeTestCases Test: atest CtsDisplayTestCases Test: atest CtsGraphicsTestCases Test: atest CtsUiRenderingTestCases Test: atest CtsViewTestCases Test: atest android.media.cts.EncodeVirtualDisplayWithCompositionTest Bug: 121291683 Change-Id: I8cda7bf26ec4b9e437c91ef951c5030f8d2752e9 --- .../include/compositionengine/Output.h | 16 +++++ .../include/compositionengine/impl/Display.h | 5 +- .../include/compositionengine/impl/Output.h | 2 + .../include/compositionengine/mock/Output.h | 3 + .../CompositionEngine/src/Display.cpp | 29 +++++++- .../CompositionEngine/src/Output.cpp | 59 +++++++++++++++++ .../CompositionEngine/tests/DisplayTest.cpp | 39 +++++++++++ services/surfaceflinger/SurfaceFlinger.cpp | 66 +------------------ services/surfaceflinger/SurfaceFlinger.h | 1 - 9 files changed, 152 insertions(+), 68 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 1525a096f4..ebfda1f702 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -19,8 +19,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -28,6 +30,10 @@ #include "DisplayHardware/DisplayIdentification.h" +namespace HWC2 { +class Layer; +} // namespace HWC2 + namespace android::compositionengine { class DisplayColorProfile; @@ -48,6 +54,12 @@ public: using OutputLayers = std::vector>; using ReleasedLayers = std::vector>; + struct FrameFences { + sp presentFence{Fence::NO_FENCE}; + sp clientTargetAcquireFence{Fence::NO_FENCE}; + std::unordered_map> layerFences; + }; + virtual ~Output(); // Returns true if the output is valid. This is meant to be checked post- @@ -141,10 +153,14 @@ public: // Prepares a frame for display virtual void prepareFrame() = 0; + // Posts the new frame, and sets release fences. + virtual void postFramebuffer() = 0; + protected: virtual void setDisplayColorProfile(std::unique_ptr) = 0; virtual void setRenderSurface(std::unique_ptr) = 0; virtual void chooseCompositionStrategy() = 0; + virtual FrameFences presentAndGetFrameFences() = 0; }; } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index 8a3f8a79e9..795061af28 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -42,6 +42,7 @@ public: void setColorTransform(const mat4&) override; void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override; void chooseCompositionStrategy() override; + compositionengine::Output::FrameFences presentAndGetFrameFences() override; // compositionengine::Display overrides const std::optional& getId() const override; @@ -66,7 +67,7 @@ private: std::optional mId; }; -std::shared_ptr createDisplay( - const compositionengine::CompositionEngine&, compositionengine::DisplayCreationArgs&&); +std::shared_ptr createDisplay(const compositionengine::CompositionEngine&, + compositionengine::DisplayCreationArgs&&); } // 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 503d2fa2c8..b454212e2c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -76,6 +76,7 @@ public: ReleasedLayers takeReleasedLayers() override; void prepareFrame() override; + void postFramebuffer() override; // Testing void setDisplayColorProfileForTest(std::unique_ptr); @@ -84,6 +85,7 @@ public: protected: const CompositionEngine& getCompositionEngine() const; void chooseCompositionStrategy() override; + compositionengine::Output::FrameFences presentAndGetFrameFences() override; void dumpBase(std::string&) const; private: diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index b8679d8021..8aaebc2628 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -75,6 +75,9 @@ public: MOCK_METHOD0(prepareFrame, void()); MOCK_METHOD0(chooseCompositionStrategy, void()); + + MOCK_METHOD0(postFramebuffer, void()); + MOCK_METHOD0(presentAndGetFrameFences, compositionengine::Output::FrameFences()); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 528a8a63cb..68319013d7 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -29,7 +29,7 @@ namespace android::compositionengine::impl { -std::shared_ptr createDisplay( +std::shared_ptr createDisplay( const compositionengine::CompositionEngine& compositionEngine, compositionengine::DisplayCreationArgs&& args) { return std::make_shared(compositionEngine, std::move(args)); @@ -213,4 +213,31 @@ void Display::applyLayerRequestsToLayers(const LayerRequests& layerRequests) { } } +compositionengine::Output::FrameFences Display::presentAndGetFrameFences() { + auto result = impl::Output::presentAndGetFrameFences(); + + if (!mId) { + return result; + } + + auto& hwc = getCompositionEngine().getHwComposer(); + hwc.presentAndGetReleaseFences(*mId); + + result.presentFence = hwc.getPresentFence(*mId); + + // TODO(b/121291683): Change HWComposer call to return entire map + for (const auto& layer : getOutputLayersOrderedByZ()) { + auto hwcLayer = layer->getHwcLayer(); + if (!hwcLayer) { + continue; + } + + result.layerFences.emplace(hwcLayer, hwc.getLayerReleaseFence(*mId, hwcLayer)); + } + + hwc.clearReleaseFences(*mId); + + return result; +} + } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 83195229b2..6d060e404a 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -264,6 +264,57 @@ void Output::prepareFrame() { mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition); } +void Output::postFramebuffer() { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + + if (!getState().isEnabled) { + return; + } + + mRenderSurface->onPresentDisplayCompleted(); + + auto frame = presentAndGetFrameFences(); + + for (auto& layer : getOutputLayersOrderedByZ()) { + // The layer buffer from the previous frame (if any) is released + // by HWC only when the release fence from this frame (if any) is + // signaled. Always get the release fence from HWC first. + sp releaseFence = Fence::NO_FENCE; + + if (auto hwcLayer = layer->getHwcLayer()) { + if (auto f = frame.layerFences.find(hwcLayer); f != frame.layerFences.end()) { + releaseFence = f->second; + } + } + + // If the layer was client composited in the previous frame, we + // need to merge with the previous client target acquire fence. + // Since we do not track that, always merge with the current + // client target acquire fence when it is available, even though + // this is suboptimal. + // TODO(b/121291683): Track previous frame client target acquire fence. + if (mState.usesClientComposition) { + releaseFence = + Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence); + } + + layer->getLayerFE().onLayerDisplayed(releaseFence); + } + + // We've got a list of layers needing fences, that are disjoint with + // getOutputLayersOrderedByZ. The best we can do is to + // supply them with the present fence. + for (auto& weakLayer : mReleasedLayers) { + if (auto layer = weakLayer.promote(); layer != nullptr) { + layer->onLayerDisplayed(frame.presentFence); + } + } + + // Clear out the released layers now that we're done with them. + mReleasedLayers.clear(); +} + void Output::dirtyEntireOutput() { mState.dirtyRegion.set(mState.bounds); } @@ -274,5 +325,13 @@ void Output::chooseCompositionStrategy() { mState.usesDeviceComposition = false; } +compositionengine::Output::FrameFences Output::presentAndGetFrameFences() { + compositionengine::Output::FrameFences result; + if (mState.usesClientComposition) { + result.clientTargetAcquireFence = mRenderSurface->getClientTargetAcquireFence(); + } + return result; +} + } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index d0f79f2d81..e3be0d7a9c 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -463,5 +463,44 @@ TEST_F(DisplayTest, applyLayerRequestsToLayers2) { }); } +/* + * Display::presentAndGetFrameFences() + */ + +TEST_F(DisplayTest, presentAndGetFrameFencesReturnsNoFencesOnNonHwcDisplay) { + auto nonHwcDisplay{ + impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; + + auto result = nonHwcDisplay->presentAndGetFrameFences(); + + ASSERT_TRUE(result.presentFence.get()); + EXPECT_FALSE(result.presentFence->isValid()); + EXPECT_EQ(0u, result.layerFences.size()); +} + +TEST_F(DisplayTest, presentAndGetFrameFencesReturnsPresentAndLayerFences) { + sp presentFence = new Fence(); + sp layer1Fence = new Fence(); + sp layer2Fence = new Fence(); + + 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)) + .WillOnce(Return(layer1Fence)); + EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mHWC2Layer2)) + .WillOnce(Return(layer2Fence)); + EXPECT_CALL(mHwComposer, clearReleaseFences(DEFAULT_DISPLAY_ID)).Times(1); + + auto result = mDisplay.presentAndGetFrameFences(); + + 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]); +} + } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 017c3d2bb6..4a4db4c5a2 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1948,7 +1948,7 @@ void SurfaceFlinger::doDebugFlashRegions(const sp& displayDevice, } } - postFramebuffer(displayDevice); + displayDevice->getCompositionDisplay()->postFramebuffer(); if (mDebugRegion > 1) { usleep(mDebugRegion * 1000); @@ -2422,7 +2422,7 @@ void SurfaceFlinger::doComposition(const sp& displayDevice, bool display->editState().dirtyRegion.clear(); display->getRenderSurface()->flip(); } - postFramebuffer(displayDevice); + displayDevice->getCompositionDisplay()->postFramebuffer(); } void SurfaceFlinger::postFrame() @@ -2437,68 +2437,6 @@ void SurfaceFlinger::postFrame() } } -void SurfaceFlinger::postFramebuffer(const sp& displayDevice) { - ATRACE_CALL(); - ALOGV("postFramebuffer"); - - auto display = displayDevice->getCompositionDisplay(); - const auto& displayState = display->getState(); - const auto displayId = display->getId(); - - if (displayState.isEnabled) { - if (displayId) { - getHwComposer().presentAndGetReleaseFences(*displayId); - } - display->getRenderSurface()->onPresentDisplayCompleted(); - for (auto& layer : display->getOutputLayersOrderedByZ()) { - sp releaseFence = Fence::NO_FENCE; - bool usedClientComposition = true; - - // The layer buffer from the previous frame (if any) is released - // by HWC only when the release fence from this frame (if any) is - // signaled. Always get the release fence from HWC first. - if (layer->getState().hwc) { - const auto& hwcState = *layer->getState().hwc; - releaseFence = - getHwComposer().getLayerReleaseFence(*displayId, hwcState.hwcLayer.get()); - usedClientComposition = - hwcState.hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT; - } - - // If the layer was client composited in the previous frame, we - // need to merge with the previous client target acquire fence. - // Since we do not track that, always merge with the current - // client target acquire fence when it is available, even though - // this is suboptimal. - if (usedClientComposition) { - releaseFence = - Fence::merge("LayerRelease", releaseFence, - display->getRenderSurface()->getClientTargetAcquireFence()); - } - - layer->getLayerFE().onLayerDisplayed(releaseFence); - } - - // We've got a list of layers needing fences, that are disjoint with - // display->getVisibleLayersSortedByZ. The best we can do is to - // supply them with the present fence. - auto releasedLayers = display->takeReleasedLayers(); - if (!releasedLayers.empty()) { - sp presentFence = - displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE; - for (auto& weakLayer : releasedLayers) { - if (auto layer = weakLayer.promote(); layer != nullptr) { - layer->onLayerDisplayed(presentFence); - } - } - } - - if (displayId) { - getHwComposer().clearReleaseFences(*displayId); - } - } -} - void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { ATRACE_CALL(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f2bcd36249..f953234d17 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -780,7 +780,6 @@ private: bool doComposeSurfaces(const sp& display, const Region& debugRegionm, base::unique_fd* readyFence); - void postFramebuffer(const sp& display); void postFrame(); /* ------------------------------------------------------------------------ -- GitLab From c7e17a2e5fea4a8eb4280ac289f447db73734cce Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Tue, 19 Feb 2019 17:47:02 -0800 Subject: [PATCH 0119/1255] SF: Remove unused SurfaceFlinger::getLayerSortedByZForHwcDisplay There were no callers, and it relied on CompositionEngine state being made internal to the new code. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: I896ccc65c13acf3d9ea87c65da388b06f35ac175 --- services/surfaceflinger/SurfaceFlinger.cpp | 13 ------------- services/surfaceflinger/SurfaceFlinger.h | 4 ---- 2 files changed, 17 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4a4db4c5a2..36e69560f2 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4972,19 +4972,6 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co result.append("\n"); } -const Vector>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) { - // Note: mStateLock is held here - for (const auto& [token, display] : mDisplays) { - if (display->getId() == displayId) { - return getDisplayDeviceLocked(token)->getVisibleLayersSortedByZ(); - } - } - - ALOGE("%s: Invalid display %s", __FUNCTION__, to_string(displayId).c_str()); - static const Vector> empty; - return empty; -} - void SurfaceFlinger::updateColorMatrixLocked() { mat4 colorMatrix; if (mGlobalSaturationFactor != 1.0f) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f953234d17..f5ff01e760 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -304,10 +304,6 @@ public: // TODO: this should be made accessible only to MessageQueue void onMessageReceived(int32_t what); - // for debugging only - // TODO: this should be made accessible only to HWComposer - const Vector>& getLayerSortedByZForHwcDisplay(DisplayId displayId); - renderengine::RenderEngine& getRenderEngine() const; bool authenticateSurfaceTextureLocked( -- GitLab From a08194b0086226364d5e045e52ff19028601bbdc Mon Sep 17 00:00:00 2001 From: mamik Date: Thu, 25 Jul 2019 13:07:21 -0700 Subject: [PATCH 0120/1255] Updating ConfigurationDataGet api to include edid data. Bug: 138398637 Test: manual - ran through modified unit test to make sure the edid data was returned on the MTP 845. Change-Id: I171cf90d005a09a9cb6ee1081efee653cce47c4a --- .../include/private/dvr/display_protocol.h | 3 ++- libs/vr/libdvr/include/dvr/dvr_api.h | 2 ++ libs/vr/libvrflinger/display_service.cpp | 18 ++++++++++++++++++ libs/vr/libvrflinger/display_service.h | 4 ++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h index 3786d1d5e9..861dc6c2a0 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h +++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h @@ -191,7 +191,8 @@ struct SurfaceInfo { enum class ConfigFileType : uint32_t { kLensMetrics, kDeviceMetrics, - kDeviceConfiguration + kDeviceConfiguration, + kDeviceEdid }; struct DisplayProtocol { diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h index e383bb2cb3..b7abb99559 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api.h +++ b/libs/vr/libdvr/include/dvr/dvr_api.h @@ -85,6 +85,8 @@ enum { DVR_CONFIGURATION_DATA_DEVICE_METRICS = 1, // Request the per device configuration data file. DVR_CONFIGURATION_DATA_DEVICE_CONFIG = 2, + // Request the edid data for the display. + DVR_CONFIGURATION_DATA_DEVICE_EDID = 3, }; // dvr_display_manager.h diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index 87162c0b5a..8980a92776 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -44,6 +44,18 @@ DisplayService::DisplayService(Hwc2::Composer* hidl, Endpoint::Create(display::DisplayProtocol::kClientPath)) { hardware_composer_.Initialize( hidl, primary_display_id, request_display_callback); + + uint8_t port; + const auto error = hidl->getDisplayIdentificationData( + primary_display_id, &port, &display_identification_data_); + if (error != android::hardware::graphics::composer::V2_1::Error::NONE) { + if (error != + android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) { + ALOGI("DisplayService: identification data error\n"); + } else { + ALOGI("DisplayService: identification data unsupported\n"); + } + } } bool DisplayService::IsInitialized() const { @@ -204,6 +216,12 @@ pdx::Status DisplayService::OnGetConfigurationData( case display::ConfigFileType::kDeviceConfiguration: property_name = kDvrDeviceConfigProperty; break; + case display::ConfigFileType::kDeviceEdid: + if (display_identification_data_.size() == 0) { + return ErrorStatus(ENOENT); + } + return std::string(display_identification_data_.begin(), + display_identification_data_.end()); default: return ErrorStatus(EINVAL); } diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index e0f2eddfea..d45a61fad7 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -18,6 +18,8 @@ #include "epoll_event_dispatcher.h" #include "hardware_composer.h" +#include "DisplayHardware/DisplayIdentification.h" + namespace android { namespace dvr { @@ -117,6 +119,8 @@ class DisplayService : public pdx::ServiceBase { DisplayService(const DisplayService&) = delete; void operator=(const DisplayService&) = delete; + + DisplayIdentificationData display_identification_data_; }; } // namespace dvr -- GitLab From 4e68fbfecc6ab41bfa3d6c06d4e04ff4b098eb00 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 31 Jul 2019 14:00:52 -0700 Subject: [PATCH 0121/1255] Return early in doDispatchCycleFinishedLockedInterruptible Reduce the identation of the entire method by returning early if entry is null. Bug: 70668286 Test: none Change-Id: Ic9239c4f7e3566cd584a57973d9e8ed08d8c0287 --- services/inputflinger/InputDispatcher.cpp | 82 ++++++++++++----------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index fc40eafd08..019815c2c5 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -4237,53 +4237,55 @@ void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntr void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( CommandEntry* commandEntry) { sp connection = commandEntry->connection; - nsecs_t finishTime = commandEntry->eventTime; + const nsecs_t finishTime = commandEntry->eventTime; uint32_t seq = commandEntry->seq; - bool handled = commandEntry->handled; + const bool handled = commandEntry->handled; // Handle post-event policy actions. DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq); - if (dispatchEntry) { - nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime; - if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) { - std::string msg = - StringPrintf("Window '%s' spent %0.1fms processing the last input event: ", - connection->getWindowName().c_str(), eventDuration * 0.000001f); - dispatchEntry->eventEntry->appendDescription(msg); - ALOGI("%s", msg.c_str()); - } - - bool restartEvent; - if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { - KeyEntry* keyEntry = static_cast(dispatchEntry->eventEntry); - restartEvent = afterKeyEventLockedInterruptible(connection, - dispatchEntry, keyEntry, handled); - } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) { - MotionEntry* motionEntry = static_cast(dispatchEntry->eventEntry); - restartEvent = afterMotionEventLockedInterruptible(connection, - dispatchEntry, motionEntry, handled); + if (!dispatchEntry) { + return; + } + + nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime; + if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) { + std::string msg = + StringPrintf("Window '%s' spent %0.1fms processing the last input event: ", + connection->getWindowName().c_str(), eventDuration * 0.000001f); + dispatchEntry->eventEntry->appendDescription(msg); + ALOGI("%s", msg.c_str()); + } + + bool restartEvent; + if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { + KeyEntry* keyEntry = static_cast(dispatchEntry->eventEntry); + restartEvent = + afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled); + } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) { + MotionEntry* motionEntry = static_cast(dispatchEntry->eventEntry); + restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry, + handled); + } else { + restartEvent = false; + } + + // Dequeue the event and start the next cycle. + // Note that because the lock might have been released, it is possible that the + // contents of the wait queue to have been drained, so we need to double-check + // a few things. + if (dispatchEntry == connection->findWaitQueueEntry(seq)) { + connection->waitQueue.dequeue(dispatchEntry); + traceWaitQueueLength(connection); + if (restartEvent && connection->status == Connection::STATUS_NORMAL) { + connection->outboundQueue.enqueueAtHead(dispatchEntry); + traceOutboundQueueLength(connection); } else { - restartEvent = false; - } - - // Dequeue the event and start the next cycle. - // Note that because the lock might have been released, it is possible that the - // contents of the wait queue to have been drained, so we need to double-check - // a few things. - if (dispatchEntry == connection->findWaitQueueEntry(seq)) { - connection->waitQueue.dequeue(dispatchEntry); - traceWaitQueueLength(connection); - if (restartEvent && connection->status == Connection::STATUS_NORMAL) { - connection->outboundQueue.enqueueAtHead(dispatchEntry); - traceOutboundQueueLength(connection); - } else { - releaseDispatchEntry(dispatchEntry); - } + releaseDispatchEntry(dispatchEntry); } - - // Start the next dispatch cycle for this connection. - startDispatchCycleLocked(now(), connection); } + + // Start the next dispatch cycle for this connection. + startDispatchCycleLocked(now(), connection); } bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& connection, -- GitLab From b1b0b011ba0884964219f6d2421f99efa6f9ed42 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Tue, 30 Jul 2019 22:31:41 -0700 Subject: [PATCH 0122/1255] vkjson: correctly handle std::numeric_limits::infinity() Java JSON library can't handle infinity value. So if vkjson reports infinity limit, we need to manually clamp the value within the Java JSON value range. Up-casting float infinity will be equal to double infinity, and we need to make sure the text representation is not going out of range between the cppjson to Java json converison, so we have to clamp to a safe min/max range of double. Bug: 134453786 Test: adb shell cmd gpu vkjson Change-Id: I498fbcdb76ec55d6443ca202af191d6fb12fec12 --- vulkan/vkjson/vkjson.cc | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc index 3da4336069..6204779625 100644 --- a/vulkan/vkjson/vkjson.cc +++ b/vulkan/vkjson/vkjson.cc @@ -21,11 +21,14 @@ #include "vkjson.h" #include -#include #include +#include -#include +#include + +#include #include +#include #include #include #include @@ -33,8 +36,6 @@ #include #include -#include - namespace { inline bool IsIntegral(double value) { @@ -46,6 +47,14 @@ inline bool IsIntegral(double value) { #endif } +// Floating point fields of Vulkan structure use single precision. The string +// output of max double value in c++ will be larger than Java double's infinity +// value. Below fake double max/min values are only to serve the safe json text +// parsing in between C++ and Java, becasue Java json library simply cannot +// handle infinity. +static const double SAFE_DOUBLE_MAX = 0.99 * std::numeric_limits::max(); +static const double SAFE_DOUBLE_MIN = 0.99 * std::numeric_limits::min(); + template struct EnumTraits; template <> struct EnumTraits { static uint32_t min() { return VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE; } @@ -851,7 +860,8 @@ Json::Value ToJsonValue(const T& value); template > inline Json::Value ToJsonValue(const T& value) { - return Json::Value(static_cast(value)); + return Json::Value( + std::clamp(static_cast(value), SAFE_DOUBLE_MIN, SAFE_DOUBLE_MAX)); } inline Json::Value ToJsonValue(const uint64_t& value) { -- GitLab From 362720724944a779fa754709602ec67175aeace2 Mon Sep 17 00:00:00 2001 From: Fedor Kudasov Date: Thu, 4 Jul 2019 12:53:57 +0100 Subject: [PATCH 0123/1255] Enable surface for host Bug: 117921091 Test: all tests should pass Change-Id: I222ddcfda80c96726d96158173fcc1015abf7d36 --- libs/ui/Android.bp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 2cc6857744..2bbb0ee50a 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -187,3 +187,11 @@ subdirs = [ "tests", "tools", ] + +filegroup { + name: "libui_host_common", + srcs: [ + "Rect.cpp", + "PixelFormat.cpp" + ], +} -- GitLab From 402a839ef5e2fdecfd9a0fc75e6250d374bfc83e Mon Sep 17 00:00:00 2001 From: Nandana Dutt Date: Fri, 14 Jun 2019 14:25:13 +0100 Subject: [PATCH 0124/1255] Remove old dumpstate aidl methods In Q we added new aidl methods for dumpstate to communicate with SystemServer. The old methods can be removed now. This change is functionally equivalent to before except for how progress is reported. Dumpstate loads previous run stats and calculates expected run time. If the current run exceeds that time, it used to let the client know via onMaxProgressUpdated(). Given the API world, this CL simplifies this model so that dumpstate conveys just one piece of information, i.e. final progress precentage, rather than current, previous_max, and new_max. Test: atest dumpstate_test Test: bugreport from power button works as expected BUG: 128980174 Change-Id: Id9103649b0f7c8e6ea0b79583ea04825cb5b455f --- cmds/dumpstate/Android.bp | 1 - cmds/dumpstate/DumpstateSectionReporter.cpp | 42 ----------- cmds/dumpstate/DumpstateSectionReporter.h | 65 ----------------- cmds/dumpstate/DumpstateService.cpp | 3 +- .../binder/android/os/IDumpstateListener.aidl | 17 ----- cmds/dumpstate/dumpstate.cpp | 25 ++----- cmds/dumpstate/dumpstate.h | 8 +-- cmds/dumpstate/tests/dumpstate_smoke_test.cpp | 21 ------ cmds/dumpstate/tests/dumpstate_test.cpp | 72 ++++--------------- 9 files changed, 22 insertions(+), 232 deletions(-) delete mode 100644 cmds/dumpstate/DumpstateSectionReporter.cpp delete mode 100644 cmds/dumpstate/DumpstateSectionReporter.h diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp index 8d383f501a..93bbe902c0 100644 --- a/cmds/dumpstate/Android.bp +++ b/cmds/dumpstate/Android.bp @@ -93,7 +93,6 @@ cc_defaults { "libutils", ], srcs: [ - "DumpstateSectionReporter.cpp", "DumpstateService.cpp", ], static_libs: [ diff --git a/cmds/dumpstate/DumpstateSectionReporter.cpp b/cmds/dumpstate/DumpstateSectionReporter.cpp deleted file mode 100644 index f814bde26d..0000000000 --- a/cmds/dumpstate/DumpstateSectionReporter.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "dumpstate" - -#include "DumpstateSectionReporter.h" - -namespace android { -namespace os { -namespace dumpstate { - -DumpstateSectionReporter::DumpstateSectionReporter(const std::string& title, - sp listener, - bool sendReport) - : title_(title), listener_(listener), sendReport_(sendReport), status_(OK), size_(-1) { - started_ = std::chrono::steady_clock::now(); -} - -DumpstateSectionReporter::~DumpstateSectionReporter() { - if ((listener_ != nullptr) && (sendReport_)) { - auto elapsed = std::chrono::duration_cast( - std::chrono::steady_clock::now() - started_); - listener_->onSectionComplete(title_, status_, size_, (int32_t)elapsed.count()); - } -} - -} // namespace dumpstate -} // namespace os -} // namespace android diff --git a/cmds/dumpstate/DumpstateSectionReporter.h b/cmds/dumpstate/DumpstateSectionReporter.h deleted file mode 100644 index e971de84c5..0000000000 --- a/cmds/dumpstate/DumpstateSectionReporter.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_OS_DUMPSTATESECTIONREPORTER_H_ -#define ANDROID_OS_DUMPSTATESECTIONREPORTER_H_ - -#include -#include - -namespace android { -namespace os { -namespace dumpstate { - - -/* - * Helper class used to report per section details to a listener. - * - * Typical usage: - * - * DumpstateSectionReporter sectionReporter(title, listener, sendReport); - * sectionReporter.setSize(5000); - * - */ -class DumpstateSectionReporter { - public: - DumpstateSectionReporter(const std::string& title, sp listener, - bool sendReport); - - ~DumpstateSectionReporter(); - - void setStatus(status_t status) { - status_ = status; - } - - void setSize(int size) { - size_ = size; - } - - private: - std::string title_; - android::sp listener_; - bool sendReport_; - status_t status_; - int size_; - std::chrono::time_point started_; -}; - -} // namespace dumpstate -} // namespace os -} // namespace android - -#endif // ANDROID_OS_DUMPSTATESECTIONREPORTER_H_ diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp index 37ba4f906e..f98df99534 100644 --- a/cmds/dumpstate/DumpstateService.cpp +++ b/cmds/dumpstate/DumpstateService.cpp @@ -200,8 +200,7 @@ status_t DumpstateService::dump(int fd, const Vector&) { dprintf(fd, "id: %d\n", ds_->id_); dprintf(fd, "pid: %d\n", ds_->pid_); dprintf(fd, "update_progress: %s\n", ds_->options_->do_progress_updates ? "true" : "false"); - dprintf(fd, "update_progress_threshold: %d\n", ds_->update_progress_threshold_); - dprintf(fd, "last_updated_progress: %d\n", ds_->last_updated_progress_); + dprintf(fd, "last_percent_progress: %d\n", ds_->last_reported_percent_progress_); dprintf(fd, "progress:\n"); ds_->progress_->Dump(fd, " "); dprintf(fd, "args: %s\n", ds_->options_->args.c_str()); diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl index ea1e467dca..e486460753 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl @@ -61,21 +61,4 @@ interface IDumpstateListener { * Called when taking bugreport finishes successfully. */ void onFinished(); - - // TODO(b/111441001): Remove old methods when not used anymore. - void onProgressUpdated(int progress); - void onMaxProgressUpdated(int maxProgress); - - /** - * Called after every section is complete. - * - * @param name section name - * @param status values from status_t - * {@code OK} section completed successfully - * {@code TIMEOUT} dump timed out - * {@code != OK} error - * @param size size in bytes, may be invalid if status != OK - * @param durationMs duration in ms - */ - void onSectionComplete(@utf8InCpp String name, int status, int size, int durationMs); } diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index fe55fe7d4b..6b2e3b70cd 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -80,7 +80,6 @@ #include #include #include "DumpstateInternal.h" -#include "DumpstateSectionReporter.h" #include "DumpstateService.h" #include "dumpstate.h" @@ -105,7 +104,6 @@ using android::base::StringPrintf; using android::os::IDumpstateListener; using android::os::dumpstate::CommandOptions; using android::os::dumpstate::DumpFileToFd; -using android::os::dumpstate::DumpstateSectionReporter; using android::os::dumpstate::PropertiesHelper; // Keep in sync with @@ -1047,7 +1045,6 @@ static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, i RETURN_IF_USER_DENIED_CONSENT(); std::string path(title); path.append(" - ").append(String8(service).c_str()); - DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_); size_t bytes_written = 0; status_t status = dumpsys.startDumpThread(service, args); if (status == OK) { @@ -1055,12 +1052,10 @@ static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, i std::chrono::duration elapsed_seconds; status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout, /* as_proto = */ false, elapsed_seconds, bytes_written); - section_reporter.setSize(bytes_written); dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds); bool dump_complete = (status == OK); dumpsys.stopDumpThread(dump_complete); } - section_reporter.setStatus(status); auto elapsed_duration = std::chrono::duration_cast( std::chrono::steady_clock::now() - start); @@ -1123,7 +1118,6 @@ static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priori path.append("_HIGH"); } path.append(kProtoExt); - DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_); status_t status = dumpsys.startDumpThread(service, args); if (status == OK) { status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout); @@ -1132,8 +1126,6 @@ static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priori } ZipWriter::FileEntry file_entry; ds.zip_writer_->GetLastEntry(&file_entry); - section_reporter.setSize(file_entry.compressed_size); - section_reporter.setStatus(status); auto elapsed_duration = std::chrono::duration_cast( std::chrono::steady_clock::now() - start); @@ -2813,6 +2805,7 @@ int run_main(int argc, char* argv[]) { Dumpstate::Dumpstate(const std::string& version) : pid_(getpid()), options_(new Dumpstate::DumpOptions()), + last_reported_percent_progress_(0), version_(version), now_(time(nullptr)) { } @@ -3575,31 +3568,25 @@ void Dumpstate::UpdateProgress(int32_t delta_sec) { } // Always update progess so stats can be tuned... - bool max_changed = progress_->Inc(delta_sec); + progress_->Inc(delta_sec); // ...but only notifiy listeners when necessary. if (!options_->do_progress_updates) return; int progress = progress_->Get(); int max = progress_->GetMax(); + int percent = 100 * progress / max; - // adjusts max on the fly - if (max_changed && listener_ != nullptr) { - listener_->onMaxProgressUpdated(max); - } - - int32_t last_update_delta = progress - last_updated_progress_; - if (last_updated_progress_ > 0 && last_update_delta < update_progress_threshold_) { + if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) { return; } - last_updated_progress_ = progress; + last_reported_percent_progress_ = percent; if (control_socket_fd_ >= 0) { dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max); fsync(control_socket_fd_); } - int percent = 100 * progress / max; if (listener_ != nullptr) { if (percent % 5 == 0) { // We don't want to spam logcat, so only log multiples of 5. @@ -3611,8 +3598,6 @@ void Dumpstate::UpdateProgress(int32_t delta_sec) { fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max, percent); } - // TODO(b/111441001): Remove in favor of onProgress - listener_->onProgressUpdated(progress); listener_->onProgress(percent); } diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index fe330df30a..77b5e8a9f9 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -405,12 +405,8 @@ class Dumpstate { // Runtime options. std::unique_ptr options_; - // How frequently the progess should be updated;the listener will only be notificated when the - // delta from the previous update is more than the threshold. - int32_t update_progress_threshold_ = 100; - - // Last progress that triggered a listener updated - int32_t last_updated_progress_; + // Last progress that was sent to the listener [0-100]. + int last_reported_percent_progress_ = 0; // Whether it should take an screenshot earlier in the process. bool do_early_screenshot_ = false; diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp index f7acaf1b9b..181046a7a7 100644 --- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp @@ -167,26 +167,6 @@ class DumpstateListener : public BnDumpstateListener { return binder::Status::ok(); } - binder::Status onProgressUpdated(int32_t progress) override { - dprintf(out_fd_, "\rIn progress %d/%d", progress, max_progress_); - return binder::Status::ok(); - } - - binder::Status onMaxProgressUpdated(int32_t max_progress) override { - std::lock_guard lock(lock_); - max_progress_ = max_progress; - return binder::Status::ok(); - } - - binder::Status onSectionComplete(const ::std::string& name, int32_t, int32_t size_bytes, - int32_t) override { - std::lock_guard lock(lock_); - if (sections_.get() != nullptr) { - sections_->push_back({name, size_bytes}); - } - return binder::Status::ok(); - } - bool getIsFinished() { std::lock_guard lock(lock_); return is_finished_; @@ -199,7 +179,6 @@ class DumpstateListener : public BnDumpstateListener { private: int out_fd_; - int max_progress_ = 5000; int error_code_ = -1; bool is_finished_ = false; std::shared_ptr> sections_; diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 4e6b084ff6..cff1d439d9 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -62,10 +62,6 @@ class DumpstateListenerMock : public IDumpstateListener { MOCK_METHOD1(onProgress, binder::Status(int32_t progress)); MOCK_METHOD1(onError, binder::Status(int32_t error_code)); MOCK_METHOD0(onFinished, binder::Status()); - MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress)); - MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress)); - MOCK_METHOD4(onSectionComplete, binder::Status(const ::std::string& name, int32_t status, - int32_t size, int32_t durationMs)); protected: MOCK_METHOD0(onAsBinder, IBinder*()); @@ -590,7 +586,6 @@ class DumpstateTest : public DumpstateBaseTest { SetDryRun(false); SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)")); ds.progress_.reset(new Progress()); - ds.update_progress_threshold_ = 0; ds.options_.reset(new Dumpstate::DumpOptions()); } @@ -615,10 +610,9 @@ class DumpstateTest : public DumpstateBaseTest { return status; } - void SetProgress(long progress, long initial_max, long threshold = 0) { + void SetProgress(long progress, long initial_max) { + ds.last_reported_percent_progress_ = 0; ds.options_->do_progress_updates = true; - ds.update_progress_threshold_ = threshold; - ds.last_updated_progress_ = 0; ds.progress_.reset(new Progress(initial_max, progress, 1.2)); } @@ -796,73 +790,36 @@ TEST_F(DumpstateTest, RunCommandProgress) { ds.listener_name_ = "FoxMulder"; SetProgress(0, 30); - EXPECT_CALL(*listener, onProgressUpdated(20)); EXPECT_CALL(*listener, onProgress(66)); // 20/30 % EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build())); std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30); EXPECT_THAT(out, StrEq("stdout\n")); EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); - EXPECT_CALL(*listener, onProgressUpdated(30)); - EXPECT_CALL(*listener, onProgress(100)); // 35/35 % - EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Build())); - progress_message = GetProgressMessage(ds.listener_name_, 30, 30); - EXPECT_THAT(out, StrEq("stdout\n")); - EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); - - // Run a command that will increase maximum timeout. - EXPECT_CALL(*listener, onProgressUpdated(31)); - EXPECT_CALL(*listener, onMaxProgressUpdated(37)); - EXPECT_CALL(*listener, onProgress(83)); // 31/37 % - EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build())); - progress_message = GetProgressMessage(ds.listener_name_, 31, 37, 30); // 20% increase + EXPECT_CALL(*listener, onProgress(80)); // 24/30 % + EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build())); + progress_message = GetProgressMessage(ds.listener_name_, 24, 30); EXPECT_THAT(out, StrEq("stdout\n")); EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); // Make sure command ran while in dry_run is counted. SetDryRun(true); - EXPECT_CALL(*listener, onProgressUpdated(35)); - EXPECT_CALL(*listener, onProgress(94)); // 35/37 % - EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build())); - progress_message = GetProgressMessage(ds.listener_name_, 35, 37); + EXPECT_CALL(*listener, onProgress(90)); // 27/30 % + EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build())); + progress_message = GetProgressMessage(ds.listener_name_, 27, 30); EXPECT_THAT(out, IsEmpty()); EXPECT_THAT(err, StrEq(progress_message)); - ds.listener_.clear(); -} - -TEST_F(DumpstateTest, RunCommandProgressIgnoreThreshold) { - sp listener(new DumpstateListenerMock()); - ds.listener_ = listener; - ds.listener_name_ = "FoxMulder"; - SetProgress(0, 8, 5); // 8 max, 5 threshold - - // First update should always be sent. - EXPECT_CALL(*listener, onProgressUpdated(1)); - EXPECT_CALL(*listener, onProgress(12)); // 1/12 % - EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build())); - std::string progress_message = GetProgressMessage(ds.listener_name_, 1, 8); + SetDryRun(false); + EXPECT_CALL(*listener, onProgress(96)); // 29/30 % + EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(2).Build())); + progress_message = GetProgressMessage(ds.listener_name_, 29, 30); EXPECT_THAT(out, StrEq("stdout\n")); EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); - // Fourth update should be ignored because it's between the threshold (5 -1 = 4 < 5). - EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build())); - EXPECT_THAT(out, StrEq("stdout\n")); - EXPECT_THAT(err, StrEq("stderr\n")); - - // Third update should be sent because it reaches threshold (6 - 1 = 5). - EXPECT_CALL(*listener, onProgressUpdated(6)); - EXPECT_CALL(*listener, onProgress(75)); // 6/8 % + EXPECT_CALL(*listener, onProgress(100)); // 30/30 % EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build())); - progress_message = GetProgressMessage(ds.listener_name_, 6, 8); - EXPECT_THAT(out, StrEq("stdout\n")); - EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); - - // Fourth update should be ignored because it's between the threshold (9 - 6 = 3 < 5). - // But max update should be sent. - EXPECT_CALL(*listener, onMaxProgressUpdated(10)); // 9 * 120% = 10.8 = 10 - EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build())); - progress_message = GetProgressMessage(ds.listener_name_, 9, 10, 8, false); + progress_message = GetProgressMessage(ds.listener_name_, 30, 30); EXPECT_THAT(out, StrEq("stdout\n")); EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); @@ -1090,7 +1047,6 @@ TEST_F(DumpstateTest, DumpFileUpdateProgress) { ds.listener_name_ = "FoxMulder"; SetProgress(0, 30); - EXPECT_CALL(*listener, onProgressUpdated(5)); EXPECT_CALL(*listener, onProgress(16)); // 5/30 % EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt")); -- GitLab From d0a92a0dd469f59029f60cc67352564fe5f84e1f Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Tue, 19 Feb 2019 17:47:26 -0800 Subject: [PATCH 0125/1255] SF: Move beginFrame to CompositionEngine Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: I80d963f1befd88c52e17aa9ed5989d28f5dd0c13 --- .../include/compositionengine/Output.h | 3 ++ .../include/compositionengine/impl/Output.h | 1 + .../include/compositionengine/mock/Output.h | 1 + .../CompositionEngine/src/Output.cpp | 28 ++++++++++++ services/surfaceflinger/SurfaceFlinger.cpp | 43 +++---------------- services/surfaceflinger/SurfaceFlinger.h | 6 --- 6 files changed, 39 insertions(+), 43 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index ebfda1f702..4dfcfa4593 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -150,6 +150,9 @@ public: // Takes (moves) the set of layers being released this frame. virtual ReleasedLayers takeReleasedLayers() = 0; + // Signals that a frame is beginning on the output + virtual void beginFrame() = 0; + // Prepares a frame for display virtual void prepareFrame() = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index b454212e2c..5f4a76440c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -75,6 +75,7 @@ public: void setReleasedLayers(ReleasedLayers&&) override; ReleasedLayers takeReleasedLayers() override; + void beginFrame() override; void prepareFrame() override; void postFramebuffer() override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 8aaebc2628..d494413af5 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -73,6 +73,7 @@ public: MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&)); MOCK_METHOD0(takeReleasedLayers, ReleasedLayers()); + MOCK_METHOD0(beginFrame, void()); MOCK_METHOD0(prepareFrame, void()); MOCK_METHOD0(chooseCompositionStrategy, void()); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 6d060e404a..b411e0a04a 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -251,6 +251,34 @@ Output::ReleasedLayers Output::takeReleasedLayers() { return std::move(mReleasedLayers); } +void Output::beginFrame() { + const bool dirty = !getDirtyRegion(false).isEmpty(); + const bool empty = mOutputLayersOrderedByZ.empty(); + const bool wasEmpty = !mState.lastCompositionHadVisibleLayers; + + // If nothing has changed (!dirty), don't recompose. + // If something changed, but we don't currently have any visible layers, + // and didn't when we last did a composition, then skip it this time. + // The second rule does two things: + // - When all layers are removed from a display, we'll emit one black + // frame, then nothing more until we get new layers. + // - When a display is created with a private layer stack, we won't + // emit any black frames until a layer is added to the layer stack. + const bool mustRecompose = dirty && !(empty && wasEmpty); + + const char flagPrefix[] = {'-', '+'}; + static_cast(flagPrefix); + ALOGV_IF("%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", __FUNCTION__, + mustRecompose ? "doing" : "skipping", getName().c_str(), flagPrefix[dirty], + flagPrefix[empty], flagPrefix[wasEmpty]); + + mRenderSurface->beginFrame(mustRecompose); + + if (mustRecompose) { + mState.lastCompositionHadVisibleLayers = !empty; + } +} + void Output::prepareFrame() { ATRACE_CALL(); ALOGV(__FUNCTION__); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index acfd534018..1aec0c5389 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1790,11 +1790,12 @@ void SurfaceFlinger::handleMessageRefresh() { mCompositionEngine->preComposition(refreshArgs); rebuildLayerStacks(); calculateWorkingSet(); - for (const auto& [token, display] : mDisplays) { - beginFrame(display); - display->getCompositionDisplay()->prepareFrame(); - doDebugFlashRegions(display, repaintEverything); - doComposition(display, repaintEverything); + for (const auto& [token, displayDevice] : mDisplays) { + auto display = displayDevice->getCompositionDisplay(); + display->beginFrame(); + display->prepareFrame(); + doDebugFlashRegions(displayDevice, repaintEverything); + doComposition(displayDevice, repaintEverything); } logLayerStats(); @@ -2373,38 +2374,6 @@ void SurfaceFlinger::pickColorMode(const sp& display, ColorMode* profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent); } -void SurfaceFlinger::beginFrame(const sp& displayDevice) { - auto display = displayDevice->getCompositionDisplay(); - const auto& displayState = display->getState(); - - bool dirty = !display->getDirtyRegion(false).isEmpty(); - bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0; - bool wasEmpty = !displayState.lastCompositionHadVisibleLayers; - - // If nothing has changed (!dirty), don't recompose. - // If something changed, but we don't currently have any visible layers, - // and didn't when we last did a composition, then skip it this time. - // The second rule does two things: - // - When all layers are removed from a display, we'll emit one black - // frame, then nothing more until we get new layers. - // - When a display is created with a private layer stack, we won't - // emit any black frames until a layer is added to the layer stack. - bool mustRecompose = dirty && !(empty && wasEmpty); - - const char flagPrefix[] = {'-', '+'}; - static_cast(flagPrefix); - ALOGV_IF(displayDevice->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", - __FUNCTION__, mustRecompose ? "doing" : "skipping", - displayDevice->getDebugName().c_str(), flagPrefix[dirty], flagPrefix[empty], - flagPrefix[wasEmpty]); - - display->getRenderSurface()->beginFrame(mustRecompose); - - if (mustRecompose) { - display->editState().lastCompositionHadVisibleLayers = !empty; - } -} - void SurfaceFlinger::doComposition(const sp& displayDevice, bool repaintEverything) { ATRACE_CALL(); ALOGV("doComposition"); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index af216037d4..3974a8cf08 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -760,12 +760,6 @@ private: ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const; void calculateWorkingSet(); - /* - * beginFrame - This function handles any pre-frame processing that needs to be - * prior to any CompositionInfo handling and is not dependent on data in - * CompositionInfo - */ - void beginFrame(const sp& display); void doComposition(const sp& display, bool repainEverything); void doDebugFlashRegions(const sp& display, bool repaintEverything); void logLayerStats(); -- GitLab From f16688fcebb22193b555e24c329155f6f0a2f372 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Tue, 19 Feb 2019 17:47:57 -0800 Subject: [PATCH 0126/1255] SF: Introduce LayerFE::prepareClientComposition Renames Layer::prepareClientLayer, and alters it to not take a RenderArea. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: I6da6005c2e34e6e44692043cdc7adf9c4aa57cf5 --- services/surfaceflinger/BufferLayer.cpp | 42 +++++++------- services/surfaceflinger/BufferLayer.h | 17 +++--- services/surfaceflinger/ColorLayer.cpp | 18 +++--- services/surfaceflinger/ColorLayer.h | 13 ++--- .../include/compositionengine/LayerFE.h | 31 ++++++++++ .../include/compositionengine/mock/LayerFE.h | 3 + services/surfaceflinger/ContainerLayer.cpp | 5 -- services/surfaceflinger/ContainerLayer.h | 8 --- services/surfaceflinger/Layer.cpp | 57 +++++++------------ services/surfaceflinger/Layer.h | 21 ++----- services/surfaceflinger/SurfaceFlinger.cpp | 56 ++++++++++++------ 11 files changed, 141 insertions(+), 130 deletions(-) diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 59ea9afa97..87bec11609 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -132,13 +132,15 @@ static constexpr mat4 inverseOrientation(uint32_t transform) { return inverse(tr); } -bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip, - bool useIdentityTransform, Region& clearRegion, - const bool supportProtectedContent, - renderengine::LayerSettings& layer) { +std::optional BufferLayer::prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { ATRACE_CALL(); - Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, - supportProtectedContent, layer); + + auto result = Layer::prepareClientComposition(targetSettings); + if (!result) { + return result; + } + if (CC_UNLIKELY(mActiveBuffer == 0)) { // the texture has not been created yet, this Layer has // in fact never been drawn into. This happens frequently with @@ -159,15 +161,16 @@ bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& under.orSelf(layer->visibleRegion); }); // if not everything below us is covered, we plug the holes! - Region holes(clip.subtract(under)); + Region holes(targetSettings.clip.subtract(under)); if (!holes.isEmpty()) { - clearRegion.orSelf(holes); + targetSettings.clearRegion.orSelf(holes); } - return false; + return std::nullopt; } - bool blackOutLayer = - (isProtected() && !supportProtectedContent) || (isSecure() && !renderArea.isSecure()); + bool blackOutLayer = (isProtected() && !targetSettings.supportProtectedContent) || + (isSecure() && !targetSettings.isSecure); const State& s(getDrawingState()); + auto& layer = *result; if (!blackOutLayer) { layer.source.buffer.buffer = mActiveBuffer; layer.source.buffer.isOpaque = isOpaque(s); @@ -176,8 +179,7 @@ bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha(); layer.source.buffer.isY410BT2020 = isHdrY410(); // TODO: we could be more subtle with isFixedSize() - const bool useFiltering = needsFiltering(renderArea.getDisplayDevice()) || - renderArea.needsFiltering() || isFixedSize(); + const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize(); // Query the texture matrix given our current filtering mode. float textureMatrix[16]; @@ -244,7 +246,7 @@ bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& layer.alpha = 1.0; } - return true; + return result; } bool BufferLayer::isHdrY410() const { @@ -572,21 +574,23 @@ bool BufferLayer::getOpacityForFormat(uint32_t format) { } bool BufferLayer::needsFiltering(const sp& displayDevice) const { - // If we are not capturing based on the state of a known display device, we - // only return mNeedsFiltering + // If we are not capturing based on the state of a known display device, + // just return false. if (displayDevice == nullptr) { - return mNeedsFiltering; + return false; } const auto outputLayer = findOutputLayerForDisplay(displayDevice); if (outputLayer == nullptr) { - return mNeedsFiltering; + return false; } + // We need filtering if the sourceCrop rectangle size does not match the + // displayframe rectangle size (not a 1:1 render) const auto& compositionState = outputLayer->getState(); const auto displayFrame = compositionState.displayFrame; const auto sourceCrop = compositionState.sourceCrop; - return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() || + return sourceCrop.getHeight() != displayFrame.getHeight() || sourceCrop.getWidth() != displayFrame.getWidth(); } diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index bb0205de3e..c86acf08f8 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -82,7 +82,6 @@ public: bool isHdrY410() const override; - bool onPreComposition(nsecs_t refreshStartTime) override; bool onPostComposition(const std::optional& displayId, const std::shared_ptr& glDoneFence, const std::shared_ptr& presentFence, @@ -146,7 +145,13 @@ private: virtual status_t updateFrameNumber(nsecs_t latchTime) = 0; protected: - void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const override; + /* + * compositionengine::LayerFE overrides + */ + bool onPreComposition(nsecs_t) override; + void latchPerFrameState(compositionengine::LayerFECompositionState&) const override; + std::optional prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings&) override; // Loads the corresponding system property once per process static bool latchUnsignaledBuffers(); @@ -163,15 +168,9 @@ protected: bool mRefreshPending{false}; - // prepareClientLayer - constructs a RenderEngine layer for GPU composition. - bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, - bool useIdentityTransform, Region& clearRegion, - const bool supportProtectedContent, - renderengine::LayerSettings& layer) override; - private: // Returns true if this layer requires filtering - bool needsFiltering(const sp& displayDevice) const; + bool needsFiltering(const sp& displayDevice) const override; uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const; diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp index f15957adf9..b65d351263 100644 --- a/services/surfaceflinger/ColorLayer.cpp +++ b/services/surfaceflinger/ColorLayer.cpp @@ -50,16 +50,14 @@ ColorLayer::ColorLayer(const LayerCreationArgs& args) ColorLayer::~ColorLayer() = default; -bool ColorLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip, - bool useIdentityTransform, Region& clearRegion, - const bool supportProtectedContent, - renderengine::LayerSettings& layer) { - Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, - supportProtectedContent, layer); - half4 color(getColor()); - half3 solidColor(color.r, color.g, color.b); - layer.source.solidColor = solidColor; - return true; +std::optional ColorLayer::prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { + auto result = Layer::prepareClientComposition(targetSettings); + if (!result) { + return result; + } + result->source.solidColor = getColor().rgb; + return result; } bool ColorLayer::isVisible() const { diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h index 2483ff0bfb..015b939457 100644 --- a/services/surfaceflinger/ColorLayer.h +++ b/services/surfaceflinger/ColorLayer.h @@ -39,16 +39,13 @@ public: void commitTransaction(const State& stateToCommit) override; - bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; } - protected: - virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, - bool useIdentityTransform, Region& clearRegion, - const bool supportProtectedContent, - renderengine::LayerSettings& layer); - -private: + /* + * compositionengine::LayerFE overrides + */ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override; + std::optional prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings&) override; std::shared_ptr mCompositionLayer; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 1f2cae9c2b..94fab1fdf6 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -16,6 +16,9 @@ #pragma once +#include + +#include #include #include @@ -40,6 +43,34 @@ public: // geometry state can be skipped. virtual void latchCompositionState(LayerFECompositionState&, bool includeGeometry) const = 0; + struct ClientCompositionTargetSettings { + // The clip region, or visible region that is being rendered to + const Region& clip; + + // If true, the layer should use an identity transform for its position + // transform. Used only by the captureScreen API call. + const bool useIdentityTransform; + + // If set to true, the layer should enable filtering when rendering. + const bool needsFiltering; + + // If set to true, the buffer is being sent to a destination that is + // expected to treat the buffer contents as secure. + const bool isSecure; + + // If set to true, the target buffer has protected content support. + const bool supportProtectedContent; + + // Modified by each call to prepareClientComposition to indicate the + // region of the target buffer that should be cleared. + Region& clearRegion; + }; + + // Returns the LayerSettings to pass to RenderEngine::drawLayers, or + // nullopt_t if the layer does not render + virtual std::optional prepareClientComposition( + ClientCompositionTargetSettings&) = 0; + // Called after the layer is displayed to update the presentation fence virtual void onLayerDisplayed(const sp&) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index 952f702e1c..48c2dbf3d6 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -33,6 +33,9 @@ public: MOCK_METHOD1(onPreComposition, bool(nsecs_t)); MOCK_CONST_METHOD2(latchCompositionState, void(LayerFECompositionState&, bool)); + MOCK_METHOD1(prepareClientComposition, + std::optional( + compositionengine::LayerFE::ClientCompositionTargetSettings&)); MOCK_METHOD1(onLayerDisplayed, void(const sp&)); MOCK_CONST_METHOD0(getDebugName, const char*()); diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp index 3a5f3faa20..d40a38c811 100644 --- a/services/surfaceflinger/ContainerLayer.cpp +++ b/services/surfaceflinger/ContainerLayer.cpp @@ -26,11 +26,6 @@ ContainerLayer::ContainerLayer(const LayerCreationArgs& args) : Layer(args) {} ContainerLayer::~ContainerLayer() = default; -bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&, const bool, - renderengine::LayerSettings&) { - return false; -} - bool ContainerLayer::isVisible() const { return false; } diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h index 57267c70c8..a1607ffabb 100644 --- a/services/surfaceflinger/ContainerLayer.h +++ b/services/surfaceflinger/ContainerLayer.h @@ -34,14 +34,6 @@ public: bool canReceiveInput() const override; bool isCreatedFromMainThread() const override { return true; } - - bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; } - -protected: - bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, - bool useIdentityTransform, Region& clearRegion, - const bool supportProtectedContent, - renderengine::LayerSettings& layer) override; }; } // namespace android diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 8150ca7dfc..a2eeea545b 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -458,6 +458,10 @@ void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compo } } +bool Layer::onPreComposition(nsecs_t) { + return false; +} + void Layer::latchCompositionState(compositionengine::LayerFECompositionState& compositionState, bool includeGeometry) const { if (includeGeometry) { @@ -507,54 +511,33 @@ void Layer::updateCursorPosition(const sp& display) { // drawing... // --------------------------------------------------------------------------- -bool Layer::prepareClientLayer(const RenderArea& renderArea, const Region& clip, - Region& clearRegion, const bool supportProtectedContent, - renderengine::LayerSettings& layer) { - return prepareClientLayer(renderArea, clip, false, clearRegion, supportProtectedContent, layer); -} - -bool Layer::prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform, - Region& clearRegion, const bool supportProtectedContent, - renderengine::LayerSettings& layer) { - return prepareClientLayer(renderArea, Region(renderArea.getBounds()), useIdentityTransform, - clearRegion, supportProtectedContent, layer); -} +std::optional Layer::prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { + if (!getCompositionLayer()) { + return {}; + } -bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/, - bool useIdentityTransform, Region& /*clearRegion*/, - const bool /*supportProtectedContent*/, - renderengine::LayerSettings& layer) { FloatRect bounds = getBounds(); half alpha = getAlpha(); - layer.geometry.boundaries = bounds; - if (useIdentityTransform) { - layer.geometry.positionTransform = mat4(); + renderengine::LayerSettings layerSettings; + layerSettings.geometry.boundaries = bounds; + if (targetSettings.useIdentityTransform) { + layerSettings.geometry.positionTransform = mat4(); } else { - const ui::Transform transform = getTransform(); - mat4 m; - m[0][0] = transform[0][0]; - m[0][1] = transform[0][1]; - m[0][3] = transform[0][2]; - m[1][0] = transform[1][0]; - m[1][1] = transform[1][1]; - m[1][3] = transform[1][2]; - m[3][0] = transform[2][0]; - m[3][1] = transform[2][1]; - m[3][3] = transform[2][2]; - layer.geometry.positionTransform = m; + layerSettings.geometry.positionTransform = getTransform().asMatrix4(); } if (hasColorTransform()) { - layer.colorTransform = getColorTransform(); + layerSettings.colorTransform = getColorTransform(); } const auto roundedCornerState = getRoundedCornerState(); - layer.geometry.roundedCornersRadius = roundedCornerState.radius; - layer.geometry.roundedCornersCrop = roundedCornerState.cropRect; + layerSettings.geometry.roundedCornersRadius = roundedCornerState.radius; + layerSettings.geometry.roundedCornersCrop = roundedCornerState.cropRect; - layer.alpha = alpha; - layer.sourceDataspace = mCurrentDataSpace; - return true; + layerSettings.alpha = alpha; + layerSettings.sourceDataspace = mCurrentDataSpace; + return layerSettings; } Hwc2::IComposerClient::Composition Layer::getCompositionType( diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index aa7e2f1ec3..953f25ddf1 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -461,19 +461,17 @@ public: return s.activeTransparentRegion_legacy; } virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; } - -protected: - virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, - bool useIdentityTransform, Region& clearRegion, - const bool supportProtectedContent, - renderengine::LayerSettings& layer); + virtual bool needsFiltering(const sp&) const { return false; } public: /* * compositionengine::LayerFE overrides */ + bool onPreComposition(nsecs_t) override; void latchCompositionState(compositionengine::LayerFECompositionState&, bool includeGeometry) const override; + std::optional prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings&) override; void onLayerDisplayed(const sp& releaseFence) override; const char* getDebugName() const override; @@ -508,17 +506,6 @@ public: // If a buffer was replaced this frame, release the former buffer virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { } - /* - * prepareClientLayer - populates a renderengine::LayerSettings to passed to - * RenderEngine::drawLayers. Returns true if the layer can be used, and - * false otherwise. - */ - bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, Region& clearRegion, - const bool supportProtectedContent, renderengine::LayerSettings& layer); - bool prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform, - Region& clearRegion, const bool supportProtectedContent, - renderengine::LayerSettings& layer); - /* * doTransaction - process the transaction. This is a good place to figure * out which attributes of the surface have changed. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1aec0c5389..d877e77832 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3319,6 +3319,7 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& displayDevice, */ ALOGV("Rendering client layers"); + const bool useIdentityTransform = false; bool firstLayer = true; Region clearRegion = Region::INVALID_REGION; for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { @@ -3339,13 +3340,20 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& displayDevice, layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) { // never clear the very first layer since we're // guaranteed the FB is already cleared - renderengine::LayerSettings layerSettings; Region dummyRegion; - bool prepared = - layer->prepareClientLayer(renderArea, clip, dummyRegion, - supportProtectedContent, layerSettings); - - if (prepared) { + compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ + clip, + useIdentityTransform, + layer->needsFiltering(renderArea.getDisplayDevice()) || + renderArea.needsFiltering(), + renderArea.isSecure(), + supportProtectedContent, + dummyRegion, + }; + auto result = layer->prepareClientComposition(targetSettings); + + if (result) { + auto& layerSettings = *result; layerSettings.source.buffer.buffer = nullptr; layerSettings.source.solidColor = half3(0.0, 0.0, 0.0); layerSettings.alpha = half(0.0); @@ -3356,12 +3364,18 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& displayDevice, break; } case Hwc2::IComposerClient::Composition::CLIENT: { - renderengine::LayerSettings layerSettings; - bool prepared = - layer->prepareClientLayer(renderArea, clip, clearRegion, - supportProtectedContent, layerSettings); - if (prepared) { - clientCompositionLayers.push_back(layerSettings); + compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ + clip, + useIdentityTransform, + layer->needsFiltering(renderArea.getDisplayDevice()) || + renderArea.needsFiltering(), + renderArea.isSecure(), + supportProtectedContent, + clearRegion, + }; + auto result = layer->prepareClientComposition(targetSettings); + if (result) { + clientCompositionLayers.push_back(*result); } break; } @@ -5902,11 +5916,19 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, Region clearRegion = Region::INVALID_REGION; traverseLayers([&](Layer* layer) { - renderengine::LayerSettings layerSettings; - bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion, - false, layerSettings); - if (prepared) { - clientCompositionLayers.push_back(layerSettings); + const bool supportProtectedContent = false; + Region clip(renderArea.getBounds()); + compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ + clip, + useIdentityTransform, + layer->needsFiltering(renderArea.getDisplayDevice()) || renderArea.needsFiltering(), + renderArea.isSecure(), + supportProtectedContent, + clearRegion, + }; + auto result = layer->prepareClientComposition(targetSettings); + if (result) { + clientCompositionLayers.push_back(*result); } }); -- GitLab From 7c9dbf97c8d7696106c97d9cc27d74e72b68bd4c Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 1 Aug 2019 17:57:31 -0700 Subject: [PATCH 0127/1255] SF: Refactor Scheduler mock injection Factor out TestableScheduler setup to TestableSurfaceFlinger, and instantiate a VSyncModulator, since the std::optional may be dereferenced in tests. Bug: 123530318 Test: libsurfaceflinger_unittest Change-Id: Ic7c95024e63d861c5c5c53e4973995a4fd83a7d8 --- .../surfaceflinger/Scheduler/Scheduler.cpp | 8 ++++ services/surfaceflinger/Scheduler/Scheduler.h | 4 ++ .../tests/unittests/CompositionTest.cpp | 33 +++++++-------- .../unittests/DisplayTransactionTest.cpp | 41 ++++++++----------- .../tests/unittests/TestableScheduler.h | 9 ++-- .../tests/unittests/TestableSurfaceFlinger.h | 27 +++++++++--- 6 files changed, 70 insertions(+), 52 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 952643ce70..38834273a4 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -118,6 +118,14 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, } } +Scheduler::Scheduler(std::unique_ptr primaryDispSync, + std::unique_ptr eventControlThread, + const scheduler::RefreshRateConfigs& configs) + : mHasSyncFramework(false), + mPrimaryDispSync(std::move(primaryDispSync)), + mEventControlThread(std::move(eventControlThread)), + mRefreshRateConfigs(configs) {} + Scheduler::~Scheduler() { // Ensure the OneShotTimer threads are joined before we start destroying state. mDisplayPowerTimer.reset(); diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 0d9d7aa3ba..5905ff6eb9 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -204,6 +204,10 @@ private: enum class TimerState { Reset, Expired }; enum class TouchState { Inactive, Active }; + // Used by tests to inject mocks. + Scheduler(std::unique_ptr, std::unique_ptr, + const scheduler::RefreshRateConfigs&); + // Creates a connection on the given EventThread and forwards the given callbacks. sp createConnectionInternal(EventThread*, ResyncCallback&&, ISurfaceComposer::ConfigChanged); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 47243a9595..82dd3c7bd8 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -34,7 +34,6 @@ #include "ColorLayer.h" #include "Layer.h" -#include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/MockDispSync.h" @@ -95,10 +94,6 @@ public: mFlinger.mutableEventQueue().reset(mMessageQueue); setupScheduler(); - EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0)); - EXPECT_CALL(*mPrimaryDispSync, getPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE)); - EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0)); EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0))); EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) @@ -125,15 +120,22 @@ public: } void setupScheduler() { - mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs()); - mScheduler->mutableEventControlThread().reset(mEventControlThread); - mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync); - EXPECT_CALL(*mEventThread.get(), registerDisplayEventConnection(_)); - sp connectionHandle = - mScheduler->addConnection(std::move(mEventThread)); - mFlinger.mutableSfConnectionHandle() = std::move(connectionHandle); + auto eventThread = std::make_unique(); + auto sfEventThread = std::make_unique(); + + EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); + + auto primaryDispSync = std::make_unique(); - mFlinger.mutableScheduler().reset(mScheduler); + EXPECT_CALL(*primaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0)); + EXPECT_CALL(*primaryDispSync, getPeriod()) + .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE)); + EXPECT_CALL(*primaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0)); + + mFlinger.setupScheduler(std::move(primaryDispSync), + std::make_unique(), + std::move(eventThread), std::move(sfEventThread)); } void setupForceGeometryDirty() { @@ -157,7 +159,6 @@ public: std::unordered_set mDefaultCapabilities = {HWC2::Capability::SidebandStream}; - TestableScheduler* mScheduler; TestableSurfaceFlinger mFlinger; sp mDisplay; sp mExternalDisplay; @@ -168,13 +169,9 @@ public: sp mBuffer = new GraphicBuffer(); ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer(); - std::unique_ptr mEventThread = std::make_unique(); - mock::EventControlThread* mEventControlThread = new mock::EventControlThread(); - Hwc2::mock::Composer* mComposer = nullptr; renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); - mock::DispSync* mPrimaryDispSync = new mock::DispSync(); sp mClientTargetAcquireFence = Fence::NO_FENCE; diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 5f58e7dce9..8f6f3ecfe4 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -95,11 +95,10 @@ public: DisplayTransactionTest(); ~DisplayTransactionTest() override; - void setupScheduler(); - // -------------------------------------------------------------------- // Mock/Fake injection + void injectMockScheduler(); void injectMockComposer(int virtualDisplayCount); void injectFakeBufferQueueFactory(); void injectFakeNativeWindowSurfaceFactory(); @@ -119,11 +118,7 @@ public: // -------------------------------------------------------------------- // Test instances - TestableScheduler* mScheduler; TestableSurfaceFlinger mFlinger; - mock::EventThread* mEventThread = new mock::EventThread(); - mock::EventThread* mSFEventThread = new mock::EventThread(); - mock::EventControlThread* mEventControlThread = new mock::EventControlThread(); sp mNativeWindow = new mock::NativeWindow(); sp mBuffer = new GraphicBuffer(); @@ -134,7 +129,11 @@ public: Hwc2::mock::Composer* mComposer = nullptr; mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor(); - mock::DispSync* mPrimaryDispSync = new mock::DispSync(); + + mock::DispSync* mPrimaryDispSync = new mock::DispSync; + mock::EventControlThread* mEventControlThread = new mock::EventControlThread; + mock::EventThread* mEventThread = new mock::EventThread; + mock::EventThread* mSFEventThread = new mock::EventThread; // These mocks are created only when expected to be created via a factory. sp mConsumer; @@ -164,7 +163,7 @@ DisplayTransactionTest::DisplayTransactionTest() { return nullptr; }); - setupScheduler(); + injectMockScheduler(); mFlinger.mutableEventQueue().reset(mMessageQueue); mFlinger.setupRenderEngine(std::unique_ptr(mRenderEngine)); mFlinger.mutableInterceptor().reset(mSurfaceInterceptor); @@ -178,20 +177,14 @@ DisplayTransactionTest::~DisplayTransactionTest() { ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } -void DisplayTransactionTest::setupScheduler() { - mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs()); - mScheduler->mutableEventControlThread().reset(mEventControlThread); - mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync); +void DisplayTransactionTest::injectMockScheduler() { EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_)); - sp sfConnectionHandle = - mScheduler->addConnection(std::unique_ptr(mSFEventThread)); - mFlinger.mutableSfConnectionHandle() = std::move(sfConnectionHandle); - sp appConnectionHandle = - mScheduler->addConnection(std::unique_ptr(mEventThread)); - mFlinger.mutableAppConnectionHandle() = std::move(appConnectionHandle); - mFlinger.mutableScheduler().reset(mScheduler); + mFlinger.setupScheduler(std::unique_ptr(mPrimaryDispSync), + std::unique_ptr(mEventControlThread), + std::unique_ptr(mEventThread), + std::unique_ptr(mSFEventThread)); } void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) { @@ -1131,8 +1124,8 @@ TEST_F(DisplayTransactionTest, resetDisplayStateClearsState) { // Preconditions // vsync is enabled and available - mScheduler->mutablePrimaryHWVsyncEnabled() = true; - mScheduler->mutableHWVsyncAvailable() = true; + mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = true; + mFlinger.scheduler()->mutableHWVsyncAvailable() = true; // A display exists auto existing = Case::Display::makeFakeExistingDisplayInjector(this); @@ -1156,8 +1149,8 @@ TEST_F(DisplayTransactionTest, resetDisplayStateClearsState) { // Postconditions // vsyncs should be off and not available. - EXPECT_FALSE(mScheduler->mutablePrimaryHWVsyncEnabled()); - EXPECT_FALSE(mScheduler->mutableHWVsyncAvailable()); + EXPECT_FALSE(mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled()); + EXPECT_FALSE(mFlinger.scheduler()->mutableHWVsyncAvailable()); // The display should have been removed from the display map. EXPECT_FALSE(hasDisplayDevice(existing.token())); @@ -3008,7 +3001,7 @@ struct DisplayPowerCase { } static void setInitialPrimaryHWVsyncEnabled(DisplayTransactionTest* test, bool enabled) { - test->mScheduler->mutablePrimaryHWVsyncEnabled() = enabled; + test->mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = enabled; } static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) { diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index cb6980ed1a..5157cc4e2c 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -20,15 +20,16 @@ #include #include "Scheduler/EventThread.h" -#include "Scheduler/RefreshRateConfigs.h" #include "Scheduler/Scheduler.h" namespace android { class TestableScheduler : public Scheduler { public: - TestableScheduler(const scheduler::RefreshRateConfigs& refreshRateConfig) - : Scheduler([](bool) {}, refreshRateConfig) {} + TestableScheduler(std::unique_ptr primaryDispSync, + std::unique_ptr eventControlThread, + const scheduler::RefreshRateConfigs& configs) + : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs) {} // Creates EventThreadConnection with the given eventThread. Creates Scheduler::Connection // and adds it to the list of connectins. Returns the ConnectionHandle for the @@ -62,7 +63,7 @@ public: mutableEventControlThread().reset(); mutablePrimaryDispSync().reset(); mConnections.clear(); - }; + } }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 64d34ee102..97fafcba78 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -36,7 +36,7 @@ #include "SurfaceFlinger.h" #include "SurfaceFlingerFactory.h" #include "SurfaceInterceptor.h" - +#include "TestableScheduler.h" #include "TimeStats/TimeStats.h" namespace android { @@ -176,6 +176,8 @@ public: class TestableSurfaceFlinger { public: + TestableScheduler* scheduler() { return mScheduler; } + // Extend this as needed for accessing SurfaceFlinger private (and public) // functions. @@ -188,6 +190,23 @@ public: std::make_unique(std::move(composer))); } + void setupScheduler(std::unique_ptr primaryDispSync, + std::unique_ptr eventControlThread, + std::unique_ptr appEventThread, + std::unique_ptr sfEventThread) { + mScheduler = + new TestableScheduler(std::move(primaryDispSync), std::move(eventControlThread), + mFlinger->mRefreshRateConfigs); + + mFlinger->mAppConnectionHandle = mScheduler->addConnection(std::move(appEventThread)); + mFlinger->mSfConnectionHandle = mScheduler->addConnection(std::move(sfEventThread)); + + mFlinger->mScheduler.reset(mScheduler); + mFlinger->mVSyncModulator.emplace(*mScheduler, mFlinger->mAppConnectionHandle, + mFlinger->mSfConnectionHandle, + mFlinger->mPhaseOffsets->getCurrentOffsets()); + } + using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction; void setCreateBufferQueueFunction(CreateBufferQueueFunction f) { mFactory.mCreateBufferQueue = f; @@ -338,10 +357,6 @@ public: auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; } auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; } auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; } - auto& mutableScheduler() { return mFlinger->mScheduler; } - auto& mutableAppConnectionHandle() { return mFlinger->mAppConnectionHandle; } - auto& mutableSfConnectionHandle() { return mFlinger->mSfConnectionHandle; } - auto& mutableRefreshRateConfigs() { return mFlinger->mRefreshRateConfigs; } ~TestableSurfaceFlinger() { // All these pointer and container clears help ensure that GMock does @@ -353,7 +368,6 @@ public: mutableDrawingState().displays.clear(); mutableEventQueue().reset(); mutableInterceptor().reset(); - mutableScheduler().reset(); mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr()); mFlinger->mCompositionEngine->setRenderEngine( std::unique_ptr()); @@ -573,6 +587,7 @@ public: surfaceflinger::test::Factory mFactory; sp mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization); + TestableScheduler* mScheduler = nullptr; // We need to keep a reference to these so they are properly destroyed. std::vector> mFakeHwcDisplays; -- GitLab From 0bbb2a1e5a5d8a67591b731a2497dd0ce0305a26 Mon Sep 17 00:00:00 2001 From: Inseob Kim Date: Tue, 30 Jul 2019 18:24:39 +0900 Subject: [PATCH 0128/1255] Implement sysprop_library API stability check sysprop_library now checks the API stability itself, cutting dependency on java_sdk_library. Under the directory {module_dir}/api, {module_name}-current.txt and {module_name}-latest.txt hold API signatures. When sysprop_library is built, or a user run "m {module_name}-check-api" command, API check is performed. First, current.txt must have exactly same signature with built sysprop_library module. Second, current.txt must be compatible with latest.txt. Build system emits a handy error message to generate/update those API files, in case of missing or mismatching. Also, a script file for freezing API files is introduced. Bug: 131637873 Test: 1) m && boot blueline Test: 2) m {sysprop_library} performs API check Test: 3) manual test for check-api, freezing api Change-Id: I7812db716ca42055caa70385c71a90de49fc1afc --- .../api/SurfaceFlingerProperties-current.txt | 138 ++++++++++++++++++ .../api/SurfaceFlingerProperties-latest.txt | 138 ++++++++++++++++++ .../surfaceflinger/sysprop/api/current.txt | 1 - .../surfaceflinger/sysprop/api/removed.txt | 1 - .../sysprop/api/system-current.txt | 45 ------ .../sysprop/api/system-removed.txt | 1 - .../sysprop/api/test-current.txt | 1 - .../sysprop/api/test-removed.txt | 1 - 8 files changed, 276 insertions(+), 50 deletions(-) create mode 100644 services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt create mode 100644 services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt delete mode 100644 services/surfaceflinger/sysprop/api/current.txt delete mode 100644 services/surfaceflinger/sysprop/api/removed.txt delete mode 100644 services/surfaceflinger/sysprop/api/system-current.txt delete mode 100644 services/surfaceflinger/sysprop/api/system-removed.txt delete mode 100644 services/surfaceflinger/sysprop/api/test-current.txt delete mode 100644 services/surfaceflinger/sysprop/api/test-removed.txt diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt new file mode 100644 index 0000000000..b66e56ecc7 --- /dev/null +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -0,0 +1,138 @@ +props { + module: "android.sysprop.SurfaceFlingerProperties" + prop { + api_name: "color_space_agnostic_dataspace" + type: Long + prop_name: "ro.surface_flinger.color_space_agnostic_dataspace" + } + prop { + api_name: "default_composition_dataspace" + type: Long + prop_name: "ro.surface_flinger.default_composition_dataspace" + } + prop { + api_name: "default_composition_pixel_format" + type: Integer + prop_name: "ro.surface_flinger.default_composition_pixel_format" + } + prop { + api_name: "display_primary_blue" + type: DoubleList + prop_name: "ro.surface_flinger.display_primary_blue" + } + prop { + api_name: "display_primary_green" + type: DoubleList + prop_name: "ro.surface_flinger.display_primary_green" + } + prop { + api_name: "display_primary_red" + type: DoubleList + prop_name: "ro.surface_flinger.display_primary_red" + } + prop { + api_name: "display_primary_white" + type: DoubleList + prop_name: "ro.surface_flinger.display_primary_white" + } + prop { + api_name: "enable_protected_contents" + prop_name: "ro.surface_flinger.protected_contents" + } + prop { + api_name: "force_hwc_copy_for_virtual_displays" + prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays" + } + prop { + api_name: "has_HDR_display" + prop_name: "ro.surface_flinger.has_HDR_display" + } + prop { + api_name: "has_wide_color_display" + prop_name: "ro.surface_flinger.has_wide_color_display" + } + prop { + api_name: "max_frame_buffer_acquired_buffers" + type: Long + prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers" + } + prop { + api_name: "max_virtual_display_dimension" + type: Long + prop_name: "ro.surface_flinger.max_virtual_display_dimension" + } + prop { + api_name: "present_time_offset_from_vsync_ns" + type: Long + prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns" + } + prop { + api_name: "primary_display_orientation" + type: Enum + prop_name: "ro.surface_flinger.primary_display_orientation" + enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270" + } + prop { + api_name: "running_without_sync_framework" + prop_name: "ro.surface_flinger.running_without_sync_framework" + } + prop { + api_name: "set_display_power_timer_ms" + type: Integer + prop_name: "ro.surface_flinger.set_display_power_timer_ms" + } + prop { + api_name: "set_idle_timer_ms" + type: Integer + prop_name: "ro.surface_flinger.set_idle_timer_ms" + } + prop { + api_name: "set_touch_timer_ms" + type: Integer + prop_name: "ro.surface_flinger.set_touch_timer_ms" + } + prop { + api_name: "start_graphics_allocator_service" + prop_name: "ro.surface_flinger.start_graphics_allocator_service" + } + prop { + api_name: "support_kernel_idle_timer" + prop_name: "ro.surface_flinger.support_kernel_idle_timer" + } + prop { + api_name: "use_color_management" + prop_name: "ro.surface_flinger.use_color_management" + } + prop { + api_name: "use_context_priority" + prop_name: "ro.surface_flinger.use_context_priority" + } + prop { + api_name: "use_smart_90_for_video" + prop_name: "ro.surface_flinger.use_smart_90_for_video" + } + prop { + api_name: "use_vr_flinger" + prop_name: "ro.surface_flinger.use_vr_flinger" + } + prop { + api_name: "vsync_event_phase_offset_ns" + type: Long + prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns" + } + prop { + api_name: "vsync_sf_event_phase_offset_ns" + type: Long + prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns" + } + prop { + api_name: "wcg_composition_dataspace" + type: Long + prop_name: "ro.surface_flinger.wcg_composition_dataspace" + } + prop { + api_name: "wcg_composition_pixel_format" + type: Integer + prop_name: "ro.surface_flinger.wcg_composition_pixel_format" + } +} diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt new file mode 100644 index 0000000000..b66e56ecc7 --- /dev/null +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt @@ -0,0 +1,138 @@ +props { + module: "android.sysprop.SurfaceFlingerProperties" + prop { + api_name: "color_space_agnostic_dataspace" + type: Long + prop_name: "ro.surface_flinger.color_space_agnostic_dataspace" + } + prop { + api_name: "default_composition_dataspace" + type: Long + prop_name: "ro.surface_flinger.default_composition_dataspace" + } + prop { + api_name: "default_composition_pixel_format" + type: Integer + prop_name: "ro.surface_flinger.default_composition_pixel_format" + } + prop { + api_name: "display_primary_blue" + type: DoubleList + prop_name: "ro.surface_flinger.display_primary_blue" + } + prop { + api_name: "display_primary_green" + type: DoubleList + prop_name: "ro.surface_flinger.display_primary_green" + } + prop { + api_name: "display_primary_red" + type: DoubleList + prop_name: "ro.surface_flinger.display_primary_red" + } + prop { + api_name: "display_primary_white" + type: DoubleList + prop_name: "ro.surface_flinger.display_primary_white" + } + prop { + api_name: "enable_protected_contents" + prop_name: "ro.surface_flinger.protected_contents" + } + prop { + api_name: "force_hwc_copy_for_virtual_displays" + prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays" + } + prop { + api_name: "has_HDR_display" + prop_name: "ro.surface_flinger.has_HDR_display" + } + prop { + api_name: "has_wide_color_display" + prop_name: "ro.surface_flinger.has_wide_color_display" + } + prop { + api_name: "max_frame_buffer_acquired_buffers" + type: Long + prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers" + } + prop { + api_name: "max_virtual_display_dimension" + type: Long + prop_name: "ro.surface_flinger.max_virtual_display_dimension" + } + prop { + api_name: "present_time_offset_from_vsync_ns" + type: Long + prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns" + } + prop { + api_name: "primary_display_orientation" + type: Enum + prop_name: "ro.surface_flinger.primary_display_orientation" + enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270" + } + prop { + api_name: "running_without_sync_framework" + prop_name: "ro.surface_flinger.running_without_sync_framework" + } + prop { + api_name: "set_display_power_timer_ms" + type: Integer + prop_name: "ro.surface_flinger.set_display_power_timer_ms" + } + prop { + api_name: "set_idle_timer_ms" + type: Integer + prop_name: "ro.surface_flinger.set_idle_timer_ms" + } + prop { + api_name: "set_touch_timer_ms" + type: Integer + prop_name: "ro.surface_flinger.set_touch_timer_ms" + } + prop { + api_name: "start_graphics_allocator_service" + prop_name: "ro.surface_flinger.start_graphics_allocator_service" + } + prop { + api_name: "support_kernel_idle_timer" + prop_name: "ro.surface_flinger.support_kernel_idle_timer" + } + prop { + api_name: "use_color_management" + prop_name: "ro.surface_flinger.use_color_management" + } + prop { + api_name: "use_context_priority" + prop_name: "ro.surface_flinger.use_context_priority" + } + prop { + api_name: "use_smart_90_for_video" + prop_name: "ro.surface_flinger.use_smart_90_for_video" + } + prop { + api_name: "use_vr_flinger" + prop_name: "ro.surface_flinger.use_vr_flinger" + } + prop { + api_name: "vsync_event_phase_offset_ns" + type: Long + prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns" + } + prop { + api_name: "vsync_sf_event_phase_offset_ns" + type: Long + prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns" + } + prop { + api_name: "wcg_composition_dataspace" + type: Long + prop_name: "ro.surface_flinger.wcg_composition_dataspace" + } + prop { + api_name: "wcg_composition_pixel_format" + type: Integer + prop_name: "ro.surface_flinger.wcg_composition_pixel_format" + } +} diff --git a/services/surfaceflinger/sysprop/api/current.txt b/services/surfaceflinger/sysprop/api/current.txt deleted file mode 100644 index d802177e24..0000000000 --- a/services/surfaceflinger/sysprop/api/current.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/services/surfaceflinger/sysprop/api/removed.txt b/services/surfaceflinger/sysprop/api/removed.txt deleted file mode 100644 index d802177e24..0000000000 --- a/services/surfaceflinger/sysprop/api/removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/services/surfaceflinger/sysprop/api/system-current.txt b/services/surfaceflinger/sysprop/api/system-current.txt deleted file mode 100644 index 79854b36a2..0000000000 --- a/services/surfaceflinger/sysprop/api/system-current.txt +++ /dev/null @@ -1,45 +0,0 @@ -// Signature format: 2.0 -package android.sysprop { - - public final class SurfaceFlingerProperties { - method public static java.util.Optional color_space_agnostic_dataspace(); - method public static java.util.Optional default_composition_dataspace(); - method public static java.util.Optional default_composition_pixel_format(); - method public static java.util.List display_primary_blue(); - method public static java.util.List display_primary_green(); - method public static java.util.List display_primary_red(); - method public static java.util.List display_primary_white(); - method public static java.util.Optional enable_protected_contents(); - method public static java.util.Optional force_hwc_copy_for_virtual_displays(); - method public static java.util.Optional has_HDR_display(); - method public static java.util.Optional has_wide_color_display(); - method public static java.util.Optional max_frame_buffer_acquired_buffers(); - method public static java.util.Optional max_virtual_display_dimension(); - method public static java.util.Optional present_time_offset_from_vsync_ns(); - method public static java.util.Optional primary_display_orientation(); - method public static java.util.Optional running_without_sync_framework(); - method public static java.util.Optional set_display_power_timer_ms(); - method public static java.util.Optional set_idle_timer_ms(); - method public static java.util.Optional set_touch_timer_ms(); - method public static java.util.Optional start_graphics_allocator_service(); - method public static java.util.Optional support_kernel_idle_timer(); - method public static java.util.Optional use_color_management(); - method public static java.util.Optional use_context_priority(); - method public static java.util.Optional use_smart_90_for_video(); - method public static java.util.Optional use_vr_flinger(); - method public static java.util.Optional vsync_event_phase_offset_ns(); - method public static java.util.Optional vsync_sf_event_phase_offset_ns(); - method public static java.util.Optional wcg_composition_dataspace(); - method public static java.util.Optional wcg_composition_pixel_format(); - } - - public enum SurfaceFlingerProperties.primary_display_orientation_values { - method public String getPropValue(); - enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_0; - enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_180; - enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_270; - enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_90; - } - -} - diff --git a/services/surfaceflinger/sysprop/api/system-removed.txt b/services/surfaceflinger/sysprop/api/system-removed.txt deleted file mode 100644 index d802177e24..0000000000 --- a/services/surfaceflinger/sysprop/api/system-removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/services/surfaceflinger/sysprop/api/test-current.txt b/services/surfaceflinger/sysprop/api/test-current.txt deleted file mode 100644 index d802177e24..0000000000 --- a/services/surfaceflinger/sysprop/api/test-current.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/services/surfaceflinger/sysprop/api/test-removed.txt b/services/surfaceflinger/sysprop/api/test-removed.txt deleted file mode 100644 index d802177e24..0000000000 --- a/services/surfaceflinger/sysprop/api/test-removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 -- GitLab From aa74a6635cbab0966b77722f48a26bdb3479a8f6 Mon Sep 17 00:00:00 2001 From: Robert Delgado Date: Wed, 31 Jul 2019 13:02:33 -0700 Subject: [PATCH 0129/1255] Changed target path for transaction writing. Previously, transactions were written into a directory (data/SurfaceTrace.dat) that required SELinux write permissions. Changing it to the new path now allows for it to be accessed with no permission changes needed. Test: adb shell su root service call SurfaceFlinger 1020 i32 1 then verify that the transaction file is in /data/misc/wmtrace/transaction_trace.pb Change-Id: I1fc30bca93e7f2a064db856be223ddd64b53fbda --- services/surfaceflinger/SurfaceInterceptor.h | 2 +- services/surfaceflinger/tests/SurfaceInterceptor_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h index fdc6c580ed..6858c4d5a6 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -46,7 +46,7 @@ using SurfaceChange = surfaceflinger::SurfaceChange; using Increment = surfaceflinger::Increment; using DisplayChange = surfaceflinger::DisplayChange; -constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat"; +constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb"; class SurfaceInterceptor { public: diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index bc5f1aab42..59e9c00ae7 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -60,7 +60,7 @@ constexpr auto UNIQUE_TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface#0"; constexpr auto LAYER_NAME = "Layer Create and Delete Test"; constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0"; -constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat"; +constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb"; // Fill an RGBA_8888 formatted surface with a single color. static void fillSurfaceRGBA8(const sp& sc, uint8_t r, uint8_t g, uint8_t b) { -- GitLab From 14d7692c0f7c0ad9d8a26c9c85033c48eb6c007f Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 5 Aug 2019 08:41:20 -0700 Subject: [PATCH 0130/1255] Reparent children before reparenting to null When we reparent a layer to null, we remove its child layers from current state and remove their relative z. If the children are reparented in the same transaction, then we have to make sure we reparent the children first so we do not lose their relative z order. Test: atest SurfaceFlinger_test Bug: 132205507 Change-Id: I6b73758065c7eb46ac3b60a1b40f6839be24b09c --- services/surfaceflinger/SurfaceFlinger.cpp | 22 +++++++++------ .../surfaceflinger/tests/Transaction_test.cpp | 28 +++++++++++++++++++ 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8bf6b999bb..fc1f31894b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4052,15 +4052,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( // We don't trigger a traversal here because if no other state is // changed, we don't want this to cause any more work } - if (what & layer_state_t::eReparent) { - bool hadParent = layer->hasParent(); - if (layer->reparent(s.parentHandleForChild)) { - if (!hadParent) { - mCurrentState.layersSortedByZ.remove(layer); - } - flags |= eTransactionNeeded|eTraversalNeeded; - } - } if (what & layer_state_t::eReparentChildren) { if (layer->reparentChildren(s.reparentHandle)) { flags |= eTransactionNeeded|eTraversalNeeded; @@ -4121,6 +4112,19 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } + // This has to happen after we reparent children because when we reparent to null we remove + // child layers from current state and remove its relative z. If the children are reparented in + // the same transaction, then we have to make sure we reparent the children first so we do not + // lose its relative z order. + if (what & layer_state_t::eReparent) { + bool hadParent = layer->hasParent(); + if (layer->reparent(s.parentHandleForChild)) { + if (!hadParent) { + mCurrentState.layersSortedByZ.remove(layer); + } + flags |= eTransactionNeeded | eTraversalNeeded; + } + } std::vector> callbackHandles; if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!listenerCallbacks.empty())) { for (const auto& [listener, callbackIds] : listenerCallbacks) { diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index c8f5618a80..b1fde22e0e 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -4686,6 +4686,34 @@ TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) { } } +TEST_F(ChildLayerTest, ChildrenRelativeZSurvivesParentDestruction) { + sp mGrandChild = + createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get()); + fillSurfaceRGBA8(mGrandChild, 111, 111, 111); + + // draw grand child behind the foreground surface + asTransaction([&](Transaction& t) { + t.setRelativeLayer(mGrandChild, mFGSurfaceControl->getHandle(), -1); + }); + + { + SCOPED_TRACE("Child visible"); + ScreenCapture::captureScreen(&mCapture); + mCapture->checkPixel(64, 64, 200, 200, 200); + } + + asTransaction([&](Transaction& t) { + t.reparent(mChild, nullptr); + t.reparentChildren(mChild, mFGSurfaceControl->getHandle()); + }); + + { + SCOPED_TRACE("foreground visible reparenting grandchild"); + ScreenCapture::captureScreen(&mCapture); + mCapture->checkPixel(64, 64, 195, 63, 63); + } +} + TEST_F(ChildLayerTest, DetachChildrenSameClient) { asTransaction([&](Transaction& t) { t.show(mChild); -- GitLab From 3649106e95f8fe5a733b5113ba76d7a3f4a0b85c Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Fri, 26 Jul 2019 14:41:43 -0700 Subject: [PATCH 0131/1255] Adding test to test closer boundary for overflow Bug: 137801859 Test: build, boot, GraphicBuffer_test Change-Id: Ic5c74a52dcf325c9151f63bd9bbb11ea17222b0b --- libs/ui/tests/GraphicBuffer_test.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp index 127f7eedd6..5e0b094b7b 100644 --- a/libs/ui/tests/GraphicBuffer_test.cpp +++ b/libs/ui/tests/GraphicBuffer_test.cpp @@ -44,11 +44,28 @@ TEST_F(GraphicBufferTest, AllocateNoError) { TEST_F(GraphicBufferTest, AllocateBadDimensions) { PixelFormat format = PIXEL_FORMAT_RGBA_8888; + if (std::numeric_limits::max() / std::numeric_limits::max() / + bytesPerPixel(format) >= + std::numeric_limits::max()) { + GTEST_SUCCEED() << "Cannot overflow with this format"; + } uint32_t width, height; width = height = std::numeric_limits::max(); sp gb(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage, std::string("test"))); ASSERT_EQ(BAD_VALUE, gb->initCheck()); + + const size_t targetArea = std::numeric_limits::max() / bytesPerPixel(format); + const size_t widthCandidate = targetArea / std::numeric_limits::max(); + if (widthCandidate == 0) { + width = 1; + } else { + width = std::numeric_limits::max(); + } + height = (targetArea / width) + 1; + sp gb2(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage, + std::string("test"))); + ASSERT_EQ(BAD_VALUE, gb2->initCheck()); } TEST_F(GraphicBufferTest, CreateFromBufferHubBuffer) { -- GitLab From 46470110f4faa3a901067b066fdfc90a6a110b60 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Fri, 2 Aug 2019 13:13:11 -0700 Subject: [PATCH 0132/1255] SF: Omit layer tree dump if flag is specified Bug: None Test: dumpsys SurfaceFlinger --vsync Change-Id: I4214d75faff5c0ee1f29ff3d63b45e5e0825dba7 --- services/surfaceflinger/SurfaceFlinger.cpp | 19 +++++++++++-------- .../surfaceflinger/TimeStats/TimeStats.cpp | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index acfd534018..67735aa970 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4498,7 +4498,8 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, const auto flag = args.empty() ? ""s : std::string(String8(args[0])); - if (const auto it = dumpers.find(flag); it != dumpers.end()) { + const auto it = dumpers.find(flag); + if (it != dumpers.end()) { (it->second)(args, asProto, result); } else if (!asProto) { dumpAllLocked(args, result); @@ -4508,13 +4509,15 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, mStateLock.unlock(); } - LayersProto layersProto = dumpProtoFromMainThread(); - if (asProto) { - result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize()); - } else { - auto layerTree = LayerProtoParser::generateLayerTree(layersProto); - result.append(LayerProtoParser::layerTreeToString(layerTree)); - result.append("\n"); + if (it == dumpers.end()) { + const LayersProto layersProto = dumpProtoFromMainThread(); + if (asProto) { + result.append(layersProto.SerializeAsString()); + } else { + const auto layerTree = LayerProtoParser::generateLayerTree(layersProto); + result.append(LayerProtoParser::layerTreeToString(layerTree)); + result.append("\n"); + } } } write(fd, result.c_str(), result.size()); diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index c97a19b39b..1ac50986d9 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -613,7 +613,7 @@ void TimeStats::dump(bool asProto, std::optional maxLayers, std::strin if (asProto) { ALOGD("Dumping TimeStats as proto"); SFTimeStatsGlobalProto timeStatsProto = mTimeStats.toProto(maxLayers); - result.append(timeStatsProto.SerializeAsString().c_str(), timeStatsProto.ByteSize()); + result.append(timeStatsProto.SerializeAsString()); } else { ALOGD("Dumping TimeStats as text"); result.append(mTimeStats.toString(maxLayers)); -- GitLab From 7c9d8958aaa963419a415fff863a6c322e38cfc2 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Thu, 1 Aug 2019 14:24:25 -0700 Subject: [PATCH 0133/1255] Skip SensorDevice disable sensors for HAL 2.0 SystemServerTimingAsync_StartSensorService_avg Prefix -> 43.111111111111114O ms Postfix -> 10.777777777777779 ms Bug: 133859966 Test: Pushed libsensorservice onto local device. Observed that code flow chose to skip disabling sensors for HAL 2.0 and framework seemed to behave properly. Ran atest boottime and observed change in sensor service start time. Change-Id: I99f3d38b62e4bf73aeb76be55a1b6b8e72052215 --- services/sensorservice/SensorDevice.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index 717f31769b..c7a8f5bee3 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -134,7 +134,12 @@ void SensorDevice::initializeSensorList() { mActivationCount.add(list[i].sensorHandle, model); - checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */)); + // Only disable all sensors on HAL 1.0 since HAL 2.0 + // handles this in its initialize method + if (!mSensors->supportsMessageQueues()) { + checkReturn(mSensors->activate(list[i].sensorHandle, + 0 /* enabled */)); + } } })); } -- GitLab From 8384682fd25b54921fd74288788f2a9299dd8dba Mon Sep 17 00:00:00 2001 From: Atif Niyaz Date: Thu, 18 Jul 2019 15:17:40 -0700 Subject: [PATCH 0134/1255] Seperate LatencyStatistics from InputReader Test: atest LatencyStatisticsTest Change-Id: I22a39cd5bef7fa9180bc1ee1fd9478a2cf872e83 --- include/input/LatencyStatistics.h | 59 ++++++++++++++ libs/input/Android.bp | 1 + libs/input/LatencyStatistics.cpp | 90 +++++++++++++++++++++ libs/input/tests/Android.bp | 1 + libs/input/tests/LatencyStatistics_test.cpp | 72 +++++++++++++++++ services/inputflinger/InputReader.cpp | 21 ++--- services/inputflinger/InputReader.h | 72 ++--------------- 7 files changed, 237 insertions(+), 79 deletions(-) create mode 100644 include/input/LatencyStatistics.h create mode 100644 libs/input/LatencyStatistics.cpp create mode 100644 libs/input/tests/LatencyStatistics_test.cpp diff --git a/include/input/LatencyStatistics.h b/include/input/LatencyStatistics.h new file mode 100644 index 0000000000..bd86266901 --- /dev/null +++ b/include/input/LatencyStatistics.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 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. + */ + +#ifndef _UI_INPUT_STATISTICS_H +#define _UI_INPUT_STATISTICS_H + +#include + +#include + +namespace android { + +class LatencyStatistics { +private: + /* Minimum sample recorded */ + float mMin; + /* Maximum sample recorded */ + float mMax; + /* Sum of all samples recorded */ + float mSum; + /* Sum of all the squares of samples recorded */ + float mSum2; + /* Count of all samples recorded */ + size_t mCount; + /* The last time statistics were reported */ + std::chrono::steady_clock::time_point mLastReportTime; + /* Statistics Report Frequency */ + const std::chrono::seconds mReportPeriod; + +public: + LatencyStatistics(std::chrono::seconds period); + + void addValue(float); + void reset(); + bool shouldReport(); + + float getMean(); + float getMin(); + float getMax(); + float getStDev(); + size_t getCount(); +}; + +} // namespace android + +#endif // _UI_INPUT_STATISTICS_H diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 2d788119cd..17138506e5 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -48,6 +48,7 @@ cc_library { "InputTransport.cpp", "InputWindow.cpp", "ISetInputWindowsListener.cpp", + "LatencyStatistics.cpp", "VelocityControl.cpp", "VelocityTracker.cpp", ], diff --git a/libs/input/LatencyStatistics.cpp b/libs/input/LatencyStatistics.cpp new file mode 100644 index 0000000000..e343578e00 --- /dev/null +++ b/libs/input/LatencyStatistics.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 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 -inline T max(T a, T b, T c) { - return max(a, max(b, c)); -} -template -inline T min(T a, T b) { - return a -inline T min(T a, T b, T c) { - return min(a, min(b, c)); -} -template -inline T min(T a, T b, T c, T d) { - return min(min(a,b), min(c,d)); -} - -// ---------------------------------------------------------------------------- -// vertices -// ---------------------------------------------------------------------------- - -struct vec3_t { - union { - struct { GLfixed x, y, z; }; - struct { GLfixed r, g, b; }; - struct { GLfixed S, T, R; }; - GLfixed v[3]; - }; -}; - -struct vec4_t { - union { - struct { GLfixed x, y, z, w; }; - struct { GLfixed r, g, b, a; }; - struct { GLfixed S, T, R, Q; }; - GLfixed v[4]; - }; -}; - -struct vertex_t { - enum { - // these constant matter for our clipping - CLIP_L = 0x0001, // clipping flags - CLIP_R = 0x0002, - CLIP_B = 0x0004, - CLIP_T = 0x0008, - CLIP_N = 0x0010, - CLIP_F = 0x0020, - - EYE = 0x0040, - RESERVED = 0x0080, - - USER_CLIP_0 = 0x0100, // user clipping flags - USER_CLIP_1 = 0x0200, - USER_CLIP_2 = 0x0400, - USER_CLIP_3 = 0x0800, - USER_CLIP_4 = 0x1000, - USER_CLIP_5 = 0x2000, - - LIT = 0x4000, // lighting has been applied - TT = 0x8000, // texture coords transformed - - FRUSTUM_CLIP_ALL= 0x003F, - USER_CLIP_ALL = 0x3F00, - CLIP_ALL = 0x3F3F, - }; - - // the fields below are arranged to minimize d-cache usage - // we group together, by cache-line, the fields most likely to be used - - union { - vec4_t obj; - vec4_t eye; - }; - vec4_t clip; - - uint32_t flags; - size_t index; // cache tag, and vertex index - GLfixed fog; - uint8_t locked; - uint8_t mru; - uint8_t reserved[2]; - vec4_t window; - - vec4_t color; - vec4_t texture[GGL_TEXTURE_UNIT_COUNT]; -#ifdef __LP64__ - uint32_t reserved1[2]; -#else - uint32_t reserved1[4]; -#endif - - inline void clear() { - flags = index = locked = mru = 0; - } -}; - -struct point_size_t { - GGLcoord size; - GLboolean smooth; -}; - -struct line_width_t { - GGLcoord width; - GLboolean smooth; -}; - -struct polygon_offset_t { - GLfixed factor; - GLfixed units; - GLboolean enable; -}; - -// ---------------------------------------------------------------------------- -// arrays -// ---------------------------------------------------------------------------- - -struct array_t { - typedef void (*fetcher_t)(ogles_context_t*, GLfixed*, const GLvoid*); - fetcher_t fetch; - GLvoid const* physical_pointer; - GLint size; - GLsizei stride; - GLvoid const* pointer; - buffer_t const* bo; - uint16_t type; - GLboolean enable; - GLboolean pad; - GLsizei bounds; - void init(GLint, GLenum, GLsizei, const GLvoid *, const buffer_t*, GLsizei); - inline void resolve(); - inline const GLubyte* element(GLint i) const { - return (const GLubyte*)physical_pointer + i * stride; - } -}; - -struct array_machine_t { - array_t vertex; - array_t normal; - array_t color; - array_t texture[GGL_TEXTURE_UNIT_COUNT]; - uint8_t activeTexture; - uint8_t tmu; - uint16_t cull; - uint32_t flags; - GLenum indicesType; - buffer_t const* array_buffer; - buffer_t const* element_array_buffer; - - void (*compileElements)(ogles_context_t*, vertex_t*, GLint, GLsizei); - void (*compileElement)(ogles_context_t*, vertex_t*, GLint); - - void (*mvp_transform)(transform_t const*, vec4_t*, vec4_t const*); - void (*mv_transform)(transform_t const*, vec4_t*, vec4_t const*); - void (*tex_transform[2])(transform_t const*, vec4_t*, vec4_t const*); - void (*perspective)(ogles_context_t*c, vertex_t* v); - void (*clipVertex)(ogles_context_t* c, vertex_t* nv, - GGLfixed t, const vertex_t* s, const vertex_t* p); - void (*clipEye)(ogles_context_t* c, vertex_t* nv, - GGLfixed t, const vertex_t* s, const vertex_t* p); -}; - -struct vertex_cache_t { - enum { - // must be at least 4 - // 3 vertice for triangles - // or 2 + 2 for indexed triangles w/ cache contention - VERTEX_BUFFER_SIZE = 8, - // must be a power of two and at least 3 - VERTEX_CACHE_SIZE = 64, // 8 KB - - INDEX_BITS = 16, - INDEX_MASK = ((1LU<(__get_tls()[TLS_SLOT_OPENGL]); - } -#else - extern pthread_key_t gGLKey; - inline void setGlThreadSpecific(ogles_context_t *value) { - pthread_setspecific(gGLKey, value); - } - inline ogles_context_t* getGlThreadSpecific() { - return static_cast(pthread_getspecific(gGLKey)); - } -#endif - - -struct prims_t { - typedef ogles_context_t* GL; - void (*renderPoint)(GL, vertex_t*); - void (*renderLine)(GL, vertex_t*, vertex_t*); - void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*); -}; - -struct ogles_context_t { - context_t rasterizer; - array_machine_t arrays __attribute__((aligned(32))); - texture_state_t textures; - transform_state_t transforms; - vertex_cache_t vc; - prims_t prims; - culling_t cull; - lighting_t lighting; - user_clip_planes_t clipPlanes; - compute_iterators_t lerp __attribute__((aligned(32))); - vertex_t current; - vec4_t currentColorClamped; - vec3_t currentNormal; - viewport_t viewport; - point_size_t point; - line_width_t line; - polygon_offset_t polygonOffset; - fog_t fog; - uint32_t perspective : 1; - uint32_t transformTextures : 1; - EGLSurfaceManager* surfaceManager; - EGLBufferObjectManager* bufferObjectManager; - - GLenum error; - - static inline ogles_context_t* get() { - return getGlThreadSpecific(); - } - -}; - -}; // namespace gl -}; // namespace android - -using namespace android::gl; - -#endif // ANDROID_OPENGLES_CONTEXT_H - diff --git a/opengl/libagl/dxt.cpp b/opengl/libagl/dxt.cpp deleted file mode 100644 index 238c81fae9..0000000000 --- a/opengl/libagl/dxt.cpp +++ /dev/null @@ -1,636 +0,0 @@ -/* libs/opengles/dxt.cpp -** -** Copyright 2007, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#define TIMING 0 - -#if TIMING -#include // for optimization timing -#include -#include -#endif - -#include -#include - -#include "context.h" - -#define TIMING 0 - -namespace android { - -static uint8_t avg23tab[64*64]; -static volatile int tables_initialized = 0; - -// Definitions below are equivalent to these over the valid range of arguments -// #define div5(x) ((x)/5) -// #define div7(x) ((x)/7) - -// Use fixed-point to divide by 5 and 7 -// 3277 = 2^14/5 + 1 -// 2341 = 2^14/7 + 1 -#define div5(x) (((x)*3277) >> 14) -#define div7(x) (((x)*2341) >> 14) - -// Table with entry [a << 6 | b] = (2*a + b)/3 for 0 <= a,b < 64 -#define avg23(x0,x1) avg23tab[((x0) << 6) | (x1)] - -// Extract 5/6/5 RGB -#define red(x) (((x) >> 11) & 0x1f) -#define green(x) (((x) >> 5) & 0x3f) -#define blue(x) ( (x) & 0x1f) - -/* - * Convert 5/6/5 RGB (as 3 ints) to 8/8/8 - * - * Operation count: 8 <<, 0 &, 5 | - */ -inline static int rgb565SepTo888(int r, int g, int b) - -{ - return ((((r << 3) | (r >> 2)) << 16) | - (((g << 2) | (g >> 4)) << 8) | - ((b << 3) | (b >> 2))); -} - -/* - * Convert 5/6/5 RGB (as a single 16-bit word) to 8/8/8 - * - * r4r3r2r1 r0g5g4g3 g2g1g0b4 b3b2b1b0 rgb - * r4r3r2 r1r0g5g4 g3g2g1g0 b4b3b2b1 b0 0 0 0 rgb << 3 - * r4r3r2r1 r0r4r3r2 g5g4g3g2 g1g0g5g4 b4b3b2b1 b0b4b3b2 desired result - * - * Construct the 24-bit RGB word as: - * - * r4r3r2r1 r0------ -------- -------- -------- -------- (rgb << 8) & 0xf80000 - * r4r3r2 -------- -------- -------- -------- (rgb << 3) & 0x070000 - * g5g4g3g2 g1g0---- -------- -------- (rgb << 5) & 0x00fc00 - * g5g4 -------- -------- (rgb >> 1) & 0x000300 - * b4b3b2b1 b0------ (rgb << 3) & 0x0000f8 - * b4b3b2 (rgb >> 2) & 0x000007 - * - * Operation count: 5 <<, 6 &, 5 | (n.b. rgb >> 3 is used twice) - */ -inline static int rgb565To888(int rgb) - -{ - int rgb3 = rgb >> 3; - return (((rgb << 8) & 0xf80000) | - ( rgb3 & 0x070000) | - ((rgb << 5) & 0x00fc00) | - ((rgb >> 1) & 0x000300) | - ( rgb3 & 0x0000f8) | - ((rgb >> 2) & 0x000007)); -} - -#if __BYTE_ORDER == __BIG_ENDIAN -static uint32_t swap(uint32_t x) { - int b0 = (x >> 24) & 0xff; - int b1 = (x >> 16) & 0xff; - int b2 = (x >> 8) & 0xff; - int b3 = (x ) & 0xff; - - return (uint32_t)((b3 << 24) | (b2 << 16) | (b1 << 8) | b0); -} -#endif - -static void -init_tables() -{ - if (tables_initialized) { - return; - } - - for (int i = 0; i < 64; i++) { - for (int j = 0; j < 64; j++) { - int avg = (2*i + j)/3; - avg23tab[(i << 6) | j] = avg; - } - } - - asm volatile ("" : : : "memory"); - tables_initialized = 1; -} - -/* - * Utility to scan a DXT1 compressed texture to determine whether it - * contains a transparent pixel (color0 < color1, code == 3). This - * may be useful if the application lacks information as to whether - * the true format is GL_COMPRESSED_RGB_S3TC_DXT1_EXT or - * GL_COMPRESSED_RGBA_S3TC_DXT1_EXT. - */ -bool -DXT1HasAlpha(const GLvoid *data, int width, int height) { -#if TIMING - struct timeval start_t, end_t; - struct timezone tz; - - gettimeofday(&start_t, &tz); -#endif - - bool hasAlpha = false; - - int xblocks = (width + 3)/4; - int yblocks = (height + 3)/4; - int numblocks = xblocks*yblocks; - - uint32_t const *d32 = (uint32_t *)data; - for (int b = 0; b < numblocks; b++) { - uint32_t colors = *d32++; - -#if __BYTE_ORDER == __BIG_ENDIAN - colors = swap(colors); -#endif - - uint16_t color0 = colors & 0xffff; - uint16_t color1 = colors >> 16; - - if (color0 < color1) { - // There's no need to endian-swap within 'bits' - // since we don't care which pixel is the transparent one - uint32_t bits = *d32++; - - // Detect if any (odd, even) pair of bits are '11' - // bits: b31 b30 b29 ... b3 b2 b1 b0 - // bits >> 1: b31 b31 b30 ... b4 b3 b2 b1 - // &: b31 (b31 & b30) (b29 & b28) ... (b2 & b1) (b1 & b0) - // & 0x55..: 0 (b31 & b30) 0 ... 0 (b1 & b0) - if (((bits & (bits >> 1)) & 0x55555555) != 0) { - hasAlpha = true; - goto done; - } - } else { - // Skip 4 bytes - ++d32; - } - } - - done: -#if TIMING - gettimeofday(&end_t, &tz); - long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 + - (end_t.tv_usec - start_t.tv_usec); - - printf("Scanned w=%d h=%d in %ld usec\n", width, height, usec); -#endif - - return hasAlpha; -} - -static void -decodeDXT1(const GLvoid *data, int width, int height, - void *surface, int stride, - bool hasAlpha) - -{ - init_tables(); - - uint32_t const *d32 = (uint32_t *)data; - - // Color table for the current block - uint16_t c[4]; - c[0] = c[1] = c[2] = c[3] = 0; - - // Specified colors from the previous block - uint16_t prev_color0 = 0x0000; - uint16_t prev_color1 = 0x0000; - - uint16_t* rowPtr = (uint16_t*)surface; - for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) { - uint16_t *blockPtr = rowPtr; - for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) { - uint32_t colors = *d32++; - uint32_t bits = *d32++; - -#if __BYTE_ORDER == __BIG_ENDIAN - colors = swap(colors); - bits = swap(bits); -#endif - - // Raw colors - uint16_t color0 = colors & 0xffff; - uint16_t color1 = colors >> 16; - - // If the new block has the same base colors as the - // previous one, we don't need to recompute the color - // table c[] - if (color0 != prev_color0 || color1 != prev_color1) { - // Store raw colors for comparison with next block - prev_color0 = color0; - prev_color1 = color1; - - int r0 = red(color0); - int g0 = green(color0); - int b0 = blue(color0); - - int r1 = red(color1); - int g1 = green(color1); - int b1 = blue(color1); - - if (hasAlpha) { - c[0] = (r0 << 11) | ((g0 >> 1) << 6) | (b0 << 1) | 0x1; - c[1] = (r1 << 11) | ((g1 >> 1) << 6) | (b1 << 1) | 0x1; - } else { - c[0] = color0; - c[1] = color1; - } - - int r2, g2, b2, r3, g3, b3, a3; - - int bbits = bits >> 1; - bool has2 = ((bbits & ~bits) & 0x55555555) != 0; - bool has3 = ((bbits & bits) & 0x55555555) != 0; - - if (has2 || has3) { - if (color0 > color1) { - r2 = avg23(r0, r1); - g2 = avg23(g0, g1); - b2 = avg23(b0, b1); - - r3 = avg23(r1, r0); - g3 = avg23(g1, g0); - b3 = avg23(b1, b0); - a3 = 1; - } else { - r2 = (r0 + r1) >> 1; - g2 = (g0 + g1) >> 1; - b2 = (b0 + b1) >> 1; - - r3 = g3 = b3 = a3 = 0; - } - if (hasAlpha) { - c[2] = (r2 << 11) | ((g2 >> 1) << 6) | - (b2 << 1) | 0x1; - c[3] = (r3 << 11) | ((g3 >> 1) << 6) | - (b3 << 1) | a3; - } else { - c[2] = (r2 << 11) | (g2 << 5) | b2; - c[3] = (r3 << 11) | (g3 << 5) | b3; - } - } - } - - uint16_t* blockRowPtr = blockPtr; - for (int y = 0; y < 4; y++, blockRowPtr += stride) { - // Don't process rows past the botom - if (base_y + y >= height) { - break; - } - - int w = min(width - base_x, 4); - for (int x = 0; x < w; x++) { - int code = bits & 0x3; - bits >>= 2; - - blockRowPtr[x] = c[code]; - } - } - } - } -} - -// Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE -static void -decodeDXT3(const GLvoid *data, int width, int height, - void *surface, int stride) - -{ - init_tables(); - - uint32_t const *d32 = (uint32_t *)data; - - // Specified colors from the previous block - uint16_t prev_color0 = 0x0000; - uint16_t prev_color1 = 0x0000; - - // Color table for the current block - uint32_t c[4]; - c[0] = c[1] = c[2] = c[3] = 0; - - uint32_t* rowPtr = (uint32_t*)surface; - for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) { - uint32_t *blockPtr = rowPtr; - for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) { - -#if __BYTE_ORDER == __BIG_ENDIAN - uint32_t alphahi = *d32++; - uint32_t alphalo = *d32++; - alphahi = swap(alphahi); - alphalo = swap(alphalo); -#else - uint32_t alphalo = *d32++; - uint32_t alphahi = *d32++; -#endif - - uint32_t colors = *d32++; - uint32_t bits = *d32++; - -#if __BYTE_ORDER == __BIG_ENDIAN - colors = swap(colors); - bits = swap(bits); -#endif - - uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo; - - // Raw colors - uint16_t color0 = colors & 0xffff; - uint16_t color1 = colors >> 16; - - // If the new block has the same base colors as the - // previous one, we don't need to recompute the color - // table c[] - if (color0 != prev_color0 || color1 != prev_color1) { - // Store raw colors for comparison with next block - prev_color0 = color0; - prev_color1 = color1; - - int bbits = bits >> 1; - bool has2 = ((bbits & ~bits) & 0x55555555) != 0; - bool has3 = ((bbits & bits) & 0x55555555) != 0; - - if (has2 || has3) { - int r0 = red(color0); - int g0 = green(color0); - int b0 = blue(color0); - - int r1 = red(color1); - int g1 = green(color1); - int b1 = blue(color1); - - int r2 = avg23(r0, r1); - int g2 = avg23(g0, g1); - int b2 = avg23(b0, b1); - - int r3 = avg23(r1, r0); - int g3 = avg23(g1, g0); - int b3 = avg23(b1, b0); - - c[0] = rgb565SepTo888(r0, g0, b0); - c[1] = rgb565SepTo888(r1, g1, b1); - c[2] = rgb565SepTo888(r2, g2, b2); - c[3] = rgb565SepTo888(r3, g3, b3); - } else { - // Convert to 8 bits - c[0] = rgb565To888(color0); - c[1] = rgb565To888(color1); - } - } - - uint32_t* blockRowPtr = blockPtr; - for (int y = 0; y < 4; y++, blockRowPtr += stride) { - // Don't process rows past the botom - if (base_y + y >= height) { - break; - } - - int w = min(width - base_x, 4); - for (int x = 0; x < w; x++) { - int a = alpha & 0xf; - alpha >>= 4; - - int code = bits & 0x3; - bits >>= 2; - - blockRowPtr[x] = c[code] | (a << 28) | (a << 24); - } - } - } - } -} - -// Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE -static void -decodeDXT5(const GLvoid *data, int width, int height, - void *surface, int stride) - -{ - init_tables(); - - uint32_t const *d32 = (uint32_t *)data; - - // Specified alphas from the previous block - uint8_t prev_alpha0 = 0x00; - uint8_t prev_alpha1 = 0x00; - - // Specified colors from the previous block - uint16_t prev_color0 = 0x0000; - uint16_t prev_color1 = 0x0000; - - // Alpha table for the current block - uint8_t a[8]; - a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = 0; - - // Color table for the current block - uint32_t c[4]; - c[0] = c[1] = c[2] = c[3] = 0; - - int good_a5 = 0; - int bad_a5 = 0; - int good_a6 = 0; - int bad_a6 = 0; - int good_a7 = 0; - int bad_a7 = 0; - - uint32_t* rowPtr = (uint32_t*)surface; - for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) { - uint32_t *blockPtr = rowPtr; - for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) { - -#if __BYTE_ORDER == __BIG_ENDIAN - uint32_t alphahi = *d32++; - uint32_t alphalo = *d32++; - alphahi = swap(alphahi); - alphalo = swap(alphalo); -#else - uint32_t alphalo = *d32++; - uint32_t alphahi = *d32++; -#endif - - uint32_t colors = *d32++; - uint32_t bits = *d32++; - -#if __BYTE_ORDER == __BIG_ENDIANx - colors = swap(colors); - bits = swap(bits); -#endif - - uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo; - uint64_t alpha0 = alpha & 0xff; - alpha >>= 8; - uint64_t alpha1 = alpha & 0xff; - alpha >>= 8; - - if (alpha0 != prev_alpha0 || alpha1 != prev_alpha1) { - prev_alpha0 = alpha0; - prev_alpha1 = alpha1; - - a[0] = alpha0; - a[1] = alpha1; - int a01 = alpha0 + alpha1 - 1; - if (alpha0 > alpha1) { - a[2] = div7(6*alpha0 + alpha1); - a[4] = div7(4*alpha0 + 3*alpha1); - a[6] = div7(2*alpha0 + 5*alpha1); - - // Use symmetry to derive half of the values - // A few values will be off by 1 (~.5%) - // Alternate which values are computed directly - // and which are derived to try to reduce bias - a[3] = a01 - a[6]; - a[5] = a01 - a[4]; - a[7] = a01 - a[2]; - } else { - a[2] = div5(4*alpha0 + alpha1); - a[4] = div5(2*alpha0 + 3*alpha1); - a[3] = a01 - a[4]; - a[5] = a01 - a[2]; - a[6] = 0x00; - a[7] = 0xff; - } - } - - // Raw colors - uint16_t color0 = colors & 0xffff; - uint16_t color1 = colors >> 16; - - // If the new block has the same base colors as the - // previous one, we don't need to recompute the color - // table c[] - if (color0 != prev_color0 || color1 != prev_color1) { - // Store raw colors for comparison with next block - prev_color0 = color0; - prev_color1 = color1; - - int bbits = bits >> 1; - bool has2 = ((bbits & ~bits) & 0x55555555) != 0; - bool has3 = ((bbits & bits) & 0x55555555) != 0; - - if (has2 || has3) { - int r0 = red(color0); - int g0 = green(color0); - int b0 = blue(color0); - - int r1 = red(color1); - int g1 = green(color1); - int b1 = blue(color1); - - int r2 = avg23(r0, r1); - int g2 = avg23(g0, g1); - int b2 = avg23(b0, b1); - - int r3 = avg23(r1, r0); - int g3 = avg23(g1, g0); - int b3 = avg23(b1, b0); - - c[0] = rgb565SepTo888(r0, g0, b0); - c[1] = rgb565SepTo888(r1, g1, b1); - c[2] = rgb565SepTo888(r2, g2, b2); - c[3] = rgb565SepTo888(r3, g3, b3); - } else { - // Convert to 8 bits - c[0] = rgb565To888(color0); - c[1] = rgb565To888(color1); - } - } - - uint32_t* blockRowPtr = blockPtr; - for (int y = 0; y < 4; y++, blockRowPtr += stride) { - // Don't process rows past the botom - if (base_y + y >= height) { - break; - } - - int w = min(width - base_x, 4); - for (int x = 0; x < w; x++) { - int acode = alpha & 0x7; - alpha >>= 3; - - int code = bits & 0x3; - bits >>= 2; - - blockRowPtr[x] = c[code] | (a[acode] << 24); - } - } - } - } -} - -/* - * Decode a DXT-compressed texture into memory. DXT textures consist of - * a series of 4x4 pixel blocks in left-to-right, top-down order. - * The number of blocks is given by ceil(width/4)*ceil(height/4). - * - * 'data' points to the texture data. 'width' and 'height' indicate the - * dimensions of the texture. We assume width and height are >= 0 but - * do not require them to be powers of 2 or divisible by any factor. - * - * The output is written to 'surface' with each scanline separated by - * 'stride' 2- or 4-byte words. - * - * 'format' indicates the type of compression and must be one of the following: - * - * GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - * The output is written as 5/6/5 opaque RGB (16 bit words). - * 8 bytes are read from 'data' for each block. - * - * GL_COMPRESSED_RGBA_S3TC_DXT1_EXT - * The output is written as 5/5/5/1 RGBA (16 bit words) - * 8 bytes are read from 'data' for each block. - * - * GL_COMPRESSED_RGBA_S3TC_DXT3_EXT - * GL_COMPRESSED_RGBA_S3TC_DXT5_EXT - * The output is written as 8/8/8/8 ARGB (32 bit words) - * 16 bytes are read from 'data' for each block. - */ -void -decodeDXT(const GLvoid *data, int width, int height, - void *surface, int stride, int format) -{ -#if TIMING - struct timeval start_t, end_t; - struct timezone tz; - - gettimeofday(&start_t, &tz); -#endif - - switch (format) { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - decodeDXT1(data, width, height, surface, stride, false); - break; - - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - decodeDXT1(data, width, height, surface, stride, true); - break; - - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - decodeDXT3(data, width, height, surface, stride); - break; - - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - decodeDXT5(data, width, height, surface, stride); - break; - } - -#if TIMING - gettimeofday(&end_t, &tz); - long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 + - (end_t.tv_usec - start_t.tv_usec); - - printf("Loaded w=%d h=%d in %ld usec\n", width, height, usec); -#endif -} - -} // namespace android diff --git a/opengl/libagl/dxt.h b/opengl/libagl/dxt.h deleted file mode 100644 index d95a36cd1a..0000000000 --- a/opengl/libagl/dxt.h +++ /dev/null @@ -1,33 +0,0 @@ -/* libs/opengles/dxt.h -** -** Copyright 2007, 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_OPENGLES_TEXTURE_H -#define ANDROID_OPENGLES_TEXTURE_H - -#include - -#include - -namespace android { - - bool DXT1HasAlpha(const GLvoid *data, int width, int height); - void decodeDXT(const GLvoid *data, int width, int height, - void *surface, int stride, int format); - -} // namespace android - -#endif // ANDROID_OPENGLES_TEXTURE_H diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp deleted file mode 100644 index be437054ce..0000000000 --- a/opengl/libagl/egl.cpp +++ /dev/null @@ -1,2230 +0,0 @@ -/* -** -** Copyright 2007 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "context.h" -#include "state.h" -#include "texture.h" -#include "matrix.h" - -#undef NELEM -#define NELEM(x) (sizeof(x)/sizeof(*(x))) - -// ---------------------------------------------------------------------------- - -EGLBoolean EGLAPI eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, - EGLint left, EGLint top, EGLint width, EGLint height); - - -typedef struct egl_native_pixmap_t -{ - int32_t version; /* must be 32 */ - int32_t width; - int32_t height; - int32_t stride; - uint8_t* data; - uint8_t format; - uint8_t rfu[3]; - union { - uint32_t compressedFormat; - int32_t vstride; - }; - int32_t reserved; -} egl_native_pixmap_t; - - -// ---------------------------------------------------------------------------- -namespace android { - -// ---------------------------------------------------------------------------- - -const unsigned int NUM_DISPLAYS = 1; - -#ifndef __ANDROID__ -static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER; -#endif -static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_key_t gEGLErrorKey = -1; -#ifndef __ANDROID__ -namespace gl { -pthread_key_t gGLKey = -1; -}; // namespace gl -#endif - -template -static T setError(GLint error, T returnValue) { - if (ggl_unlikely(gEGLErrorKey == -1)) { - pthread_mutex_lock(&gErrorKeyMutex); - if (gEGLErrorKey == -1) - pthread_key_create(&gEGLErrorKey, NULL); - pthread_mutex_unlock(&gErrorKeyMutex); - } - pthread_setspecific(gEGLErrorKey, (void*)(uintptr_t)error); - return returnValue; -} - -static GLint getError() { - if (ggl_unlikely(gEGLErrorKey == -1)) - return EGL_SUCCESS; - GLint error = (GLint)(uintptr_t)pthread_getspecific(gEGLErrorKey); - if (error == 0) { - // The TLS key has been created by another thread, but the value for - // this thread has not been initialized. - return EGL_SUCCESS; - } - pthread_setspecific(gEGLErrorKey, (void*)(uintptr_t)EGL_SUCCESS); - return error; -} - -// ---------------------------------------------------------------------------- - -struct egl_display_t -{ - egl_display_t() : type(0), initialized(0) { } - - static egl_display_t& get_display(EGLDisplay dpy); - - static EGLBoolean is_valid(EGLDisplay dpy) { - return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE; - } - - NativeDisplayType type; - std::atomic_size_t initialized; -}; - -static egl_display_t gDisplays[NUM_DISPLAYS]; - -egl_display_t& egl_display_t::get_display(EGLDisplay dpy) { - return gDisplays[uintptr_t(dpy)-1U]; -} - -struct egl_context_t { - enum { - IS_CURRENT = 0x00010000, - NEVER_CURRENT = 0x00020000 - }; - uint32_t flags; - EGLDisplay dpy; - EGLConfig config; - EGLSurface read; - EGLSurface draw; - - static inline egl_context_t* context(EGLContext ctx) { - ogles_context_t* const gl = static_cast(ctx); - return static_cast(gl->rasterizer.base); - } -}; - -// ---------------------------------------------------------------------------- - -struct egl_surface_t -{ - enum { - PAGE_FLIP = 0x00000001, - MAGIC = 0x31415265 - }; - - uint32_t magic; - EGLDisplay dpy; - EGLConfig config; - EGLContext ctx; - bool zombie; - - egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat); - virtual ~egl_surface_t(); - bool isValid() const; - virtual bool initCheck() const = 0; - - virtual EGLBoolean bindDrawSurface(ogles_context_t* gl) = 0; - virtual EGLBoolean bindReadSurface(ogles_context_t* gl) = 0; - virtual EGLBoolean connect() { return EGL_TRUE; } - virtual void disconnect() {} - virtual EGLint getWidth() const = 0; - virtual EGLint getHeight() const = 0; - - virtual EGLint getHorizontalResolution() const; - virtual EGLint getVerticalResolution() const; - virtual EGLint getRefreshRate() const; - virtual EGLint getSwapBehavior() const; - virtual EGLBoolean swapBuffers(); - virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h); -protected: - GGLSurface depth; -}; - -egl_surface_t::egl_surface_t(EGLDisplay dpy, - EGLConfig config, - int32_t depthFormat) - : magic(MAGIC), dpy(dpy), config(config), ctx(0), zombie(false) -{ - depth.version = sizeof(GGLSurface); - depth.data = 0; - depth.format = depthFormat; -} -egl_surface_t::~egl_surface_t() -{ - magic = 0; - free(depth.data); -} -bool egl_surface_t::isValid() const { - ALOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this); - return magic == MAGIC; -} - -EGLBoolean egl_surface_t::swapBuffers() { - return EGL_FALSE; -} -EGLint egl_surface_t::getHorizontalResolution() const { - return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f); -} -EGLint egl_surface_t::getVerticalResolution() const { - return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f); -} -EGLint egl_surface_t::getRefreshRate() const { - return (60 * EGL_DISPLAY_SCALING); -} -EGLint egl_surface_t::getSwapBehavior() const { - return EGL_BUFFER_PRESERVED; -} -EGLBoolean egl_surface_t::setSwapRectangle( - EGLint /*l*/, EGLint /*t*/, EGLint /*w*/, EGLint /*h*/) -{ - return EGL_FALSE; -} - -// ---------------------------------------------------------------------------- - -struct egl_window_surface_v2_t : public egl_surface_t -{ - egl_window_surface_v2_t( - EGLDisplay dpy, EGLConfig config, - int32_t depthFormat, - ANativeWindow* window); - - ~egl_window_surface_v2_t(); - - virtual bool initCheck() const { return true; } // TODO: report failure if ctor fails - virtual EGLBoolean swapBuffers(); - virtual EGLBoolean bindDrawSurface(ogles_context_t* gl); - virtual EGLBoolean bindReadSurface(ogles_context_t* gl); - virtual EGLBoolean connect(); - virtual void disconnect(); - virtual EGLint getWidth() const { return width; } - virtual EGLint getHeight() const { return height; } - virtual EGLint getHorizontalResolution() const; - virtual EGLint getVerticalResolution() const; - virtual EGLint getRefreshRate() const; - virtual EGLint getSwapBehavior() const; - virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h); - -private: - status_t lock(ANativeWindowBuffer* buf, int usage, void** vaddr); - status_t unlock(ANativeWindowBuffer* buf); - ANativeWindow* nativeWindow; - ANativeWindowBuffer* buffer; - ANativeWindowBuffer* previousBuffer; - int width; - int height; - void* bits; - GGLFormat const* pixelFormatTable; - - struct Rect { - inline Rect() { }; - inline Rect(int32_t w, int32_t h) - : left(0), top(0), right(w), bottom(h) { } - inline Rect(int32_t l, int32_t t, int32_t r, int32_t b) - : left(l), top(t), right(r), bottom(b) { } - Rect& andSelf(const Rect& r) { - left = max(left, r.left); - top = max(top, r.top); - right = min(right, r.right); - bottom = min(bottom, r.bottom); - return *this; - } - bool isEmpty() const { - return (left>=right || top>=bottom); - } - void dump(char const* what) { - ALOGD("%s { %5d, %5d, w=%5d, h=%5d }", - what, left, top, right-left, bottom-top); - } - - int32_t left; - int32_t top; - int32_t right; - int32_t bottom; - }; - - struct Region { - inline Region() : count(0) { } - typedef Rect const* const_iterator; - const_iterator begin() const { return storage; } - const_iterator end() const { return storage+count; } - static Region subtract(const Rect& lhs, const Rect& rhs) { - Region reg; - Rect* storage = reg.storage; - if (!lhs.isEmpty()) { - if (lhs.top < rhs.top) { // top rect - storage->left = lhs.left; - storage->top = lhs.top; - storage->right = lhs.right; - storage->bottom = rhs.top; - storage++; - } - const int32_t top = max(lhs.top, rhs.top); - const int32_t bot = min(lhs.bottom, rhs.bottom); - if (top < bot) { - if (lhs.left < rhs.left) { // left-side rect - storage->left = lhs.left; - storage->top = top; - storage->right = rhs.left; - storage->bottom = bot; - storage++; - } - if (lhs.right > rhs.right) { // right-side rect - storage->left = rhs.right; - storage->top = top; - storage->right = lhs.right; - storage->bottom = bot; - storage++; - } - } - if (lhs.bottom > rhs.bottom) { // bottom rect - storage->left = lhs.left; - storage->top = rhs.bottom; - storage->right = lhs.right; - storage->bottom = lhs.bottom; - storage++; - } - reg.count = storage - reg.storage; - } - return reg; - } - bool isEmpty() const { - return count<=0; - } - private: - Rect storage[4]; - ssize_t count; - }; - - void copyBlt( - ANativeWindowBuffer* dst, void* dst_vaddr, - ANativeWindowBuffer* src, void const* src_vaddr, - const Region& clip); - - Rect dirtyRegion; - Rect oldDirtyRegion; -}; - -egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy, - EGLConfig config, - int32_t depthFormat, - ANativeWindow* window) - : egl_surface_t(dpy, config, depthFormat), - nativeWindow(window), buffer(0), previousBuffer(0), bits(NULL) -{ - - pixelFormatTable = gglGetPixelFormatTable(); - - // keep a reference on the window - nativeWindow->common.incRef(&nativeWindow->common); - nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width); - nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height); -} - -egl_window_surface_v2_t::~egl_window_surface_v2_t() { - if (buffer) { - buffer->common.decRef(&buffer->common); - } - if (previousBuffer) { - previousBuffer->common.decRef(&previousBuffer->common); - } - nativeWindow->common.decRef(&nativeWindow->common); -} - -EGLBoolean egl_window_surface_v2_t::connect() -{ - // we're intending to do software rendering - native_window_set_usage(nativeWindow, - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); - - // dequeue a buffer - int fenceFd = -1; - if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, - &fenceFd) != NO_ERROR) { - return setError(EGL_BAD_ALLOC, EGL_FALSE); - } - - // wait for the buffer - sp fence(new Fence(fenceFd)); - if (fence->wait(Fence::TIMEOUT_NEVER) != NO_ERROR) { - nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd); - return setError(EGL_BAD_ALLOC, EGL_FALSE); - } - - // allocate a corresponding depth-buffer - width = buffer->width; - height = buffer->height; - if (depth.format) { - depth.width = width; - depth.height = height; - depth.stride = depth.width; // use the width here - uint64_t allocSize = static_cast(depth.stride) * - static_cast(depth.height) * 2; - if (depth.stride < 0 || depth.height > INT_MAX || - allocSize > UINT32_MAX) { - return setError(EGL_BAD_ALLOC, EGL_FALSE); - } - depth.data = (GGLubyte*)malloc(allocSize); - if (depth.data == 0) { - return setError(EGL_BAD_ALLOC, EGL_FALSE); - } - } - - // keep a reference on the buffer - buffer->common.incRef(&buffer->common); - - // pin the buffer down - if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN | - GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) { - ALOGE("connect() failed to lock buffer %p (%ux%u)", - buffer, buffer->width, buffer->height); - return setError(EGL_BAD_ACCESS, EGL_FALSE); - // FIXME: we should make sure we're not accessing the buffer anymore - } - return EGL_TRUE; -} - -void egl_window_surface_v2_t::disconnect() -{ - if (buffer && bits) { - bits = NULL; - unlock(buffer); - } - if (buffer) { - nativeWindow->cancelBuffer(nativeWindow, buffer, -1); - buffer->common.decRef(&buffer->common); - buffer = 0; - } - if (previousBuffer) { - previousBuffer->common.decRef(&previousBuffer->common); - previousBuffer = 0; - } -} - -status_t egl_window_surface_v2_t::lock( - ANativeWindowBuffer* buf, int usage, void** vaddr) -{ - auto& mapper = GraphicBufferMapper::get(); - return mapper.lock(buf->handle, usage, - android::Rect(buf->width, buf->height), vaddr); -} - -status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf) -{ - if (!buf) return BAD_VALUE; - auto& mapper = GraphicBufferMapper::get(); - return mapper.unlock(buf->handle); -} - -void egl_window_surface_v2_t::copyBlt( - ANativeWindowBuffer* dst, void* dst_vaddr, - ANativeWindowBuffer* src, void const* src_vaddr, - const Region& clip) -{ - // NOTE: dst and src must be the same format - - Region::const_iterator cur = clip.begin(); - Region::const_iterator end = clip.end(); - - const size_t bpp = pixelFormatTable[src->format].size; - const size_t dbpr = dst->stride * bpp; - const size_t sbpr = src->stride * bpp; - - uint8_t const * const src_bits = (uint8_t const *)src_vaddr; - uint8_t * const dst_bits = (uint8_t *)dst_vaddr; - - while (cur != end) { - const Rect& r(*cur++); - ssize_t w = r.right - r.left; - ssize_t h = r.bottom - r.top; - if (w <= 0 || h<=0) continue; - size_t size = w * bpp; - uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp; - uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp; - if (dbpr==sbpr && size==sbpr) { - size *= h; - h = 1; - } - do { - memcpy(d, s, size); - d += dbpr; - s += sbpr; - } while (--h > 0); - } -} - -EGLBoolean egl_window_surface_v2_t::swapBuffers() -{ - if (!buffer) { - return setError(EGL_BAD_ACCESS, EGL_FALSE); - } - - /* - * Handle eglSetSwapRectangleANDROID() - * We copyback from the front buffer - */ - if (!dirtyRegion.isEmpty()) { - dirtyRegion.andSelf(Rect(buffer->width, buffer->height)); - if (previousBuffer) { - // This was const Region copyBack, but that causes an - // internal compile error on simulator builds - /*const*/ Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion)); - if (!copyBack.isEmpty()) { - void* prevBits; - if (lock(previousBuffer, - GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) { - // copy from previousBuffer to buffer - copyBlt(buffer, bits, previousBuffer, prevBits, copyBack); - unlock(previousBuffer); - } - } - } - oldDirtyRegion = dirtyRegion; - } - - if (previousBuffer) { - previousBuffer->common.decRef(&previousBuffer->common); - previousBuffer = 0; - } - - unlock(buffer); - previousBuffer = buffer; - nativeWindow->queueBuffer(nativeWindow, buffer, -1); - buffer = 0; - - // dequeue a new buffer - int fenceFd = -1; - if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd) == NO_ERROR) { - sp fence(new Fence(fenceFd)); - if (fence->wait(Fence::TIMEOUT_NEVER)) { - nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd); - return setError(EGL_BAD_ALLOC, EGL_FALSE); - } - - // reallocate the depth-buffer if needed - if ((width != buffer->width) || (height != buffer->height)) { - // TODO: we probably should reset the swap rect here - // if the window size has changed - width = buffer->width; - height = buffer->height; - if (depth.data) { - free(depth.data); - depth.width = width; - depth.height = height; - depth.stride = buffer->stride; - uint64_t allocSize = static_cast(depth.stride) * - static_cast(depth.height) * 2; - if (depth.stride < 0 || depth.height > INT_MAX || - allocSize > UINT32_MAX) { - setError(EGL_BAD_ALLOC, EGL_FALSE); - return EGL_FALSE; - } - depth.data = (GGLubyte*)malloc(allocSize); - if (depth.data == 0) { - setError(EGL_BAD_ALLOC, EGL_FALSE); - return EGL_FALSE; - } - } - } - - // keep a reference on the buffer - buffer->common.incRef(&buffer->common); - - // finally pin the buffer down - if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN | - GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) { - ALOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)", - buffer, buffer->width, buffer->height); - return setError(EGL_BAD_ACCESS, EGL_FALSE); - // FIXME: we should make sure we're not accessing the buffer anymore - } - } else { - return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE); - } - - return EGL_TRUE; -} - -EGLBoolean egl_window_surface_v2_t::setSwapRectangle( - EGLint l, EGLint t, EGLint w, EGLint h) -{ - dirtyRegion = Rect(l, t, l+w, t+h); - return EGL_TRUE; -} - -EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl) -{ - GGLSurface buffer; - buffer.version = sizeof(GGLSurface); - buffer.width = this->buffer->width; - buffer.height = this->buffer->height; - buffer.stride = this->buffer->stride; - buffer.data = (GGLubyte*)bits; - buffer.format = this->buffer->format; - gl->rasterizer.procs.colorBuffer(gl, &buffer); - if (depth.data != gl->rasterizer.state.buffers.depth.data) - gl->rasterizer.procs.depthBuffer(gl, &depth); - - return EGL_TRUE; -} -EGLBoolean egl_window_surface_v2_t::bindReadSurface(ogles_context_t* gl) -{ - GGLSurface buffer; - buffer.version = sizeof(GGLSurface); - buffer.width = this->buffer->width; - buffer.height = this->buffer->height; - buffer.stride = this->buffer->stride; - buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!! - buffer.format = this->buffer->format; - gl->rasterizer.procs.readBuffer(gl, &buffer); - return EGL_TRUE; -} -EGLint egl_window_surface_v2_t::getHorizontalResolution() const { - return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f); -} -EGLint egl_window_surface_v2_t::getVerticalResolution() const { - return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f); -} -EGLint egl_window_surface_v2_t::getRefreshRate() const { - return (60 * EGL_DISPLAY_SCALING); // FIXME -} -EGLint egl_window_surface_v2_t::getSwapBehavior() const -{ - /* - * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves - * the content of the swapped buffer. - * - * EGL_BUFFER_DESTROYED means that the content of the buffer is lost. - * - * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED - * only applies to the area specified by eglSetSwapRectangleANDROID(), that - * is, everything outside of this area is preserved. - * - * This implementation of EGL assumes the later case. - * - */ - - return EGL_BUFFER_DESTROYED; -} - -// ---------------------------------------------------------------------------- - -struct egl_pixmap_surface_t : public egl_surface_t -{ - egl_pixmap_surface_t( - EGLDisplay dpy, EGLConfig config, - int32_t depthFormat, - egl_native_pixmap_t const * pixmap); - - virtual ~egl_pixmap_surface_t() { } - - virtual bool initCheck() const { return !depth.format || depth.data!=0; } - virtual EGLBoolean bindDrawSurface(ogles_context_t* gl); - virtual EGLBoolean bindReadSurface(ogles_context_t* gl); - virtual EGLint getWidth() const { return nativePixmap.width; } - virtual EGLint getHeight() const { return nativePixmap.height; } -private: - egl_native_pixmap_t nativePixmap; -}; - -egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy, - EGLConfig config, - int32_t depthFormat, - egl_native_pixmap_t const * pixmap) - : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap) -{ - if (depthFormat) { - depth.width = pixmap->width; - depth.height = pixmap->height; - depth.stride = depth.width; // use the width here - uint64_t allocSize = static_cast(depth.stride) * - static_cast(depth.height) * 2; - if (depth.stride < 0 || depth.height > INT_MAX || - allocSize > UINT32_MAX) { - setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); - return; - } - depth.data = (GGLubyte*)malloc(allocSize); - if (depth.data == 0) { - setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); - } - } -} -EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl) -{ - GGLSurface buffer; - buffer.version = sizeof(GGLSurface); - buffer.width = nativePixmap.width; - buffer.height = nativePixmap.height; - buffer.stride = nativePixmap.stride; - buffer.data = nativePixmap.data; - buffer.format = nativePixmap.format; - - gl->rasterizer.procs.colorBuffer(gl, &buffer); - if (depth.data != gl->rasterizer.state.buffers.depth.data) - gl->rasterizer.procs.depthBuffer(gl, &depth); - return EGL_TRUE; -} -EGLBoolean egl_pixmap_surface_t::bindReadSurface(ogles_context_t* gl) -{ - GGLSurface buffer; - buffer.version = sizeof(GGLSurface); - buffer.width = nativePixmap.width; - buffer.height = nativePixmap.height; - buffer.stride = nativePixmap.stride; - buffer.data = nativePixmap.data; - buffer.format = nativePixmap.format; - gl->rasterizer.procs.readBuffer(gl, &buffer); - return EGL_TRUE; -} - -// ---------------------------------------------------------------------------- - -struct egl_pbuffer_surface_t : public egl_surface_t -{ - egl_pbuffer_surface_t( - EGLDisplay dpy, EGLConfig config, int32_t depthFormat, - int32_t w, int32_t h, int32_t f); - - virtual ~egl_pbuffer_surface_t(); - - virtual bool initCheck() const { return pbuffer.data != 0; } - virtual EGLBoolean bindDrawSurface(ogles_context_t* gl); - virtual EGLBoolean bindReadSurface(ogles_context_t* gl); - virtual EGLint getWidth() const { return pbuffer.width; } - virtual EGLint getHeight() const { return pbuffer.height; } -private: - GGLSurface pbuffer; -}; - -egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, - EGLConfig config, int32_t depthFormat, - int32_t w, int32_t h, int32_t f) - : egl_surface_t(dpy, config, depthFormat) -{ - size_t size = w*h; - switch (f) { - case GGL_PIXEL_FORMAT_A_8: size *= 1; break; - case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break; - case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break; - case GGL_PIXEL_FORMAT_RGBX_8888: size *= 4; break; - case GGL_PIXEL_FORMAT_BGRA_8888: size *= 4; break; - default: - ALOGE("incompatible pixel format for pbuffer (format=%d)", f); - pbuffer.data = 0; - break; - } - pbuffer.version = sizeof(GGLSurface); - pbuffer.width = w; - pbuffer.height = h; - pbuffer.stride = w; - pbuffer.data = (GGLubyte*)malloc(size); - pbuffer.format = f; - - if (depthFormat) { - depth.width = pbuffer.width; - depth.height = pbuffer.height; - depth.stride = depth.width; // use the width here - uint64_t allocSize = static_cast(depth.stride) * - static_cast(depth.height) * 2; - if (depth.stride < 0 || depth.height > INT_MAX || - allocSize > UINT32_MAX) { - setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); - return; - } - depth.data = (GGLubyte*)malloc(allocSize); - if (depth.data == 0) { - setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); - return; - } - } -} -egl_pbuffer_surface_t::~egl_pbuffer_surface_t() { - free(pbuffer.data); -} -EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(ogles_context_t* gl) -{ - gl->rasterizer.procs.colorBuffer(gl, &pbuffer); - if (depth.data != gl->rasterizer.state.buffers.depth.data) - gl->rasterizer.procs.depthBuffer(gl, &depth); - return EGL_TRUE; -} -EGLBoolean egl_pbuffer_surface_t::bindReadSurface(ogles_context_t* gl) -{ - gl->rasterizer.procs.readBuffer(gl, &pbuffer); - return EGL_TRUE; -} - -// ---------------------------------------------------------------------------- - -struct config_pair_t { - GLint key; - GLint value; -}; - -struct configs_t { - const config_pair_t* array; - int size; -}; - -struct config_management_t { - GLint key; - bool (*match)(GLint reqValue, GLint confValue); - static bool atLeast(GLint reqValue, GLint confValue) { - return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue); - } - static bool exact(GLint reqValue, GLint confValue) { - return (reqValue == EGL_DONT_CARE) || (confValue == reqValue); - } - static bool mask(GLint reqValue, GLint confValue) { - return (confValue & reqValue) == reqValue; - } - static bool ignore(GLint /*reqValue*/, GLint /*confValue*/) { - return true; - } -}; - -// ---------------------------------------------------------------------------- - -#define VERSION_MAJOR 1 -#define VERSION_MINOR 2 -static char const * const gVendorString = "Google Inc."; -static char const * const gVersionString = "1.2 Android Driver 1.2.0"; -static char const * const gClientApiString = "OpenGL_ES"; -static char const * const gExtensionsString = - "EGL_KHR_fence_sync " - "EGL_KHR_image_base " - // "KHR_image_pixmap " - "EGL_ANDROID_image_native_buffer " - "EGL_ANDROID_swap_rectangle " - ; - -// ---------------------------------------------------------------------------- - -struct extention_map_t { - const char * const name; - __eglMustCastToProperFunctionPointerType address; -}; - -static const extention_map_t gExtentionMap[] = { - { "glDrawTexsOES", - (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES }, - { "glDrawTexiOES", - (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES }, - { "glDrawTexfOES", - (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES }, - { "glDrawTexxOES", - (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES }, - { "glDrawTexsvOES", - (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES }, - { "glDrawTexivOES", - (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES }, - { "glDrawTexfvOES", - (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES }, - { "glDrawTexxvOES", - (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES }, - { "glQueryMatrixxOES", - (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES }, - { "glEGLImageTargetTexture2DOES", - (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES }, - { "glEGLImageTargetRenderbufferStorageOES", - (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES }, - { "glClipPlanef", - (__eglMustCastToProperFunctionPointerType)&glClipPlanef }, - { "glClipPlanex", - (__eglMustCastToProperFunctionPointerType)&glClipPlanex }, - { "glBindBuffer", - (__eglMustCastToProperFunctionPointerType)&glBindBuffer }, - { "glBufferData", - (__eglMustCastToProperFunctionPointerType)&glBufferData }, - { "glBufferSubData", - (__eglMustCastToProperFunctionPointerType)&glBufferSubData }, - { "glDeleteBuffers", - (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers }, - { "glGenBuffers", - (__eglMustCastToProperFunctionPointerType)&glGenBuffers }, - { "eglCreateImageKHR", - (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR }, - { "eglDestroyImageKHR", - (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR }, - { "eglCreateSyncKHR", - (__eglMustCastToProperFunctionPointerType)&eglCreateSyncKHR }, - { "eglDestroySyncKHR", - (__eglMustCastToProperFunctionPointerType)&eglDestroySyncKHR }, - { "eglClientWaitSyncKHR", - (__eglMustCastToProperFunctionPointerType)&eglClientWaitSyncKHR }, - { "eglGetSyncAttribKHR", - (__eglMustCastToProperFunctionPointerType)&eglGetSyncAttribKHR }, - { "eglSetSwapRectangleANDROID", - (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID }, -}; - -/* - * In the lists below, attributes names MUST be sorted. - * Additionally, all configs must be sorted according to - * the EGL specification. - */ - -static config_pair_t const config_base_attribute_list[] = { - { EGL_STENCIL_SIZE, 0 }, - { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG }, - { EGL_LEVEL, 0 }, - { EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS }, - { EGL_MAX_PBUFFER_PIXELS, - GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS }, - { EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS }, - { EGL_NATIVE_RENDERABLE, EGL_TRUE }, - { EGL_NATIVE_VISUAL_ID, 0 }, - { EGL_NATIVE_VISUAL_TYPE, GGL_PIXEL_FORMAT_RGB_565 }, - { EGL_SAMPLES, 0 }, - { EGL_SAMPLE_BUFFERS, 0 }, - { EGL_TRANSPARENT_TYPE, EGL_NONE }, - { EGL_TRANSPARENT_BLUE_VALUE, 0 }, - { EGL_TRANSPARENT_GREEN_VALUE, 0 }, - { EGL_TRANSPARENT_RED_VALUE, 0 }, - { EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE }, - { EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE }, - { EGL_MIN_SWAP_INTERVAL, 1 }, - { EGL_MAX_SWAP_INTERVAL, 1 }, - { EGL_LUMINANCE_SIZE, 0 }, - { EGL_ALPHA_MASK_SIZE, 0 }, - { EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER }, - { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT }, - { EGL_CONFORMANT, 0 } -}; - -// These configs can override the base attribute list -// NOTE: when adding a config here, don't forget to update eglCreate*Surface() - -// 565 configs -static config_pair_t const config_0_attribute_list[] = { - { EGL_BUFFER_SIZE, 16 }, - { EGL_ALPHA_SIZE, 0 }, - { EGL_BLUE_SIZE, 5 }, - { EGL_GREEN_SIZE, 6 }, - { EGL_RED_SIZE, 5 }, - { EGL_DEPTH_SIZE, 0 }, - { EGL_CONFIG_ID, 0 }, - { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 }, - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, -}; - -static config_pair_t const config_1_attribute_list[] = { - { EGL_BUFFER_SIZE, 16 }, - { EGL_ALPHA_SIZE, 0 }, - { EGL_BLUE_SIZE, 5 }, - { EGL_GREEN_SIZE, 6 }, - { EGL_RED_SIZE, 5 }, - { EGL_DEPTH_SIZE, 16 }, - { EGL_CONFIG_ID, 1 }, - { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 }, - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, -}; - -// RGB 888 configs -static config_pair_t const config_2_attribute_list[] = { - { EGL_BUFFER_SIZE, 32 }, - { EGL_ALPHA_SIZE, 0 }, - { EGL_BLUE_SIZE, 8 }, - { EGL_GREEN_SIZE, 8 }, - { EGL_RED_SIZE, 8 }, - { EGL_DEPTH_SIZE, 0 }, - { EGL_CONFIG_ID, 6 }, - { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 }, - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, -}; - -static config_pair_t const config_3_attribute_list[] = { - { EGL_BUFFER_SIZE, 32 }, - { EGL_ALPHA_SIZE, 0 }, - { EGL_BLUE_SIZE, 8 }, - { EGL_GREEN_SIZE, 8 }, - { EGL_RED_SIZE, 8 }, - { EGL_DEPTH_SIZE, 16 }, - { EGL_CONFIG_ID, 7 }, - { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 }, - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, -}; - -// 8888 configs -static config_pair_t const config_4_attribute_list[] = { - { EGL_BUFFER_SIZE, 32 }, - { EGL_ALPHA_SIZE, 8 }, - { EGL_BLUE_SIZE, 8 }, - { EGL_GREEN_SIZE, 8 }, - { EGL_RED_SIZE, 8 }, - { EGL_DEPTH_SIZE, 0 }, - { EGL_CONFIG_ID, 2 }, - { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 }, - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, -}; - -static config_pair_t const config_5_attribute_list[] = { - { EGL_BUFFER_SIZE, 32 }, - { EGL_ALPHA_SIZE, 8 }, - { EGL_BLUE_SIZE, 8 }, - { EGL_GREEN_SIZE, 8 }, - { EGL_RED_SIZE, 8 }, - { EGL_DEPTH_SIZE, 16 }, - { EGL_CONFIG_ID, 3 }, - { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 }, - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, -}; - -// A8 configs -static config_pair_t const config_6_attribute_list[] = { - { EGL_BUFFER_SIZE, 8 }, - { EGL_ALPHA_SIZE, 8 }, - { EGL_BLUE_SIZE, 0 }, - { EGL_GREEN_SIZE, 0 }, - { EGL_RED_SIZE, 0 }, - { EGL_DEPTH_SIZE, 0 }, - { EGL_CONFIG_ID, 4 }, - { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 }, - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, -}; - -static config_pair_t const config_7_attribute_list[] = { - { EGL_BUFFER_SIZE, 8 }, - { EGL_ALPHA_SIZE, 8 }, - { EGL_BLUE_SIZE, 0 }, - { EGL_GREEN_SIZE, 0 }, - { EGL_RED_SIZE, 0 }, - { EGL_DEPTH_SIZE, 16 }, - { EGL_CONFIG_ID, 5 }, - { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 }, - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, -}; - -// BGRA 8888 config -static config_pair_t const config_8_attribute_list[] = { - { EGL_BUFFER_SIZE, 32 }, - { EGL_ALPHA_SIZE, 8 }, - { EGL_BLUE_SIZE, 8 }, - { EGL_GREEN_SIZE, 8 }, - { EGL_RED_SIZE, 8 }, - { EGL_DEPTH_SIZE, 0 }, - { EGL_CONFIG_ID, 8 }, - { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_BGRA_8888 }, - { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, -}; - -static configs_t const gConfigs[] = { - { config_0_attribute_list, NELEM(config_0_attribute_list) }, - { config_1_attribute_list, NELEM(config_1_attribute_list) }, - { config_2_attribute_list, NELEM(config_2_attribute_list) }, - { config_3_attribute_list, NELEM(config_3_attribute_list) }, - { config_4_attribute_list, NELEM(config_4_attribute_list) }, - { config_5_attribute_list, NELEM(config_5_attribute_list) }, - { config_6_attribute_list, NELEM(config_6_attribute_list) }, - { config_7_attribute_list, NELEM(config_7_attribute_list) }, - { config_8_attribute_list, NELEM(config_8_attribute_list) }, -}; - -static config_management_t const gConfigManagement[] = { - { EGL_BUFFER_SIZE, config_management_t::atLeast }, - { EGL_ALPHA_SIZE, config_management_t::atLeast }, - { EGL_BLUE_SIZE, config_management_t::atLeast }, - { EGL_GREEN_SIZE, config_management_t::atLeast }, - { EGL_RED_SIZE, config_management_t::atLeast }, - { EGL_DEPTH_SIZE, config_management_t::atLeast }, - { EGL_STENCIL_SIZE, config_management_t::atLeast }, - { EGL_CONFIG_CAVEAT, config_management_t::exact }, - { EGL_CONFIG_ID, config_management_t::exact }, - { EGL_LEVEL, config_management_t::exact }, - { EGL_MAX_PBUFFER_HEIGHT, config_management_t::ignore }, - { EGL_MAX_PBUFFER_PIXELS, config_management_t::ignore }, - { EGL_MAX_PBUFFER_WIDTH, config_management_t::ignore }, - { EGL_NATIVE_RENDERABLE, config_management_t::exact }, - { EGL_NATIVE_VISUAL_ID, config_management_t::ignore }, - { EGL_NATIVE_VISUAL_TYPE, config_management_t::exact }, - { EGL_SAMPLES, config_management_t::exact }, - { EGL_SAMPLE_BUFFERS, config_management_t::exact }, - { EGL_SURFACE_TYPE, config_management_t::mask }, - { EGL_TRANSPARENT_TYPE, config_management_t::exact }, - { EGL_TRANSPARENT_BLUE_VALUE, config_management_t::exact }, - { EGL_TRANSPARENT_GREEN_VALUE, config_management_t::exact }, - { EGL_TRANSPARENT_RED_VALUE, config_management_t::exact }, - { EGL_BIND_TO_TEXTURE_RGBA, config_management_t::exact }, - { EGL_BIND_TO_TEXTURE_RGB, config_management_t::exact }, - { EGL_MIN_SWAP_INTERVAL, config_management_t::exact }, - { EGL_MAX_SWAP_INTERVAL, config_management_t::exact }, - { EGL_LUMINANCE_SIZE, config_management_t::atLeast }, - { EGL_ALPHA_MASK_SIZE, config_management_t::atLeast }, - { EGL_COLOR_BUFFER_TYPE, config_management_t::exact }, - { EGL_RENDERABLE_TYPE, config_management_t::mask }, - { EGL_CONFORMANT, config_management_t::mask } -}; - - -static config_pair_t const config_defaults[] = { - // attributes that are not specified are simply ignored, if a particular - // one needs not be ignored, it must be specified here, eg: - // { EGL_SURFACE_TYPE, EGL_WINDOW_BIT }, -}; - -// ---------------------------------------------------------------------------- - -static status_t getConfigFormatInfo(EGLint configID, - int32_t& pixelFormat, int32_t& depthFormat) -{ - switch(configID) { - case 0: - pixelFormat = GGL_PIXEL_FORMAT_RGB_565; - depthFormat = 0; - break; - case 1: - pixelFormat = GGL_PIXEL_FORMAT_RGB_565; - depthFormat = GGL_PIXEL_FORMAT_Z_16; - break; - case 2: - pixelFormat = GGL_PIXEL_FORMAT_RGBX_8888; - depthFormat = 0; - break; - case 3: - pixelFormat = GGL_PIXEL_FORMAT_RGBX_8888; - depthFormat = GGL_PIXEL_FORMAT_Z_16; - break; - case 4: - pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; - depthFormat = 0; - break; - case 5: - pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888; - depthFormat = GGL_PIXEL_FORMAT_Z_16; - break; - case 6: - pixelFormat = GGL_PIXEL_FORMAT_A_8; - depthFormat = 0; - break; - case 7: - pixelFormat = GGL_PIXEL_FORMAT_A_8; - depthFormat = GGL_PIXEL_FORMAT_Z_16; - break; - case 8: - pixelFormat = GGL_PIXEL_FORMAT_BGRA_8888; - depthFormat = 0; - break; - default: - return NAME_NOT_FOUND; - } - return NO_ERROR; -} - -// ---------------------------------------------------------------------------- - -template -static int binarySearch(T const sortedArray[], int first, int last, EGLint key) -{ - while (first <= last) { - int mid = (first + last) / 2; - if (key > sortedArray[mid].key) { - first = mid + 1; - } else if (key < sortedArray[mid].key) { - last = mid - 1; - } else { - return mid; - } - } - return -1; -} - -static int isAttributeMatching(int i, EGLint attr, EGLint val) -{ - // look for the attribute in all of our configs - config_pair_t const* configFound = gConfigs[i].array; - int index = binarySearch( - gConfigs[i].array, - 0, gConfigs[i].size-1, - attr); - if (index < 0) { - configFound = config_base_attribute_list; - index = binarySearch( - config_base_attribute_list, - 0, NELEM(config_base_attribute_list)-1, - attr); - } - if (index >= 0) { - // attribute found, check if this config could match - int cfgMgtIndex = binarySearch( - gConfigManagement, - 0, NELEM(gConfigManagement)-1, - attr); - if (cfgMgtIndex >= 0) { - bool match = gConfigManagement[cfgMgtIndex].match( - val, configFound[index].value); - if (match) { - // this config matches - return 1; - } - } else { - // attribute not found. this should NEVER happen. - } - } else { - // error, this attribute doesn't exist - } - return 0; -} - -static int makeCurrent(ogles_context_t* gl) -{ - ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific(); - if (gl) { - egl_context_t* c = egl_context_t::context(gl); - if (c->flags & egl_context_t::IS_CURRENT) { - if (current != gl) { - // it is an error to set a context current, if it's already - // current to another thread - return -1; - } - } else { - if (current) { - // mark the current context as not current, and flush - glFlush(); - egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT; - } - } - if (!(c->flags & egl_context_t::IS_CURRENT)) { - // The context is not current, make it current! - setGlThreadSpecific(gl); - c->flags |= egl_context_t::IS_CURRENT; - } - } else { - if (current) { - // mark the current context as not current, and flush - glFlush(); - egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT; - } - // this thread has no context attached to it - setGlThreadSpecific(0); - } - return 0; -} - -static EGLBoolean getConfigAttrib(EGLDisplay /*dpy*/, EGLConfig config, - EGLint attribute, EGLint *value) -{ - size_t numConfigs = NELEM(gConfigs); - int index = (int)(uintptr_t)config; - if (uint32_t(index) >= numConfigs) - return setError(EGL_BAD_CONFIG, EGL_FALSE); - - int attrIndex; - attrIndex = binarySearch( - gConfigs[index].array, - 0, gConfigs[index].size-1, - attribute); - if (attrIndex>=0) { - *value = gConfigs[index].array[attrIndex].value; - return EGL_TRUE; - } - - attrIndex = binarySearch( - config_base_attribute_list, - 0, NELEM(config_base_attribute_list)-1, - attribute); - if (attrIndex>=0) { - *value = config_base_attribute_list[attrIndex].value; - return EGL_TRUE; - } - return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); -} - -static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config, - NativeWindowType window, const EGLint* /*attrib_list*/) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); - if (window == 0) - return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); - - EGLint surfaceType; - if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) - return EGL_FALSE; - - if (!(surfaceType & EGL_WINDOW_BIT)) - return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); - - if (static_cast(window)->common.magic != - ANDROID_NATIVE_WINDOW_MAGIC) { - return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); - } - - EGLint configID; - if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE) - return EGL_FALSE; - - int32_t depthFormat; - int32_t pixelFormat; - if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) { - return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); - } - - // FIXME: we don't have access to the pixelFormat here just yet. - // (it's possible that the surface is not fully initialized) - // maybe this should be done after the page-flip - //if (EGLint(info.format) != pixelFormat) - // return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); - - egl_surface_t* surface; - surface = new egl_window_surface_v2_t(dpy, config, depthFormat, - static_cast(window)); - - if (!surface->initCheck()) { - // there was a problem in the ctor, the error - // flag has been set. - delete surface; - surface = 0; - } - return surface; -} - -static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config, - NativePixmapType pixmap, const EGLint* /*attrib_list*/) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); - if (pixmap == 0) - return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); - - EGLint surfaceType; - if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) - return EGL_FALSE; - - if (!(surfaceType & EGL_PIXMAP_BIT)) - return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); - - if (static_cast(pixmap)->version != - sizeof(egl_native_pixmap_t)) { - return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE); - } - - EGLint configID; - if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE) - return EGL_FALSE; - - int32_t depthFormat; - int32_t pixelFormat; - if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) { - return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); - } - - if (pixmap->format != pixelFormat) - return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); - - egl_surface_t* surface = - new egl_pixmap_surface_t(dpy, config, depthFormat, - static_cast(pixmap)); - - if (!surface->initCheck()) { - // there was a problem in the ctor, the error - // flag has been set. - delete surface; - surface = 0; - } - return surface; -} - -static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config, - const EGLint *attrib_list) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); - - EGLint surfaceType; - if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE) - return EGL_FALSE; - - if (!(surfaceType & EGL_PBUFFER_BIT)) - return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); - - EGLint configID; - if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE) - return EGL_FALSE; - - int32_t depthFormat; - int32_t pixelFormat; - if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) { - return setError(EGL_BAD_MATCH, EGL_NO_SURFACE); - } - - int32_t w = 0; - int32_t h = 0; - while (attrib_list[0] != EGL_NONE) { - if (attrib_list[0] == EGL_WIDTH) w = attrib_list[1]; - if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1]; - attrib_list+=2; - } - - egl_surface_t* surface = - new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat); - - if (!surface->initCheck()) { - // there was a problem in the ctor, the error - // flag has been set. - delete surface; - surface = 0; - } - return surface; -} - -// ---------------------------------------------------------------------------- -}; // namespace android -// ---------------------------------------------------------------------------- - -using namespace android; - -// ---------------------------------------------------------------------------- -// Initialization -// ---------------------------------------------------------------------------- - -EGLDisplay eglGetDisplay(NativeDisplayType display) -{ -#ifndef __ANDROID__ - // this just needs to be done once - if (gGLKey == -1) { - pthread_mutex_lock(&gInitMutex); - if (gGLKey == -1) - pthread_key_create(&gGLKey, NULL); - pthread_mutex_unlock(&gInitMutex); - } -#endif - if (display == EGL_DEFAULT_DISPLAY) { - EGLDisplay dpy = (EGLDisplay)1; - egl_display_t& d = egl_display_t::get_display(dpy); - d.type = display; - return dpy; - } - return EGL_NO_DISPLAY; -} - -EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - - EGLBoolean res = EGL_TRUE; - egl_display_t& d = egl_display_t::get_display(dpy); - - if (d.initialized.fetch_add(1, std::memory_order_acquire) == 0) { - // initialize stuff here if needed - //pthread_mutex_lock(&gInitMutex); - //pthread_mutex_unlock(&gInitMutex); - } - - if (res == EGL_TRUE) { - if (major != NULL) *major = VERSION_MAJOR; - if (minor != NULL) *minor = VERSION_MINOR; - } - return res; -} - -EGLBoolean eglTerminate(EGLDisplay dpy) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - - EGLBoolean res = EGL_TRUE; - egl_display_t& d = egl_display_t::get_display(dpy); - if (d.initialized.fetch_sub(1, std::memory_order_release) == 1) { - std::atomic_thread_fence(std::memory_order_acquire); - // TODO: destroy all resources (surfaces, contexts, etc...) - //pthread_mutex_lock(&gInitMutex); - //pthread_mutex_unlock(&gInitMutex); - } - return res; -} - -// ---------------------------------------------------------------------------- -// configuration -// ---------------------------------------------------------------------------- - -EGLBoolean eglGetConfigs( EGLDisplay dpy, - EGLConfig *configs, - EGLint config_size, EGLint *num_config) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - - if (ggl_unlikely(num_config==NULL)) - return setError(EGL_BAD_PARAMETER, EGL_FALSE); - - GLint numConfigs = NELEM(gConfigs); - if (!configs) { - *num_config = numConfigs; - return EGL_TRUE; - } - GLint i; - for (i=0 ; i( - (config_pair_t const*)attrib_list, - 0, numAttributes-1, - config_defaults[j].key) < 0) - { - for (int i=0 ; possibleMatch && i(eglSurface) ); - if (!surface->isValid()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); - if (surface->dpy != dpy) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - if (surface->ctx) { - // defer disconnect/delete until no longer current - surface->zombie = true; - } else { - surface->disconnect(); - delete surface; - } - } - return EGL_TRUE; -} - -EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface, - EGLint attribute, EGLint *value) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - egl_surface_t* surface = static_cast(eglSurface); - if (!surface->isValid()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); - if (surface->dpy != dpy) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - - EGLBoolean ret = EGL_TRUE; - switch (attribute) { - case EGL_CONFIG_ID: - ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value); - break; - case EGL_WIDTH: - *value = surface->getWidth(); - break; - case EGL_HEIGHT: - *value = surface->getHeight(); - break; - case EGL_LARGEST_PBUFFER: - // not modified for a window or pixmap surface - break; - case EGL_TEXTURE_FORMAT: - *value = EGL_NO_TEXTURE; - break; - case EGL_TEXTURE_TARGET: - *value = EGL_NO_TEXTURE; - break; - case EGL_MIPMAP_TEXTURE: - *value = EGL_FALSE; - break; - case EGL_MIPMAP_LEVEL: - *value = 0; - break; - case EGL_RENDER_BUFFER: - // TODO: return the real RENDER_BUFFER here - *value = EGL_BACK_BUFFER; - break; - case EGL_HORIZONTAL_RESOLUTION: - // pixel/mm * EGL_DISPLAY_SCALING - *value = surface->getHorizontalResolution(); - break; - case EGL_VERTICAL_RESOLUTION: - // pixel/mm * EGL_DISPLAY_SCALING - *value = surface->getVerticalResolution(); - break; - case EGL_PIXEL_ASPECT_RATIO: { - // w/h * EGL_DISPLAY_SCALING - int wr = surface->getHorizontalResolution(); - int hr = surface->getVerticalResolution(); - *value = (wr * EGL_DISPLAY_SCALING) / hr; - } break; - case EGL_SWAP_BEHAVIOR: - *value = surface->getSwapBehavior(); - break; - default: - ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); - } - return ret; -} - -EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, - EGLContext /*share_list*/, const EGLint* /*attrib_list*/) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); - - ogles_context_t* gl = ogles_init(sizeof(egl_context_t)); - if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT); - - egl_context_t* c = static_cast(gl->rasterizer.base); - c->flags = egl_context_t::NEVER_CURRENT; - c->dpy = dpy; - c->config = config; - c->read = 0; - c->draw = 0; - return (EGLContext)gl; -} - -EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - egl_context_t* c = egl_context_t::context(ctx); - if (c->flags & egl_context_t::IS_CURRENT) - setGlThreadSpecific(0); - ogles_uninit((ogles_context_t*)ctx); - return EGL_TRUE; -} - -EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, - EGLSurface read, EGLContext ctx) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - if (draw) { - egl_surface_t* s = (egl_surface_t*)draw; - if (!s->isValid()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); - if (s->dpy != dpy) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - // TODO: check that draw is compatible with the context - } - if (read && read!=draw) { - egl_surface_t* s = (egl_surface_t*)read; - if (!s->isValid()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); - if (s->dpy != dpy) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - // TODO: check that read is compatible with the context - } - - EGLContext current_ctx = EGL_NO_CONTEXT; - - if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT)) - return setError(EGL_BAD_MATCH, EGL_FALSE); - - if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT)) - return setError(EGL_BAD_MATCH, EGL_FALSE); - - if (ctx == EGL_NO_CONTEXT) { - // if we're detaching, we need the current context - current_ctx = (EGLContext)getGlThreadSpecific(); - } else { - egl_surface_t* d = (egl_surface_t*)draw; - egl_surface_t* r = (egl_surface_t*)read; - if ((d && d->ctx && d->ctx != ctx) || - (r && r->ctx && r->ctx != ctx)) { - // one of the surface is bound to a context in another thread - return setError(EGL_BAD_ACCESS, EGL_FALSE); - } - } - - ogles_context_t* gl = (ogles_context_t*)ctx; - if (makeCurrent(gl) == 0) { - if (ctx) { - egl_context_t* c = egl_context_t::context(ctx); - egl_surface_t* d = (egl_surface_t*)draw; - egl_surface_t* r = (egl_surface_t*)read; - - if (c->draw) { - egl_surface_t* s = reinterpret_cast(c->draw); - s->disconnect(); - s->ctx = EGL_NO_CONTEXT; - if (s->zombie) - delete s; - } - if (c->read) { - // FIXME: unlock/disconnect the read surface too - } - - c->draw = draw; - c->read = read; - - if (c->flags & egl_context_t::NEVER_CURRENT) { - c->flags &= ~egl_context_t::NEVER_CURRENT; - GLint w = 0; - GLint h = 0; - if (draw) { - w = d->getWidth(); - h = d->getHeight(); - } - ogles_surfaceport(gl, 0, 0); - ogles_viewport(gl, 0, 0, w, h); - ogles_scissor(gl, 0, 0, w, h); - } - if (d) { - if (d->connect() == EGL_FALSE) { - return EGL_FALSE; - } - d->ctx = ctx; - d->bindDrawSurface(gl); - } - if (r) { - // FIXME: lock/connect the read surface too - r->ctx = ctx; - r->bindReadSurface(gl); - } - } else { - // if surfaces were bound to the context bound to this thread - // mark then as unbound. - if (current_ctx) { - egl_context_t* c = egl_context_t::context(current_ctx); - egl_surface_t* d = (egl_surface_t*)c->draw; - egl_surface_t* r = (egl_surface_t*)c->read; - if (d) { - c->draw = 0; - d->disconnect(); - d->ctx = EGL_NO_CONTEXT; - if (d->zombie) - delete d; - } - if (r) { - c->read = 0; - r->ctx = EGL_NO_CONTEXT; - // FIXME: unlock/disconnect the read surface too - } - } - } - return EGL_TRUE; - } - return setError(EGL_BAD_ACCESS, EGL_FALSE); -} - -EGLContext eglGetCurrentContext(void) -{ - // eglGetCurrentContext returns the current EGL rendering context, - // as specified by eglMakeCurrent. If no context is current, - // EGL_NO_CONTEXT is returned. - return (EGLContext)getGlThreadSpecific(); -} - -EGLSurface eglGetCurrentSurface(EGLint readdraw) -{ - // eglGetCurrentSurface returns the read or draw surface attached - // to the current EGL rendering context, as specified by eglMakeCurrent. - // If no context is current, EGL_NO_SURFACE is returned. - EGLContext ctx = (EGLContext)getGlThreadSpecific(); - if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE; - egl_context_t* c = egl_context_t::context(ctx); - if (readdraw == EGL_READ) { - return c->read; - } else if (readdraw == EGL_DRAW) { - return c->draw; - } - return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); -} - -EGLDisplay eglGetCurrentDisplay(void) -{ - // eglGetCurrentDisplay returns the current EGL display connection - // for the current EGL rendering context, as specified by eglMakeCurrent. - // If no context is current, EGL_NO_DISPLAY is returned. - EGLContext ctx = (EGLContext)getGlThreadSpecific(); - if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY; - egl_context_t* c = egl_context_t::context(ctx); - return c->dpy; -} - -EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, - EGLint attribute, EGLint *value) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - egl_context_t* c = egl_context_t::context(ctx); - switch (attribute) { - case EGL_CONFIG_ID: - // Returns the ID of the EGL frame buffer configuration with - // respect to which the context was created - return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value); - } - return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); -} - -EGLBoolean eglWaitGL(void) -{ - return EGL_TRUE; -} - -EGLBoolean eglWaitNative(EGLint /*engine*/) -{ - return EGL_TRUE; -} - -EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - - egl_surface_t* d = static_cast(draw); - if (!d->isValid()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); - if (d->dpy != dpy) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - - // post the surface - d->swapBuffers(); - - // if it's bound to a context, update the buffer - if (d->ctx != EGL_NO_CONTEXT) { - d->bindDrawSurface((ogles_context_t*)d->ctx); - // if this surface is also the read surface of the context - // it is bound to, make sure to update the read buffer as well. - // The EGL spec is a little unclear about this. - egl_context_t* c = egl_context_t::context(d->ctx); - if (c->read == draw) { - d->bindReadSurface((ogles_context_t*)d->ctx); - } - } - - return EGL_TRUE; -} - -EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface /*surface*/, - NativePixmapType /*target*/) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - // TODO: eglCopyBuffers() - return EGL_FALSE; -} - -EGLint eglGetError(void) -{ - return getError(); -} - -const char* eglQueryString(EGLDisplay dpy, EGLint name) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, (const char*)0); - - switch (name) { - case EGL_VENDOR: - return gVendorString; - case EGL_VERSION: - return gVersionString; - case EGL_EXTENSIONS: - return gExtensionsString; - case EGL_CLIENT_APIS: - return gClientApiString; - } - return setError(EGL_BAD_PARAMETER, (const char *)0); -} - -// ---------------------------------------------------------------------------- -// EGL 1.1 -// ---------------------------------------------------------------------------- - -EGLBoolean eglSurfaceAttrib( - EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*attribute*/, EGLint /*value*/) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - // TODO: eglSurfaceAttrib() - return setError(EGL_BAD_PARAMETER, EGL_FALSE); -} - -EGLBoolean eglBindTexImage( - EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*buffer*/) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - // TODO: eglBindTexImage() - return setError(EGL_BAD_PARAMETER, EGL_FALSE); -} - -EGLBoolean eglReleaseTexImage( - EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*buffer*/) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - // TODO: eglReleaseTexImage() - return setError(EGL_BAD_PARAMETER, EGL_FALSE); -} - -EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint /*interval*/) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - // TODO: eglSwapInterval() - return EGL_TRUE; -} - -// ---------------------------------------------------------------------------- -// EGL 1.2 -// ---------------------------------------------------------------------------- - -EGLBoolean eglBindAPI(EGLenum api) -{ - if (api != EGL_OPENGL_ES_API) - return setError(EGL_BAD_PARAMETER, EGL_FALSE); - return EGL_TRUE; -} - -EGLenum eglQueryAPI(void) -{ - return EGL_OPENGL_ES_API; -} - -EGLBoolean eglWaitClient(void) -{ - glFinish(); - return EGL_TRUE; -} - -EGLBoolean eglReleaseThread(void) -{ - // TODO: eglReleaseThread() - return EGL_TRUE; -} - -EGLSurface eglCreatePbufferFromClientBuffer( - EGLDisplay dpy, EGLenum /*buftype*/, EGLClientBuffer /*buffer*/, - EGLConfig /*config*/, const EGLint* /*attrib_list*/) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE); - // TODO: eglCreatePbufferFromClientBuffer() - return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE); -} - -// ---------------------------------------------------------------------------- -// EGL_EGLEXT_VERSION 3 -// ---------------------------------------------------------------------------- - -void (*eglGetProcAddress (const char *procname))() -{ - extention_map_t const * const map = gExtentionMap; - for (uint32_t i=0 ; icommon.magic != ANDROID_NATIVE_BUFFER_MAGIC) - return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); - - if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) - return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); - - switch (native_buffer->format) { - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - case HAL_PIXEL_FORMAT_RGB_888: - case HAL_PIXEL_FORMAT_RGB_565: - case HAL_PIXEL_FORMAT_BGRA_8888: - break; - default: - return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR); - } - - native_buffer->common.incRef(&native_buffer->common); - return (EGLImageKHR)native_buffer; -} - -EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) { - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - } - - ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)img; - - if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) - return setError(EGL_BAD_PARAMETER, EGL_FALSE); - - if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) - return setError(EGL_BAD_PARAMETER, EGL_FALSE); - - native_buffer->common.decRef(&native_buffer->common); - - return EGL_TRUE; -} - -// ---------------------------------------------------------------------------- -// EGL_KHR_fence_sync -// ---------------------------------------------------------------------------- - -#define FENCE_SYNC_HANDLE ((EGLSyncKHR)0xFE4CE) - -EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, - const EGLint *attrib_list) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) { - return setError(EGL_BAD_DISPLAY, EGL_NO_SYNC_KHR); - } - - if (type != EGL_SYNC_FENCE_KHR || - (attrib_list != NULL && attrib_list[0] != EGL_NONE)) { - return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR); - } - - if (eglGetCurrentContext() == EGL_NO_CONTEXT) { - return setError(EGL_BAD_MATCH, EGL_NO_SYNC_KHR); - } - - // AGL is synchronous; nothing to do here. - - return FENCE_SYNC_HANDLE; -} - -EGLBoolean eglDestroySyncKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync) -{ - if (sync != FENCE_SYNC_HANDLE) { - return setError(EGL_BAD_PARAMETER, EGL_FALSE); - } - - return EGL_TRUE; -} - -EGLint eglClientWaitSyncKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync, EGLint /*flags*/, - EGLTimeKHR /*timeout*/) -{ - if (sync != FENCE_SYNC_HANDLE) { - return setError(EGL_BAD_PARAMETER, EGL_FALSE); - } - - return EGL_CONDITION_SATISFIED_KHR; -} - -EGLBoolean eglGetSyncAttribKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync, - EGLint attribute, EGLint *value) -{ - if (sync != FENCE_SYNC_HANDLE) { - return setError(EGL_BAD_PARAMETER, EGL_FALSE); - } - - switch (attribute) { - case EGL_SYNC_TYPE_KHR: - *value = EGL_SYNC_FENCE_KHR; - return EGL_TRUE; - case EGL_SYNC_STATUS_KHR: - *value = EGL_SIGNALED_KHR; - return EGL_TRUE; - case EGL_SYNC_CONDITION_KHR: - *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR; - return EGL_TRUE; - default: - return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); - } -} - -// ---------------------------------------------------------------------------- -// ANDROID extensions -// ---------------------------------------------------------------------------- - -EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, - EGLint left, EGLint top, EGLint width, EGLint height) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - - egl_surface_t* d = static_cast(draw); - if (!d->isValid()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); - if (d->dpy != dpy) - return setError(EGL_BAD_DISPLAY, EGL_FALSE); - - // post the surface - d->setSwapRectangle(left, top, width, height); - - return EGL_TRUE; -} diff --git a/opengl/libagl/fixed_asm.S b/opengl/libagl/fixed_asm.S deleted file mode 100644 index 5e08856d0a..0000000000 --- a/opengl/libagl/fixed_asm.S +++ /dev/null @@ -1,67 +0,0 @@ -/* libs/opengles/fixed_asm.S -** -** Copyright 2006, 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. -*/ - - - .text - .align 2 - - .global gglFloatToFixed - .type gglFloatToFixed, %function - .global gglFloatToFixedFast - .type gglFloatToFixedFast, %function - - -/* - * Converts a float to a s15.16 fixed-point number. - * this doesn't handle floats out of the [-32768, +32768[ range - * and doesn't performs round-to-nearest. - * however, it's very fast :-) - */ - -gglFloatToFixedFast: - movs r1, r0, lsl #1 /* remove bit sign */ - mov r2, #0x8E /* 127 + 15 */ - sub r1, r2, r1, lsr #24 /* compute shift */ - mov r2, r0, lsl #8 /* mantissa<<8 */ - orr r2, r2, #0x80000000 /* add the missing 1 */ - mov r0, r2, lsr r1 /* scale to 16.16 */ - rsbcs r0, r0, #0 /* negate if needed */ - bx lr - -/* - * this version rounds-to-nearest and saturates numbers - * outside the range (but not NaNs). - */ - -gglFloatToFixed: - mov r1, r0, lsl #1 /* remove bit sign */ - mov r2, #0x8E /* 127 + 15 */ - subs r1, r2, r1, lsr #24 /* compute shift */ - bls 0f /* too big */ - mov r2, r0, lsl #8 /* mantissa<<8 */ - orr r2, r2, #0x80000000 /* add the missing 1 */ - mov r3, r0 - movs r0, r2, lsr r1 /* scale to 16.16 */ - addcs r0, r0, #1 /* round-to-nearest */ - tst r3, #0x80000000 /* negative? */ - rsbne r0, r0, #0 /* negate if needed */ - bx lr - -0: ands r0, r0, #0x80000000 /* keep only the sign bit */ - moveq r0, #0x7fffffff /* positive, maximum value */ - bx lr - diff --git a/opengl/libagl/fp.cpp b/opengl/libagl/fp.cpp deleted file mode 100644 index a7a4f7b102..0000000000 --- a/opengl/libagl/fp.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* libs/opengles/fp.cpp -** -** Copyright 2006, 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 "fp.h" - -// ---------------------------------------------------------------------------- - -#if !(defined(__arm__) || (defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6)) -GGLfixed gglFloatToFixed(float v) { - return GGLfixed(floorf(v * 65536.0f + 0.5f)); -} -#endif - -// ---------------------------------------------------------------------------- - -namespace android { - -namespace gl { - -GLfloat fixedToFloat(GLfixed x) -{ -#if DEBUG_USE_FLOATS - return x / 65536.0f; -#else - if (!x) return 0; - const uint32_t s = x & 0x80000000; - union { - uint32_t i; - float f; - }; - i = s ? -x : x; - const int c = gglClz(i) - 8; - i = (c>=0) ? (i<>-c); - const uint32_t e = 134 - c; - i &= ~0x800000; - i |= e<<23; - i |= s; - return f; -#endif -} - -float sinef(float x) -{ - const float A = 1.0f / (2.0f*M_PI); - const float B = -16.0f; - const float C = 8.0f; - - // scale angle for easy argument reduction - x *= A; - - if (fabsf(x) >= 0.5f) { - // Argument reduction - x = x - ceilf(x + 0.5f) + 1.0f; - } - - const float y = B*x*fabsf(x) + C*x; - return 0.2215f * (y*fabsf(y) - y) + y; -} - -float cosinef(float x) -{ - return sinef(x + float(M_PI/2)); -} - -void sincosf(GLfloat angle, GLfloat* s, GLfloat* c) { - *s = sinef(angle); - *c = cosinef(angle); -} - -}; // namespace fp_utils - -// ---------------------------------------------------------------------------- -}; // namespace android diff --git a/opengl/libagl/fp.h b/opengl/libagl/fp.h deleted file mode 100644 index 6d0c18339f..0000000000 --- a/opengl/libagl/fp.h +++ /dev/null @@ -1,243 +0,0 @@ -/* libs/opengles/fp.h -** -** Copyright 2006, 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_OPENGLES_FP_H -#define ANDROID_OPENGLES_FP_H - -#include -#include -#include -#include - -#include - -#include - -#define DEBUG_USE_FLOATS 0 - -// ---------------------------------------------------------------------------- - -extern "C" GLfixed gglFloatToFixed(float f) __attribute__((const)); - -// ---------------------------------------------------------------------------- -namespace android { - -namespace gl { - - GLfloat fixedToFloat(GLfixed) CONST; - - void sincosf(GLfloat angle, GLfloat* s, GLfloat* c); - float sinef(GLfloat x) CONST; - float cosinef(GLfloat x) CONST; - -inline bool cmpf(GLfloat a, GLfloat b) CONST; -inline bool isZerof(GLfloat) CONST; -inline bool isOnef(GLfloat) CONST; - -inline int isZeroOrNegativef(GLfloat) CONST; - -inline int exponent(GLfloat) CONST; -inline int32_t mantissa(GLfloat) CONST; -inline GLfloat clampToZerof(GLfloat) CONST; -inline GLfloat reciprocalf(GLfloat) CONST; -inline GLfloat rsqrtf(GLfloat) CONST; -inline GLfloat sqrf(GLfloat) CONST; -inline GLfloat addExpf(GLfloat v, int e) CONST; -inline GLfloat mul2f(GLfloat v) CONST; -inline GLfloat div2f(GLfloat v) CONST; -inline GLfloat absf(GLfloat v) CONST; - - -/* - * float fastexpf(float) : a fast approximation of expf(x) - * give somewhat accurate results for -88 <= x <= 88 - * - * exp(x) = 2^(x/ln(2)) - * we use the properties of float encoding - * to get a fast 2^ and linear interpolation - * - */ - -inline float fastexpf(float y) __attribute__((const)); - -inline float fastexpf(float y) -{ - union { - float r; - int32_t i; - } u; - - // 127*ln(2) = 88 - if (y < -88.0f) { - u.r = 0.0f; - } else if (y > 88.0f) { - u.r = INFINITY; - } else { - const float kOneOverLogTwo = (1L<<23) / M_LN2; - const int32_t kExponentBias = 127L<<23; - const int32_t e = int32_t(y*kOneOverLogTwo); - u.i = e + kExponentBias; - } - - return u.r; -} - - -bool cmpf(GLfloat a, GLfloat b) { -#if DEBUG_USE_FLOATS - return a == b; -#else - union { - float f; - uint32_t i; - } ua, ub; - ua.f = a; - ub.f = b; - return ua.i == ub.i; -#endif -} - -bool isZerof(GLfloat v) { -#if DEBUG_USE_FLOATS - return v == 0; -#else - union { - float f; - int32_t i; - }; - f = v; - return (i<<1) == 0; -#endif -} - -bool isOnef(GLfloat v) { - return cmpf(v, 1.0f); -} - -int isZeroOrNegativef(GLfloat v) { -#if DEBUG_USE_FLOATS - return v <= 0; -#else - union { - float f; - int32_t i; - }; - f = v; - return isZerof(v) | (i>>31); -#endif -} - -int exponent(GLfloat v) { - union { - float f; - uint32_t i; - }; - f = v; - return ((i << 1) >> 24) - 127; -} - -int32_t mantissa(GLfloat v) { - union { - float f; - uint32_t i; - }; - f = v; - if (!(i&0x7F800000)) return 0; - const int s = i >> 31; - i |= (1L<<23); - i &= ~0xFF000000; - return s ? -i : i; -} - -GLfloat clampToZerof(GLfloat v) { -#if DEBUG_USE_FLOATS - return v<0 ? 0 : (v>1 ? 1 : v); -#else - union { - float f; - int32_t i; - }; - f = v; - i &= ~(i>>31); - return f; -#endif -} - -GLfloat reciprocalf(GLfloat v) { - // XXX: do better - return 1.0f / v; -} - -GLfloat rsqrtf(GLfloat v) { - // XXX: do better - return 1.0f / sqrtf(v); -} - -GLfloat sqrf(GLfloat v) { - // XXX: do better - return v*v; -} - -GLfloat addExpf(GLfloat v, int e) { - union { - float f; - int32_t i; - }; - f = v; - if (i<<1) { // XXX: deal with over/underflow - i += int32_t(e)<<23; - } - return f; -} - -GLfloat mul2f(GLfloat v) { -#if DEBUG_USE_FLOATS - return v*2; -#else - return addExpf(v, 1); -#endif -} - -GLfloat div2f(GLfloat v) { -#if DEBUG_USE_FLOATS - return v*0.5f; -#else - return addExpf(v, -1); -#endif -} - -GLfloat absf(GLfloat v) { -#if DEBUG_USE_FLOATS - return v<0 ? -v : v; -#else - union { - float f; - int32_t i; - }; - f = v; - i &= ~0x80000000; - return f; -#endif -} - -}; // namespace gl - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_OPENGLES_FP_H - diff --git a/opengl/libagl/iterators.S b/opengl/libagl/iterators.S deleted file mode 100644 index 8fe9039088..0000000000 --- a/opengl/libagl/iterators.S +++ /dev/null @@ -1,89 +0,0 @@ -/* libs/opengles/iterators.S -** -** Copyright 2006, 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. -*/ - - - .text - .align 2 - .arm - - .global iterators0032 - .type iterators0032, %function - -/* - * iterators0032 - * - * MUST BE CALLED FROM ARM CODE - * - * r0: const compute_iterators_t* (this) - * r0 + 0: m_dx01 - * r0 + 4: m_dy10 - * r0 + 8: m_dx20 - * r0 +12: m_dy02 - * r0 +16: m_x0 - * r0 +20: m_y0 - * r0 +24: m_area - * r0 +28: m_scale - * r0 +29: m_area_scale; - * r1: int32_t* (out) - * r1 + 0: c - * r1 + 4: dcdx - * r1 + 8: dcdy - * r2: c0 - * r3: c1 - * [sp]: c2 - */ - -iterators0032: - stmfd sp!, {r4, r5, r6, r7, r8, lr} - ldr r4, [sp, #4*6] - - ldrb r12, [r0, #29] - sub r3, r3, r2 - sub r4, r4, r2 - sub r12, r12, #16 - mov r3, r3, asr r12 - mov r4, r4, asr r12 - - ldr r5, [r0, #0] - ldr r12, [r0, #4] - smull r8, lr, r4, r5 - ldr r5, [r0, #8] - smull r6, r7, r4, r12 - ldr r12, [r0, #12] - smlal r8, lr, r3, r5 - smlal r6, r7, r3, r12 - - ldr r3, [r0, #16] // m_x0 - ldr r4, [r0, #20] // m_x1 - - str r6, [r1, #4] - str r8, [r1, #8] - - umull r6, r5, r3, r6 - umull r8, r0, r4, r8 - mla r7, r3, r7, r5 - mla lr, r4, lr, r0 - adds r6, r6, r8 - adc r7, r7, lr - - movs r6, r6, lsr #4 - adc r6, r6, r7, lsl #28 - rsb r6, r6, r2, lsl #16 - str r6, [r1, #0] - - ldmfd sp!, {r4, r5, r6, r7, r8, pc} - diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp deleted file mode 100644 index 216c725128..0000000000 --- a/opengl/libagl/light.cpp +++ /dev/null @@ -1,882 +0,0 @@ -/* libs/opengles/light.cpp -** -** Copyright 2006, 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 -#include "context.h" -#include "fp.h" -#include "light.h" -#include "state.h" -#include "matrix.h" - - -#if defined(__arm__) && defined(__thumb__) -#warning "light.cpp should not be compiled in thumb on ARM." -#endif - -namespace android { - -// ---------------------------------------------------------------------------- - -static void invalidate_lighting(ogles_context_t* c); -static void lightVertexValidate(ogles_context_t* c, vertex_t* v); -static void lightVertexNop(ogles_context_t* c, vertex_t* v); -static void lightVertex(ogles_context_t* c, vertex_t* v); -static void lightVertexMaterial(ogles_context_t* c, vertex_t* v); - -static inline void vscale3(GLfixed* d, const GLfixed* m, GLfixed s); - -static __attribute__((noinline)) -void vnorm3(GLfixed* d, const GLfixed* a); - -static inline void vsa3(GLfixed* d, - const GLfixed* m, GLfixed s, const GLfixed* a); -static inline void vss3(GLfixed* d, - const GLfixed* m, GLfixed s, const GLfixed* a); -static inline void vmla3(GLfixed* d, - const GLfixed* m0, const GLfixed* m1, const GLfixed* a); -static inline void vmul3(GLfixed* d, - const GLfixed* m0, const GLfixed* m1); - -static GLfixed fog_linear(ogles_context_t* c, GLfixed z); -static GLfixed fog_exp(ogles_context_t* c, GLfixed z); -static GLfixed fog_exp2(ogles_context_t* c, GLfixed z); - - -// ---------------------------------------------------------------------------- - -static void init_white(vec4_t& c) { - c.r = c.g = c.b = c.a = 0x10000; -} - -void ogles_init_light(ogles_context_t* c) -{ - for (unsigned int i=0 ; ilighting.lights[i].ambient.a = 0x10000; - c->lighting.lights[i].position.z = 0x10000; - c->lighting.lights[i].spotDir.z = -0x10000; - c->lighting.lights[i].spotCutoff = gglIntToFixed(180); - c->lighting.lights[i].attenuation[0] = 0x10000; - } - init_white(c->lighting.lights[0].diffuse); - init_white(c->lighting.lights[0].specular); - - c->lighting.front.ambient.r = - c->lighting.front.ambient.g = - c->lighting.front.ambient.b = gglFloatToFixed(0.2f); - c->lighting.front.ambient.a = 0x10000; - c->lighting.front.diffuse.r = - c->lighting.front.diffuse.g = - c->lighting.front.diffuse.b = gglFloatToFixed(0.8f); - c->lighting.front.diffuse.a = 0x10000; - c->lighting.front.specular.a = 0x10000; - c->lighting.front.emission.a = 0x10000; - - c->lighting.lightModel.ambient.r = - c->lighting.lightModel.ambient.g = - c->lighting.lightModel.ambient.b = gglFloatToFixed(0.2f); - c->lighting.lightModel.ambient.a = 0x10000; - - c->lighting.colorMaterial.face = GL_FRONT_AND_BACK; - c->lighting.colorMaterial.mode = GL_AMBIENT_AND_DIFFUSE; - - c->fog.mode = GL_EXP; - c->fog.fog = fog_exp; - c->fog.density = 0x10000; - c->fog.end = 0x10000; - c->fog.invEndMinusStart = 0x10000; - - invalidate_lighting(c); - - c->rasterizer.procs.shadeModel(c, GL_SMOOTH); - c->lighting.shadeModel = GL_SMOOTH; -} - -void ogles_uninit_light(ogles_context_t* /*c*/) -{ -} - -static inline int32_t clampF(GLfixed f) CONST; -int32_t clampF(GLfixed f) { - f = (f & ~(f>>31)); - if (f >= 0x10000) - f = 0x10000; - return f; -} - -static GLfixed fog_linear(ogles_context_t* c, GLfixed z) { - return clampF(gglMulx((c->fog.end - ((z<0)?-z:z)), c->fog.invEndMinusStart)); -} - -static GLfixed fog_exp(ogles_context_t* c, GLfixed z) { - const float e = fixedToFloat(gglMulx(c->fog.density, ((z<0)?-z:z))); - return clampF(gglFloatToFixed(fastexpf(-e))); -} - -static GLfixed fog_exp2(ogles_context_t* c, GLfixed z) { - const float e = fixedToFloat(gglMulx(c->fog.density, z)); - return clampF(gglFloatToFixed(fastexpf(-e*e))); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark math helpers -#endif - -static inline -void vscale3(GLfixed* d, const GLfixed* m, GLfixed s) { - d[0] = gglMulx(m[0], s); - d[1] = gglMulx(m[1], s); - d[2] = gglMulx(m[2], s); -} - -static inline -void vsa3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a) { - d[0] = gglMulAddx(m[0], s, a[0]); - d[1] = gglMulAddx(m[1], s, a[1]); - d[2] = gglMulAddx(m[2], s, a[2]); -} - -static inline -void vss3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a) { - d[0] = gglMulSubx(m[0], s, a[0]); - d[1] = gglMulSubx(m[1], s, a[1]); - d[2] = gglMulSubx(m[2], s, a[2]); -} - -static inline -void vmla3(GLfixed* d, - const GLfixed* m0, const GLfixed* m1, const GLfixed* a) -{ - d[0] = gglMulAddx(m0[0], m1[0], a[0]); - d[1] = gglMulAddx(m0[1], m1[1], a[1]); - d[2] = gglMulAddx(m0[2], m1[2], a[2]); -} - -static inline -void vmul3(GLfixed* d, const GLfixed* m0, const GLfixed* m1) { - d[0] = gglMulx(m0[0], m1[0]); - d[1] = gglMulx(m0[1], m1[1]); - d[2] = gglMulx(m0[2], m1[2]); -} - -void vnorm3(GLfixed* d, const GLfixed* a) -{ - // we must take care of overflows when normalizing a vector - GLfixed n; - int32_t x = a[0]; x = x>=0 ? x : -x; - int32_t y = a[1]; y = y>=0 ? y : -y; - int32_t z = a[2]; z = z>=0 ? z : -z; - if (ggl_likely(x<=0x6800 && y<=0x6800 && z<= 0x6800)) { - // in this case this will all fit on 32 bits - n = x*x + y*y + z*z; - n = gglSqrtRecipx(n); - n <<= 8; - } else { - // here norm^2 is at least 0x7EC00000 (>>32 == 0.495117) - n = vsquare3(x, y, z); - n = gglSqrtRecipx(n); - } - vscale3(d, a, n); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark lighting equations -#endif - -static inline void light_picker(ogles_context_t* c) -{ - if (ggl_likely(!c->lighting.enable)) { - c->lighting.lightVertex = lightVertexNop; - return; - } - if (c->lighting.colorMaterial.enable) { - c->lighting.lightVertex = lightVertexMaterial; - } else { - c->lighting.lightVertex = lightVertex; - } -} - -static inline void validate_light_mvi(ogles_context_t* c) -{ - uint32_t en = c->lighting.enabledLights; - // Vector from object to viewer, in eye coordinates - while (en) { - const int i = 31 - gglClz(en); - en &= ~(1<lighting.lights[i]; -#if OBJECT_SPACE_LIGHTING - c->transforms.mvui.point4(&c->transforms.mvui, - &l.objPosition, &l.position); -#else - l.objPosition = l.position; -#endif - vnorm3(l.normalizedObjPosition.v, l.objPosition.v); - } - const vec4_t eyeViewer = {{{ 0, 0, 0x10000, 0 }}}; -#if OBJECT_SPACE_LIGHTING - c->transforms.mvui.point3(&c->transforms.mvui, - &c->lighting.objViewer, &eyeViewer); - vnorm3(c->lighting.objViewer.v, c->lighting.objViewer.v); -#else - c->lighting.objViewer = eyeViewer; -#endif -} - -static inline void validate_light(ogles_context_t* c) -{ - // if colorMaterial is enabled, we get the color from the vertex - if (!c->lighting.colorMaterial.enable) { - material_t& material = c->lighting.front; - uint32_t en = c->lighting.enabledLights; - while (en) { - const int i = 31 - gglClz(en); - en &= ~(1<lighting.lights[i]; - vmul3(l.implicitAmbient.v, material.ambient.v, l.ambient.v); - vmul3(l.implicitDiffuse.v, material.diffuse.v, l.diffuse.v); - vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v); - - // this is just a flag to tell if we have a specular component - l.implicitSpecular.v[3] = - l.implicitSpecular.r | - l.implicitSpecular.g | - l.implicitSpecular.b; - - l.rConstAttenuation = (l.attenuation[1] | l.attenuation[2])==0; - if (l.rConstAttenuation) - l.rConstAttenuation = gglRecipFast(l.attenuation[0]); - } - // emission and ambient for the whole scene - vmla3( c->lighting.implicitSceneEmissionAndAmbient.v, - c->lighting.lightModel.ambient.v, - material.ambient.v, - material.emission.v); - c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a; - } - validate_light_mvi(c); -} - -void invalidate_lighting(ogles_context_t* c) -{ - // TODO: pick lightVertexValidate or lightVertexValidateMVI - // instead of systematically the heavier lightVertexValidate() - c->lighting.lightVertex = lightVertexValidate; -} - -void ogles_invalidate_lighting_mvui(ogles_context_t* c) -{ - invalidate_lighting(c); -} - -void lightVertexNop(ogles_context_t*, vertex_t* /*v*/) -{ - // we should never end-up here -} - -void lightVertexValidateMVI(ogles_context_t* c, vertex_t* v) -{ - validate_light_mvi(c); - light_picker(c); - c->lighting.lightVertex(c, v); -} - -void lightVertexValidate(ogles_context_t* c, vertex_t* v) -{ - validate_light(c); - light_picker(c); - c->lighting.lightVertex(c, v); -} - -void lightVertexMaterial(ogles_context_t* c, vertex_t* v) -{ - // fetch the material color - const GLvoid* cp = c->arrays.color.element( - v->index & vertex_cache_t::INDEX_MASK); - c->arrays.color.fetch(c, v->color.v, cp); - - // acquire the color-material from the vertex - material_t& material = c->lighting.front; - material.ambient = - material.diffuse = v->color; - // implicit arguments need to be computed per/vertex - uint32_t en = c->lighting.enabledLights; - while (en) { - const int i = 31 - gglClz(en); - en &= ~(1<lighting.lights[i]; - vmul3(l.implicitAmbient.v, material.ambient.v, l.ambient.v); - vmul3(l.implicitDiffuse.v, material.diffuse.v, l.diffuse.v); - vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v); - // this is just a flag to tell if we have a specular component - l.implicitSpecular.v[3] = - l.implicitSpecular.r | - l.implicitSpecular.g | - l.implicitSpecular.b; - } - // emission and ambient for the whole scene - vmla3( c->lighting.implicitSceneEmissionAndAmbient.v, - c->lighting.lightModel.ambient.v, - material.ambient.v, - material.emission.v); - c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a; - - // now we can light our vertex as usual - lightVertex(c, v); -} - -void lightVertex(ogles_context_t* c, vertex_t* v) -{ - // emission and ambient for the whole scene - vec4_t r = c->lighting.implicitSceneEmissionAndAmbient; - const vec4_t objViewer = c->lighting.objViewer; - - uint32_t en = c->lighting.enabledLights; - if (ggl_likely(en)) { - // since we do the lighting in object-space, we don't need to - // transform each normal. However, we might still have to normalize - // it if GL_NORMALIZE is enabled. - vec4_t n; - c->arrays.normal.fetch(c, n.v, - c->arrays.normal.element(v->index & vertex_cache_t::INDEX_MASK)); - -#if !OBJECT_SPACE_LIGHTING - c->transforms.mvui.point3(&c->transforms.mvui, &n, &n); -#endif - - // TODO: right now we handle GL_RESCALE_NORMALS as if it were - // GL_NORMALIZE. We could optimize this by scaling mvui - // appropriately instead. - if (c->transforms.rescaleNormals) - vnorm3(n.v, n.v); - - const material_t& material = c->lighting.front; - const int twoSide = c->lighting.lightModel.twoSide; - - while (en) { - const int i = 31 - gglClz(en); - en &= ~(1<lighting.lights[i]; - - vec4_t d, t; - GLfixed s; - GLfixed sqDist = 0x10000; - - // compute vertex-to-light vector - if (ggl_unlikely(l.position.w)) { - // lightPos/1.0 - vertex/vertex.w == lightPos*vertex.w - vertex -#if !OBJECT_SPACE_LIGHTING - vec4_t o; - const transform_t& mv = c->transforms.modelview.transform; - mv.point4(&mv, &o, &v->obj); - vss3(d.v, l.objPosition.v, o.w, o.v); -#else - vss3(d.v, l.objPosition.v, v->obj.w, v->obj.v); -#endif - sqDist = dot3(d.v, d.v); - vscale3(d.v, d.v, gglSqrtRecipx(sqDist)); - } else { - // TODO: avoid copy here - d = l.normalizedObjPosition; - } - - // ambient & diffuse - s = dot3(n.v, d.v); - s = (s<0) ? (twoSide?(-s):0) : s; - vsa3(t.v, l.implicitDiffuse.v, s, l.implicitAmbient.v); - - // specular - if (ggl_unlikely(s && l.implicitSpecular.v[3])) { - vec4_t h; - h.x = d.x + objViewer.x; - h.y = d.y + objViewer.y; - h.z = d.z + objViewer.z; - vnorm3(h.v, h.v); - s = dot3(n.v, h.v); - s = (s<0) ? (twoSide?(-s):0) : s; - if (s > 0) { - s = gglPowx(s, material.shininess); - vsa3(t.v, l.implicitSpecular.v, s, t.v); - } - } - - // spot - if (ggl_unlikely(l.spotCutoff != gglIntToFixed(180))) { - GLfixed spotAtt = -dot3(l.normalizedSpotDir.v, d.v); - if (spotAtt >= l.spotCutoffCosine) { - vscale3(t.v, t.v, gglPowx(spotAtt, l.spotExp)); - } - } - - // attenuation - if (ggl_unlikely(l.position.w)) { - if (l.rConstAttenuation) { - s = l.rConstAttenuation; - } else { - s = gglMulAddx(sqDist, l.attenuation[2], l.attenuation[0]); - if (l.attenuation[1]) - s = gglMulAddx(gglSqrtx(sqDist), l.attenuation[1], s); - s = gglRecipFast(s); - } - vscale3(t.v, t.v, s); - } - - r.r += t.r; - r.g += t.g; - r.b += t.b; - } - } - v->color.r = gglClampx(r.r); - v->color.g = gglClampx(r.g); - v->color.b = gglClampx(r.b); - v->color.a = gglClampx(r.a); - v->flags |= vertex_t::LIT; -} - -static void lightModelx(GLenum pname, GLfixed param, ogles_context_t* c) -{ - if (ggl_unlikely(pname != GL_LIGHT_MODEL_TWO_SIDE)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - c->lighting.lightModel.twoSide = param ? GL_TRUE : GL_FALSE; - invalidate_lighting(c); -} - -static void lightx(GLenum i, GLenum pname, GLfixed param, ogles_context_t* c) -{ - if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - - light_t& light = c->lighting.lights[i-GL_LIGHT0]; - switch (pname) { - case GL_SPOT_EXPONENT: - if (GGLfixed(param) >= gglIntToFixed(128)) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - light.spotExp = param; - break; - case GL_SPOT_CUTOFF: - if (param!=gglIntToFixed(180) && GGLfixed(param)>=gglIntToFixed(90)) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - light.spotCutoff = param; - light.spotCutoffCosine = - gglFloatToFixed(cosinef((M_PI/(180.0f*65536.0f))*param)); - break; - case GL_CONSTANT_ATTENUATION: - if (param < 0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - light.attenuation[0] = param; - break; - case GL_LINEAR_ATTENUATION: - if (param < 0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - light.attenuation[1] = param; - break; - case GL_QUADRATIC_ATTENUATION: - if (param < 0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - light.attenuation[2] = param; - break; - default: - ogles_error(c, GL_INVALID_ENUM); - return; - } - invalidate_lighting(c); -} - -static void lightxv(GLenum i, GLenum pname, const GLfixed *params, ogles_context_t* c) -{ - if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - - GLfixed* what; - light_t& light = c->lighting.lights[i-GL_LIGHT0]; - switch (pname) { - case GL_AMBIENT: - what = light.ambient.v; - break; - case GL_DIFFUSE: - what = light.diffuse.v; - break; - case GL_SPECULAR: - what = light.specular.v; - break; - case GL_POSITION: { - ogles_validate_transform(c, transform_state_t::MODELVIEW); - transform_t& mv = c->transforms.modelview.transform; - mv.point4(&mv, &light.position, reinterpret_cast(params)); - invalidate_lighting(c); - return; - } - case GL_SPOT_DIRECTION: { -#if OBJECT_SPACE_LIGHTING - ogles_validate_transform(c, transform_state_t::MVUI); - transform_t& mvui = c->transforms.mvui; - mvui.point3(&mvui, &light.spotDir, reinterpret_cast(params)); -#else - light.spotDir = *reinterpret_cast(params); -#endif - vnorm3(light.normalizedSpotDir.v, light.spotDir.v); - invalidate_lighting(c); - return; - } - default: - lightx(i, pname, params[0], c); - return; - } - what[0] = params[0]; - what[1] = params[1]; - what[2] = params[2]; - what[3] = params[3]; - invalidate_lighting(c); -} - -static void materialx(GLenum face, GLenum pname, GLfixed param, ogles_context_t* c) -{ - if (ggl_unlikely(face != GL_FRONT_AND_BACK)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - if (ggl_unlikely(pname != GL_SHININESS)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - c->lighting.front.shininess = param; - invalidate_lighting(c); -} - -static void fogx(GLenum pname, GLfixed param, ogles_context_t* c) -{ - switch (pname) { - case GL_FOG_DENSITY: - if (param >= 0) { - c->fog.density = param; - break; - } - ogles_error(c, GL_INVALID_VALUE); - break; - case GL_FOG_START: - c->fog.start = param; - c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start); - break; - case GL_FOG_END: - c->fog.end = param; - c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start); - break; - case GL_FOG_MODE: - switch (param) { - case GL_LINEAR: - c->fog.mode = param; - c->fog.fog = fog_linear; - break; - case GL_EXP: - c->fog.mode = param; - c->fog.fog = fog_exp; - break; - case GL_EXP2: - c->fog.mode = param; - c->fog.fog = fog_exp2; - break; - default: - ogles_error(c, GL_INVALID_ENUM); - break; - } - break; - default: - ogles_error(c, GL_INVALID_ENUM); - break; - } -} - -// ---------------------------------------------------------------------------- -}; // namespace android -// ---------------------------------------------------------------------------- - -using namespace android; - -#if 0 -#pragma mark - -#pragma mark lighting APIs -#endif - -void glShadeModel(GLenum mode) -{ - ogles_context_t* c = ogles_context_t::get(); - if (ggl_unlikely(mode != GL_SMOOTH && mode != GL_FLAT)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - c->lighting.shadeModel = mode; -} - -void glLightModelf(GLenum pname, GLfloat param) -{ - ogles_context_t* c = ogles_context_t::get(); - lightModelx(pname, gglFloatToFixed(param), c); -} - -void glLightModelx(GLenum pname, GLfixed param) -{ - ogles_context_t* c = ogles_context_t::get(); - lightModelx(pname, param, c); -} - -void glLightModelfv(GLenum pname, const GLfloat *params) -{ - ogles_context_t* c = ogles_context_t::get(); - if (pname == GL_LIGHT_MODEL_TWO_SIDE) { - lightModelx(pname, gglFloatToFixed(params[0]), c); - return; - } - - if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - - c->lighting.lightModel.ambient.r = gglFloatToFixed(params[0]); - c->lighting.lightModel.ambient.g = gglFloatToFixed(params[1]); - c->lighting.lightModel.ambient.b = gglFloatToFixed(params[2]); - c->lighting.lightModel.ambient.a = gglFloatToFixed(params[3]); - invalidate_lighting(c); -} - -void glLightModelxv(GLenum pname, const GLfixed *params) -{ - ogles_context_t* c = ogles_context_t::get(); - if (pname == GL_LIGHT_MODEL_TWO_SIDE) { - lightModelx(pname, params[0], c); - return; - } - - if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - - c->lighting.lightModel.ambient.r = params[0]; - c->lighting.lightModel.ambient.g = params[1]; - c->lighting.lightModel.ambient.b = params[2]; - c->lighting.lightModel.ambient.a = params[3]; - invalidate_lighting(c); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#endif - -void glLightf(GLenum i, GLenum pname, GLfloat param) -{ - ogles_context_t* c = ogles_context_t::get(); - lightx(i, pname, gglFloatToFixed(param), c); -} - -void glLightx(GLenum i, GLenum pname, GLfixed param) -{ - ogles_context_t* c = ogles_context_t::get(); - lightx(i, pname, param, c); -} - -void glLightfv(GLenum i, GLenum pname, const GLfloat *params) -{ - ogles_context_t* c = ogles_context_t::get(); - switch (pname) { - case GL_SPOT_EXPONENT: - case GL_SPOT_CUTOFF: - case GL_CONSTANT_ATTENUATION: - case GL_LINEAR_ATTENUATION: - case GL_QUADRATIC_ATTENUATION: - lightx(i, pname, gglFloatToFixed(params[0]), c); - return; - } - - GLfixed paramsx[4]; - paramsx[0] = gglFloatToFixed(params[0]); - paramsx[1] = gglFloatToFixed(params[1]); - paramsx[2] = gglFloatToFixed(params[2]); - if (pname != GL_SPOT_DIRECTION) - paramsx[3] = gglFloatToFixed(params[3]); - - lightxv(i, pname, paramsx, c); -} - -void glLightxv(GLenum i, GLenum pname, const GLfixed *params) -{ - ogles_context_t* c = ogles_context_t::get(); - lightxv(i, pname, params, c); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#endif - -void glMaterialf(GLenum face, GLenum pname, GLfloat param) -{ - ogles_context_t* c = ogles_context_t::get(); - materialx(face, pname, gglFloatToFixed(param), c); -} - -void glMaterialx(GLenum face, GLenum pname, GLfixed param) -{ - ogles_context_t* c = ogles_context_t::get(); - materialx(face, pname, param, c); -} - -void glMaterialfv( - GLenum face, GLenum pname, const GLfloat *params) -{ - ogles_context_t* c = ogles_context_t::get(); - if (ggl_unlikely(face != GL_FRONT_AND_BACK)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - GLfixed* what=0; - GLfixed* other=0; - switch (pname) { - case GL_AMBIENT: what = c->lighting.front.ambient.v; break; - case GL_DIFFUSE: what = c->lighting.front.diffuse.v; break; - case GL_SPECULAR: what = c->lighting.front.specular.v; break; - case GL_EMISSION: what = c->lighting.front.emission.v; break; - case GL_AMBIENT_AND_DIFFUSE: - what = c->lighting.front.ambient.v; - other = c->lighting.front.diffuse.v; - break; - case GL_SHININESS: - c->lighting.front.shininess = gglFloatToFixed(params[0]); - invalidate_lighting(c); - return; - default: - ogles_error(c, GL_INVALID_ENUM); - return; - } - what[0] = gglFloatToFixed(params[0]); - what[1] = gglFloatToFixed(params[1]); - what[2] = gglFloatToFixed(params[2]); - what[3] = gglFloatToFixed(params[3]); - if (other) { - other[0] = what[0]; - other[1] = what[1]; - other[2] = what[2]; - other[3] = what[3]; - } - invalidate_lighting(c); -} - -void glMaterialxv( - GLenum face, GLenum pname, const GLfixed *params) -{ - ogles_context_t* c = ogles_context_t::get(); - if (ggl_unlikely(face != GL_FRONT_AND_BACK)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - GLfixed* what=0; - GLfixed* other=0; - switch (pname) { - case GL_AMBIENT: what = c->lighting.front.ambient.v; break; - case GL_DIFFUSE: what = c->lighting.front.diffuse.v; break; - case GL_SPECULAR: what = c->lighting.front.specular.v; break; - case GL_EMISSION: what = c->lighting.front.emission.v; break; - case GL_AMBIENT_AND_DIFFUSE: - what = c->lighting.front.ambient.v; - other = c->lighting.front.diffuse.v; - break; - case GL_SHININESS: - c->lighting.front.shininess = gglFloatToFixed(params[0]); - invalidate_lighting(c); - return; - default: - ogles_error(c, GL_INVALID_ENUM); - return; - } - what[0] = params[0]; - what[1] = params[1]; - what[2] = params[2]; - what[3] = params[3]; - if (other) { - other[0] = what[0]; - other[1] = what[1]; - other[2] = what[2]; - other[3] = what[3]; - } - invalidate_lighting(c); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark fog -#endif - -void glFogf(GLenum pname, GLfloat param) { - ogles_context_t* c = ogles_context_t::get(); - GLfixed paramx = (GLfixed)param; - if (pname != GL_FOG_MODE) - paramx = gglFloatToFixed(param); - fogx(pname, paramx, c); -} - -void glFogx(GLenum pname, GLfixed param) { - ogles_context_t* c = ogles_context_t::get(); - fogx(pname, param, c); -} - -void glFogfv(GLenum pname, const GLfloat *params) -{ - ogles_context_t* c = ogles_context_t::get(); - if (pname != GL_FOG_COLOR) { - GLfixed paramx = (GLfixed)params[0]; - if (pname != GL_FOG_MODE) - paramx = gglFloatToFixed(params[0]); - fogx(pname, paramx, c); - return; - } - GLfixed paramsx[4]; - paramsx[0] = gglFloatToFixed(params[0]); - paramsx[1] = gglFloatToFixed(params[1]); - paramsx[2] = gglFloatToFixed(params[2]); - paramsx[3] = gglFloatToFixed(params[3]); - c->rasterizer.procs.fogColor3xv(c, paramsx); -} - -void glFogxv(GLenum pname, const GLfixed *params) -{ - ogles_context_t* c = ogles_context_t::get(); - if (pname != GL_FOG_COLOR) { - fogx(pname, params[0], c); - return; - } - c->rasterizer.procs.fogColor3xv(c, params); -} diff --git a/opengl/libagl/light.h b/opengl/libagl/light.h deleted file mode 100644 index 39e3309d0d..0000000000 --- a/opengl/libagl/light.h +++ /dev/null @@ -1,45 +0,0 @@ -/* libs/opengles/light.h -** -** Copyright 2006, 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_OPENGLES_LIGHT_H -#define ANDROID_OPENGLES_LIGHT_H - -#include -#include -#include - - -// Set to 1 for object-space lighting evaluation. -// There are still some bugs with object-space lighting, -// especially visible in the San Angeles demo. -#define OBJECT_SPACE_LIGHTING 0 - - -namespace android { - -namespace gl { -struct ogles_context_t; -}; - -void ogles_init_light(ogles_context_t* c); -void ogles_uninit_light(ogles_context_t* c); -void ogles_invalidate_lighting_mvui(ogles_context_t* c); - -}; // namespace android - -#endif // ANDROID_OPENGLES_LIGHT_H - diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp deleted file mode 100644 index edd474d30c..0000000000 --- a/opengl/libagl/matrix.cpp +++ /dev/null @@ -1,1123 +0,0 @@ -/* libs/opengles/matrix.cpp -** -** Copyright 2006, 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 -#include - -#include "context.h" -#include "fp.h" -#include "state.h" -#include "matrix.h" -#include "vertex.h" -#include "light.h" - -#if defined(__arm__) && defined(__thumb__) -#warning "matrix.cpp should not be compiled in thumb on ARM." -#endif - -#define I(_i, _j) ((_j)+ 4*(_i)) - -namespace android { - -// ---------------------------------------------------------------------------- - -static const GLfloat gIdentityf[16] = { 1,0,0,0, - 0,1,0,0, - 0,0,1,0, - 0,0,0,1 }; - -static const matrixx_t gIdentityx = { - { 0x10000,0,0,0, - 0,0x10000,0,0, - 0,0,0x10000,0, - 0,0,0,0x10000 - } - }; - -static void point2__nop(transform_t const*, vec4_t* c, vec4_t const* o); -static void point3__nop(transform_t const*, vec4_t* c, vec4_t const* o); -static void point4__nop(transform_t const*, vec4_t* c, vec4_t const* o); -static void point2__generic(transform_t const*, vec4_t* c, vec4_t const* o); -static void point3__generic(transform_t const*, vec4_t* c, vec4_t const* o); -static void point4__generic(transform_t const*, vec4_t* c, vec4_t const* o); -static void point3__mvui(transform_t const*, vec4_t* c, vec4_t const* o); -static void point4__mvui(transform_t const*, vec4_t* c, vec4_t const* o); - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#endif - -void ogles_init_matrix(ogles_context_t* c) -{ - c->transforms.modelview.init(OGLES_MODELVIEW_STACK_DEPTH); - c->transforms.projection.init(OGLES_PROJECTION_STACK_DEPTH); - for (int i=0; itransforms.texture[i].init(OGLES_TEXTURE_STACK_DEPTH); - - c->transforms.current = &c->transforms.modelview; - c->transforms.matrixMode = GL_MODELVIEW; - c->transforms.dirty = transform_state_t::VIEWPORT | - transform_state_t::MVUI | - transform_state_t::MVIT | - transform_state_t::MVP; - c->transforms.mvp.loadIdentity(); - c->transforms.mvp4.loadIdentity(); - c->transforms.mvit4.loadIdentity(); - c->transforms.mvui.loadIdentity(); - c->transforms.vpt.loadIdentity(); - c->transforms.vpt.zNear = 0.0f; - c->transforms.vpt.zFar = 1.0f; -} - -void ogles_uninit_matrix(ogles_context_t* c) -{ - c->transforms.modelview.uninit(); - c->transforms.projection.uninit(); - for (int i=0; itransforms.texture[i].uninit(); -} - -static void validate_perspective(ogles_context_t* c, vertex_t* v) -{ - const uint32_t enables = c->rasterizer.state.enables; - c->arrays.perspective = (c->clipPlanes.enable) ? - ogles_vertex_clipAllPerspective3D : ogles_vertex_perspective3D; - if (enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) { - c->arrays.perspective = ogles_vertex_perspective3DZ; - if (c->clipPlanes.enable || (enables&GGL_ENABLE_FOG)) - c->arrays.perspective = ogles_vertex_clipAllPerspective3DZ; - } - if ((c->arrays.vertex.size != 4) && - (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION)) { - c->arrays.perspective = ogles_vertex_perspective2D; - } - c->arrays.perspective(c, v); -} - -void ogles_invalidate_perspective(ogles_context_t* c) -{ - c->arrays.perspective = validate_perspective; -} - -void ogles_validate_transform_impl(ogles_context_t* c, uint32_t want) -{ - int dirty = c->transforms.dirty & want; - - // Validate the modelview - if (dirty & transform_state_t::MODELVIEW) { - c->transforms.modelview.validate(); - } - - // Validate the projection stack (in fact, it's never needed) - if (dirty & transform_state_t::PROJECTION) { - c->transforms.projection.validate(); - } - - // Validate the viewport transformation - if (dirty & transform_state_t::VIEWPORT) { - vp_transform_t& vpt = c->transforms.vpt; - vpt.transform.matrix.load(vpt.matrix); - vpt.transform.picker(); - } - - // We need to update the mvp (used to transform each vertex) - if (dirty & transform_state_t::MVP) { - c->transforms.update_mvp(); - // invalidate perspective (divide by W) and view volume clipping - ogles_invalidate_perspective(c); - } - - // Validate the mvui (for normal transformation) - if (dirty & transform_state_t::MVUI) { - c->transforms.update_mvui(); - ogles_invalidate_lighting_mvui(c); - } - - // Validate the texture stack - if (dirty & transform_state_t::TEXTURE) { - for (int i=0; itransforms.texture[i].validate(); - } - - // Validate the mvit4 (user-clip planes) - if (dirty & transform_state_t::MVIT) { - c->transforms.update_mvit(); - } - - c->transforms.dirty &= ~want; -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark transform_t -#endif - -void transform_t::loadIdentity() { - matrix = gIdentityx; - flags = 0; - ops = OP_IDENTITY; - point2 = point2__nop; - point3 = point3__nop; - point4 = point4__nop; -} - - -static inline -int notZero(GLfixed v) { - return abs(v) & ~0x3; -} - -static inline -int notOne(GLfixed v) { - return notZero(v - 0x10000); -} - -void transform_t::picker() -{ - const GLfixed* const m = matrix.m; - - // XXX: picker needs to be smarter - flags = 0; - ops = OP_ALL; - point2 = point2__generic; - point3 = point3__generic; - point4 = point4__generic; - - // find out if this is a 2D projection - if (!(notZero(m[3]) | notZero(m[7]) | notZero(m[11]) | notOne(m[15]))) { - flags |= FLAGS_2D_PROJECTION; - } -} - -void mvui_transform_t::picker() -{ - flags = 0; - ops = OP_ALL; - point3 = point3__mvui; - point4 = point4__mvui; -} - -void transform_t::dump(const char* what) -{ - GLfixed const * const m = matrix.m; - ALOGD("%s:", what); - for (int i=0 ; i<4 ; i++) - ALOGD("[%08x %08x %08x %08x] [%f %f %f %f]\n", - m[I(0,i)], m[I(1,i)], m[I(2,i)], m[I(3,i)], - fixedToFloat(m[I(0,i)]), - fixedToFloat(m[I(1,i)]), - fixedToFloat(m[I(2,i)]), - fixedToFloat(m[I(3,i)])); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark matrixx_t -#endif - -void matrixx_t::load(const matrixf_t& rhs) { - GLfixed* xp = m; - GLfloat const* fp = rhs.elements(); - unsigned int i = 16; - do { - const GLfloat f = *fp++; - *xp++ = isZerof(f) ? 0 : gglFloatToFixed(f); - } while (--i); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark matrixf_t -#endif - -void matrixf_t::multiply(matrixf_t& r, const matrixf_t& lhs, const matrixf_t& rhs) -{ - GLfloat const* const m = lhs.m; - for (int i=0 ; i<4 ; i++) { - const float rhs_i0 = rhs.m[ I(i,0) ]; - float ri0 = m[ I(0,0) ] * rhs_i0; - float ri1 = m[ I(0,1) ] * rhs_i0; - float ri2 = m[ I(0,2) ] * rhs_i0; - float ri3 = m[ I(0,3) ] * rhs_i0; - for (int j=1 ; j<4 ; j++) { - const float rhs_ij = rhs.m[ I(i,j) ]; - ri0 += m[ I(j,0) ] * rhs_ij; - ri1 += m[ I(j,1) ] * rhs_ij; - ri2 += m[ I(j,2) ] * rhs_ij; - ri3 += m[ I(j,3) ] * rhs_ij; - } - r.m[ I(i,0) ] = ri0; - r.m[ I(i,1) ] = ri1; - r.m[ I(i,2) ] = ri2; - r.m[ I(i,3) ] = ri3; - } -} - -void matrixf_t::dump(const char* what) { - ALOGD("%s", what); - ALOGD("[ %9f %9f %9f %9f ]", m[I(0,0)], m[I(1,0)], m[I(2,0)], m[I(3,0)]); - ALOGD("[ %9f %9f %9f %9f ]", m[I(0,1)], m[I(1,1)], m[I(2,1)], m[I(3,1)]); - ALOGD("[ %9f %9f %9f %9f ]", m[I(0,2)], m[I(1,2)], m[I(2,2)], m[I(3,2)]); - ALOGD("[ %9f %9f %9f %9f ]", m[I(0,3)], m[I(1,3)], m[I(2,3)], m[I(3,3)]); -} - -void matrixf_t::loadIdentity() { - memcpy(m, gIdentityf, sizeof(m)); -} - -void matrixf_t::set(const GLfixed* rhs) { - load(rhs); -} - -void matrixf_t::set(const GLfloat* rhs) { - load(rhs); -} - -void matrixf_t::load(const GLfixed* rhs) { - GLfloat* fp = m; - unsigned int i = 16; - do { - *fp++ = fixedToFloat(*rhs++); - } while (--i); -} - -void matrixf_t::load(const GLfloat* rhs) { - memcpy(m, rhs, sizeof(m)); -} - -void matrixf_t::load(const matrixf_t& rhs) { - operator = (rhs); -} - -void matrixf_t::multiply(const matrixf_t& rhs) { - matrixf_t r; - multiply(r, *this, rhs); - operator = (r); -} - -void matrixf_t::translate(GLfloat x, GLfloat y, GLfloat z) { - for (int i=0 ; i<4 ; i++) { - m[12+i] += m[i]*x + m[4+i]*y + m[8+i]*z; - } -} - -void matrixf_t::scale(GLfloat x, GLfloat y, GLfloat z) { - for (int i=0 ; i<4 ; i++) { - m[ i] *= x; - m[4+i] *= y; - m[8+i] *= z; - } -} - -void matrixf_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z) -{ - matrixf_t rotation; - GLfloat* r = rotation.m; - GLfloat c, s; - r[3] = 0; r[7] = 0; r[11]= 0; - r[12]= 0; r[13]= 0; r[14]= 0; r[15]= 1; - a *= GLfloat(M_PI / 180.0f); - sincosf(a, &s, &c); - if (isOnef(x) && isZerof(y) && isZerof(z)) { - r[5] = c; r[10]= c; - r[6] = s; r[9] = -s; - r[1] = 0; r[2] = 0; - r[4] = 0; r[8] = 0; - r[0] = 1; - } else if (isZerof(x) && isOnef(y) && isZerof(z)) { - r[0] = c; r[10]= c; - r[8] = s; r[2] = -s; - r[1] = 0; r[4] = 0; - r[6] = 0; r[9] = 0; - r[5] = 1; - } else if (isZerof(x) && isZerof(y) && isOnef(z)) { - r[0] = c; r[5] = c; - r[1] = s; r[4] = -s; - r[2] = 0; r[6] = 0; - r[8] = 0; r[9] = 0; - r[10]= 1; - } else { - const GLfloat len = sqrtf(x*x + y*y + z*z); - if (!isOnef(len)) { - const GLfloat recipLen = reciprocalf(len); - x *= recipLen; - y *= recipLen; - z *= recipLen; - } - const GLfloat nc = 1.0f - c; - const GLfloat xy = x * y; - const GLfloat yz = y * z; - const GLfloat zx = z * x; - const GLfloat xs = x * s; - const GLfloat ys = y * s; - const GLfloat zs = z * s; - r[ 0] = x*x*nc + c; r[ 4] = xy*nc - zs; r[ 8] = zx*nc + ys; - r[ 1] = xy*nc + zs; r[ 5] = y*y*nc + c; r[ 9] = yz*nc - xs; - r[ 2] = zx*nc - ys; r[ 6] = yz*nc + xs; r[10] = z*z*nc + c; - } - multiply(rotation); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark matrix_stack_t -#endif - -void matrix_stack_t::init(int depth) { - stack = new matrixf_t[depth]; - ops = new uint8_t[depth]; - maxDepth = depth; - depth = 0; - dirty = 0; - loadIdentity(); -} - -void matrix_stack_t::uninit() { - delete [] stack; - delete [] ops; -} - -void matrix_stack_t::loadIdentity() { - transform.loadIdentity(); - stack[depth].loadIdentity(); - ops[depth] = OP_IDENTITY; -} - -void matrix_stack_t::load(const GLfixed* rhs) -{ - memcpy(transform.matrix.m, rhs, sizeof(transform.matrix.m)); - stack[depth].load(rhs); - ops[depth] = OP_ALL; // TODO: we should look at the matrix -} - -void matrix_stack_t::load(const GLfloat* rhs) -{ - stack[depth].load(rhs); - ops[depth] = OP_ALL; // TODO: we should look at the matrix -} - -void matrix_stack_t::multiply(const matrixf_t& rhs) -{ - stack[depth].multiply(rhs); - ops[depth] = OP_ALL; // TODO: we should look at the matrix -} - -void matrix_stack_t::translate(GLfloat x, GLfloat y, GLfloat z) -{ - stack[depth].translate(x,y,z); - ops[depth] |= OP_TRANSLATE; -} - -void matrix_stack_t::scale(GLfloat x, GLfloat y, GLfloat z) -{ - stack[depth].scale(x,y,z); - if (x==y && y==z) { - ops[depth] |= OP_UNIFORM_SCALE; - } else { - ops[depth] |= OP_SCALE; - } -} - -void matrix_stack_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z) -{ - stack[depth].rotate(a,x,y,z); - ops[depth] |= OP_ROTATE; -} - -void matrix_stack_t::validate() -{ - if (dirty & DO_FLOAT_TO_FIXED) { - transform.matrix.load(top()); - } - if (dirty & DO_PICKER) { - transform.picker(); - } - dirty = 0; -} - -GLint matrix_stack_t::push() -{ - if (depth >= (maxDepth-1)) { - return GL_STACK_OVERFLOW; - } - stack[depth+1] = stack[depth]; - ops[depth+1] = ops[depth]; - depth++; - return 0; -} - -GLint matrix_stack_t::pop() -{ - if (depth == 0) { - return GL_STACK_UNDERFLOW; - } - depth--; - return 0; -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark vp_transform_t -#endif - -void vp_transform_t::loadIdentity() { - transform.loadIdentity(); - matrix.loadIdentity(); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark transform_state_t -#endif - -void transform_state_t::invalidate() -{ - switch (matrixMode) { - case GL_MODELVIEW: dirty |= MODELVIEW | MVP | MVUI | MVIT; break; - case GL_PROJECTION: dirty |= PROJECTION | MVP; break; - case GL_TEXTURE: dirty |= TEXTURE | MVP; break; - } - current->dirty = matrix_stack_t::DO_PICKER | - matrix_stack_t::DO_FLOAT_TO_FIXED; -} - -void transform_state_t::update_mvp() -{ - matrixf_t temp_mvp; - matrixf_t::multiply(temp_mvp, projection.top(), modelview.top()); - mvp4.matrix.load(temp_mvp); - mvp4.picker(); - - if (mvp4.flags & transform_t::FLAGS_2D_PROJECTION) { - // the mvp matrix doesn't transform W, in this case we can - // premultiply it with the viewport transformation. In addition to - // being more efficient, this is also much more accurate and in fact - // is needed for 2D drawing with a resulting 1:1 mapping. - matrixf_t mvpv; - matrixf_t::multiply(mvpv, vpt.matrix, temp_mvp); - mvp.matrix.load(mvpv); - mvp.picker(); - } else { - mvp = mvp4; - } -} - -static __attribute__((noinline)) -void invert(GLfloat* inverse, const GLfloat* src) -{ - double t; - int i, j, k, swap; - GLfloat tmp[4][4]; - - memcpy(inverse, gIdentityf, sizeof(gIdentityf)); - memcpy(tmp, src, sizeof(GLfloat)*16); - - for (i = 0; i < 4; i++) { - // look for largest element in column - swap = i; - for (j = i + 1; j < 4; j++) { - if (fabs(tmp[j][i]) > fabs(tmp[i][i])) { - swap = j; - } - } - - if (swap != i) { - /* swap rows. */ - for (k = 0; k < 4; k++) { - t = tmp[i][k]; - tmp[i][k] = tmp[swap][k]; - tmp[swap][k] = t; - - t = inverse[i*4+k]; - inverse[i*4+k] = inverse[swap*4+k]; - inverse[swap*4+k] = t; - } - } - - t = 1.0f / tmp[i][i]; - for (k = 0; k < 4; k++) { - tmp[i][k] *= t; - inverse[i*4+k] *= t; - } - for (j = 0; j < 4; j++) { - if (j != i) { - t = tmp[j][i]; - for (k = 0; k < 4; k++) { - tmp[j][k] -= tmp[i][k]*t; - inverse[j*4+k] -= inverse[i*4+k]*t; - } - } - } - } -} - -void transform_state_t::update_mvit() -{ - GLfloat r[16]; - const GLfloat* const mv = modelview.top().elements(); - invert(r, mv); - // convert to fixed-point and transpose - GLfixed* const x = mvit4.matrix.m; - for (int i=0 ; i<4 ; i++) - for (int j=0 ; j<4 ; j++) - x[I(i,j)] = gglFloatToFixed(r[I(j,i)]); - mvit4.picker(); -} - -void transform_state_t::update_mvui() -{ - GLfloat r[16]; - const GLfloat* const mv = modelview.top().elements(); - - /* - When evaluating the lighting equation in eye-space, normals - are transformed by the upper 3x3 modelview inverse-transpose. - http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node26.html - - (note that inverse-transpose is distributive). - Also note that: - l(obj) = inv(modelview).l(eye) for local light - l(obj) = tr(modelview).l(eye) for infinite light - */ - - invert(r, mv); - - GLfixed* const x = mvui.matrix.m; - -#if OBJECT_SPACE_LIGHTING - for (int i=0 ; i<4 ; i++) - for (int j=0 ; j<4 ; j++) - x[I(i,j)] = gglFloatToFixed(r[I(i,j)]); -#else - for (int i=0 ; i<4 ; i++) - for (int j=0 ; j<4 ; j++) - x[I(i,j)] = gglFloatToFixed(r[I(j,i)]); -#endif - - mvui.picker(); -} - - -// ---------------------------------------------------------------------------- -// transformation and matrices API -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark transformation and matrices API -#endif - -int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y) -{ - c->viewport.surfaceport.x = x; - c->viewport.surfaceport.y = y; - - ogles_viewport(c, - c->viewport.x, - c->viewport.y, - c->viewport.w, - c->viewport.h); - - ogles_scissor(c, - c->viewport.scissor.x, - c->viewport.scissor.y, - c->viewport.scissor.w, - c->viewport.scissor.h); - - return 0; -} - -void ogles_scissor(ogles_context_t* c, - GLint x, GLint y, GLsizei w, GLsizei h) -{ - if ((w|h) < 0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - c->viewport.scissor.x = x; - c->viewport.scissor.y = y; - c->viewport.scissor.w = w; - c->viewport.scissor.h = h; - - x += c->viewport.surfaceport.x; - y += c->viewport.surfaceport.y; - - y = c->rasterizer.state.buffers.color.height - (y + h); - c->rasterizer.procs.scissor(c, x, y, w, h); -} - -void ogles_viewport(ogles_context_t* c, - GLint x, GLint y, GLsizei w, GLsizei h) -{ - if ((w|h)<0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - - c->viewport.x = x; - c->viewport.y = y; - c->viewport.w = w; - c->viewport.h = h; - - x += c->viewport.surfaceport.x; - y += c->viewport.surfaceport.y; - - GLint H = c->rasterizer.state.buffers.color.height; - GLfloat sx = div2f(w); - GLfloat ox = sx + x; - GLfloat sy = div2f(h); - GLfloat oy = sy - y + (H - h); - - GLfloat near = c->transforms.vpt.zNear; - GLfloat far = c->transforms.vpt.zFar; - GLfloat A = div2f(far - near); - GLfloat B = div2f(far + near); - - // compute viewport matrix - GLfloat* const f = c->transforms.vpt.matrix.editElements(); - f[0] = sx; f[4] = 0; f[ 8] = 0; f[12] = ox; - f[1] = 0; f[5] =-sy; f[ 9] = 0; f[13] = oy; - f[2] = 0; f[6] = 0; f[10] = A; f[14] = B; - f[3] = 0; f[7] = 0; f[11] = 0; f[15] = 1; - c->transforms.dirty |= transform_state_t::VIEWPORT; - if (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION) - c->transforms.dirty |= transform_state_t::MVP; -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark matrix * vertex -#endif - -void point2__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { - const GLfixed* const m = mx->matrix.m; - const GLfixed rx = rhs->x; - const GLfixed ry = rhs->y; - lhs->x = mla2a(rx, m[ 0], ry, m[ 4], m[12]); - lhs->y = mla2a(rx, m[ 1], ry, m[ 5], m[13]); - lhs->z = mla2a(rx, m[ 2], ry, m[ 6], m[14]); - lhs->w = mla2a(rx, m[ 3], ry, m[ 7], m[15]); -} - -void point3__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { - const GLfixed* const m = mx->matrix.m; - const GLfixed rx = rhs->x; - const GLfixed ry = rhs->y; - const GLfixed rz = rhs->z; - lhs->x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]); - lhs->y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]); - lhs->z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]); - lhs->w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]); -} - -void point4__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { - const GLfixed* const m = mx->matrix.m; - const GLfixed rx = rhs->x; - const GLfixed ry = rhs->y; - const GLfixed rz = rhs->z; - const GLfixed rw = rhs->w; - lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]); - lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]); - lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]); - lhs->w = mla4(rx, m[ 3], ry, m[ 7], rz, m[11], rw, m[15]); -} - -void point3__mvui(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { - // this is used for transforming light positions back to object space. - // w is used as a switch for directional lights, so we need - // to preserve it. - const GLfixed* const m = mx->matrix.m; - const GLfixed rx = rhs->x; - const GLfixed ry = rhs->y; - const GLfixed rz = rhs->z; - lhs->x = mla3(rx, m[ 0], ry, m[ 4], rz, m[ 8]); - lhs->y = mla3(rx, m[ 1], ry, m[ 5], rz, m[ 9]); - lhs->z = mla3(rx, m[ 2], ry, m[ 6], rz, m[10]); - lhs->w = 0; -} - -void point4__mvui(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) { - // this is used for transforming light positions back to object space. - // w is used as a switch for directional lights, so we need - // to preserve it. - const GLfixed* const m = mx->matrix.m; - const GLfixed rx = rhs->x; - const GLfixed ry = rhs->y; - const GLfixed rz = rhs->z; - const GLfixed rw = rhs->w; - lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]); - lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]); - lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]); - lhs->w = rw; -} - -void point2__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { - lhs->z = 0; - lhs->w = 0x10000; - if (lhs != rhs) { - lhs->x = rhs->x; - lhs->y = rhs->y; - } -} - -void point3__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { - lhs->w = 0x10000; - if (lhs != rhs) { - lhs->x = rhs->x; - lhs->y = rhs->y; - lhs->z = rhs->z; - } -} - -void point4__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) { - if (lhs != rhs) - *lhs = *rhs; -} - - -static void frustumf( - GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat zNear, GLfloat zFar, - ogles_context_t* c) - { - if (cmpf(left,right) || - cmpf(top, bottom) || - cmpf(zNear, zFar) || - isZeroOrNegativef(zNear) || - isZeroOrNegativef(zFar)) - { - ogles_error(c, GL_INVALID_VALUE); - return; - } - const GLfloat r_width = reciprocalf(right - left); - const GLfloat r_height = reciprocalf(top - bottom); - const GLfloat r_depth = reciprocalf(zNear - zFar); - const GLfloat x = mul2f(zNear * r_width); - const GLfloat y = mul2f(zNear * r_height); - const GLfloat A = mul2f((right + left) * r_width); - const GLfloat B = (top + bottom) * r_height; - const GLfloat C = (zFar + zNear) * r_depth; - const GLfloat D = mul2f(zFar * zNear * r_depth); - GLfloat f[16]; - f[ 0] = x; - f[ 5] = y; - f[ 8] = A; - f[ 9] = B; - f[10] = C; - f[14] = D; - f[11] = -1.0f; - f[ 1] = f[ 2] = f[ 3] = - f[ 4] = f[ 6] = f[ 7] = - f[12] = f[13] = f[15] = 0.0f; - - matrixf_t rhs; - rhs.set(f); - c->transforms.current->multiply(rhs); - c->transforms.invalidate(); -} - -static void orthof( - GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat zNear, GLfloat zFar, - ogles_context_t* c) -{ - if (cmpf(left,right) || - cmpf(top, bottom) || - cmpf(zNear, zFar)) - { - ogles_error(c, GL_INVALID_VALUE); - return; - } - const GLfloat r_width = reciprocalf(right - left); - const GLfloat r_height = reciprocalf(top - bottom); - const GLfloat r_depth = reciprocalf(zFar - zNear); - const GLfloat x = mul2f(r_width); - const GLfloat y = mul2f(r_height); - const GLfloat z = -mul2f(r_depth); - const GLfloat tx = -(right + left) * r_width; - const GLfloat ty = -(top + bottom) * r_height; - const GLfloat tz = -(zFar + zNear) * r_depth; - GLfloat f[16]; - f[ 0] = x; - f[ 5] = y; - f[10] = z; - f[12] = tx; - f[13] = ty; - f[14] = tz; - f[15] = 1.0f; - f[ 1] = f[ 2] = f[ 3] = - f[ 4] = f[ 6] = f[ 7] = - f[ 8] = f[ 9] = f[11] = 0.0f; - matrixf_t rhs; - rhs.set(f); - c->transforms.current->multiply(rhs); - c->transforms.invalidate(); -} - -static void depthRangef(GLclampf zNear, GLclampf zFar, ogles_context_t* c) -{ - zNear = clampToZerof(zNear > 1 ? 1 : zNear); - zFar = clampToZerof(zFar > 1 ? 1 : zFar); - GLfloat* const f = c->transforms.vpt.matrix.editElements(); - f[10] = div2f(zFar - zNear); - f[14] = div2f(zFar + zNear); - c->transforms.dirty |= transform_state_t::VIEWPORT; - c->transforms.vpt.zNear = zNear; - c->transforms.vpt.zFar = zFar; -} - - -// ---------------------------------------------------------------------------- -}; // namespace android - -using namespace android; - -void glMatrixMode(GLenum mode) -{ - ogles_context_t* c = ogles_context_t::get(); - matrix_stack_t* stack = 0; - switch (mode) { - case GL_MODELVIEW: - stack = &c->transforms.modelview; - break; - case GL_PROJECTION: - stack = &c->transforms.projection; - break; - case GL_TEXTURE: - stack = &c->transforms.texture[c->textures.active]; - break; - default: - ogles_error(c, GL_INVALID_ENUM); - return; - } - c->transforms.matrixMode = mode; - c->transforms.current = stack; -} - -void glLoadIdentity() -{ - ogles_context_t* c = ogles_context_t::get(); - c->transforms.current->loadIdentity(); // also loads the GLfixed transform - c->transforms.invalidate(); - c->transforms.current->dirty = 0; -} - -void glLoadMatrixf(const GLfloat* m) -{ - ogles_context_t* c = ogles_context_t::get(); - c->transforms.current->load(m); - c->transforms.invalidate(); -} - -void glLoadMatrixx(const GLfixed* m) -{ - ogles_context_t* c = ogles_context_t::get(); - c->transforms.current->load(m); // also loads the GLfixed transform - c->transforms.invalidate(); - c->transforms.current->dirty &= ~matrix_stack_t::DO_FLOAT_TO_FIXED; -} - -void glMultMatrixf(const GLfloat* m) -{ - ogles_context_t* c = ogles_context_t::get(); - matrixf_t rhs; - rhs.set(m); - c->transforms.current->multiply(rhs); - c->transforms.invalidate(); -} - -void glMultMatrixx(const GLfixed* m) -{ - ogles_context_t* c = ogles_context_t::get(); - matrixf_t rhs; - rhs.set(m); - c->transforms.current->multiply(rhs); - c->transforms.invalidate(); -} - -void glPopMatrix() -{ - ogles_context_t* c = ogles_context_t::get(); - GLint err = c->transforms.current->pop(); - if (ggl_unlikely(err)) { - ogles_error(c, err); - return; - } - c->transforms.invalidate(); -} - -void glPushMatrix() -{ - ogles_context_t* c = ogles_context_t::get(); - GLint err = c->transforms.current->push(); - if (ggl_unlikely(err)) { - ogles_error(c, err); - return; - } - c->transforms.invalidate(); -} - -void glFrustumf( - GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat zNear, GLfloat zFar) -{ - ogles_context_t* c = ogles_context_t::get(); - frustumf(left, right, bottom, top, zNear, zFar, c); -} - -void glFrustumx( - GLfixed left, GLfixed right, - GLfixed bottom, GLfixed top, - GLfixed zNear, GLfixed zFar) -{ - ogles_context_t* c = ogles_context_t::get(); - frustumf( fixedToFloat(left), fixedToFloat(right), - fixedToFloat(bottom), fixedToFloat(top), - fixedToFloat(zNear), fixedToFloat(zFar), - c); -} - -void glOrthof( - GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat zNear, GLfloat zFar) -{ - ogles_context_t* c = ogles_context_t::get(); - orthof(left, right, bottom, top, zNear, zFar, c); -} - -void glOrthox( - GLfixed left, GLfixed right, - GLfixed bottom, GLfixed top, - GLfixed zNear, GLfixed zFar) -{ - ogles_context_t* c = ogles_context_t::get(); - orthof( fixedToFloat(left), fixedToFloat(right), - fixedToFloat(bottom), fixedToFloat(top), - fixedToFloat(zNear), fixedToFloat(zFar), - c); -} - -void glRotatef(GLfloat a, GLfloat x, GLfloat y, GLfloat z) -{ - ogles_context_t* c = ogles_context_t::get(); - c->transforms.current->rotate(a, x, y, z); - c->transforms.invalidate(); -} - -void glRotatex(GLfixed a, GLfixed x, GLfixed y, GLfixed z) -{ - ogles_context_t* c = ogles_context_t::get(); - c->transforms.current->rotate( - fixedToFloat(a), fixedToFloat(x), - fixedToFloat(y), fixedToFloat(z)); - c->transforms.invalidate(); -} - -void glScalef(GLfloat x, GLfloat y, GLfloat z) -{ - ogles_context_t* c = ogles_context_t::get(); - c->transforms.current->scale(x, y, z); - c->transforms.invalidate(); -} - -void glScalex(GLfixed x, GLfixed y, GLfixed z) -{ - ogles_context_t* c = ogles_context_t::get(); - c->transforms.current->scale( - fixedToFloat(x), fixedToFloat(y), fixedToFloat(z)); - c->transforms.invalidate(); -} - -void glTranslatef(GLfloat x, GLfloat y, GLfloat z) -{ - ogles_context_t* c = ogles_context_t::get(); - c->transforms.current->translate(x, y, z); - c->transforms.invalidate(); -} - -void glTranslatex(GLfixed x, GLfixed y, GLfixed z) -{ - ogles_context_t* c = ogles_context_t::get(); - c->transforms.current->translate( - fixedToFloat(x), fixedToFloat(y), fixedToFloat(z)); - c->transforms.invalidate(); -} - -void glScissor(GLint x, GLint y, GLsizei w, GLsizei h) -{ - ogles_context_t* c = ogles_context_t::get(); - ogles_scissor(c, x, y, w, h); -} - -void glViewport(GLint x, GLint y, GLsizei w, GLsizei h) -{ - ogles_context_t* c = ogles_context_t::get(); - ogles_viewport(c, x, y, w, h); -} - -void glDepthRangef(GLclampf zNear, GLclampf zFar) -{ - ogles_context_t* c = ogles_context_t::get(); - depthRangef(zNear, zFar, c); -} - -void glDepthRangex(GLclampx zNear, GLclampx zFar) -{ - ogles_context_t* c = ogles_context_t::get(); - depthRangef(fixedToFloat(zNear), fixedToFloat(zFar), c); -} - -void glPolygonOffsetx(GLfixed factor, GLfixed units) -{ - ogles_context_t* c = ogles_context_t::get(); - c->polygonOffset.factor = factor; - c->polygonOffset.units = units; -} - -void glPolygonOffset(GLfloat factor, GLfloat units) -{ - ogles_context_t* c = ogles_context_t::get(); - c->polygonOffset.factor = gglFloatToFixed(factor); - c->polygonOffset.units = gglFloatToFixed(units); -} - -GLbitfield glQueryMatrixxOES(GLfixed* m, GLint* e) -{ - ogles_context_t* c = ogles_context_t::get(); - GLbitfield status = 0; - GLfloat const* f = c->transforms.current->top().elements(); - for (int i=0 ; i<16 ; i++) { - if (isnan(f[i]) || isinf(f[i])) { - status |= 1< -#include -#include -#include - -#include - -#include - -namespace android { - -const int OGLES_MODELVIEW_STACK_DEPTH = 16; -const int OGLES_PROJECTION_STACK_DEPTH = 2; -const int OGLES_TEXTURE_STACK_DEPTH = 2; - -void ogles_init_matrix(ogles_context_t*); -void ogles_uninit_matrix(ogles_context_t*); -void ogles_invalidate_perspective(ogles_context_t* c); -void ogles_validate_transform_impl(ogles_context_t* c, uint32_t want); - -int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y); - -void ogles_scissor(ogles_context_t* c, - GLint x, GLint y, GLsizei w, GLsizei h); - -void ogles_viewport(ogles_context_t* c, - GLint x, GLint y, GLsizei w, GLsizei h); - -inline void ogles_validate_transform( - ogles_context_t* c, uint32_t want) -{ - if (c->transforms.dirty & want) - ogles_validate_transform_impl(c, want); -} - -// ---------------------------------------------------------------------------- - -inline -GLfixed vsquare3(GLfixed a, GLfixed b, GLfixed c) -{ -#if defined(__arm__) && !defined(__thumb__) - - GLfixed r; - int32_t t; - asm( - "smull %0, %1, %2, %2 \n" - "smlal %0, %1, %3, %3 \n" - "smlal %0, %1, %4, %4 \n" - "movs %0, %0, lsr #16 \n" - "adc %0, %0, %1, lsl #16 \n" - : "=&r"(r), "=&r"(t) - : "%r"(a), "r"(b), "r"(c) - : "cc" - ); - return r; - -#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 - - GLfixed res; - int32_t t1,t2,t3; - asm( - "mult %[a], %[a] \r\n" - "li %[res],0x8000 \r\n" - "madd %[b],%[b] \r\n" - "move %[t3],$zero \r\n" - "madd %[c],%[c] \r\n" - "mflo %[t1]\r\n" - "mfhi %[t2]\r\n" - "addu %[t1],%[res],%[t1]\r\n" /*add 0x8000*/ - "sltu %[t3],%[t1],%[res]\r\n" - "addu %[t2],%[t2],%[t3]\r\n" - "srl %[res],%[t1],16\r\n" - "sll %[t2],%[t2],16\r\n" - "or %[res],%[res],%[t2]\r\n" - : [res]"=&r"(res),[t1]"=&r"(t1),[t2]"=&r"(t2),[t3]"=&r"(t3) - : [a] "r" (a),[b] "r" (b),[c] "r" (c) - : "%hi","%lo" - ); - return res; - -#else - - return (( int64_t(a)*a + - int64_t(b)*b + - int64_t(c)*c + 0x8000)>>16); - -#endif -} - -static inline GLfixed mla2a( GLfixed a0, GLfixed b0, - GLfixed a1, GLfixed b1, - GLfixed c) -{ -#if defined(__arm__) && !defined(__thumb__) - - GLfixed r; - int32_t t; - asm( - "smull %0, %1, %2, %3 \n" - "smlal %0, %1, %4, %5 \n" - "add %0, %6, %0, lsr #16 \n" - "add %0, %0, %1, lsl #16 \n" - : "=&r"(r), "=&r"(t) - : "%r"(a0), "r"(b0), - "%r"(a1), "r"(b1), - "r"(c) - : - ); - return r; - -#else - - return (( int64_t(a0)*b0 + - int64_t(a1)*b1)>>16) + c; - -#endif -} - -static inline GLfixed mla3a( GLfixed a0, GLfixed b0, - GLfixed a1, GLfixed b1, - GLfixed a2, GLfixed b2, - GLfixed c) -{ -#if defined(__arm__) && !defined(__thumb__) - - GLfixed r; - int32_t t; - asm( - "smull %0, %1, %2, %3 \n" - "smlal %0, %1, %4, %5 \n" - "smlal %0, %1, %6, %7 \n" - "add %0, %8, %0, lsr #16 \n" - "add %0, %0, %1, lsl #16 \n" - : "=&r"(r), "=&r"(t) - : "%r"(a0), "r"(b0), - "%r"(a1), "r"(b1), - "%r"(a2), "r"(b2), - "r"(c) - : - ); - return r; - -#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 - - GLfixed res; - int32_t t1,t2; - asm( - "mult %[a0],%[b0] \r\n" - "madd %[a1],%[b1] \r\n" - "madd %[a2],%[b2] \r\n" - "mflo %[t2]\r\n" - "mfhi %[t1]\r\n" - "srl %[t2],%[t2],16\r\n" - "sll %[t1],%[t1],16\r\n" - "or %[t2],%[t2],%[t1]\r\n" - "addu %[res],%[t2],%[c]" - : [res]"=&r"(res),[t1]"=&r"(t1),[t2]"=&r"(t2) - : [a0] "r" (a0),[b0] "r" (b0),[a1] "r" (a1),[b1] "r" (b1),[a2] "r" (a2),[b2] "r" (b2),[c] "r" (c) - : "%hi","%lo" - ); - return res; - -#else - - return (( int64_t(a0)*b0 + - int64_t(a1)*b1 + - int64_t(a2)*b2)>>16) + c; - -#endif -} - -// b0, b1, b2 are signed 16-bit quanities -// that have been shifted right by 'shift' bits relative to normal -// S16.16 fixed point -static inline GLfixed mla3a16( GLfixed a0, int32_t b1b0, - GLfixed a1, - GLfixed a2, int32_t b2, - GLint shift, - GLfixed c) -{ -#if defined(__arm__) && !defined(__thumb__) - - GLfixed r; - asm( - "smulwb %0, %1, %2 \n" - "smlawt %0, %3, %2, %0 \n" - "smlawb %0, %4, %5, %0 \n" - "add %0, %7, %0, lsl %6 \n" - : "=&r"(r) - : "r"(a0), "r"(b1b0), - "r"(a1), - "r"(a2), "r"(b2), - "r"(shift), - "r"(c) - : - ); - return r; - -#else - - int32_t accum; - int16_t b0 = b1b0 & 0xffff; - int16_t b1 = (b1b0 >> 16) & 0xffff; - accum = int64_t(a0)*int16_t(b0) >> 16; - accum += int64_t(a1)*int16_t(b1) >> 16; - accum += int64_t(a2)*int16_t(b2) >> 16; - accum = (accum << shift) + c; - return accum; - -#endif -} - - -static inline GLfixed mla3a16_btb( GLfixed a0, - GLfixed a1, - GLfixed a2, - int32_t b1b0, int32_t xxb2, - GLint shift, - GLfixed c) -{ -#if defined(__arm__) && !defined(__thumb__) - - GLfixed r; - asm( - "smulwb %0, %1, %4 \n" - "smlawt %0, %2, %4, %0 \n" - "smlawb %0, %3, %5, %0 \n" - "add %0, %7, %0, lsl %6 \n" - : "=&r"(r) - : "r"(a0), - "r"(a1), - "r"(a2), - "r"(b1b0), "r"(xxb2), - "r"(shift), - "r"(c) - : - ); - return r; - -#else - - int32_t accum; - int16_t b0 = b1b0 & 0xffff; - int16_t b1 = (b1b0 >> 16) & 0xffff; - int16_t b2 = xxb2 & 0xffff; - accum = int64_t(a0)*int16_t(b0) >> 16; - accum += int64_t(a1)*int16_t(b1) >> 16; - accum += int64_t(a2)*int16_t(b2) >> 16; - accum = (accum << shift) + c; - return accum; - -#endif -} - -static inline GLfixed mla3a16_btt( GLfixed a0, - GLfixed a1, - GLfixed a2, - int32_t b1b0, int32_t b2xx, - GLint shift, - GLfixed c) -{ -#if defined(__arm__) && !defined(__thumb__) - - GLfixed r; - asm( - "smulwb %0, %1, %4 \n" - "smlawt %0, %2, %4, %0 \n" - "smlawt %0, %3, %5, %0 \n" - "add %0, %7, %0, lsl %6 \n" - : "=&r"(r) - : "r"(a0), - "r"(a1), - "r"(a2), - "r"(b1b0), "r"(b2xx), - "r"(shift), - "r"(c) - : - ); - return r; - -#else - - int32_t accum; - int16_t b0 = b1b0 & 0xffff; - int16_t b1 = (b1b0 >> 16) & 0xffff; - int16_t b2 = (b2xx >> 16) & 0xffff; - accum = int64_t(a0)*int16_t(b0) >> 16; - accum += int64_t(a1)*int16_t(b1) >> 16; - accum += int64_t(a2)*int16_t(b2) >> 16; - accum = (accum << shift) + c; - return accum; - -#endif -} - -static inline GLfixed mla3( GLfixed a0, GLfixed b0, - GLfixed a1, GLfixed b1, - GLfixed a2, GLfixed b2) -{ -#if defined(__arm__) && !defined(__thumb__) - - GLfixed r; - int32_t t; - asm( - "smull %0, %1, %2, %3 \n" - "smlal %0, %1, %4, %5 \n" - "smlal %0, %1, %6, %7 \n" - "movs %0, %0, lsr #16 \n" - "adc %0, %0, %1, lsl #16 \n" - : "=&r"(r), "=&r"(t) - : "%r"(a0), "r"(b0), - "%r"(a1), "r"(b1), - "%r"(a2), "r"(b2) - : "cc" - ); - return r; - -#else - - return (( int64_t(a0)*b0 + - int64_t(a1)*b1 + - int64_t(a2)*b2 + 0x8000)>>16); - -#endif -} - -static inline GLfixed mla4( GLfixed a0, GLfixed b0, - GLfixed a1, GLfixed b1, - GLfixed a2, GLfixed b2, - GLfixed a3, GLfixed b3) -{ -#if defined(__arm__) && !defined(__thumb__) - - GLfixed r; - int32_t t; - asm( - "smull %0, %1, %2, %3 \n" - "smlal %0, %1, %4, %5 \n" - "smlal %0, %1, %6, %7 \n" - "smlal %0, %1, %8, %9 \n" - "movs %0, %0, lsr #16 \n" - "adc %0, %0, %1, lsl #16 \n" - : "=&r"(r), "=&r"(t) - : "%r"(a0), "r"(b0), - "%r"(a1), "r"(b1), - "%r"(a2), "r"(b2), - "%r"(a3), "r"(b3) - : "cc" - ); - return r; - -#else - - return (( int64_t(a0)*b0 + - int64_t(a1)*b1 + - int64_t(a2)*b2 + - int64_t(a3)*b3 + 0x8000)>>16); - -#endif -} - -inline -GLfixed dot4(const GLfixed* a, const GLfixed* b) -{ - return mla4(a[0], b[0], a[1], b[1], a[2], b[2], a[3], b[3]); -} - - -inline -GLfixed dot3(const GLfixed* a, const GLfixed* b) -{ - return mla3(a[0], b[0], a[1], b[1], a[2], b[2]); -} - - -}; // namespace android - -#endif // ANDROID_OPENGLES_MATRIX_H - diff --git a/opengl/libagl/mipmap.cpp b/opengl/libagl/mipmap.cpp deleted file mode 100644 index e142a58d00..0000000000 --- a/opengl/libagl/mipmap.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* libs/opengles/mipmap.cpp -** -** Copyright 2006, 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 -#include - -#include "context.h" -#include "state.h" -#include "texture.h" -#include "TextureObjectManager.h" - -namespace android { - -// ---------------------------------------------------------------------------- - -status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex) -{ - int level = 0; - const GGLSurface* base = &tex->surface; - const GGLFormat& pixelFormat(c->rasterizer.formats[base->format]); - - int w = base->width; - int h = base->height; - if ((w&h) == 1) - return NO_ERROR; - - w = (w>>1) ? : 1; - h = (h>>1) ? : 1; - - while(true) { - ++level; - const int bpr = w * pixelFormat.size; - if (tex->reallocate(level, w, h, w, - base->format, base->compressedFormat, bpr) != NO_ERROR) { - return NO_MEMORY; - } - - int stride = w; - int bs = base->stride; - GGLSurface& cur = tex->editMip(level); - - if (base->format == GGL_PIXEL_FORMAT_RGB_565) - { - uint16_t const * src = (uint16_t const *)base->data; - uint16_t* dst = (uint16_t*)cur.data; - const uint32_t mask = 0x07E0F81F; - for (int y=0 ; y> 2) & mask; - uint32_t rgb = (grb & 0xFFFF) | (grb >> 16); - dst[x + y*stride] = rgb; - offset += 2; - } - } - } - else if (base->format == GGL_PIXEL_FORMAT_RGBA_5551) - { - uint16_t const * src = (uint16_t const *)base->data; - uint16_t* dst = (uint16_t*)cur.data; - for (int y=0 ; y>11)+(p10>>11)+(p01>>11)+(p11>>11)+2)>>2; - uint32_t g = (((p00>>6)+(p10>>6)+(p01>>6)+(p11>>6)+2)>>2)&0x3F; - uint32_t b = ((p00&0x3E)+(p10&0x3E)+(p01&0x3E)+(p11&0x3E)+4)>>3; - uint32_t a = ((p00&1)+(p10&1)+(p01&1)+(p11&1)+2)>>2; - dst[x + y*stride] = (r<<11)|(g<<6)|(b<<1)|a; - offset += 2; - } - } - } - else if (base->format == GGL_PIXEL_FORMAT_RGBA_8888) - { - uint32_t const * src = (uint32_t const *)base->data; - uint32_t* dst = (uint32_t*)cur.data; - for (int y=0 ; y> 8) & 0x00FF00FF; - uint32_t ga01 = (p01 >> 8) & 0x00FF00FF; - uint32_t ga10 = (p10 >> 8) & 0x00FF00FF; - uint32_t ga11 = (p11 >> 8) & 0x00FF00FF; - uint32_t rb = (rb00 + rb01 + rb10 + rb11)>>2; - uint32_t ga = (ga00 + ga01 + ga10 + ga11)>>2; - uint32_t rgba = (rb & 0x00FF00FF) | ((ga & 0x00FF00FF)<<8); - dst[x + y*stride] = rgba; - offset += 2; - } - } - } - else if ((base->format == GGL_PIXEL_FORMAT_RGB_888) || - (base->format == GGL_PIXEL_FORMAT_LA_88) || - (base->format == GGL_PIXEL_FORMAT_A_8) || - (base->format == GGL_PIXEL_FORMAT_L_8)) - { - int skip; - switch (base->format) { - case GGL_PIXEL_FORMAT_RGB_888: skip = 3; break; - case GGL_PIXEL_FORMAT_LA_88: skip = 2; break; - default: skip = 1; break; - } - uint8_t const * src = (uint8_t const *)base->data; - uint8_t* dst = (uint8_t*)cur.data; - bs *= skip; - stride *= skip; - for (int y=0 ; y> 2; - } - offset += 2*skip; - } - } - } - else if (base->format == GGL_PIXEL_FORMAT_RGBA_4444) - { - uint16_t const * src = (uint16_t const *)base->data; - uint16_t* dst = (uint16_t*)cur.data; - for (int y=0 ; y> 2; - uint32_t rgba = (rbga & 0x0F0F) | ((rbga>>12) & 0xF0F0); - dst[x + y*stride] = rgba; - offset += 2; - } - } - } else { - ALOGE("Unsupported format (%d)", base->format); - return BAD_TYPE; - } - - // exit condition: we just processed the 1x1 LODs - if ((w&h) == 1) - break; - - base = &cur; - w = (w>>1) ? : 1; - h = (h>>1) ? : 1; - } - return NO_ERROR; -} - -}; // namespace android diff --git a/opengl/libagl/primitives.cpp b/opengl/libagl/primitives.cpp deleted file mode 100644 index d3b19e8e6d..0000000000 --- a/opengl/libagl/primitives.cpp +++ /dev/null @@ -1,1112 +0,0 @@ -/* libs/opengles/primitives.cpp -** -** Copyright 2006, 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 -#include -#include - -#include "context.h" -#include "primitives.h" -#include "light.h" -#include "matrix.h" -#include "vertex.h" -#include "fp.h" -#include "TextureObjectManager.h" - -extern "C" void iterators0032(const void* that, - int32_t* it, int32_t c0, int32_t c1, int32_t c2); - -namespace android { - -// ---------------------------------------------------------------------------- - -static void primitive_point(ogles_context_t* c, vertex_t* v); -static void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1); -static void primitive_clip_triangle(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2); - -static void primitive_nop_point(ogles_context_t* c, vertex_t* v); -static void primitive_nop_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1); -static void primitive_nop_triangle(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2); - -static inline bool cull_triangle(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2); - -static void lerp_triangle(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2); - -static void lerp_texcoords(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2); - -static void lerp_texcoords_w(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2); - -static void triangle(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2); - -static void clip_triangle(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2); - -static unsigned int clip_line(ogles_context_t* c, - vertex_t* s, vertex_t* p); - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#endif - -static void lightTriangleDarkSmooth(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - if (!(v0->flags & vertex_t::LIT)) { - v0->flags |= vertex_t::LIT; - const GLvoid* cp = c->arrays.color.element( - v0->index & vertex_cache_t::INDEX_MASK); - c->arrays.color.fetch(c, v0->color.v, cp); - } - if (!(v1->flags & vertex_t::LIT)) { - v1->flags |= vertex_t::LIT; - const GLvoid* cp = c->arrays.color.element( - v1->index & vertex_cache_t::INDEX_MASK); - c->arrays.color.fetch(c, v1->color.v, cp); - } - if(!(v2->flags & vertex_t::LIT)) { - v2->flags |= vertex_t::LIT; - const GLvoid* cp = c->arrays.color.element( - v2->index & vertex_cache_t::INDEX_MASK); - c->arrays.color.fetch(c, v2->color.v, cp); - } -} - -static void lightTriangleDarkFlat(ogles_context_t* c, - vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* v2) -{ - if (!(v2->flags & vertex_t::LIT)) { - v2->flags |= vertex_t::LIT; - const GLvoid* cp = c->arrays.color.element( - v2->index & vertex_cache_t::INDEX_MASK); - c->arrays.color.fetch(c, v2->color.v, cp); - } - // configure the rasterizer here, before we clip - c->rasterizer.procs.color4xv(c, v2->color.v); -} - -static void lightTriangleSmooth(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - if (!(v0->flags & vertex_t::LIT)) - c->lighting.lightVertex(c, v0); - if (!(v1->flags & vertex_t::LIT)) - c->lighting.lightVertex(c, v1); - if(!(v2->flags & vertex_t::LIT)) - c->lighting.lightVertex(c, v2); -} - -static void lightTriangleFlat(ogles_context_t* c, - vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* v2) -{ - if (!(v2->flags & vertex_t::LIT)) - c->lighting.lightVertex(c, v2); - // configure the rasterizer here, before we clip - c->rasterizer.procs.color4xv(c, v2->color.v); -} - -// The fog versions... - -static inline -void lightVertexDarkSmoothFog(ogles_context_t* c, vertex_t* v) -{ - if (!(v->flags & vertex_t::LIT)) { - v->flags |= vertex_t::LIT; - v->fog = c->fog.fog(c, v->eye.z); - const GLvoid* cp = c->arrays.color.element( - v->index & vertex_cache_t::INDEX_MASK); - c->arrays.color.fetch(c, v->color.v, cp); - } -} -static inline -void lightVertexDarkFlatFog(ogles_context_t* c, vertex_t* v) -{ - if (!(v->flags & vertex_t::LIT)) { - v->flags |= vertex_t::LIT; - v->fog = c->fog.fog(c, v->eye.z); - } -} -static inline -void lightVertexSmoothFog(ogles_context_t* c, vertex_t* v) -{ - if (!(v->flags & vertex_t::LIT)) { - v->fog = c->fog.fog(c, v->eye.z); - c->lighting.lightVertex(c, v); - } -} - -static void lightTriangleDarkSmoothFog(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - lightVertexDarkSmoothFog(c, v0); - lightVertexDarkSmoothFog(c, v1); - lightVertexDarkSmoothFog(c, v2); -} - -static void lightTriangleDarkFlatFog(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - lightVertexDarkFlatFog(c, v0); - lightVertexDarkFlatFog(c, v1); - lightVertexDarkSmoothFog(c, v2); - // configure the rasterizer here, before we clip - c->rasterizer.procs.color4xv(c, v2->color.v); -} - -static void lightTriangleSmoothFog(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - lightVertexSmoothFog(c, v0); - lightVertexSmoothFog(c, v1); - lightVertexSmoothFog(c, v2); -} - -static void lightTriangleFlatFog(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - lightVertexDarkFlatFog(c, v0); - lightVertexDarkFlatFog(c, v1); - lightVertexSmoothFog(c, v2); - // configure the rasterizer here, before we clip - c->rasterizer.procs.color4xv(c, v2->color.v); -} - - - -typedef void (*light_primitive_t)(ogles_context_t*, - vertex_t*, vertex_t*, vertex_t*); - -// fog 0x4, light 0x2, smooth 0x1 -static const light_primitive_t lightPrimitive[8] = { - lightTriangleDarkFlat, // no fog | dark | flat - lightTriangleDarkSmooth, // no fog | dark | smooth - lightTriangleFlat, // no fog | light | flat - lightTriangleSmooth, // no fog | light | smooth - lightTriangleDarkFlatFog, // fog | dark | flat - lightTriangleDarkSmoothFog, // fog | dark | smooth - lightTriangleFlatFog, // fog | light | flat - lightTriangleSmoothFog // fog | light | smooth -}; - -void ogles_validate_primitives(ogles_context_t* c) -{ - const uint32_t enables = c->rasterizer.state.enables; - - // set up the lighting/shading/smoothing/fogging function - int index = enables & GGL_ENABLE_SMOOTH ? 0x1 : 0; - index |= c->lighting.enable ? 0x2 : 0; - index |= enables & GGL_ENABLE_FOG ? 0x4 : 0; - c->lighting.lightTriangle = lightPrimitive[index]; - - // set up the primitive renderers - if (ggl_likely(c->arrays.vertex.enable)) { - c->prims.renderPoint = primitive_point; - c->prims.renderLine = primitive_line; - c->prims.renderTriangle = primitive_clip_triangle; - } else { - c->prims.renderPoint = primitive_nop_point; - c->prims.renderLine = primitive_nop_line; - c->prims.renderTriangle = primitive_nop_triangle; - } -} - -// ---------------------------------------------------------------------------- - -void compute_iterators_t::initTriangle( - vertex_t const* v0, vertex_t const* v1, vertex_t const* v2) -{ - m_dx01 = v1->window.x - v0->window.x; - m_dy10 = v0->window.y - v1->window.y; - m_dx20 = v0->window.x - v2->window.x; - m_dy02 = v2->window.y - v0->window.y; - m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20; - (void)m_reserved; // suppress unused warning -} - -void compute_iterators_t::initLine( - vertex_t const* v0, vertex_t const* v1) -{ - m_dx01 = m_dy02 = v1->window.x - v0->window.x; - m_dy10 = m_dx20 = v0->window.y - v1->window.y; - m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20; -} - -void compute_iterators_t::initLerp(vertex_t const* v0, uint32_t enables) -{ - m_x0 = v0->window.x; - m_y0 = v0->window.y; - const GGLcoord area = (m_area + TRI_HALF) >> TRI_FRACTION_BITS; - const GGLcoord minArea = 2; // cannot be inverted - // triangles with an area smaller than 1.0 are not smooth-shaded - - int q=0, s=0, d=0; - if (abs(area) >= minArea) { - // Here we do some voodoo magic, to compute a suitable scale - // factor for deltas/area: - - // First compute the 1/area with full 32-bits precision, - // gglRecipQNormalized returns a number [-0.5, 0.5[ and an exponent. - d = gglRecipQNormalized(area, &q); - - // Then compute the minimum left-shift to not overflow the muls - // below. - s = 32 - gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20)); - - // We'll keep 16-bits of precision for deltas/area. So we need - // to shift everything left an extra 15 bits. - s += 15; - - // make sure all final shifts are not > 32, because gglMulx - // can't handle it. - if (s < q) s = q; - if (s > 32) { - d >>= 32-s; - s = 32; - } - } - - m_dx01 = gglMulx(m_dx01, d, s); - m_dy10 = gglMulx(m_dy10, d, s); - m_dx20 = gglMulx(m_dx20, d, s); - m_dy02 = gglMulx(m_dy02, d, s); - m_area_scale = 32 + q - s; - m_scale = 0; - - if (enables & GGL_ENABLE_TMUS) { - const int A = gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20)); - const int B = gglClz(abs(m_x0)|abs(m_y0)); - m_scale = max(0, 32 - (A + 16)) + - max(0, 32 - (B + TRI_FRACTION_BITS)) + 1; - } -} - -int compute_iterators_t::iteratorsScale(GGLfixed* it, - int32_t c0, int32_t c1, int32_t c2) const -{ - int32_t dc01 = c1 - c0; - int32_t dc02 = c2 - c0; - const int A = gglClz(abs(c0)); - const int B = gglClz(abs(dc01)|abs(dc02)); - const int scale = min(A, B - m_scale) - 2; - if (scale >= 0) { - c0 <<= scale; - dc01 <<= scale; - dc02 <<= scale; - } else { - c0 >>= -scale; - dc01 >>= -scale; - dc02 >>= -scale; - } - const int s = m_area_scale; - int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s); - int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s); - int32_t c = c0 - (gglMulAddx(dcdx, m_x0, - gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS)); - it[0] = c; - it[1] = dcdx; - it[2] = dcdy; - return scale; -} - -void compute_iterators_t::iterators1616(GGLfixed* it, - GGLfixed c0, GGLfixed c1, GGLfixed c2) const -{ - const GGLfixed dc01 = c1 - c0; - const GGLfixed dc02 = c2 - c0; - // 16.16 x 16.16 == 32.32 --> 16.16 - const int s = m_area_scale; - int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s); - int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s); - int32_t c = c0 - (gglMulAddx(dcdx, m_x0, - gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS)); - it[0] = c; - it[1] = dcdx; - it[2] = dcdy; -} - -void compute_iterators_t::iterators0032(int64_t* it, - int32_t c0, int32_t c1, int32_t c2) const -{ - const int s = m_area_scale - 16; - int32_t dc01 = (c1 - c0)>>s; - int32_t dc02 = (c2 - c0)>>s; - // 16.16 x 16.16 == 32.32 - int64_t dcdx = gglMulii(dc01, m_dy02) + gglMulii(dc02, m_dy10); - int64_t dcdy = gglMulii(dc02, m_dx01) + gglMulii(dc01, m_dx20); - it[ 0] = (c0<<16) - ((dcdx*m_x0 + dcdy*m_y0)>>4); - it[ 1] = dcdx; - it[ 2] = dcdy; -} - -#if defined(__arm__) && !defined(__thumb__) -inline void compute_iterators_t::iterators0032(int32_t* it, - int32_t c0, int32_t c1, int32_t c2) const -{ - ::iterators0032(this, it, c0, c1, c2); -} -#else -void compute_iterators_t::iterators0032(int32_t* it, - int32_t c0, int32_t c1, int32_t c2) const -{ - int64_t it64[3]; - iterators0032(it64, c0, c1, c2); - it[0] = it64[0]; - it[1] = it64[1]; - it[2] = it64[2]; -} -#endif - -// ---------------------------------------------------------------------------- - -static inline int32_t clampZ(GLfixed z) CONST; -int32_t clampZ(GLfixed z) { - z = (z & ~(z>>31)); - if (z >= 0x10000) - z = 0xFFFF; - return z; -} - -static __attribute__((noinline)) -void fetch_texcoord_impl(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - vertex_t* const vtx[3] = { v0, v1, v2 }; - array_t const * const texcoordArray = c->arrays.texture; - - for (int i=0 ; irasterizer.state.texture[i].enable)) - continue; - - for (int j=0 ; j<3 ; j++) { - vertex_t* const v = vtx[j]; - if (v->flags & vertex_t::TT) - continue; - - // NOTE: here we could compute automatic texgen - // such as sphere/cube maps, instead of fetching them - // from the textcoord array. - - vec4_t& coords = v->texture[i]; - const GLubyte* tp = texcoordArray[i].element( - v->index & vertex_cache_t::INDEX_MASK); - texcoordArray[i].fetch(c, coords.v, tp); - - // transform texture coordinates... - coords.Q = 0x10000; - const transform_t& tr = c->transforms.texture[i].transform; - if (ggl_unlikely(tr.ops)) { - c->arrays.tex_transform[i](&tr, &coords, &coords); - } - - // divide by Q - const GGLfixed q = coords.Q; - if (ggl_unlikely(q != 0x10000)) { - const int32_t qinv = gglRecip28(q); - coords.S = gglMulx(coords.S, qinv, 28); - coords.T = gglMulx(coords.T, qinv, 28); - } - } - } - v0->flags |= vertex_t::TT; - v1->flags |= vertex_t::TT; - v2->flags |= vertex_t::TT; -} - -inline void fetch_texcoord(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - const uint32_t enables = c->rasterizer.state.enables; - if (!(enables & GGL_ENABLE_TMUS)) - return; - - // Fetch & transform texture coordinates... - if (ggl_likely(v0->flags & v1->flags & v2->flags & vertex_t::TT)) { - // already done for all three vertices, bail... - return; - } - fetch_texcoord_impl(c, v0, v1, v2); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark Point -#endif - -void primitive_nop_point(ogles_context_t*, vertex_t*) { -} - -void primitive_point(ogles_context_t* c, vertex_t* v) -{ - // lighting & clamping... - const uint32_t enables = c->rasterizer.state.enables; - - if (ggl_unlikely(!(v->flags & vertex_t::LIT))) { - if (c->lighting.enable) { - c->lighting.lightVertex(c, v); - } else { - v->flags |= vertex_t::LIT; - const GLvoid* cp = c->arrays.color.element( - v->index & vertex_cache_t::INDEX_MASK); - c->arrays.color.fetch(c, v->color.v, cp); - } - if (enables & GGL_ENABLE_FOG) { - v->fog = c->fog.fog(c, v->eye.z); - } - } - - // XXX: we don't need to do that each-time - // if color array and lighting not enabled - c->rasterizer.procs.color4xv(c, v->color.v); - - // XXX: look into ES point-sprite extension - if (enables & GGL_ENABLE_TMUS) { - fetch_texcoord(c, v,v,v); - for (int i=0 ; irasterizer.state.texture[i].enable) - continue; - int32_t itt[8]; - itt[1] = itt[2] = itt[4] = itt[5] = 0; - itt[6] = itt[7] = 16; // XXX: check that - if (c->rasterizer.state.texture[i].s_wrap == GGL_CLAMP) { - int width = c->textures.tmu[i].texture->surface.width; - itt[0] = v->texture[i].S * width; - itt[6] = 0; - } - if (c->rasterizer.state.texture[i].t_wrap == GGL_CLAMP) { - int height = c->textures.tmu[i].texture->surface.height; - itt[3] = v->texture[i].T * height; - itt[7] = 0; - } - c->rasterizer.procs.texCoordGradScale8xv(c, i, itt); - } - } - - if (enables & GGL_ENABLE_DEPTH_TEST) { - int32_t itz[3]; - itz[0] = clampZ(v->window.z) * 0x00010001; - itz[1] = itz[2] = 0; - c->rasterizer.procs.zGrad3xv(c, itz); - } - - if (enables & GGL_ENABLE_FOG) { - GLfixed itf[3]; - itf[0] = v->fog; - itf[1] = itf[2] = 0; - c->rasterizer.procs.fogGrad3xv(c, itf); - } - - // Render our point... - c->rasterizer.procs.pointx(c, v->window.v, c->point.size); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark Line -#endif - -void primitive_nop_line(ogles_context_t*, vertex_t*, vertex_t*) { -} - -void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1) -{ - // get texture coordinates - fetch_texcoord(c, v0, v1, v1); - - // light/shade the vertices first (they're copied below) - c->lighting.lightTriangle(c, v0, v1, v1); - - // clip the line if needed - if (ggl_unlikely((v0->flags | v1->flags) & vertex_t::CLIP_ALL)) { - unsigned int count = clip_line(c, v0, v1); - if (ggl_unlikely(count == 0)) - return; - } - - // compute iterators... - const uint32_t enables = c->rasterizer.state.enables; - const uint32_t mask = GGL_ENABLE_TMUS | - GGL_ENABLE_SMOOTH | - GGL_ENABLE_W | - GGL_ENABLE_FOG | - GGL_ENABLE_DEPTH_TEST; - - if (ggl_unlikely(enables & mask)) { - c->lerp.initLine(v0, v1); - lerp_triangle(c, v0, v1, v0); - } - - // render our line - c->rasterizer.procs.linex(c, v0->window.v, v1->window.v, c->line.width); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark Triangle -#endif - -void primitive_nop_triangle(ogles_context_t* /*c*/, - vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* /*v2*/) { -} - -void primitive_clip_triangle(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - uint32_t cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL; - if (ggl_likely(!cc)) { - // code below must be as optimized as possible, this is the - // common code path. - - // This triangle is not clipped, test if it's culled - // unclipped triangle... - c->lerp.initTriangle(v0, v1, v2); - if (cull_triangle(c, v0, v1, v2)) - return; // culled! - - // Fetch all texture coordinates if needed - fetch_texcoord(c, v0, v1, v2); - - // light (or shade) our triangle! - c->lighting.lightTriangle(c, v0, v1, v2); - - triangle(c, v0, v1, v2); - return; - } - - // The assumption here is that we're not going to clip very often, - // and even more rarely will we clip a triangle that ends up - // being culled out. So it's okay to light the vertices here, even though - // in a few cases we won't render the triangle (if culled). - - // Fetch texture coordinates... - fetch_texcoord(c, v0, v1, v2); - - // light (or shade) our triangle! - c->lighting.lightTriangle(c, v0, v1, v2); - - clip_triangle(c, v0, v1, v2); -} - -// ----------------------------------------------------------------------- - -void triangle(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - // compute iterators... - const uint32_t enables = c->rasterizer.state.enables; - const uint32_t mask = GGL_ENABLE_TMUS | - GGL_ENABLE_SMOOTH | - GGL_ENABLE_W | - GGL_ENABLE_FOG | - GGL_ENABLE_DEPTH_TEST; - - if (ggl_likely(enables & mask)) - lerp_triangle(c, v0, v1, v2); - - c->rasterizer.procs.trianglex(c, v0->window.v, v1->window.v, v2->window.v); -} - -void lerp_triangle(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - const uint32_t enables = c->rasterizer.state.enables; - c->lerp.initLerp(v0, enables); - - // set up texture iterators - if (enables & GGL_ENABLE_TMUS) { - if (enables & GGL_ENABLE_W) { - lerp_texcoords_w(c, v0, v1, v2); - } else { - lerp_texcoords(c, v0, v1, v2); - } - } - - // set up the color iterators - const compute_iterators_t& lerp = c->lerp; - if (enables & GGL_ENABLE_SMOOTH) { - GLfixed itc[12]; - for (int i=0 ; i<4 ; i++) { - const GGLcolor c0 = v0->color.v[i] * 255; - const GGLcolor c1 = v1->color.v[i] * 255; - const GGLcolor c2 = v2->color.v[i] * 255; - lerp.iterators1616(&itc[i*3], c0, c1, c2); - } - c->rasterizer.procs.colorGrad12xv(c, itc); - } - - if (enables & GGL_ENABLE_DEPTH_TEST) { - int32_t itz[3]; - const int32_t v0z = clampZ(v0->window.z); - const int32_t v1z = clampZ(v1->window.z); - const int32_t v2z = clampZ(v2->window.z); - if (ggl_unlikely(c->polygonOffset.enable)) { - const int32_t units = (c->polygonOffset.units << 16); - const GLfixed factor = c->polygonOffset.factor; - if (factor) { - int64_t itz64[3]; - lerp.iterators0032(itz64, v0z, v1z, v2z); - int64_t maxDepthSlope = max(itz64[1], itz64[2]); - itz[0] = uint32_t(itz64[0]) - + uint32_t((maxDepthSlope*factor)>>16) + units; - itz[1] = uint32_t(itz64[1]); - itz[2] = uint32_t(itz64[2]); - } else { - lerp.iterators0032(itz, v0z, v1z, v2z); - itz[0] += units; - } - } else { - lerp.iterators0032(itz, v0z, v1z, v2z); - } - c->rasterizer.procs.zGrad3xv(c, itz); - } - - if (ggl_unlikely(enables & GGL_ENABLE_FOG)) { - GLfixed itf[3]; - lerp.iterators1616(itf, v0->fog, v1->fog, v2->fog); - c->rasterizer.procs.fogGrad3xv(c, itf); - } -} - - -static inline -int compute_lod(ogles_context_t* c, int i, - int32_t s0, int32_t t0, int32_t s1, int32_t t1, int32_t s2, int32_t t2) -{ - // Compute mipmap level / primitive - // rho = sqrt( texelArea / area ) - // lod = log2( rho ) - // lod = log2( texelArea / area ) / 2 - // lod = (log2( texelArea ) - log2( area )) / 2 - const compute_iterators_t& lerp = c->lerp; - const GGLcoord area = abs(lerp.area()); - const int w = c->textures.tmu[i].texture->surface.width; - const int h = c->textures.tmu[i].texture->surface.height; - const int shift = 16 + (16 - TRI_FRACTION_BITS); - int32_t texelArea = abs( gglMulx(s1-s0, t2-t0, shift) - - gglMulx(s2-s0, t1-t0, shift) )*w*h; - int log2TArea = (32-TRI_FRACTION_BITS -1) - gglClz(texelArea); - int log2Area = (32-TRI_FRACTION_BITS*2-1) - gglClz(area); - int lod = (log2TArea - log2Area + 1) >> 1; - return lod; -} - -void lerp_texcoords(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - const compute_iterators_t& lerp = c->lerp; - int32_t itt[8] __attribute__((aligned(16))); - for (int i=0 ; irasterizer.state.texture[i]; - if (!tmu.enable) - continue; - - // compute the jacobians using block floating-point - int32_t s0 = v0->texture[i].S; - int32_t t0 = v0->texture[i].T; - int32_t s1 = v1->texture[i].S; - int32_t t1 = v1->texture[i].T; - int32_t s2 = v2->texture[i].S; - int32_t t2 = v2->texture[i].T; - - const GLenum min_filter = c->textures.tmu[i].texture->min_filter; - if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) { - int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2); - c->rasterizer.procs.bindTextureLod(c, i, - &c->textures.tmu[i].texture->mip(lod)); - } - - // premultiply (s,t) when clampling - if (tmu.s_wrap == GGL_CLAMP) { - const int width = tmu.surface.width; - s0 *= width; - s1 *= width; - s2 *= width; - } - if (tmu.t_wrap == GGL_CLAMP) { - const int height = tmu.surface.height; - t0 *= height; - t1 *= height; - t2 *= height; - } - itt[6] = -lerp.iteratorsScale(itt+0, s0, s1, s2); - itt[7] = -lerp.iteratorsScale(itt+3, t0, t1, t2); - c->rasterizer.procs.texCoordGradScale8xv(c, i, itt); - } -} - -void lerp_texcoords_w(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - const compute_iterators_t& lerp = c->lerp; - int32_t itt[8] __attribute__((aligned(16))); - int32_t itw[3]; - - // compute W's scale to 2.30 - int32_t w0 = v0->window.w; - int32_t w1 = v1->window.w; - int32_t w2 = v2->window.w; - int wscale = 32 - gglClz(w0|w1|w2); - - // compute the jacobian using block floating-point - int sc = lerp.iteratorsScale(itw, w0, w1, w2); - sc += wscale - 16; - c->rasterizer.procs.wGrad3xv(c, itw); - - for (int i=0 ; irasterizer.state.texture[i]; - if (!tmu.enable) - continue; - - // compute the jacobians using block floating-point - int32_t s0 = v0->texture[i].S; - int32_t t0 = v0->texture[i].T; - int32_t s1 = v1->texture[i].S; - int32_t t1 = v1->texture[i].T; - int32_t s2 = v2->texture[i].S; - int32_t t2 = v2->texture[i].T; - - const GLenum min_filter = c->textures.tmu[i].texture->min_filter; - if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) { - int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2); - c->rasterizer.procs.bindTextureLod(c, i, - &c->textures.tmu[i].texture->mip(lod)); - } - - // premultiply (s,t) when clampling - if (tmu.s_wrap == GGL_CLAMP) { - const int width = tmu.surface.width; - s0 *= width; - s1 *= width; - s2 *= width; - } - if (tmu.t_wrap == GGL_CLAMP) { - const int height = tmu.surface.height; - t0 *= height; - t1 *= height; - t2 *= height; - } - - s0 = gglMulx(s0, w0, wscale); - t0 = gglMulx(t0, w0, wscale); - s1 = gglMulx(s1, w1, wscale); - t1 = gglMulx(t1, w1, wscale); - s2 = gglMulx(s2, w2, wscale); - t2 = gglMulx(t2, w2, wscale); - - itt[6] = sc - lerp.iteratorsScale(itt+0, s0, s1, s2); - itt[7] = sc - lerp.iteratorsScale(itt+3, t0, t1, t2); - c->rasterizer.procs.texCoordGradScale8xv(c, i, itt); - } -} - - -static inline -bool cull_triangle(ogles_context_t* c, vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* /*v2*/) -{ - if (ggl_likely(c->cull.enable)) { - const GLenum winding = (c->lerp.area() > 0) ? GL_CW : GL_CCW; - const GLenum face = (winding == c->cull.frontFace) ? GL_FRONT : GL_BACK; - if (face == c->cull.cullFace) - return true; // culled! - } - return false; -} - -static inline -GLfixed frustumPlaneDist(int plane, const vec4_t& s) -{ - const GLfixed d = s.v[ plane >> 1 ]; - return ((plane & 1) ? (s.w - d) : (s.w + d)); -} - -static inline -int32_t clipDivide(GLfixed a, GLfixed b) { - // returns a 4.28 fixed-point - return gglMulDivi(1LU<<28, a, b); -} - -void clip_triangle(ogles_context_t* c, - vertex_t* v0, vertex_t* v1, vertex_t* v2) -{ - uint32_t all_cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL; - - vertex_t *p0, *p1, *p2; - const int MAX_CLIPPING_PLANES = 6 + OGLES_MAX_CLIP_PLANES; - const int MAX_VERTICES = 3; - - // Temporary buffer to hold the new vertices. Each plane can add up to - // two new vertices (because the polygon is convex). - // We need one extra element, to handle an overflow case when - // the polygon degenerates into something non convex. - vertex_t buffer[MAX_CLIPPING_PLANES * 2 + 1]; // ~3KB - vertex_t* buf = buffer; - - // original list of vertices (polygon to clip, in fact this - // function works with an arbitrary polygon). - vertex_t* in[3] = { v0, v1, v2 }; - - // output lists (we need 2, which we use back and forth) - // (maximum outpout list's size is MAX_CLIPPING_PLANES + MAX_VERTICES) - // 2 more elements for overflow when non convex polygons. - vertex_t* out[2][MAX_CLIPPING_PLANES + MAX_VERTICES + 2]; - unsigned int outi = 0; - - // current input list - vertex_t** ivl = in; - - // 3 input vertices, 0 in the output list, first plane - unsigned int ic = 3; - - // User clip-planes first, the clipping is always done in eye-coordinate - // this is basically the same algorithm than for the view-volume - // clipping, except for the computation of the distance (vertex, plane) - // and the fact that we need to compute the eye-coordinates of each - // new vertex we create. - - if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL)) - { - unsigned int plane = 0; - uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8; - do { - if (cc & 1) { - // pointers to our output list (head and current) - vertex_t** const ovl = &out[outi][0]; - vertex_t** output = ovl; - unsigned int oc = 0; - unsigned int sentinel = 0; - // previous vertex, compute distance to the plane - vertex_t* s = ivl[ic-1]; - const vec4_t& equation = c->clipPlanes.plane[plane].equation; - GLfixed sd = dot4(equation.v, s->eye.v); - // clip each vertex against this plane... - for (unsigned int i=0 ; ieye.v); - if (sd >= 0) { - if (pd >= 0) { - // both inside - *output++ = p; - oc++; - } else { - // s inside, p outside (exiting) - const GLfixed t = clipDivide(sd, sd-pd); - c->arrays.clipEye(c, buf, t, p, s); - *output++ = buf++; - oc++; - if (++sentinel >= 3) - return; // non-convex polygon! - } - } else { - if (pd >= 0) { - // s outside (entering) - if (pd) { - const GLfixed t = clipDivide(pd, pd-sd); - c->arrays.clipEye(c, buf, t, s, p); - *output++ = buf++; - oc++; - if (++sentinel >= 3) - return; // non-convex polygon! - } - *output++ = p; - oc++; - } else { - // both outside - } - } - s = p; - sd = pd; - } - // output list become the new input list - if (oc<3) - return; // less than 3 vertices left? we're done! - ivl = ovl; - ic = oc; - outi = 1-outi; - } - cc >>= 1; - plane++; - } while (cc); - } - - // frustum clip-planes - if (all_cc & vertex_t::FRUSTUM_CLIP_ALL) - { - unsigned int plane = 0; - uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL; - do { - if (cc & 1) { - // pointers to our output list (head and current) - vertex_t** const ovl = &out[outi][0]; - vertex_t** output = ovl; - unsigned int oc = 0; - unsigned int sentinel = 0; - // previous vertex, compute distance to the plane - vertex_t* s = ivl[ic-1]; - GLfixed sd = frustumPlaneDist(plane, s->clip); - // clip each vertex against this plane... - for (unsigned int i=0 ; iclip); - if (sd >= 0) { - if (pd >= 0) { - // both inside - *output++ = p; - oc++; - } else { - // s inside, p outside (exiting) - const GLfixed t = clipDivide(sd, sd-pd); - c->arrays.clipVertex(c, buf, t, p, s); - *output++ = buf++; - oc++; - if (++sentinel >= 3) - return; // non-convex polygon! - } - } else { - if (pd >= 0) { - // s outside (entering) - if (pd) { - const GLfixed t = clipDivide(pd, pd-sd); - c->arrays.clipVertex(c, buf, t, s, p); - *output++ = buf++; - oc++; - if (++sentinel >= 3) - return; // non-convex polygon! - } - *output++ = p; - oc++; - } else { - // both outside - } - } - s = p; - sd = pd; - } - // output list become the new input list - if (oc<3) - return; // less than 3 vertices left? we're done! - ivl = ovl; - ic = oc; - outi = 1-outi; - } - cc >>= 1; - plane++; - } while (cc); - } - - // finally we can render our triangles... - p0 = ivl[0]; - p1 = ivl[1]; - for (unsigned int i=2 ; ilerp.initTriangle(p0, p1, p2); - if (cull_triangle(c, p0, p1, p2)) { - p1 = p2; - continue; // culled! - } - triangle(c, p0, p1, p2); - p1 = p2; - } -} - -unsigned int clip_line(ogles_context_t* c, vertex_t* s, vertex_t* p) -{ - const uint32_t all_cc = (s->flags | p->flags) & vertex_t::CLIP_ALL; - - if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL)) - { - unsigned int plane = 0; - uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8; - do { - if (cc & 1) { - const vec4_t& equation = c->clipPlanes.plane[plane].equation; - const GLfixed sd = dot4(equation.v, s->eye.v); - const GLfixed pd = dot4(equation.v, p->eye.v); - if (sd >= 0) { - if (pd >= 0) { - // both inside - } else { - // s inside, p outside (exiting) - const GLfixed t = clipDivide(sd, sd-pd); - c->arrays.clipEye(c, p, t, p, s); - } - } else { - if (pd >= 0) { - // s outside (entering) - if (pd) { - const GLfixed t = clipDivide(pd, pd-sd); - c->arrays.clipEye(c, s, t, s, p); - } - } else { - // both outside - return 0; - } - } - } - cc >>= 1; - plane++; - } while (cc); - } - - // frustum clip-planes - if (all_cc & vertex_t::FRUSTUM_CLIP_ALL) - { - unsigned int plane = 0; - uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL; - do { - if (cc & 1) { - const GLfixed sd = frustumPlaneDist(plane, s->clip); - const GLfixed pd = frustumPlaneDist(plane, p->clip); - if (sd >= 0) { - if (pd >= 0) { - // both inside - } else { - // s inside, p outside (exiting) - const GLfixed t = clipDivide(sd, sd-pd); - c->arrays.clipVertex(c, p, t, p, s); - } - } else { - if (pd >= 0) { - // s outside (entering) - if (pd) { - const GLfixed t = clipDivide(pd, pd-sd); - c->arrays.clipVertex(c, s, t, s, p); - } - } else { - // both outside - return 0; - } - } - } - cc >>= 1; - plane++; - } while (cc); - } - - return 2; -} - - -}; // namespace android diff --git a/opengl/libagl/primitives.h b/opengl/libagl/primitives.h deleted file mode 100644 index 1bef604eb6..0000000000 --- a/opengl/libagl/primitives.h +++ /dev/null @@ -1,37 +0,0 @@ -/* libs/opengles/primitives.h -** -** Copyright 2006, 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_OPENGLES_PRIMITIVES_H -#define ANDROID_OPENGLES_PRIMITIVES_H - -#include -#include -#include - - -namespace android { - -namespace gl { -struct ogles_context_t; -}; - -void ogles_validate_primitives(ogles_context_t* c); - -}; // namespace android - -#endif // ANDROID_OPENGLES_PRIMITIVES_H - diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp deleted file mode 100644 index 8bb7e83820..0000000000 --- a/opengl/libagl/state.cpp +++ /dev/null @@ -1,598 +0,0 @@ -/* libs/opengles/state.cpp -** -** Copyright 2006, 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 - -#include "context.h" -#include "fp.h" -#include "state.h" -#include "array.h" -#include "matrix.h" -#include "vertex.h" -#include "light.h" -#include "texture.h" -#include "BufferObjectManager.h" -#include "TextureObjectManager.h" - -namespace android { - -// ---------------------------------------------------------------------------- - -static char const * const gVendorString = "Android"; -static char const * const gRendererString = "Android PixelFlinger 1.4"; -static char const * const gVersionString = "OpenGL ES-CM 1.0"; -static char const * const gExtensionsString = - "GL_OES_byte_coordinates " // OK - "GL_OES_fixed_point " // OK - "GL_OES_single_precision " // OK - "GL_OES_read_format " // OK - "GL_OES_compressed_paletted_texture " // OK - "GL_OES_draw_texture " // OK - "GL_OES_matrix_get " // OK - "GL_OES_query_matrix " // OK - // "GL_OES_point_size_array " // TODO - // "GL_OES_point_sprite " // TODO - "GL_OES_EGL_image " // OK - "GL_OES_EGL_sync " // OK -#ifdef GL_OES_compressed_ETC1_RGB8_texture - "GL_OES_compressed_ETC1_RGB8_texture " // OK -#endif - "GL_ARB_texture_compression " // OK - "GL_ARB_texture_non_power_of_two " // OK - "GL_ANDROID_user_clip_plane " // OK - "GL_ANDROID_vertex_buffer_object " // OK - "GL_ANDROID_generate_mipmap " // OK - ; - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#endif - -ogles_context_t *ogles_init(size_t extra) -{ - void* const base = malloc(extra + sizeof(ogles_context_t) + 32); - if (!base) return 0; - - ogles_context_t *c = - (ogles_context_t *)((ptrdiff_t(base) + extra + 31) & ~0x1FL); - memset(c, 0, sizeof(ogles_context_t)); - ggl_init_context(&(c->rasterizer)); - - // XXX: this should be passed as an argument - sp smgr(new EGLSurfaceManager()); - c->surfaceManager = smgr.get(); - c->surfaceManager->incStrong(c); - - sp bomgr(new EGLBufferObjectManager()); - c->bufferObjectManager = bomgr.get(); - c->bufferObjectManager->incStrong(c); - - ogles_init_array(c); - ogles_init_matrix(c); - ogles_init_vertex(c); - ogles_init_light(c); - ogles_init_texture(c); - - c->rasterizer.base = base; - c->point.size = TRI_ONE; - c->line.width = TRI_ONE; - - // in OpenGL, writing to the depth buffer is enabled by default. - c->rasterizer.procs.depthMask(c, 1); - - // OpenGL enables dithering by default - c->rasterizer.procs.enable(c, GL_DITHER); - - return c; -} - -void ogles_uninit(ogles_context_t* c) -{ - ogles_uninit_array(c); - ogles_uninit_matrix(c); - ogles_uninit_vertex(c); - ogles_uninit_light(c); - ogles_uninit_texture(c); - c->surfaceManager->decStrong(c); - c->bufferObjectManager->decStrong(c); - ggl_uninit_context(&(c->rasterizer)); - free(c->rasterizer.base); -} - -void _ogles_error(ogles_context_t* c, GLenum error) -{ - if (c->error == GL_NO_ERROR) - c->error = error; -} - -static bool stencilop_valid(GLenum op) { - switch (op) { - case GL_KEEP: - case GL_ZERO: - case GL_REPLACE: - case GL_INCR: - case GL_DECR: - case GL_INVERT: - return true; - } - return false; -} - -static void enable_disable(ogles_context_t* c, GLenum cap, int enabled) -{ - if ((cap >= GL_LIGHT0) && (caplighting.lights[cap-GL_LIGHT0].enable = enabled; - c->lighting.enabledLights &= ~(1<<(cap-GL_LIGHT0)); - c->lighting.enabledLights |= (enabled<<(cap-GL_LIGHT0)); - return; - } - - switch (cap) { - case GL_POINT_SMOOTH: - c->point.smooth = enabled; - break; - case GL_LINE_SMOOTH: - c->line.smooth = enabled; - break; - case GL_POLYGON_OFFSET_FILL: - c->polygonOffset.enable = enabled; - break; - case GL_CULL_FACE: - c->cull.enable = enabled; - break; - case GL_LIGHTING: - c->lighting.enable = enabled; - break; - case GL_COLOR_MATERIAL: - c->lighting.colorMaterial.enable = enabled; - break; - case GL_NORMALIZE: - case GL_RESCALE_NORMAL: - c->transforms.rescaleNormals = enabled ? cap : 0; - // XXX: invalidate mvit - break; - - case GL_CLIP_PLANE0: - case GL_CLIP_PLANE1: - case GL_CLIP_PLANE2: - case GL_CLIP_PLANE3: - case GL_CLIP_PLANE4: - case GL_CLIP_PLANE5: - c->clipPlanes.enable &= ~(1<<(cap-GL_CLIP_PLANE0)); - c->clipPlanes.enable |= (enabled<<(cap-GL_CLIP_PLANE0)); - ogles_invalidate_perspective(c); - break; - - case GL_FOG: - case GL_DEPTH_TEST: - ogles_invalidate_perspective(c); - [[fallthrough]]; - case GL_BLEND: - case GL_SCISSOR_TEST: - case GL_ALPHA_TEST: - case GL_COLOR_LOGIC_OP: - case GL_DITHER: - case GL_STENCIL_TEST: - case GL_TEXTURE_2D: - // these need to fall through into the rasterizer - c->rasterizer.procs.enableDisable(c, cap, enabled); - break; - case GL_TEXTURE_EXTERNAL_OES: - c->rasterizer.procs.enableDisable(c, GL_TEXTURE_2D, enabled); - break; - - case GL_MULTISAMPLE: - case GL_SAMPLE_ALPHA_TO_COVERAGE: - case GL_SAMPLE_ALPHA_TO_ONE: - case GL_SAMPLE_COVERAGE: - // not supported in this implementation - break; - - default: - ogles_error(c, GL_INVALID_ENUM); - return; - } -} - -// ---------------------------------------------------------------------------- -}; // namespace android -// ---------------------------------------------------------------------------- -using namespace android; - -#if 0 -#pragma mark - -#endif - -// These ones are super-easy, we're not supporting those features! -void glSampleCoverage(GLclampf /*value*/, GLboolean /*invert*/) { -} -void glSampleCoveragex(GLclampx /*value*/, GLboolean /*invert*/) { -} -void glStencilFunc(GLenum func, GLint /*ref*/, GLuint /*mask*/) { - ogles_context_t* c = ogles_context_t::get(); - if (func < GL_NEVER || func > GL_ALWAYS) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - // from OpenGL|ES 1.0 sepcification: - // If there is no stencil buffer, no stencil modification can occur - // and it is as if the stencil test always passes. -} - -void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) { - ogles_context_t* c = ogles_context_t::get(); - if ((stencilop_valid(fail) & - stencilop_valid(zfail) & - stencilop_valid(zpass)) == 0) { - ogles_error(c, GL_INVALID_ENUM); - return; - } -} - -// ---------------------------------------------------------------------------- - -void glAlphaFunc(GLenum func, GLclampf ref) -{ - glAlphaFuncx(func, gglFloatToFixed(ref)); -} - -void glCullFace(GLenum mode) -{ - ogles_context_t* c = ogles_context_t::get(); - switch (mode) { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: - break; - default: - ogles_error(c, GL_INVALID_ENUM); - } - c->cull.cullFace = mode; -} - -void glFrontFace(GLenum mode) -{ - ogles_context_t* c = ogles_context_t::get(); - switch (mode) { - case GL_CW: - case GL_CCW: - break; - default: - ogles_error(c, GL_INVALID_ENUM); - return; - } - c->cull.frontFace = mode; -} - -void glHint(GLenum target, GLenum mode) -{ - ogles_context_t* c = ogles_context_t::get(); - switch (target) { - case GL_FOG_HINT: - case GL_GENERATE_MIPMAP_HINT: - case GL_LINE_SMOOTH_HINT: - break; - case GL_POINT_SMOOTH_HINT: - c->rasterizer.procs.enableDisable(c, - GGL_POINT_SMOOTH_NICE, mode==GL_NICEST); - break; - case GL_PERSPECTIVE_CORRECTION_HINT: - c->perspective = (mode == GL_NICEST) ? 1 : 0; - break; - default: - ogles_error(c, GL_INVALID_ENUM); - } -} - -void glEnable(GLenum cap) { - ogles_context_t* c = ogles_context_t::get(); - enable_disable(c, cap, 1); -} -void glDisable(GLenum cap) { - ogles_context_t* c = ogles_context_t::get(); - enable_disable(c, cap, 0); -} - -void glFinish() -{ // nothing to do for our software implementation -} - -void glFlush() -{ // nothing to do for our software implementation -} - -GLenum glGetError() -{ - // From OpenGL|ES 1.0 specification: - // If more than one flag has recorded an error, glGetError returns - // and clears an arbitrary error flag value. Thus, glGetError should - // always be called in a loop, until it returns GL_NO_ERROR, - // if all error flags are to be reset. - - ogles_context_t* c = ogles_context_t::get(); - if (c->error) { - const GLenum ret(c->error); - c->error = 0; - return ret; - } - - if (c->rasterizer.error) { - const GLenum ret(c->rasterizer.error); - c->rasterizer.error = 0; - return ret; - } - - return GL_NO_ERROR; -} - -const GLubyte* glGetString(GLenum string) -{ - switch (string) { - case GL_VENDOR: return (const GLubyte*)gVendorString; - case GL_RENDERER: return (const GLubyte*)gRendererString; - case GL_VERSION: return (const GLubyte*)gVersionString; - case GL_EXTENSIONS: return (const GLubyte*)gExtensionsString; - } - ogles_context_t* c = ogles_context_t::get(); - ogles_error(c, GL_INVALID_ENUM); - return 0; -} - -void glGetIntegerv(GLenum pname, GLint *params) -{ - int i; - ogles_context_t* c = ogles_context_t::get(); - switch (pname) { - case GL_ALIASED_POINT_SIZE_RANGE: - params[0] = 0; - params[1] = GGL_MAX_ALIASED_POINT_SIZE; - break; - case GL_ALIASED_LINE_WIDTH_RANGE: - params[0] = 0; - params[1] = GGL_MAX_ALIASED_POINT_SIZE; - break; - case GL_ALPHA_BITS: { - int index = c->rasterizer.state.buffers.color.format; - GGLFormat const * formats = gglGetPixelFormatTable(); - params[0] = formats[index].ah - formats[index].al; - break; - } - case GL_RED_BITS: { - int index = c->rasterizer.state.buffers.color.format; - GGLFormat const * formats = gglGetPixelFormatTable(); - params[0] = formats[index].rh - formats[index].rl; - break; - } - case GL_GREEN_BITS: { - int index = c->rasterizer.state.buffers.color.format; - GGLFormat const * formats = gglGetPixelFormatTable(); - params[0] = formats[index].gh - formats[index].gl; - break; - } - case GL_BLUE_BITS: { - int index = c->rasterizer.state.buffers.color.format; - GGLFormat const * formats = gglGetPixelFormatTable(); - params[0] = formats[index].bh - formats[index].bl; - break; - } - case GL_COMPRESSED_TEXTURE_FORMATS: - params[ 0] = GL_PALETTE4_RGB8_OES; - params[ 1] = GL_PALETTE4_RGBA8_OES; - params[ 2] = GL_PALETTE4_R5_G6_B5_OES; - params[ 3] = GL_PALETTE4_RGBA4_OES; - params[ 4] = GL_PALETTE4_RGB5_A1_OES; - params[ 5] = GL_PALETTE8_RGB8_OES; - params[ 6] = GL_PALETTE8_RGBA8_OES; - params[ 7] = GL_PALETTE8_R5_G6_B5_OES; - params[ 8] = GL_PALETTE8_RGBA4_OES; - params[ 9] = GL_PALETTE8_RGB5_A1_OES; - i = 10; -#ifdef GL_OES_compressed_ETC1_RGB8_texture - params[i++] = GL_ETC1_RGB8_OES; -#endif - break; - case GL_DEPTH_BITS: - params[0] = c->rasterizer.state.buffers.depth.format ? 0 : 16; - break; - case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES: - params[0] = GL_RGB; - break; - case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES: - params[0] = GL_UNSIGNED_SHORT_5_6_5; - break; - case GL_MAX_LIGHTS: - params[0] = OGLES_MAX_LIGHTS; - break; - case GL_MAX_CLIP_PLANES: - params[0] = OGLES_MAX_CLIP_PLANES; - break; - case GL_MAX_MODELVIEW_STACK_DEPTH: - params[0] = OGLES_MODELVIEW_STACK_DEPTH; - break; - case GL_MAX_PROJECTION_STACK_DEPTH: - params[0] = OGLES_PROJECTION_STACK_DEPTH; - break; - case GL_MAX_TEXTURE_STACK_DEPTH: - params[0] = OGLES_TEXTURE_STACK_DEPTH; - break; - case GL_MAX_TEXTURE_SIZE: - params[0] = GGL_MAX_TEXTURE_SIZE; - break; - case GL_MAX_TEXTURE_UNITS: - params[0] = GGL_TEXTURE_UNIT_COUNT; - break; - case GL_MAX_VIEWPORT_DIMS: - params[0] = GGL_MAX_VIEWPORT_DIMS; - params[1] = GGL_MAX_VIEWPORT_DIMS; - break; - case GL_NUM_COMPRESSED_TEXTURE_FORMATS: - params[0] = OGLES_NUM_COMPRESSED_TEXTURE_FORMATS; - break; - case GL_SMOOTH_LINE_WIDTH_RANGE: - params[0] = 0; - params[1] = GGL_MAX_SMOOTH_LINE_WIDTH; - break; - case GL_SMOOTH_POINT_SIZE_RANGE: - params[0] = 0; - params[1] = GGL_MAX_SMOOTH_POINT_SIZE; - break; - case GL_STENCIL_BITS: - params[0] = 0; - break; - case GL_SUBPIXEL_BITS: - params[0] = GGL_SUBPIXEL_BITS; - break; - - case GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES: - memcpy( params, - c->transforms.modelview.top().elements(), - 16*sizeof(GLint)); - break; - case GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES: - memcpy( params, - c->transforms.projection.top().elements(), - 16*sizeof(GLint)); - break; - case GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES: - memcpy( params, - c->transforms.texture[c->textures.active].top().elements(), - 16*sizeof(GLint)); - break; - - default: - ogles_error(c, GL_INVALID_ENUM); - break; - } -} - -// ---------------------------------------------------------------------------- - -void glPointSize(GLfloat size) -{ - ogles_context_t* c = ogles_context_t::get(); - if (size <= 0) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - c->point.size = TRI_FROM_FIXED(gglFloatToFixed(size)); -} - -void glPointSizex(GLfixed size) -{ - ogles_context_t* c = ogles_context_t::get(); - if (size <= 0) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - c->point.size = TRI_FROM_FIXED(size); -} - -// ---------------------------------------------------------------------------- - -void glLineWidth(GLfloat width) -{ - ogles_context_t* c = ogles_context_t::get(); - if (width <= 0) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - c->line.width = TRI_FROM_FIXED(gglFloatToFixed(width)); -} - -void glLineWidthx(GLfixed width) -{ - ogles_context_t* c = ogles_context_t::get(); - if (width <= 0) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - c->line.width = TRI_FROM_FIXED(width); -} - -// ---------------------------------------------------------------------------- - -void glColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) { - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.colorMask(c, r, g, b, a); -} - -void glDepthMask(GLboolean flag) { - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.depthMask(c, flag); -} - -void glStencilMask(GLuint mask) { - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.stencilMask(c, mask); -} - -void glDepthFunc(GLenum func) { - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.depthFunc(c, func); -} - -void glLogicOp(GLenum opcode) { - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.logicOp(c, opcode); -} - -void glAlphaFuncx(GLenum func, GLclampx ref) { - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.alphaFuncx(c, func, ref); -} - -void glBlendFunc(GLenum sfactor, GLenum dfactor) { - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.blendFunc(c, sfactor, dfactor); -} - -void glClear(GLbitfield mask) { - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.clear(c, mask); -} - -void glClearColorx(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) { - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.clearColorx(c, red, green, blue, alpha); -} - -void glClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) -{ - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.clearColorx(c, - gglFloatToFixed(r), - gglFloatToFixed(g), - gglFloatToFixed(b), - gglFloatToFixed(a)); -} - -void glClearDepthx(GLclampx depth) { - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.clearDepthx(c, depth); -} - -void glClearDepthf(GLclampf depth) -{ - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.clearDepthx(c, gglFloatToFixed(depth)); -} - -void glClearStencil(GLint s) { - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.clearStencil(c, s); -} diff --git a/opengl/libagl/state.h b/opengl/libagl/state.h deleted file mode 100644 index 55a5ccbd11..0000000000 --- a/opengl/libagl/state.h +++ /dev/null @@ -1,54 +0,0 @@ -/* libs/opengles/state.h -** -** Copyright 2006, 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_OPENGLES_STATE_H -#define ANDROID_OPENGLES_STATE_H - -#include -#include -#include - -#include - -#include - -#include - -namespace android { - -ogles_context_t *ogles_init(size_t extra); -void ogles_uninit(ogles_context_t* c); -void _ogles_error(ogles_context_t* c, GLenum error); - -#ifndef TRACE_GL_ERRORS -#define TRACE_GL_ERRORS 0 -#endif - -#if TRACE_GL_ERRORS -#define ogles_error(c, error) \ -do { \ - printf("ogles_error at file %s line %d\n", __FILE__, __LINE__); \ - _ogles_error(c, error); \ -} while (0) -#else /* !TRACE_GL_ERRORS */ -#define ogles_error(c, error) _ogles_error((c), (error)) -#endif - -}; // namespace android - -#endif // ANDROID_OPENGLES_STATE_H - diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp deleted file mode 100644 index 4c5f3e93d3..0000000000 --- a/opengl/libagl/texture.cpp +++ /dev/null @@ -1,1643 +0,0 @@ -/* libs/opengles/texture.cpp -** -** Copyright 2006, 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 -#include -#include "context.h" -#include "fp.h" -#include "state.h" -#include "texture.h" -#include "TextureObjectManager.h" - -#include - -#include -#include - -namespace android { - -// ---------------------------------------------------------------------------- - -static void bindTextureTmu( - ogles_context_t* c, int tmu, GLuint texture, const sp& tex); - -static __attribute__((noinline)) -void generateMipmap(ogles_context_t* c, GLint level); - -// ---------------------------------------------------------------------------- - -#if 0 -#pragma mark - -#pragma mark Init -#endif - -void ogles_init_texture(ogles_context_t* c) -{ - c->textures.packAlignment = 4; - c->textures.unpackAlignment = 4; - - // each context has a default named (0) texture (not shared) - c->textures.defaultTexture = new EGLTextureObject(); - c->textures.defaultTexture->incStrong(c); - - // bind the default texture to each texture unit - for (int i=0; itextures.defaultTexture); - memset(c->current.texture[i].v, 0, sizeof(vec4_t)); - c->current.texture[i].Q = 0x10000; - } -} - -void ogles_uninit_texture(ogles_context_t* c) -{ - if (c->textures.ggl) - gglUninit(c->textures.ggl); - c->textures.defaultTexture->decStrong(c); - for (int i=0; itextures.tmu[i].texture) - c->textures.tmu[i].texture->decStrong(c); - } -} - -static __attribute__((noinline)) -void validate_tmu(ogles_context_t* c, int i) -{ - texture_unit_t& u(c->textures.tmu[i]); - if (u.dirty) { - u.dirty = 0; - c->rasterizer.procs.activeTexture(c, i); - c->rasterizer.procs.bindTexture(c, &(u.texture->surface)); - c->rasterizer.procs.texGeni(c, GGL_S, - GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC); - c->rasterizer.procs.texGeni(c, GGL_T, - GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC); - c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, - GGL_TEXTURE_WRAP_S, u.texture->wraps); - c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, - GGL_TEXTURE_WRAP_T, u.texture->wrapt); - c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, - GGL_TEXTURE_MIN_FILTER, u.texture->min_filter); - c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, - GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter); - - // disable this texture unit if it's not complete - if (!u.texture->isComplete()) { - c->rasterizer.procs.disable(c, GGL_TEXTURE_2D); - } - } -} - -void ogles_validate_texture(ogles_context_t* c) -{ - for (int i=0 ; irasterizer.state.texture[i].enable) - validate_tmu(c, i); - } - c->rasterizer.procs.activeTexture(c, c->textures.active); -} - -static -void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) { - c->textures.tmu[tmu].dirty = flags; -} - -/* - * If the active textures are EGLImage, they need to be locked before - * they can be used. - * - * FIXME: code below is far from being optimal - * - */ - -void ogles_lock_textures(ogles_context_t* c) -{ - for (int i=0 ; irasterizer.state.texture[i].enable) { - texture_unit_t& u(c->textures.tmu[i]); - ANativeWindowBuffer* native_buffer = u.texture->buffer; - if (native_buffer) { - c->rasterizer.procs.activeTexture(c, i); - - auto& mapper = GraphicBufferMapper::get(); - void* vaddr; - mapper.lock(native_buffer->handle, GRALLOC_USAGE_SW_READ_OFTEN, - Rect(native_buffer->width, native_buffer->height), - &vaddr); - - u.texture->setImageBits(vaddr); - c->rasterizer.procs.bindTexture(c, &(u.texture->surface)); - } - } - } -} - -void ogles_unlock_textures(ogles_context_t* c) -{ - for (int i=0 ; irasterizer.state.texture[i].enable) { - texture_unit_t& u(c->textures.tmu[i]); - ANativeWindowBuffer* native_buffer = u.texture->buffer; - if (native_buffer) { - c->rasterizer.procs.activeTexture(c, i); - - auto& mapper = GraphicBufferMapper::get(); - mapper.unlock(native_buffer->handle); - - u.texture->setImageBits(NULL); - c->rasterizer.procs.bindTexture(c, &(u.texture->surface)); - } - } - } - c->rasterizer.procs.activeTexture(c, c->textures.active); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark Format conversion -#endif - -static uint32_t gl2format_table[6][4] = { - // BYTE, 565, 4444, 5551 - { GGL_PIXEL_FORMAT_A_8, - 0, 0, 0 }, // GL_ALPHA - { GGL_PIXEL_FORMAT_RGB_888, - GGL_PIXEL_FORMAT_RGB_565, - 0, 0 }, // GL_RGB - { GGL_PIXEL_FORMAT_RGBA_8888, - 0, - GGL_PIXEL_FORMAT_RGBA_4444, - GGL_PIXEL_FORMAT_RGBA_5551 }, // GL_RGBA - { GGL_PIXEL_FORMAT_L_8, - 0, 0, 0 }, // GL_LUMINANCE - { GGL_PIXEL_FORMAT_LA_88, - 0, 0, 0 }, // GL_LUMINANCE_ALPHA -}; - -static int32_t convertGLPixelFormat(GLint format, GLenum type) -{ - int32_t fi = -1; - int32_t ti = -1; - switch (format) { - case GL_ALPHA: fi = 0; break; - case GL_RGB: fi = 1; break; - case GL_RGBA: fi = 2; break; - case GL_LUMINANCE: fi = 3; break; - case GL_LUMINANCE_ALPHA: fi = 4; break; - } - switch (type) { - case GL_UNSIGNED_BYTE: ti = 0; break; - case GL_UNSIGNED_SHORT_5_6_5: ti = 1; break; - case GL_UNSIGNED_SHORT_4_4_4_4: ti = 2; break; - case GL_UNSIGNED_SHORT_5_5_5_1: ti = 3; break; - } - if (fi==-1 || ti==-1) - return 0; - return gl2format_table[fi][ti]; -} - -// ---------------------------------------------------------------------------- - -static GLenum validFormatType(ogles_context_t* c, GLenum format, GLenum type) -{ - GLenum error = 0; - if (formatGL_LUMINANCE_ALPHA) { - error = GL_INVALID_ENUM; - } - if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_SHORT_4_4_4_4 && - type != GL_UNSIGNED_SHORT_5_5_5_1 && type != GL_UNSIGNED_SHORT_5_6_5) { - error = GL_INVALID_ENUM; - } - if (type == GL_UNSIGNED_SHORT_5_6_5 && format != GL_RGB) { - error = GL_INVALID_OPERATION; - } - if ((type == GL_UNSIGNED_SHORT_4_4_4_4 || - type == GL_UNSIGNED_SHORT_5_5_5_1) && format != GL_RGBA) { - error = GL_INVALID_OPERATION; - } - if (error) { - ogles_error(c, error); - } - return error; -} - -// ---------------------------------------------------------------------------- - -GGLContext* getRasterizer(ogles_context_t* c) -{ - GGLContext* ggl = c->textures.ggl; - if (ggl_unlikely(!ggl)) { - // this is quite heavy the first time... - gglInit(&ggl); - if (!ggl) { - return 0; - } - GGLfixed colors[4] = { 0, 0, 0, 0x10000 }; - c->textures.ggl = ggl; - ggl->activeTexture(ggl, 0); - ggl->enable(ggl, GGL_TEXTURE_2D); - ggl->texEnvi(ggl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE); - ggl->disable(ggl, GGL_DITHER); - ggl->shadeModel(ggl, GGL_FLAT); - ggl->color4xv(ggl, colors); - } - return ggl; -} - -static __attribute__((noinline)) -int copyPixels( - ogles_context_t* c, - const GGLSurface& dst, - GLint xoffset, GLint yoffset, - const GGLSurface& src, - GLint x, GLint y, GLsizei w, GLsizei h) -{ - if ((dst.format == src.format) && - (dst.stride == src.stride) && - (dst.width == src.width) && - (dst.height == src.height) && - (dst.stride > 0) && - ((x|y) == 0) && - ((xoffset|yoffset) == 0)) - { - // this is a common case... - const GGLFormat& pixelFormat(c->rasterizer.formats[src.format]); - const size_t size = src.height * src.stride * pixelFormat.size; - memcpy(dst.data, src.data, size); - return 0; - } - - // use pixel-flinger to handle all the conversions - GGLContext* ggl = getRasterizer(c); - if (!ggl) { - // the only reason this would fail is because we ran out of memory - return GL_OUT_OF_MEMORY; - } - - ggl->colorBuffer(ggl, &dst); - ggl->bindTexture(ggl, &src); - ggl->texCoord2i(ggl, x-xoffset, y-yoffset); - ggl->recti(ggl, xoffset, yoffset, xoffset+w, yoffset+h); - return 0; -} - -// ---------------------------------------------------------------------------- - -static __attribute__((noinline)) -sp getAndBindActiveTextureObject(ogles_context_t* c) -{ - sp tex; - const int active = c->textures.active; - const GLuint name = c->textures.tmu[active].name; - - // free the reference to the previously bound object - texture_unit_t& u(c->textures.tmu[active]); - if (u.texture) - u.texture->decStrong(c); - - if (name == 0) { - // 0 is our local texture object, not shared with anyone. - // But it affects all bound TMUs immediately. - // (we need to invalidate all units bound to this texture object) - tex = c->textures.defaultTexture; - for (int i=0 ; itextures.tmu[i].texture == tex.get()) - invalidate_texture(c, i); - } - } else { - // get a new texture object for that name - tex = c->surfaceManager->replaceTexture(name); - } - - // bind this texture to the current active texture unit - // and add a reference to this texture object - u.texture = tex.get(); - u.texture->incStrong(c); - u.name = name; - invalidate_texture(c, active); - return tex; -} - -void bindTextureTmu( - ogles_context_t* c, int tmu, GLuint texture, const sp& tex) -{ - if (tex.get() == c->textures.tmu[tmu].texture) - return; - - // free the reference to the previously bound object - texture_unit_t& u(c->textures.tmu[tmu]); - if (u.texture) - u.texture->decStrong(c); - - // bind this texture to the current active texture unit - // and add a reference to this texture object - u.texture = tex.get(); - u.texture->incStrong(c); - u.name = texture; - invalidate_texture(c, tmu); -} - -int createTextureSurface(ogles_context_t* c, - GGLSurface** outSurface, int32_t* outSize, GLint level, - GLenum format, GLenum type, GLsizei width, GLsizei height, - GLenum compressedFormat = 0) -{ - // convert the pixelformat to one we can handle - const int32_t formatIdx = convertGLPixelFormat(format, type); - if (formatIdx == 0) { // we don't know what to do with this - return GL_INVALID_OPERATION; - } - - // figure out the size we need as well as the stride - const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]); - const int32_t align = c->textures.unpackAlignment-1; - const int32_t bpr = ((width * pixelFormat.size) + align) & ~align; - const size_t size = bpr * height; - const int32_t stride = bpr / pixelFormat.size; - - if (level > 0) { - const int active = c->textures.active; - EGLTextureObject* tex = c->textures.tmu[active].texture; - status_t err = tex->reallocate(level, - width, height, stride, formatIdx, compressedFormat, bpr); - if (err != NO_ERROR) - return GL_OUT_OF_MEMORY; - GGLSurface& surface = tex->editMip(level); - *outSurface = &surface; - *outSize = size; - return 0; - } - - sp tex = getAndBindActiveTextureObject(c); - status_t err = tex->reallocate(level, - width, height, stride, formatIdx, compressedFormat, bpr); - if (err != NO_ERROR) - return GL_OUT_OF_MEMORY; - - tex->internalformat = format; - *outSurface = &tex->surface; - *outSize = size; - return 0; -} - -static GLsizei dataSizePalette4(int numLevels, int width, int height, int format) -{ - int indexBits = 8; - int entrySize = 0; - switch (format) { - case GL_PALETTE4_RGB8_OES: - indexBits = 4; - [[fallthrough]]; - case GL_PALETTE8_RGB8_OES: - entrySize = 3; - break; - - case GL_PALETTE4_RGBA8_OES: - indexBits = 4; - [[fallthrough]]; - case GL_PALETTE8_RGBA8_OES: - entrySize = 4; - break; - - case GL_PALETTE4_R5_G6_B5_OES: - case GL_PALETTE4_RGBA4_OES: - case GL_PALETTE4_RGB5_A1_OES: - indexBits = 4; - [[fallthrough]]; - case GL_PALETTE8_R5_G6_B5_OES: - case GL_PALETTE8_RGBA4_OES: - case GL_PALETTE8_RGB5_A1_OES: - entrySize = 2; - break; - } - - size_t size = (1 << indexBits) * entrySize; // palette size - - for (int i=0 ; i< numLevels ; i++) { - int w = (width >> i) ? : 1; - int h = (height >> i) ? : 1; - int levelSize = h * ((w * indexBits) / 8) ? : 1; - size += levelSize; - } - - return size; -} - -static void decodePalette4(const GLvoid *data, int level, int width, int height, - void *surface, int stride, int format) - -{ - int indexBits = 8; - int entrySize = 0; - switch (format) { - case GL_PALETTE4_RGB8_OES: - indexBits = 4; - [[fallthrough]]; - case GL_PALETTE8_RGB8_OES: - entrySize = 3; - break; - - case GL_PALETTE4_RGBA8_OES: - indexBits = 4; - [[fallthrough]]; - case GL_PALETTE8_RGBA8_OES: - entrySize = 4; - break; - - case GL_PALETTE4_R5_G6_B5_OES: - case GL_PALETTE4_RGBA4_OES: - case GL_PALETTE4_RGB5_A1_OES: - indexBits = 4; - [[fallthrough]]; - case GL_PALETTE8_R5_G6_B5_OES: - case GL_PALETTE8_RGBA4_OES: - case GL_PALETTE8_RGB5_A1_OES: - entrySize = 2; - break; - } - - const int paletteSize = (1 << indexBits) * entrySize; - - uint8_t const* pixels = (uint8_t *)data + paletteSize; - for (int i=0 ; i> i) ? : 1; - int h = (height >> i) ? : 1; - pixels += h * ((w * indexBits) / 8); - } - width = (width >> level) ? : 1; - height = (height >> level) ? : 1; - - if (entrySize == 2) { - uint8_t const* const palette = (uint8_t*)data; - for (int y=0 ; y> 4); - *p++ = palette[index + 0]; - *p++ = palette[index + 1]; - if (x+1 < width) { - index = 2 * (v & 0xF); - *p++ = palette[index + 0]; - *p++ = palette[index + 1]; - } - } - } - } - } else if (entrySize == 3) { - uint8_t const* const palette = (uint8_t*)data; - for (int y=0 ; y> 4); - *p++ = palette[index + 0]; - *p++ = palette[index + 1]; - *p++ = palette[index + 2]; - if (x+1 < width) { - index = 3 * (v & 0xF); - *p++ = palette[index + 0]; - *p++ = palette[index + 1]; - *p++ = palette[index + 2]; - } - } - } - } - } else if (entrySize == 4) { - uint8_t const* const palette = (uint8_t*)data; - for (int y=0 ; y> 4); - *p++ = palette[index + 0]; - *p++ = palette[index + 1]; - *p++ = palette[index + 2]; - *p++ = palette[index + 3]; - if (x+1 < width) { - index = 4 * (v & 0xF); - *p++ = palette[index + 0]; - *p++ = palette[index + 1]; - *p++ = palette[index + 2]; - *p++ = palette[index + 3]; - } - } - } - } - } -} - - - -static __attribute__((noinline)) -void set_depth_and_fog(ogles_context_t* c, GGLfixed z) -{ - const uint32_t enables = c->rasterizer.state.enables; - // we need to compute Zw - int32_t iterators[3]; - iterators[1] = iterators[2] = 0; - GGLfixed Zw; - GGLfixed n = gglFloatToFixed(c->transforms.vpt.zNear); - GGLfixed f = gglFloatToFixed(c->transforms.vpt.zFar); - if (z<=0) Zw = n; - else if (z>=0x10000) Zw = f; - else Zw = gglMulAddx(z, (f-n), n); - if (enables & GGL_ENABLE_FOG) { - // set up fog if needed... - iterators[0] = c->fog.fog(c, Zw); - c->rasterizer.procs.fogGrad3xv(c, iterators); - } - if (enables & GGL_ENABLE_DEPTH_TEST) { - // set up z-test if needed... - int32_t z = (Zw & ~(Zw>>31)); - if (z >= 0x10000) - z = 0xFFFF; - iterators[0] = (z << 16) | z; - c->rasterizer.procs.zGrad3xv(c, iterators); - } -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark Generate mimaps -#endif - -extern status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex); - -void generateMipmap(ogles_context_t* c, GLint level) -{ - if (level == 0) { - const int active = c->textures.active; - EGLTextureObject* tex = c->textures.tmu[active].texture; - if (tex->generate_mipmap) { - if (buildAPyramid(c, tex) != NO_ERROR) { - ogles_error(c, GL_OUT_OF_MEMORY); - return; - } - } - } -} - - -static void texParameterx( - GLenum target, GLenum pname, GLfixed param, ogles_context_t* c) -{ - if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - - EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture; - switch (pname) { - case GL_TEXTURE_WRAP_S: - if ((param == GL_REPEAT) || - (param == GL_CLAMP_TO_EDGE)) { - textureObject->wraps = param; - } else { - goto invalid_enum; - } - break; - case GL_TEXTURE_WRAP_T: - if ((param == GL_REPEAT) || - (param == GL_CLAMP_TO_EDGE)) { - textureObject->wrapt = param; - } else { - goto invalid_enum; - } - break; - case GL_TEXTURE_MIN_FILTER: - if ((param == GL_NEAREST) || - (param == GL_LINEAR) || - (param == GL_NEAREST_MIPMAP_NEAREST) || - (param == GL_LINEAR_MIPMAP_NEAREST) || - (param == GL_NEAREST_MIPMAP_LINEAR) || - (param == GL_LINEAR_MIPMAP_LINEAR)) { - textureObject->min_filter = param; - } else { - goto invalid_enum; - } - break; - case GL_TEXTURE_MAG_FILTER: - if ((param == GL_NEAREST) || - (param == GL_LINEAR)) { - textureObject->mag_filter = param; - } else { - goto invalid_enum; - } - break; - case GL_GENERATE_MIPMAP: - textureObject->generate_mipmap = param; - break; - default: -invalid_enum: - ogles_error(c, GL_INVALID_ENUM); - return; - } - invalidate_texture(c, c->textures.active); -} - - - -static void drawTexxOESImp(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h, - ogles_context_t* c) -{ - ogles_lock_textures(c); - - const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; - y = gglIntToFixed(cbSurface.height) - (y + h); - w >>= FIXED_BITS; - h >>= FIXED_BITS; - - // set up all texture units - for (int i=0 ; irasterizer.state.texture[i].enable) - continue; - - int32_t texcoords[8]; - texture_unit_t& u(c->textures.tmu[i]); - - // validate this tmu (bind, wrap, filter) - validate_tmu(c, i); - // we CLAMP here, which works with premultiplied (s,t) - c->rasterizer.procs.texParameteri(c, - GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP); - c->rasterizer.procs.texParameteri(c, - GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP); - u.dirty = 0xFF; // XXX: should be more subtle - - EGLTextureObject* textureObject = u.texture; - const GLint Ucr = textureObject->crop_rect[0] << 16; - const GLint Vcr = textureObject->crop_rect[1] << 16; - const GLint Wcr = textureObject->crop_rect[2] << 16; - const GLint Hcr = textureObject->crop_rect[3] << 16; - - // computes texture coordinates (pre-multiplied) - int32_t dsdx = Wcr / w; // dsdx = ((Wcr/w)/Wt)*Wt - int32_t dtdy =-Hcr / h; // dtdy = -((Hcr/h)/Ht)*Ht - int32_t s0 = Ucr - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx - int32_t t0 = (Vcr+Hcr) - gglMulx(dtdy, y); // t0 = (Vcr+Hcr) - y*dtdy - texcoords[0] = s0; - texcoords[1] = dsdx; - texcoords[2] = 0; - texcoords[3] = t0; - texcoords[4] = 0; - texcoords[5] = dtdy; - texcoords[6] = 0; - texcoords[7] = 0; - c->rasterizer.procs.texCoordGradScale8xv(c, i, texcoords); - } - - const uint32_t enables = c->rasterizer.state.enables; - if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG))) - set_depth_and_fog(c, z); - - c->rasterizer.procs.activeTexture(c, c->textures.active); - c->rasterizer.procs.color4xv(c, c->currentColorClamped.v); - c->rasterizer.procs.disable(c, GGL_W_LERP); - c->rasterizer.procs.disable(c, GGL_AA); - c->rasterizer.procs.shadeModel(c, GL_FLAT); - c->rasterizer.procs.recti(c, - gglFixedToIntRound(x), - gglFixedToIntRound(y), - gglFixedToIntRound(x)+w, - gglFixedToIntRound(y)+h); - - ogles_unlock_textures(c); -} - -static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h, - ogles_context_t* c) -{ - // quickly reject empty rects - if ((w|h) <= 0) - return; - - drawTexxOESImp(x, y, z, w, h, c); -} - -static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c) -{ - // All coordinates are integer, so if we have only one - // texture unit active and no scaling is required - // THEN, we can use our special 1:1 mapping - // which is a lot faster. - - if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) { - const int tmu = 0; - texture_unit_t& u(c->textures.tmu[tmu]); - EGLTextureObject* textureObject = u.texture; - const GLint Wcr = textureObject->crop_rect[2]; - const GLint Hcr = textureObject->crop_rect[3]; - - if ((w == Wcr) && (h == -Hcr)) { - if ((w|h) <= 0) return; // quickly reject empty rects - - if (u.dirty) { - c->rasterizer.procs.activeTexture(c, tmu); - c->rasterizer.procs.bindTexture(c, &(u.texture->surface)); - c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, - GGL_TEXTURE_MIN_FILTER, u.texture->min_filter); - c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D, - GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter); - } - c->rasterizer.procs.texGeni(c, GGL_S, - GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE); - c->rasterizer.procs.texGeni(c, GGL_T, - GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE); - u.dirty = 0xFF; // XXX: should be more subtle - c->rasterizer.procs.activeTexture(c, c->textures.active); - - const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; - y = cbSurface.height - (y + h); - const GLint Ucr = textureObject->crop_rect[0]; - const GLint Vcr = textureObject->crop_rect[1]; - const GLint s0 = Ucr - x; - const GLint t0 = (Vcr + Hcr) - y; - - const GLuint tw = textureObject->surface.width; - const GLuint th = textureObject->surface.height; - if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) { - // The GL spec is unclear about what should happen - // in this case, so we just use the slow case, which - // at least won't crash - goto slow_case; - } - - ogles_lock_textures(c); - - c->rasterizer.procs.texCoord2i(c, s0, t0); - const uint32_t enables = c->rasterizer.state.enables; - if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG))) - set_depth_and_fog(c, gglIntToFixed(z)); - - c->rasterizer.procs.color4xv(c, c->currentColorClamped.v); - c->rasterizer.procs.disable(c, GGL_W_LERP); - c->rasterizer.procs.disable(c, GGL_AA); - c->rasterizer.procs.shadeModel(c, GL_FLAT); - c->rasterizer.procs.recti(c, x, y, x+w, y+h); - - ogles_unlock_textures(c); - - return; - } - } - -slow_case: - drawTexxOESImp( - gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z), - gglIntToFixed(w), gglIntToFixed(h), - c); -} - - -}; // namespace android -// ---------------------------------------------------------------------------- - -using namespace android; - - -#if 0 -#pragma mark - -#pragma mark Texture API -#endif - -void glActiveTexture(GLenum texture) -{ - ogles_context_t* c = ogles_context_t::get(); - if (uint32_t(texture-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - c->textures.active = texture - GL_TEXTURE0; - c->rasterizer.procs.activeTexture(c, c->textures.active); -} - -void glBindTexture(GLenum target, GLuint texture) -{ - ogles_context_t* c = ogles_context_t::get(); - if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - - // Bind or create a texture - sp tex; - if (texture == 0) { - // 0 is our local texture object - tex = c->textures.defaultTexture; - } else { - tex = c->surfaceManager->texture(texture); - if (ggl_unlikely(tex == 0)) { - tex = c->surfaceManager->createTexture(texture); - if (tex == 0) { - ogles_error(c, GL_OUT_OF_MEMORY); - return; - } - } - } - bindTextureTmu(c, c->textures.active, texture, tex); -} - -void glGenTextures(GLsizei n, GLuint *textures) -{ - ogles_context_t* c = ogles_context_t::get(); - if (n<0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - // generate unique (shared) texture names - c->surfaceManager->getToken(n, textures); -} - -void glDeleteTextures(GLsizei n, const GLuint *textures) -{ - ogles_context_t* c = ogles_context_t::get(); - if (n<0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - - // If deleting a bound texture, bind this unit to 0 - for (int t=0 ; ttextures.tmu[t].name == 0) - continue; - for (int i=0 ; itextures.tmu[t].name)) { - // bind this tmu to texture 0 - sp tex(c->textures.defaultTexture); - bindTextureTmu(c, t, 0, tex); - } - } - } - c->surfaceManager->deleteTextures(n, textures); - c->surfaceManager->recycleTokens(n, textures); -} - -void glMultiTexCoord4f( - GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) -{ - ogles_context_t* c = ogles_context_t::get(); - if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - const int tmu = target-GL_TEXTURE0; - c->current.texture[tmu].S = gglFloatToFixed(s); - c->current.texture[tmu].T = gglFloatToFixed(t); - c->current.texture[tmu].R = gglFloatToFixed(r); - c->current.texture[tmu].Q = gglFloatToFixed(q); -} - -void glMultiTexCoord4x( - GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q) -{ - ogles_context_t* c = ogles_context_t::get(); - if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - const int tmu = target-GL_TEXTURE0; - c->current.texture[tmu].S = s; - c->current.texture[tmu].T = t; - c->current.texture[tmu].R = r; - c->current.texture[tmu].Q = q; -} - -void glPixelStorei(GLenum pname, GLint param) -{ - ogles_context_t* c = ogles_context_t::get(); - if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - if ((param<=0 || param>8) || (param & (param-1))) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - if (pname == GL_PACK_ALIGNMENT) - c->textures.packAlignment = param; - if (pname == GL_UNPACK_ALIGNMENT) - c->textures.unpackAlignment = param; -} - -void glTexEnvf(GLenum target, GLenum pname, GLfloat param) -{ - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.texEnvi(c, target, pname, GLint(param)); -} - -void glTexEnvfv( - GLenum target, GLenum pname, const GLfloat *params) -{ - ogles_context_t* c = ogles_context_t::get(); - if (pname == GL_TEXTURE_ENV_MODE) { - c->rasterizer.procs.texEnvi(c, target, pname, GLint(*params)); - return; - } - if (pname == GL_TEXTURE_ENV_COLOR) { - GGLfixed fixed[4]; - for (int i=0 ; i<4 ; i++) - fixed[i] = gglFloatToFixed(params[i]); - c->rasterizer.procs.texEnvxv(c, target, pname, fixed); - return; - } - ogles_error(c, GL_INVALID_ENUM); -} - -void glTexEnvx(GLenum target, GLenum pname, GLfixed param) -{ - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.texEnvi(c, target, pname, param); -} - -void glTexEnvxv( - GLenum target, GLenum pname, const GLfixed *params) -{ - ogles_context_t* c = ogles_context_t::get(); - c->rasterizer.procs.texEnvxv(c, target, pname, params); -} - -void glTexParameteriv( - GLenum target, GLenum pname, const GLint* params) -{ - ogles_context_t* c = ogles_context_t::get(); - if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - - EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture; - switch (pname) { - case GL_TEXTURE_CROP_RECT_OES: - memcpy(textureObject->crop_rect, params, 4*sizeof(GLint)); - break; - default: - texParameterx(target, pname, GLfixed(params[0]), c); - return; - } -} - -void glTexParameterf( - GLenum target, GLenum pname, GLfloat param) -{ - ogles_context_t* c = ogles_context_t::get(); - texParameterx(target, pname, GLfixed(param), c); -} - -void glTexParameterx( - GLenum target, GLenum pname, GLfixed param) -{ - ogles_context_t* c = ogles_context_t::get(); - texParameterx(target, pname, param, c); -} - -void glTexParameteri( - GLenum target, GLenum pname, GLint param) -{ - ogles_context_t* c = ogles_context_t::get(); - texParameterx(target, pname, GLfixed(param), c); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#endif - -void glCompressedTexImage2D( - GLenum target, GLint level, GLenum internalformat, - GLsizei width, GLsizei height, GLint border, - GLsizei imageSize, const GLvoid *data) -{ - ogles_context_t* c = ogles_context_t::get(); - if (target != GL_TEXTURE_2D) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - if (width<0 || height<0 || border!=0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - - // "uncompress" the texture since pixelflinger doesn't support - // any compressed texture format natively. - GLenum format; - GLenum type; - switch (internalformat) { - case GL_PALETTE8_RGB8_OES: - case GL_PALETTE4_RGB8_OES: - format = GL_RGB; - type = GL_UNSIGNED_BYTE; - break; - case GL_PALETTE8_RGBA8_OES: - case GL_PALETTE4_RGBA8_OES: - format = GL_RGBA; - type = GL_UNSIGNED_BYTE; - break; - case GL_PALETTE8_R5_G6_B5_OES: - case GL_PALETTE4_R5_G6_B5_OES: - format = GL_RGB; - type = GL_UNSIGNED_SHORT_5_6_5; - break; - case GL_PALETTE8_RGBA4_OES: - case GL_PALETTE4_RGBA4_OES: - format = GL_RGBA; - type = GL_UNSIGNED_SHORT_4_4_4_4; - break; - case GL_PALETTE8_RGB5_A1_OES: - case GL_PALETTE4_RGB5_A1_OES: - format = GL_RGBA; - type = GL_UNSIGNED_SHORT_5_5_5_1; - break; -#ifdef GL_OES_compressed_ETC1_RGB8_texture - case GL_ETC1_RGB8_OES: - format = GL_RGB; - type = GL_UNSIGNED_BYTE; - break; -#endif - default: - ogles_error(c, GL_INVALID_ENUM); - return; - } - - if (!data || !width || !height) { - // unclear if this is an error or not... - return; - } - - int32_t size; - GGLSurface* surface; - -#ifdef GL_OES_compressed_ETC1_RGB8_texture - if (internalformat == GL_ETC1_RGB8_OES) { - GLsizei compressedSize = etc1_get_encoded_data_size(width, height); - if (compressedSize > imageSize) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - int error = createTextureSurface(c, &surface, &size, - level, format, type, width, height); - if (error) { - ogles_error(c, error); - return; - } - if (etc1_decode_image( - (const etc1_byte*)data, - (etc1_byte*)surface->data, - width, height, 3, surface->stride*3) != 0) { - ogles_error(c, GL_INVALID_OPERATION); - } - return; - } -#endif - - // all mipmap levels are specified at once. - const int numLevels = level<0 ? -level : 1; - - if (dataSizePalette4(numLevels, width, height, format) > imageSize) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - - for (int i=0 ; i> i) ? : 1; - int lod_h = (height >> i) ? : 1; - int error = createTextureSurface(c, &surface, &size, - i, format, type, lod_w, lod_h); - if (error) { - ogles_error(c, error); - return; - } - decodePalette4(data, i, width, height, - surface->data, surface->stride, internalformat); - } -} - - -void glTexImage2D( - GLenum target, GLint level, GLint internalformat, - GLsizei width, GLsizei height, GLint border, - GLenum format, GLenum type, const GLvoid *pixels) -{ - ogles_context_t* c = ogles_context_t::get(); - if (target != GL_TEXTURE_2D) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - if (width<0 || height<0 || border!=0 || level < 0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - if (format != (GLenum)internalformat) { - ogles_error(c, GL_INVALID_OPERATION); - return; - } - if (validFormatType(c, format, type)) { - return; - } - - int32_t size = 0; - GGLSurface* surface = 0; - int error = createTextureSurface(c, &surface, &size, - level, format, type, width, height); - if (error) { - ogles_error(c, error); - return; - } - - if (pixels) { - const int32_t formatIdx = convertGLPixelFormat(format, type); - const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]); - const int32_t align = c->textures.unpackAlignment-1; - const int32_t bpr = ((width * pixelFormat.size) + align) & ~align; - const int32_t stride = bpr / pixelFormat.size; - - GGLSurface userSurface; - userSurface.version = sizeof(userSurface); - userSurface.width = width; - userSurface.height = height; - userSurface.stride = stride; - userSurface.format = formatIdx; - userSurface.compressedFormat = 0; - userSurface.data = (GLubyte*)pixels; - - int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height); - if (err) { - ogles_error(c, err); - return; - } - generateMipmap(c, level); - } -} - -// ---------------------------------------------------------------------------- - -void glCompressedTexSubImage2D( - GLenum /*target*/, GLint /*level*/, GLint /*xoffset*/, - GLint /*yoffset*/, GLsizei /*width*/, GLsizei /*height*/, - GLenum /*format*/, GLsizei /*imageSize*/, - const GLvoid* /*data*/) -{ - ogles_context_t* c = ogles_context_t::get(); - ogles_error(c, GL_INVALID_ENUM); -} - -void glTexSubImage2D( - GLenum target, GLint level, GLint xoffset, - GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLenum type, const GLvoid *pixels) -{ - ogles_context_t* c = ogles_context_t::get(); - if (target != GL_TEXTURE_2D) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - if (validFormatType(c, format, type)) { - return; - } - - // find out which texture is bound to the current unit - const int active = c->textures.active; - EGLTextureObject* tex = c->textures.tmu[active].texture; - const GGLSurface& surface(tex->mip(level)); - - if (!tex->internalformat || tex->direct) { - ogles_error(c, GL_INVALID_OPERATION); - return; - } - - if (format != tex->internalformat) { - ogles_error(c, GL_INVALID_OPERATION); - return; - } - if ((xoffset + width > GLsizei(surface.width)) || - (yoffset + height > GLsizei(surface.height))) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - if (!width || !height) { - return; // okay, but no-op. - } - - // figure out the size we need as well as the stride - const int32_t formatIdx = convertGLPixelFormat(format, type); - if (formatIdx == 0) { // we don't know what to do with this - ogles_error(c, GL_INVALID_OPERATION); - return; - } - - const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]); - const int32_t align = c->textures.unpackAlignment-1; - const int32_t bpr = ((width * pixelFormat.size) + align) & ~align; - const int32_t stride = bpr / pixelFormat.size; - GGLSurface userSurface; - userSurface.version = sizeof(userSurface); - userSurface.width = width; - userSurface.height = height; - userSurface.stride = stride; - userSurface.format = formatIdx; - userSurface.compressedFormat = 0; - userSurface.data = (GLubyte*)pixels; - - int err = copyPixels(c, - surface, xoffset, yoffset, - userSurface, 0, 0, width, height); - if (err) { - ogles_error(c, err); - return; - } - - generateMipmap(c, level); - - // since we only changed the content of the texture, we don't need - // to call bindTexture on the main rasterizer. -} - -// ---------------------------------------------------------------------------- - -void glCopyTexImage2D( - GLenum target, GLint level, GLenum internalformat, - GLint x, GLint y, GLsizei width, GLsizei height, - GLint border) -{ - ogles_context_t* c = ogles_context_t::get(); - if (target != GL_TEXTURE_2D) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - if (internalformatGL_LUMINANCE_ALPHA) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - if (width<0 || height<0 || border!=0 || level<0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - - GLenum format = 0; - GLenum type = GL_UNSIGNED_BYTE; - const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; - const int cbFormatIdx = cbSurface.format; - switch (cbFormatIdx) { - case GGL_PIXEL_FORMAT_RGB_565: - type = GL_UNSIGNED_SHORT_5_6_5; - break; - case GGL_PIXEL_FORMAT_RGBA_5551: - type = GL_UNSIGNED_SHORT_5_5_5_1; - break; - case GGL_PIXEL_FORMAT_RGBA_4444: - type = GL_UNSIGNED_SHORT_4_4_4_4; - break; - } - switch (internalformat) { - case GL_ALPHA: - case GL_LUMINANCE_ALPHA: - case GL_LUMINANCE: - type = GL_UNSIGNED_BYTE; - break; - } - - // figure out the format to use for the new texture - switch (cbFormatIdx) { - case GGL_PIXEL_FORMAT_RGBA_8888: - case GGL_PIXEL_FORMAT_A_8: - case GGL_PIXEL_FORMAT_RGBA_5551: - case GGL_PIXEL_FORMAT_RGBA_4444: - format = internalformat; - break; - case GGL_PIXEL_FORMAT_RGBX_8888: - case GGL_PIXEL_FORMAT_RGB_888: - case GGL_PIXEL_FORMAT_RGB_565: - case GGL_PIXEL_FORMAT_L_8: - switch (internalformat) { - case GL_LUMINANCE: - case GL_RGB: - format = internalformat; - break; - } - break; - } - - if (format == 0) { - // invalid combination - ogles_error(c, GL_INVALID_ENUM); - return; - } - - // create the new texture... - int32_t size; - GGLSurface* surface; - int error = createTextureSurface(c, &surface, &size, - level, format, type, width, height); - if (error) { - ogles_error(c, error); - return; - } - - // The bottom row is stored first in textures - GGLSurface txSurface(*surface); - txSurface.stride = -txSurface.stride; - - // (x,y) is the lower-left corner of colorBuffer - y = cbSurface.height - (y + height); - - /* The GLES spec says: - * If any of the pixels within the specified rectangle are outside - * the framebuffer associated with the current rendering context, - * then the values obtained for those pixels are undefined. - */ - if (x+width > GLint(cbSurface.width)) - width = cbSurface.width - x; - - if (y+height > GLint(cbSurface.height)) - height = cbSurface.height - y; - - int err = copyPixels(c, - txSurface, 0, 0, - cbSurface, x, y, width, height); - if (err) { - ogles_error(c, err); - } - - generateMipmap(c, level); -} - -void glCopyTexSubImage2D( - GLenum target, GLint level, GLint xoffset, GLint yoffset, - GLint x, GLint y, GLsizei width, GLsizei height) -{ - ogles_context_t* c = ogles_context_t::get(); - if (target != GL_TEXTURE_2D) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - if (!width || !height) { - return; // okay, but no-op. - } - - // find out which texture is bound to the current unit - const int active = c->textures.active; - EGLTextureObject* tex = c->textures.tmu[active].texture; - const GGLSurface& surface(tex->mip(level)); - - if (!tex->internalformat) { - ogles_error(c, GL_INVALID_OPERATION); - return; - } - if ((xoffset + width > GLsizei(surface.width)) || - (yoffset + height > GLsizei(surface.height))) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - - // The bottom row is stored first in textures - GGLSurface txSurface(surface); - txSurface.stride = -txSurface.stride; - - // (x,y) is the lower-left corner of colorBuffer - const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s; - y = cbSurface.height - (y + height); - - /* The GLES spec says: - * If any of the pixels within the specified rectangle are outside - * the framebuffer associated with the current rendering context, - * then the values obtained for those pixels are undefined. - */ - if (x+width > GLint(cbSurface.width)) - width = cbSurface.width - x; - - if (y+height > GLint(cbSurface.height)) - height = cbSurface.height - y; - - int err = copyPixels(c, - txSurface, xoffset, yoffset, - cbSurface, x, y, width, height); - if (err) { - ogles_error(c, err); - return; - } - - generateMipmap(c, level); -} - -void glReadPixels( - GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLvoid *pixels) -{ - ogles_context_t* c = ogles_context_t::get(); - if ((format != GL_RGBA) && (format != GL_RGB)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - if (width<0 || height<0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - if (x<0 || y<0) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - - int32_t formatIdx = GGL_PIXEL_FORMAT_NONE; - if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) { - formatIdx = GGL_PIXEL_FORMAT_RGBA_8888; - } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) { - formatIdx = GGL_PIXEL_FORMAT_RGB_565; - } else { - ogles_error(c, GL_INVALID_OPERATION); - return; - } - - const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s; - if ((x+width > GLint(readSurface.width)) || - (y+height > GLint(readSurface.height))) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - - const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]); - const int32_t align = c->textures.packAlignment-1; - const int32_t bpr = ((width * pixelFormat.size) + align) & ~align; - const int32_t stride = bpr / pixelFormat.size; - - GGLSurface userSurface; - userSurface.version = sizeof(userSurface); - userSurface.width = width; - userSurface.height = height; - userSurface.stride = -stride; // bottom row is transfered first - userSurface.format = formatIdx; - userSurface.compressedFormat = 0; - userSurface.data = (GLubyte*)pixels; - - // use pixel-flinger to handle all the conversions - GGLContext* ggl = getRasterizer(c); - if (!ggl) { - // the only reason this would fail is because we ran out of memory - ogles_error(c, GL_OUT_OF_MEMORY); - return; - } - - ggl->colorBuffer(ggl, &userSurface); // destination is user buffer - ggl->bindTexture(ggl, &readSurface); // source is read-buffer - ggl->texCoord2i(ggl, x, readSurface.height - (y + height)); - ggl->recti(ggl, 0, 0, width, height); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark DrawTexture Extension -#endif - -void glDrawTexsvOES(const GLshort* coords) { - ogles_context_t* c = ogles_context_t::get(); - drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c); -} -void glDrawTexivOES(const GLint* coords) { - ogles_context_t* c = ogles_context_t::get(); - drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c); -} -void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) { - ogles_context_t* c = ogles_context_t::get(); - drawTexiOES(x, y, z, w, h, c); -} -void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) { - ogles_context_t* c = ogles_context_t::get(); - drawTexiOES(x, y, z, w, h, c); -} - -void glDrawTexfvOES(const GLfloat* coords) { - ogles_context_t* c = ogles_context_t::get(); - drawTexxOES( - gglFloatToFixed(coords[0]), - gglFloatToFixed(coords[1]), - gglFloatToFixed(coords[2]), - gglFloatToFixed(coords[3]), - gglFloatToFixed(coords[4]), - c); -} -void glDrawTexxvOES(const GLfixed* coords) { - ogles_context_t* c = ogles_context_t::get(); - drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c); -} -void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){ - ogles_context_t* c = ogles_context_t::get(); - drawTexxOES( - gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z), - gglFloatToFixed(w), gglFloatToFixed(h), - c); -} -void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) { - ogles_context_t* c = ogles_context_t::get(); - drawTexxOES(x, y, z, w, h, c); -} - -// ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark EGL Image Extension -#endif - -void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) -{ - ogles_context_t* c = ogles_context_t::get(); - if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - - if (image == EGL_NO_IMAGE_KHR) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - - ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image; - if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - - // bind it to the texture unit - sp tex = getAndBindActiveTextureObject(c); - tex->setImage(native_buffer); -} - -void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) -{ - ogles_context_t* c = ogles_context_t::get(); - if (target != GL_RENDERBUFFER_OES) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - - if (image == EGL_NO_IMAGE_KHR) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - - ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image; - if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) { - ogles_error(c, GL_INVALID_VALUE); - return; - } - - // well, we're not supporting this extension anyways -} diff --git a/opengl/libagl/texture.h b/opengl/libagl/texture.h deleted file mode 100644 index 98f75509db..0000000000 --- a/opengl/libagl/texture.h +++ /dev/null @@ -1,41 +0,0 @@ -/* libs/opengles/texture.h -** -** Copyright 2006, 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_OPENGLES_TEXTURE_H -#define ANDROID_OPENGLES_TEXTURE_H - -#include -#include -#include - -#include - -#include - -#include "context.h" - -namespace android { - -void ogles_init_texture(ogles_context_t* c); -void ogles_uninit_texture(ogles_context_t* c); -void ogles_validate_texture(ogles_context_t* c); -void ogles_lock_textures(ogles_context_t* c); -void ogles_unlock_textures(ogles_context_t* c); - -}; // namespace android - -#endif // ANDROID_OPENGLES_TEXTURE_H diff --git a/opengl/libagl/vertex.cpp b/opengl/libagl/vertex.cpp deleted file mode 100644 index 9aacdb3c89..0000000000 --- a/opengl/libagl/vertex.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* libs/opengles/vertex.cpp -** -** Copyright 2006, 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 -#include -#include "context.h" -#include "fp.h" -#include "vertex.h" -#include "state.h" -#include "matrix.h" - -namespace android { - -// ---------------------------------------------------------------------------- - -void ogles_init_vertex(ogles_context_t* c) -{ - c->cull.enable = GL_FALSE; - c->cull.cullFace = GL_BACK; - c->cull.frontFace = GL_CCW; - - c->current.color.r = 0x10000; - c->current.color.g = 0x10000; - c->current.color.b = 0x10000; - c->current.color.a = 0x10000; - - c->currentNormal.z = 0x10000; -} - -void ogles_uninit_vertex(ogles_context_t* /*c*/) -{ -} - -// ---------------------------------------------------------------------------- -// vertex processing -// ---------------------------------------------------------------------------- - -// Divides a vertex clip coordinates by W -static inline -void perspective(ogles_context_t* c, vertex_t* v, uint32_t enables) -{ - // [x,y,z]window = vpt * ([x,y,z]clip / clip.w) - // [w]window = 1/w - - // With a regular projection generated by glFrustum(), - // we have w=-z, therefore, w is in [zNear, zFar]. - // Also, zNear and zFar are stricly positive, - // and 1/w (window.w) is in [1/zFar, 1/zNear], usually this - // means ]0, +inf[ -- however, it is always recommended - // to use as large values as possible for zNear. - // All in all, w is usually smaller than 1.0 (assuming - // zNear is at least 1.0); and even if zNear is smaller than 1.0 - // values of w won't be too big. - - const int32_t rw = gglRecip28(v->clip.w); - const GLfixed* const m = c->transforms.vpt.transform.matrix.m; - v->window.w = rw; - v->window.x = gglMulAddx(gglMulx(v->clip.x, rw, 16), m[ 0], m[12], 28); - v->window.y = gglMulAddx(gglMulx(v->clip.y, rw, 16), m[ 5], m[13], 28); - v->window.x = TRI_FROM_FIXED(v->window.x); - v->window.y = TRI_FROM_FIXED(v->window.y); - if (enables & GGL_ENABLE_DEPTH_TEST) { - v->window.z = gglMulAddx(gglMulx(v->clip.z, rw, 16), m[10], m[14], 28); - } -} - -// frustum clipping and W-divide -static inline -void clipFrustumPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables) -{ - // ndc = clip / W - // window = ncd * viewport - - // clip to the view-volume - uint32_t clip = v->flags & vertex_t::CLIP_ALL; - const GLfixed w = v->clip.w; - if (v->clip.x < -w) clip |= vertex_t::CLIP_L; - if (v->clip.x > w) clip |= vertex_t::CLIP_R; - if (v->clip.y < -w) clip |= vertex_t::CLIP_B; - if (v->clip.y > w) clip |= vertex_t::CLIP_T; - if (v->clip.z < -w) clip |= vertex_t::CLIP_N; - if (v->clip.z > w) clip |= vertex_t::CLIP_F; - - v->flags |= clip; - c->arrays.cull &= clip; - - if (ggl_likely(!clip)) { - // if the vertex is clipped, we don't do the perspective - // divide, since we don't need its window coordinates. - perspective(c, v, enables); - } -} - -// frustum clipping, user clipping and W-divide -static inline -void clipAllPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables) -{ - // compute eye coordinates - c->arrays.mv_transform( - &c->transforms.modelview.transform, &v->eye, &v->obj); - v->flags |= vertex_t::EYE; - - // clip this vertex against each user clip plane - uint32_t clip = 0; - int planes = c->clipPlanes.enable; - while (planes) { - const int i = 31 - gglClz(planes); - planes &= ~(1<clipPlanes.plane[i].equation.v, v->eye.v); - if (d < 0) { - clip |= 0x100<flags |= clip; - - clipFrustumPerspective(c, v, enables); -} - -// ---------------------------------------------------------------------------- - -void ogles_vertex_project(ogles_context_t* c, vertex_t* v) { - perspective(c, v, c->rasterizer.state.enables); -} - -void ogles_vertex_perspective2D(ogles_context_t* c, vertex_t* v) -{ - // here we assume w=1.0 and the viewport transformation - // has been applied already. - c->arrays.cull = 0; - v->window.x = TRI_FROM_FIXED(v->clip.x); - v->window.y = TRI_FROM_FIXED(v->clip.y); - v->window.z = v->clip.z; - v->window.w = v->clip.w << 12; -} - -void ogles_vertex_perspective3DZ(ogles_context_t* c, vertex_t* v) { - clipFrustumPerspective(c, v, GGL_ENABLE_DEPTH_TEST); -} -void ogles_vertex_perspective3D(ogles_context_t* c, vertex_t* v) { - clipFrustumPerspective(c, v, 0); -} -void ogles_vertex_clipAllPerspective3DZ(ogles_context_t* c, vertex_t* v) { - clipAllPerspective(c, v, GGL_ENABLE_DEPTH_TEST); -} -void ogles_vertex_clipAllPerspective3D(ogles_context_t* c, vertex_t* v) { - clipAllPerspective(c, v, 0); -} - -static void clipPlanex(GLenum plane, const GLfixed* equ, ogles_context_t* c) -{ - const int p = plane - GL_CLIP_PLANE0; - if (ggl_unlikely(uint32_t(p) > (GL_CLIP_PLANE5 - GL_CLIP_PLANE0))) { - ogles_error(c, GL_INVALID_ENUM); - return; - } - - vec4_t& equation = c->clipPlanes.plane[p].equation; - memcpy(equation.v, equ, sizeof(vec4_t)); - - ogles_validate_transform(c, transform_state_t::MVIT); - transform_t& mvit = c->transforms.mvit4; - mvit.point4(&mvit, &equation, &equation); -} - -// ---------------------------------------------------------------------------- -}; // namespace android -// ---------------------------------------------------------------------------- - -using namespace android; - - -void glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) -{ - ogles_context_t* c = ogles_context_t::get(); - c->current.color.r = gglFloatToFixed(r); - c->currentColorClamped.r = gglClampx(c->current.color.r); - c->current.color.g = gglFloatToFixed(g); - c->currentColorClamped.g = gglClampx(c->current.color.g); - c->current.color.b = gglFloatToFixed(b); - c->currentColorClamped.b = gglClampx(c->current.color.b); - c->current.color.a = gglFloatToFixed(a); - c->currentColorClamped.a = gglClampx(c->current.color.a); -} - -void glColor4x(GLfixed r, GLfixed g, GLfixed b, GLfixed a) -{ - ogles_context_t* c = ogles_context_t::get(); - c->current.color.r = r; - c->current.color.g = g; - c->current.color.b = b; - c->current.color.a = a; - c->currentColorClamped.r = gglClampx(r); - c->currentColorClamped.g = gglClampx(g); - c->currentColorClamped.b = gglClampx(b); - c->currentColorClamped.a = gglClampx(a); -} - -void glNormal3f(GLfloat x, GLfloat y, GLfloat z) -{ - ogles_context_t* c = ogles_context_t::get(); - c->currentNormal.x = gglFloatToFixed(x); - c->currentNormal.y = gglFloatToFixed(y); - c->currentNormal.z = gglFloatToFixed(z); -} - -void glNormal3x(GLfixed x, GLfixed y, GLfixed z) -{ - ogles_context_t* c = ogles_context_t::get(); - c->currentNormal.x = x; - c->currentNormal.y = y; - c->currentNormal.z = z; -} - -// ---------------------------------------------------------------------------- - -void glClipPlanef(GLenum plane, const GLfloat* equ) -{ - const GLfixed equx[4] = { - gglFloatToFixed(equ[0]), - gglFloatToFixed(equ[1]), - gglFloatToFixed(equ[2]), - gglFloatToFixed(equ[3]) - }; - ogles_context_t* c = ogles_context_t::get(); - clipPlanex(plane, equx, c); -} - -void glClipPlanex(GLenum plane, const GLfixed* equ) -{ - ogles_context_t* c = ogles_context_t::get(); - clipPlanex(plane, equ, c); -} diff --git a/opengl/libagl/vertex.h b/opengl/libagl/vertex.h deleted file mode 100644 index 55e62137c1..0000000000 --- a/opengl/libagl/vertex.h +++ /dev/null @@ -1,48 +0,0 @@ -/* libs/opengles/vertex.h -** -** Copyright 2006, 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_OPENGLES_VERTEX_H -#define ANDROID_OPENGLES_VERTEX_H - -#include -#include -#include - -namespace android { - -namespace gl { -struct vertex_t; -struct ogles_context_t; -}; - -void ogles_init_vertex(ogles_context_t* c); -void ogles_uninit_vertex(ogles_context_t* c); - -void ogles_vertex_perspective2D(ogles_context_t*, vertex_t*); - -void ogles_vertex_perspective3D(ogles_context_t*, vertex_t*); -void ogles_vertex_perspective3DZ(ogles_context_t*, vertex_t*); -void ogles_vertex_clipAllPerspective3D(ogles_context_t*, vertex_t*); -void ogles_vertex_clipAllPerspective3DZ(ogles_context_t*, vertex_t*); - - -void ogles_vertex_project(ogles_context_t* c, vertex_t*); - -}; // namespace android - -#endif // ANDROID_OPENGLES_VERTEX_H - diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 23e11a82ac..ff91058f04 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -146,38 +146,6 @@ static void* load_wrapper(const char* path) { #endif #endif -static void setEmulatorGlesValue(void) { - char prop[PROPERTY_VALUE_MAX]; - property_get("ro.kernel.qemu", prop, "0"); - if (atoi(prop) != 1) return; - - property_get("ro.kernel.qemu.gles",prop,"0"); - if (atoi(prop) == 1) { - ALOGD("Emulator has host GPU support, qemu.gles is set to 1."); - property_set("qemu.gles", "1"); - return; - } - - // for now, checking the following - // directory is good enough for emulator system images - const char* vendor_lib_path = -#if defined(__LP64__) - "/vendor/lib64/egl"; -#else - "/vendor/lib/egl"; -#endif - - const bool has_vendor_lib = (access(vendor_lib_path, R_OK) == 0); - if (has_vendor_lib) { - ALOGD("Emulator has vendor provided software renderer, qemu.gles is set to 2."); - property_set("qemu.gles", "2"); - } else { - ALOGD("Emulator without GPU support detected. " - "Fallback to legacy software renderer, qemu.gles is set to 0."); - property_set("qemu.gles", "0"); - } -} - static const char* DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl"; static const char* HAL_SUBNAME_KEY_PROPERTIES[2] = { @@ -260,8 +228,6 @@ void* Loader::open(egl_connection_t* cnx) return cnx->dso; } - setEmulatorGlesValue(); - // Check if we should use ANGLE early, so loading each driver doesn't require repeated queries. if (android::GraphicsEnv::getInstance().shouldUseAngle()) { cnx->shouldUseAngle = true; -- GitLab From b856aff7430b57f5d32436ecb4e4d232d37723ed Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Thu, 22 Aug 2019 17:39:17 -0700 Subject: [PATCH 0182/1255] Remove mention of legacy software renderer Change-Id: Icf88aded420aa1c521f6fa30a9450429578d25a8 --- opengl/libs/EGL/Loader.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index ff91058f04..e1432608c9 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -51,12 +51,6 @@ namespace android { * /vendor/lib/egl/libGLESv1_CM.so * /vendor/lib/egl/libGLESv2.so * - * The software renderer for the emulator must be provided as a single - * library at: - * - * /system/lib/egl/libGLES_android.so - * - * * For backward compatibility and to facilitate the transition to * this new naming scheme, the loader will additionally look for: * -- GitLab From 194e1069a4bf40e670db59741d0fe38fcc384071 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 19 Aug 2019 14:42:56 +0900 Subject: [PATCH 0183/1255] Add a filegroup for AIDL files in frameworks/native/aidl The AIDL files under frameworks/native/aidl have been referenced via their absolute paths. This required any module that has an AIDL file depending on the AIDL types in the frameworks directory to explicitly set the include path. Fixing the problem by abstracting the AIDL files using filegroup where the path property is set to the base directory for the files. The base directory is used as include paths when the filegroup is added to srcs. Bug: 135922046 Test: m Change-Id: Ie416e49734e6e50c1e3fa41d5db6d32a662e0855 --- Android.bp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Android.bp b/Android.bp index de9ea86f1d..bf4cf5daf8 100644 --- a/Android.bp +++ b/Android.bp @@ -20,3 +20,25 @@ cc_library_headers { vendor: true, export_include_dirs: ["include_sensor"], } + +filegroup { + name: "framework_native_aidl_binder", + srcs: ["aidl/binder/**/*.aidl"], + path: "aidl/binder", + visibility: ["//frameworks/native"], +} + +filegroup { + name: "framework_native_aidl_gui", + srcs: ["aidl/gui/**/*.aidl"], + path: "aidl/gui", + visibility: ["//frameworks/native"], +} + +filegroup { + name: "framework_native_aidl", + srcs: [ + ":framework_native_aidl_binder", + ":framework_native_aidl_gui", + ], +} -- GitLab From 2c9a3341977e315ffb8e78cac2343a2682e71dc3 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Tue, 23 Jul 2019 14:18:59 +0800 Subject: [PATCH 0184/1255] Add associated function to physical keyboard The function keys (HOME/BACK/DPAD...) may not always be virtual keys, so we need provide a static input mapping mechanism to the physical keyboard to make sure key events can dispatch to the corresponding display. - Find the associated viewport for keyboard when display info changed and has an associated display port specified. - Should disable the input device when an associated port specified but no display viewport found. - Changed getAssociatedDisplay -> getAssociatedDisplayId. - Add test cases to test input device and keyboard associated mapping. Bug: 137693244 Test: atest -a libinput_tests inputflinger_tests Change-Id: If218f55645a78a4b50cec92b35b0dbae641dd1a1 --- services/inputflinger/InputReader.cpp | 86 +++++-- services/inputflinger/InputReader.h | 22 +- .../inputflinger/tests/InputReader_test.cpp | 216 ++++++++++++++---- 3 files changed, 258 insertions(+), 66 deletions(-) diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index 4631becee8..1cbf78eb43 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -819,14 +819,19 @@ bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) { } InputDevice* device = mDevices.valueAt(deviceIndex); - std::optional associatedDisplayId = device->getAssociatedDisplay(); + if (!device->isEnabled()) { + ALOGW("Ignoring disabled device %s", device->getName().c_str()); + return false; + } + + std::optional associatedDisplayId = device->getAssociatedDisplayId(); // No associated display. By default, can dispatch to all displays. if (!associatedDisplayId) { return true; } if (*associatedDisplayId == ADISPLAY_ID_NONE) { - ALOGW("Device has associated, but no associated display id."); + ALOGW("Device %s is associated with display ADISPLAY_ID_NONE.", device->getName().c_str()); return true; } @@ -1002,6 +1007,13 @@ bool InputDevice::isEnabled() { } void InputDevice::setEnabled(bool enabled, nsecs_t when) { + if (enabled && mAssociatedDisplayPort && !mAssociatedViewport) { + ALOGW("Cannot enable input device %s because it is associated with port %" PRIu8 ", " + "but the corresponding viewport is not found", + getName().c_str(), *mAssociatedDisplayPort); + enabled = false; + } + if (isEnabled() == enabled) { return; } @@ -1103,6 +1115,7 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { // In most situations, no port will be specified. mAssociatedDisplayPort = std::nullopt; + mAssociatedViewport = std::nullopt; // Find the display port that corresponds to the current input port. const std::string& inputPort = mIdentifier.location; if (!inputPort.empty()) { @@ -1112,6 +1125,23 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config mAssociatedDisplayPort = std::make_optional(displayPort->second); } } + + // If the device was explicitly disabled by the user, it would be present in the + // "disabledDevices" list. If it is associated with a specific display, and it was not + // explicitly disabled, then enable/disable the device based on whether we can find the + // corresponding viewport. + bool enabled = (config->disabledDevices.find(mId) == config->disabledDevices.end()); + if (mAssociatedDisplayPort) { + mAssociatedViewport = config->getDisplayViewportByPort(*mAssociatedDisplayPort); + if (!mAssociatedViewport) { + ALOGW("Input device %s should be associated with display on port %" PRIu8 ", " + "but the corresponding viewport is not found.", + getName().c_str(), *mAssociatedDisplayPort); + enabled = false; + } + } + + setEnabled(enabled, when); } for (InputMapper* mapper : mMappers) { @@ -1276,9 +1306,15 @@ void InputDevice::notifyReset(nsecs_t when) { mContext->getListener()->notifyDeviceReset(&args); } -std::optional InputDevice::getAssociatedDisplay() { +std::optional InputDevice::getAssociatedDisplayId() { + // Check if we had associated to the specific display. + if (mAssociatedViewport) { + return mAssociatedViewport->displayId; + } + + // No associated display port, check if some InputMapper is associated. for (InputMapper* mapper : mMappers) { - std::optional associatedDisplayId = mapper->getAssociatedDisplay(); + std::optional associatedDisplayId = mapper->getAssociatedDisplayId(); if (associatedDisplayId) { return associatedDisplayId; } @@ -2229,6 +2265,22 @@ void KeyboardInputMapper::dump(std::string& dump) { dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime); } +std::optional KeyboardInputMapper::findViewport( + nsecs_t when, const InputReaderConfiguration* config) { + const std::optional displayPort = mDevice->getAssociatedDisplayPort(); + if (displayPort) { + // Find the viewport that contains the same port + return mDevice->getAssociatedViewport(); + } + + // No associated display defined, try to find default display if orientationAware. + if (mParameters.orientationAware) { + return config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); + } + + return std::nullopt; +} + void KeyboardInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { InputMapper::configure(when, config, changes); @@ -2239,9 +2291,7 @@ void KeyboardInputMapper::configure(nsecs_t when, } if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - if (mParameters.orientationAware) { - mViewport = config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); - } + mViewport = findViewport(when, config); } } @@ -2521,6 +2571,12 @@ void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, } } +std::optional KeyboardInputMapper::getAssociatedDisplayId() { + if (mViewport) { + return std::make_optional(mViewport->displayId); + } + return std::nullopt; +} // --- CursorInputMapper --- @@ -2935,7 +2991,7 @@ void CursorInputMapper::fadePointer() { } } -std::optional CursorInputMapper::getAssociatedDisplay() { +std::optional CursorInputMapper::getAssociatedDisplayId() { if (mParameters.hasAssociatedDisplay) { if (mParameters.mode == Parameters::MODE_POINTER) { return std::make_optional(mPointerController->getDisplayId()); @@ -3467,15 +3523,10 @@ std::optional TouchInputMapper::findViewport() { const std::optional displayPort = mDevice->getAssociatedDisplayPort(); if (displayPort) { // Find the viewport that contains the same port - std::optional v = mConfig.getDisplayViewportByPort(*displayPort); - if (!v) { - ALOGW("Input device %s should be associated with display on port %" PRIu8 ", " - "but the corresponding viewport is not found.", - getDeviceName().c_str(), *displayPort); - } - return v; + return mDevice->getAssociatedViewport(); } + // Check if uniqueDisplayId is specified in idc file. if (!mParameters.uniqueDisplayId.empty()) { return mConfig.getDisplayViewportByUniqueId(mParameters.uniqueDisplayId); } @@ -3499,6 +3550,7 @@ std::optional TouchInputMapper::findViewport() { return viewport; } + // No associated display, return a non-display viewport. DisplayViewport newViewport; // Raw width and height in the natural orientation. int32_t rawWidth = mRawPointerAxes.getRawWidth(); @@ -6508,7 +6560,7 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32 if (mDeviceMode == DEVICE_MODE_POINTER) { mPointerController->getPosition(&xCursorPosition, &yCursorPosition); } - const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE); + const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE); const int32_t deviceId = getDeviceId(); std::vector frames = mDevice->getEventHub()->getVideoFrames(deviceId); std::for_each(frames.begin(), frames.end(), @@ -6817,7 +6869,7 @@ bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCode return true; } -std::optional TouchInputMapper::getAssociatedDisplay() { +std::optional TouchInputMapper::getAssociatedDisplayId() { if (mParameters.hasAssociatedDisplay) { if (mDeviceMode == DEVICE_MODE_POINTER) { return std::make_optional(mPointerController->getDisplayId()); diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index b7f94c18f3..0666ca54bf 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -265,7 +265,9 @@ public: inline std::optional getAssociatedDisplayPort() const { return mAssociatedDisplayPort; } - + inline std::optional getAssociatedViewport() const { + return mAssociatedViewport; + } inline void setMic(bool hasMic) { mHasMic = hasMic; } inline bool hasMic() const { return mHasMic; } @@ -324,7 +326,8 @@ public: return value; } - std::optional getAssociatedDisplay(); + std::optional getAssociatedDisplayId(); + private: InputReaderContext* mContext; int32_t mId; @@ -339,6 +342,7 @@ private: uint32_t mSources; bool mIsExternal; std::optional mAssociatedDisplayPort; + std::optional mAssociatedViewport; bool mHasMic; bool mDropUntilNextSync; @@ -718,9 +722,8 @@ public: virtual void updateExternalStylusState(const StylusState& state); virtual void fadePointer(); - virtual std::optional getAssociatedDisplay() { - return std::nullopt; - } + virtual std::optional getAssociatedDisplayId() { return std::nullopt; } + protected: InputDevice* mDevice; InputReaderContext* mContext; @@ -802,6 +805,7 @@ public: virtual int32_t getMetaState(); virtual void updateMetaState(int32_t keyCode); + virtual std::optional getAssociatedDisplayId(); private: // The current viewport. @@ -855,6 +859,8 @@ private: void updateLedState(bool reset); void updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset); + std::optional findViewport(nsecs_t when, + const InputReaderConfiguration* config); }; @@ -874,7 +880,8 @@ public: virtual void fadePointer(); - virtual std::optional getAssociatedDisplay(); + virtual std::optional getAssociatedDisplayId(); + private: // Amount that trackball needs to move in order to generate a key event. static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6; @@ -968,7 +975,8 @@ public: virtual void cancelTouch(nsecs_t when); virtual void timeoutExpired(nsecs_t when); virtual void updateExternalStylusState(const StylusState& state); - virtual std::optional getAssociatedDisplay(); + virtual std::optional getAssociatedDisplayId(); + protected: CursorButtonAccumulator mCursorButtonAccumulator; CursorScrollAccumulator mCursorScrollAccumulator; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index d95ac96124..348a12bf3a 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1556,10 +1556,14 @@ TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO); mReader->loopOnce(); - // Check device. + // Device should only dispatch to the specified display. ASSERT_EQ(deviceId, device->getId()); ASSERT_FALSE(mReader->canDispatchToDisplay(deviceId, DISPLAY_ID)); ASSERT_TRUE(mReader->canDispatchToDisplay(deviceId, SECONDARY_DISPLAY_ID)); + + // Can't dispatch event from a disabled device. + disableDevice(deviceId, device); + ASSERT_FALSE(mReader->canDispatchToDisplay(deviceId, SECONDARY_DISPLAY_ID)); } @@ -1568,6 +1572,7 @@ TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { class InputDeviceTest : public testing::Test { protected: static const char* DEVICE_NAME; + static const char* DEVICE_LOCATION; static const int32_t DEVICE_ID; static const int32_t DEVICE_GENERATION; static const int32_t DEVICE_CONTROLLER_NUMBER; @@ -1589,6 +1594,7 @@ protected: mFakeEventHub->addDevice(DEVICE_ID, DEVICE_NAME, 0); InputDeviceIdentifier identifier; identifier.name = DEVICE_NAME; + identifier.location = DEVICE_LOCATION; mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION, DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); } @@ -1603,6 +1609,7 @@ protected: }; const char* InputDeviceTest::DEVICE_NAME = "device"; +const char* InputDeviceTest::DEVICE_LOCATION = "USB1"; const int32_t InputDeviceTest::DEVICE_ID = 1; const int32_t InputDeviceTest::DEVICE_GENERATION = 2; const int32_t InputDeviceTest::DEVICE_CONTROLLER_NUMBER = 0; @@ -1755,6 +1762,49 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled()); } +// A single input device is associated with a specific display. Check that: +// 1. Device is disabled if the viewport corresponding to the associated display is not found +// 2. Device is disabled when setEnabled API is called +TEST_F(InputDeviceTest, Configure_AssignsDisplayPort) { + FakeInputMapper* mapper = new FakeInputMapper(mDevice, AINPUT_SOURCE_TOUCHSCREEN); + mDevice->addMapper(mapper); + + // First Configuration. + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0); + + // Device should be enabled by default. + ASSERT_TRUE(mDevice->isEnabled()); + + // Prepare associated info. + constexpr uint8_t hdmi = 1; + const std::string UNIQUE_ID = "local:1"; + + mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi); + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), + InputReaderConfiguration::CHANGE_DISPLAY_INFO); + // Device should be disabled because it is associated with a specific display via + // input port <-> display port association, but the corresponding display is not found + ASSERT_FALSE(mDevice->isEnabled()); + + // Prepare displays. + mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, + DISPLAY_ORIENTATION_0, UNIQUE_ID, hdmi, + ViewportType::VIEWPORT_INTERNAL); + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), + InputReaderConfiguration::CHANGE_DISPLAY_INFO); + ASSERT_TRUE(mDevice->isEnabled()); + + // Device should be disabled after set disable. + mFakePolicy->addDisabledDevice(mDevice->getId()); + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), + InputReaderConfiguration::CHANGE_ENABLED_STATE); + ASSERT_FALSE(mDevice->isEnabled()); + + // Device should still be disabled even found the associated display. + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), + InputReaderConfiguration::CHANGE_DISPLAY_INFO); + ASSERT_FALSE(mDevice->isEnabled()); +} // --- InputMapperTest --- @@ -1926,8 +1976,9 @@ protected: void prepareDisplay(int32_t orientation); - void testDPadKeyRotation(KeyboardInputMapper* mapper, - int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode); + void testDPadKeyRotation(KeyboardInputMapper* mapper, int32_t originalScanCode, + int32_t originalKeyCode, int32_t rotatedKeyCode, + int32_t displayId = ADISPLAY_ID_NONE); }; /* Similar to setDisplayInfoAndReconfigure, but pre-populates all parameters except for the @@ -1939,7 +1990,8 @@ void KeyboardInputMapperTest::prepareDisplay(int32_t orientation) { } void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper, - int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode) { + int32_t originalScanCode, int32_t originalKeyCode, + int32_t rotatedKeyCode, int32_t displayId) { NotifyKeyArgs args; process(mapper, ARBITRARY_TIME, EV_KEY, originalScanCode, 1); @@ -1947,15 +1999,16 @@ void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper, ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(originalScanCode, args.scanCode); ASSERT_EQ(rotatedKeyCode, args.keyCode); + ASSERT_EQ(displayId, args.displayId); process(mapper, ARBITRARY_TIME, EV_KEY, originalScanCode, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); ASSERT_EQ(originalScanCode, args.scanCode); ASSERT_EQ(rotatedKeyCode, args.keyCode); + ASSERT_EQ(displayId, args.displayId); } - TEST_F(KeyboardInputMapperTest, GetSources) { KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); @@ -2136,47 +2189,47 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { addMapperAndConfigure(mapper); prepareDisplay(DISPLAY_ORIENTATION_0); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT)); + ASSERT_NO_FATAL_FAILURE( + testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, + AKEYCODE_DPAD_RIGHT, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN, + AKEYCODE_DPAD_DOWN, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, + AKEYCODE_DPAD_LEFT, DISPLAY_ID)); clearViewports(); prepareDisplay(DISPLAY_ORIENTATION_90); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN)); + ASSERT_NO_FATAL_FAILURE( + testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, + AKEYCODE_DPAD_UP, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN, + AKEYCODE_DPAD_RIGHT, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, + AKEYCODE_DPAD_DOWN, DISPLAY_ID)); clearViewports(); prepareDisplay(DISPLAY_ORIENTATION_180); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_LEFT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_UP)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_RIGHT)); + ASSERT_NO_FATAL_FAILURE( + testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, + AKEYCODE_DPAD_LEFT, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN, + AKEYCODE_DPAD_UP, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, + AKEYCODE_DPAD_RIGHT, DISPLAY_ID)); clearViewports(); prepareDisplay(DISPLAY_ORIENTATION_270); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_DOWN)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_LEFT)); - ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, - KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_UP)); + ASSERT_NO_FATAL_FAILURE( + testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, + AKEYCODE_DPAD_DOWN, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN, + AKEYCODE_DPAD_LEFT, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, + AKEYCODE_DPAD_UP, DISPLAY_ID)); // Special case: if orientation changes while key is down, we still emit the same keycode // in the key up as we did in the key down. @@ -2360,6 +2413,84 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); } +TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) { + // keyboard 1. + mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); + mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); + mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); + mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); + + // keyboard 2. + const std::string USB2 = "USB2"; + constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1; + InputDeviceIdentifier identifier; + identifier.name = "KEYBOARD2"; + identifier.location = USB2; + std::unique_ptr device2 = + std::make_unique(mFakeContext, SECOND_DEVICE_ID, DEVICE_GENERATION, + DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); + mFakeEventHub->addDevice(SECOND_DEVICE_ID, DEVICE_NAME, 0 /*classes*/); + mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); + mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); + mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); + mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); + + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); + addMapperAndConfigure(mapper); + + KeyboardInputMapper* mapper2 = new KeyboardInputMapper(device2.get(), AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); + device2->addMapper(mapper2); + device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/); + device2->reset(ARBITRARY_TIME); + + // Prepared displays and associated info. + constexpr uint8_t hdmi1 = 0; + constexpr uint8_t hdmi2 = 1; + const std::string SECONDARY_UNIQUE_ID = "local:1"; + + mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi1); + mFakePolicy->addInputPortAssociation(USB2, hdmi2); + + // No associated display viewport found, should disable the device. + device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), + InputReaderConfiguration::CHANGE_DISPLAY_INFO); + ASSERT_FALSE(device2->isEnabled()); + + // Prepare second display. + constexpr int32_t newDisplayId = 2; + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0, + UNIQUE_ID, hdmi1, ViewportType::VIEWPORT_INTERNAL); + setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0, + SECONDARY_UNIQUE_ID, hdmi2, ViewportType::VIEWPORT_EXTERNAL); + // Default device will reconfigure above, need additional reconfiguration for another device. + device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), + InputReaderConfiguration::CHANGE_DISPLAY_INFO); + + // Device should be enabled after the associated display is found. + ASSERT_TRUE(mDevice->isEnabled()); + ASSERT_TRUE(device2->isEnabled()); + + // Test pad key events + ASSERT_NO_FATAL_FAILURE( + testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, + AKEYCODE_DPAD_RIGHT, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN, + AKEYCODE_DPAD_DOWN, DISPLAY_ID)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, + AKEYCODE_DPAD_LEFT, DISPLAY_ID)); + + ASSERT_NO_FATAL_FAILURE( + testDPadKeyRotation(mapper2, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, newDisplayId)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, + AKEYCODE_DPAD_RIGHT, newDisplayId)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_DOWN, AKEYCODE_DPAD_DOWN, + AKEYCODE_DPAD_DOWN, newDisplayId)); + ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_LEFT, AKEYCODE_DPAD_LEFT, + AKEYCODE_DPAD_LEFT, newDisplayId)); +} // --- CursorInputMapperTest --- @@ -6276,12 +6407,13 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) { // Create the second touch screen device, and enable multi fingers. const std::string USB2 = "USB2"; - const int32_t SECOND_DEVICE_ID = 2; + constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1; InputDeviceIdentifier identifier; - identifier.name = DEVICE_NAME; + identifier.name = "TOUCHSCREEN2"; identifier.location = USB2; - InputDevice* device2 = new InputDevice(mFakeContext, SECOND_DEVICE_ID, DEVICE_GENERATION, - DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); + std::unique_ptr device2 = + std::make_unique(mFakeContext, SECOND_DEVICE_ID, DEVICE_GENERATION, + DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); mFakeEventHub->addDevice(SECOND_DEVICE_ID, DEVICE_NAME, 0 /*classes*/); mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0 /*flat*/, 0 /*fuzz*/); @@ -6296,7 +6428,7 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) { String8("touchScreen")); // Setup the second touch screen device. - MultiTouchInputMapper* mapper2 = new MultiTouchInputMapper(device2); + MultiTouchInputMapper* mapper2 = new MultiTouchInputMapper(device2.get()); device2->addMapper(mapper2); device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/); device2->reset(ARBITRARY_TIME); -- GitLab From 2b0cd8de19458f8c753d403a2b27807be1f9f027 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Mon, 26 Aug 2019 10:30:52 -0700 Subject: [PATCH 0185/1255] Make Transaction inherit Parcelable at public level Bug: 139439952 Test: build, boot, SurfaceFlinger_test Change-Id: Ib0796def398cbeb295d6cd95b8422ab66bb0b2c5 --- libs/gui/include/gui/SurfaceComposerClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index f303a03254..64ee65f623 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -290,7 +290,7 @@ public: std::unordered_set, SCHash> surfaceControls; }; - class Transaction : Parcelable { + class Transaction : public Parcelable { std::unordered_map, ComposerState, IBinderHash> mComposerStates; SortedVector mDisplayStates; std::unordered_map, CallbackInfo, TCLHash> -- GitLab From f83570cba98776df78b473b4e6bdaa709215b1ed Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Mon, 26 Aug 2019 12:04:07 -0700 Subject: [PATCH 0186/1255] SF: Fix threshold for next VSYNC If debug.sf.phase_offset_threshold_for_next_vsync_ns is not set, the threshold is set to the maximum nsecs_t value. A narrowing conversion caused the value to overflow to -1, leading to garbage phase offsets. Bug: 138813900 Bug: 139284671 Bug: 138942712 Test: dumpsys SurfaceFlinger --vsync Test: atest google/perf/app-transition/app-transition-cold Change-Id: Ib7f732be95d16d29f4a71602b56795bee09be37b --- services/surfaceflinger/Scheduler/PhaseOffsets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 9f8567d0ec..1614ddcc39 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -24,7 +24,7 @@ namespace { -std::optional getProperty(const char* name) { +std::optional getProperty(const char* name) { char value[PROPERTY_VALUE_MAX]; property_get(name, value, "-1"); if (const int i = atoi(value); i != -1) return i; -- GitLab From 0b79f8c2f2676fdf8cdef201032c8d24712d95a5 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Mon, 26 Aug 2019 17:01:33 -0700 Subject: [PATCH 0187/1255] Set crop size on rounded corner test Rounded corners require an explicit layer boundary definition. Fixes: 137875576 Test: adb shell /data/nativetest/SurfaceFlinger_test/SurfaceFlinger_test --gtest_filter=LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius Change-Id: I5efc3ebb0f177c1fd107685cc485bfb0b1aec2f0 --- services/surfaceflinger/tests/Transaction_test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index b1fde22e0e..75bfa4d3b9 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -1595,6 +1595,7 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) { Transaction() .setCornerRadius(layer, cornerRadius) + .setCrop_legacy(layer, Rect(0, 0, size, size)) .apply(); { const uint8_t bottom = size - 1; @@ -1621,6 +1622,7 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) { Transaction() .setCornerRadius(parent, cornerRadius) + .setCrop_legacy(parent, Rect(0, 0, size, size)) .reparent(child, parent->getHandle()) .setPosition(child, 0, size / 2) .apply(); -- GitLab From 86f9f749cc5bc1dc75ee26c3a9618d882eabe096 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Tue, 27 Aug 2019 00:27:29 -0700 Subject: [PATCH 0188/1255] opengl: fix a race condition when unloading gl driver Previously, EGL apis call clearError() at the first place including those core apis which initialize the driver. Calling clearError() before the driver has been loaded is basically a no-op. Later the driver unloading mechanism was added to support Angle and updatable driver with EGL/GL driver still preloaded in Zygote. However, calling clearError() on another thread races with the driver unloading process. So this change moves the clearError() calls after the driver has been successfully unloaded and reloaded, so that the initial core apis will be protected by the driver loading lock in the loader. For those non-core apis, they could still be incorrectly called before calling any of those core apis on another thread when the driver unloading and reloading is still on going. Since this scenario is supposed to error out anyway, so the apps need to use EGL apis correctly by themselves. Bug: 140072978 Test: CtsAngleDeveloperOptionHostTest Change-Id: Ica5b19edc0dfb0a0910f56c1442eaff63f76b35a --- opengl/libs/EGL/eglApi.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 29a966d348..c51a1295e7 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -40,7 +40,6 @@ static inline void clearError() { EGLDisplay eglGetDisplay(EGLNativeDisplayType display) { ATRACE_CALL(); - clearError(); if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); @@ -48,6 +47,7 @@ EGLDisplay eglGetDisplay(EGLNativeDisplayType display) { // Call down the chain, which usually points directly to the impl // but may also be routed through layers + clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglGetDisplay(display); } @@ -55,7 +55,6 @@ EGLDisplay eglGetDisplay(EGLNativeDisplayType display) { EGLDisplay eglGetPlatformDisplay(EGLenum platform, EGLNativeDisplayType display, const EGLAttrib* attrib_list) { ATRACE_CALL(); - clearError(); if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); @@ -63,6 +62,7 @@ EGLDisplay eglGetPlatformDisplay(EGLenum platform, EGLNativeDisplayType display, // Call down the chain, which usually points directly to the impl // but may also be routed through layers + clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglGetPlatformDisplay(platform, display, attrib_list); } @@ -239,13 +239,12 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char* procname) // in which case we must make sure we've initialized ourselves, this // happens the first time egl_get_display() is called. - clearError(); - if (egl_init_drivers() == EGL_FALSE) { setError(EGL_BAD_PARAMETER, NULL); return nullptr; } + clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglGetProcAddress(procname); } @@ -324,23 +323,21 @@ EGLBoolean eglWaitClient(void) { } EGLBoolean eglBindAPI(EGLenum api) { - clearError(); - if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); } + clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglBindAPI(api); } EGLenum eglQueryAPI(void) { - clearError(); - if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); } + clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglQueryAPI(); } @@ -595,23 +592,21 @@ EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer* buffer) { } EGLuint64NV eglGetSystemTimeFrequencyNV() { - clearError(); - if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); } + clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglGetSystemTimeFrequencyNV(); } EGLuint64NV eglGetSystemTimeNV() { - clearError(); - if (egl_init_drivers() == EGL_FALSE) { return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); } + clearError(); egl_connection_t* const cnx = &gEGLImpl; return cnx->platform.eglGetSystemTimeNV(); } -- GitLab From 9b586699b2d9b379cbb8385ad55fe37ebb25fe1e Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 4 Jun 2019 16:04:04 -0700 Subject: [PATCH 0189/1255] SurfaceFlinger: add explicit register for DISPLAY_EVENT_CONFIG_CHANGED When display refresh rate changes, SF fires DISPLAY_EVENT_CONFIG_CHANGED thru DisplayEventReceiver. If the other end of the pipe doesn't consume the events it may lead to pipe full and dropping of events. Furthermore, The only clients interested in this event in DisplayManager and hwui. To avoid spamming all clients with this event, this change is adding an explicit register for DISPLAY_EVENT_CONFIG_CHANGED events. Bug: 131688378 Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Test: trigger config change and observe logcat Change-Id: I5973a1ecc1f3e3ff8d8a0cba19db0e49ef0d5341 (cherry picked from commit 0f4a1b19009a1e71ed2100b63b04aa015a111b44) --- libs/gui/DisplayEventReceiver.cpp | 5 ++- libs/gui/ISurfaceComposer.cpp | 12 +++-- libs/gui/include/gui/DisplayEventReceiver.h | 5 ++- libs/gui/include/gui/ISurfaceComposer.h | 5 ++- libs/gui/tests/Surface_test.cpp | 4 +- .../surfaceflinger/Scheduler/EventThread.cpp | 18 ++++++-- .../surfaceflinger/Scheduler/EventThread.h | 10 +++-- .../surfaceflinger/Scheduler/MessageQueue.cpp | 3 +- .../surfaceflinger/Scheduler/Scheduler.cpp | 15 ++++--- services/surfaceflinger/Scheduler/Scheduler.h | 8 ++-- services/surfaceflinger/SurfaceFlinger.cpp | 5 ++- services/surfaceflinger/SurfaceFlinger.h | 4 +- .../tests/unittests/EventThreadTest.cpp | 44 ++++++++++++++----- .../tests/unittests/SchedulerTest.cpp | 18 +++++--- .../tests/unittests/TestableScheduler.h | 4 +- .../tests/unittests/mock/MockEventThread.h | 3 +- 16 files changed, 116 insertions(+), 47 deletions(-) diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index f5cf1c4d5a..b8faa2df4c 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -32,10 +32,11 @@ namespace android { // --------------------------------------------------------------------------- -DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) { +DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource, + ISurfaceComposer::ConfigChanged configChanged) { sp sf(ComposerService::getComposerService()); if (sf != nullptr) { - mEventConnection = sf->createDisplayEventConnection(vsyncSource); + mEventConnection = sf->createDisplayEventConnection(vsyncSource, configChanged); if (mEventConnection != nullptr) { mDataChannel = std::make_unique(); mEventConnection->stealReceiveChannel(mDataChannel.get()); diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 6c9d81ab57..e487792c87 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -278,8 +278,8 @@ public: return NO_ERROR; } - virtual sp createDisplayEventConnection(VsyncSource vsyncSource) - { + virtual sp createDisplayEventConnection(VsyncSource vsyncSource, + ConfigChanged configChanged) { Parcel data, reply; sp result; int err = data.writeInterfaceToken( @@ -288,6 +288,7 @@ public: return result; } data.writeInt32(static_cast(vsyncSource)); + data.writeInt32(static_cast(configChanged)); err = remote()->transact( BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION, data, &reply); @@ -1155,8 +1156,11 @@ status_t BnSurfaceComposer::onTransact( } case CREATE_DISPLAY_EVENT_CONNECTION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp connection(createDisplayEventConnection( - static_cast(data.readInt32()))); + auto vsyncSource = static_cast(data.readInt32()); + auto configChanged = static_cast(data.readInt32()); + + sp connection( + createDisplayEventConnection(vsyncSource, configChanged)); reply->writeStrongBinder(IInterface::asBinder(connection)); return NO_ERROR; } diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 22de751498..a558cf9e18 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -88,10 +88,13 @@ public: * DisplayEventReceiver creates and registers an event connection with * SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate * or requestNextVsync to receive them. + * To receive Config Changed events specify this in the constructor. * Other events start being delivered immediately. */ explicit DisplayEventReceiver( - ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp); + ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp, + ISurfaceComposer::ConfigChanged configChanged = + ISurfaceComposer::eConfigChangedSuppress); /* * ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index e2f77365b3..c84910b6ec 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -90,6 +90,8 @@ public: eVsyncSourceSurfaceFlinger = 1 }; + enum ConfigChanged { eConfigChangedSuppress = 0, eConfigChangedDispatch = 1 }; + /* * Create a connection with SurfaceFlinger. */ @@ -97,7 +99,8 @@ public: /* return an IDisplayEventConnection */ virtual sp createDisplayEventConnection( - VsyncSource vsyncSource = eVsyncSourceApp) = 0; + VsyncSource vsyncSource = eVsyncSourceApp, + ConfigChanged configChanged = eConfigChangedSuppress) = 0; /* create a virtual display * requires ACCESS_SURFACE_FLINGER permission. diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 960cf1846e..d3708586f5 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -548,8 +548,8 @@ public: } sp createConnection() override { return nullptr; } - sp createDisplayEventConnection(ISurfaceComposer::VsyncSource) - override { + sp createDisplayEventConnection( + ISurfaceComposer::VsyncSource, ISurfaceComposer::ConfigChanged) override { return nullptr; } sp createDisplay(const String8& /*displayName*/, diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 05bad4ddd8..9d1f777859 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -76,6 +76,10 @@ std::string toString(const DisplayEventReceiver::Event& event) { return StringPrintf("VSync{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%u}", event.header.displayId, event.vsync.count); + case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: + return StringPrintf("ConfigChanged{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT + ", configId=%u}", + event.header.displayId, event.config.configId); default: return "Event{}"; } @@ -107,8 +111,10 @@ DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId, int32 } // namespace EventThreadConnection::EventThreadConnection(EventThread* eventThread, - ResyncCallback resyncCallback) + ResyncCallback resyncCallback, + ISurfaceComposer::ConfigChanged configChanged) : resyncCallback(std::move(resyncCallback)), + configChanged(configChanged), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {} @@ -203,8 +209,10 @@ void EventThread::setPhaseOffset(nsecs_t phaseOffset) { mVSyncSource->setPhaseOffset(phaseOffset); } -sp EventThread::createEventConnection(ResyncCallback resyncCallback) const { - return new EventThreadConnection(const_cast(this), std::move(resyncCallback)); +sp EventThread::createEventConnection( + ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged) const { + return new EventThreadConnection(const_cast(this), std::move(resyncCallback), + configChanged); } status_t EventThread::registerDisplayEventConnection(const sp& connection) { @@ -398,9 +406,11 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, const sp& connection) const { switch (event.header.type) { case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: - case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: return true; + case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: + return connection->configChanged == ISurfaceComposer::eConfigChangedDispatch; + case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: switch (connection->vsyncRequest) { case VSyncRequest::None: diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 61530c62e5..dd23b88726 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -69,7 +69,8 @@ public: class EventThreadConnection : public BnDisplayEventConnection { public: - EventThreadConnection(EventThread*, ResyncCallback); + EventThreadConnection(EventThread*, ResyncCallback, + ISurfaceComposer::ConfigChanged configChanged); virtual ~EventThreadConnection(); virtual status_t postEvent(const DisplayEventReceiver::Event& event); @@ -82,6 +83,7 @@ public: const ResyncCallback resyncCallback; VSyncRequest vsyncRequest = VSyncRequest::None; + const ISurfaceComposer::ConfigChanged configChanged; private: virtual void onFirstRef(); @@ -93,7 +95,8 @@ class EventThread { public: virtual ~EventThread(); - virtual sp createEventConnection(ResyncCallback) const = 0; + virtual sp createEventConnection( + ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const = 0; // called before the screen is turned off from main thread virtual void onScreenReleased() = 0; @@ -128,7 +131,8 @@ public: EventThread(std::unique_ptr, InterceptVSyncsCallback, const char* threadName); ~EventThread(); - sp createEventConnection(ResyncCallback) const override; + sp createEventConnection( + ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const override; status_t registerDisplayEventConnection(const sp& connection) override; void setVsyncRate(uint32_t rate, const sp& connection) override; diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index baf900df52..fcb307f213 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -96,7 +96,8 @@ void MessageQueue::setEventThread(android::EventThread* eventThread, } mEventThread = eventThread; - mEvents = eventThread->createEventConnection(std::move(resyncCallback)); + mEvents = eventThread->createEventConnection(std::move(resyncCallback), + ISurfaceComposer::eConfigChangedSuppress); mEvents->stealReceiveChannel(&mEventTube); mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver, this); diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 513436a270..7a040aa305 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -129,7 +129,8 @@ sp Scheduler::createConnection( std::move(interceptCallback)); auto eventThreadConnection = - createConnectionInternal(eventThread.get(), std::move(resyncCallback)); + createConnectionInternal(eventThread.get(), std::move(resyncCallback), + ISurfaceComposer::eConfigChangedSuppress); mConnections.emplace(id, std::make_unique(new ConnectionHandle(id), eventThreadConnection, @@ -146,16 +147,18 @@ std::unique_ptr Scheduler::makeEventThread( std::move(interceptCallback), connectionName); } -sp Scheduler::createConnectionInternal(EventThread* eventThread, - ResyncCallback&& resyncCallback) { - return eventThread->createEventConnection(std::move(resyncCallback)); +sp Scheduler::createConnectionInternal( + EventThread* eventThread, ResyncCallback&& resyncCallback, + ISurfaceComposer::ConfigChanged configChanged) { + return eventThread->createEventConnection(std::move(resyncCallback), configChanged); } sp Scheduler::createDisplayEventConnection( - const sp& handle, ResyncCallback resyncCallback) { + const sp& handle, ResyncCallback resyncCallback, + ISurfaceComposer::ConfigChanged configChanged) { RETURN_VALUE_IF_INVALID(nullptr); return createConnectionInternal(mConnections[handle->id]->thread.get(), - std::move(resyncCallback)); + std::move(resyncCallback), configChanged); } EventThread* Scheduler::getEventThread(const sp& handle) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 96d4bd5214..f5a3a0891d 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -100,8 +100,9 @@ public: ResyncCallback, impl::EventThread::InterceptVSyncsCallback); - sp createDisplayEventConnection(const sp& handle, - ResyncCallback); + sp createDisplayEventConnection( + const sp& handle, ResyncCallback, + ISurfaceComposer::ConfigChanged configChanged); // Getter methods. EventThread* getEventThread(const sp& handle); @@ -192,7 +193,8 @@ private: enum class TouchState { INACTIVE, ACTIVE }; // Creates a connection on the given EventThread and forwards the given callbacks. - sp createConnectionInternal(EventThread*, ResyncCallback&&); + sp createConnectionInternal(EventThread*, ResyncCallback&&, + ISurfaceComposer::ConfigChanged); nsecs_t calculateAverage() const; void updateFrameSkipping(const int64_t skipCount); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6166789fc4..0cf84a952d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1371,7 +1371,7 @@ status_t SurfaceFlinger::notifyPowerHint(int32_t hintId) { // ---------------------------------------------------------------------------- sp SurfaceFlinger::createDisplayEventConnection( - ISurfaceComposer::VsyncSource vsyncSource) { + ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) { auto resyncCallback = mScheduler->makeResyncCallback([this] { Mutex::Autolock lock(mStateLock); return getVsyncPeriod(); @@ -1380,7 +1380,8 @@ sp SurfaceFlinger::createDisplayEventConnection( const auto& handle = vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle; - return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback)); + return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback), + configChanged); } // ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 52655944de..40941f2140 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -399,7 +399,9 @@ private: const sp& bufferProducer) const override; status_t getSupportedFrameTimestamps(std::vector* outSupported) const override; sp createDisplayEventConnection( - ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp) override; + ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp, + ISurfaceComposer::ConfigChanged configChanged = + ISurfaceComposer::eConfigChangedSuppress) override; status_t captureScreen(const sp& displayToken, sp* outBuffer, bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat, Rect sourceCrop, diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index ea908a9018..dbd9b84039 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -55,8 +55,9 @@ protected: class MockEventThreadConnection : public EventThreadConnection { public: MockEventThreadConnection(android::impl::EventThread* eventThread, - ResyncCallback&& resyncCallback) - : EventThreadConnection(eventThread, std::move(resyncCallback)) {} + ResyncCallback&& resyncCallback, + ISurfaceComposer::ConfigChanged configChanged) + : EventThreadConnection(eventThread, std::move(resyncCallback), configChanged) {} MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event)); }; @@ -67,7 +68,8 @@ protected: ~EventThreadTest() override; void createThread(); - sp createConnection(ConnectionEventRecorder& recorder); + sp createConnection(ConnectionEventRecorder& recorder, + ISurfaceComposer::ConfigChanged configChanged); void expectVSyncSetEnabledCallReceived(bool expectedState); void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset); @@ -110,7 +112,8 @@ EventThreadTest::EventThreadTest() { .WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable())); createThread(); - mConnection = createConnection(mConnectionEventCallRecorder); + mConnection = createConnection(mConnectionEventCallRecorder, + ISurfaceComposer::eConfigChangedDispatch); // A display must be connected for VSYNC events to be delivered. mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true); @@ -138,9 +141,10 @@ void EventThreadTest::createThread() { } sp EventThreadTest::createConnection( - ConnectionEventRecorder& recorder) { + ConnectionEventRecorder& recorder, ISurfaceComposer::ConfigChanged configChanged) { sp connection = - new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable()); + new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable(), + configChanged); EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable())); return connection; } @@ -267,7 +271,9 @@ TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { // Create a first connection, register it, and request a vsync rate of zero. ConnectionEventRecorder firstConnectionEventRecorder{0}; - sp firstConnection = createConnection(firstConnectionEventRecorder); + sp firstConnection = + createConnection(firstConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(0, firstConnection); // By itself, this should not enable vsync events @@ -277,7 +283,8 @@ TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { // However if there is another connection which wants events at a nonzero rate..... ConnectionEventRecorder secondConnectionEventRecorder{0}; sp secondConnection = - createConnection(secondConnectionEventRecorder); + createConnection(secondConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(1, secondConnection); // EventThread should enable vsync callbacks. @@ -363,7 +370,9 @@ TEST_F(EventThreadTest, connectionsRemovedIfInstanceDestroyed) { TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) { ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY}; - sp errorConnection = createConnection(errorConnectionEventRecorder); + sp errorConnection = + createConnection(errorConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(1, errorConnection); // EventThread should enable vsync callbacks. @@ -387,7 +396,9 @@ TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) { TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) { ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK}; - sp errorConnection = createConnection(errorConnectionEventRecorder); + sp errorConnection = + createConnection(errorConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(1, errorConnection); // EventThread should enable vsync callbacks. @@ -449,5 +460,18 @@ TEST_F(EventThreadTest, postConfigChangedPrimary64bit) { expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7); } +TEST_F(EventThreadTest, suppressConfigChanged) { + ConnectionEventRecorder suppressConnectionEventRecorder{0}; + sp suppressConnection = + createConnection(suppressConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); + + mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 9); + expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9); + + auto args = suppressConnectionEventRecorder.waitForCall(); + ASSERT_FALSE(args.has_value()); +} + } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 1f8b11180b..af5ccbca21 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -25,7 +25,8 @@ protected: class MockEventThreadConnection : public android::EventThreadConnection { public: explicit MockEventThreadConnection(EventThread* eventThread) - : EventThreadConnection(eventThread, ResyncCallback()) {} + : EventThreadConnection(eventThread, ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress) {} ~MockEventThreadConnection() = default; MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel)); @@ -81,7 +82,7 @@ SchedulerTest::SchedulerTest() { // createConnection call to scheduler makes a createEventConnection call to EventThread. Make // sure that call gets executed and returns an EventThread::Connection object. - EXPECT_CALL(*mEventThread, createEventConnection(_)) + EXPECT_CALL(*mEventThread, createEventConnection(_, _)) .WillRepeatedly(Return(mEventThreadConnection)); mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(), @@ -105,7 +106,10 @@ TEST_F(SchedulerTest, testNullPtr) { // exceptions, just gracefully continues. sp returnedValue; ASSERT_NO_FATAL_FAILURE( - returnedValue = mScheduler->createDisplayEventConnection(nullptr, ResyncCallback())); + returnedValue = + mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(), + ISurfaceComposer:: + eConfigChangedSuppress)); EXPECT_TRUE(returnedValue == nullptr); EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr); EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr); @@ -126,7 +130,9 @@ TEST_F(SchedulerTest, invalidConnectionHandle) { sp returnedValue; ASSERT_NO_FATAL_FAILURE( returnedValue = - mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback())); + mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(), + ISurfaceComposer:: + eConfigChangedSuppress)); EXPECT_TRUE(returnedValue == nullptr); EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr); EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr); @@ -155,7 +161,9 @@ TEST_F(SchedulerTest, validConnectionHandle) { sp returnedValue; ASSERT_NO_FATAL_FAILURE( returnedValue = - mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback())); + mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(), + ISurfaceComposer:: + eConfigChangedSuppress)); EXPECT_TRUE(returnedValue != nullptr); ASSERT_EQ(returnedValue, mEventThreadConnection); diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index c3d2b8de4f..cb6980ed1a 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include "Scheduler/EventThread.h" #include "Scheduler/RefreshRateConfigs.h" @@ -34,7 +35,8 @@ public: // Scheduler::Connection. This allows plugging in mock::EventThread. sp addConnection(std::unique_ptr eventThread) { sp eventThreadConnection = - new EventThreadConnection(eventThread.get(), ResyncCallback()); + new EventThreadConnection(eventThread.get(), ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress); const int64_t id = sNextId++; mConnections.emplace(id, std::make_unique(new ConnectionHandle(id), diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 5b5f8e7fab..ed35ebf2b6 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -28,7 +28,8 @@ public: EventThread(); ~EventThread() override; - MOCK_CONST_METHOD1(createEventConnection, sp(ResyncCallback)); + MOCK_CONST_METHOD2(createEventConnection, + sp(ResyncCallback, ISurfaceComposer::ConfigChanged)); MOCK_METHOD0(onScreenReleased, void()); MOCK_METHOD0(onScreenAcquired, void()); MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool)); -- GitLab From 3bf71ab81e1ff56520ce3e8d8eb901e5b360e245 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Tue, 25 Jun 2019 17:25:02 -0700 Subject: [PATCH 0190/1255] Attach color space information when attach and queue buffer. Currently when calling attachAndQueueBuffer, the color space information is lost. This results in color shift if the color space doesn't match the color space of the surface. BUG: b/135002842, b/131928312 Test: boot. Manually verified on P19 Change-Id: I1d77c9994f50d9a2f5cfde96ca805f7142fddfab (cherry picked from commit 0f6a41299aa367762dbbb49e51d6073c4ca4ba8f) --- libs/gui/Surface.cpp | 12 +++++++++++- libs/gui/include/gui/Surface.h | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e6eb327c6f..9fe5de82d1 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1920,7 +1920,8 @@ status_t Surface::getAndFlushRemovedBuffers(std::vector>* out) return OK; } -status_t Surface::attachAndQueueBuffer(Surface* surface, sp buffer) { +status_t Surface::attachAndQueueBufferWithDataspace(Surface* surface, sp buffer, + Dataspace dataspace) { if (buffer == nullptr) { return BAD_VALUE; } @@ -1929,6 +1930,11 @@ status_t Surface::attachAndQueueBuffer(Surface* surface, sp buffe if (err != OK) { return err; } + ui::Dataspace tmpDataspace = surface->getBuffersDataSpace(); + err = surface->setBuffersDataSpace(dataspace); + if (err != OK) { + return err; + } err = surface->attachBuffer(buffer->getNativeBuffer()); if (err != OK) { return err; @@ -1937,6 +1943,10 @@ status_t Surface::attachAndQueueBuffer(Surface* surface, sp buffe if (err != OK) { return err; } + err = surface->setBuffersDataSpace(tmpDataspace); + if (err != OK) { + return err; + } err = surface->disconnect(NATIVE_WINDOW_API_CPU); return err; } diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 0c471bb701..5c6a1ee383 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -292,7 +292,8 @@ public: ui::Dataspace getBuffersDataSpace(); - static status_t attachAndQueueBuffer(Surface* surface, sp buffer); + static status_t attachAndQueueBufferWithDataspace(Surface* surface, sp buffer, + ui::Dataspace dataspace); protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; -- GitLab From e9137b776a6de8070e00771f111a8523fb858280 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Tue, 27 Aug 2019 13:22:18 -0700 Subject: [PATCH 0191/1255] Break up TransactionTest helpers into util directory Bug: 140128949 Test: build, boot, SurfaceFlinger_test Change-Id: I10d29ae47cf29979289469832e2fcd1acefbe45f --- services/surfaceflinger/tests/Android.bp | 1 + .../surfaceflinger/tests/Transaction_test.cpp | 520 +----------------- .../tests/utils/CallbackUtils.h | 196 +++++++ .../surfaceflinger/tests/utils/ColorUtils.h | 86 +++ .../tests/utils/ScreenshotUtils.h | 167 ++++++ .../tests/utils/TransactionUtils.h | 188 +++++++ 6 files changed, 642 insertions(+), 516 deletions(-) create mode 100644 services/surfaceflinger/tests/utils/CallbackUtils.h create mode 100644 services/surfaceflinger/tests/utils/ColorUtils.h create mode 100644 services/surfaceflinger/tests/utils/ScreenshotUtils.h create mode 100644 services/surfaceflinger/tests/utils/TransactionUtils.h diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 53a3611472..159c2a464a 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -50,6 +50,7 @@ subdirs = [ "fakehwc", "hwc2", "unittests", + "utils", "vsync", "waitforvsync", ] diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index b1fde22e0e..57e5c51d44 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include @@ -37,10 +36,7 @@ #include #include -#include #include -#include -#include #include #include @@ -48,293 +44,14 @@ #include #include "BufferGenerator.h" +#include "utils/CallbackUtils.h" +#include "utils/ColorUtils.h" +#include "utils/ScreenshotUtils.h" +#include "utils/TransactionUtils.h" namespace android { -namespace { - -struct Color { - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; - - static const Color RED; - static const Color GREEN; - static const Color BLUE; - static const Color WHITE; - static const Color BLACK; - static const Color TRANSPARENT; -}; - -const Color Color::RED{255, 0, 0, 255}; -const Color Color::GREEN{0, 255, 0, 255}; -const Color Color::BLUE{0, 0, 255, 255}; -const Color Color::WHITE{255, 255, 255, 255}; -const Color Color::BLACK{0, 0, 0, 255}; -const Color Color::TRANSPARENT{0, 0, 0, 0}; - using android::hardware::graphics::common::V1_1::BufferUsage; -using namespace std::chrono_literals; - -std::ostream& operator<<(std::ostream& os, const Color& color) { - os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a); - return os; -} - -// Fill a region with the specified color. -void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect, - const Color& color) { - Rect r(0, 0, buffer.width, buffer.height); - if (!r.intersect(rect, &r)) { - return; - } - - int32_t width = r.right - r.left; - int32_t height = r.bottom - r.top; - - for (int32_t row = 0; row < height; row++) { - uint8_t* dst = - static_cast(buffer.bits) + (buffer.stride * (r.top + row) + r.left) * 4; - for (int32_t column = 0; column < width; column++) { - dst[0] = color.r; - dst[1] = color.g; - dst[2] = color.b; - dst[3] = color.a; - dst += 4; - } - } -} - -// Fill a region with the specified color. -void fillGraphicBufferColor(const sp& buffer, const Rect& rect, const Color& color) { - Rect r(0, 0, buffer->width, buffer->height); - if (!r.intersect(rect, &r)) { - return; - } - - int32_t width = r.right - r.left; - int32_t height = r.bottom - r.top; - - uint8_t* pixels; - buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); - - for (int32_t row = 0; row < height; row++) { - uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4; - for (int32_t column = 0; column < width; column++) { - dst[0] = color.r; - dst[1] = color.g; - dst[2] = color.b; - dst[3] = color.a; - dst += 4; - } - } - buffer->unlock(); -} - -// Check if a region has the specified color. -void expectBufferColor(const sp& outBuffer, uint8_t* pixels, const Rect& rect, - const Color& color, uint8_t tolerance) { - int32_t x = rect.left; - int32_t y = rect.top; - int32_t width = rect.right - rect.left; - int32_t height = rect.bottom - rect.top; - - int32_t bufferWidth = int32_t(outBuffer->getWidth()); - int32_t bufferHeight = int32_t(outBuffer->getHeight()); - if (x + width > bufferWidth) { - x = std::min(x, bufferWidth); - width = bufferWidth - x; - } - if (y + height > bufferHeight) { - y = std::min(y, bufferHeight); - height = bufferHeight - y; - } - - auto colorCompare = [tolerance](uint8_t a, uint8_t b) { - uint8_t tmp = a >= b ? a - b : b - a; - return tmp <= tolerance; - }; - for (int32_t j = 0; j < height; j++) { - const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4; - for (int32_t i = 0; i < width; i++) { - const uint8_t expected[4] = {color.r, color.g, color.b, color.a}; - EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare)) - << "pixel @ (" << x + i << ", " << y + j << "): " - << "expected (" << color << "), " - << "got (" << Color{src[0], src[1], src[2], src[3]} << ")"; - src += 4; - } - } -} - -} // anonymous namespace - -using Transaction = SurfaceComposerClient::Transaction; - -// Fill an RGBA_8888 formatted surface with a single color. -static void fillSurfaceRGBA8(const sp& sc, uint8_t r, uint8_t g, uint8_t b, - bool unlock = true) { - ANativeWindow_Buffer outBuffer; - sp s = sc->getSurface(); - ASSERT_TRUE(s != nullptr); - ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr)); - uint8_t* img = reinterpret_cast(outBuffer.bits); - for (int y = 0; y < outBuffer.height; y++) { - for (int x = 0; x < outBuffer.width; x++) { - uint8_t* pixel = img + (4 * (y * outBuffer.stride + x)); - pixel[0] = r; - pixel[1] = g; - pixel[2] = b; - pixel[3] = 255; - } - } - if (unlock) { - ASSERT_EQ(NO_ERROR, s->unlockAndPost()); - } -} - -// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check -// individual pixel values for testing purposes. -class ScreenCapture : public RefBase { -public: - static void captureScreen(std::unique_ptr* sc) { - captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken()); - } - - static void captureScreen(std::unique_ptr* sc, sp displayToken) { - const auto sf = ComposerService::getComposerService(); - SurfaceComposerClient::Transaction().apply(true); - - sp outBuffer; - ASSERT_EQ(NO_ERROR, sf->captureScreen(displayToken, &outBuffer, Rect(), 0, 0, false)); - *sc = std::make_unique(outBuffer); - } - - static void captureLayers(std::unique_ptr* sc, sp& parentHandle, - Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) { - sp sf(ComposerService::getComposerService()); - SurfaceComposerClient::Transaction().apply(true); - - sp outBuffer; - ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale)); - *sc = std::make_unique(outBuffer); - } - - static void captureChildLayers(std::unique_ptr* sc, sp& parentHandle, - Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) { - sp sf(ComposerService::getComposerService()); - SurfaceComposerClient::Transaction().apply(true); - - sp outBuffer; - ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true)); - *sc = std::make_unique(outBuffer); - } - - static void captureChildLayersExcluding( - std::unique_ptr* sc, sp& parentHandle, - std::unordered_set, ISurfaceComposer::SpHash> excludeLayers) { - sp sf(ComposerService::getComposerService()); - SurfaceComposerClient::Transaction().apply(true); - - sp outBuffer; - ASSERT_EQ(NO_ERROR, - sf->captureLayers(parentHandle, &outBuffer, ui::Dataspace::V0_SRGB, - ui::PixelFormat::RGBA_8888, Rect::EMPTY_RECT, excludeLayers, - 1.0f, true)); - *sc = std::make_unique(outBuffer); - } - - void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) { - ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat()); - expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance); - } - - void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) { - ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat()); - const bool leftBorder = rect.left > 0; - const bool topBorder = rect.top > 0; - const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth()); - const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight()); - - if (topBorder) { - Rect top(rect.left, rect.top - 1, rect.right, rect.top); - if (leftBorder) { - top.left -= 1; - } - if (rightBorder) { - top.right += 1; - } - expectColor(top, color, tolerance); - } - if (leftBorder) { - Rect left(rect.left - 1, rect.top, rect.left, rect.bottom); - expectColor(left, color, tolerance); - } - if (rightBorder) { - Rect right(rect.right, rect.top, rect.right + 1, rect.bottom); - expectColor(right, color, tolerance); - } - if (bottomBorder) { - Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1); - if (leftBorder) { - bottom.left -= 1; - } - if (rightBorder) { - bottom.right += 1; - } - expectColor(bottom, color, tolerance); - } - } - - void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight, - const Color& bottomLeft, const Color& bottomRight, bool filtered = false, - uint8_t tolerance = 0) { - ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0); - - const int32_t centerX = rect.left + (rect.right - rect.left) / 2; - const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2; - // avoid checking borders due to unspecified filtering behavior - const int32_t offsetX = filtered ? 2 : 0; - const int32_t offsetY = filtered ? 2 : 0; - expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft, - tolerance); - expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight, - tolerance); - expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft, - tolerance); - expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom), - bottomRight, tolerance); - } - - void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) { - ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat()); - const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x)); - if (r != pixel[0] || g != pixel[1] || b != pixel[2]) { - String8 err(String8::format("pixel @ (%3d, %3d): " - "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", - x, y, r, g, b, pixel[0], pixel[1], pixel[2])); - EXPECT_EQ(String8(), err) << err.string(); - } - } - - void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); } - - void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); } - - void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); } - - explicit ScreenCapture(const sp& outBuffer) : mOutBuffer(outBuffer) { - mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast(&mPixels)); - } - - ~ScreenCapture() { mOutBuffer->unlock(); } - -private: - sp mOutBuffer; - uint8_t* mPixels = nullptr; -}; class LayerTransactionTest : public ::testing::Test { protected: @@ -583,7 +300,6 @@ private: friend class LayerRenderPathTestHarness; }; -enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY }; class LayerRenderPathTestHarness { public: @@ -693,13 +409,6 @@ protected: LayerRenderPathTestHarness mRenderPathHarness; }; -// Environment for starting up binder threads. This is required for testing -// virtual displays, as BufferQueue parameters may be queried over binder. -class BinderEnvironment : public ::testing::Environment { -public: - void SetUp() override { ProcessState::self()->startThreadPool(); } -}; - ::testing::Environment* const binderEnv = ::testing::AddGlobalTestEnvironment(new BinderEnvironment()); @@ -1338,19 +1047,6 @@ TEST_P(LayerTypeTransactionTest, SetFlagsSecure) { composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false)); } -/** RAII Wrapper around get/seteuid */ -class UIDFaker { - uid_t oldId; -public: - UIDFaker(uid_t uid) { - oldId = geteuid(); - seteuid(uid); - } - ~UIDFaker() { - seteuid(oldId); - } -}; - TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) { sp layer; ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); @@ -2934,47 +2630,6 @@ TEST_F(LayerTransactionTest, ReparentToSelf) { } } -class ColorTransformHelper { -public: - static void DegammaColorSingle(half& s) { - if (s <= 0.03928f) - s = s / 12.92f; - else - s = pow((s + 0.055f) / 1.055f, 2.4f); - } - - static void DegammaColor(half3& color) { - DegammaColorSingle(color.r); - DegammaColorSingle(color.g); - DegammaColorSingle(color.b); - } - - static void GammaColorSingle(half& s) { - if (s <= 0.0031308f) { - s = s * 12.92f; - } else { - s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f; - } - } - - static void GammaColor(half3& color) { - GammaColorSingle(color.r); - GammaColorSingle(color.g); - GammaColorSingle(color.b); - } - - static void applyMatrix(half3& color, const mat3& mat) { - half3 ret = half3(0); - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - ret[i] = ret[i] + color[j] * mat[j][i]; - } - } - color = ret; - } -}; - TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) { sp colorLayer; ASSERT_NO_FATAL_FAILURE(colorLayer = @@ -3138,173 +2793,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnChildAndParent) { } } -struct CallbackData { - CallbackData() = default; - CallbackData(nsecs_t time, const sp& fence, - const std::vector& stats) - : latchTime(time), presentFence(fence), surfaceControlStats(stats) {} - - nsecs_t latchTime; - sp presentFence; - std::vector surfaceControlStats; -}; - -class ExpectedResult { -public: - enum Transaction { - NOT_PRESENTED = 0, - PRESENTED, - }; - - enum Buffer { - NOT_ACQUIRED = 0, - ACQUIRED, - }; - - enum PreviousBuffer { - NOT_RELEASED = 0, - RELEASED, - UNKNOWN, - }; - - void reset() { - mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED; - mExpectedSurfaceResults.clear(); - } - - void addSurface(ExpectedResult::Transaction transactionResult, const sp& layer, - ExpectedResult::Buffer bufferResult = ACQUIRED, - ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) { - mTransactionResult = transactionResult; - mExpectedSurfaceResults.emplace(std::piecewise_construct, std::forward_as_tuple(layer), - std::forward_as_tuple(bufferResult, previousBufferResult)); - } - - void addSurfaces(ExpectedResult::Transaction transactionResult, - const std::vector>& layers, - ExpectedResult::Buffer bufferResult = ACQUIRED, - ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) { - for (const auto& layer : layers) { - addSurface(transactionResult, layer, bufferResult, previousBufferResult); - } - } - - void addExpectedPresentTime(nsecs_t expectedPresentTime) { - mExpectedPresentTime = expectedPresentTime; - } - - void verifyCallbackData(const CallbackData& callbackData) const { - const auto& [latchTime, presentFence, surfaceControlStats] = callbackData; - if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) { - ASSERT_GE(latchTime, 0) << "bad latch time"; - ASSERT_NE(presentFence, nullptr); - if (mExpectedPresentTime >= 0) { - ASSERT_EQ(presentFence->wait(3000), NO_ERROR); - ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6)); - // if the panel is running at 30 hz, at the worst case, our expected time just - // misses vsync and we have to wait another 33.3ms - ASSERT_LE(presentFence->getSignalTime(), - mExpectedPresentTime + nsecs_t(66.666666 * 1e6)); - } - } else { - ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented"; - ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched"; - } - - ASSERT_EQ(surfaceControlStats.size(), mExpectedSurfaceResults.size()) - << "wrong number of surfaces"; - - for (const auto& stats : surfaceControlStats) { - ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control"; - - const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl); - ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end()) - << "unexpected surface control"; - expectedSurfaceResult->second.verifySurfaceControlStats(stats, latchTime); - } - } - -private: - class ExpectedSurfaceResult { - public: - ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult, - ExpectedResult::PreviousBuffer previousBufferResult) - : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {} - - void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats, - nsecs_t latchTime) const { - const auto& [surfaceControl, acquireTime, previousReleaseFence] = surfaceControlStats; - - ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED) - << "bad acquire time"; - ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time"; - - if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) { - ASSERT_NE(previousReleaseFence, nullptr) - << "failed to set release prev buffer fence"; - } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) { - ASSERT_EQ(previousReleaseFence, nullptr) - << "should not have set released prev buffer fence"; - } - } - - private: - ExpectedResult::Buffer mBufferResult; - ExpectedResult::PreviousBuffer mPreviousBufferResult; - }; - - struct SCHash { - std::size_t operator()(const sp& sc) const { - return std::hash{}(sc->getHandle().get()); - } - }; - ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED; - nsecs_t mExpectedPresentTime = -1; - std::unordered_map, ExpectedSurfaceResult, SCHash> mExpectedSurfaceResults; -}; - -class CallbackHelper { -public: - static void function(void* callbackContext, nsecs_t latchTime, const sp& presentFence, - const std::vector& stats) { - if (!callbackContext) { - ALOGE("failed to get callback context"); - } - CallbackHelper* helper = static_cast(callbackContext); - std::lock_guard lock(helper->mMutex); - helper->mCallbackDataQueue.emplace(latchTime, presentFence, stats); - helper->mConditionVariable.notify_all(); - } - - void getCallbackData(CallbackData* outData) { - std::unique_lock lock(mMutex); - - if (mCallbackDataQueue.empty()) { - ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)), - std::cv_status::timeout) - << "did not receive callback"; - } - - *outData = std::move(mCallbackDataQueue.front()); - mCallbackDataQueue.pop(); - } - - void verifyFinalState() { - // Wait to see if there are extra callbacks - std::this_thread::sleep_for(500ms); - - std::lock_guard lock(mMutex); - EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received"; - mCallbackDataQueue = {}; - } - - void* getContext() { return static_cast(this); } - - std::mutex mMutex; - std::condition_variable mConditionVariable; - std::queue mCallbackDataQueue; -}; - class LayerCallbackTest : public LayerTransactionTest { public: virtual sp createBufferStateLayer() { diff --git a/services/surfaceflinger/tests/utils/CallbackUtils.h b/services/surfaceflinger/tests/utils/CallbackUtils.h new file mode 100644 index 0000000000..51ae8c4e94 --- /dev/null +++ b/services/surfaceflinger/tests/utils/CallbackUtils.h @@ -0,0 +1,196 @@ +/* + * Copyright (C) 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 +#include +#include +#include +#include +#include + +namespace android { + +namespace { + +struct CallbackData { + CallbackData() = default; + CallbackData(nsecs_t time, const sp& fence, + const std::vector& stats) + : latchTime(time), presentFence(fence), surfaceControlStats(stats) {} + + nsecs_t latchTime; + sp presentFence; + std::vector surfaceControlStats; +}; + +class ExpectedResult { +public: + enum Transaction { + NOT_PRESENTED = 0, + PRESENTED, + }; + + enum Buffer { + NOT_ACQUIRED = 0, + ACQUIRED, + }; + + enum PreviousBuffer { + NOT_RELEASED = 0, + RELEASED, + UNKNOWN, + }; + + void reset() { + mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED; + mExpectedSurfaceResults.clear(); + } + + void addSurface(ExpectedResult::Transaction transactionResult, const sp& layer, + ExpectedResult::Buffer bufferResult = ACQUIRED, + ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) { + mTransactionResult = transactionResult; + mExpectedSurfaceResults.emplace(std::piecewise_construct, std::forward_as_tuple(layer), + std::forward_as_tuple(bufferResult, previousBufferResult)); + } + + void addSurfaces(ExpectedResult::Transaction transactionResult, + const std::vector>& layers, + ExpectedResult::Buffer bufferResult = ACQUIRED, + ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) { + for (const auto& layer : layers) { + addSurface(transactionResult, layer, bufferResult, previousBufferResult); + } + } + + void addExpectedPresentTime(nsecs_t expectedPresentTime) { + mExpectedPresentTime = expectedPresentTime; + } + + void verifyCallbackData(const CallbackData& callbackData) const { + const auto& [latchTime, presentFence, surfaceControlStats] = callbackData; + if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) { + ASSERT_GE(latchTime, 0) << "bad latch time"; + ASSERT_NE(presentFence, nullptr); + if (mExpectedPresentTime >= 0) { + ASSERT_EQ(presentFence->wait(3000), NO_ERROR); + ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6)); + // if the panel is running at 30 hz, at the worst case, our expected time just + // misses vsync and we have to wait another 33.3ms + ASSERT_LE(presentFence->getSignalTime(), + mExpectedPresentTime + nsecs_t(66.666666 * 1e6)); + } + } else { + ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented"; + ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched"; + } + + ASSERT_EQ(surfaceControlStats.size(), mExpectedSurfaceResults.size()) + << "wrong number of surfaces"; + + for (const auto& stats : surfaceControlStats) { + ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control"; + + const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl); + ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end()) + << "unexpected surface control"; + expectedSurfaceResult->second.verifySurfaceControlStats(stats, latchTime); + } + } + +private: + class ExpectedSurfaceResult { + public: + ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult, + ExpectedResult::PreviousBuffer previousBufferResult) + : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {} + + void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats, + nsecs_t latchTime) const { + const auto& [surfaceControl, acquireTime, previousReleaseFence] = surfaceControlStats; + + ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED) + << "bad acquire time"; + ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time"; + + if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) { + ASSERT_NE(previousReleaseFence, nullptr) + << "failed to set release prev buffer fence"; + } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) { + ASSERT_EQ(previousReleaseFence, nullptr) + << "should not have set released prev buffer fence"; + } + } + + private: + ExpectedResult::Buffer mBufferResult; + ExpectedResult::PreviousBuffer mPreviousBufferResult; + }; + + struct SCHash { + std::size_t operator()(const sp& sc) const { + return std::hash{}(sc->getHandle().get()); + } + }; + ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED; + nsecs_t mExpectedPresentTime = -1; + std::unordered_map, ExpectedSurfaceResult, SCHash> mExpectedSurfaceResults; +}; + +class CallbackHelper { +public: + static void function(void* callbackContext, nsecs_t latchTime, const sp& presentFence, + const std::vector& stats) { + if (!callbackContext) { + ALOGE("failed to get callback context"); + } + CallbackHelper* helper = static_cast(callbackContext); + std::lock_guard lock(helper->mMutex); + helper->mCallbackDataQueue.emplace(latchTime, presentFence, stats); + helper->mConditionVariable.notify_all(); + } + + void getCallbackData(CallbackData* outData) { + std::unique_lock lock(mMutex); + + if (mCallbackDataQueue.empty()) { + ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)), + std::cv_status::timeout) + << "did not receive callback"; + } + + *outData = std::move(mCallbackDataQueue.front()); + mCallbackDataQueue.pop(); + } + + void verifyFinalState() { + // Wait to see if there are extra callbacks + std::this_thread::sleep_for(500ms); + + std::lock_guard lock(mMutex); + EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received"; + mCallbackDataQueue = {}; + } + + void* getContext() { return static_cast(this); } + + std::mutex mMutex; + std::condition_variable mConditionVariable; + std::queue mCallbackDataQueue; +}; +} +} // namespace android diff --git a/services/surfaceflinger/tests/utils/ColorUtils.h b/services/surfaceflinger/tests/utils/ColorUtils.h new file mode 100644 index 0000000000..07916b60a7 --- /dev/null +++ b/services/surfaceflinger/tests/utils/ColorUtils.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 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 + +namespace android { + +namespace { + +struct Color { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + + static const Color RED; + static const Color GREEN; + static const Color BLUE; + static const Color WHITE; + static const Color BLACK; + static const Color TRANSPARENT; +}; + +const Color Color::RED{255, 0, 0, 255}; +const Color Color::GREEN{0, 255, 0, 255}; +const Color Color::BLUE{0, 0, 255, 255}; +const Color Color::WHITE{255, 255, 255, 255}; +const Color Color::BLACK{0, 0, 0, 255}; +const Color Color::TRANSPARENT{0, 0, 0, 0}; + +class ColorTransformHelper { +public: + static void DegammaColorSingle(half& s) { + if (s <= 0.03928f) + s = s / 12.92f; + else + s = pow((s + 0.055f) / 1.055f, 2.4f); + } + + static void DegammaColor(half3& color) { + DegammaColorSingle(color.r); + DegammaColorSingle(color.g); + DegammaColorSingle(color.b); + } + + static void GammaColorSingle(half& s) { + if (s <= 0.0031308f) { + s = s * 12.92f; + } else { + s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f; + } + } + + static void GammaColor(half3& color) { + GammaColorSingle(color.r); + GammaColorSingle(color.g); + GammaColorSingle(color.b); + } + + static void applyMatrix(half3& color, const mat3& mat) { + half3 ret = half3(0); + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + ret[i] = ret[i] + color[j] * mat[j][i]; + } + } + color = ret; + } +}; +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h new file mode 100644 index 0000000000..02e7623dbd --- /dev/null +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -0,0 +1,167 @@ +/* + * Copyright (C) 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 +#include +#include "TransactionUtils.h" + +namespace android { + +namespace { + +// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check +// individual pixel values for testing purposes. +class ScreenCapture : public RefBase { +public: + static void captureScreen(std::unique_ptr* sc) { + captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken()); + } + + static void captureScreen(std::unique_ptr* sc, sp displayToken) { + const auto sf = ComposerService::getComposerService(); + SurfaceComposerClient::Transaction().apply(true); + + sp outBuffer; + ASSERT_EQ(NO_ERROR, sf->captureScreen(displayToken, &outBuffer, Rect(), 0, 0, false)); + *sc = std::make_unique(outBuffer); + } + + static void captureLayers(std::unique_ptr* sc, sp& parentHandle, + Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) { + sp sf(ComposerService::getComposerService()); + SurfaceComposerClient::Transaction().apply(true); + + sp outBuffer; + ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale)); + *sc = std::make_unique(outBuffer); + } + + static void captureChildLayers(std::unique_ptr* sc, sp& parentHandle, + Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) { + sp sf(ComposerService::getComposerService()); + SurfaceComposerClient::Transaction().apply(true); + + sp outBuffer; + ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true)); + *sc = std::make_unique(outBuffer); + } + + static void captureChildLayersExcluding( + std::unique_ptr* sc, sp& parentHandle, + std::unordered_set, ISurfaceComposer::SpHash> excludeLayers) { + sp sf(ComposerService::getComposerService()); + SurfaceComposerClient::Transaction().apply(true); + + sp outBuffer; + ASSERT_EQ(NO_ERROR, + sf->captureLayers(parentHandle, &outBuffer, ui::Dataspace::V0_SRGB, + ui::PixelFormat::RGBA_8888, Rect::EMPTY_RECT, excludeLayers, + 1.0f, true)); + *sc = std::make_unique(outBuffer); + } + + void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) { + ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat()); + expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance); + } + + void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) { + ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat()); + const bool leftBorder = rect.left > 0; + const bool topBorder = rect.top > 0; + const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth()); + const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight()); + + if (topBorder) { + Rect top(rect.left, rect.top - 1, rect.right, rect.top); + if (leftBorder) { + top.left -= 1; + } + if (rightBorder) { + top.right += 1; + } + expectColor(top, color, tolerance); + } + if (leftBorder) { + Rect left(rect.left - 1, rect.top, rect.left, rect.bottom); + expectColor(left, color, tolerance); + } + if (rightBorder) { + Rect right(rect.right, rect.top, rect.right + 1, rect.bottom); + expectColor(right, color, tolerance); + } + if (bottomBorder) { + Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1); + if (leftBorder) { + bottom.left -= 1; + } + if (rightBorder) { + bottom.right += 1; + } + expectColor(bottom, color, tolerance); + } + } + + void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight, + const Color& bottomLeft, const Color& bottomRight, bool filtered = false, + uint8_t tolerance = 0) { + ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0); + + const int32_t centerX = rect.left + (rect.right - rect.left) / 2; + const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2; + // avoid checking borders due to unspecified filtering behavior + const int32_t offsetX = filtered ? 2 : 0; + const int32_t offsetY = filtered ? 2 : 0; + expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft, + tolerance); + expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight, + tolerance); + expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft, + tolerance); + expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom), + bottomRight, tolerance); + } + + void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) { + ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat()); + const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x)); + if (r != pixel[0] || g != pixel[1] || b != pixel[2]) { + String8 err(String8::format("pixel @ (%3d, %3d): " + "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", + x, y, r, g, b, pixel[0], pixel[1], pixel[2])); + EXPECT_EQ(String8(), err) << err.string(); + } + } + + void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); } + + void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); } + + void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); } + + explicit ScreenCapture(const sp& outBuffer) : mOutBuffer(outBuffer) { + mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast(&mPixels)); + } + + ~ScreenCapture() { mOutBuffer->unlock(); } + +private: + sp mOutBuffer; + uint8_t* mPixels = nullptr; +}; +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h new file mode 100644 index 0000000000..f6b33a9bc3 --- /dev/null +++ b/services/surfaceflinger/tests/utils/TransactionUtils.h @@ -0,0 +1,188 @@ +/* + * Copyright (C) 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 +#include +//#include +//#include +//#include +//#include +//#include +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include + +#include "ColorUtils.h" +//#include +//#include + +namespace android { + +namespace { + +using namespace std::chrono_literals; + +std::ostream& operator<<(std::ostream& os, const Color& color) { + os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a); + return os; +} + +// Fill a region with the specified color. +void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect, + const Color& color) { + Rect r(0, 0, buffer.width, buffer.height); + if (!r.intersect(rect, &r)) { + return; + } + + int32_t width = r.right - r.left; + int32_t height = r.bottom - r.top; + + for (int32_t row = 0; row < height; row++) { + uint8_t* dst = + static_cast(buffer.bits) + (buffer.stride * (r.top + row) + r.left) * 4; + for (int32_t column = 0; column < width; column++) { + dst[0] = color.r; + dst[1] = color.g; + dst[2] = color.b; + dst[3] = color.a; + dst += 4; + } + } +} + +// Fill a region with the specified color. +void fillGraphicBufferColor(const sp& buffer, const Rect& rect, const Color& color) { + Rect r(0, 0, buffer->width, buffer->height); + if (!r.intersect(rect, &r)) { + return; + } + + int32_t width = r.right - r.left; + int32_t height = r.bottom - r.top; + + uint8_t* pixels; + buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); + + for (int32_t row = 0; row < height; row++) { + uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4; + for (int32_t column = 0; column < width; column++) { + dst[0] = color.r; + dst[1] = color.g; + dst[2] = color.b; + dst[3] = color.a; + dst += 4; + } + } + buffer->unlock(); +} + +// Check if a region has the specified color. +void expectBufferColor(const sp& outBuffer, uint8_t* pixels, const Rect& rect, + const Color& color, uint8_t tolerance) { + int32_t x = rect.left; + int32_t y = rect.top; + int32_t width = rect.right - rect.left; + int32_t height = rect.bottom - rect.top; + + int32_t bufferWidth = int32_t(outBuffer->getWidth()); + int32_t bufferHeight = int32_t(outBuffer->getHeight()); + if (x + width > bufferWidth) { + x = std::min(x, bufferWidth); + width = bufferWidth - x; + } + if (y + height > bufferHeight) { + y = std::min(y, bufferHeight); + height = bufferHeight - y; + } + + auto colorCompare = [tolerance](uint8_t a, uint8_t b) { + uint8_t tmp = a >= b ? a - b : b - a; + return tmp <= tolerance; + }; + for (int32_t j = 0; j < height; j++) { + const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4; + for (int32_t i = 0; i < width; i++) { + const uint8_t expected[4] = {color.r, color.g, color.b, color.a}; + EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare)) + << "pixel @ (" << x + i << ", " << y + j << "): " + << "expected (" << color << "), " + << "got (" << Color{src[0], src[1], src[2], src[3]} << ")"; + src += 4; + } + } +} + +using Transaction = SurfaceComposerClient::Transaction; + +// Fill an RGBA_8888 formatted surface with a single color. +static void fillSurfaceRGBA8(const sp& sc, uint8_t r, uint8_t g, uint8_t b, + bool unlock = true) { + ANativeWindow_Buffer outBuffer; + sp s = sc->getSurface(); + ASSERT_TRUE(s != nullptr); + ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr)); + uint8_t* img = reinterpret_cast(outBuffer.bits); + for (int y = 0; y < outBuffer.height; y++) { + for (int x = 0; x < outBuffer.width; x++) { + uint8_t* pixel = img + (4 * (y * outBuffer.stride + x)); + pixel[0] = r; + pixel[1] = g; + pixel[2] = b; + pixel[3] = 255; + } + } + if (unlock) { + ASSERT_EQ(NO_ERROR, s->unlockAndPost()); + } +} + +enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY }; + +// Environment for starting up binder threads. This is required for testing +// virtual displays, as BufferQueue parameters may be queried over binder. +class BinderEnvironment : public ::testing::Environment { +public: + void SetUp() override { ProcessState::self()->startThreadPool(); } +}; + +/** RAII Wrapper around get/seteuid */ +class UIDFaker { + uid_t oldId; + +public: + UIDFaker(uid_t uid) { + oldId = geteuid(); + seteuid(uid); + } + ~UIDFaker() { seteuid(oldId); } +}; +} // namespace +} // namespace android -- GitLab From 98fca268fc322de36868f17a2508ed44f6d9b82a Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 23 May 2019 07:14:20 -0700 Subject: [PATCH 0192/1255] [SurfaceFlinger] add minimum frame count for early gl offsets. This is to avoid edge case behavior by rapidly switching in and out of gl composition, causing poor vsync timelines. Bug: 132997413 Test: systrace Change-Id: I4665f34f7e027a7883cfb5e47e14f41d845d1298 (cherry picked from commit 5a1021000dabfad591dc1afa6525b7165c046bf9) Merged-In: I4665f34f7e027a7883cfb5e47e14f41d845d1298 --- .../surfaceflinger/Scheduler/VSyncModulator.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 81a7864cdb..72f90505c6 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -35,6 +35,11 @@ private: // sending new transactions. const int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2; + // Number of frames we'll keep the early gl phase offsets once they are activated. + // This acts as a low-pass filter to avoid scenarios where we rapidly + // switch in and out of gl composition. + const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; + public: struct Offsets { nsecs_t sf; @@ -130,10 +135,14 @@ public: mRemainingEarlyFrameCount--; updateOffsetsNeeded = true; } - if (usedRenderEngine != mLastFrameUsedRenderEngine) { - mLastFrameUsedRenderEngine = usedRenderEngine; + if (usedRenderEngine) { + mRemainingRenderEngineUsageCount = MIN_EARLY_GL_FRAME_COUNT_TRANSACTION; + updateOffsetsNeeded = true; + } else if (mRemainingRenderEngineUsageCount > 0) { + mRemainingRenderEngineUsageCount--; updateOffsetsNeeded = true; } + if (updateOffsetsNeeded) { updateOffsets(); } @@ -145,7 +154,7 @@ public: if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { return mEarlyOffsets; - } else if (mLastFrameUsedRenderEngine) { + } else if (mRemainingRenderEngineUsageCount > 0) { return mEarlyGlOffsets; } else { return mLateOffsets; @@ -195,9 +204,9 @@ private: std::atomic mTransactionStart = Scheduler::TransactionStart::NORMAL; - std::atomic mLastFrameUsedRenderEngine = false; std::atomic mRefreshRateChangePending = false; std::atomic mRemainingEarlyFrameCount = 0; + std::atomic mRemainingRenderEngineUsageCount = 0; }; } // namespace android -- GitLab From 1f534ab8076868d84afd39aa8485972a42b74db4 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 21 May 2019 00:51:01 -0700 Subject: [PATCH 0193/1255] [SurfaceFlinger] Some dispsync fixes for early event firing * Fix lastEventTime for listeners so that they don't fire early. * Properly set mHasFired for listeners so that if the dispsync model is currently being updated that mHasFired is always set to true if lastEventTime is after the most recent vsync reference. Bug: 132678707 Bug: 130684082 Test: systrace Change-Id: I5b860336f12b742cc67665776290939b61e7e3af (cherry picked from commit c3a482d7555905f8f65d693293175186aff19466) Merged-In: I5b860336f12b742cc67665776290939b61e7e3af --- .../surfaceflinger/Scheduler/DispSync.cpp | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index cd6fa41940..7a44c4e845 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -79,11 +79,7 @@ public: Mutex::Autolock lock(mMutex); mPhase = phase; - if (mReferenceTime != referenceTime) { - for (auto& eventListener : mEventListeners) { - eventListener.mHasFired = false; - } - } + const bool referenceTimeChanged = mReferenceTime != referenceTime; mReferenceTime = referenceTime; if (mPeriod != 0 && mPeriod != period && mReferenceTime != 0) { // Inflate the reference time to be the most recent predicted @@ -94,6 +90,13 @@ public: mReferenceTime = mReferenceTime + (numOldPeriods)*mPeriod; } mPeriod = period; + if (!mModelLocked && referenceTimeChanged) { + for (auto& eventListener : mEventListeners) { + eventListener.mHasFired = false; + eventListener.mLastEventTime = + mReferenceTime - mPeriod + mPhase + eventListener.mPhase; + } + } if (mTraceDetailedInfo) { ATRACE_INT64("DispSync:Period", mPeriod); ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2); @@ -119,6 +122,13 @@ public: void unlockModel() { Mutex::Autolock lock(mMutex); + if (mModelLocked) { + for (auto& eventListener : mEventListeners) { + if (eventListener.mLastEventTime > mReferenceTime) { + eventListener.mHasFired = true; + } + } + } mModelLocked = false; } @@ -247,6 +257,10 @@ public: listener.mLastCallbackTime = lastCallbackTime; } + if (!mModelLocked && listener.mLastEventTime > mReferenceTime) { + listener.mHasFired = true; + } + mEventListeners.push_back(listener); mCond.signal(); -- GitLab From 5b3f19be3ca637c3914f79793ebd6cacd94c5d4c Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 20 May 2019 18:32:22 -0700 Subject: [PATCH 0194/1255] [SurfaceFlinger] fix permanently enabling early offsets. * Add notion of intended period in DispSync, and use that to detect whether the simulated period will be changed. * Propagate that signal to setDesiredActiveConfig, so that we don't fall into early offsets unnecessarily, which can cause early offsets to always be enabled. Bug: 132678707 Test: systrace Test: swappy test app Test: scrolling through google news Change-Id: I18df1b9d949cd534ecbf1c8891b6f88eab8be399 (cherry picked from commit f8e689cfd25f27c4af36a27e145d4cac1d0bb9cb) Merged-In: I18df1b9d949cd534ecbf1c8891b6f88eab8be399 --- .../surfaceflinger/Scheduler/DispSync.cpp | 38 +++++++++++++------ services/surfaceflinger/Scheduler/DispSync.h | 21 ++++++---- .../surfaceflinger/Scheduler/Scheduler.cpp | 8 ++-- services/surfaceflinger/Scheduler/Scheduler.h | 11 ++++-- .../surfaceflinger/Scheduler/VSyncModulator.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 23 ++++++++--- .../tests/unittests/mock/MockDispSync.h | 1 + 7 files changed, 72 insertions(+), 32 deletions(-) diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index 7a44c4e845..95ff9d0c73 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -118,6 +118,7 @@ public: void lockModel() { Mutex::Autolock lock(mMutex); mModelLocked = true; + ATRACE_INT("DispSync:ModelLocked", mModelLocked); } void unlockModel() { @@ -130,6 +131,7 @@ public: } } mModelLocked = false; + ATRACE_INT("DispSync:ModelLocked", mModelLocked); } virtual bool threadLoop() { @@ -507,7 +509,6 @@ void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) { ALOGE("Couldn't set SCHED_FIFO for DispSyncThread"); } - reset(); beginResync(); if (mTraceDetailedInfo && kEnableZeroPhaseTracer) { @@ -559,17 +560,15 @@ bool DispSync::addPresentFence(const std::shared_ptr& fenceTime) { void DispSync::beginResync() { Mutex::Autolock lock(mMutex); ALOGV("[%s] beginResync", mName); - mThread->unlockModel(); - mModelUpdated = false; - mNumResyncSamples = 0; + resetLocked(); } -bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodChanged) { +bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodFlushed) { Mutex::Autolock lock(mMutex); ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp)); - *periodChanged = false; + *periodFlushed = false; const size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES; mResyncSamples[idx] = timestamp; if (mNumResyncSamples == 0) { @@ -583,16 +582,20 @@ bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodChanged) { const nsecs_t lastTimestamp = mResyncSamples[priorIdx]; const nsecs_t observedVsync = std::abs(timestamp - lastTimestamp); - if (std::abs(observedVsync - mPendingPeriod) < std::abs(observedVsync - mPeriod)) { - // Observed vsync is closer to the pending period, so reset the - // model and flush the pending period. + if (std::abs(observedVsync - mPendingPeriod) <= std::abs(observedVsync - mIntendedPeriod)) { + // Either the observed vsync is closer to the pending period, (and + // thus we detected a period change), or the period change will + // no-op. In either case, reset the model and flush the pending + // period. resetLocked(); + mIntendedPeriod = mPendingPeriod; mPeriod = mPendingPeriod; mPendingPeriod = 0; if (mTraceDetailedInfo) { ATRACE_INT("DispSync:PendingPeriod", mPendingPeriod); + ATRACE_INT("DispSync:IntendedPeriod", mIntendedPeriod); } - *periodChanged = true; + *periodFlushed = true; } } // Always update the reference time with the most recent timestamp. @@ -623,6 +626,7 @@ bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodChanged) { bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2) && mPendingPeriod == 0; ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked"); if (modelLocked) { + *periodFlushed = true; mThread->lockModel(); } return !modelLocked; @@ -657,10 +661,17 @@ status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) { void DispSync::setPeriod(nsecs_t period) { Mutex::Autolock lock(mMutex); + + const bool pendingPeriodShouldChange = + period != mIntendedPeriod || (period == mIntendedPeriod && mPendingPeriod != 0); + + if (pendingPeriodShouldChange) { + mPendingPeriod = period; + } if (mTraceDetailedInfo) { - ATRACE_INT("DispSync:PendingPeriod", period); + ATRACE_INT("DispSync:IntendedPeriod", mIntendedPeriod); + ATRACE_INT("DispSync:PendingPeriod", mPendingPeriod); } - mPendingPeriod = period; } nsecs_t DispSync::getPeriod() { @@ -778,6 +789,9 @@ void DispSync::resetErrorLocked() { mPresentSampleOffset = 0; mError = 0; mZeroErrSamplesCount = 0; + if (mTraceDetailedInfo) { + ATRACE_INT64("DispSync:Error", mError); + } for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) { mPresentFences[i] = FenceTime::NO_FENCE; } diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h index 8f8b8e7a99..3e33c7edc0 100644 --- a/services/surfaceflinger/Scheduler/DispSync.h +++ b/services/surfaceflinger/Scheduler/DispSync.h @@ -49,7 +49,7 @@ public: virtual void reset() = 0; virtual bool addPresentFence(const std::shared_ptr&) = 0; virtual void beginResync() = 0; - virtual bool addResyncSample(nsecs_t timestamp, bool* periodChanged) = 0; + virtual bool addResyncSample(nsecs_t timestamp, bool* periodFlushed) = 0; virtual void endResync() = 0; virtual void setPeriod(nsecs_t period) = 0; virtual nsecs_t getPeriod() = 0; @@ -120,17 +120,19 @@ public: // from the hardware vsync events. void beginResync() override; // Adds a vsync sample to the dispsync model. The timestamp is the time - // of the vsync event that fired. periodChanged will return true if the + // of the vsync event that fired. periodFlushed will return true if the // vsync period was detected to have changed to mPendingPeriod. // // This method will return true if more vsync samples are needed to lock // down the DispSync model, and false otherwise. - bool addResyncSample(nsecs_t timestamp, bool* periodChanged) override; + // periodFlushed will be set to true if mPendingPeriod is flushed to + // mIntendedPeriod, and false otherwise. + bool addResyncSample(nsecs_t timestamp, bool* periodFlushed) override; void endResync() override; // The setPeriod method sets the vsync event model's period to a specific - // value. This should be used to prime the model when a display is first - // turned on. It should NOT be used after that. + // value. This should be used to prime the model when a display is first + // turned on, or when a refresh rate change is requested. void setPeriod(nsecs_t period) override; // The getPeriod method returns the current vsync period. @@ -205,6 +207,11 @@ private: // nanoseconds. nsecs_t mPeriod; + // mIntendedPeriod is the intended period of the modeled vsync events in + // nanoseconds. Under ideal conditions this should be similar if not the + // same as mPeriod, plus or minus an observed error. + nsecs_t mIntendedPeriod = 0; + // mPendingPeriod is the proposed period change in nanoseconds. // If mPendingPeriod differs from mPeriod and is nonzero, it will // be flushed to mPeriod when we detect that the hardware switched @@ -236,8 +243,8 @@ private: // process to store information about the hardware vsync event times used // to compute the model. nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES] = {0}; - size_t mFirstResyncSample; - size_t mNumResyncSamples; + size_t mFirstResyncSample = 0; + size_t mNumResyncSamples = 0; int mNumResyncSamplesSincePresent; // These member variables store information about the present fences used diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 7a040aa305..afcf3d45ba 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -283,13 +283,13 @@ void Scheduler::setVsyncPeriod(const nsecs_t period) { } } -void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodChanged) { +void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodFlushed) { bool needsHwVsync = false; - *periodChanged = false; + *periodFlushed = false; { // Scope for the lock std::lock_guard lock(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { - needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodChanged); + needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodFlushed); } } @@ -418,7 +418,7 @@ void Scheduler::resetKernelTimerCallback() { ATRACE_INT("ExpiredKernelIdleTimer", 0); std::lock_guard lock(mCallbackLock); if (mGetVsyncPeriod) { - resyncToHardwareVsync(false, mGetVsyncPeriod()); + resyncToHardwareVsync(true, mGetVsyncPeriod()); } } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index f5a3a0891d..6b5a8b715d 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -136,13 +136,18 @@ public: void enableHardwareVsync(); void disableHardwareVsync(bool makeUnavailable); + // Resyncs the scheduler to hardware vsync. + // If makeAvailable is true, then hardware vsync will be turned on. + // Otherwise, if hardware vsync is not already enabled then this method will + // no-op. + // The period is the vsync period from the current display configuration. void resyncToHardwareVsync(bool makeAvailable, nsecs_t period); // Creates a callback for resyncing. ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod); void setRefreshSkipCount(int count); - // Passes a vsync sample to DispSync. periodChange will be true if DipSync - // detected that the vsync period changed, and false otherwise. - void addResyncSample(const nsecs_t timestamp, bool* periodChanged); + // Passes a vsync sample to DispSync. periodFlushed will be true if + // DispSync detected that the vsync period changed, and false otherwise. + void addResyncSample(const nsecs_t timestamp, bool* periodFlushed); void addPresentFence(const std::shared_ptr& fenceTime); void setIgnorePresentFences(bool ignore); nsecs_t expectedPresentTime(); diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 72f90505c6..41c3a3a605 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -121,7 +121,7 @@ public: // Called when we detect from vsync signals that the refresh rate changed. // This way we can move out of early offsets if no longer necessary. - void onRefreshRateChangeDetected() { + void onRefreshRateChangeCompleted() { if (!mRefreshRateChangePending) { return; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0cf84a952d..6d731042ac 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -940,9 +940,14 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { // Start receiving vsync samples now, so that we can detect a period // switch. mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); + // We should only move to early offsets when we know that the refresh + // rate will change. Otherwise, we may be stuck in early offsets + // forever, as onRefreshRateChangeDetected will not be called. + if (mDesiredActiveConfig.event == Scheduler::ConfigEvent::Changed) { + mVsyncModulator.onRefreshRateChangeInitiated(); + } mPhaseOffsets->setRefreshRateType(info.type); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.onRefreshRateChangeInitiated(); mVsyncModulator.setPhaseOffsets(early, gl, late); } mDesiredActiveConfigChanged = true; @@ -1019,6 +1024,10 @@ bool SurfaceFlinger::performSetActiveConfig() { std::lock_guard lock(mActiveConfigLock); mDesiredActiveConfig.event = Scheduler::ConfigEvent::None; mDesiredActiveConfigChanged = false; + // Update scheduler with the correct vsync period as a no-op. + // Otherwise, there exists a race condition where we get stuck in the + // incorrect vsync period. + mScheduler->resyncToHardwareVsync(false, getVsyncPeriod()); ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); return false; } @@ -1031,6 +1040,10 @@ bool SurfaceFlinger::performSetActiveConfig() { mDesiredActiveConfig.event = Scheduler::ConfigEvent::None; mDesiredActiveConfig.configId = display->getActiveConfig(); mDesiredActiveConfigChanged = false; + // Update scheduler with the current vsync period as a no-op. + // Otherwise, there exists a race condition where we get stuck in the + // incorrect vsync period. + mScheduler->resyncToHardwareVsync(false, getVsyncPeriod()); ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); return false; } @@ -1454,10 +1467,10 @@ void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDispl return; } - bool periodChanged = false; - mScheduler->addResyncSample(timestamp, &periodChanged); - if (periodChanged) { - mVsyncModulator.onRefreshRateChangeDetected(); + bool periodFlushed = false; + mScheduler->addResyncSample(timestamp, &periodFlushed); + if (periodFlushed) { + mVsyncModulator.onRefreshRateChangeCompleted(); } } diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h index 12a349dd76..9ca116d735 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h +++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h @@ -35,6 +35,7 @@ public: MOCK_METHOD0(endResync, void()); MOCK_METHOD1(setPeriod, void(nsecs_t)); MOCK_METHOD0(getPeriod, nsecs_t()); + MOCK_METHOD0(getIntendedPeriod, nsecs_t()); MOCK_METHOD1(setRefreshSkipCount, void(int)); MOCK_CONST_METHOD1(computeNextRefresh, nsecs_t(int)); MOCK_METHOD1(setIgnorePresentFences, void(bool)); -- GitLab From baa35b0e2f71a3ca2bb2fbb3f71b1f7cf4447bdd Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 30 May 2019 17:59:36 -0700 Subject: [PATCH 0195/1255] SurfaceFlinger: do not force HDR content to default refresh rate Now that HWC supports HDR content at 90Hz there is no need to override from the platform side. Test: Youtube with HDR video Bug: 129694529 Change-Id: If59bab3d40c783843f3c1d2312a5768a8af2b921 (cherry picked from commit 8444c3642b469a3ec8074bf2fabd2d22abd3f9b3) Merged-In: If59bab3d40c783843f3c1d2312a5768a8af2b921 --- services/surfaceflinger/Scheduler/Scheduler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 6b5a8b715d..597f9a2878 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -299,7 +299,7 @@ private: const scheduler::RefreshRateConfigs& mRefreshRateConfigs; // Global config to force HDR content to work on DEFAULT refreshRate - static constexpr bool mForceHDRContentToDefaultRefreshRate = true; + static constexpr bool mForceHDRContentToDefaultRefreshRate = false; }; } // namespace android -- GitLab From 48630145d44081eb4f3b189bb32748da6eab98a9 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 3 Jun 2019 17:10:55 -0700 Subject: [PATCH 0196/1255] SurfaceFlinger: HWVsync when display is off HWC expects that HWVsync will not be turned on if display if off. To ensure that we move enabling/disabling of HWVsync to the main thread and caching the latest request in case the display is off. When the display is turned on again we apply the latest state of HWVsync. Bug: 134050982 Test: Toggle screen on/off in a loop Change-Id: Ib87f885f95195b8bb402d5a5b2c75f20e213d2aa (cherry picked from commit 9ba25125f9ced03fc3f96a111d2987494d074d57) Merged-In: Ib87f885f95195b8bb402d5a5b2c75f20e213d2aa --- services/surfaceflinger/SurfaceFlinger.cpp | 26 +++++++++++++++++++--- services/surfaceflinger/SurfaceFlinger.h | 6 +++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6d731042ac..157fc9e62f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1543,10 +1543,25 @@ void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDispl void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) { ATRACE_CALL(); - Mutex::Autolock lock(mStateLock); + + // Enable / Disable HWVsync from the main thread to avoid race conditions with + // display power state. + postMessageAsync(new LambdaMessage( + [=]() NO_THREAD_SAFETY_ANALYSIS { setPrimaryVsyncEnabledInternal(enabled); })); +} + +void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) { + ATRACE_CALL(); + if (const auto displayId = getInternalDisplayIdLocked()) { - getHwComposer().setVsyncEnabled(*displayId, - enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable); + sp display = getDefaultDisplayDeviceLocked(); + if (display && display->isPoweredOn()) { + getHwComposer().setVsyncEnabled(*displayId, + enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable); + } else { + // Cache the latest vsync state and apply it when screen is on again + mEnableHWVsyncScreenOn = enabled; + } } } @@ -4451,6 +4466,11 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, int // Turn on the display getHwComposer().setPowerMode(*displayId, mode); if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) { + if (mEnableHWVsyncScreenOn) { + setPrimaryVsyncEnabledInternal(mEnableHWVsyncScreenOn); + mEnableHWVsyncScreenOn = false; + } + mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 40941f2140..3e1d42c615 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -293,6 +293,9 @@ public: // TODO: this should be made accessible only to EventThread void setPrimaryVsyncEnabled(bool enabled); + // main thread function to enable/disable h/w composer event + void setPrimaryVsyncEnabledInternal(bool enabled); + // called on the main thread by MessageQueue when an internal message // is received // TODO: this should be made accessible only to MessageQueue @@ -1169,6 +1172,9 @@ private: // The Layer pointer is removed from the set when the destructor is called so there shouldn't // be any issues with a raw pointer referencing an invalid object. std::unordered_set mOffscreenLayers; + + // Flag to indicate whether to re-enable HWVsync when screen is on + bool mEnableHWVsyncScreenOn = false; }; } // namespace android -- GitLab From 746654af879429b1d5b3606d78e31444ff6b6b99 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 6 Jun 2019 13:28:34 -0700 Subject: [PATCH 0197/1255] [SurfaceFlinger] correct present time for negative phase offsets DispSync::expectedPresentTime returns the expected presentation time for the current frame, but when we're in negative offsets we are targetting the following frame instead. Bug: 133241520 Bug: 134589085 Test: systrace when flinging through news Change-Id: I7cc05a0b9e8e9b5c3e8d0c4b1d59b0a7dabd43d4 (cherry picked from commit aa61419b69daed4794c593f0718b3330ee2ec8dc) Merged-In: I7cc05a0b9e8e9b5c3e8d0c4b1d59b0a7dabd43d4 --- services/surfaceflinger/BufferQueueLayer.cpp | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 15 +++++++++++++-- services/surfaceflinger/SurfaceFlinger.h | 5 +++++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index bd0b55f688..57f1008e85 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -143,7 +143,7 @@ bool BufferQueueLayer::framePresentTimeIsCurrent() const { } Mutex::Autolock lock(mQueueItemLock); - return mQueueItems[0].mTimestamp <= mFlinger->mScheduler->expectedPresentTime(); + return mQueueItems[0].mTimestamp <= mFlinger->getExpectedPresentTime(); } nsecs_t BufferQueueLayer::getDesiredPresentTime() { diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 05c721f141..203bd72e6f 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -380,7 +380,7 @@ bool BufferStateLayer::framePresentTimeIsCurrent() const { return true; } - return mDesiredPresentTime <= mFlinger->mScheduler->expectedPresentTime(); + return mDesiredPresentTime <= mFlinger->getExpectedPresentTime(); } nsecs_t BufferStateLayer::getDesiredPresentTime() { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 157fc9e62f..853763cd46 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1671,6 +1671,18 @@ bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS { return fence != Fence::NO_FENCE && (fence->getStatus() == Fence::Status::Unsignaled); } +nsecs_t SurfaceFlinger::getExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS { + DisplayStatInfo stats; + mScheduler->getDisplayStatInfo(&stats); + const nsecs_t presentTime = mScheduler->expectedPresentTime(); + // Inflate the expected present time if we're targetting the next vsync. + const nsecs_t correctedTime = + mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync() + ? presentTime + : presentTime + stats.vsyncPeriod; + return correctedTime; +} + void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { ATRACE_CALL(); switch (what) { @@ -3279,8 +3291,7 @@ bool SurfaceFlinger::handlePageFlip() mDrawingState.traverseInZOrder([&](Layer* layer) { if (layer->hasReadyFrame()) { frameQueued = true; - nsecs_t expectedPresentTime; - expectedPresentTime = mScheduler->expectedPresentTime(); + const nsecs_t expectedPresentTime = getExpectedPresentTime(); if (layer->shouldPresentNow(expectedPresentTime)) { mLayersWithQueuedFrames.push_back(layer); } else { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 3e1d42c615..c09998d32e 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -301,6 +301,11 @@ public: // TODO: this should be made accessible only to MessageQueue void onMessageReceived(int32_t what); + // Returns the expected present time for this frame. + // When we are in negative offsets, we perform a correction so that the + // predicted vsync for the *next* frame is used instead. + nsecs_t getExpectedPresentTime(); + // for debugging only // TODO: this should be made accessible only to HWComposer const Vector>& getLayerSortedByZForHwcDisplay(DisplayId displayId); -- GitLab From 0ff5e8c4b7dfcecba0810eaf5677689a7314a4de Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Sat, 1 Jun 2019 18:51:35 -0700 Subject: [PATCH 0198/1255] [SurfaceFlinger] support EGLImage management in BLAST This mirrors a performance optimization for BufferQueueLayers where EGLImages were allocated in onFrameAvailable. Here when buffers are passed over to SurfaceFlinger in a transaction, an EGLImage is also created for that buffer. This is critical for reducing jank when operating in higher refresh rates, as eglCreateImageKHR can take long enough for frames to miss. Bug: 133627730 Test: systrace of chrome in landscope orientation caches properly Change-Id: I2022564fbecace7cadd00c89abdcc358d6323315 (cherry picked from commit 1c8d7209992582fcfef020d75c990565dee1c71d) Merged-In: I2022564fbecace7cadd00c89abdcc358d6323315 --- services/surfaceflinger/BufferStateLayer.cpp | 15 ++++----------- services/surfaceflinger/BufferStateLayer.h | 4 +++- services/surfaceflinger/Layer.h | 16 +++++++++------- services/surfaceflinger/SurfaceFlinger.cpp | 3 +++ 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 05c721f141..bcc9915099 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -50,12 +50,6 @@ BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; mCurrentState.dataspace = ui::Dataspace::V0_SRGB; } -BufferStateLayer::~BufferStateLayer() { - if (mActiveBuffer != nullptr) { - auto& engine(mFlinger->getRenderEngine()); - engine.unbindExternalTextureBuffer(mActiveBuffer->getId()); - } -} // ----------------------------------------------------------------------- // Interface implementation for Layer @@ -571,11 +565,6 @@ status_t BufferStateLayer::updateActiveBuffer() { return BAD_VALUE; } - if (mActiveBuffer != nullptr) { - // todo: get this to work with BufferStateLayerCache - auto& engine(mFlinger->getRenderEngine()); - engine.unbindExternalTextureBuffer(mActiveBuffer->getId()); - } mActiveBuffer = s.buffer; mActiveBufferFence = s.acquireFence; auto& layerCompositionState = getCompositionLayer()->editState().frontEnd; @@ -621,6 +610,10 @@ void BufferStateLayer::onFirstRef() { } } +void BufferStateLayer::bufferErased(const client_cache_t& clientCacheId) { + mFlinger->getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id); +} + void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) { std::lock_guard lock(mMutex); if (!clientCacheId.isValid()) { diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 4e2bc45287..db8ae0d337 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -34,7 +34,6 @@ class SlotGenerationTest; class BufferStateLayer : public BufferLayer { public: explicit BufferStateLayer(const LayerCreationArgs&); - ~BufferStateLayer() override; // ----------------------------------------------------------------------- // Interface implementation for Layer @@ -103,6 +102,9 @@ public: bool fenceHasSignaled() const override; bool framePresentTimeIsCurrent() const override; + // Inherit from ClientCache::ErasedRecipient + void bufferErased(const client_cache_t& clientCacheId) override; + private: nsecs_t getDesiredPresentTime() override; std::shared_ptr getCurrentFenceTime() const override; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 8a80e15f29..ec7389ebad 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -17,8 +17,6 @@ #ifndef ANDROID_LAYER_H #define ANDROID_LAYER_H -#include - #include #include #include @@ -28,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -44,16 +43,16 @@ #include #include "Client.h" +#include "ClientCache.h" +#include "DisplayHardware/ComposerHal.h" +#include "DisplayHardware/HWComposer.h" #include "FrameTracker.h" #include "LayerVector.h" #include "MonitoredProducer.h" +#include "RenderArea.h" #include "SurfaceFlinger.h" #include "TransactionCompletedThread.h" -#include "DisplayHardware/ComposerHal.h" -#include "DisplayHardware/HWComposer.h" -#include "RenderArea.h" - using namespace android::surfaceflinger; namespace android { @@ -94,7 +93,7 @@ struct LayerCreationArgs { LayerMetadata metadata; }; -class Layer : public virtual compositionengine::LayerFE { +class Layer : public virtual compositionengine::LayerFE, public ClientCache::ErasedRecipient { static std::atomic sSequence; public: @@ -701,6 +700,9 @@ public: compositionengine::OutputLayer* findOutputLayerForDisplay( const sp& display) const; + // Inherit from ClientCache::ErasedRecipient + void bufferErased(const client_cache_t& /*clientCacheId*/) override {} + protected: // constant sp mFlinger; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6d731042ac..31687caad2 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4142,6 +4142,9 @@ uint32_t SurfaceFlinger::setClientStateLocked( sp buffer; if (bufferChanged && cacheIdChanged) { ClientCache::getInstance().add(s.cachedBuffer, s.buffer); + ClientCache::getInstance().registerErasedRecipient(s.cachedBuffer, + wp(layer)); + getRenderEngine().cacheExternalTextureBuffer(s.buffer); buffer = s.buffer; } else if (cacheIdChanged) { buffer = ClientCache::getInstance().get(s.cachedBuffer); -- GitLab From 66a877723cc8019ec828a3fc8372d364f02384df Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Mon, 24 Jun 2019 16:30:00 -0700 Subject: [PATCH 0199/1255] Support noted appops collection in native code With change I96ded4a8d8d9bcb37a4555d9b1281cb57945ffa9 the system now allows apps to collect all app-ops that are noted for them. Native code can also note app-op. Unfortunately there is no guaranteed way how an app's native code can interact with java code that might or might not be running in the same process. Hence we cannot support sending the noted app-ops back to the caller over binders. Hence all notes app-ops will need to be collected as AsyncNotedOps Test: atest CtsAppOpsTestCases (includes tests that note app-ops natively) Bug: 136505050 Change-Id: I5dc479468c8dae3b10f071123b0535a288bf8662 --- libs/binder/Android.bp | 2 - libs/binder/AppOpsManager.cpp | 86 ++++++++++++++++++++- libs/binder/IAppOpsService.cpp | 62 ++++++++++++++- libs/binder/include/binder/AppOpsManager.h | 35 +++++++-- libs/binder/include/binder/IAppOpsService.h | 15 ++-- 5 files changed, 184 insertions(+), 16 deletions(-) diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 027418a035..0b71d1f60c 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -86,10 +86,8 @@ cc_library_shared { vendor: { exclude_srcs: [ "ActivityManager.cpp", - "AppOpsManager.cpp", "IActivityManager.cpp", "IAppOpsCallback.cpp", - "IAppOpsService.cpp", "IBatteryStats.cpp", "IMediaResourceMonitor.cpp", "IPermissionController.cpp", diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index 525685c35e..48b218e78b 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -21,10 +21,18 @@ #include +#include + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "AppOpsManager" + namespace android { namespace { +#ifndef __ANDROID_VNDK__ #if defined(__BRILLO__) // Because Brillo has no application model, security policy is managed // statically (at build time) with SELinux controls. @@ -33,13 +41,17 @@ const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_ALLOWED; #else const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_IGNORED; #endif // defined(__BRILLO__) +#endif // __ANDROID_VNDK__ } // namespace static String16 _appops("appops"); +#ifndef __ANDROID_VNDK__ static pthread_mutex_t gTokenMutex = PTHREAD_MUTEX_INITIALIZER; +#endif // __ANDROID_VNDK__ static sp gToken; +#ifndef __ANDROID_VNDK__ static const sp& getToken(const sp& service) { pthread_mutex_lock(&gTokenMutex); if (gToken == nullptr || gToken->pingBinder() != NO_ERROR) { @@ -48,6 +60,17 @@ static const sp& getToken(const sp& service) { pthread_mutex_unlock(&gTokenMutex); return gToken; } +#endif // __ANDROID_VNDK__ + +thread_local uint64_t notedAppOpsInThisBinderTransaction[2]; +thread_local int32_t uidOfThisBinderTransaction = -1; + +// Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note +#ifndef __ANDROID_VNDK__ +uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0}; +#else +uint8_t appOpsToNote[128] = {0}; +#endif // __ANDROID_VNDK__ AppOpsManager::AppOpsManager() { @@ -85,6 +108,7 @@ sp AppOpsManager::getService() } #endif // defined(__BRILLO__) +#ifndef __ANDROID_VNDK__ int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage) { sp service = getService(); @@ -102,18 +126,41 @@ int32_t AppOpsManager::checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t ui } int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) { + return noteOp(op, uid, callingPackage, String16("noteOp from native code")); +} + +int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage, + const String16& message) { sp service = getService(); - return service != nullptr + int32_t mode = service != nullptr ? service->noteOperation(op, uid, callingPackage) : APP_OPS_MANAGER_UNAVAILABLE_MODE; + + if (mode == AppOpsManager::MODE_ALLOWED) { + markAppOpNoted(uid, callingPackage, op, message); + } + + return mode; } int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, bool startIfModeDefault) { + return startOpNoThrow(op, uid, callingPackage, startIfModeDefault, + String16("startOpNoThrow from native code")); +} + +int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, + bool startIfModeDefault, const String16& message) { sp service = getService(); - return service != nullptr + int32_t mode = service != nullptr ? service->startOperation(getToken(service), op, uid, callingPackage, startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE; + + if (mode == AppOpsManager::MODE_ALLOWED) { + markAppOpNoted(uid, callingPackage, op, message); + } + + return mode; } void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) { @@ -146,5 +193,40 @@ int32_t AppOpsManager::permissionToOpCode(const String16& permission) { return -1; } +#endif // __ANDROID_VNDK__ + +bool AppOpsManager::shouldCollectNotes(int32_t opcode) { + sp service = getService(); + if (service != nullptr) { + return service->shouldCollectNotes(opcode); + } + return false; +} + +void AppOpsManager::markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode, + const String16& message) { + // check it the appops needs to be collected and cache result + if (appOpsToNote[opCode] == 0) { + if (shouldCollectNotes(opCode)) { + appOpsToNote[opCode] = 2; + } else { + appOpsToNote[opCode] = 1; + } + } + + if (appOpsToNote[opCode] != 2) { + return; + } + + noteAsyncOp(String16(), uid, packageName, opCode, message); +} + +void AppOpsManager::noteAsyncOp(const String16& callingPackageName, int32_t uid, + const String16& packageName, int32_t opCode, const String16& message) { + sp service = getService(); + if (service != nullptr) { + return service->noteAsyncOp(callingPackageName, uid, packageName, opCode, message); + } +} }; // namespace android diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index c426f3a31f..8840990824 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -34,6 +34,7 @@ public: { } +#ifndef __ANDROID_VNDK__ virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); @@ -111,7 +112,6 @@ public: return reply.readStrongBinder(); } - virtual int32_t permissionToOpCode(const String16& permission) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); @@ -137,6 +137,45 @@ public: } return reply.readInt32(); } + +#endif + virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid, + const String16& packageName, int32_t opCode, const String16& message) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + + // Convert empty callingPackage into null string + if (callingPackageName.size() != 0) { + data.writeString16(callingPackageName); + } else { + data.writeString16(nullptr, 0); + } + + data.writeInt32(uid); + + // Convert empty packageName into null string + if (packageName.size() != 0) { + data.writeString16(packageName); + } else { + data.writeString16(nullptr, 0); + } + + data.writeInt32(opCode); + data.writeString16(message); + remote()->transact(NOTE_ASYNC_OP_TRANSACTION, data, &reply); + } + + virtual bool shouldCollectNotes(int32_t opCode) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + data.writeInt32(opCode); + remote()->transact(SHOULD_COLLECT_NOTES_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) { + return false; + } + return reply.readBool(); + } }; IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService"); @@ -149,6 +188,7 @@ status_t BnAppOpsService::onTransact( { //printf("AppOpsService received: "); data.print(); switch(code) { +#ifndef __ANDROID_VNDK__ case CHECK_OPERATION_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); int32_t code = data.readInt32(); @@ -234,6 +274,26 @@ status_t BnAppOpsService::onTransact( reply->writeInt32(res); return NO_ERROR; } break; +#endif // __ANDROID_VNDK__ + case NOTE_ASYNC_OP_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + String16 callingPackageName = data.readString16(); + int32_t uid = data.readInt32(); + String16 packageName = data.readString16(); + int32_t opCode = data.readInt32(); + String16 message = data.readString16(); + noteAsyncOp(callingPackageName, uid, packageName, opCode, message); + reply->writeNoException(); + return NO_ERROR; + } break; + case SHOULD_COLLECT_NOTES_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + int32_t opCode = data.readInt32(); + bool shouldCollect = shouldCollectNotes(opCode); + reply->writeNoException(); + reply->writeBool(shouldCollect); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index 17493b4252..7a99396eef 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -17,8 +17,6 @@ #ifndef ANDROID_APP_OPS_MANAGER_H #define ANDROID_APP_OPS_MANAGER_H -#ifndef __ANDROID_VNDK__ - #include #include @@ -35,6 +33,7 @@ public: MODE_ERRORED = IAppOpsService::MODE_ERRORED }; +#ifndef __ANDROID_VNDK__ enum { OP_NONE = -1, OP_COARSE_LOCATION = 0, @@ -109,34 +108,58 @@ public: OP_START_FOREGROUND = 76, OP_BLUETOOTH_SCAN = 77, OP_USE_BIOMETRIC = 78, + OP_ACTIVITY_RECOGNITION = 79, + OP_SMS_FINANCIAL_TRANSACTIONS = 80, + OP_READ_MEDIA_AUDIO = 81, + OP_WRITE_MEDIA_AUDIO = 82, + OP_READ_MEDIA_VIDEO = 83, + OP_WRITE_MEDIA_VIDEO = 84, + OP_READ_MEDIA_IMAGES = 85, + OP_WRITE_MEDIA_IMAGES = 86, + OP_LEGACY_STORAGE = 87, + OP_ACCESS_ACCESSIBILITY = 88, + OP_READ_DEVICE_IDENTIFIERS = 89, + _NUM_OP = 90 }; +#endif // __ANDROID_VNDK__ AppOpsManager(); +#ifndef __ANDROID_VNDK__ int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage); int32_t checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid, const String16& callingPackage); + // @Deprecated, use noteOp(int32_t, int32_t uid, const String16&, const String16&) instead int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage); + int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage, + const String16& message); + // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&) + // instead int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, bool startIfModeDefault); + int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, + bool startIfModeDefault, const String16& message); void finishOp(int32_t op, int32_t uid, const String16& callingPackage); void startWatchingMode(int32_t op, const String16& packageName, const sp& callback); void stopWatchingMode(const sp& callback); int32_t permissionToOpCode(const String16& permission); - +#endif // __ANDROID_VNDK__ + void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, + int32_t opCode, const String16& message); private: Mutex mLock; sp mService; sp getService(); + void markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode, + const String16& message); + bool shouldCollectNotes(int32_t opCode); }; }; // namespace android + // --------------------------------------------------------------------------- -#else // __ANDROID_VNDK__ -#error "This header is not visible to vendors" -#endif // __ANDROID_VNDK__ #endif // ANDROID_APP_OPS_MANAGER_H diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index 3dbd0d9f7a..9d02370015 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -19,8 +19,8 @@ #define ANDROID_IAPP_OPS_SERVICE_H #ifndef __ANDROID_VNDK__ - #include +#endif #include namespace android { @@ -32,6 +32,7 @@ class IAppOpsService : public IInterface public: DECLARE_META_INTERFACE(AppOpsService) +#ifndef __ANDROID_VNDK__ virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, @@ -45,8 +46,13 @@ public: virtual int32_t permissionToOpCode(const String16& permission) = 0; virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid, const String16& packageName) = 0; +#endif // __ANDROID_VNDK__ + virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid, + const String16& packageName, int32_t opCode, const String16& message) = 0; + virtual bool shouldCollectNotes(int32_t opCode) = 0; enum { +#ifndef __ANDROID_VNDK__ CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, NOTE_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+1, START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2, @@ -56,6 +62,9 @@ public: GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6, PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7, CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8, +#endif // __ANDROID_VNDK__ + NOTE_ASYNC_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9, + SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10, }; enum { @@ -81,8 +90,4 @@ public: }; // namespace android -#else // __ANDROID_VNDK__ -#error "This header is not visible to vendors" -#endif // __ANDROID_VNDK__ - #endif // ANDROID_IAPP_OPS_SERVICE_H -- GitLab From f629f10f62ab695aa0a154aca9a6a53aae476163 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 6 Aug 2019 18:16:23 -0700 Subject: [PATCH 0200/1255] [ANativeWindow] Test with a TestableSurface TestableSurface is the same as a Surface but with hooks into protected members so that tests can verify that any internal state returned by the ANativeWindow interface is in fact correct. Bug: 137012161 Test: atest Change-Id: I4320cdee35ec9b523d6b321d22a13f7e61f1a77c --- libs/nativewindow/tests/ANativeWindowTest.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp index a80da24a47..5247e04c32 100644 --- a/libs/nativewindow/tests/ANativeWindowTest.cpp +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -29,6 +29,15 @@ using namespace android; +class TestableSurface final : public Surface { +public: + explicit TestableSurface(const sp& bufferProducer) + : Surface(bufferProducer) {} + + // Exposes the internal last dequeue duration that's stored on the Surface. + nsecs_t getLastDequeueDuration() const { return mLastDequeueDuration; } +}; + class ANativeWindowTest : public ::testing::Test { protected: void SetUp() override { @@ -37,7 +46,7 @@ protected: ALOGV("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); BufferQueue::createBufferQueue(&mProducer, &mConsumer); mItemConsumer = new BufferItemConsumer(mConsumer, GRALLOC_USAGE_SW_READ_OFTEN); - mWindow = new Surface(mProducer); + mWindow = new TestableSurface(mProducer); const int success = native_window_api_connect(mWindow.get(), NATIVE_WINDOW_API_CPU); EXPECT_EQ(0, success); } @@ -52,12 +61,14 @@ protected: sp mProducer; sp mConsumer; sp mItemConsumer; - sp mWindow; + + sp mWindow; }; TEST_F(ANativeWindowTest, getLastDequeueDuration_noDequeue_returnsZero) { int result = ANativeWindow_getLastDequeueDuration(mWindow.get()); EXPECT_EQ(0, result); + EXPECT_EQ(0, mWindow->getLastDequeueDuration() / 1000); } TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) { @@ -69,4 +80,5 @@ TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) { result = ANativeWindow_getLastDequeueDuration(mWindow.get()); EXPECT_GT(result, 0); + EXPECT_EQ(result, mWindow->getLastDequeueDuration() / 1000); } -- GitLab From 2e1608ff49148a8d99c2e33897fa0e5c3ce532c2 Mon Sep 17 00:00:00 2001 From: Mikael Pessa Date: Fri, 19 Jul 2019 11:25:35 -0700 Subject: [PATCH 0201/1255] Add per-buffer perfetto trace points for SurfaceFlinger frame events In order to track how buffers move through the system, we add per-buffer perfetto trace points for SurfaceFlinger. The majority of these were already tracked through TimeStats, so the new tracing was built on top of TimeStats. Test: atest libsurfaceflinger_unittest Run trace with: { adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/trace <& displayId, if (presentFence->isValid()) { mFlinger->mTimeStats->setPresentFence(layerID, mCurrentFrameNumber, presentFence); + mFlinger->mTimeStats->traceFence(layerID, getCurrentBufferId(), mCurrentFrameNumber, + presentFence, TimeStats::FrameEvent::PRESENT_FENCE); mFrameTracker.setActualPresentFence(std::shared_ptr(presentFence)); } else if (displayId && mFlinger->getHwComposer().isConnected(*displayId)) { // The HWC doesn't support present fences, so use the refresh // timestamp instead. const nsecs_t actualPresentTime = mFlinger->getHwComposer().getRefreshTimestamp(*displayId); mFlinger->mTimeStats->setPresentTime(layerID, mCurrentFrameNumber, actualPresentTime); + mFlinger->mTimeStats->traceTimestamp(layerID, getCurrentBufferId(), mCurrentFrameNumber, + actualPresentTime, + TimeStats::FrameEvent::PRESENT_FENCE); mFrameTracker.setActualPresentTime(actualPresentTime); } diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 5f494ff3d5..6cad3c7d07 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -45,6 +45,14 @@ BufferQueueLayer::~BufferQueueLayer() { void BufferQueueLayer::onLayerDisplayed(const sp& releaseFence) { mConsumer->setReleaseFence(releaseFence); + + // Prevent tracing the same release multiple times. + if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) { + mFlinger->mTimeStats->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber, + std::make_shared(releaseFence), + TimeStats::FrameEvent::RELEASE_FENCE); + mPreviousReleasedFrameNumber = mPreviousFrameNumber; + } } void BufferQueueLayer::setTransformHint(uint32_t orientation) const { @@ -355,9 +363,15 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t mQueuedFrames--; } + uint64_t bufferID = mQueueItems[0].mGraphicBuffer->getId(); mFlinger->mTimeStats->setAcquireFence(layerID, currentFrameNumber, mQueueItems[0].mFenceTime); + mFlinger->mTimeStats->traceFence(layerID, bufferID, currentFrameNumber, + mQueueItems[0].mFenceTime, + TimeStats::FrameEvent::ACQUIRE_FENCE); mFlinger->mTimeStats->setLatchTime(layerID, currentFrameNumber, latchTime); + mFlinger->mTimeStats->traceTimestamp(layerID, bufferID, currentFrameNumber, latchTime, + TimeStats::FrameEvent::LATCH); mQueueItems.removeAt(0); } @@ -373,6 +387,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t status_t BufferQueueLayer::updateActiveBuffer() { // update the active buffer + mPreviousBufferId = getCurrentBufferId(); mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence); auto& layerCompositionState = getCompositionLayer()->editState().frontEnd; layerCompositionState.buffer = mActiveBuffer; @@ -413,6 +428,11 @@ void BufferQueueLayer::latchPerFrameState( // ----------------------------------------------------------------------- void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { + const int32_t layerID = getSequence(); + mFlinger->mTimeStats->traceNewLayer(layerID, getName().c_str()); + mFlinger->mTimeStats->traceTimestamp(layerID, item.mGraphicBuffer->getId(), item.mFrameNumber, + systemTime(), TimeStats::FrameEvent::POST); + ATRACE_CALL(); // Add this buffer from our internal queue tracker { // Autolock scope diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 3bc625e462..bf3f917196 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -128,6 +128,9 @@ private: uint64_t mPreviousFrameNumber{0}; bool mUpdateTexImageFailed{false}; + uint64_t mPreviousBufferId = 0; + uint64_t mPreviousReleasedFrameNumber = 0; + // Local copy of the queued contents of the incoming BufferQueue mutable Mutex mQueueItemLock; Condition mQueueItemCondition; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index e0804ff50e..4a8261d99f 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -87,6 +87,14 @@ void BufferStateLayer::onLayerDisplayed(const sp& releaseFence) { break; } } + + // Prevent tracing the same release multiple times. + if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) { + mFlinger->mTimeStats->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber, + std::make_shared(releaseFence), + TimeStats::FrameEvent::RELEASE_FENCE); + mPreviousReleasedFrameNumber = mPreviousFrameNumber; + } } void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const { @@ -226,7 +234,11 @@ bool BufferStateLayer::setBuffer(const sp& buffer, nsecs_t postTi mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); - mFlinger->mTimeStats->setPostTime(getSequence(), mFrameNumber, getName().c_str(), postTime); + const int32_t layerID = getSequence(); + mFlinger->mTimeStats->setPostTime(layerID, mFrameNumber, getName().c_str(), postTime); + mFlinger->mTimeStats->traceNewLayer(layerID, getName().c_str()); + mFlinger->mTimeStats->traceTimestamp(layerID, buffer->getId(), mFrameNumber, postTime, + TimeStats::FrameEvent::POST); mCurrentState.desiredPresentTime = desiredPresentTime; if (mFlinger->mUseSmart90ForVideo) { @@ -561,8 +573,13 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse } } + const uint64_t bufferID = getCurrentBufferId(); mFlinger->mTimeStats->setAcquireFence(layerID, mFrameNumber, getCurrentFenceTime()); + mFlinger->mTimeStats->traceFence(layerID, bufferID, mFrameNumber, getCurrentFenceTime(), + TimeStats::FrameEvent::ACQUIRE_FENCE); mFlinger->mTimeStats->setLatchTime(layerID, mFrameNumber, latchTime); + mFlinger->mTimeStats->traceTimestamp(layerID, bufferID, mFrameNumber, latchTime, + TimeStats::FrameEvent::LATCH); mCurrentStateModified = false; @@ -576,6 +593,7 @@ status_t BufferStateLayer::updateActiveBuffer() { return BAD_VALUE; } + mPreviousBufferId = getCurrentBufferId(); mActiveBuffer = s.buffer; mActiveBufferFence = s.acquireFence; auto& layerCompositionState = getCompositionLayer()->editState().frontEnd; @@ -586,6 +604,7 @@ status_t BufferStateLayer::updateActiveBuffer() { status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) { // TODO(marissaw): support frame history events + mPreviousFrameNumber = mCurrentFrameNumber; mCurrentFrameNumber = mFrameNumber; return NO_ERROR; } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index cc670087ac..c060ca8e76 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -156,6 +156,9 @@ private: mutable uint32_t mFrameNumber{0}; sp mPreviousReleaseFence; + uint64_t mPreviousBufferId = 0; + uint64_t mPreviousFrameNumber = 0; + uint64_t mPreviousReleasedFrameNumber = 0; mutable bool mCurrentStateModified = false; bool mReleasePreviousBuffer = false; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 9107189d52..aa3970eb3a 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -376,6 +376,14 @@ public: int32_t getSequence() const { return sequence; } + // For tracing. + // TODO: Replace with raw buffer id from buffer metadata when that becomes available. + // GraphicBuffer::getId() does not provide a reliable global identifier. Since the traces + // creates its tracks by buffer id and has no way of associating a buffer back to the process + // that created it, the current implementation is only sufficient for cases where a buffer is + // only used within a single layer. + uint64_t getCurrentBufferId() const { return mActiveBuffer ? mActiveBuffer->getId() : 0; } + // ----------------------------------------------------------------------- // Virtuals diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e8049239ba..6543089101 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -513,6 +513,8 @@ void SurfaceFlinger::bootFinished() const nsecs_t duration = now - mBootTime; ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); + mTimeStats->initializeTracing(); + // wait patiently for the window manager death const String16 name("window"); mWindowManager = defaultServiceManager()->getService(name); diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp new file mode 100644 index 0000000000..9e1d5033b2 --- /dev/null +++ b/services/surfaceflinger/TimeStats/Android.bp @@ -0,0 +1,15 @@ +cc_library_static { + name: "libtimestats", + defaults: ["surfaceflinger_defaults"], + srcs: [ + "TimeStats.cpp" + ], + export_include_dirs: ["."], + static_libs: [ + "libperfetto_client_experimental", + ], + shared_libs: [ + "libtimestats_proto", + "libui", + ], +} diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 3e3ab18e8f..b66e4cfe4f 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -30,10 +30,141 @@ #include #include +PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::impl::TimeStats::TimeStatsDataSource); + namespace android { namespace impl { +void TimeStats::initializeTracing() { + perfetto::TracingInitArgs args; + args.backends = perfetto::kSystemBackend; + perfetto::Tracing::Initialize(args); + registerTracingDataSource(); +} + +void TimeStats::registerTracingDataSource() { + perfetto::DataSourceDescriptor dsd; + dsd.set_name(kTimeStatsDataSource); + TimeStatsDataSource::Register(dsd); +} + +void TimeStats::traceNewLayer(int32_t layerID, const std::string& layerName) { + TimeStatsDataSource::Trace([this, layerID, &layerName](TimeStatsDataSource::TraceContext) { + if (mTraceTracker.find(layerID) == mTraceTracker.end()) { + std::lock_guard lock(mTraceMutex); + mTraceTracker[layerID].layerName = layerName; + } + }); +} + +void TimeStats::traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, + nsecs_t timestamp, FrameEvent::BufferEventType type, + nsecs_t duration) { + TimeStatsDataSource::Trace([this, layerID, bufferID, frameNumber, timestamp, type, + duration](TimeStatsDataSource::TraceContext ctx) { + std::lock_guard lock(mTraceMutex); + if (mTraceTracker.find(layerID) == mTraceTracker.end()) { + return; + } + + // Handle any pending fences for this buffer. + tracePendingFencesLocked(ctx, layerID, bufferID); + + // Complete current trace. + traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration); + }); +} + +void TimeStats::traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, + const std::shared_ptr& fence, + FrameEvent::BufferEventType type, nsecs_t startTime) { + TimeStatsDataSource::Trace([this, layerID, bufferID, frameNumber, &fence, type, + startTime](TimeStatsDataSource::TraceContext ctx) { + const nsecs_t signalTime = fence->getSignalTime(); + if (signalTime != Fence::SIGNAL_TIME_INVALID) { + std::lock_guard lock(mTraceMutex); + if (mTraceTracker.find(layerID) == mTraceTracker.end()) { + return; + } + + // Handle any pending fences for this buffer. + tracePendingFencesLocked(ctx, layerID, bufferID); + + if (signalTime != Fence::SIGNAL_TIME_PENDING) { + traceSpanLocked(ctx, layerID, bufferID, frameNumber, type, startTime, signalTime); + } else { + mTraceTracker[layerID].pendingFences[bufferID].push_back( + {.frameNumber = frameNumber, + .type = type, + .fence = fence, + .startTime = startTime}); + } + } + }); +} + +void TimeStats::tracePendingFencesLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, + uint64_t bufferID) { + if (mTraceTracker[layerID].pendingFences.count(bufferID)) { + auto& pendingFences = mTraceTracker[layerID].pendingFences[bufferID]; + for (size_t i = 0; i < pendingFences.size(); ++i) { + auto& pendingFence = pendingFences[i]; + + nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID; + if (pendingFence.fence && pendingFence.fence->isValid()) { + signalTime = pendingFence.fence->getSignalTime(); + if (signalTime == Fence::SIGNAL_TIME_PENDING) { + continue; + } + } + + if (signalTime != Fence::SIGNAL_TIME_INVALID && + systemTime() - signalTime < kFenceSignallingDeadline) { + traceSpanLocked(ctx, layerID, bufferID, pendingFence.frameNumber, pendingFence.type, + pendingFence.startTime, signalTime); + } + + pendingFences.erase(pendingFences.begin() + i); + --i; + } + } +} + +void TimeStats::traceLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, + uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp, + FrameEvent::BufferEventType type, nsecs_t duration) { + auto packet = ctx.NewTracePacket(); + packet->set_timestamp(timestamp); + auto* event = packet->set_graphics_frame_event()->set_buffer_event(); + event->set_buffer_id(static_cast(bufferID)); + event->set_frame_number(frameNumber); + event->set_type(type); + + if (mTraceTracker.find(layerID) != mTraceTracker.end() && + !mTraceTracker[layerID].layerName.empty()) { + const std::string& layerName = mTraceTracker[layerID].layerName; + event->set_layer_name(layerName.c_str(), layerName.size()); + } + + if (duration > 0) { + event->set_duration_ns(duration); + } +} + +void TimeStats::traceSpanLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, + uint64_t bufferID, uint64_t frameNumber, + FrameEvent::BufferEventType type, nsecs_t startTime, + nsecs_t endTime) { + nsecs_t timestamp = endTime; + nsecs_t duration = 0; + if (startTime > 0 && startTime < endTime) { + timestamp = startTime; + duration = endTime - startTime; + } + traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration); +} + void TimeStats::parseArgs(bool asProto, const Vector& args, std::string& result) { ATRACE_CALL(); @@ -76,6 +207,8 @@ std::string TimeStats::miniDump() { mTimeStatsTracker.size()); android::base::StringAppendF(&result, "Number of layers in the stats pool is %zu\n", mTimeStats.stats.size()); + android::base::StringAppendF(&result, "Number of layers currently being traced is %zu\n", + mTraceTracker.size()); return result; } @@ -407,14 +540,17 @@ void TimeStats::setPresentFence(int32_t layerID, uint64_t frameNumber, } void TimeStats::onDestroy(int32_t layerID) { - if (!mEnabled.load()) return; - ATRACE_CALL(); ALOGV("[%d]-onDestroy", layerID); + { + std::lock_guard lock(mMutex); + mTimeStatsTracker.erase(layerID); + } - std::lock_guard lock(mMutex); - if (!mTimeStatsTracker.count(layerID)) return; - mTimeStatsTracker.erase(layerID); + { + std::lock_guard traceLock(mTraceMutex); + mTraceTracker.erase(layerID); + } } void TimeStats::removeTimeRecord(int32_t layerID, uint64_t frameNumber) { diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index eed711158a..470137a431 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -16,13 +16,12 @@ #pragma once +#include +#include +#include #include #include - -#include - #include - #include #include @@ -37,8 +36,32 @@ namespace android { class TimeStats { public: + using FrameEvent = perfetto::protos::pbzero::GraphicsFrameEvent; + virtual ~TimeStats() = default; + // Sets up the perfetto tracing backend and data source. + virtual void initializeTracing() = 0; + // Registers the data source with the perfetto backend. Called as part of initializeTracing() + // and should not be called manually outside of tests. Public to allow for substituting a + // perfetto::kInProcessBackend in tests. + virtual void registerTracingDataSource() = 0; + // Starts tracking a new layer for tracing. Needs to be called once before traceTimestamp() or + // traceFence() for each layer. + virtual void traceNewLayer(int32_t layerID, const std::string& layerName) = 0; + // Creates a trace point at the timestamp provided. + virtual void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, + nsecs_t timestamp, FrameEvent::BufferEventType type, + nsecs_t duration = 0) = 0; + // Creates a trace point after the provided fence has been signalled. If a startTime is provided + // the trace will have be timestamped from startTime until fence signalling time. If no + // startTime is provided, a durationless trace point will be created timestamped at fence + // signalling time. If the fence hasn't signalled yet, the trace point will be created the next + // time after signalling a trace call for this buffer occurs. + virtual void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, + const std::shared_ptr& fence, + FrameEvent::BufferEventType type, nsecs_t startTime = 0) = 0; + virtual void parseArgs(bool asProto, const Vector& args, std::string& result) = 0; virtual bool isEnabled() = 0; virtual std::string miniDump() = 0; @@ -66,6 +89,13 @@ public: // Source of truth is RefrehRateStats. virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0; virtual void setPresentFenceGlobal(const std::shared_ptr& presentFence) = 0; + + static constexpr char kTimeStatsDataSource[] = "android.surfaceflinger.timestats"; + + // The maximum amount of time a fence has to signal before it is discarded. + // Used to avoid fence's from previous traces generating new trace points in later ones. + // Public for testing. + static constexpr nsecs_t kFenceSignallingDeadline = 60'000'000'000; // 60 seconds }; namespace impl { @@ -87,6 +117,13 @@ class TimeStats : public android::TimeStats { std::shared_ptr presentFence; }; + struct PendingFence { + uint64_t frameNumber; + FrameEvent::BufferEventType type; + std::shared_ptr fence; + nsecs_t startTime; + }; + struct LayerRecord { std::string layerName; // This is the index in timeRecords, at which the timestamps for that @@ -98,6 +135,12 @@ class TimeStats : public android::TimeStats { std::deque timeRecords; }; + struct TraceRecord { + std::string layerName; + using BufferID = uint64_t; + std::unordered_map> pendingFences; + }; + struct PowerTime { int32_t powerMode = HWC_POWER_MODE_OFF; nsecs_t prevTime = 0; @@ -109,8 +152,23 @@ class TimeStats : public android::TimeStats { }; public: + class TimeStatsDataSource : public perfetto::DataSource { + virtual void OnSetup(const SetupArgs&) override{}; + virtual void OnStart(const StartArgs&) override { ALOGV("TimeStats trace started"); }; + virtual void OnStop(const StopArgs&) override { ALOGV("TimeStats trace stopped"); }; + }; + TimeStats() = default; + void initializeTracing() override; + void registerTracingDataSource() override; + void traceNewLayer(int32_t layerID, const std::string& layerName) override; + void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp, + FrameEvent::BufferEventType type, nsecs_t duration = 0) override; + void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, + const std::shared_ptr& fence, FrameEvent::BufferEventType type, + nsecs_t startTime = 0) override; + void parseArgs(bool asProto, const Vector& args, std::string& result) override; bool isEnabled() override; std::string miniDump() override; @@ -142,6 +200,20 @@ public: static const size_t MAX_NUM_TIME_RECORDS = 64; private: + // Checks if any pending fences for a layer and buffer have signalled and, if they have, creates + // trace points for them. + void tracePendingFencesLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, + uint64_t bufferID); + // Creates a trace point by translating a start time and an end time to a timestamp and + // duration. If startTime is later than end time it sets end time as the timestamp and the + // duration to 0. Used by traceFence(). + void traceSpanLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID, + uint64_t frameNumber, FrameEvent::BufferEventType type, nsecs_t startTime, + nsecs_t endTime); + void traceLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID, + uint64_t frameNumber, nsecs_t timestamp, FrameEvent::BufferEventType type, + nsecs_t duration = 0); + bool recordReadyLocked(int32_t layerID, TimeRecord* timeRecord); void flushAvailableRecordsToStatsLocked(int32_t layerID); void flushPowerTimeLocked(); @@ -160,6 +232,9 @@ private: PowerTime mPowerTime; GlobalRecord mGlobalRecord; + std::mutex mTraceMutex; + std::unordered_map mTraceTracker; + static const size_t MAX_NUM_LAYER_RECORDS = 200; static const size_t MAX_NUM_LAYER_STATS = 200; }; diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp index 644cd7e698..57851bc850 100644 --- a/services/surfaceflinger/tests/fakehwc/Android.bp +++ b/services/surfaceflinger/tests/fakehwc/Android.bp @@ -34,7 +34,9 @@ cc_test { ], static_libs: [ "libgmock", + "libperfetto_client_experimental", "librenderengine", + "libtimestats", "libtrace_proto", ], header_libs: [ diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 4917bc2a51..0eedf9b7b1 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -36,7 +36,7 @@ cc_test { ":libsurfaceflinger_sources", "libsurfaceflinger_unittest_main.cpp", "CachingTest.cpp", - "CompositionTest.cpp", + "CompositionTest.cpp", "DispSyncSourceTest.cpp", "DisplayIdentificationTest.cpp", "DisplayTransactionTest.cpp", @@ -69,7 +69,13 @@ cc_test { "libgmock", "libcompositionengine", "libcompositionengine_mocks", + "libperfetto_client_experimental", "librenderengine_mocks", + "libtimestats", + "perfetto_trace_protos", + ], + shared_libs: [ + "libsurfaceflinger", ], header_libs: [ "libsurfaceflinger_headers", diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index f35758debf..f01e603f20 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -17,18 +17,17 @@ #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" +#include #include #include - #include +#include #include #include #include #include -#include "TimeStats/TimeStats.h" - #include "libsurfaceflinger_unittest_main.h" using namespace android::surfaceflinger; @@ -110,6 +109,15 @@ public: 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()); + + // Need to initialize tracing in process for testing, and only once per test suite. + static bool wasInitialized = false; + if (!wasInitialized) { + perfetto::TracingInitArgs args; + args.backends = perfetto::kInProcessBackend; + perfetto::Tracing::Initialize(args); + wasInitialized = true; + } } ~TimeStatsTest() { @@ -118,6 +126,13 @@ public: ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } + void SetUp() override { + mTimeStats = std::make_unique(); + mTimeStats->registerTracingDataSource(); + } + + void TearDown() override { mTimeStats.reset(); } + std::string inputCommand(InputCommand cmd, bool useProto); void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts); @@ -132,8 +147,22 @@ public: } } + // Each tracing session can be used for a single block of Start -> Stop. + static std::unique_ptr getTracingSessionForTest() { + perfetto::TraceConfig cfg; + cfg.set_duration_ms(500); + cfg.add_buffers()->set_size_kb(1024); + auto* ds_cfg = cfg.add_data_sources()->mutable_config(); + ds_cfg->set_name(TimeStats::kTimeStatsDataSource); + + auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend); + tracingSession->Setup(cfg); + return tracingSession; + } + std::mt19937 mRandomEngine = std::mt19937(std::random_device()()); - std::unique_ptr mTimeStats = std::make_unique(); + std::unique_ptr mTimeStats; + FenceToFenceTimeMap fenceFactory; }; std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) { @@ -210,6 +239,330 @@ int32_t TimeStatsTest::genRandomInt32(int32_t begin, int32_t end) { return distr(mRandomEngine); } +TEST_F(TimeStatsTest, traceNewLayerStartsTrackingLayerWhenTracing) { + EXPECT_EQ(mTimeStats->miniDump(), + "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " + "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n"); + + const std::string layerName = "co.layername#0"; + const int32_t layerID = 5; + mTimeStats->traceNewLayer(layerID, layerName); + + EXPECT_EQ(mTimeStats->miniDump(), + "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " + "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n"); + + auto tracingSession = getTracingSessionForTest(); + tracingSession->StartBlocking(); + EXPECT_EQ(mTimeStats->miniDump(), + "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " + "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n"); + mTimeStats->traceNewLayer(layerID, layerName); + EXPECT_EQ(mTimeStats->miniDump(), + "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " + "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n"); + tracingSession->StopBlocking(); +} + +TEST_F(TimeStatsTest, onDestroyRemovesTheTrackedLayer) { + EXPECT_EQ(mTimeStats->miniDump(), + "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " + "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n"); + + const std::string layerName = "co.layername#0"; + const int32_t layerID = 5; + const int32_t secondLayerID = 6; + + auto tracingSession = getTracingSessionForTest(); + tracingSession->StartBlocking(); + mTimeStats->traceNewLayer(layerID, layerName); + mTimeStats->traceNewLayer(secondLayerID, layerName); + EXPECT_EQ(mTimeStats->miniDump(), + "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " + "layers in the stats pool is 0\nNumber of layers currently being traced is 2\n"); + tracingSession->StopBlocking(); + + mTimeStats->onDestroy(layerID); + EXPECT_EQ(mTimeStats->miniDump(), + "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " + "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n"); + mTimeStats->onDestroy(layerID); + EXPECT_EQ(mTimeStats->miniDump(), + "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " + "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n"); + mTimeStats->onDestroy(secondLayerID); + EXPECT_EQ(mTimeStats->miniDump(), + "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " + "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n"); +} + +TEST_F(TimeStatsTest, canTraceAfterAddingLayer) { + const std::string layerName = "co.layername#0"; + const int32_t layerID = 1; + const uint32_t bufferID = 2; + const uint64_t frameNumber = 3; + const nsecs_t timestamp = 4; + const nsecs_t duration = 5; + const auto type = TimeStats::FrameEvent::POST; + + { + auto tracingSession = getTracingSessionForTest(); + + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + + mTimeStats->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration); + // Create second trace packet to finalize the previous one. + mTimeStats->traceTimestamp(layerID, 0, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + EXPECT_EQ(raw_trace.size(), 0); + } + + { + auto tracingSession = getTracingSessionForTest(); + + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + + mTimeStats->traceNewLayer(layerID, layerName); + mTimeStats->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration); + // Create second trace packet to finalize the previous one. + mTimeStats->traceTimestamp(layerID, 0, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + ASSERT_GT(raw_trace.size(), 0); + + perfetto::protos::Trace trace; + ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); + ASSERT_FALSE(trace.packet().empty()); + EXPECT_EQ(trace.packet().size(), 1); + + const auto& packet = trace.packet().Get(0); + ASSERT_TRUE(packet.has_timestamp()); + EXPECT_EQ(packet.timestamp(), timestamp); + ASSERT_TRUE(packet.has_graphics_frame_event()); + const auto& frame_event = packet.graphics_frame_event(); + ASSERT_TRUE(frame_event.has_buffer_event()); + const auto& buffer_event = frame_event.buffer_event(); + ASSERT_TRUE(buffer_event.has_buffer_id()); + EXPECT_EQ(buffer_event.buffer_id(), bufferID); + ASSERT_TRUE(buffer_event.has_frame_number()); + EXPECT_EQ(buffer_event.frame_number(), frameNumber); + ASSERT_TRUE(buffer_event.has_type()); + EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type)); + ASSERT_TRUE(buffer_event.has_duration_ns()); + EXPECT_EQ(buffer_event.duration_ns(), duration); + } +} + +TEST_F(TimeStatsTest, traceFenceTriggersOnNextTraceAfterFenceFired) { + const std::string layerName = "co.layername#0"; + const int32_t layerID = 5; + const uint32_t bufferID = 4; + const uint64_t frameNumber = 3; + const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE; + + { + auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING); + auto tracingSession = getTracingSessionForTest(); + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + // Trace. + mTimeStats->traceNewLayer(layerID, layerName); + mTimeStats->traceFence(layerID, bufferID, frameNumber, fenceTime, type); + // Create extra trace packet to (hopefully not) trigger and finalize the fence packet. + mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + EXPECT_EQ(raw_trace.size(), 0); + } + + { + auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + auto tracingSession = getTracingSessionForTest(); + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + mTimeStats->traceNewLayer(layerID, layerName); + mTimeStats->traceFence(layerID, bufferID, frameNumber, fenceTime, type); + const nsecs_t timestamp = systemTime(); + fenceFactory.signalAllForTest(Fence::NO_FENCE, timestamp); + // Create extra trace packet to trigger and finalize fence trace packets. + mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + ASSERT_GT(raw_trace.size(), 0); + + perfetto::protos::Trace trace; + ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); + ASSERT_FALSE(trace.packet().empty()); + EXPECT_EQ(trace.packet().size(), 2); // Two packets because of the extra trace made above. + + const auto& packet = trace.packet().Get(1); + ASSERT_TRUE(packet.has_timestamp()); + EXPECT_EQ(packet.timestamp(), timestamp); + ASSERT_TRUE(packet.has_graphics_frame_event()); + const auto& frame_event = packet.graphics_frame_event(); + ASSERT_TRUE(frame_event.has_buffer_event()); + const auto& buffer_event = frame_event.buffer_event(); + ASSERT_TRUE(buffer_event.has_buffer_id()); + EXPECT_EQ(buffer_event.buffer_id(), bufferID); + ASSERT_TRUE(buffer_event.has_frame_number()); + EXPECT_EQ(buffer_event.frame_number(), frameNumber); + ASSERT_TRUE(buffer_event.has_type()); + EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type)); + EXPECT_FALSE(buffer_event.has_duration_ns()); + } +} + +TEST_F(TimeStatsTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDuration) { + const std::string layerName = "co.layername#0"; + const int32_t layerID = 5; + const uint32_t bufferID = 4; + const uint64_t frameNumber = 3; + const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE; + + auto tracingSession = getTracingSessionForTest(); + + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + mTimeStats->traceNewLayer(layerID, layerName); + + // traceFence called after fence signalled. + const nsecs_t signalTime1 = systemTime(); + const nsecs_t startTime1 = signalTime1 + 100000; + auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1); + mTimeStats->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1); + + // traceFence called before fence signalled. + const nsecs_t signalTime2 = systemTime(); + const nsecs_t startTime2 = signalTime2 + 100000; + auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + mTimeStats->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2); + fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2); + + // Create extra trace packet to trigger and finalize fence trace packets. + mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + ASSERT_GT(raw_trace.size(), 0); + + perfetto::protos::Trace trace; + ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); + ASSERT_FALSE(trace.packet().empty()); + EXPECT_EQ(trace.packet().size(), 2); + + const auto& packet1 = trace.packet().Get(0); + ASSERT_TRUE(packet1.has_timestamp()); + EXPECT_EQ(packet1.timestamp(), signalTime1); + ASSERT_TRUE(packet1.has_graphics_frame_event()); + ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event()); + ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns()); + + const auto& packet2 = trace.packet().Get(1); + ASSERT_TRUE(packet2.has_timestamp()); + EXPECT_EQ(packet2.timestamp(), signalTime2); + ASSERT_TRUE(packet2.has_graphics_frame_event()); + ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event()); + ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns()); +} + +TEST_F(TimeStatsTest, traceFenceOlderThanDeadline_ShouldBeIgnored) { + const std::string layerName = "co.layername#0"; + const int32_t layerID = 5; + const uint32_t bufferID = 4; + const uint64_t frameNumber = 3; + const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE; + const nsecs_t signalTime = systemTime() - TimeStats::kFenceSignallingDeadline; + + auto tracingSession = getTracingSessionForTest(); + auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + mTimeStats->traceNewLayer(layerID, layerName); + mTimeStats->traceFence(layerID, bufferID, frameNumber, fence, type); + fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime); + // Create extra trace packet to trigger and finalize any previous fence packets. + mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + EXPECT_EQ(raw_trace.size(), 0); +} + +TEST_F(TimeStatsTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) { + const std::string layerName = "co.layername#0"; + const int32_t layerID = 5; + const uint32_t bufferID = 4; + const uint64_t frameNumber = 3; + const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE; + const nsecs_t duration = 1234; + + auto tracingSession = getTracingSessionForTest(); + + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + mTimeStats->traceNewLayer(layerID, layerName); + + // traceFence called after fence signalled. + const nsecs_t signalTime1 = systemTime(); + const nsecs_t startTime1 = signalTime1 - duration; + auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1); + mTimeStats->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1); + + // traceFence called before fence signalled. + const nsecs_t signalTime2 = systemTime(); + const nsecs_t startTime2 = signalTime2 - duration; + auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + mTimeStats->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2); + fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2); + + // Create extra trace packet to trigger and finalize fence trace packets. + mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + ASSERT_GT(raw_trace.size(), 0); + + perfetto::protos::Trace trace; + ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); + ASSERT_FALSE(trace.packet().empty()); + EXPECT_EQ(trace.packet().size(), 2); + + const auto& packet1 = trace.packet().Get(0); + ASSERT_TRUE(packet1.has_timestamp()); + EXPECT_EQ(packet1.timestamp(), startTime1); + ASSERT_TRUE(packet1.has_graphics_frame_event()); + ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event()); + ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns()); + const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event(); + EXPECT_EQ(buffer_event1.duration_ns(), duration); + + const auto& packet2 = trace.packet().Get(1); + ASSERT_TRUE(packet2.has_timestamp()); + EXPECT_EQ(packet2.timestamp(), startTime2); + ASSERT_TRUE(packet2.has_graphics_frame_event()); + ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event()); + ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns()); + const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event(); + EXPECT_EQ(buffer_event2.duration_ns(), duration); +} + TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) { EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); ASSERT_TRUE(mTimeStats->isEnabled()); diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h index b1634a8da7..542c70a8fb 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h @@ -28,6 +28,14 @@ public: TimeStats(); ~TimeStats() override; + MOCK_METHOD0(initializeTracing, void()); + MOCK_METHOD0(registerTracingDataSource, void()); + MOCK_METHOD2(traceNewLayer, void(int32_t, const std::string&)); + MOCK_METHOD6(traceTimestamp, + void(int32_t, uint64_t, uint64_t, nsecs_t, FrameEvent::BufferEventType, nsecs_t)); + MOCK_METHOD6(traceFence, + void(int32_t, uint64_t, uint64_t, const std::shared_ptr&, + FrameEvent::BufferEventType, nsecs_t)); MOCK_METHOD3(parseArgs, void(bool, const Vector&, std::string&)); MOCK_METHOD0(isEnabled, bool()); MOCK_METHOD0(miniDump, std::string()); -- GitLab From 8cf7c7b92f9557bc9745622bd167e0721cca7cd6 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Wed, 28 Aug 2019 13:07:30 -0700 Subject: [PATCH 0202/1255] GpuService: pass args to GpuStats Test: adb shell dumpsys gpu --gpustats --(global|app|clear) Change-Id: I0f898fe02137a27a427a51a211a7226a36db9586 --- services/gpuservice/GpuService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 42d566f7a2..55a0c0a639 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -273,7 +273,7 @@ status_t GpuService::doDump(int fd, const Vector& args, bool /*asProto result.append("\n"); } if (dumpAll || dumpStats) { - mGpuStats->dump(Vector(), &result); + mGpuStats->dump(args, &result); result.append("\n"); } if (dumpAll || dumpMemory) { -- GitLab From 56eba802e4966725ded65b54d29fca0faa17c331 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Wed, 28 Aug 2019 15:45:25 -0700 Subject: [PATCH 0203/1255] SF: Fix layer outside of viewport test When performing client (GPU) composition, the code checks to see if the visible region for each layer is contained in the output viewport. Unfortunately when moving the code to CompositionEngine, I used the "wrong" visible region -- one that had been transformed by the output rotation. This led to layers that should have been visible in split screen portrait mode not being rendered, leaving a black space on the screen. The fix was simply to use the non-transformed visible region, as set in the output-independent state in LayerStateFE. Additionally as there was a lack of any unit test coverage for the Output::composeSurfaces and Output::generateClientCompositionRequests functions, I've added some quick basic tests, as well as a specific test to simulate the reported regression. Bug: 139806358 Bug: 121291683 Test: Manual test on crosshatch Test: atest libcompositionengine_test Change-Id: I028ef238a2e08759cf32ea2f2e27aaea32f3e89b --- .../CompositionEngine/src/Output.cpp | 2 +- .../CompositionEngine/tests/OutputTest.cpp | 271 ++++++++++++++++++ 2 files changed, 272 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 55fdacde44..e4404bffd6 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -402,7 +402,7 @@ std::vector Output::generateClientCompositionReques const auto& layerFEState = layer->getLayer().getState().frontEnd; auto& layerFE = layer->getLayerFE(); - const Region clip(viewportRegion.intersect(layer->getState().visibleRegion)); + const Region clip(viewportRegion.intersect(layerFEState.geomVisibleRegion)); ALOGV("Layer: %s", layerFE.getDebugName()); if (clip.isEmpty()) { ALOGV(" Skipping for empty clip"); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index aa35d2581c..318818a11c 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -16,8 +16,10 @@ #include +#include #include #include +#include #include #include #include @@ -25,6 +27,7 @@ #include #include #include +#include #include #include @@ -34,10 +37,14 @@ namespace android::compositionengine { namespace { +using testing::_; using testing::Return; using testing::ReturnRef; using testing::StrictMock; +constexpr auto TR_IDENT = 0u; +constexpr auto TR_ROT_90 = HAL_TRANSFORM_ROT_90; + struct OutputTest : public testing::Test { OutputTest() { mOutput.setDisplayColorProfileForTest( @@ -446,5 +453,269 @@ TEST_F(OutputTest, prepareFrameSetsClientCompositionOnlyByDefault) { EXPECT_FALSE(mOutput.getState().usesDeviceComposition); } +/* + * Output::composeSurfaces() + */ + +struct OutputComposeSurfacesTest : public testing::Test { + static constexpr uint32_t kDefaultOutputOrientation = TR_IDENT; + static constexpr ui::Dataspace kDefaultOutputDataspace = ui::Dataspace::DISPLAY_P3; + + static const Rect kDefaultOutputFrame; + static const Rect kDefaultOutputViewport; + static const Rect kDefaultOutputScissor; + static const mat4 kDefaultColorTransformMat; + + struct OutputPartialMock : public impl::Output { + OutputPartialMock(const compositionengine::CompositionEngine& compositionEngine) + : impl::Output(compositionEngine) {} + + // Sets up the helper functions called by composeSurfaces to use a mock + // implementations. + MOCK_CONST_METHOD0(getSkipColorTransform, bool()); + MOCK_METHOD2(generateClientCompositionRequests, + std::vector(bool, Region&)); + MOCK_METHOD2(appendRegionFlashRequests, + void(const Region&, std::vector&)); + MOCK_METHOD1(setExpensiveRenderingExpected, void(bool)); + }; + + OutputComposeSurfacesTest() { + mOutput.setDisplayColorProfileForTest( + std::unique_ptr(mDisplayColorProfile)); + mOutput.setRenderSurfaceForTest(std::unique_ptr(mRenderSurface)); + + Output::OutputLayers outputLayers; + outputLayers.emplace_back(std::unique_ptr(mOutputLayer1)); + outputLayers.emplace_back(std::unique_ptr(mOutputLayer2)); + mOutput.setOutputLayersOrderedByZ(std::move(outputLayers)); + + mOutput.editState().frame = kDefaultOutputFrame; + mOutput.editState().viewport = kDefaultOutputViewport; + mOutput.editState().scissor = kDefaultOutputScissor; + mOutput.editState().transform = ui::Transform{kDefaultOutputOrientation}; + mOutput.editState().orientation = kDefaultOutputOrientation; + mOutput.editState().dataspace = kDefaultOutputDataspace; + mOutput.editState().colorTransformMat = kDefaultColorTransformMat; + mOutput.editState().isSecure = true; + mOutput.editState().needsFiltering = false; + mOutput.editState().usesClientComposition = true; + mOutput.editState().usesDeviceComposition = false; + + EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine)); + } + + StrictMock mCompositionEngine; + StrictMock mRenderEngine; + mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock(); + mock::RenderSurface* mRenderSurface = new StrictMock(); + mock::OutputLayer* mOutputLayer1 = new StrictMock(); + mock::OutputLayer* mOutputLayer2 = new StrictMock(); + StrictMock mOutput{mCompositionEngine}; + sp mOutputBuffer = new GraphicBuffer(); +}; + +const Rect OutputComposeSurfacesTest::kDefaultOutputFrame{1001, 1002, 1003, 1004}; +const Rect OutputComposeSurfacesTest::kDefaultOutputViewport{1005, 1006, 1007, 1008}; +const Rect OutputComposeSurfacesTest::kDefaultOutputScissor{1009, 1010, 1011, 1012}; +const mat4 OutputComposeSurfacesTest::kDefaultColorTransformMat{mat4() * 0.5}; + +// TODO(b/121291683): Expand unit test coverage for composeSurfaces beyond these +// basic tests. + +TEST_F(OutputComposeSurfacesTest, doesNothingIfNoClientComposition) { + mOutput.editState().usesClientComposition = false; + + Region debugRegion; + base::unique_fd readyFence; + EXPECT_EQ(true, mOutput.composeSurfaces(debugRegion, &readyFence)); +} + +TEST_F(OutputComposeSurfacesTest, worksIfNoClientLayersQueued) { + const Region kDebugRegion{Rect{100, 101, 102, 103}}; + + constexpr float kDefaultMaxLuminance = 1.0f; + constexpr float kDefaultAvgLuminance = 0.7f; + constexpr float kDefaultMinLuminance = 0.1f; + HdrCapabilities HdrCapabilities{{}, + kDefaultMaxLuminance, + kDefaultAvgLuminance, + kDefaultMinLuminance}; + + EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillOnce(Return(false)); + EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, true, _, _)).Times(1); + + EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillOnce(Return(true)); + EXPECT_CALL(*mDisplayColorProfile, getHdrCapabilities()).WillOnce(ReturnRef(HdrCapabilities)); + + EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(mOutputBuffer)); + + EXPECT_CALL(mOutput, getSkipColorTransform()).WillOnce(Return(false)); + EXPECT_CALL(mOutput, generateClientCompositionRequests(false, _)).Times(1); + EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _)).Times(1); + EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)).Times(1); + EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false)).Times(1); + + base::unique_fd readyFence; + EXPECT_EQ(true, mOutput.composeSurfaces(kDebugRegion, &readyFence)); +} + +/* + * Output::generateClientCompositionRequests() + */ + +struct GenerateClientCompositionRequestsTest : public testing::Test { + struct OutputPartialMock : public impl::Output { + OutputPartialMock(const compositionengine::CompositionEngine& compositionEngine) + : impl::Output(compositionEngine) {} + + std::vector generateClientCompositionRequests( + bool supportsProtectedContent, Region& clearRegion) override { + return impl::Output::generateClientCompositionRequests(supportsProtectedContent, + clearRegion); + } + }; + + GenerateClientCompositionRequestsTest() { + mOutput.setDisplayColorProfileForTest( + std::unique_ptr(mDisplayColorProfile)); + mOutput.setRenderSurfaceForTest(std::unique_ptr(mRenderSurface)); + } + + StrictMock mCompositionEngine; + mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock(); + mock::RenderSurface* mRenderSurface = new StrictMock(); + StrictMock mOutput{mCompositionEngine}; +}; + +// TODO(b/121291683): Add more unit test coverage for generateClientCompositionRequests + +TEST_F(GenerateClientCompositionRequestsTest, worksForLandscapeModeSplitScreen) { + // In split-screen landscape mode, the screen is rotated 90 degrees, with + // one layer on the left covering the left side of the output, and one layer + // on the right covering that side of the output. + + mock::OutputLayer* leftOutputLayer = new StrictMock(); + mock::OutputLayer* rightOutputLayer = new StrictMock(); + + StrictMock leftLayer; + StrictMock leftLayerFE; + StrictMock rightLayer; + StrictMock rightLayerFE; + + impl::OutputLayerCompositionState leftOutputLayerState; + leftOutputLayerState.clearClientTarget = false; + + impl::LayerCompositionState leftLayerState; + leftLayerState.frontEnd.geomVisibleRegion = Region{Rect{0, 0, 1000, 1000}}; + leftLayerState.frontEnd.isOpaque = true; + + const half3 leftLayerColor{1.f, 0.f, 0.f}; + renderengine::LayerSettings leftLayerRESettings; + leftLayerRESettings.source.solidColor = leftLayerColor; + + impl::OutputLayerCompositionState rightOutputLayerState; + rightOutputLayerState.clearClientTarget = false; + + impl::LayerCompositionState rightLayerState; + rightLayerState.frontEnd.geomVisibleRegion = Region{Rect{1000, 0, 2000, 1000}}; + rightLayerState.frontEnd.isOpaque = true; + + const half3 rightLayerColor{0.f, 1.f, 0.f}; + renderengine::LayerSettings rightLayerRESettings; + rightLayerRESettings.source.solidColor = rightLayerColor; + + EXPECT_CALL(*leftOutputLayer, getState()).WillRepeatedly(ReturnRef(leftOutputLayerState)); + EXPECT_CALL(*leftOutputLayer, getLayer()).WillRepeatedly(ReturnRef(leftLayer)); + EXPECT_CALL(*leftOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(leftLayerFE)); + EXPECT_CALL(*leftOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true)); + EXPECT_CALL(*leftOutputLayer, needsFiltering()).WillRepeatedly(Return(false)); + EXPECT_CALL(leftLayer, getState()).WillRepeatedly(ReturnRef(leftLayerState)); + EXPECT_CALL(leftLayerFE, prepareClientComposition(_)).WillOnce(Return(leftLayerRESettings)); + + EXPECT_CALL(*rightOutputLayer, getState()).WillRepeatedly(ReturnRef(rightOutputLayerState)); + EXPECT_CALL(*rightOutputLayer, getLayer()).WillRepeatedly(ReturnRef(rightLayer)); + EXPECT_CALL(*rightOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(rightLayerFE)); + EXPECT_CALL(*rightOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true)); + EXPECT_CALL(*rightOutputLayer, needsFiltering()).WillRepeatedly(Return(false)); + EXPECT_CALL(rightLayer, getState()).WillRepeatedly(ReturnRef(rightLayerState)); + EXPECT_CALL(rightLayerFE, prepareClientComposition(_)).WillOnce(Return(rightLayerRESettings)); + + Output::OutputLayers outputLayers; + outputLayers.emplace_back(std::unique_ptr(leftOutputLayer)); + outputLayers.emplace_back(std::unique_ptr(rightOutputLayer)); + mOutput.setOutputLayersOrderedByZ(std::move(outputLayers)); + + const Rect kPortraitFrame(0, 0, 1000, 2000); + const Rect kPortraitViewport(0, 0, 2000, 1000); + const Rect kPortraitScissor(0, 0, 1000, 2000); + const uint32_t kPortraitOrientation = TR_ROT_90; + + mOutput.editState().frame = kPortraitFrame; + mOutput.editState().viewport = kPortraitViewport; + mOutput.editState().scissor = kPortraitScissor; + mOutput.editState().transform = ui::Transform{kPortraitOrientation}; + mOutput.editState().orientation = kPortraitOrientation; + mOutput.editState().needsFiltering = true; + mOutput.editState().isSecure = false; + + constexpr bool supportsProtectedContent = false; + Region clearRegion; + auto requests = + mOutput.generateClientCompositionRequests(supportsProtectedContent, clearRegion); + + ASSERT_EQ(2u, requests.size()); + EXPECT_EQ(leftLayerColor, requests[0].source.solidColor); + EXPECT_EQ(rightLayerColor, requests[1].source.solidColor); +} + +TEST_F(GenerateClientCompositionRequestsTest, ignoresLayersThatDoNotIntersectWithViewport) { + // Layers whose visible region does not intersect with the viewport will be + // skipped when generating client composition request state. + + mock::OutputLayer* outputLayer = new StrictMock(); + StrictMock layer; + StrictMock layerFE; + + impl::OutputLayerCompositionState outputLayerState; + outputLayerState.clearClientTarget = false; + + impl::LayerCompositionState layerState; + layerState.frontEnd.geomVisibleRegion = Region{Rect{3000, 0, 4000, 1000}}; + layerState.frontEnd.isOpaque = true; + + EXPECT_CALL(*outputLayer, getState()).WillRepeatedly(ReturnRef(outputLayerState)); + EXPECT_CALL(*outputLayer, getLayer()).WillRepeatedly(ReturnRef(layer)); + EXPECT_CALL(*outputLayer, getLayerFE()).WillRepeatedly(ReturnRef(layerFE)); + EXPECT_CALL(*outputLayer, requiresClientComposition()).WillRepeatedly(Return(true)); + EXPECT_CALL(*outputLayer, needsFiltering()).WillRepeatedly(Return(false)); + EXPECT_CALL(layer, getState()).WillRepeatedly(ReturnRef(layerState)); + EXPECT_CALL(layerFE, prepareClientComposition(_)).Times(0); + + Output::OutputLayers outputLayers; + outputLayers.emplace_back(std::unique_ptr(outputLayer)); + mOutput.setOutputLayersOrderedByZ(std::move(outputLayers)); + + const Rect kPortraitFrame(0, 0, 1000, 2000); + const Rect kPortraitViewport(0, 0, 2000, 1000); + const Rect kPortraitScissor(0, 0, 1000, 2000); + const uint32_t kPortraitOrientation = TR_ROT_90; + + mOutput.editState().frame = kPortraitFrame; + mOutput.editState().viewport = kPortraitViewport; + mOutput.editState().scissor = kPortraitScissor; + mOutput.editState().transform = ui::Transform{kPortraitOrientation}; + mOutput.editState().orientation = kPortraitOrientation; + mOutput.editState().needsFiltering = true; + mOutput.editState().isSecure = false; + + constexpr bool supportsProtectedContent = false; + Region clearRegion; + auto requests = + mOutput.generateClientCompositionRequests(supportsProtectedContent, clearRegion); + + EXPECT_EQ(0u, requests.size()); +} + } // namespace } // namespace android::compositionengine -- GitLab From c2d54d4038202406573191ffdc54c96d8079d09c Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Wed, 28 Aug 2019 18:04:21 -0700 Subject: [PATCH 0204/1255] SF: Clear layers properly doing client composition When performing client composition, layers that are set to use device composition should clear the client composition framebuffer unless they are the bottom most layer. This regressed when I moved the code to CompositionEngine, and I caught it while adding a unit test. The expected behavior is now covered by a new test. Bug: 121291683 Test: atest libcompositionengine_test Test: YouTube, Twitch PiP on crosshatch Change-Id: Id0db7b0d21afadc331d9b42dadef1d90a989389e --- .../CompositionEngine/src/Output.cpp | 2 +- .../CompositionEngine/tests/OutputTest.cpp | 79 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index e4404bffd6..2483c0682b 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -432,7 +432,7 @@ std::vector Output::generateClientCompositionReques clientComposition ? clearRegion : dummyRegion, }; if (auto result = layerFE.prepareClientComposition(targetSettings)) { - if (clearClientComposition) { + if (!clientComposition) { auto& layerSettings = *result; layerSettings.source.buffer.buffer = nullptr; layerSettings.source.solidColor = half3(0.0, 0.0, 0.0); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 318818a11c..f4d2cf180b 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -717,5 +717,84 @@ TEST_F(GenerateClientCompositionRequestsTest, ignoresLayersThatDoNotIntersectWit EXPECT_EQ(0u, requests.size()); } +TEST_F(GenerateClientCompositionRequestsTest, clearsDeviceLayesAfterFirst) { + // If client composition is performed with some layers set to use device + // composition, device layers after the first layer (device or client) will + // clear the frame buffer if they are opaque and if that layer has a flag + // set to do so. The first layer is skipped as the frame buffer is already + // expected to be clear. + + mock::OutputLayer* leftOutputLayer = new StrictMock(); + mock::OutputLayer* rightOutputLayer = new StrictMock(); + + StrictMock leftLayer; + StrictMock leftLayerFE; + StrictMock rightLayer; + StrictMock rightLayerFE; + + impl::OutputLayerCompositionState leftOutputLayerState; + leftOutputLayerState.clearClientTarget = true; + + impl::LayerCompositionState leftLayerState; + leftLayerState.frontEnd.geomVisibleRegion = Region{Rect{0, 0, 1000, 1000}}; + leftLayerState.frontEnd.isOpaque = true; + + impl::OutputLayerCompositionState rightOutputLayerState; + rightOutputLayerState.clearClientTarget = true; + + impl::LayerCompositionState rightLayerState; + rightLayerState.frontEnd.geomVisibleRegion = Region{Rect{1000, 0, 2000, 1000}}; + rightLayerState.frontEnd.isOpaque = true; + + const half3 rightLayerColor{0.f, 1.f, 0.f}; + renderengine::LayerSettings rightLayerRESettings; + rightLayerRESettings.geometry.boundaries = FloatRect{456, 0, 0, 0}; + rightLayerRESettings.source.solidColor = rightLayerColor; + + EXPECT_CALL(*leftOutputLayer, getState()).WillRepeatedly(ReturnRef(leftOutputLayerState)); + EXPECT_CALL(*leftOutputLayer, getLayer()).WillRepeatedly(ReturnRef(leftLayer)); + EXPECT_CALL(*leftOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(leftLayerFE)); + EXPECT_CALL(*leftOutputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); + EXPECT_CALL(*leftOutputLayer, needsFiltering()).WillRepeatedly(Return(false)); + EXPECT_CALL(leftLayer, getState()).WillRepeatedly(ReturnRef(leftLayerState)); + + EXPECT_CALL(*rightOutputLayer, getState()).WillRepeatedly(ReturnRef(rightOutputLayerState)); + EXPECT_CALL(*rightOutputLayer, getLayer()).WillRepeatedly(ReturnRef(rightLayer)); + EXPECT_CALL(*rightOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(rightLayerFE)); + EXPECT_CALL(*rightOutputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); + EXPECT_CALL(*rightOutputLayer, needsFiltering()).WillRepeatedly(Return(false)); + EXPECT_CALL(rightLayer, getState()).WillRepeatedly(ReturnRef(rightLayerState)); + EXPECT_CALL(rightLayerFE, prepareClientComposition(_)).WillOnce(Return(rightLayerRESettings)); + + Output::OutputLayers outputLayers; + outputLayers.emplace_back(std::unique_ptr(leftOutputLayer)); + outputLayers.emplace_back(std::unique_ptr(rightOutputLayer)); + mOutput.setOutputLayersOrderedByZ(std::move(outputLayers)); + + const Rect kPortraitFrame(0, 0, 1000, 2000); + const Rect kPortraitViewport(0, 0, 2000, 1000); + const Rect kPortraitScissor(0, 0, 1000, 2000); + const uint32_t kPortraitOrientation = TR_ROT_90; + + mOutput.editState().frame = kPortraitFrame; + mOutput.editState().viewport = kPortraitViewport; + mOutput.editState().scissor = kPortraitScissor; + mOutput.editState().transform = ui::Transform{kPortraitOrientation}; + mOutput.editState().orientation = kPortraitOrientation; + mOutput.editState().needsFiltering = true; + mOutput.editState().isSecure = false; + + constexpr bool supportsProtectedContent = false; + Region clearRegion; + auto requests = + mOutput.generateClientCompositionRequests(supportsProtectedContent, clearRegion); + + const half3 clearColor{0.f, 0.f, 0.f}; + + ASSERT_EQ(1u, requests.size()); + EXPECT_EQ(456.f, requests[0].geometry.boundaries.left); + EXPECT_EQ(clearColor, requests[0].source.solidColor); +} + } // namespace } // namespace android::compositionengine -- GitLab From 07d587b98905d04c8a5fb05c7f6820c1acfc7a67 Mon Sep 17 00:00:00 2001 From: Abhijeet Kaur Date: Thu, 29 Aug 2019 14:11:57 +0100 Subject: [PATCH 0205/1255] Remove outfile flag as it's unused and all callers migrated Bug: 111441001 Bug: 135186519 Test: builds Test: atest dumpstate_test Change-Id: I9fbaa6765f7384d99239161a38a9962d476e1394 --- cmds/dumpstate/dumpstate.cpp | 3 --- cmds/dumpstate/dumpstate.rc | 3 +-- cmds/dumpstate/tests/dumpstate_smoke_test.cpp | 4 +--- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index a8e6738228..b781da308c 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -2328,9 +2328,6 @@ Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) // clang-format off case 'd': do_add_date = true; break; case 'z': do_zip_file = true; break; - // o=use_outfile not supported anymore. - // TODO(b/111441001): Remove when all callers have migrated. - case 'o': break; case 's': use_socket = true; break; case 'S': use_control_socket = true; break; case 'v': show_header_only = true; break; diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc index 14937b80b9..e491a4b614 100644 --- a/cmds/dumpstate/dumpstate.rc +++ b/cmds/dumpstate/dumpstate.rc @@ -11,8 +11,7 @@ service dumpstate /system/bin/dumpstate -s # dumpstatez generates a zipped bugreport but also uses a socket to print the file location once # it is finished. -service dumpstatez /system/bin/dumpstate -S -d -z \ - -o /data/user_de/0/com.android.shell/files/bugreports/bugreport +service dumpstatez /system/bin/dumpstate -S -d -z socket dumpstate stream 0660 shell log class main disabled diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp index 181046a7a7..dbbcdff63e 100644 --- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp @@ -201,9 +201,7 @@ class ZippedBugreportGenerationTest : public Test { (char*)"dumpstate", (char*)"-d", (char*)"-z", - (char*)"-B", - (char*)"-o", - (char*)dirname(android::base::GetExecutablePath().c_str()) + (char*)"-B" }; // clang-format on sp listener(new DumpstateListener(dup(fileno(stdout)), sections)); -- GitLab From f8cf14d48d45c10a729e35ac4302136888fdc59c Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 28 Feb 2019 16:03:12 -0800 Subject: [PATCH 0206/1255] SF: Move doDebugFlashRegions to CompositionEngine Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: I0ea71e6c86231d6fedca7309889001cea3ecf47b --- .../CompositionRefreshArgs.h | 9 +++++ .../include/compositionengine/Output.h | 5 +++ .../include/compositionengine/impl/Output.h | 1 + .../include/compositionengine/mock/Output.h | 3 ++ .../CompositionEngine/src/Output.cpp | 27 +++++++++++++ services/surfaceflinger/SurfaceFlinger.cpp | 40 ++++--------------- services/surfaceflinger/SurfaceFlinger.h | 1 - 7 files changed, 52 insertions(+), 34 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index 20f131e56d..b329f76445 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -16,6 +16,9 @@ #pragma once +#include +#include + #include #include @@ -35,6 +38,12 @@ struct CompositionRefreshArgs { // the layers is important, and should be in traversal order from back to // front. Layers layers; + + // If true, forces the entire display to be considered dirty and repainted + bool repaintEverything{false}; + + // If set, causes the dirty regions to flash with the delay + std::optional devOptFlashDirtyRegionsDelay; }; } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index f73304d211..df7add2f08 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -43,6 +43,8 @@ class LayerFE; class RenderSurface; class OutputLayer; +struct CompositionRefreshArgs; + namespace impl { struct OutputCompositionState; } // namespace impl @@ -157,6 +159,9 @@ public: // Prepares a frame for display virtual void prepareFrame() = 0; + // Performs any debug related screen flashing due to the update + virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0; + // Performs client composition as needed for layers on the output. The // output fence is set to a fence to signal when client composition is // finished. diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 3972f2bcf4..36d6a692e9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -77,6 +77,7 @@ public: void beginFrame() override; void prepareFrame() override; + void devOptRepaintFlash(const compositionengine::CompositionRefreshArgs&) override; bool composeSurfaces(const Region&, base::unique_fd*) override; void postFramebuffer() override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index c944becd22..b9e1c9c007 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -77,6 +78,8 @@ public: MOCK_METHOD0(prepareFrame, void()); MOCK_METHOD0(chooseCompositionStrategy, void()); + MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&)); + MOCK_METHOD2(composeSurfaces, bool(const Region&, base::unique_fd*)); MOCK_CONST_METHOD0(getSkipColorTransform, bool()); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 2483c0682b..10534f4de3 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -14,8 +14,11 @@ * limitations under the License. */ +#include + #include #include +#include #include #include #include @@ -299,6 +302,30 @@ void Output::prepareFrame() { mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition); } +void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& refreshArgs) { + if (CC_LIKELY(!refreshArgs.devOptFlashDirtyRegionsDelay)) { + return; + } + + if (mState.isEnabled) { + // transform the dirty region into this screen's coordinate space + const Region dirtyRegion = getDirtyRegion(refreshArgs.repaintEverything); + if (!dirtyRegion.isEmpty()) { + base::unique_fd readyFence; + // redraw the whole screen + composeSurfaces(dirtyRegion, &readyFence); + + mRenderSurface->queueBuffer(std::move(readyFence)); + } + } + + postFramebuffer(); + + std::this_thread::sleep_for(*refreshArgs.devOptFlashDirtyRegionsDelay); + + prepareFrame(); +} + bool Output::composeSurfaces(const Region& debugRegion, base::unique_fd* readyFence) { ATRACE_CALL(); ALOGV(__FUNCTION__); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6543089101..dd0890c820 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1787,8 +1787,12 @@ void SurfaceFlinger::handleMessageRefresh() { auto compositionLayer = layer->getCompositionLayer(); if (compositionLayer) refreshArgs.layers.push_back(compositionLayer); }); + refreshArgs.repaintEverything = mRepaintEverything.exchange(false); + if (mDebugRegion != 0) { + refreshArgs.devOptFlashDirtyRegionsDelay = + std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0); + } - const bool repaintEverything = mRepaintEverything.exchange(false); mCompositionEngine->preComposition(refreshArgs); rebuildLayerStacks(); calculateWorkingSet(); @@ -1796,8 +1800,8 @@ void SurfaceFlinger::handleMessageRefresh() { auto display = displayDevice->getCompositionDisplay(); display->beginFrame(); display->prepareFrame(); - doDebugFlashRegions(displayDevice, repaintEverything); - doComposition(displayDevice, repaintEverything); + display->devOptRepaintFlash(refreshArgs); + doComposition(displayDevice, refreshArgs.repaintEverything); } postFrame(); @@ -1915,36 +1919,6 @@ void SurfaceFlinger::calculateWorkingSet() { } } -void SurfaceFlinger::doDebugFlashRegions(const sp& displayDevice, - bool repaintEverything) { - auto display = displayDevice->getCompositionDisplay(); - const auto& displayState = display->getState(); - - // is debugging enabled - if (CC_LIKELY(!mDebugRegion)) - return; - - if (displayState.isEnabled) { - // transform the dirty region into this screen's coordinate space - const Region dirtyRegion = display->getDirtyRegion(repaintEverything); - if (!dirtyRegion.isEmpty()) { - base::unique_fd readyFence; - // redraw the whole screen - display->composeSurfaces(dirtyRegion, &readyFence); - - display->getRenderSurface()->queueBuffer(std::move(readyFence)); - } - } - - displayDevice->getCompositionDisplay()->postFramebuffer(); - - if (mDebugRegion > 1) { - usleep(mDebugRegion * 1000); - } - - displayDevice->getCompositionDisplay()->prepareFrame(); -} - void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime, std::shared_ptr& presentFenceTime) { // Update queue of past composite+present times and determine the diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8408ef5174..bc57284488 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -763,7 +763,6 @@ private: void calculateWorkingSet(); void doComposition(const sp& display, bool repainEverything); - void doDebugFlashRegions(const sp& display, bool repaintEverything); void doDisplayComposition(const sp& display, const Region& dirtyRegion); void postFrame(); -- GitLab From d3d6988c925732192b5349fe2a4b5689df0d1abb Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 28 Feb 2019 16:03:46 -0800 Subject: [PATCH 0207/1255] SF: Move/Refactor doComposition and doDisplayComposition to CompositionEngine Test: atest libsurfaceflinger_unittest libcompositionengine_test Test: atest CtsColorModeTestCases Test: atest CtsDisplayTestCases Test: atest CtsGraphicsTestCases Test: atest CtsUiRenderingTestCases Test: atest CtsViewTestCases Test: atest android.media.cts.EncodeVirtualDisplayWithCompositionTest Bug: 121291683 Change-Id: I6c796ec613ce163764a403bcd669dab38300f437 --- .../include/compositionengine/Output.h | 8 +- .../include/compositionengine/impl/Display.h | 1 + .../include/compositionengine/impl/Output.h | 3 +- .../include/compositionengine/mock/Output.h | 4 +- .../CompositionEngine/src/Display.cpp | 16 ++++ .../CompositionEngine/src/Output.cpp | 36 ++++++-- .../CompositionEngine/tests/DisplayTest.cpp | 85 +++++++++++++++++++ .../CompositionEngine/tests/OutputTest.cpp | 8 +- services/surfaceflinger/SurfaceFlinger.cpp | 43 +--------- services/surfaceflinger/SurfaceFlinger.h | 2 - 10 files changed, 149 insertions(+), 57 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index df7add2f08..fa2bb46f17 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -162,11 +162,15 @@ public: // Performs any debug related screen flashing due to the update virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0; + // Finishes the current frame on the output, performing client composition + // and ensuring the content is displayed. + virtual void finishFrame(const CompositionRefreshArgs&) = 0; + // Performs client composition as needed for layers on the output. The // output fence is set to a fence to signal when client composition is // finished. - // Returns false if client composition cannot be performed. - virtual bool composeSurfaces(const Region& debugFence, base::unique_fd* outReadyFence) = 0; + // Returns std::nullopt if client composition cannot be performed. + virtual std::optional composeSurfaces(const Region&) = 0; // Posts the new frame, and sets release fences. virtual void postFramebuffer() = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index 36e4aac76e..bdc1291873 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -46,6 +46,7 @@ public: bool getSkipColorTransform() const override; compositionengine::Output::FrameFences presentAndGetFrameFences() override; void setExpensiveRenderingExpected(bool) override; + void finishFrame(const compositionengine::CompositionRefreshArgs&) override; // compositionengine::Display overrides const std::optional& getId() const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 36d6a692e9..b854314381 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -78,7 +78,8 @@ public: void beginFrame() override; void prepareFrame() override; void devOptRepaintFlash(const compositionengine::CompositionRefreshArgs&) override; - bool composeSurfaces(const Region&, base::unique_fd*) override; + void finishFrame(const compositionengine::CompositionRefreshArgs&) override; + std::optional composeSurfaces(const Region&) override; void postFramebuffer() override; // Testing diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index b9e1c9c007..ade745c4f9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -80,7 +80,9 @@ public: MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&)); - MOCK_METHOD2(composeSurfaces, bool(const Region&, base::unique_fd*)); + MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&)); + + MOCK_METHOD1(composeSurfaces, std::optional(const Region&)); MOCK_CONST_METHOD0(getSkipColorTransform, bool()); MOCK_METHOD0(postFramebuffer, void()); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 6cd392eabd..cabbc085c8 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -259,4 +260,19 @@ void Display::setExpensiveRenderingExpected(bool enabled) { } } +void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) { + // We only need to actually compose the display if: + // 1) It is being handled by hardware composer, which may need this to + // keep its virtual display state machine in sync, or + // 2) There is work to be done (the dirty region isn't empty) + if (!mId) { + if (getDirtyRegion(refreshArgs.repaintEverything).isEmpty()) { + ALOGV("Skipping display composition"); + return; + } + } + + impl::Output::finishFrame(refreshArgs); +} + } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 10534f4de3..8b156f8e09 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -313,7 +313,7 @@ void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& if (!dirtyRegion.isEmpty()) { base::unique_fd readyFence; // redraw the whole screen - composeSurfaces(dirtyRegion, &readyFence); + static_cast(composeSurfaces(dirtyRegion)); mRenderSurface->queueBuffer(std::move(readyFence)); } @@ -326,14 +326,35 @@ void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& prepareFrame(); } -bool Output::composeSurfaces(const Region& debugRegion, base::unique_fd* readyFence) { +void Output::finishFrame(const compositionengine::CompositionRefreshArgs&) { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + + if (!mState.isEnabled) { + return; + } + + // Repaint the framebuffer (if needed), getting the optional fence for when + // the composition completes. + auto optReadyFence = composeSurfaces(Region::INVALID_REGION); + if (!optReadyFence) { + return; + } + + // swap buffers (presentation) + mRenderSurface->queueBuffer(std::move(*optReadyFence)); +} + +std::optional Output::composeSurfaces(const Region& debugRegion) { ATRACE_CALL(); ALOGV(__FUNCTION__); const TracedOrdinal hasClientComposition = {"hasClientComposition", mState.usesClientComposition}; + base::unique_fd readyFence; + if (!hasClientComposition) { - return true; + return readyFence; } ALOGV("hasClientComposition"); @@ -389,7 +410,7 @@ bool Output::composeSurfaces(const Region& debugRegion, base::unique_fd* readyFe ALOGW("Dequeuing buffer for display [%s] failed, bailing out of " "client composition for this frame", mName.c_str()); - return false; + return std::nullopt; } // We boost GPU frequency here because there will be color spaces conversion @@ -404,13 +425,13 @@ bool Output::composeSurfaces(const Region& debugRegion, base::unique_fd* readyFe renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers, buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd), - readyFence); + &readyFence); if (expensiveRenderingExpected) { setExpensiveRenderingExpected(false); } - return true; + return readyFence; } std::vector Output::generateClientCompositionRequests( @@ -507,6 +528,9 @@ void Output::postFramebuffer() { return; } + mState.dirtyRegion.clear(); + mRenderSurface->flip(); + auto frame = presentAndGetFrameFences(); mRenderSurface->onPresentDisplayCompleted(); diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 743da8207a..e9752605d4 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -537,5 +537,90 @@ TEST_F(DisplayTest, setExpensiveRenderingExpectedForwardsToPowerAdvisor) { mDisplay.setExpensiveRenderingExpected(false); } +/* + * Display::finishFrame() + */ + +TEST_F(DisplayTest, finishFrameDoesNotSkipCompositionIfNotDirtyOnHwcDisplay) { + mock::RenderSurface* renderSurface = new StrictMock(); + mDisplay.setRenderSurfaceForTest(std::unique_ptr(renderSurface)); + + // We expect no calls to queueBuffer if composition was skipped. + EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1); + + mDisplay.editState().isEnabled = true; + mDisplay.editState().usesClientComposition = false; + mDisplay.editState().viewport = Rect(0, 0, 1, 1); + mDisplay.editState().dirtyRegion = Region::INVALID_REGION; + + CompositionRefreshArgs refreshArgs; + refreshArgs.repaintEverything = false; + + mDisplay.finishFrame(refreshArgs); +} + +TEST_F(DisplayTest, finishFrameSkipsCompositionIfNotDirty) { + std::shared_ptr nonHwcDisplay{ + impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; + + mock::RenderSurface* renderSurface = new StrictMock(); + nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); + + // We expect no calls to queueBuffer if composition was skipped. + EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(0); + + nonHwcDisplay->editState().isEnabled = true; + nonHwcDisplay->editState().usesClientComposition = false; + nonHwcDisplay->editState().viewport = Rect(0, 0, 1, 1); + nonHwcDisplay->editState().dirtyRegion = Region::INVALID_REGION; + + CompositionRefreshArgs refreshArgs; + refreshArgs.repaintEverything = false; + + nonHwcDisplay->finishFrame(refreshArgs); +} + +TEST_F(DisplayTest, finishFramePerformsCompositionIfDirty) { + std::shared_ptr nonHwcDisplay{ + impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; + + mock::RenderSurface* renderSurface = new StrictMock(); + nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); + + // We expect a single call to queueBuffer when composition is not skipped. + EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1); + + nonHwcDisplay->editState().isEnabled = true; + nonHwcDisplay->editState().usesClientComposition = false; + nonHwcDisplay->editState().viewport = Rect(0, 0, 1, 1); + nonHwcDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1)); + + CompositionRefreshArgs refreshArgs; + refreshArgs.repaintEverything = false; + + nonHwcDisplay->finishFrame(refreshArgs); +} + +TEST_F(DisplayTest, finishFramePerformsCompositionIfRepaintEverything) { + std::shared_ptr nonHwcDisplay{ + impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; + + mock::RenderSurface* renderSurface = new StrictMock(); + nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); + + // We expect a single call to queueBuffer when composition is not skipped. + EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1); + + nonHwcDisplay->editState().isEnabled = true; + nonHwcDisplay->editState().usesClientComposition = false; + nonHwcDisplay->editState().viewport = Rect(0, 0, 1, 1); + nonHwcDisplay->editState().dirtyRegion = Region::INVALID_REGION; + + CompositionRefreshArgs refreshArgs; + refreshArgs.repaintEverything = true; + + nonHwcDisplay->finishFrame(refreshArgs); +} + } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index f4d2cf180b..eddb67f45b 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -527,8 +527,8 @@ TEST_F(OutputComposeSurfacesTest, doesNothingIfNoClientComposition) { mOutput.editState().usesClientComposition = false; Region debugRegion; - base::unique_fd readyFence; - EXPECT_EQ(true, mOutput.composeSurfaces(debugRegion, &readyFence)); + std::optional readyFence = mOutput.composeSurfaces(debugRegion); + EXPECT_TRUE(readyFence); } TEST_F(OutputComposeSurfacesTest, worksIfNoClientLayersQueued) { @@ -556,8 +556,8 @@ TEST_F(OutputComposeSurfacesTest, worksIfNoClientLayersQueued) { EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)).Times(1); EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false)).Times(1); - base::unique_fd readyFence; - EXPECT_EQ(true, mOutput.composeSurfaces(kDebugRegion, &readyFence)); + std::optional readyFence = mOutput.composeSurfaces(kDebugRegion); + EXPECT_TRUE(readyFence); } /* diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index dd0890c820..1875151376 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1801,7 +1801,8 @@ void SurfaceFlinger::handleMessageRefresh() { display->beginFrame(); display->prepareFrame(); display->devOptRepaintFlash(refreshArgs); - doComposition(displayDevice, refreshArgs.repaintEverything); + display->finishFrame(refreshArgs); + display->postFramebuffer(); } postFrame(); @@ -2321,26 +2322,6 @@ void SurfaceFlinger::pickColorMode(const sp& display, ColorMode* profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent); } -void SurfaceFlinger::doComposition(const sp& displayDevice, bool repaintEverything) { - ATRACE_CALL(); - ALOGV("doComposition"); - - auto display = displayDevice->getCompositionDisplay(); - const auto& displayState = display->getState(); - - if (displayState.isEnabled) { - // transform the dirty region into this screen's coordinate space - const Region dirtyRegion = display->getDirtyRegion(repaintEverything); - - // repaint the framebuffer (if needed) - doDisplayComposition(displayDevice, dirtyRegion); - - display->editState().dirtyRegion.clear(); - display->getRenderSurface()->flip(); - } - displayDevice->getCompositionDisplay()->postFramebuffer(); -} - void SurfaceFlinger::postFrame() { // |mStateLock| not needed as we are on the main thread @@ -3162,26 +3143,6 @@ void SurfaceFlinger::invalidateHwcGeometry() mGeometryInvalid = true; } -void SurfaceFlinger::doDisplayComposition(const sp& displayDevice, - const Region& inDirtyRegion) { - auto display = displayDevice->getCompositionDisplay(); - // We only need to actually compose the display if: - // 1) It is being handled by hardware composer, which may need this to - // keep its virtual display state machine in sync, or - // 2) There is work to be done (the dirty region isn't empty) - if (!displayDevice->getId() && inDirtyRegion.isEmpty()) { - ALOGV("Skipping display composition"); - return; - } - - ALOGV("doDisplayComposition"); - base::unique_fd readyFence; - if (!display->composeSurfaces(Region::INVALID_REGION, &readyFence)) return; - - // swap buffers (presentation) - display->getRenderSurface()->queueBuffer(std::move(readyFence)); -} - status_t SurfaceFlinger::addClientLayer(const sp& client, const sp& handle, const sp& gbc, const sp& lbc, const sp& parentHandle, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index bc57284488..9acd9750b7 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -762,8 +762,6 @@ private: ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const; void calculateWorkingSet(); - void doComposition(const sp& display, bool repainEverything); - void doDisplayComposition(const sp& display, const Region& dirtyRegion); void postFrame(); -- GitLab From 6a3b44698f365cb608f43df6e45844b4e18d3064 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 7 Mar 2019 20:58:12 -0800 Subject: [PATCH 0208/1255] SF: Move pickColorMode and getBestDataspace to CompositionEngine Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: I37c39f49bf0e1c851d0d5e4040dc3aa3e433e9f8 --- .../CompositionRefreshArgs.h | 10 ++ .../include/compositionengine/Output.h | 13 +- .../compositionengine/OutputColorSetting.h | 27 ++++ .../include/compositionengine/impl/Display.h | 2 +- .../include/compositionengine/impl/Output.h | 7 +- .../include/compositionengine/mock/Output.h | 4 +- .../CompositionEngine/src/Display.cpp | 22 +-- .../CompositionEngine/src/Output.cpp | 139 +++++++++++++++-- .../CompositionEngine/tests/DisplayTest.cpp | 18 ++- .../CompositionEngine/tests/OutputTest.cpp | 14 +- services/surfaceflinger/SurfaceFlinger.cpp | 147 +++--------------- services/surfaceflinger/SurfaceFlinger.h | 22 +-- .../surfaceflinger/tests/fakehwc/Android.bp | 1 + .../unittests/DisplayTransactionTest.cpp | 6 +- 14 files changed, 248 insertions(+), 184 deletions(-) create mode 100644 services/surfaceflinger/CompositionEngine/include/compositionengine/OutputColorSetting.h diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index b329f76445..1001cf7e02 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -21,6 +21,7 @@ #include #include +#include namespace android::compositionengine { @@ -42,6 +43,15 @@ struct CompositionRefreshArgs { // If true, forces the entire display to be considered dirty and repainted bool repaintEverything{false}; + // Controls how the color mode is chosen for an output + OutputColorSetting outputColorSetting{OutputColorSetting::kEnhanced}; + + // If not Dataspace::UNKNOWN, overrides the dataspace on each output + ui::Dataspace colorSpaceAgnosticDataspace{ui::Dataspace::UNKNOWN}; + + // Forces a color mode on the outputs being refreshed + ui::ColorMode forceOutputColorMode{ui::ColorMode::NATIVE}; + // If set, causes the dirty regions to flash with the delay std::optional devOptFlashDirtyRegionsDelay; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index fa2bb46f17..82cde4b82e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -63,6 +63,13 @@ public: std::unordered_map> layerFences; }; + struct ColorProfile { + ui::ColorMode mode{ui::ColorMode::NATIVE}; + ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; + ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC}; + ui::Dataspace colorSpaceAgnosticDataspace{ui::Dataspace::UNKNOWN}; + }; + virtual ~Output(); // Returns true if the output is valid. This is meant to be checked post- @@ -87,8 +94,7 @@ public: virtual void setColorTransform(const mat4&) = 0; // Sets the output color mode - virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, - ui::Dataspace colorSpaceAgnosticDataspace) = 0; + virtual void setColorProfile(const ColorProfile&) = 0; // Outputs a string with a state dump virtual void dump(std::string&) const = 0; @@ -153,6 +159,9 @@ public: // Takes (moves) the set of layers being released this frame. virtual ReleasedLayers takeReleasedLayers() = 0; + // Updates the color mode used on this output + virtual void updateColorProfile(const CompositionRefreshArgs&) = 0; + // Signals that a frame is beginning on the output virtual void beginFrame() = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputColorSetting.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputColorSetting.h new file mode 100644 index 0000000000..6e798cea55 --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputColorSetting.h @@ -0,0 +1,27 @@ +/* + * 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 + +namespace android::compositionengine { + +enum class OutputColorSetting : int32_t { + kManaged = 0, + kUnmanaged = 1, + kEnhanced = 2, +}; + +} // namespace android::compositionengine \ No newline at end of file diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index bdc1291873..dba112eb4e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -41,7 +41,7 @@ public: // compositionengine::Output overrides void dump(std::string&) const override; void setColorTransform(const mat4&) override; - void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override; + void setColorProfile(const ColorProfile&) override; void chooseCompositionStrategy() override; bool getSkipColorTransform() const override; compositionengine::Output::FrameFences presentAndGetFrameFences() override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index b854314381..904edc791c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -45,7 +45,7 @@ public: void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override; void setColorTransform(const mat4&) override; - void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override; + void setColorProfile(const ColorProfile&) override; void dump(std::string&) const override; @@ -75,6 +75,8 @@ public: void setReleasedLayers(ReleasedLayers&&) override; ReleasedLayers takeReleasedLayers() override; + void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override; + void beginFrame() override; void prepareFrame() override; void devOptRepaintFlash(const compositionengine::CompositionRefreshArgs&) override; @@ -100,6 +102,9 @@ protected: private: void dirtyEntireOutput(); + ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const; + compositionengine::Output::ColorProfile pickColorProfile( + const compositionengine::CompositionRefreshArgs&) const; const CompositionEngine& mCompositionEngine; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index ade745c4f9..44cd5e99de 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -42,7 +42,7 @@ public: MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool)); MOCK_METHOD1(setColorTransform, void(const mat4&)); - MOCK_METHOD4(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace)); + MOCK_METHOD1(setColorProfile, void(const ColorProfile&)); MOCK_CONST_METHOD1(dump, void(std::string&)); MOCK_CONST_METHOD0(getName, const std::string&()); @@ -74,6 +74,8 @@ public: MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&)); MOCK_METHOD0(takeReleasedLayers, ReleasedLayers()); + MOCK_METHOD1(updateColorProfile, void(const compositionengine::CompositionRefreshArgs&)); + MOCK_METHOD0(beginFrame, void()); MOCK_METHOD0(prepareFrame, void()); MOCK_METHOD0(chooseCompositionStrategy, void()); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index cabbc085c8..108720a52b 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -78,15 +78,15 @@ void Display::setColorTransform(const mat4& transform) { mId ? to_string(*mId).c_str() : "", result); } -void Display::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace, - ui::RenderIntent renderIntent, - ui::Dataspace colorSpaceAgnosticDataspace) { - ui::Dataspace targetDataspace = - getDisplayColorProfile()->getTargetDataspace(mode, dataspace, - colorSpaceAgnosticDataspace); - - if (mode == getState().colorMode && dataspace == getState().dataspace && - renderIntent == getState().renderIntent && targetDataspace == getState().targetDataspace) { +void Display::setColorProfile(const ColorProfile& colorProfile) { + const ui::Dataspace targetDataspace = + getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace, + colorProfile.colorSpaceAgnosticDataspace); + + if (colorProfile.mode == getState().colorMode && + colorProfile.dataspace == getState().dataspace && + colorProfile.renderIntent == getState().renderIntent && + targetDataspace == getState().targetDataspace) { return; } @@ -95,10 +95,10 @@ void Display::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace, return; } - Output::setColorMode(mode, dataspace, renderIntent, colorSpaceAgnosticDataspace); + Output::setColorProfile(colorProfile); auto& hwc = getCompositionEngine().getHwComposer(); - hwc.setActiveColorMode(*mId, mode, renderIntent); + hwc.setActiveColorMode(*mId, colorProfile.mode, colorProfile.renderIntent); } void Display::dump(std::string& out) const { diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 8b156f8e09..cc7e4533f4 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -114,28 +114,27 @@ void Output::setColorTransform(const mat4& transform) { dirtyEntireOutput(); } -void Output::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace, - ui::RenderIntent renderIntent, - ui::Dataspace colorSpaceAgnosticDataspace) { - ui::Dataspace targetDataspace = - getDisplayColorProfile()->getTargetDataspace(mode, dataspace, - colorSpaceAgnosticDataspace); - - if (mState.colorMode == mode && mState.dataspace == dataspace && - mState.renderIntent == renderIntent && mState.targetDataspace == targetDataspace) { +void Output::setColorProfile(const ColorProfile& colorProfile) { + const ui::Dataspace targetDataspace = + getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace, + colorProfile.colorSpaceAgnosticDataspace); + + if (mState.colorMode == colorProfile.mode && mState.dataspace == colorProfile.dataspace && + mState.renderIntent == colorProfile.renderIntent && + mState.targetDataspace == targetDataspace) { return; } - mState.colorMode = mode; - mState.dataspace = dataspace; - mState.renderIntent = renderIntent; + mState.colorMode = colorProfile.mode; + mState.dataspace = colorProfile.dataspace; + mState.renderIntent = colorProfile.renderIntent; mState.targetDataspace = targetDataspace; - mRenderSurface->setBufferDataspace(dataspace); + mRenderSurface->setBufferDataspace(colorProfile.dataspace); ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)", - decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(), - renderIntent); + decodeColorMode(colorProfile.mode).c_str(), colorProfile.mode, + decodeRenderIntent(colorProfile.renderIntent).c_str(), colorProfile.renderIntent); dirtyEntireOutput(); } @@ -261,6 +260,116 @@ Output::ReleasedLayers Output::takeReleasedLayers() { return std::move(mReleasedLayers); } +void Output::updateColorProfile(const compositionengine::CompositionRefreshArgs& refreshArgs) { + setColorProfile(pickColorProfile(refreshArgs)); +} + +// Returns a data space that fits all visible layers. The returned data space +// can only be one of +// - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced) +// - Dataspace::DISPLAY_P3 +// - Dataspace::DISPLAY_BT2020 +// The returned HDR data space is one of +// - Dataspace::UNKNOWN +// - Dataspace::BT2020_HLG +// - Dataspace::BT2020_PQ +ui::Dataspace Output::getBestDataspace(ui::Dataspace* outHdrDataSpace, + bool* outIsHdrClientComposition) const { + ui::Dataspace bestDataSpace = ui::Dataspace::V0_SRGB; + *outHdrDataSpace = ui::Dataspace::UNKNOWN; + + for (const auto& layer : mOutputLayersOrderedByZ) { + switch (layer->getLayer().getState().frontEnd.dataspace) { + case ui::Dataspace::V0_SCRGB: + case ui::Dataspace::V0_SCRGB_LINEAR: + case ui::Dataspace::BT2020: + case ui::Dataspace::BT2020_ITU: + case ui::Dataspace::BT2020_LINEAR: + case ui::Dataspace::DISPLAY_BT2020: + bestDataSpace = ui::Dataspace::DISPLAY_BT2020; + break; + case ui::Dataspace::DISPLAY_P3: + bestDataSpace = ui::Dataspace::DISPLAY_P3; + break; + case ui::Dataspace::BT2020_PQ: + case ui::Dataspace::BT2020_ITU_PQ: + bestDataSpace = ui::Dataspace::DISPLAY_P3; + *outHdrDataSpace = ui::Dataspace::BT2020_PQ; + *outIsHdrClientComposition = + layer->getLayer().getState().frontEnd.forceClientComposition; + break; + case ui::Dataspace::BT2020_HLG: + case ui::Dataspace::BT2020_ITU_HLG: + bestDataSpace = ui::Dataspace::DISPLAY_P3; + // When there's mixed PQ content and HLG content, we set the HDR + // data space to be BT2020_PQ and convert HLG to PQ. + if (*outHdrDataSpace == ui::Dataspace::UNKNOWN) { + *outHdrDataSpace = ui::Dataspace::BT2020_HLG; + } + break; + default: + break; + } + } + + return bestDataSpace; +} + +compositionengine::Output::ColorProfile Output::pickColorProfile( + const compositionengine::CompositionRefreshArgs& refreshArgs) const { + if (refreshArgs.outputColorSetting == OutputColorSetting::kUnmanaged) { + return ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, + ui::RenderIntent::COLORIMETRIC, + refreshArgs.colorSpaceAgnosticDataspace}; + } + + ui::Dataspace hdrDataSpace; + bool isHdrClientComposition = false; + ui::Dataspace bestDataSpace = getBestDataspace(&hdrDataSpace, &isHdrClientComposition); + + switch (refreshArgs.forceOutputColorMode) { + case ui::ColorMode::SRGB: + bestDataSpace = ui::Dataspace::V0_SRGB; + break; + case ui::ColorMode::DISPLAY_P3: + bestDataSpace = ui::Dataspace::DISPLAY_P3; + break; + default: + break; + } + + // respect hdrDataSpace only when there is no legacy HDR support + const bool isHdr = hdrDataSpace != ui::Dataspace::UNKNOWN && + !mDisplayColorProfile->hasLegacyHdrSupport(hdrDataSpace) && !isHdrClientComposition; + if (isHdr) { + bestDataSpace = hdrDataSpace; + } + + ui::RenderIntent intent; + switch (refreshArgs.outputColorSetting) { + case OutputColorSetting::kManaged: + case OutputColorSetting::kUnmanaged: + intent = isHdr ? ui::RenderIntent::TONE_MAP_COLORIMETRIC + : ui::RenderIntent::COLORIMETRIC; + break; + case OutputColorSetting::kEnhanced: + intent = isHdr ? ui::RenderIntent::TONE_MAP_ENHANCE : ui::RenderIntent::ENHANCE; + break; + default: // vendor display color setting + intent = static_cast(refreshArgs.outputColorSetting); + break; + } + + ui::ColorMode outMode; + ui::Dataspace outDataSpace; + ui::RenderIntent outRenderIntent; + mDisplayColorProfile->getBestColorMode(bestDataSpace, intent, &outDataSpace, &outMode, + &outRenderIntent); + + return ColorProfile{outMode, outDataSpace, outRenderIntent, + refreshArgs.colorSpaceAgnosticDataspace}; +} + void Output::beginFrame() { const bool dirty = !getDirtyRegion(false).isEmpty(); const bool empty = mOutputLayersOrderedByZ.empty(); diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index e9752605d4..06e3a70665 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -162,6 +162,8 @@ TEST_F(DisplayTest, setColorTransformSetsTransform) { */ TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) { + using ColorProfile = Output::ColorProfile; + mock::RenderSurface* renderSurface = new StrictMock(); mDisplay.setRenderSurfaceForTest(std::unique_ptr(renderSurface)); mock::DisplayColorProfile* colorProfile = new StrictMock(); @@ -177,8 +179,8 @@ TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) { ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace); // If the set values are unchanged, nothing happens - mDisplay.setColorMode(ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, - ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN); + mDisplay.setColorProfile(ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, + ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN}); EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode); EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace); @@ -192,8 +194,9 @@ TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) { ui::RenderIntent::TONE_MAP_COLORIMETRIC)) .Times(1); - mDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN); + mDisplay.setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, + ui::RenderIntent::TONE_MAP_COLORIMETRIC, + ui::Dataspace::UNKNOWN}); EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mDisplay.getState().colorMode); EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mDisplay.getState().dataspace); @@ -202,6 +205,8 @@ TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) { } TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) { + using ColorProfile = Output::ColorProfile; + impl::Display virtualDisplay{mCompositionEngine, DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}}; @@ -214,8 +219,9 @@ TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) { ui::Dataspace::UNKNOWN)) .WillOnce(Return(ui::Dataspace::UNKNOWN)); - virtualDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN); + virtualDisplay.setColorProfile( + ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, + ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN}); EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode); EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay.getState().dataspace); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index eddb67f45b..dccad58dde 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -211,14 +211,17 @@ TEST_F(OutputTest, setColorTransformSetsTransform) { */ TEST_F(OutputTest, setColorModeSetsStateAndDirtiesOutputIfChanged) { + using ColorProfile = Output::ColorProfile; + EXPECT_CALL(*mDisplayColorProfile, getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, ui::Dataspace::UNKNOWN)) .WillOnce(Return(ui::Dataspace::UNKNOWN)); EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1); - mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN); + mOutput.setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, + ui::RenderIntent::TONE_MAP_COLORIMETRIC, + ui::Dataspace::UNKNOWN}); EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput.getState().colorMode); EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput.getState().dataspace); @@ -229,6 +232,8 @@ TEST_F(OutputTest, setColorModeSetsStateAndDirtiesOutputIfChanged) { } TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) { + using ColorProfile = Output::ColorProfile; + EXPECT_CALL(*mDisplayColorProfile, getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, ui::Dataspace::UNKNOWN)) @@ -239,8 +244,9 @@ TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) { mOutput.editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC; mOutput.editState().targetDataspace = ui::Dataspace::UNKNOWN; - mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN); + mOutput.setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, + ui::RenderIntent::TONE_MAP_COLORIMETRIC, + ui::Dataspace::UNKNOWN}); EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region())); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1875151376..83f3b2cecd 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -239,11 +239,11 @@ bool useTrebleTestingOverride() { std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { switch(displayColorSetting) { - case DisplayColorSetting::MANAGED: + case DisplayColorSetting::kManaged: return std::string("Managed"); - case DisplayColorSetting::UNMANAGED: + case DisplayColorSetting::kUnmanaged: return std::string("Unmanaged"); - case DisplayColorSetting::ENHANCED: + case DisplayColorSetting::kEnhanced: return std::string("Enhanced"); default: return std::string("Unknown ") + @@ -1133,9 +1133,10 @@ status_t SurfaceFlinger::setActiveColorMode(const sp& displayToken, Col ALOGW("Attempt to set active color mode %s (%d) for virtual display", decodeColorMode(mode).c_str(), mode); } else { - display->getCompositionDisplay()->setColorMode(mode, Dataspace::UNKNOWN, - RenderIntent::COLORIMETRIC, - Dataspace::UNKNOWN); + display->getCompositionDisplay()->setColorProfile( + compositionengine::Output::ColorProfile{mode, Dataspace::UNKNOWN, + RenderIntent::COLORIMETRIC, + Dataspace::UNKNOWN}); } })); @@ -1788,6 +1789,11 @@ void SurfaceFlinger::handleMessageRefresh() { if (compositionLayer) refreshArgs.layers.push_back(compositionLayer); }); refreshArgs.repaintEverything = mRepaintEverything.exchange(false); + refreshArgs.outputColorSetting = useColorManagement + ? mDisplayColorSetting + : compositionengine::OutputColorSetting::kUnmanaged; + refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace; + refreshArgs.forceOutputColorMode = mForceColorMode; if (mDebugRegion != 0) { refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0); @@ -1795,7 +1801,7 @@ void SurfaceFlinger::handleMessageRefresh() { mCompositionEngine->preComposition(refreshArgs); rebuildLayerStacks(); - calculateWorkingSet(); + calculateWorkingSet(refreshArgs); for (const auto& [token, displayDevice] : mDisplays) { auto display = displayDevice->getCompositionDisplay(); display->beginFrame(); @@ -1852,7 +1858,8 @@ bool SurfaceFlinger::handleMessageInvalidate() { return refreshNeeded; } -void SurfaceFlinger::calculateWorkingSet() { +void SurfaceFlinger::calculateWorkingSet( + const compositionengine::CompositionRefreshArgs& refreshArgs) { ATRACE_CALL(); ALOGV(__FUNCTION__); @@ -1884,14 +1891,7 @@ void SurfaceFlinger::calculateWorkingSet() { // Determine the color configuration of each output for (const auto& [token, displayDevice] : mDisplays) { auto display = displayDevice->getCompositionDisplay(); - - ColorMode colorMode = ColorMode::NATIVE; - Dataspace dataspace = Dataspace::UNKNOWN; - RenderIntent renderIntent = RenderIntent::COLORIMETRIC; - if (useColorManagement) { - pickColorMode(displayDevice, &colorMode, &dataspace, &renderIntent); - } - display->setColorMode(colorMode, dataspace, renderIntent, mColorSpaceAgnosticDataspace); + display->updateColorProfile(refreshArgs); } for (const auto& [token, displayDevice] : mDisplays) { @@ -2219,109 +2219,6 @@ void SurfaceFlinger::rebuildLayerStacks() { } } -// Returns a data space that fits all visible layers. The returned data space -// can only be one of -// - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced) -// - Dataspace::DISPLAY_P3 -// - Dataspace::DISPLAY_BT2020 -// The returned HDR data space is one of -// - Dataspace::UNKNOWN -// - Dataspace::BT2020_HLG -// - Dataspace::BT2020_PQ -Dataspace SurfaceFlinger::getBestDataspace(const sp& display, - Dataspace* outHdrDataSpace, - bool* outIsHdrClientComposition) const { - Dataspace bestDataSpace = Dataspace::V0_SRGB; - *outHdrDataSpace = Dataspace::UNKNOWN; - - for (const auto& layer : display->getVisibleLayersSortedByZ()) { - switch (layer->getDataSpace()) { - case Dataspace::V0_SCRGB: - case Dataspace::V0_SCRGB_LINEAR: - case Dataspace::BT2020: - case Dataspace::BT2020_ITU: - case Dataspace::BT2020_LINEAR: - case Dataspace::DISPLAY_BT2020: - bestDataSpace = Dataspace::DISPLAY_BT2020; - break; - case Dataspace::DISPLAY_P3: - bestDataSpace = Dataspace::DISPLAY_P3; - break; - case Dataspace::BT2020_PQ: - case Dataspace::BT2020_ITU_PQ: - bestDataSpace = Dataspace::DISPLAY_P3; - *outHdrDataSpace = Dataspace::BT2020_PQ; - *outIsHdrClientComposition = - layer->getCompositionLayer()->getState().frontEnd.forceClientComposition; - break; - case Dataspace::BT2020_HLG: - case Dataspace::BT2020_ITU_HLG: - bestDataSpace = Dataspace::DISPLAY_P3; - // When there's mixed PQ content and HLG content, we set the HDR - // data space to be BT2020_PQ and convert HLG to PQ. - if (*outHdrDataSpace == Dataspace::UNKNOWN) { - *outHdrDataSpace = Dataspace::BT2020_HLG; - } - break; - default: - break; - } - } - - return bestDataSpace; -} - -// Pick the ColorMode / Dataspace for the display device. -void SurfaceFlinger::pickColorMode(const sp& display, ColorMode* outMode, - Dataspace* outDataSpace, RenderIntent* outRenderIntent) const { - if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) { - *outMode = ColorMode::NATIVE; - *outDataSpace = Dataspace::UNKNOWN; - *outRenderIntent = RenderIntent::COLORIMETRIC; - return; - } - - Dataspace hdrDataSpace; - bool isHdrClientComposition = false; - Dataspace bestDataSpace = getBestDataspace(display, &hdrDataSpace, &isHdrClientComposition); - - auto* profile = display->getCompositionDisplay()->getDisplayColorProfile(); - - switch (mForceColorMode) { - case ColorMode::SRGB: - bestDataSpace = Dataspace::V0_SRGB; - break; - case ColorMode::DISPLAY_P3: - bestDataSpace = Dataspace::DISPLAY_P3; - break; - default: - break; - } - - // respect hdrDataSpace only when there is no legacy HDR support - const bool isHdr = hdrDataSpace != Dataspace::UNKNOWN && - !profile->hasLegacyHdrSupport(hdrDataSpace) && !isHdrClientComposition; - if (isHdr) { - bestDataSpace = hdrDataSpace; - } - - RenderIntent intent; - switch (mDisplayColorSetting) { - case DisplayColorSetting::MANAGED: - case DisplayColorSetting::UNMANAGED: - intent = isHdr ? RenderIntent::TONE_MAP_COLORIMETRIC : RenderIntent::COLORIMETRIC; - break; - case DisplayColorSetting::ENHANCED: - intent = isHdr ? RenderIntent::TONE_MAP_ENHANCE : RenderIntent::ENHANCE; - break; - default: // vendor display color setting - intent = static_cast(mDisplayColorSetting); - break; - } - - profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent); -} - void SurfaceFlinger::postFrame() { // |mStateLock| not needed as we are on the main thread @@ -2469,8 +2366,10 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( defaultColorMode = ColorMode::SRGB; defaultDataSpace = Dataspace::V0_SRGB; } - display->getCompositionDisplay()->setColorMode(defaultColorMode, defaultDataSpace, - RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN); + display->getCompositionDisplay()->setColorProfile( + compositionengine::Output::ColorProfile{defaultColorMode, defaultDataSpace, + RenderIntent::COLORIMETRIC, + Dataspace::UNKNOWN}); if (!state.isVirtual()) { LOG_ALWAYS_FATAL_IF(!displayId); display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId)); @@ -5028,13 +4927,13 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r DisplayColorSetting setting = static_cast(data.readInt32()); switch (setting) { - case DisplayColorSetting::MANAGED: + case DisplayColorSetting::kManaged: reply->writeBool(useColorManagement); break; - case DisplayColorSetting::UNMANAGED: + case DisplayColorSetting::kUnmanaged: reply->writeBool(true); break; - case DisplayColorSetting::ENHANCED: + case DisplayColorSetting::kEnhanced: reply->writeBool(display->hasRenderIntent(RenderIntent::ENHANCE)); break; default: // vendor display color setting diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 9acd9750b7..1aa99fccfd 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -23,6 +23,7 @@ */ #include +#include #include #include #include @@ -97,6 +98,8 @@ class TimeStats; namespace compositionengine { class DisplaySurface; + +struct CompositionRefreshArgs; } // namespace compositionengine namespace renderengine { @@ -116,11 +119,7 @@ enum { eTransactionMask = 0x1f, }; -enum class DisplayColorSetting : int32_t { - MANAGED = 0, - UNMANAGED = 1, - ENHANCED = 2, -}; +using DisplayColorSetting = compositionengine::OutputColorSetting; class SurfaceFlingerBE { @@ -752,16 +751,7 @@ private: nsecs_t compositeToPresentLatency); void rebuildLayerStacks(); - ui::Dataspace getBestDataspace(const sp& display, ui::Dataspace* outHdrDataSpace, - bool* outIsHdrClientComposition) const; - - // Returns the appropriate ColorMode, Dataspace and RenderIntent for the - // DisplayDevice. The function only returns the supported ColorMode, - // Dataspace and RenderIntent. - void pickColorMode(const sp& display, ui::ColorMode* outMode, - ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const; - - void calculateWorkingSet(); + void calculateWorkingSet(const compositionengine::CompositionRefreshArgs&); void postFrame(); @@ -1071,7 +1061,7 @@ private: static bool useVrFlinger; std::thread::id mMainThreadId = std::this_thread::get_id(); - DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::ENHANCED; + DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::kEnhanced; // Color mode forced by setting persist.sys.sf.color_mode, it must: // 1. not be NATIVE color mode, NATIVE color mode means no forced color mode; diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp index 57851bc850..3e290160b3 100644 --- a/services/surfaceflinger/tests/fakehwc/Android.bp +++ b/services/surfaceflinger/tests/fakehwc/Android.bp @@ -33,6 +33,7 @@ cc_test { "libutils", ], static_libs: [ + "libcompositionengine", "libgmock", "libperfetto_client_experimental", "librenderengine", diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index c858cc0b95..fcce57b382 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -149,7 +149,7 @@ DisplayTransactionTest::DisplayTransactionTest() { // Default to no wide color display support configured mFlinger.mutableHasWideColorDisplay() = false; mFlinger.mutableUseColorManagement() = false; - mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED; + mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged; // Default to using HWC virtual displays mFlinger.mutableUseHwcVirtualDisplays() = true; @@ -598,7 +598,7 @@ struct WideColorSupportNotConfiguredVariant { static void injectConfigChange(DisplayTransactionTest* test) { test->mFlinger.mutableHasWideColorDisplay() = false; test->mFlinger.mutableUseColorManagement() = false; - test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED; + test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged; } static void setupComposerCallExpectations(DisplayTransactionTest* test) { @@ -618,7 +618,7 @@ struct WideColorP3ColorimetricSupportedVariant { static void injectConfigChange(DisplayTransactionTest* test) { test->mFlinger.mutableUseColorManagement() = true; test->mFlinger.mutableHasWideColorDisplay() = true; - test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED; + test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged; } static void setupComposerCallExpectations(DisplayTransactionTest* test) { -- GitLab From c7b0c75f80c5cd5e1de1b7911981061bfd672f6e Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 7 Mar 2019 20:59:59 -0800 Subject: [PATCH 0209/1255] SF: Move/Refactor updateCursorAsync to CompositionEngine As part of this change, the existing LayerFE::latchCompositionState is extended to allow for more state types to be fetched. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: I71e0f547440a64c1025f36741beb68e72c18e475 --- .../compositionengine/CompositionEngine.h | 3 + .../include/compositionengine/LayerFE.h | 4 + .../LayerFECompositionState.h | 7 ++ .../include/compositionengine/OutputLayer.h | 6 ++ .../impl/CompositionEngine.h | 2 + .../compositionengine/impl/OutputLayer.h | 2 + .../mock/CompositionEngine.h | 1 + .../include/compositionengine/mock/LayerFE.h | 1 + .../compositionengine/mock/OutputLayer.h | 2 + .../src/CompositionEngine.cpp | 17 ++++ .../CompositionEngine/src/OutputLayer.cpp | 26 ++++++ .../tests/OutputLayerTest.cpp | 79 +++++++++++++++++++ services/surfaceflinger/Layer.cpp | 47 ++++------- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 13 ++- 15 files changed, 172 insertions(+), 40 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h index 31d6365bf4..298aff57a9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h @@ -58,6 +58,9 @@ public: virtual bool needsAnotherUpdate() const = 0; virtual nsecs_t getLastFrameRefreshTimestamp() const = 0; + // Updates the cursor position for the indicated outputs. + virtual void updateCursorAsync(CompositionRefreshArgs&) = 0; + // TODO(b/121291683): These will become private/internal virtual void preComposition(CompositionRefreshArgs&) = 0; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 2a901ae68b..db4f9698e2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -43,6 +43,10 @@ public: // geometry state can be skipped. virtual void latchCompositionState(LayerFECompositionState&, bool includeGeometry) const = 0; + // Latches the minimal bit of state for the cursor for a fast asynchronous + // update. + virtual void latchCursorCompositionState(LayerFECompositionState&) const = 0; + struct ClientCompositionTargetSettings { // The clip region, or visible region that is being rendered to const Region& clip; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index d5763d5611..6a0caf0746 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -122,6 +122,13 @@ struct LayerFECompositionState { // True if the layer has protected content bool hasProtectedContent{false}; + + /* + * Cursor state + */ + + // The output-independent frame for the cursor + Rect cursorFrame; }; } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index 5f62b32c9a..cedd728588 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -78,12 +78,18 @@ public: // skipped. virtual void writeStateToHWC(bool includeGeometry) = 0; + // Updates the cursor position with the HWC + virtual void writeCursorPositionToHWC() const = 0; + // Returns the HWC2::Layer associated with this layer, if it exists virtual HWC2::Layer* getHwcLayer() const = 0; // Returns true if the current layer state requires client composition virtual bool requiresClientComposition() const = 0; + // Returns true if the current layer should be treated as a cursor layer + virtual bool isHardwareCursor() const = 0; + // Applies a HWC device requested composition type change virtual void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h index 96e609d1c9..982a37604d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h @@ -39,6 +39,8 @@ public: bool needsAnotherUpdate() const override; nsecs_t getLastFrameRefreshTimestamp() const override; + void updateCursorAsync(CompositionRefreshArgs&) override; + void preComposition(CompositionRefreshArgs&) override; // Testing diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index 4c3f9359b0..fa4d8cd6db 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -49,9 +49,11 @@ public: void updateCompositionState(bool) override; void writeStateToHWC(bool) override; + void writeCursorPositionToHWC() const override; HWC2::Layer* getHwcLayer() const override; bool requiresClientComposition() const override; + bool isHardwareCursor() const override; void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override; void prepareForDeviceLayerRequests() override; void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h index 82ecec502d..6450b222dc 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h @@ -44,6 +44,7 @@ public: MOCK_CONST_METHOD0(needsAnotherUpdate, bool()); MOCK_CONST_METHOD0(getLastFrameRefreshTimestamp, nsecs_t()); + MOCK_METHOD1(updateCursorAsync, void(CompositionRefreshArgs&)); MOCK_METHOD1(preComposition, void(CompositionRefreshArgs&)); }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index 48c2dbf3d6..e2802954d6 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -33,6 +33,7 @@ public: MOCK_METHOD1(onPreComposition, bool(nsecs_t)); MOCK_CONST_METHOD2(latchCompositionState, void(LayerFECompositionState&, bool)); + MOCK_CONST_METHOD1(latchCursorCompositionState, void(LayerFECompositionState&)); MOCK_METHOD1(prepareClientComposition, std::optional( compositionengine::LayerFE::ClientCompositionTargetSettings&)); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h index d8d637d302..6b2224ac60 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -40,9 +40,11 @@ public: MOCK_METHOD1(updateCompositionState, void(bool)); MOCK_METHOD1(writeStateToHWC, void(bool)); + MOCK_CONST_METHOD0(writeCursorPositionToHWC, void()); MOCK_CONST_METHOD0(getHwcLayer, HWC2::Layer*()); MOCK_CONST_METHOD0(requiresClientComposition, bool()); + MOCK_CONST_METHOD0(isHardwareCursor, bool()); MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition)); MOCK_METHOD0(prepareForDeviceLayerRequests, void()); MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request)); diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp index 9558266a34..8bc3a349ca 100644 --- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp +++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -70,6 +71,22 @@ nsecs_t CompositionEngine::getLastFrameRefreshTimestamp() const { return mRefreshStartTime; } +void CompositionEngine::updateCursorAsync(CompositionRefreshArgs& args) { + std::unordered_map + uniqueVisibleLayers; + + for (const auto& output : args.outputs) { + for (auto& layer : output->getOutputLayersOrderedByZ()) { + if (layer->isHardwareCursor()) { + // Latch the cursor composition state from each front-end layer. + layer->getLayerFE().latchCursorCompositionState( + layer->getLayer().editState().frontEnd); + layer->writeCursorPositionToHWC(); + } + } + } +} + void CompositionEngine::preComposition(CompositionRefreshArgs& args) { ATRACE_CALL(); ALOGV(__FUNCTION__); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index e721cf5375..73bb03be02 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -550,6 +550,27 @@ void OutputLayer::writeCompositionTypeToHWC( } } +void OutputLayer::writeCursorPositionToHWC() const { + // Skip doing this if there is no HWC interface + auto hwcLayer = getHwcLayer(); + if (!hwcLayer) { + return; + } + + const auto& layerFEState = mLayer->getState().frontEnd; + const auto& outputState = mOutput.getState(); + + Rect frame = layerFEState.cursorFrame; + frame.intersect(outputState.viewport, &frame); + Rect position = outputState.transform.transform(frame); + + if (auto error = hwcLayer->setCursorPosition(position.left, position.top); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set cursor position to (%d, %d): %s (%d)", mLayerFE->getDebugName(), + position.left, position.top, to_string(error).c_str(), static_cast(error)); + } +} + HWC2::Layer* OutputLayer::getHwcLayer() const { return mState.hwc ? mState.hwc->hwcLayer.get() : nullptr; } @@ -559,6 +580,11 @@ bool OutputLayer::requiresClientComposition() const { mState.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT; } +bool OutputLayer::isHardwareCursor() const { + return mState.hwc && + mState.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CURSOR; +} + void OutputLayer::detectDisallowedCompositionTypeChange( Hwc2::IComposerClient::Composition from, Hwc2::IComposerClient::Composition to) const { bool result = false; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index c83cae65fb..75e960c575 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -781,6 +781,61 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompo mOutputLayer.writeStateToHWC(false); } +/* + * OutputLayer::writeCursorPositionToHWC() + */ + +struct OutputLayerWriteCursorPositionToHWCTest : public OutputLayerTest { + static constexpr int kDefaultTransform = TR_IDENT; + static constexpr HWC2::Error kDefaultError = HWC2::Error::Unsupported; + + static const Rect kDefaultDisplayViewport; + static const Rect kDefaultCursorFrame; + + OutputLayerWriteCursorPositionToHWCTest() { + auto& outputLayerState = mOutputLayer.editState(); + outputLayerState.hwc = impl::OutputLayerCompositionState::Hwc(mHwcLayer); + + mLayerState.frontEnd.cursorFrame = kDefaultCursorFrame; + + mOutputState.viewport = kDefaultDisplayViewport; + mOutputState.transform = ui::Transform{kDefaultTransform}; + } + + std::shared_ptr mHwcLayer{std::make_shared>()}; +}; + +const Rect OutputLayerWriteCursorPositionToHWCTest::kDefaultDisplayViewport{0, 0, 1920, 1080}; +const Rect OutputLayerWriteCursorPositionToHWCTest::kDefaultCursorFrame{1, 2, 3, 4}; + +TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCHandlesNoHwcState) { + mOutputLayer.editState().hwc.reset(); + + mOutputLayer.writeCursorPositionToHWC(); +} + +TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCWritesStateToHWC) { + EXPECT_CALL(*mHwcLayer, setCursorPosition(1, 2)).WillOnce(Return(kDefaultError)); + + mOutputLayer.writeCursorPositionToHWC(); +} + +TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCIntersectedWithViewport) { + mLayerState.frontEnd.cursorFrame = Rect{3000, 3000, 3016, 3016}; + + EXPECT_CALL(*mHwcLayer, setCursorPosition(1920, 1080)).WillOnce(Return(kDefaultError)); + + mOutputLayer.writeCursorPositionToHWC(); +} + +TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCRotatedByTransform) { + mOutputState.transform = ui::Transform{TR_ROT_90}; + + EXPECT_CALL(*mHwcLayer, setCursorPosition(-4, 1)).WillOnce(Return(kDefaultError)); + + mOutputLayer.writeCursorPositionToHWC(); +} + /* * OutputLayer::getHwcLayer() */ @@ -828,6 +883,30 @@ TEST_F(OutputLayerTest, requiresClientCompositionReturnsFalseIfSetToDeviceCompos EXPECT_FALSE(mOutputLayer.requiresClientComposition()); } +/* + * OutputLayer::isHardwareCursor() + */ + +TEST_F(OutputLayerTest, isHardwareCursorReturnsFalseIfNoHWC2State) { + mOutputLayer.editState().hwc.reset(); + + EXPECT_FALSE(mOutputLayer.isHardwareCursor()); +} + +TEST_F(OutputLayerTest, isHardwareCursorReturnsTrueIfSetToCursorComposition) { + mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr}; + mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CURSOR; + + EXPECT_TRUE(mOutputLayer.isHardwareCursor()); +} + +TEST_F(OutputLayerTest, isHardwareCursorReturnsFalseIfSetToDeviceComposition) { + mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr}; + mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE; + + EXPECT_FALSE(mOutputLayer.isHardwareCursor()); +} + /* * OutputLayer::applyDeviceCompositionTypeChange() */ diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5121835cae..557d0bba27 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -464,6 +464,21 @@ void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compo } } +void Layer::latchCursorCompositionState( + compositionengine::LayerFECompositionState& compositionState) const { + // This gives us only the "orientation" component of the transform + const State& drawingState{getDrawingState()}; + + // Apply the layer's transform, followed by the display's global transform + // Here we're guaranteed that the layer's transform preserves rects + Rect win = getCroppedBufferSize(drawingState); + // Subtract the transparent region and snap to the bounds + Rect bounds = reduce(win, getActiveTransparentRegion(drawingState)); + Rect frame(getTransform().transform(bounds)); + + compositionState.cursorFrame = frame; +} + bool Layer::onPreComposition(nsecs_t) { return false; } @@ -481,38 +496,6 @@ const char* Layer::getDebugName() const { return mName.string(); } -void Layer::updateCursorPosition(const sp& display) { - const auto outputLayer = findOutputLayerForDisplay(display); - LOG_FATAL_IF(!outputLayer); - - if (!outputLayer->getState().hwc || - (*outputLayer->getState().hwc).hwcCompositionType != - Hwc2::IComposerClient::Composition::CURSOR) { - return; - } - - // This gives us only the "orientation" component of the transform - const State& s(getDrawingState()); - - // Apply the layer's transform, followed by the display's global transform - // Here we're guaranteed that the layer's transform preserves rects - Rect win = getCroppedBufferSize(s); - // Subtract the transparent region and snap to the bounds - Rect bounds = reduce(win, getActiveTransparentRegion(s)); - Rect frame(getTransform().transform(bounds)); - frame.intersect(display->getViewport(), &frame); - auto& displayTransform = display->getTransform(); - auto position = displayTransform.transform(frame); - - auto error = - (*outputLayer->getState().hwc).hwcLayer->setCursorPosition(position.left, position.top); - ALOGE_IF(error != HWC2::Error::None, - "[%s] Failed to set cursor position " - "to (%d, %d): %s (%d)", - mName.string(), position.left, position.top, to_string(error).c_str(), - static_cast(error)); -} - // --------------------------------------------------------------------------- // drawing... // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index aa3970eb3a..23763d2729 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -476,6 +476,7 @@ public: bool onPreComposition(nsecs_t) override; void latchCompositionState(compositionengine::LayerFECompositionState&, bool includeGeometry) const override; + void latchCursorCompositionState(compositionengine::LayerFECompositionState&) const override; std::optional prepareClientComposition( compositionengine::LayerFE::ClientCompositionTargetSettings&) override; void onLayerDisplayed(const sp& releaseFence) override; @@ -493,7 +494,6 @@ public: Hwc2::IComposerClient::Composition getCompositionType( const sp& display) const; bool getClearClientTarget(const sp& display) const; - void updateCursorPosition(const sp& display); virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; } virtual void setTransformHint(uint32_t /*orientation*/) const { } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 83f3b2cecd..8760bb0900 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2715,15 +2715,14 @@ void SurfaceFlinger::executeInputWindowCommands() { void SurfaceFlinger::updateCursorAsync() { - for (const auto& [token, display] : mDisplays) { - if (!display->getId()) { - continue; - } - - for (auto& layer : display->getVisibleLayersSortedByZ()) { - layer->updateCursorPosition(display); + compositionengine::CompositionRefreshArgs refreshArgs; + for (const auto& [_, display] : mDisplays) { + if (display->getId()) { + refreshArgs.outputs.push_back(display->getCompositionDisplay()); } } + + mCompositionEngine->updateCursorAsync(refreshArgs); } void SurfaceFlinger::commitTransaction() -- GitLab From d7b429f63cbda9391e3743cf47e6606290846220 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 7 Mar 2019 21:11:02 -0800 Subject: [PATCH 0210/1255] SF: Move/refactor presentation loop to CompositionEngine This introduces CompositionEngine::present(), which will be the entry point for performing all composition related work. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: I5980da7fd471ad0920f6737698c214ed5ee07c60 --- .../compositionengine/CompositionEngine.h | 3 ++ .../include/compositionengine/Output.h | 30 ++++++------------- .../impl/CompositionEngine.h | 2 ++ .../include/compositionengine/impl/Output.h | 2 ++ .../mock/CompositionEngine.h | 1 + .../include/compositionengine/mock/Output.h | 3 ++ .../src/CompositionEngine.cpp | 6 ++++ .../CompositionEngine/src/Output.cpp | 8 +++++ services/surfaceflinger/SurfaceFlinger.cpp | 9 +----- 9 files changed, 35 insertions(+), 29 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h index 298aff57a9..a8e05cbe99 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h @@ -58,6 +58,9 @@ public: virtual bool needsAnotherUpdate() const = 0; virtual nsecs_t getLastFrameRefreshTimestamp() const = 0; + // Presents the indicated outputs + virtual void present(CompositionRefreshArgs&) = 0; + // Updates the cursor position for the indicated outputs. virtual void updateCursorAsync(CompositionRefreshArgs&) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 82cde4b82e..e71e97229b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -159,34 +159,22 @@ public: // Takes (moves) the set of layers being released this frame. virtual ReleasedLayers takeReleasedLayers() = 0; + // Presents the output, finalizing all composition details + virtual void present(const compositionengine::CompositionRefreshArgs&) = 0; + // Updates the color mode used on this output virtual void updateColorProfile(const CompositionRefreshArgs&) = 0; - // Signals that a frame is beginning on the output - virtual void beginFrame() = 0; +protected: + virtual void setDisplayColorProfile(std::unique_ptr) = 0; + virtual void setRenderSurface(std::unique_ptr) = 0; - // Prepares a frame for display + virtual void beginFrame() = 0; virtual void prepareFrame() = 0; - - // Performs any debug related screen flashing due to the update - virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0; - - // Finishes the current frame on the output, performing client composition - // and ensuring the content is displayed. - virtual void finishFrame(const CompositionRefreshArgs&) = 0; - - // Performs client composition as needed for layers on the output. The - // output fence is set to a fence to signal when client composition is - // finished. - // Returns std::nullopt if client composition cannot be performed. + virtual void devOptRepaintFlash(const compositionengine::CompositionRefreshArgs&) = 0; + virtual void finishFrame(const compositionengine::CompositionRefreshArgs&) = 0; virtual std::optional composeSurfaces(const Region&) = 0; - - // Posts the new frame, and sets release fences. virtual void postFramebuffer() = 0; - -protected: - virtual void setDisplayColorProfile(std::unique_ptr) = 0; - virtual void setRenderSurface(std::unique_ptr) = 0; virtual void chooseCompositionStrategy() = 0; virtual bool getSkipColorTransform() const = 0; virtual FrameFences presentAndGetFrameFences() = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h index 982a37604d..d476b85320 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h @@ -39,6 +39,8 @@ public: bool needsAnotherUpdate() const override; nsecs_t getLastFrameRefreshTimestamp() const override; + void present(CompositionRefreshArgs&) override; + void updateCursorAsync(CompositionRefreshArgs&) override; void preComposition(CompositionRefreshArgs&) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 904edc791c..22bad244e3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -75,6 +75,8 @@ public: void setReleasedLayers(ReleasedLayers&&) override; ReleasedLayers takeReleasedLayers() override; + void present(const compositionengine::CompositionRefreshArgs&) override; + void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override; void beginFrame() override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h index 6450b222dc..5a5c36a8d7 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h @@ -44,6 +44,7 @@ public: MOCK_CONST_METHOD0(needsAnotherUpdate, bool()); MOCK_CONST_METHOD0(getLastFrameRefreshTimestamp, nsecs_t()); + MOCK_METHOD1(present, void(CompositionRefreshArgs&)); MOCK_METHOD1(updateCursorAsync, void(CompositionRefreshArgs&)); MOCK_METHOD1(preComposition, void(CompositionRefreshArgs&)); }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 44cd5e99de..feca92932f 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -74,9 +74,12 @@ public: MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&)); MOCK_METHOD0(takeReleasedLayers, ReleasedLayers()); + MOCK_METHOD1(present, void(const compositionengine::CompositionRefreshArgs&)); + MOCK_METHOD1(updateColorProfile, void(const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD0(beginFrame, void()); + MOCK_METHOD0(prepareFrame, void()); MOCK_METHOD0(chooseCompositionStrategy, void()); diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp index 8bc3a349ca..6ed50aa223 100644 --- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp +++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp @@ -71,6 +71,12 @@ nsecs_t CompositionEngine::getLastFrameRefreshTimestamp() const { return mRefreshStartTime; } +void CompositionEngine::present(CompositionRefreshArgs& args) { + for (const auto& output : args.outputs) { + output->present(args); + } +} + void CompositionEngine::updateCursorAsync(CompositionRefreshArgs& args) { std::unordered_map uniqueVisibleLayers; diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index cc7e4533f4..635e4502c3 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -260,6 +260,14 @@ Output::ReleasedLayers Output::takeReleasedLayers() { return std::move(mReleasedLayers); } +void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) { + beginFrame(); + prepareFrame(); + devOptRepaintFlash(refreshArgs); + finishFrame(refreshArgs); + postFramebuffer(); +} + void Output::updateColorProfile(const compositionengine::CompositionRefreshArgs& refreshArgs) { setColorProfile(pickColorProfile(refreshArgs)); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8760bb0900..e0d160925b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1802,14 +1802,7 @@ void SurfaceFlinger::handleMessageRefresh() { mCompositionEngine->preComposition(refreshArgs); rebuildLayerStacks(); calculateWorkingSet(refreshArgs); - for (const auto& [token, displayDevice] : mDisplays) { - auto display = displayDevice->getCompositionDisplay(); - display->beginFrame(); - display->prepareFrame(); - display->devOptRepaintFlash(refreshArgs); - display->finishFrame(refreshArgs); - display->postFramebuffer(); - } + mCompositionEngine->present(refreshArgs); postFrame(); postComposition(); -- GitLab From 3eb1b21a2e4139a7e01fe1db525ed2618d7ac14e Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 7 Mar 2019 21:15:40 -0800 Subject: [PATCH 0211/1255] SF: Move/Refactor calculateWorkingSet to CompositionEngine The functionality is made part of CompositionEngine::present() Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: I0eb74f9fe8421468fbc1048aec23d7c91ce4f302 --- .../CompositionRefreshArgs.h | 11 +++ .../include/compositionengine/Output.h | 22 +++-- .../impl/CompositionEngine.h | 2 + .../include/compositionengine/impl/Display.h | 2 +- .../include/compositionengine/impl/Output.h | 6 +- .../impl/OutputCompositionState.h | 7 +- .../mock/CompositionEngine.h | 1 + .../include/compositionengine/mock/Output.h | 5 +- .../src/CompositionEngine.cpp | 13 +++ .../CompositionEngine/src/Display.cpp | 10 ++- .../CompositionEngine/src/Output.cpp | 52 +++++++++-- .../src/OutputCompositionState.cpp | 2 +- .../CompositionEngine/tests/DisplayTest.cpp | 23 ++--- .../CompositionEngine/tests/OutputTest.cpp | 90 ++++++++++++++----- services/surfaceflinger/SurfaceFlinger.cpp | 75 +++------------- services/surfaceflinger/SurfaceFlinger.h | 2 - 16 files changed, 197 insertions(+), 126 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index 1001cf7e02..6f689ad4be 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -22,6 +22,7 @@ #include #include #include +#include namespace android::compositionengine { @@ -52,6 +53,16 @@ struct CompositionRefreshArgs { // Forces a color mode on the outputs being refreshed ui::ColorMode forceOutputColorMode{ui::ColorMode::NATIVE}; + // If true, there was a geometry update this frame + bool updatingGeometryThisFrame{false}; + + // The color matrix to use for this + // frame. Only set if the color transform is changing this frame. + std::optional colorTransformMatrix; + + // If true, client composition is always used. + bool devOptForceClientComposition{false}; + // If set, causes the dirty regions to flash with the delay std::optional devOptFlashDirtyRegionsDelay; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index e71e97229b..a509ca8129 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -44,6 +43,7 @@ class RenderSurface; class OutputLayer; struct CompositionRefreshArgs; +struct LayerFECompositionState; namespace impl { struct OutputCompositionState; @@ -56,6 +56,7 @@ class Output { public: using OutputLayers = std::vector>; using ReleasedLayers = std::vector>; + using UniqueFELayerStateMap = std::unordered_map; struct FrameFences { sp presentFence{Fence::NO_FENCE}; @@ -90,9 +91,6 @@ public: // belongsInOutput for full details. virtual void setLayerStackFilter(uint32_t layerStackId, bool isInternal) = 0; - // Sets the color transform matrix to use - virtual void setColorTransform(const mat4&) = 0; - // Sets the output color mode virtual void setColorProfile(const ColorProfile&) = 0; @@ -159,20 +157,26 @@ public: // Takes (moves) the set of layers being released this frame. virtual ReleasedLayers takeReleasedLayers() = 0; + // Prepare the output, updating the OutputLayers used in the output + virtual void prepare(CompositionRefreshArgs&) = 0; + // Presents the output, finalizing all composition details - virtual void present(const compositionengine::CompositionRefreshArgs&) = 0; + virtual void present(const CompositionRefreshArgs&) = 0; - // Updates the color mode used on this output - virtual void updateColorProfile(const CompositionRefreshArgs&) = 0; + // Latches the front-end layer state for each output layer + virtual void updateLayerStateFromFE(const CompositionRefreshArgs&) const = 0; protected: virtual void setDisplayColorProfile(std::unique_ptr) = 0; virtual void setRenderSurface(std::unique_ptr) = 0; + virtual void updateAndWriteCompositionState(const CompositionRefreshArgs&) = 0; + virtual void setColorTransform(const CompositionRefreshArgs&) = 0; + virtual void updateColorProfile(const CompositionRefreshArgs&) = 0; virtual void beginFrame() = 0; virtual void prepareFrame() = 0; - virtual void devOptRepaintFlash(const compositionengine::CompositionRefreshArgs&) = 0; - virtual void finishFrame(const compositionengine::CompositionRefreshArgs&) = 0; + virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0; + virtual void finishFrame(const CompositionRefreshArgs&) = 0; virtual std::optional composeSurfaces(const Region&) = 0; virtual void postFramebuffer() = 0; virtual void chooseCompositionStrategy() = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h index d476b85320..6340b1482a 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h @@ -45,6 +45,8 @@ public: void preComposition(CompositionRefreshArgs&) override; + void updateLayerStateFromFE(CompositionRefreshArgs& args); + // Testing void setNeedsAnotherUpdateForTest(bool); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index dba112eb4e..bd1aa08fde 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -40,7 +40,7 @@ public: // compositionengine::Output overrides void dump(std::string&) const override; - void setColorTransform(const mat4&) override; + void setColorTransform(const compositionengine::CompositionRefreshArgs&) override; void setColorProfile(const ColorProfile&) override; void chooseCompositionStrategy() override; bool getSkipColorTransform() const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 22bad244e3..d826161a4d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -44,7 +44,7 @@ public: void setBounds(const ui::Size&) override; void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override; - void setColorTransform(const mat4&) override; + void setColorTransform(const compositionengine::CompositionRefreshArgs&) override; void setColorProfile(const ColorProfile&) override; void dump(std::string&) const override; @@ -75,10 +75,12 @@ public: void setReleasedLayers(ReleasedLayers&&) override; ReleasedLayers takeReleasedLayers() override; + void prepare(compositionengine::CompositionRefreshArgs&) override; void present(const compositionengine::CompositionRefreshArgs&) override; + void updateLayerStateFromFE(const CompositionRefreshArgs&) const override; + void updateAndWriteCompositionState(const compositionengine::CompositionRefreshArgs&) override; void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override; - void beginFrame() override; void prepareFrame() override; void devOptRepaintFlash(const compositionengine::CompositionRefreshArgs&) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 1078f11c2d..17d3d3fb7d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -86,11 +86,8 @@ struct OutputCompositionState { // True if the last composition frame had visible layers bool lastCompositionHadVisibleLayers{false}; - // The color transform to apply - android_color_transform_t colorTransform{HAL_COLOR_TRANSFORM_IDENTITY}; - - // The color transform matrix to apply, corresponding with colorTransform. - mat4 colorTransformMat; + // The color transform matrix to apply + mat4 colorTransformMatrix; // Current active color mode ui::ColorMode colorMode{ui::ColorMode::NATIVE}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h index 5a5c36a8d7..e3254acd9a 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h @@ -46,6 +46,7 @@ public: MOCK_METHOD1(present, void(CompositionRefreshArgs&)); MOCK_METHOD1(updateCursorAsync, void(CompositionRefreshArgs&)); + MOCK_METHOD1(preComposition, void(CompositionRefreshArgs&)); }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index feca92932f..33925d5691 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -41,7 +41,7 @@ public: MOCK_METHOD1(setBounds, void(const ui::Size&)); MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool)); - MOCK_METHOD1(setColorTransform, void(const mat4&)); + MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD1(setColorProfile, void(const ColorProfile&)); MOCK_CONST_METHOD1(dump, void(std::string&)); @@ -74,8 +74,11 @@ public: MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&)); MOCK_METHOD0(takeReleasedLayers, ReleasedLayers()); + MOCK_METHOD1(prepare, void(compositionengine::CompositionRefreshArgs&)); MOCK_METHOD1(present, void(const compositionengine::CompositionRefreshArgs&)); + MOCK_CONST_METHOD1(updateLayerStateFromFE, void(const CompositionRefreshArgs&)); + MOCK_METHOD1(updateAndWriteCompositionState, void(const CompositionRefreshArgs&)); MOCK_METHOD1(updateColorProfile, void(const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD0(beginFrame, void()); diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp index 6ed50aa223..590c596a6d 100644 --- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp +++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp @@ -72,6 +72,12 @@ nsecs_t CompositionEngine::getLastFrameRefreshTimestamp() const { } void CompositionEngine::present(CompositionRefreshArgs& args) { + for (const auto& output : args.outputs) { + output->prepare(args); + } + + updateLayerStateFromFE(args); + for (const auto& output : args.outputs) { output->present(args); } @@ -115,5 +121,12 @@ void CompositionEngine::setNeedsAnotherUpdateForTest(bool value) { mNeedsAnotherUpdate = value; } +void CompositionEngine::updateLayerStateFromFE(CompositionRefreshArgs& args) { + // Update the composition state from each front-end layer + for (const auto& output : args.outputs) { + output->updateLayerStateFromFE(args); + } +} + } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 108720a52b..000a294c75 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -69,11 +69,15 @@ void Display::disconnect() { mId.reset(); } -void Display::setColorTransform(const mat4& transform) { - Output::setColorTransform(transform); +void Display::setColorTransform(const compositionengine::CompositionRefreshArgs& args) { + Output::setColorTransform(args); + + if (!mId || CC_LIKELY(!args.colorTransformMatrix)) { + return; + } auto& hwc = getCompositionEngine().getHwComposer(); - status_t result = hwc.setColorTransform(*mId, transform); + status_t result = hwc.setColorTransform(*mId, *args.colorTransformMatrix); ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display \"%s\": %d", mId ? to_string(*mId).c_str() : "", result); } diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 635e4502c3..903ca9891c 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -99,17 +99,12 @@ void Output::setLayerStackFilter(uint32_t layerStackId, bool isInternal) { dirtyEntireOutput(); } -void Output::setColorTransform(const mat4& transform) { - if (mState.colorTransformMat == transform) { +void Output::setColorTransform(const compositionengine::CompositionRefreshArgs& args) { + if (!args.colorTransformMatrix || mState.colorTransformMatrix == *args.colorTransformMatrix) { return; } - const bool isIdentity = (transform == mat4()); - const auto newColorTransform = - isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX; - - mState.colorTransform = newColorTransform; - mState.colorTransformMat = transform; + mState.colorTransformMatrix = *args.colorTransformMatrix; dirtyEntireOutput(); } @@ -260,7 +255,22 @@ Output::ReleasedLayers Output::takeReleasedLayers() { return std::move(mReleasedLayers); } +void Output::prepare(compositionengine::CompositionRefreshArgs& refreshArgs) { + if (CC_LIKELY(!refreshArgs.updatingGeometryThisFrame)) { + return; + } + + uint32_t zOrder = 0; + for (auto& layer : mOutputLayersOrderedByZ) { + // Assign a simple Z order sequence to each visible layer. + layer->editState().z = zOrder++; + } +} + void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) { + updateColorProfile(refreshArgs); + updateAndWriteCompositionState(refreshArgs); + setColorTransform(refreshArgs); beginFrame(); prepareFrame(); devOptRepaintFlash(refreshArgs); @@ -268,6 +278,30 @@ void Output::present(const compositionengine::CompositionRefreshArgs& refreshArg postFramebuffer(); } +void Output::updateLayerStateFromFE(const CompositionRefreshArgs& args) const { + for (auto& layer : mOutputLayersOrderedByZ) { + layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd, + args.updatingGeometryThisFrame); + } +} + +void Output::updateAndWriteCompositionState( + const compositionengine::CompositionRefreshArgs& refreshArgs) { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + + for (auto& layer : mOutputLayersOrderedByZ) { + if (refreshArgs.devOptForceClientComposition) { + layer->editState().forceClientComposition = true; + } + + layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame); + + // Send the updated state to the HWC, if appropriate. + layer->writeStateToHWC(refreshArgs.updatingGeometryThisFrame); + } +} + void Output::updateColorProfile(const compositionengine::CompositionRefreshArgs& refreshArgs) { setColorProfile(pickColorProfile(refreshArgs)); } @@ -491,7 +525,7 @@ std::optional Output::composeSurfaces(const Region& debugRegion // Compute the global color transform matrix. if (!mState.usesDeviceComposition && !getSkipColorTransform()) { - clientCompositionDisplay.colorTransform = mState.colorTransformMat; + clientCompositionDisplay.colorTransform = mState.colorTransformMatrix; } // Note: Updated by generateClientCompositionRequests diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index 3e47fe2a12..0fcc308ca0 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -47,7 +47,7 @@ void OutputCompositionState::dump(std::string& out) const { dumpVal(out, "colorMode", toString(colorMode), colorMode); dumpVal(out, "renderIntent", toString(renderIntent), renderIntent); dumpVal(out, "dataspace", toString(dataspace), dataspace); - dumpVal(out, "colorTransform", colorTransform); + dumpVal(out, "colorTransformMatrix", colorTransformMatrix); dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace); out.append("\n"); diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 06e3a70665..008e631deb 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -138,23 +138,26 @@ TEST_F(DisplayTest, disconnectDisconnectsDisplay) { */ TEST_F(DisplayTest, setColorTransformSetsTransform) { - // Identity matrix sets an identity state value - const mat4 identity; + // No change does nothing + CompositionRefreshArgs refreshArgs; + refreshArgs.colorTransformMatrix = std::nullopt; + mDisplay.setColorTransform(refreshArgs); - EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, identity)).Times(1); + // Identity matrix sets an identity state value + const mat4 kIdentity; - mDisplay.setColorTransform(identity); + EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, kIdentity)).Times(1); - EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mDisplay.getState().colorTransform); + refreshArgs.colorTransformMatrix = kIdentity; + mDisplay.setColorTransform(refreshArgs); // Non-identity matrix sets a non-identity state value - const mat4 nonIdentity = mat4() * 2; - - EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, nonIdentity)).Times(1); + const mat4 kNonIdentity = mat4() * 2; - mDisplay.setColorTransform(nonIdentity); + EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, kNonIdentity)).Times(1); - EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mDisplay.getState().colorTransform); + refreshArgs.colorTransformMatrix = kNonIdentity; + mDisplay.setColorTransform(refreshArgs); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index dccad58dde..1d5f2f0d54 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -45,6 +45,10 @@ using testing::StrictMock; constexpr auto TR_IDENT = 0u; constexpr auto TR_ROT_90 = HAL_TRANSFORM_ROT_90; +const mat4 kIdentity; +const mat4 kNonIdentityHalf = mat4() * 0.5; +const mat4 kNonIdentityQuarter = mat4() * 0.25; + struct OutputTest : public testing::Test { OutputTest() { mOutput.setDisplayColorProfileForTest( @@ -171,38 +175,84 @@ TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) { * Output::setColorTransform */ -TEST_F(OutputTest, setColorTransformSetsTransform) { - // Identity matrix sets an identity state value - const mat4 identity; +TEST_F(OutputTest, setColorTransformWithNoChangeFlaggedSkipsUpdates) { + mOutput.editState().colorTransformMatrix = kIdentity; + + // If no colorTransformMatrix is set the update should be skipped. + CompositionRefreshArgs refreshArgs; + refreshArgs.colorTransformMatrix = std::nullopt; + + mOutput.setColorTransform(refreshArgs); + + // The internal state should be unchanged + EXPECT_EQ(kIdentity, mOutput.getState().colorTransformMatrix); + + // No dirty region should be set + EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region())); +} + +TEST_F(OutputTest, setColorTransformWithNoActualChangeSkipsUpdates) { + mOutput.editState().colorTransformMatrix = kIdentity; - mOutput.setColorTransform(identity); + // Attempting to set the same colorTransformMatrix that is already set should + // also skip the update. + CompositionRefreshArgs refreshArgs; + refreshArgs.colorTransformMatrix = kIdentity; - EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mOutput.getState().colorTransform); - EXPECT_EQ(identity, mOutput.getState().colorTransformMat); + mOutput.setColorTransform(refreshArgs); - // Since identity is the default, the dirty region should be unchanged (empty) + // The internal state should be unchanged + EXPECT_EQ(kIdentity, mOutput.getState().colorTransformMatrix); + + // No dirty region should be set EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region())); +} - // Non-identity matrix sets a non-identity state value - const mat4 nonIdentityHalf = mat4() * 0.5; +TEST_F(OutputTest, setColorTransformPerformsUpdateToIdentity) { + mOutput.editState().colorTransformMatrix = kNonIdentityHalf; - mOutput.setColorTransform(nonIdentityHalf); + // Setting a different colorTransformMatrix should perform the update. + CompositionRefreshArgs refreshArgs; + refreshArgs.colorTransformMatrix = kIdentity; - EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform); - EXPECT_EQ(nonIdentityHalf, mOutput.getState().colorTransformMat); + mOutput.setColorTransform(refreshArgs); - // Since this is a state change, the entire output should now be dirty. + // The internal state should have been updated + EXPECT_EQ(kIdentity, mOutput.getState().colorTransformMatrix); + + // The dirtyRegion should be set to the full display size + EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); +} + +TEST_F(OutputTest, setColorTransformPerformsUpdateForIdentityToHalf) { + mOutput.editState().colorTransformMatrix = kIdentity; + + // Setting a different colorTransformMatrix should perform the update. + CompositionRefreshArgs refreshArgs; + refreshArgs.colorTransformMatrix = kNonIdentityHalf; + + mOutput.setColorTransform(refreshArgs); + + // The internal state should have been updated + EXPECT_EQ(kNonIdentityHalf, mOutput.getState().colorTransformMatrix); + + // The dirtyRegion should be set to the full display size EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); +} + +TEST_F(OutputTest, setColorTransformPerformsUpdateForHalfToQuarter) { + mOutput.editState().colorTransformMatrix = kNonIdentityHalf; - // Non-identity matrix sets a non-identity state value - const mat4 nonIdentityQuarter = mat4() * 0.25; + // Setting a different colorTransformMatrix should perform the update. + CompositionRefreshArgs refreshArgs; + refreshArgs.colorTransformMatrix = kNonIdentityQuarter; - mOutput.setColorTransform(nonIdentityQuarter); + mOutput.setColorTransform(refreshArgs); - EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform); - EXPECT_EQ(nonIdentityQuarter, mOutput.getState().colorTransformMat); + // The internal state should have been updated + EXPECT_EQ(kNonIdentityQuarter, mOutput.getState().colorTransformMatrix); - // Since this is a state change, the entire output should now be dirty. + // The dirtyRegion should be set to the full display size EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } @@ -502,7 +552,7 @@ struct OutputComposeSurfacesTest : public testing::Test { mOutput.editState().transform = ui::Transform{kDefaultOutputOrientation}; mOutput.editState().orientation = kDefaultOutputOrientation; mOutput.editState().dataspace = kDefaultOutputDataspace; - mOutput.editState().colorTransformMat = kDefaultColorTransformMat; + mOutput.editState().colorTransformMatrix = kDefaultColorTransformMat; mOutput.editState().isSecure = true; mOutput.editState().needsFiltering = false; mOutput.editState().usesClientComposition = true; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e0d160925b..34981aebb1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1794,6 +1794,15 @@ void SurfaceFlinger::handleMessageRefresh() { : compositionengine::OutputColorSetting::kUnmanaged; refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace; refreshArgs.forceOutputColorMode = mForceColorMode; + refreshArgs.updatingGeometryThisFrame = mGeometryInvalid; + + if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) { + refreshArgs.colorTransformMatrix = mDrawingState.colorMatrix; + mDrawingState.colorMatrixChanged = false; + } + + refreshArgs.devOptForceClientComposition = mDebugDisableHWC || mDebugRegion; + if (mDebugRegion != 0) { refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0); @@ -1801,9 +1810,11 @@ void SurfaceFlinger::handleMessageRefresh() { mCompositionEngine->preComposition(refreshArgs); rebuildLayerStacks(); - calculateWorkingSet(refreshArgs); + refreshArgs.updatingGeometryThisFrame = mGeometryInvalid; // Can be set by rebuildLayerStacks() mCompositionEngine->present(refreshArgs); + mGeometryInvalid = false; + postFrame(); postComposition(); @@ -1851,68 +1862,6 @@ bool SurfaceFlinger::handleMessageInvalidate() { return refreshNeeded; } -void SurfaceFlinger::calculateWorkingSet( - const compositionengine::CompositionRefreshArgs& refreshArgs) { - ATRACE_CALL(); - ALOGV(__FUNCTION__); - - const bool updatingGeometryThisFrame = mGeometryInvalid; - mGeometryInvalid = false; - - // Latch the frontend layer composition state for each layer being - // composed. - for (const auto& [token, displayDevice] : mDisplays) { - auto display = displayDevice->getCompositionDisplay(); - for (auto& layer : display->getOutputLayersOrderedByZ()) { - layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd, - updatingGeometryThisFrame); - } - } - - if (CC_UNLIKELY(updatingGeometryThisFrame)) { - for (const auto& [token, displayDevice] : mDisplays) { - auto display = displayDevice->getCompositionDisplay(); - uint32_t zOrder = 0; - - for (auto& layer : display->getOutputLayersOrderedByZ()) { - // Assign a simple Z order sequence to each visible layer. - layer->editState().z = zOrder++; - } - } - } - - // Determine the color configuration of each output - for (const auto& [token, displayDevice] : mDisplays) { - auto display = displayDevice->getCompositionDisplay(); - display->updateColorProfile(refreshArgs); - } - - for (const auto& [token, displayDevice] : mDisplays) { - auto display = displayDevice->getCompositionDisplay(); - - for (auto& layer : display->getOutputLayersOrderedByZ()) { - if (mDebugDisableHWC || mDebugRegion) { - layer->editState().forceClientComposition = true; - } - - // Update the composition state of the output layer, as needed - // recomputing it from the state given by the front-end layer. - layer->updateCompositionState(updatingGeometryThisFrame); - - // Send the updated state to the HWC, if appropriate. - layer->writeStateToHWC(updatingGeometryThisFrame); - } - } - - if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) { - for (const auto& [token, displayDevice] : mDisplays) { - auto display = displayDevice->getCompositionDisplay(); - display->setColorTransform(mDrawingState.colorMatrix); - } - mDrawingState.colorMatrixChanged = false; - } -} - void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime, std::shared_ptr& presentFenceTime) { // Update queue of past composite+present times and determine the diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 1aa99fccfd..0f9a4bdeba 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -751,8 +751,6 @@ private: nsecs_t compositeToPresentLatency); void rebuildLayerStacks(); - void calculateWorkingSet(const compositionengine::CompositionRefreshArgs&); - void postFrame(); /* ------------------------------------------------------------------------ -- GitLab From 306299821902c05dfc3121a7201404ac465419ee Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 7 Mar 2019 21:20:05 -0800 Subject: [PATCH 0212/1255] SF: Remove DisplayDevice visible layer members There are no longer any consumers of it, so the data and related functions are removed, and the bit of code that was still setting it is removed. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: If09254dc44645b816d88b89cda64284822dd43ed --- services/surfaceflinger/DisplayDevice.cpp | 11 ----------- services/surfaceflinger/DisplayDevice.h | 6 ------ services/surfaceflinger/SurfaceFlinger.cpp | 5 ----- .../tests/unittests/CompositionTest.cpp | 5 ----- 4 files changed, 27 deletions(-) diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index b6d79d41f2..2ada86beca 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -116,16 +116,6 @@ uint32_t DisplayDevice::getPageFlipCount() const { return mCompositionDisplay->getRenderSurface()->getPageFlipCount(); } -// ---------------------------------------------------------------------------- - -void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp >& layers) { - mVisibleLayersSortedByZ = layers; -} - -const Vector< sp >& DisplayDevice::getVisibleLayersSortedByZ() const { - return mVisibleLayersSortedByZ; -} - // ---------------------------------------------------------------------------- void DisplayDevice::setPowerMode(int mode) { mPowerMode = mode; @@ -291,7 +281,6 @@ void DisplayDevice::dump(std::string& result) const { result.append(" "); StringAppendF(&result, "powerMode=%d, ", mPowerMode); StringAppendF(&result, "activeConfig=%d, ", mActiveConfig); - StringAppendF(&result, "numLayers=%zu\n", mVisibleLayersSortedByZ.size()); getCompositionDisplay()->dump(result); } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 4321e3dd13..52773204b9 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -87,9 +87,6 @@ public: int getHeight() const; int getInstallOrientation() const { return mDisplayInstallOrientation; } - void setVisibleLayersSortedByZ(const Vector< sp >& layers); - const Vector< sp >& getVisibleLayersSortedByZ() const; - void setLayerStack(uint32_t stack); void setDisplaySize(const int newWidth, const int newHeight); void setProjection(int orientation, const Rect& viewport, const Rect& frame); @@ -179,9 +176,6 @@ private: * don't need synchronization. */ - // list of visible layers on that display - Vector< sp > mVisibleLayersSortedByZ; - /* * Transaction state */ diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 34981aebb1..50440e8d3b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2093,7 +2093,6 @@ void SurfaceFlinger::rebuildLayerStacks() { Region dirtyRegion; compositionengine::Output::OutputLayers layersSortedByZ; compositionengine::Output::ReleasedLayers releasedLayers; - Vector> deprecated_layersSortedByZ; const ui::Transform& tr = displayState.transform; const Rect bounds = displayState.bounds; if (displayState.isEnabled) { @@ -2125,8 +2124,6 @@ void SurfaceFlinger::rebuildLayerStacks() { layersSortedByZ.emplace_back( display->getOrCreateOutputLayer(displayId, compositionLayer, layerFE)); - deprecated_layersSortedByZ.add(layer); - auto& outputLayerState = layersSortedByZ.back()->editState(); outputLayerState.visibleRegion = tr.transform(layer->visibleRegion.intersect(displayState.viewport)); @@ -2150,8 +2147,6 @@ void SurfaceFlinger::rebuildLayerStacks() { display->setOutputLayersOrderedByZ(std::move(layersSortedByZ)); display->setReleasedLayers(std::move(releasedLayers)); - displayDevice->setVisibleLayersSortedByZ(deprecated_layersSortedByZ); - Region undefinedRegion{bounds}; undefinedRegion.subtractSelf(tr.transform(opaqueRegion)); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 2e64a78458..425768e244 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -805,9 +805,6 @@ struct BaseLayerVariant { Mock::VerifyAndClear(test->mComposer); - Vector> layers; - layers.add(layer); - test->mDisplay->setVisibleLayersSortedByZ(layers); test->mFlinger.mutableDrawingState().layersSortedByZ.add(layer); } @@ -1096,8 +1093,6 @@ struct CompositionCase { for (auto& hwcDisplay : test->mFlinger.mFakeHwcDisplays) { hwcDisplay->mutableLayers().clear(); } - - test->mDisplay->setVisibleLayersSortedByZ(Vector>()); } }; -- GitLab From 0f085c6a3e5aa5ffa4619f612c2d3b1244420b31 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 30 Aug 2019 08:49:12 -0700 Subject: [PATCH 0213/1255] Dump offscreen layers in dumpsys and winscope trace Now that clients can keep layers alive by holding a reference to its handle and clients can also create layers, we need to an easier way to keep track of layers that are offscreen but not destroyed. This change keeps track of the calling pid and uid so it is easier to track the creating process. Since the tracing thread will also read from mOffscreenLayers, we want to protect access to it with the tracing lock. Bug:127687760 Test: run dumpsys check for offscreen layers Test: capture sf trace and check for offscreen layers Change-Id: I400f33b11b0a4f78f4c35027c457eb56ff12c22e --- services/surfaceflinger/Layer.cpp | 24 +++++- services/surfaceflinger/Layer.h | 12 ++- services/surfaceflinger/SurfaceFlinger.cpp | 85 ++++++++++++++++------ services/surfaceflinger/SurfaceFlinger.h | 3 + services/surfaceflinger/SurfaceTracing.cpp | 1 + 5 files changed, 100 insertions(+), 25 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5121835cae..688c5ee2a7 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -22,6 +22,7 @@ #include "Layer.h" #include +#include #include #include #include @@ -121,7 +122,8 @@ Layer::Layer(const LayerCreationArgs& args) mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval); mSchedulerLayerHandle = mFlinger->mScheduler->registerLayer(mName.c_str(), mWindowType); - + mCallingPid = args.callingPid; + mCallingUid = args.callingUid; mFlinger->onLayerCreated(); } @@ -135,6 +137,21 @@ Layer::~Layer() { mFlinger->onLayerDestroyed(this); } +LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, const sp& client, + const String8& name, uint32_t w, uint32_t h, uint32_t flags, + LayerMetadata metadata) + : flinger(flinger), + client(client), + name(name), + w(w), + h(h), + flags(flags), + metadata(std::move(metadata)) { + IPCThreadState* ipc = IPCThreadState::self(); + callingPid = ipc->getCallingPid(); + callingUid = ipc->getCallingUid(); +} + // --------------------------------------------------------------------------- // callbacks // --------------------------------------------------------------------------- @@ -1340,6 +1357,11 @@ void Layer::dumpFrameEvents(std::string& result) { mFrameEventHistory.dump(result); } +void Layer::dumpCallingUidPid(std::string& result) const { + StringAppendF(&result, "Layer %s (%s) pid:%d uid:%d\n", getName().string(), getType(), + mCallingPid, mCallingUid); +} + void Layer::onDisconnect() { Mutex::Autolock lock(mFrameEventHistoryMutex); mFrameEventHistory.onDisconnect(); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 9107189d52..49542395ee 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -80,9 +80,7 @@ class SurfaceInterceptor; struct LayerCreationArgs { LayerCreationArgs(SurfaceFlinger* flinger, const sp& client, const String8& name, - uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata) - : flinger(flinger), client(client), name(name), w(w), h(h), flags(flags), - metadata(std::move(metadata)) {} + uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata); SurfaceFlinger* flinger; const sp& client; @@ -91,6 +89,8 @@ struct LayerCreationArgs { uint32_t h; uint32_t flags; LayerMetadata metadata; + pid_t callingPid; + uid_t callingUid; }; class Layer : public virtual compositionengine::LayerFE { @@ -600,6 +600,7 @@ public: void miniDump(std::string& result, const sp& display) const; void dumpFrameStats(std::string& result) const; void dumpFrameEvents(std::string& result); + void dumpCallingUidPid(std::string& result) const; void clearFrameStats(); void logFrameStats(); void getFrameStats(FrameStats* outStats) const; @@ -924,6 +925,11 @@ private: bool mGetHandleCalled = false; void removeRemoteSyncPoints(); + + // Tracks the process and user id of the caller when creating this layer + // to help debugging. + pid_t mCallingPid; + uid_t mCallingUid; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e8049239ba..c081ddeae6 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2872,32 +2872,31 @@ void SurfaceFlinger::updateCursorAsync() void SurfaceFlinger::commitTransaction() { - if (!mLayersPendingRemoval.isEmpty()) { - // Notify removed layers now that they can't be drawn from - for (const auto& l : mLayersPendingRemoval) { - recordBufferingStats(l->getName().string(), - l->getOccupancyHistory(true)); - - // Ensure any buffers set to display on any children are released. - if (l->isRemovedFromCurrentState()) { - l->latchAndReleaseBuffer(); - } + withTracingLock([&]() { + if (!mLayersPendingRemoval.isEmpty()) { + // Notify removed layers now that they can't be drawn from + for (const auto& l : mLayersPendingRemoval) { + recordBufferingStats(l->getName().string(), l->getOccupancyHistory(true)); + + // Ensure any buffers set to display on any children are released. + if (l->isRemovedFromCurrentState()) { + l->latchAndReleaseBuffer(); + } - // If the layer has been removed and has no parent, then it will not be reachable - // when traversing layers on screen. Add the layer to the offscreenLayers set to - // ensure we can copy its current to drawing state. - if (!l->getParent()) { - mOffscreenLayers.emplace(l.get()); + // If the layer has been removed and has no parent, then it will not be reachable + // when traversing layers on screen. Add the layer to the offscreenLayers set to + // ensure we can copy its current to drawing state. + if (!l->getParent()) { + mOffscreenLayers.emplace(l.get()); + } } + mLayersPendingRemoval.clear(); } - mLayersPendingRemoval.clear(); - } - // If this transaction is part of a window animation then the next frame - // we composite should be considered an animation as well. - mAnimCompositionPending = mAnimTransactionPending; + // If this transaction is part of a window animation then the next frame + // we composite should be considered an animation as well. + mAnimCompositionPending = mAnimTransactionPending; - withTracingLock([&]() { mDrawingState = mCurrentState; // clear the "changed" flags in current state mCurrentState.colorMatrixChanged = false; @@ -4286,9 +4285,11 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, if (asProto) { result.append(layersProto.SerializeAsString()); } else { + // Dump info that we need to access from the main thread const auto layerTree = LayerProtoParser::generateLayerTree(layersProto); result.append(LayerProtoParser::layerTreeToString(layerTree)); result.append("\n"); + dumpOffscreenLayers(result); } } } @@ -4546,12 +4547,54 @@ LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { return layersProto; } +void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags) const { + // Add a fake invisible root layer to the proto output and parent all the offscreen layers to + // it. + LayerProto* rootProto = layersProto.add_layers(); + const int32_t offscreenRootLayerId = INT32_MAX - 2; + rootProto->set_id(offscreenRootLayerId); + rootProto->set_name("Offscreen Root"); + + for (Layer* offscreenLayer : mOffscreenLayers) { + // Add layer as child of the fake root + rootProto->add_children(offscreenLayer->sequence); + + // Add layer + LayerProto* layerProto = layersProto.add_layers(); + offscreenLayer->writeToProtoDrawingState(layerProto, traceFlags); + offscreenLayer->writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, + traceFlags); + layerProto->set_parent(offscreenRootLayerId); + + // Add children + offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { + if (layer == offscreenLayer) { + return; + } + LayerProto* childProto = layersProto.add_layers(); + layer->writeToProtoDrawingState(childProto, traceFlags); + layer->writeToProtoCommonState(childProto, LayerVector::StateSet::Drawing, traceFlags); + }); + } +} + LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) { LayersProto layersProto; postMessageSync(new LambdaMessage([&]() { layersProto = dumpDrawingStateProto(traceFlags); })); return layersProto; } +void SurfaceFlinger::dumpOffscreenLayers(std::string& result) { + result.append("Offscreen Layers:\n"); + postMessageSync(new LambdaMessage([&]() { + for (Layer* offscreenLayer : mOffscreenLayers) { + offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { + layer->dumpCallingUidPid(result); + }); + } + })); +} + void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const { const bool colorize = !args.empty() && args[0] == String16("--color"); Colorizer colorizer(colorize); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8408ef5174..d44ff9c5f4 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -876,8 +876,11 @@ private: void dumpDisplayIdentificationData(std::string& result) const; void dumpWideColorInfo(std::string& result) const; LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + void dumpOffscreenLayersProto(LayersProto& layersProto, + uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) EXCLUDES(mStateLock); + void dumpOffscreenLayers(std::string& result) EXCLUDES(mStateLock); void withTracingLock(std::function operation) REQUIRES(mStateLock); bool isLayerTripleBufferingDisabled() const { diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp index 9053f2c7de..eb26cd0379 100644 --- a/services/surfaceflinger/SurfaceTracing.cpp +++ b/services/surfaceflinger/SurfaceTracing.cpp @@ -163,6 +163,7 @@ LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) { entry.set_elapsed_realtime_nanos(elapsedRealtimeNano()); entry.set_where(where); LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags)); + mFlinger.dumpOffscreenLayersProto(layers); entry.mutable_layers()->Swap(&layers); return entry; -- GitLab From 90092f4335b7360b149a57ee759df778e099ff87 Mon Sep 17 00:00:00 2001 From: Mikael Pessa Date: Mon, 26 Aug 2019 17:22:04 -0700 Subject: [PATCH 0214/1255] Refactor: Pull tracing out of TimeStats. The tracing in TimeStats ended up having no actual overlap with current TimeStats functionality. This CL pulls all tracing related code out into its own class. Test: atest libsurfaceflinger_unittest and manually inspected traces. Run trace with: { adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/trace <deleteTextureAsync(mTextureName); - mFlinger->mTimeStats->onDestroy(getSequence()); + const int32_t layerID = getSequence(); + mFlinger->mTimeStats->onDestroy(layerID); + mFlinger->mFrameTracer->onDestroy(layerID); } void BufferLayer::useSurfaceDamage() { @@ -314,17 +317,17 @@ bool BufferLayer::onPostComposition(const std::optional& displayId, if (presentFence->isValid()) { mFlinger->mTimeStats->setPresentFence(layerID, mCurrentFrameNumber, presentFence); - mFlinger->mTimeStats->traceFence(layerID, getCurrentBufferId(), mCurrentFrameNumber, - presentFence, TimeStats::FrameEvent::PRESENT_FENCE); + mFlinger->mFrameTracer->traceFence(layerID, getCurrentBufferId(), mCurrentFrameNumber, + presentFence, FrameTracer::FrameEvent::PRESENT_FENCE); mFrameTracker.setActualPresentFence(std::shared_ptr(presentFence)); } else if (displayId && mFlinger->getHwComposer().isConnected(*displayId)) { // The HWC doesn't support present fences, so use the refresh // timestamp instead. const nsecs_t actualPresentTime = mFlinger->getHwComposer().getRefreshTimestamp(*displayId); mFlinger->mTimeStats->setPresentTime(layerID, mCurrentFrameNumber, actualPresentTime); - mFlinger->mTimeStats->traceTimestamp(layerID, getCurrentBufferId(), mCurrentFrameNumber, - actualPresentTime, - TimeStats::FrameEvent::PRESENT_FENCE); + mFlinger->mFrameTracer->traceTimestamp(layerID, getCurrentBufferId(), mCurrentFrameNumber, + actualPresentTime, + FrameTracer::FrameEvent::PRESENT_FENCE); mFrameTracker.setActualPresentTime(actualPresentTime); } diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 6cad3c7d07..4da39e4d6f 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -29,6 +29,7 @@ #include "LayerRejecter.h" #include "SurfaceInterceptor.h" +#include "FrameTracer/FrameTracer.h" #include "TimeStats/TimeStats.h" namespace android { @@ -48,9 +49,9 @@ void BufferQueueLayer::onLayerDisplayed(const sp& releaseFence) { // Prevent tracing the same release multiple times. if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) { - mFlinger->mTimeStats->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber, - std::make_shared(releaseFence), - TimeStats::FrameEvent::RELEASE_FENCE); + mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber, + std::make_shared(releaseFence), + FrameTracer::FrameEvent::RELEASE_FENCE); mPreviousReleasedFrameNumber = mPreviousFrameNumber; } } @@ -337,6 +338,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t mQueueItems.clear(); mQueuedFrames = 0; mFlinger->mTimeStats->onDestroy(layerID); + mFlinger->mFrameTracer->onDestroy(layerID); } // Once we have hit this state, the shadow queue may no longer @@ -366,12 +368,12 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t uint64_t bufferID = mQueueItems[0].mGraphicBuffer->getId(); mFlinger->mTimeStats->setAcquireFence(layerID, currentFrameNumber, mQueueItems[0].mFenceTime); - mFlinger->mTimeStats->traceFence(layerID, bufferID, currentFrameNumber, - mQueueItems[0].mFenceTime, - TimeStats::FrameEvent::ACQUIRE_FENCE); + mFlinger->mFrameTracer->traceFence(layerID, bufferID, currentFrameNumber, + mQueueItems[0].mFenceTime, + FrameTracer::FrameEvent::ACQUIRE_FENCE); mFlinger->mTimeStats->setLatchTime(layerID, currentFrameNumber, latchTime); - mFlinger->mTimeStats->traceTimestamp(layerID, bufferID, currentFrameNumber, latchTime, - TimeStats::FrameEvent::LATCH); + mFlinger->mFrameTracer->traceTimestamp(layerID, bufferID, currentFrameNumber, latchTime, + FrameTracer::FrameEvent::LATCH); mQueueItems.removeAt(0); } @@ -429,9 +431,9 @@ void BufferQueueLayer::latchPerFrameState( void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { const int32_t layerID = getSequence(); - mFlinger->mTimeStats->traceNewLayer(layerID, getName().c_str()); - mFlinger->mTimeStats->traceTimestamp(layerID, item.mGraphicBuffer->getId(), item.mFrameNumber, - systemTime(), TimeStats::FrameEvent::POST); + mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str()); + mFlinger->mFrameTracer->traceTimestamp(layerID, item.mGraphicBuffer->getId(), item.mFrameNumber, + systemTime(), FrameTracer::FrameEvent::POST); ATRACE_CALL(); // Add this buffer from our internal queue tracker diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 4a8261d99f..e7d1b63b03 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -32,6 +32,7 @@ #include "BufferStateLayer.h" #include "ColorLayer.h" +#include "FrameTracer/FrameTracer.h" #include "TimeStats/TimeStats.h" namespace android { @@ -90,9 +91,9 @@ void BufferStateLayer::onLayerDisplayed(const sp& releaseFence) { // Prevent tracing the same release multiple times. if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) { - mFlinger->mTimeStats->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber, - std::make_shared(releaseFence), - TimeStats::FrameEvent::RELEASE_FENCE); + mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber, + std::make_shared(releaseFence), + FrameTracer::FrameEvent::RELEASE_FENCE); mPreviousReleasedFrameNumber = mPreviousFrameNumber; } } @@ -236,9 +237,9 @@ bool BufferStateLayer::setBuffer(const sp& buffer, nsecs_t postTi const int32_t layerID = getSequence(); mFlinger->mTimeStats->setPostTime(layerID, mFrameNumber, getName().c_str(), postTime); - mFlinger->mTimeStats->traceNewLayer(layerID, getName().c_str()); - mFlinger->mTimeStats->traceTimestamp(layerID, buffer->getId(), mFrameNumber, postTime, - TimeStats::FrameEvent::POST); + mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str()); + mFlinger->mFrameTracer->traceTimestamp(layerID, buffer->getId(), mFrameNumber, postTime, + FrameTracer::FrameEvent::POST); mCurrentState.desiredPresentTime = desiredPresentTime; if (mFlinger->mUseSmart90ForVideo) { @@ -569,17 +570,18 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse status_t err = bindTextureImage(); if (err != NO_ERROR) { mFlinger->mTimeStats->onDestroy(layerID); + mFlinger->mFrameTracer->onDestroy(layerID); return BAD_VALUE; } } const uint64_t bufferID = getCurrentBufferId(); mFlinger->mTimeStats->setAcquireFence(layerID, mFrameNumber, getCurrentFenceTime()); - mFlinger->mTimeStats->traceFence(layerID, bufferID, mFrameNumber, getCurrentFenceTime(), - TimeStats::FrameEvent::ACQUIRE_FENCE); + mFlinger->mFrameTracer->traceFence(layerID, bufferID, mFrameNumber, getCurrentFenceTime(), + FrameTracer::FrameEvent::ACQUIRE_FENCE); mFlinger->mTimeStats->setLatchTime(layerID, mFrameNumber, latchTime); - mFlinger->mTimeStats->traceTimestamp(layerID, bufferID, mFrameNumber, latchTime, - TimeStats::FrameEvent::LATCH); + mFlinger->mFrameTracer->traceTimestamp(layerID, bufferID, mFrameNumber, latchTime, + FrameTracer::FrameEvent::LATCH); mCurrentStateModified = false; diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.cpp b/services/surfaceflinger/FrameTracer/FrameTracer.cpp new file mode 100644 index 0000000000..7cbb8d8b7c --- /dev/null +++ b/services/surfaceflinger/FrameTracer/FrameTracer.cpp @@ -0,0 +1,173 @@ +/* + * 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. + */ + +#undef LOG_TAG +#define LOG_TAG "FrameTracer" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "FrameTracer.h" + +#include + +#include + +PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::FrameTracer::FrameTracerDataSource); + +namespace android { + +void FrameTracer::initialize() { + perfetto::TracingInitArgs args; + args.backends = perfetto::kSystemBackend; + perfetto::Tracing::Initialize(args); + registerDataSource(); +} + +void FrameTracer::registerDataSource() { + perfetto::DataSourceDescriptor dsd; + dsd.set_name(kFrameTracerDataSource); + FrameTracerDataSource::Register(dsd); +} + +void FrameTracer::traceNewLayer(int32_t layerID, const std::string& layerName) { + FrameTracerDataSource::Trace([this, layerID, &layerName](FrameTracerDataSource::TraceContext) { + if (mTraceTracker.find(layerID) == mTraceTracker.end()) { + std::lock_guard lock(mTraceMutex); + mTraceTracker[layerID].layerName = layerName; + } + }); +} + +void FrameTracer::traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, + nsecs_t timestamp, FrameEvent::BufferEventType type, + nsecs_t duration) { + FrameTracerDataSource::Trace([this, layerID, bufferID, frameNumber, timestamp, type, + duration](FrameTracerDataSource::TraceContext ctx) { + std::lock_guard lock(mTraceMutex); + if (mTraceTracker.find(layerID) == mTraceTracker.end()) { + return; + } + + // Handle any pending fences for this buffer. + tracePendingFencesLocked(ctx, layerID, bufferID); + + // Complete current trace. + traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration); + }); +} + +void FrameTracer::traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, + const std::shared_ptr& fence, + FrameEvent::BufferEventType type, nsecs_t startTime) { + FrameTracerDataSource::Trace([this, layerID, bufferID, frameNumber, &fence, type, + startTime](FrameTracerDataSource::TraceContext ctx) { + const nsecs_t signalTime = fence->getSignalTime(); + if (signalTime != Fence::SIGNAL_TIME_INVALID) { + std::lock_guard lock(mTraceMutex); + if (mTraceTracker.find(layerID) == mTraceTracker.end()) { + return; + } + + // Handle any pending fences for this buffer. + tracePendingFencesLocked(ctx, layerID, bufferID); + + if (signalTime != Fence::SIGNAL_TIME_PENDING) { + traceSpanLocked(ctx, layerID, bufferID, frameNumber, type, startTime, signalTime); + } else { + mTraceTracker[layerID].pendingFences[bufferID].push_back( + {.frameNumber = frameNumber, + .type = type, + .fence = fence, + .startTime = startTime}); + } + } + }); +} + +void FrameTracer::tracePendingFencesLocked(FrameTracerDataSource::TraceContext& ctx, + int32_t layerID, uint64_t bufferID) { + if (mTraceTracker[layerID].pendingFences.count(bufferID)) { + auto& pendingFences = mTraceTracker[layerID].pendingFences[bufferID]; + for (size_t i = 0; i < pendingFences.size(); ++i) { + auto& pendingFence = pendingFences[i]; + + nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID; + if (pendingFence.fence && pendingFence.fence->isValid()) { + signalTime = pendingFence.fence->getSignalTime(); + if (signalTime == Fence::SIGNAL_TIME_PENDING) { + continue; + } + } + + if (signalTime != Fence::SIGNAL_TIME_INVALID && + systemTime() - signalTime < kFenceSignallingDeadline) { + traceSpanLocked(ctx, layerID, bufferID, pendingFence.frameNumber, pendingFence.type, + pendingFence.startTime, signalTime); + } + + pendingFences.erase(pendingFences.begin() + i); + --i; + } + } +} + +void FrameTracer::traceLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID, + uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp, + FrameEvent::BufferEventType type, nsecs_t duration) { + auto packet = ctx.NewTracePacket(); + packet->set_timestamp(timestamp); + auto* event = packet->set_graphics_frame_event()->set_buffer_event(); + event->set_buffer_id(static_cast(bufferID)); + event->set_frame_number(frameNumber); + event->set_type(type); + + if (mTraceTracker.find(layerID) != mTraceTracker.end() && + !mTraceTracker[layerID].layerName.empty()) { + const std::string& layerName = mTraceTracker[layerID].layerName; + event->set_layer_name(layerName.c_str(), layerName.size()); + } + + if (duration > 0) { + event->set_duration_ns(duration); + } +} + +void FrameTracer::traceSpanLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID, + uint64_t bufferID, uint64_t frameNumber, + FrameEvent::BufferEventType type, nsecs_t startTime, + nsecs_t endTime) { + nsecs_t timestamp = endTime; + nsecs_t duration = 0; + if (startTime > 0 && startTime < endTime) { + timestamp = startTime; + duration = endTime - startTime; + } + traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration); +} + +void FrameTracer::onDestroy(int32_t layerID) { + std::lock_guard traceLock(mTraceMutex); + mTraceTracker.erase(layerID); +} + +std::string FrameTracer::miniDump() { + std::string result = "FrameTracer miniDump:\n"; + std::lock_guard lock(mTraceMutex); + android::base::StringAppendF(&result, "Number of layers currently being traced is %zu\n", + mTraceTracker.size()); + return result; +} + +} // namespace android diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.h b/services/surfaceflinger/FrameTracer/FrameTracer.h new file mode 100644 index 0000000000..d34ad81fee --- /dev/null +++ b/services/surfaceflinger/FrameTracer/FrameTracer.h @@ -0,0 +1,105 @@ +/* + * 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 +#include +#include + +#include +#include + +namespace android { + +class FrameTracer { +public: + class FrameTracerDataSource : public perfetto::DataSource { + virtual void OnSetup(const SetupArgs&) override{}; + virtual void OnStart(const StartArgs&) override{}; + virtual void OnStop(const StopArgs&) override{}; + }; + + using FrameEvent = perfetto::protos::pbzero::GraphicsFrameEvent; + + ~FrameTracer() = default; + + // Sets up the perfetto tracing backend and data source. + void initialize(); + // Registers the data source with the perfetto backend. Called as part of initialize() + // and should not be called manually outside of tests. Public to allow for substituting a + // perfetto::kInProcessBackend in tests. + void registerDataSource(); + // Starts tracking a new layer for tracing. Needs to be called once before traceTimestamp() or + // traceFence() for each layer. + void traceNewLayer(int32_t layerID, const std::string& layerName); + // Creates a trace point at the timestamp provided. + void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp, + FrameEvent::BufferEventType type, nsecs_t duration = 0); + // Creates a trace point after the provided fence has been signalled. If a startTime is provided + // the trace will have be timestamped from startTime until fence signalling time. If no + // startTime is provided, a durationless trace point will be created timestamped at fence + // signalling time. If the fence hasn't signalled yet, the trace point will be created the next + // time after signalling a trace call for this buffer occurs. + void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, + const std::shared_ptr& fence, FrameEvent::BufferEventType type, + nsecs_t startTime = 0); + + // Takes care of cleanup when a layer is destroyed. + void onDestroy(int32_t layerID); + + std::string miniDump(); + + static constexpr char kFrameTracerDataSource[] = "android.surfaceflinger.frame"; + + // The maximum amount of time a fence has to signal before it is discarded. + // Used to avoid fences from previous traces generating new trace points in later ones. + // Public for testing. + static constexpr nsecs_t kFenceSignallingDeadline = 60'000'000'000; // 60 seconds + +private: + struct PendingFence { + uint64_t frameNumber; + FrameEvent::BufferEventType type; + std::shared_ptr fence; + nsecs_t startTime; + }; + + struct TraceRecord { + std::string layerName; + using BufferID = uint64_t; + std::unordered_map> pendingFences; + }; + + // Checks if any pending fences for a layer and buffer have signalled and, if they have, creates + // trace points for them. + void tracePendingFencesLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID, + uint64_t bufferID); + // Creates a trace point by translating a start time and an end time to a timestamp and + // duration. If startTime is later than end time it sets end time as the timestamp and the + // duration to 0. Used by traceFence(). + void traceSpanLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID, + uint64_t bufferID, uint64_t frameNumber, FrameEvent::BufferEventType type, + nsecs_t startTime, nsecs_t endTime); + void traceLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID, + uint64_t frameNumber, nsecs_t timestamp, FrameEvent::BufferEventType type, + nsecs_t duration = 0); + + std::mutex mTraceMutex; + std::unordered_map mTraceTracker; +}; + +} // namespace android diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5121835cae..106d505faa 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -57,6 +57,7 @@ #include "Colorizer.h" #include "DisplayDevice.h" #include "DisplayHardware/HWComposer.h" +#include "FrameTracer/FrameTracer.h" #include "LayerProtoHelper.h" #include "LayerRejecter.h" #include "MonitoredProducer.h" @@ -1343,7 +1344,9 @@ void Layer::dumpFrameEvents(std::string& result) { void Layer::onDisconnect() { Mutex::Autolock lock(mFrameEventHistoryMutex); mFrameEventHistory.onDisconnect(); - mFlinger->mTimeStats->onDestroy(getSequence()); + const int32_t layerID = getSequence(); + mFlinger->mTimeStats->onDestroy(layerID); + mFlinger->mFrameTracer->onDestroy(layerID); } void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6543089101..e8902b3c62 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -98,6 +98,7 @@ #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/VirtualDisplaySurface.h" #include "Effects/Daltonizer.h" +#include "FrameTracer/FrameTracer.h" #include "RegionSamplingThread.h" #include "Scheduler/DispSync.h" #include "Scheduler/DispSyncSource.h" @@ -257,6 +258,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) : mFactory(factory), mInterceptor(mFactory.createSurfaceInterceptor(this)), mTimeStats(mFactory.createTimeStats()), + mFrameTracer(std::make_unique()), mEventQueue(mFactory.createMessageQueue()), mCompositionEngine(mFactory.createCompositionEngine()), mPhaseOffsets(mFactory.createPhaseOffsets()) {} @@ -513,7 +515,7 @@ void SurfaceFlinger::bootFinished() const nsecs_t duration = now - mBootTime; ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); - mTimeStats->initializeTracing(); + mFrameTracer->initialize(); // wait patiently for the window manager death const String16 name("window"); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8408ef5174..c7cc07e490 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -94,6 +94,7 @@ class MessageBase; class RefreshRateOverlay; class RegionSamplingThread; class TimeStats; +class FrameTracer; namespace compositionengine { class DisplaySurface; @@ -996,6 +997,7 @@ private: bool mTracingEnabled = false; bool mTracingEnabledChanged GUARDED_BY(mStateLock) = false; const std::shared_ptr mTimeStats; + const std::unique_ptr mFrameTracer; bool mUseHwcVirtualDisplays = false; std::atomic mFrameMissedCount = 0; std::atomic mHwcFrameMissedCount = 0; diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp index 9e1d5033b2..2080a3847e 100644 --- a/services/surfaceflinger/TimeStats/Android.bp +++ b/services/surfaceflinger/TimeStats/Android.bp @@ -2,12 +2,9 @@ cc_library_static { name: "libtimestats", defaults: ["surfaceflinger_defaults"], srcs: [ - "TimeStats.cpp" + "TimeStats.cpp", ], export_include_dirs: ["."], - static_libs: [ - "libperfetto_client_experimental", - ], shared_libs: [ "libtimestats_proto", "libui", diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index b66e4cfe4f..b01fa81594 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -30,141 +30,10 @@ #include #include -PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::impl::TimeStats::TimeStatsDataSource); - namespace android { namespace impl { -void TimeStats::initializeTracing() { - perfetto::TracingInitArgs args; - args.backends = perfetto::kSystemBackend; - perfetto::Tracing::Initialize(args); - registerTracingDataSource(); -} - -void TimeStats::registerTracingDataSource() { - perfetto::DataSourceDescriptor dsd; - dsd.set_name(kTimeStatsDataSource); - TimeStatsDataSource::Register(dsd); -} - -void TimeStats::traceNewLayer(int32_t layerID, const std::string& layerName) { - TimeStatsDataSource::Trace([this, layerID, &layerName](TimeStatsDataSource::TraceContext) { - if (mTraceTracker.find(layerID) == mTraceTracker.end()) { - std::lock_guard lock(mTraceMutex); - mTraceTracker[layerID].layerName = layerName; - } - }); -} - -void TimeStats::traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, - nsecs_t timestamp, FrameEvent::BufferEventType type, - nsecs_t duration) { - TimeStatsDataSource::Trace([this, layerID, bufferID, frameNumber, timestamp, type, - duration](TimeStatsDataSource::TraceContext ctx) { - std::lock_guard lock(mTraceMutex); - if (mTraceTracker.find(layerID) == mTraceTracker.end()) { - return; - } - - // Handle any pending fences for this buffer. - tracePendingFencesLocked(ctx, layerID, bufferID); - - // Complete current trace. - traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration); - }); -} - -void TimeStats::traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, - const std::shared_ptr& fence, - FrameEvent::BufferEventType type, nsecs_t startTime) { - TimeStatsDataSource::Trace([this, layerID, bufferID, frameNumber, &fence, type, - startTime](TimeStatsDataSource::TraceContext ctx) { - const nsecs_t signalTime = fence->getSignalTime(); - if (signalTime != Fence::SIGNAL_TIME_INVALID) { - std::lock_guard lock(mTraceMutex); - if (mTraceTracker.find(layerID) == mTraceTracker.end()) { - return; - } - - // Handle any pending fences for this buffer. - tracePendingFencesLocked(ctx, layerID, bufferID); - - if (signalTime != Fence::SIGNAL_TIME_PENDING) { - traceSpanLocked(ctx, layerID, bufferID, frameNumber, type, startTime, signalTime); - } else { - mTraceTracker[layerID].pendingFences[bufferID].push_back( - {.frameNumber = frameNumber, - .type = type, - .fence = fence, - .startTime = startTime}); - } - } - }); -} - -void TimeStats::tracePendingFencesLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, - uint64_t bufferID) { - if (mTraceTracker[layerID].pendingFences.count(bufferID)) { - auto& pendingFences = mTraceTracker[layerID].pendingFences[bufferID]; - for (size_t i = 0; i < pendingFences.size(); ++i) { - auto& pendingFence = pendingFences[i]; - - nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID; - if (pendingFence.fence && pendingFence.fence->isValid()) { - signalTime = pendingFence.fence->getSignalTime(); - if (signalTime == Fence::SIGNAL_TIME_PENDING) { - continue; - } - } - - if (signalTime != Fence::SIGNAL_TIME_INVALID && - systemTime() - signalTime < kFenceSignallingDeadline) { - traceSpanLocked(ctx, layerID, bufferID, pendingFence.frameNumber, pendingFence.type, - pendingFence.startTime, signalTime); - } - - pendingFences.erase(pendingFences.begin() + i); - --i; - } - } -} - -void TimeStats::traceLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, - uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp, - FrameEvent::BufferEventType type, nsecs_t duration) { - auto packet = ctx.NewTracePacket(); - packet->set_timestamp(timestamp); - auto* event = packet->set_graphics_frame_event()->set_buffer_event(); - event->set_buffer_id(static_cast(bufferID)); - event->set_frame_number(frameNumber); - event->set_type(type); - - if (mTraceTracker.find(layerID) != mTraceTracker.end() && - !mTraceTracker[layerID].layerName.empty()) { - const std::string& layerName = mTraceTracker[layerID].layerName; - event->set_layer_name(layerName.c_str(), layerName.size()); - } - - if (duration > 0) { - event->set_duration_ns(duration); - } -} - -void TimeStats::traceSpanLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, - uint64_t bufferID, uint64_t frameNumber, - FrameEvent::BufferEventType type, nsecs_t startTime, - nsecs_t endTime) { - nsecs_t timestamp = endTime; - nsecs_t duration = 0; - if (startTime > 0 && startTime < endTime) { - timestamp = startTime; - duration = endTime - startTime; - } - traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration); -} - void TimeStats::parseArgs(bool asProto, const Vector& args, std::string& result) { ATRACE_CALL(); @@ -207,8 +76,6 @@ std::string TimeStats::miniDump() { mTimeStatsTracker.size()); android::base::StringAppendF(&result, "Number of layers in the stats pool is %zu\n", mTimeStats.stats.size()); - android::base::StringAppendF(&result, "Number of layers currently being traced is %zu\n", - mTraceTracker.size()); return result; } @@ -542,15 +409,8 @@ void TimeStats::setPresentFence(int32_t layerID, uint64_t frameNumber, void TimeStats::onDestroy(int32_t layerID) { ATRACE_CALL(); ALOGV("[%d]-onDestroy", layerID); - { - std::lock_guard lock(mMutex); - mTimeStatsTracker.erase(layerID); - } - - { - std::lock_guard traceLock(mTraceMutex); - mTraceTracker.erase(layerID); - } + std::lock_guard lock(mMutex); + mTimeStatsTracker.erase(layerID); } void TimeStats::removeTimeRecord(int32_t layerID, uint64_t frameNumber) { diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 470137a431..9ebc1adc90 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -17,8 +17,6 @@ #pragma once #include -#include -#include #include #include #include @@ -36,32 +34,8 @@ namespace android { class TimeStats { public: - using FrameEvent = perfetto::protos::pbzero::GraphicsFrameEvent; - virtual ~TimeStats() = default; - // Sets up the perfetto tracing backend and data source. - virtual void initializeTracing() = 0; - // Registers the data source with the perfetto backend. Called as part of initializeTracing() - // and should not be called manually outside of tests. Public to allow for substituting a - // perfetto::kInProcessBackend in tests. - virtual void registerTracingDataSource() = 0; - // Starts tracking a new layer for tracing. Needs to be called once before traceTimestamp() or - // traceFence() for each layer. - virtual void traceNewLayer(int32_t layerID, const std::string& layerName) = 0; - // Creates a trace point at the timestamp provided. - virtual void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, - nsecs_t timestamp, FrameEvent::BufferEventType type, - nsecs_t duration = 0) = 0; - // Creates a trace point after the provided fence has been signalled. If a startTime is provided - // the trace will have be timestamped from startTime until fence signalling time. If no - // startTime is provided, a durationless trace point will be created timestamped at fence - // signalling time. If the fence hasn't signalled yet, the trace point will be created the next - // time after signalling a trace call for this buffer occurs. - virtual void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, - const std::shared_ptr& fence, - FrameEvent::BufferEventType type, nsecs_t startTime = 0) = 0; - virtual void parseArgs(bool asProto, const Vector& args, std::string& result) = 0; virtual bool isEnabled() = 0; virtual std::string miniDump() = 0; @@ -89,13 +63,6 @@ public: // Source of truth is RefrehRateStats. virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0; virtual void setPresentFenceGlobal(const std::shared_ptr& presentFence) = 0; - - static constexpr char kTimeStatsDataSource[] = "android.surfaceflinger.timestats"; - - // The maximum amount of time a fence has to signal before it is discarded. - // Used to avoid fence's from previous traces generating new trace points in later ones. - // Public for testing. - static constexpr nsecs_t kFenceSignallingDeadline = 60'000'000'000; // 60 seconds }; namespace impl { @@ -117,13 +84,6 @@ class TimeStats : public android::TimeStats { std::shared_ptr presentFence; }; - struct PendingFence { - uint64_t frameNumber; - FrameEvent::BufferEventType type; - std::shared_ptr fence; - nsecs_t startTime; - }; - struct LayerRecord { std::string layerName; // This is the index in timeRecords, at which the timestamps for that @@ -135,12 +95,6 @@ class TimeStats : public android::TimeStats { std::deque timeRecords; }; - struct TraceRecord { - std::string layerName; - using BufferID = uint64_t; - std::unordered_map> pendingFences; - }; - struct PowerTime { int32_t powerMode = HWC_POWER_MODE_OFF; nsecs_t prevTime = 0; @@ -152,23 +106,8 @@ class TimeStats : public android::TimeStats { }; public: - class TimeStatsDataSource : public perfetto::DataSource { - virtual void OnSetup(const SetupArgs&) override{}; - virtual void OnStart(const StartArgs&) override { ALOGV("TimeStats trace started"); }; - virtual void OnStop(const StopArgs&) override { ALOGV("TimeStats trace stopped"); }; - }; - TimeStats() = default; - void initializeTracing() override; - void registerTracingDataSource() override; - void traceNewLayer(int32_t layerID, const std::string& layerName) override; - void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp, - FrameEvent::BufferEventType type, nsecs_t duration = 0) override; - void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, - const std::shared_ptr& fence, FrameEvent::BufferEventType type, - nsecs_t startTime = 0) override; - void parseArgs(bool asProto, const Vector& args, std::string& result) override; bool isEnabled() override; std::string miniDump() override; @@ -200,20 +139,6 @@ public: static const size_t MAX_NUM_TIME_RECORDS = 64; private: - // Checks if any pending fences for a layer and buffer have signalled and, if they have, creates - // trace points for them. - void tracePendingFencesLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, - uint64_t bufferID); - // Creates a trace point by translating a start time and an end time to a timestamp and - // duration. If startTime is later than end time it sets end time as the timestamp and the - // duration to 0. Used by traceFence(). - void traceSpanLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID, - uint64_t frameNumber, FrameEvent::BufferEventType type, nsecs_t startTime, - nsecs_t endTime); - void traceLocked(TimeStatsDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID, - uint64_t frameNumber, nsecs_t timestamp, FrameEvent::BufferEventType type, - nsecs_t duration = 0); - bool recordReadyLocked(int32_t layerID, TimeRecord* timeRecord); void flushAvailableRecordsToStatsLocked(int32_t layerID); void flushPowerTimeLocked(); @@ -232,9 +157,6 @@ private: PowerTime mPowerTime; GlobalRecord mGlobalRecord; - std::mutex mTraceMutex; - std::unordered_map mTraceTracker; - static const size_t MAX_NUM_LAYER_RECORDS = 200; static const size_t MAX_NUM_LAYER_STATS = 200; }; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 0eedf9b7b1..8d98af6298 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -51,6 +51,7 @@ cc_test { "RefreshRateStatsTest.cpp", "RegionSamplingTest.cpp", "TimeStatsTest.cpp", + "FrameTracerTest.cpp", "mock/DisplayHardware/MockComposer.cpp", "mock/DisplayHardware/MockDisplay.cpp", "mock/DisplayHardware/MockPowerAdvisor.cpp", @@ -63,6 +64,7 @@ cc_test { "mock/MockNativeWindowSurface.cpp", "mock/MockSurfaceInterceptor.cpp", "mock/MockTimeStats.cpp", + "mock/MockFrameTracer.cpp", "mock/system/window/MockNativeWindow.cpp", ], static_libs: [ diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp new file mode 100644 index 0000000000..b5af591e25 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp @@ -0,0 +1,396 @@ +/* + * 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. + */ + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include +#include +#include +#include +#include + +#include "libsurfaceflinger_unittest_main.h" + +using namespace google::protobuf; + +namespace android { +namespace { + +class FrameTracerTest : public testing::Test { +public: + FrameTracerTest() { + 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()); + + // Need to initialize tracing in process for testing, and only once per test suite. + static bool wasInitialized = false; + if (!wasInitialized) { + perfetto::TracingInitArgs args; + args.backends = perfetto::kInProcessBackend; + perfetto::Tracing::Initialize(args); + wasInitialized = true; + } + } + + ~FrameTracerTest() { + 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()); + } + + void SetUp() override { + mFrameTracer = std::make_unique(); + mFrameTracer->registerDataSource(); + } + + void TearDown() override { mFrameTracer.reset(); } + + // Each tracing session can be used for a single block of Start -> Stop. + static std::unique_ptr getTracingSessionForTest() { + perfetto::TraceConfig cfg; + cfg.set_duration_ms(500); + cfg.add_buffers()->set_size_kb(1024); + auto* ds_cfg = cfg.add_data_sources()->mutable_config(); + ds_cfg->set_name(FrameTracer::kFrameTracerDataSource); + + auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend); + tracingSession->Setup(cfg); + return tracingSession; + } + + std::unique_ptr mFrameTracer; + FenceToFenceTimeMap fenceFactory; +}; + +TEST_F(FrameTracerTest, traceNewLayerStartsTrackingLayerWhenTracing) { + EXPECT_EQ(mFrameTracer->miniDump(), + "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n"); + + const std::string layerName = "co.layername#0"; + const int32_t layerID = 5; + mFrameTracer->traceNewLayer(layerID, layerName); + + EXPECT_EQ(mFrameTracer->miniDump(), + "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n"); + + auto tracingSession = getTracingSessionForTest(); + tracingSession->StartBlocking(); + EXPECT_EQ(mFrameTracer->miniDump(), + "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n"); + mFrameTracer->traceNewLayer(layerID, layerName); + EXPECT_EQ(mFrameTracer->miniDump(), + "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n"); + tracingSession->StopBlocking(); +} + +TEST_F(FrameTracerTest, onDestroyRemovesTheTrackedLayer) { + EXPECT_EQ(mFrameTracer->miniDump(), + "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n"); + + const std::string layerName = "co.layername#0"; + const int32_t layerID = 5; + const int32_t secondLayerID = 6; + + auto tracingSession = getTracingSessionForTest(); + tracingSession->StartBlocking(); + mFrameTracer->traceNewLayer(layerID, layerName); + mFrameTracer->traceNewLayer(secondLayerID, layerName); + EXPECT_EQ(mFrameTracer->miniDump(), + "FrameTracer miniDump:\nNumber of layers currently being traced is 2\n"); + tracingSession->StopBlocking(); + + mFrameTracer->onDestroy(layerID); + EXPECT_EQ(mFrameTracer->miniDump(), + "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n"); + mFrameTracer->onDestroy(layerID); + EXPECT_EQ(mFrameTracer->miniDump(), + "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n"); + mFrameTracer->onDestroy(secondLayerID); + EXPECT_EQ(mFrameTracer->miniDump(), + "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n"); +} + +TEST_F(FrameTracerTest, canTraceAfterAddingLayer) { + const std::string layerName = "co.layername#0"; + const int32_t layerID = 1; + const uint32_t bufferID = 2; + const uint64_t frameNumber = 3; + const nsecs_t timestamp = 4; + const nsecs_t duration = 5; + const auto type = FrameTracer::FrameEvent::POST; + + { + auto tracingSession = getTracingSessionForTest(); + + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + + mFrameTracer->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration); + // Create second trace packet to finalize the previous one. + mFrameTracer->traceTimestamp(layerID, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + EXPECT_EQ(raw_trace.size(), 0); + } + + { + auto tracingSession = getTracingSessionForTest(); + + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + + mFrameTracer->traceNewLayer(layerID, layerName); + mFrameTracer->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration); + // Create second trace packet to finalize the previous one. + mFrameTracer->traceTimestamp(layerID, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + ASSERT_GT(raw_trace.size(), 0); + + perfetto::protos::Trace trace; + ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); + ASSERT_FALSE(trace.packet().empty()); + EXPECT_EQ(trace.packet().size(), 1); + + const auto& packet = trace.packet().Get(0); + ASSERT_TRUE(packet.has_timestamp()); + EXPECT_EQ(packet.timestamp(), timestamp); + ASSERT_TRUE(packet.has_graphics_frame_event()); + const auto& frame_event = packet.graphics_frame_event(); + ASSERT_TRUE(frame_event.has_buffer_event()); + const auto& buffer_event = frame_event.buffer_event(); + ASSERT_TRUE(buffer_event.has_buffer_id()); + EXPECT_EQ(buffer_event.buffer_id(), bufferID); + ASSERT_TRUE(buffer_event.has_frame_number()); + EXPECT_EQ(buffer_event.frame_number(), frameNumber); + ASSERT_TRUE(buffer_event.has_type()); + EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type)); + ASSERT_TRUE(buffer_event.has_duration_ns()); + EXPECT_EQ(buffer_event.duration_ns(), duration); + } +} + +TEST_F(FrameTracerTest, traceFenceTriggersOnNextTraceAfterFenceFired) { + const std::string layerName = "co.layername#0"; + const int32_t layerID = 5; + const uint32_t bufferID = 4; + const uint64_t frameNumber = 3; + const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE; + + { + auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING); + auto tracingSession = getTracingSessionForTest(); + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + // Trace. + mFrameTracer->traceNewLayer(layerID, layerName); + mFrameTracer->traceFence(layerID, bufferID, frameNumber, fenceTime, type); + // Create extra trace packet to (hopefully not) trigger and finalize the fence packet. + mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + EXPECT_EQ(raw_trace.size(), 0); + } + + { + auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + auto tracingSession = getTracingSessionForTest(); + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + mFrameTracer->traceNewLayer(layerID, layerName); + mFrameTracer->traceFence(layerID, bufferID, frameNumber, fenceTime, type); + const nsecs_t timestamp = systemTime(); + fenceFactory.signalAllForTest(Fence::NO_FENCE, timestamp); + // Create extra trace packet to trigger and finalize fence trace packets. + mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + ASSERT_GT(raw_trace.size(), 0); + + perfetto::protos::Trace trace; + ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); + ASSERT_FALSE(trace.packet().empty()); + EXPECT_EQ(trace.packet().size(), 2); // Two packets because of the extra trace made above. + + const auto& packet = trace.packet().Get(1); + ASSERT_TRUE(packet.has_timestamp()); + EXPECT_EQ(packet.timestamp(), timestamp); + ASSERT_TRUE(packet.has_graphics_frame_event()); + const auto& frame_event = packet.graphics_frame_event(); + ASSERT_TRUE(frame_event.has_buffer_event()); + const auto& buffer_event = frame_event.buffer_event(); + ASSERT_TRUE(buffer_event.has_buffer_id()); + EXPECT_EQ(buffer_event.buffer_id(), bufferID); + ASSERT_TRUE(buffer_event.has_frame_number()); + EXPECT_EQ(buffer_event.frame_number(), frameNumber); + ASSERT_TRUE(buffer_event.has_type()); + EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type)); + EXPECT_FALSE(buffer_event.has_duration_ns()); + } +} + +TEST_F(FrameTracerTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDuration) { + const std::string layerName = "co.layername#0"; + const int32_t layerID = 5; + const uint32_t bufferID = 4; + const uint64_t frameNumber = 3; + const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE; + + auto tracingSession = getTracingSessionForTest(); + + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + mFrameTracer->traceNewLayer(layerID, layerName); + + // traceFence called after fence signalled. + const nsecs_t signalTime1 = systemTime(); + const nsecs_t startTime1 = signalTime1 + 100000; + auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1); + mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1); + + // traceFence called before fence signalled. + const nsecs_t signalTime2 = systemTime(); + const nsecs_t startTime2 = signalTime2 + 100000; + auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2); + fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2); + + // Create extra trace packet to trigger and finalize fence trace packets. + mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + ASSERT_GT(raw_trace.size(), 0); + + perfetto::protos::Trace trace; + ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); + ASSERT_FALSE(trace.packet().empty()); + EXPECT_EQ(trace.packet().size(), 2); + + const auto& packet1 = trace.packet().Get(0); + ASSERT_TRUE(packet1.has_timestamp()); + EXPECT_EQ(packet1.timestamp(), signalTime1); + ASSERT_TRUE(packet1.has_graphics_frame_event()); + ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event()); + ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns()); + + const auto& packet2 = trace.packet().Get(1); + ASSERT_TRUE(packet2.has_timestamp()); + EXPECT_EQ(packet2.timestamp(), signalTime2); + ASSERT_TRUE(packet2.has_graphics_frame_event()); + ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event()); + ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns()); +} + +TEST_F(FrameTracerTest, traceFenceOlderThanDeadline_ShouldBeIgnored) { + const std::string layerName = "co.layername#0"; + const int32_t layerID = 5; + const uint32_t bufferID = 4; + const uint64_t frameNumber = 3; + const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE; + const nsecs_t signalTime = systemTime() - FrameTracer::kFenceSignallingDeadline; + + auto tracingSession = getTracingSessionForTest(); + auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + mFrameTracer->traceNewLayer(layerID, layerName); + mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence, type); + fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime); + // Create extra trace packet to trigger and finalize any previous fence packets. + mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + EXPECT_EQ(raw_trace.size(), 0); +} + +TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) { + const std::string layerName = "co.layername#0"; + const int32_t layerID = 5; + const uint32_t bufferID = 4; + const uint64_t frameNumber = 3; + const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE; + const nsecs_t duration = 1234; + + auto tracingSession = getTracingSessionForTest(); + + tracingSession->StartBlocking(); + // Clean up irrelevant traces. + tracingSession->ReadTraceBlocking(); + mFrameTracer->traceNewLayer(layerID, layerName); + + // traceFence called after fence signalled. + const nsecs_t signalTime1 = systemTime(); + const nsecs_t startTime1 = signalTime1 - duration; + auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1); + mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1); + + // traceFence called before fence signalled. + const nsecs_t signalTime2 = systemTime(); + const nsecs_t startTime2 = signalTime2 - duration; + auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2); + fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2); + + // Create extra trace packet to trigger and finalize fence trace packets. + mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); + tracingSession->StopBlocking(); + + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + ASSERT_GT(raw_trace.size(), 0); + + perfetto::protos::Trace trace; + ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); + ASSERT_FALSE(trace.packet().empty()); + EXPECT_EQ(trace.packet().size(), 2); + + const auto& packet1 = trace.packet().Get(0); + ASSERT_TRUE(packet1.has_timestamp()); + EXPECT_EQ(packet1.timestamp(), startTime1); + ASSERT_TRUE(packet1.has_graphics_frame_event()); + ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event()); + ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns()); + const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event(); + EXPECT_EQ(buffer_event1.duration_ns(), duration); + + const auto& packet2 = trace.packet().Get(1); + ASSERT_TRUE(packet2.has_timestamp()); + EXPECT_EQ(packet2.timestamp(), startTime2); + ASSERT_TRUE(packet2.has_graphics_frame_event()); + ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event()); + ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns()); + const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event(); + EXPECT_EQ(buffer_event2.duration_ns(), duration); +} + +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index f01e603f20..ffacbfef16 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -20,8 +20,8 @@ #include #include #include + #include -#include #include #include @@ -109,15 +109,6 @@ public: 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()); - - // Need to initialize tracing in process for testing, and only once per test suite. - static bool wasInitialized = false; - if (!wasInitialized) { - perfetto::TracingInitArgs args; - args.backends = perfetto::kInProcessBackend; - perfetto::Tracing::Initialize(args); - wasInitialized = true; - } } ~TimeStatsTest() { @@ -126,13 +117,6 @@ public: ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } - void SetUp() override { - mTimeStats = std::make_unique(); - mTimeStats->registerTracingDataSource(); - } - - void TearDown() override { mTimeStats.reset(); } - std::string inputCommand(InputCommand cmd, bool useProto); void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts); @@ -147,22 +131,8 @@ public: } } - // Each tracing session can be used for a single block of Start -> Stop. - static std::unique_ptr getTracingSessionForTest() { - perfetto::TraceConfig cfg; - cfg.set_duration_ms(500); - cfg.add_buffers()->set_size_kb(1024); - auto* ds_cfg = cfg.add_data_sources()->mutable_config(); - ds_cfg->set_name(TimeStats::kTimeStatsDataSource); - - auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend); - tracingSession->Setup(cfg); - return tracingSession; - } - std::mt19937 mRandomEngine = std::mt19937(std::random_device()()); - std::unique_ptr mTimeStats; - FenceToFenceTimeMap fenceFactory; + std::unique_ptr mTimeStats = std::make_unique(); }; std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) { @@ -239,330 +209,6 @@ int32_t TimeStatsTest::genRandomInt32(int32_t begin, int32_t end) { return distr(mRandomEngine); } -TEST_F(TimeStatsTest, traceNewLayerStartsTrackingLayerWhenTracing) { - EXPECT_EQ(mTimeStats->miniDump(), - "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " - "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n"); - - const std::string layerName = "co.layername#0"; - const int32_t layerID = 5; - mTimeStats->traceNewLayer(layerID, layerName); - - EXPECT_EQ(mTimeStats->miniDump(), - "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " - "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n"); - - auto tracingSession = getTracingSessionForTest(); - tracingSession->StartBlocking(); - EXPECT_EQ(mTimeStats->miniDump(), - "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " - "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n"); - mTimeStats->traceNewLayer(layerID, layerName); - EXPECT_EQ(mTimeStats->miniDump(), - "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " - "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n"); - tracingSession->StopBlocking(); -} - -TEST_F(TimeStatsTest, onDestroyRemovesTheTrackedLayer) { - EXPECT_EQ(mTimeStats->miniDump(), - "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " - "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n"); - - const std::string layerName = "co.layername#0"; - const int32_t layerID = 5; - const int32_t secondLayerID = 6; - - auto tracingSession = getTracingSessionForTest(); - tracingSession->StartBlocking(); - mTimeStats->traceNewLayer(layerID, layerName); - mTimeStats->traceNewLayer(secondLayerID, layerName); - EXPECT_EQ(mTimeStats->miniDump(), - "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " - "layers in the stats pool is 0\nNumber of layers currently being traced is 2\n"); - tracingSession->StopBlocking(); - - mTimeStats->onDestroy(layerID); - EXPECT_EQ(mTimeStats->miniDump(), - "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " - "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n"); - mTimeStats->onDestroy(layerID); - EXPECT_EQ(mTimeStats->miniDump(), - "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " - "layers in the stats pool is 0\nNumber of layers currently being traced is 1\n"); - mTimeStats->onDestroy(secondLayerID); - EXPECT_EQ(mTimeStats->miniDump(), - "TimeStats miniDump:\nNumber of layers currently being tracked is 0\nNumber of " - "layers in the stats pool is 0\nNumber of layers currently being traced is 0\n"); -} - -TEST_F(TimeStatsTest, canTraceAfterAddingLayer) { - const std::string layerName = "co.layername#0"; - const int32_t layerID = 1; - const uint32_t bufferID = 2; - const uint64_t frameNumber = 3; - const nsecs_t timestamp = 4; - const nsecs_t duration = 5; - const auto type = TimeStats::FrameEvent::POST; - - { - auto tracingSession = getTracingSessionForTest(); - - tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); - - mTimeStats->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration); - // Create second trace packet to finalize the previous one. - mTimeStats->traceTimestamp(layerID, 0, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); - tracingSession->StopBlocking(); - - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - EXPECT_EQ(raw_trace.size(), 0); - } - - { - auto tracingSession = getTracingSessionForTest(); - - tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); - - mTimeStats->traceNewLayer(layerID, layerName); - mTimeStats->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration); - // Create second trace packet to finalize the previous one. - mTimeStats->traceTimestamp(layerID, 0, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); - tracingSession->StopBlocking(); - - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - ASSERT_GT(raw_trace.size(), 0); - - perfetto::protos::Trace trace; - ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); - ASSERT_FALSE(trace.packet().empty()); - EXPECT_EQ(trace.packet().size(), 1); - - const auto& packet = trace.packet().Get(0); - ASSERT_TRUE(packet.has_timestamp()); - EXPECT_EQ(packet.timestamp(), timestamp); - ASSERT_TRUE(packet.has_graphics_frame_event()); - const auto& frame_event = packet.graphics_frame_event(); - ASSERT_TRUE(frame_event.has_buffer_event()); - const auto& buffer_event = frame_event.buffer_event(); - ASSERT_TRUE(buffer_event.has_buffer_id()); - EXPECT_EQ(buffer_event.buffer_id(), bufferID); - ASSERT_TRUE(buffer_event.has_frame_number()); - EXPECT_EQ(buffer_event.frame_number(), frameNumber); - ASSERT_TRUE(buffer_event.has_type()); - EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type)); - ASSERT_TRUE(buffer_event.has_duration_ns()); - EXPECT_EQ(buffer_event.duration_ns(), duration); - } -} - -TEST_F(TimeStatsTest, traceFenceTriggersOnNextTraceAfterFenceFired) { - const std::string layerName = "co.layername#0"; - const int32_t layerID = 5; - const uint32_t bufferID = 4; - const uint64_t frameNumber = 3; - const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE; - - { - auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); - fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING); - auto tracingSession = getTracingSessionForTest(); - tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); - // Trace. - mTimeStats->traceNewLayer(layerID, layerName); - mTimeStats->traceFence(layerID, bufferID, frameNumber, fenceTime, type); - // Create extra trace packet to (hopefully not) trigger and finalize the fence packet. - mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); - tracingSession->StopBlocking(); - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - EXPECT_EQ(raw_trace.size(), 0); - } - - { - auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); - auto tracingSession = getTracingSessionForTest(); - tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); - mTimeStats->traceNewLayer(layerID, layerName); - mTimeStats->traceFence(layerID, bufferID, frameNumber, fenceTime, type); - const nsecs_t timestamp = systemTime(); - fenceFactory.signalAllForTest(Fence::NO_FENCE, timestamp); - // Create extra trace packet to trigger and finalize fence trace packets. - mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); - tracingSession->StopBlocking(); - - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - ASSERT_GT(raw_trace.size(), 0); - - perfetto::protos::Trace trace; - ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); - ASSERT_FALSE(trace.packet().empty()); - EXPECT_EQ(trace.packet().size(), 2); // Two packets because of the extra trace made above. - - const auto& packet = trace.packet().Get(1); - ASSERT_TRUE(packet.has_timestamp()); - EXPECT_EQ(packet.timestamp(), timestamp); - ASSERT_TRUE(packet.has_graphics_frame_event()); - const auto& frame_event = packet.graphics_frame_event(); - ASSERT_TRUE(frame_event.has_buffer_event()); - const auto& buffer_event = frame_event.buffer_event(); - ASSERT_TRUE(buffer_event.has_buffer_id()); - EXPECT_EQ(buffer_event.buffer_id(), bufferID); - ASSERT_TRUE(buffer_event.has_frame_number()); - EXPECT_EQ(buffer_event.frame_number(), frameNumber); - ASSERT_TRUE(buffer_event.has_type()); - EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type)); - EXPECT_FALSE(buffer_event.has_duration_ns()); - } -} - -TEST_F(TimeStatsTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDuration) { - const std::string layerName = "co.layername#0"; - const int32_t layerID = 5; - const uint32_t bufferID = 4; - const uint64_t frameNumber = 3; - const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE; - - auto tracingSession = getTracingSessionForTest(); - - tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); - mTimeStats->traceNewLayer(layerID, layerName); - - // traceFence called after fence signalled. - const nsecs_t signalTime1 = systemTime(); - const nsecs_t startTime1 = signalTime1 + 100000; - auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); - fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1); - mTimeStats->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1); - - // traceFence called before fence signalled. - const nsecs_t signalTime2 = systemTime(); - const nsecs_t startTime2 = signalTime2 + 100000; - auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); - mTimeStats->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2); - fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2); - - // Create extra trace packet to trigger and finalize fence trace packets. - mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); - tracingSession->StopBlocking(); - - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - ASSERT_GT(raw_trace.size(), 0); - - perfetto::protos::Trace trace; - ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); - ASSERT_FALSE(trace.packet().empty()); - EXPECT_EQ(trace.packet().size(), 2); - - const auto& packet1 = trace.packet().Get(0); - ASSERT_TRUE(packet1.has_timestamp()); - EXPECT_EQ(packet1.timestamp(), signalTime1); - ASSERT_TRUE(packet1.has_graphics_frame_event()); - ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event()); - ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns()); - - const auto& packet2 = trace.packet().Get(1); - ASSERT_TRUE(packet2.has_timestamp()); - EXPECT_EQ(packet2.timestamp(), signalTime2); - ASSERT_TRUE(packet2.has_graphics_frame_event()); - ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event()); - ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns()); -} - -TEST_F(TimeStatsTest, traceFenceOlderThanDeadline_ShouldBeIgnored) { - const std::string layerName = "co.layername#0"; - const int32_t layerID = 5; - const uint32_t bufferID = 4; - const uint64_t frameNumber = 3; - const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE; - const nsecs_t signalTime = systemTime() - TimeStats::kFenceSignallingDeadline; - - auto tracingSession = getTracingSessionForTest(); - auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); - - tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); - mTimeStats->traceNewLayer(layerID, layerName); - mTimeStats->traceFence(layerID, bufferID, frameNumber, fence, type); - fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime); - // Create extra trace packet to trigger and finalize any previous fence packets. - mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); - tracingSession->StopBlocking(); - - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - EXPECT_EQ(raw_trace.size(), 0); -} - -TEST_F(TimeStatsTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) { - const std::string layerName = "co.layername#0"; - const int32_t layerID = 5; - const uint32_t bufferID = 4; - const uint64_t frameNumber = 3; - const auto type = TimeStats::FrameEvent::ACQUIRE_FENCE; - const nsecs_t duration = 1234; - - auto tracingSession = getTracingSessionForTest(); - - tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); - mTimeStats->traceNewLayer(layerID, layerName); - - // traceFence called after fence signalled. - const nsecs_t signalTime1 = systemTime(); - const nsecs_t startTime1 = signalTime1 - duration; - auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); - fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1); - mTimeStats->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1); - - // traceFence called before fence signalled. - const nsecs_t signalTime2 = systemTime(); - const nsecs_t startTime2 = signalTime2 - duration; - auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); - mTimeStats->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2); - fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2); - - // Create extra trace packet to trigger and finalize fence trace packets. - mTimeStats->traceTimestamp(layerID, bufferID, 0, 0, TimeStats::FrameEvent::UNSPECIFIED); - tracingSession->StopBlocking(); - - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - ASSERT_GT(raw_trace.size(), 0); - - perfetto::protos::Trace trace; - ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); - ASSERT_FALSE(trace.packet().empty()); - EXPECT_EQ(trace.packet().size(), 2); - - const auto& packet1 = trace.packet().Get(0); - ASSERT_TRUE(packet1.has_timestamp()); - EXPECT_EQ(packet1.timestamp(), startTime1); - ASSERT_TRUE(packet1.has_graphics_frame_event()); - ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event()); - ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns()); - const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event(); - EXPECT_EQ(buffer_event1.duration_ns(), duration); - - const auto& packet2 = trace.packet().Get(1); - ASSERT_TRUE(packet2.has_timestamp()); - EXPECT_EQ(packet2.timestamp(), startTime2); - ASSERT_TRUE(packet2.has_graphics_frame_event()); - ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event()); - ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns()); - const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event(); - EXPECT_EQ(buffer_event2.duration_ns(), duration); -} - TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) { EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); ASSERT_TRUE(mTimeStats->isEnabled()); diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp new file mode 100644 index 0000000000..358dfdb856 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp @@ -0,0 +1,27 @@ +/* + * 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 "mock/MockFrameTracer.h" + +namespace android { +namespace mock { + +// Explicit default instantiation is recommended. +FrameTracer::FrameTracer() = default; +FrameTracer::~FrameTracer() = default; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h new file mode 100644 index 0000000000..f768b8114d --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h @@ -0,0 +1,43 @@ +/* + * 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 + +#include "FrameTracer/FrameTracer.h" + +namespace android { +namespace mock { + +class FrameTracer : public android::FrameTracer { +public: + FrameTracer(); + ~FrameTracer(); + + MOCK_METHOD0(initialize, void()); + MOCK_METHOD0(registerDataSource, void()); + MOCK_METHOD2(traceNewLayer, void(int32_t, const std::string&)); + MOCK_METHOD6(traceTimestamp, + void(int32_t, uint64_t, uint64_t, nsecs_t, FrameEvent::BufferEventType, nsecs_t)); + MOCK_METHOD6(traceFence, + void(int32_t, uint64_t, uint64_t, const std::shared_ptr&, + FrameEvent::BufferEventType, nsecs_t)); + MOCK_METHOD0(miniDump, std::string()); +}; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h index 542c70a8fb..b1634a8da7 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h @@ -28,14 +28,6 @@ public: TimeStats(); ~TimeStats() override; - MOCK_METHOD0(initializeTracing, void()); - MOCK_METHOD0(registerTracingDataSource, void()); - MOCK_METHOD2(traceNewLayer, void(int32_t, const std::string&)); - MOCK_METHOD6(traceTimestamp, - void(int32_t, uint64_t, uint64_t, nsecs_t, FrameEvent::BufferEventType, nsecs_t)); - MOCK_METHOD6(traceFence, - void(int32_t, uint64_t, uint64_t, const std::shared_ptr&, - FrameEvent::BufferEventType, nsecs_t)); MOCK_METHOD3(parseArgs, void(bool, const Vector&, std::string&)); MOCK_METHOD0(isEnabled, bool()); MOCK_METHOD0(miniDump, std::string()); -- GitLab From 8e95ee87a96bcacab17a4b49a8150fb42565ac8c Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Tue, 13 Aug 2019 12:24:25 -0700 Subject: [PATCH 0215/1255] Camera: add camera audio restriction binder call Also add the API to AppOpsManager Test: new CTS tests Bug: 135676184 Change-Id: I8bcdd34a4b6bb0fba5151677db38f8c35b7ae97e --- libs/binder/AppOpsManager.cpp | 7 +++++++ libs/binder/IAppOpsService.cpp | 14 ++++++++++++++ libs/binder/include/binder/AppOpsManager.h | 2 ++ libs/binder/include/binder/IAppOpsService.h | 5 +++++ 4 files changed, 28 insertions(+) diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index 48b218e78b..e2af01c161 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -193,6 +193,13 @@ int32_t AppOpsManager::permissionToOpCode(const String16& permission) { return -1; } +void AppOpsManager::setCameraAudioRestriction(int32_t mode) { + sp service = getService(); + if (service != nullptr) { + service->setCameraAudioRestriction(mode); + } +} + #endif // __ANDROID_VNDK__ bool AppOpsManager::shouldCollectNotes(int32_t opcode) { diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index 8840990824..b6360cbffd 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -138,6 +138,13 @@ public: return reply.readInt32(); } + virtual void setCameraAudioRestriction(int32_t mode) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + data.writeInt32(mode); + remote()->transact(SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION, data, &reply); + } + #endif virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, int32_t opCode, const String16& message) { @@ -274,6 +281,13 @@ status_t BnAppOpsService::onTransact( reply->writeInt32(res); return NO_ERROR; } break; + case SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + const int32_t mode = data.readInt32(); + setCameraAudioRestriction(mode); + reply->writeNoException(); + return NO_ERROR; + } break; #endif // __ANDROID_VNDK__ case NOTE_ASYNC_OP_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index 7a99396eef..dff4d49596 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -144,9 +144,11 @@ public: const sp& callback); void stopWatchingMode(const sp& callback); int32_t permissionToOpCode(const String16& permission); + void setCameraAudioRestriction(int32_t mode); #endif // __ANDROID_VNDK__ void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, int32_t opCode, const String16& message); + private: Mutex mLock; sp mService; diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index 9d02370015..009ef6c7a7 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -46,6 +46,7 @@ public: virtual int32_t permissionToOpCode(const String16& permission) = 0; virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid, const String16& packageName) = 0; + virtual void setCameraAudioRestriction(int32_t mode) = 0; #endif // __ANDROID_VNDK__ virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, int32_t opCode, const String16& message) = 0; @@ -65,6 +66,10 @@ public: #endif // __ANDROID_VNDK__ NOTE_ASYNC_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9, SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10, +#ifndef __ANDROID_VNDK__ + SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+11, +#endif // __ANDROID_VNDK__ + }; enum { -- GitLab From a4f14de792bf6bc8bab907db172fd26c034aa515 Mon Sep 17 00:00:00 2001 From: mamik Date: Fri, 30 Aug 2019 07:27:14 -0700 Subject: [PATCH 0216/1255] Update external display property in hardware_composer. This change removes the "persist.vr.use_external_display" property and updates the code path to always allow external displays. Bug: 140287770 Test: Manual, ran on device and verified that it works Change-Id: I8bedeb18c93b2a9dc3815177aa9a6a897b63c81e --- libs/vr/libvrflinger/hardware_composer.cpp | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index e1240d6311..9072d89d76 100644 --- a/libs/vr/libvrflinger/hardware_composer.cpp +++ b/libs/vr/libvrflinger/hardware_composer.cpp @@ -51,8 +51,6 @@ const char kDvrStandaloneProperty[] = "ro.boot.vr"; const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns"; -const char kUseExternalDisplayProperty[] = "persist.vr.use_external_display"; - // Surface flinger uses "VSYNC-sf" and "VSYNC-app" for its version of these // events. Name ours similarly. const char kVsyncTraceEventName[] = "VSYNC-vrflinger"; @@ -965,18 +963,9 @@ bool HardwareComposer::UpdateTargetDisplay() { external_display_ = GetDisplayParams(composer_.get(), *displays.external_display, /*is_primary*/ false); - if (property_get_bool(kUseExternalDisplayProperty, false)) { - ALOGI("External display connected. Switching to external display."); - target_display_ = &(*external_display_); - target_display_changed = true; - } else { - ALOGI("External display connected, but sysprop %s is unset, so" - " using primary display.", kUseExternalDisplayProperty); - if (was_using_external_display) { - target_display_ = &primary_display_; - target_display_changed = true; - } - } + ALOGI("External display connected. Switching to external display."); + target_display_ = &(*external_display_); + target_display_changed = true; } else { // External display was disconnected external_display_ = std::nullopt; -- GitLab From 94e91f62bb251bc08864e1aa5f0e9e30908ba35d Mon Sep 17 00:00:00 2001 From: mamik Date: Mon, 19 Aug 2019 09:11:33 -0700 Subject: [PATCH 0217/1255] Rev up vr_hwc to composer@2.3 Fix for issue: "[GSI XR] VrFlinger doesn't work on GSI/MTP845." The flow that causes the issue is: SurfaceFlinger gets an hotplug event and adds a display id of the internal display (For instance, display id of 19260371107735809). This display id gets added to the HWComposer through the hotplug event. When updateVrFlinger() is eventually called in SurfaceFlinger, a new HWComposer is created which has no display ids being tracked in HWComposer. Another hotplug event starts from vr_hwc.cpp, which has a display id of 0. SurfaceFlinger receives this hot plug event so SurfaceFlinger has an display ids of [19260371107735809, 0]. HWComposer only has display id 0. Next processDisplayChangesLocked() is called in SurfaceFlinger and a new FramebufferSurface is created with display id 19260371107735809. In the FramebufferSurface it tries to call getActiveConfig() in HWComposer with the display id of 19260371107735809, which HWComposer does not know about. This results in a crash. The display id is created from the edid data and display port. The fix is to have the vr_hwc return the same edid data and display port as the internal display. This will make the display id originating from vr_hwc be the same as the internal display id. SurfaceFlinger will now only have the display id of 19260371107735809, since it does not overwrite the same display id on the hotplug events. HWComposer will only have display id of 19260371107735809. The SurfaceFlinger and HwComposer display ids match the code works correctly now. This is accomplished by creating a version 2.0 of the vr_composer_client and having vr_hwc inherit from version 2.3 instead of version 2.1 of the composer hal. These changes are required to be able to pass through the edid data. The display port and edid data is retrieved by vr_hwc via the display_client. The other required changes needed for this to work is: ag/9215156 ag/9226524 Bug: 137325030 Bug: 138938154 Bug: 137448042 Test: manual - ran through modified unit test to make sure the edid data was returned on the MTP 845. Change-Id: I1c54e6cfda348260cf1013d6dca0dda58acb3b3c --- libs/vr/libdisplay/display_client.cpp | 4 + .../include/private/dvr/display_client.h | 1 + .../include/private/dvr/display_protocol.h | 3 + libs/vr/libvrflinger/Android.bp | 2 +- libs/vr/libvrflinger/display_service.cpp | 13 +- libs/vr/libvrflinger/display_service.h | 2 + services/surfaceflinger/Android.bp | 21 +- .../CompositionEngine/Android.bp | 2 +- .../DisplayHardware/ComposerHal.cpp | 44 ++- .../DisplayHardware/ComposerHal.h | 16 +- services/vr/hardware_composer/Android.bp | 16 +- .../impl/vr_composer_client.cpp | 22 +- .../impl/vr_composer_client.h | 15 +- services/vr/hardware_composer/impl/vr_hwc.cpp | 296 +++++++++++++----- services/vr/hardware_composer/impl/vr_hwc.h | 173 +++++++--- 15 files changed, 456 insertions(+), 174 deletions(-) diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp index f67e258cee..62856dfbf8 100644 --- a/libs/vr/libdisplay/display_client.cpp +++ b/libs/vr/libdisplay/display_client.cpp @@ -178,6 +178,10 @@ Status DisplayClient::GetConfigurationData( return status; } +Status DisplayClient::GetDisplayIdentificationPort() { + return InvokeRemoteMethod(); +} + Status> DisplayClient::CreateSurface( const SurfaceAttributes& attributes) { int error; diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h index f8f5b3ddb3..81546ac5c2 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_client.h +++ b/libs/vr/libdisplay/include/private/dvr/display_client.h @@ -72,6 +72,7 @@ class DisplayClient : public pdx::ClientBase { public: pdx::Status GetDisplayMetrics(); pdx::Status GetConfigurationData(ConfigFileType config_type); + pdx::Status GetDisplayIdentificationPort(); pdx::Status> SetupGlobalBuffer( DvrGlobalBufferKey key, size_t size, uint64_t usage); pdx::Status DeleteGlobalBuffer(DvrGlobalBufferKey key); diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h index 861dc6c2a0..9f4cc4afcc 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h +++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h @@ -211,6 +211,7 @@ struct DisplayProtocol { kOpGetSurfaceInfo, kOpCreateQueue, kOpSetAttributes, + kOpGetDisplayIdentificationPort, }; // Aliases. @@ -221,6 +222,8 @@ struct DisplayProtocol { PDX_REMOTE_METHOD(GetMetrics, kOpGetMetrics, Metrics(Void)); PDX_REMOTE_METHOD(GetConfigurationData, kOpGetConfigurationData, std::string(ConfigFileType config_type)); + PDX_REMOTE_METHOD(GetDisplayIdentificationPort, + kOpGetDisplayIdentificationPort, uint8_t(Void)); PDX_REMOTE_METHOD(SetupGlobalBuffer, kOpSetupGlobalBuffer, LocalNativeBufferHandle(DvrGlobalBufferKey key, size_t size, uint64_t usage)); diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp index 282935307c..444167227c 100644 --- a/libs/vr/libvrflinger/Android.bp +++ b/libs/vr/libvrflinger/Android.bp @@ -35,7 +35,7 @@ staticLibraries = [ ] sharedLibraries = [ - "android.frameworks.vr.composer@1.0", + "android.frameworks.vr.composer@2.0", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.2", diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index 8980a92776..5a9360c2ae 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -47,7 +47,8 @@ DisplayService::DisplayService(Hwc2::Composer* hidl, uint8_t port; const auto error = hidl->getDisplayIdentificationData( - primary_display_id, &port, &display_identification_data_); + primary_display_id, &display_identification_port_, + &display_identification_data_); if (error != android::hardware::graphics::composer::V2_1::Error::NONE) { if (error != android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) { @@ -151,6 +152,11 @@ Status DisplayService::HandleMessage(pdx::Message& message) { *this, &DisplayService::OnGetConfigurationData, message); return {}; + case DisplayProtocol::GetDisplayIdentificationPort::Opcode: + DispatchRemoteMethod( + *this, &DisplayService::OnGetDisplayIdentificationPort, message); + return {}; + case DisplayProtocol::CreateSurface::Opcode: DispatchRemoteMethod( *this, &DisplayService::OnCreateSurface, message); @@ -238,6 +244,11 @@ pdx::Status DisplayService::OnGetConfigurationData( return std::move(data); } +pdx::Status DisplayService::OnGetDisplayIdentificationPort( + pdx::Message& /*message*/) { + return display_identification_port_; +} + // Creates a new DisplaySurface and associates it with this channel. This may // only be done once per channel. Status DisplayService::OnCreateSurface( diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index d45a61fad7..06ba566d32 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -82,6 +82,7 @@ class DisplayService : public pdx::ServiceBase { pdx::Status OnGetMetrics(pdx::Message& message); pdx::Status OnGetConfigurationData( pdx::Message& message, display::ConfigFileType config_type); + pdx::Status OnGetDisplayIdentificationPort(pdx::Message& message); pdx::Status OnCreateSurface( pdx::Message& message, const display::SurfaceAttributes& attributes); pdx::Status OnSetupGlobalBuffer( @@ -121,6 +122,7 @@ class DisplayService : public pdx::ServiceBase { void operator=(const DisplayService&) = delete; DisplayIdentificationData display_identification_data_; + uint8_t display_identification_port_; }; } // namespace dvr diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index afb9cec4cc..97b7697485 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -19,7 +19,7 @@ cc_defaults { "-DEGL_EGLEXT_PROTOTYPES", ], shared_libs: [ - "android.frameworks.vr.composer@1.0", + "android.frameworks.vr.composer@2.0", "android.hardware.configstore-utils", "android.hardware.configstore@1.0", "android.hardware.configstore@1.1", @@ -58,6 +58,14 @@ cc_defaults { "libutils", "libSurfaceFlingerProp", ], + // VrComposer is not used when building surfaceflinger for vendors + target: { + vendor: { + exclude_shared_libs: [ + "android.frameworks.vr.composer@2.0", + ], + }, + }, static_libs: [ "libcompositionengine", "librenderengine", @@ -177,6 +185,17 @@ cc_library_shared { // can be easily replaced. "SurfaceFlingerFactory.cpp", ], + cflags: [ + "-DUSE_VR_COMPOSER=1", + ], + // VrComposer is not used when building surfaceflinger for vendors + target: { + vendor: { + cflags: [ + "-DUSE_VR_COMPOSER=0", + ], + }, + }, logtags: ["EventLog/EventLogTags.logtags"], } diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index ae6bdbce60..d2e95d05a1 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -5,7 +5,7 @@ cc_defaults { "-DLOG_TAG=\"CompositionEngine\"", ], shared_libs: [ - "android.frameworks.vr.composer@1.0", + "android.frameworks.vr.composer@2.0", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.2", diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index 7f47a2ecd4..e53d09949c 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -110,6 +110,7 @@ Error unwrapRet(Return& ret) namespace impl { +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER Composer::CommandWriter::CommandWriter(uint32_t initialMaxSize) : CommandWriterBase(initialMaxSize) {} @@ -160,6 +161,7 @@ void Composer::CommandWriter::writeBufferMetadata( writeSigned(static_cast(metadata.format)); write64(metadata.usage); } +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER Composer::Composer(const std::string& serviceName) : mWriter(kWriterInitialSize), @@ -198,12 +200,14 @@ Composer::Composer(const std::string& serviceName) LOG_ALWAYS_FATAL("failed to create composer client"); } +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER if (mIsUsingVrComposer) { sp vrClient = IVrComposerClient::castFrom(mClient); if (vrClient == nullptr) { LOG_ALWAYS_FATAL("failed to create vr composer client"); } } +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER } Composer::~Composer() = default; @@ -565,17 +569,20 @@ Error Composer::setClientTarget(Display display, uint32_t slot, const std::vector& damage) { mWriter.selectDisplay(display); + +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER if (mIsUsingVrComposer && target.get()) { IVrComposerClient::BufferMetadata metadata = { - .width = target->getWidth(), - .height = target->getHeight(), - .stride = target->getStride(), - .layerCount = target->getLayerCount(), - .format = static_cast(target->getPixelFormat()), - .usage = target->getUsage(), + .width = target->getWidth(), + .height = target->getHeight(), + .stride = target->getStride(), + .layerCount = target->getLayerCount(), + .format = static_cast(target->getPixelFormat()), + .usage = target->getUsage(), }; mWriter.setClientTargetMetadata(metadata); } +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER const native_handle_t* handle = nullptr; if (target.get()) { @@ -695,17 +702,20 @@ Error Composer::setLayerBuffer(Display display, Layer layer, { mWriter.selectDisplay(display); mWriter.selectLayer(layer); + +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER if (mIsUsingVrComposer && buffer.get()) { IVrComposerClient::BufferMetadata metadata = { - .width = buffer->getWidth(), - .height = buffer->getHeight(), - .stride = buffer->getStride(), - .layerCount = buffer->getLayerCount(), - .format = static_cast(buffer->getPixelFormat()), - .usage = buffer->getUsage(), + .width = buffer->getWidth(), + .height = buffer->getHeight(), + .stride = buffer->getStride(), + .layerCount = buffer->getLayerCount(), + .format = static_cast(buffer->getPixelFormat()), + .usage = buffer->getUsage(), }; mWriter.setLayerBufferMetadata(metadata); } +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER const native_handle_t* handle = nullptr; if (buffer.get()) { @@ -823,6 +833,7 @@ Error Composer::setLayerZOrder(Display display, Layer layer, uint32_t z) return Error::NONE; } +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER Error Composer::setLayerInfo(Display display, Layer layer, uint32_t type, uint32_t appId) { @@ -833,6 +844,15 @@ Error Composer::setLayerInfo(Display display, Layer layer, uint32_t type, } return Error::NONE; } +#else +Error Composer::setLayerInfo(Display display, Layer layer, uint32_t, uint32_t) { + if (mIsUsingVrComposer) { + mWriter.selectDisplay(display); + mWriter.selectLayer(layer); + } + return Error::NONE; +} +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER Error Composer::execute() { diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index c4e952b8d9..9f6cac22b7 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -23,7 +23,9 @@ #include #include -#include +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER +#include +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER #include #include #include @@ -38,7 +40,9 @@ namespace android { namespace Hwc2 { -using frameworks::vr::composer::V1_0::IVrComposerClient; +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER +using frameworks::vr::composer::V2_0::IVrComposerClient; +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER namespace types = hardware::graphics::common; @@ -418,6 +422,7 @@ public: Error setDisplayBrightness(Display display, float brightness) override; private: +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER class CommandWriter : public CommandWriterBase { public: explicit CommandWriter(uint32_t initialMaxSize); @@ -433,6 +438,13 @@ private: void writeBufferMetadata( const IVrComposerClient::BufferMetadata& metadata); }; +#else + class CommandWriter : public CommandWriterBase { + public: + explicit CommandWriter(uint32_t initialMaxSize) : CommandWriterBase(initialMaxSize) {} + ~CommandWriter() override {} + }; +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER // Many public functions above simply write a command into the command // queue to batch the calls. validateDisplay and presentDisplay will call diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp index bc7cc1c409..2cfeda3760 100644 --- a/services/vr/hardware_composer/Android.bp +++ b/services/vr/hardware_composer/Android.bp @@ -12,8 +12,10 @@ cc_library_shared { ], shared_libs: [ - "android.frameworks.vr.composer@1.0", + "android.frameworks.vr.composer@2.0", "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.1-resources", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", @@ -34,11 +36,11 @@ cc_library_shared { header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", - "android.hardware.graphics.composer@2.1-hal", + "android.hardware.graphics.composer@2.3-hal", ], export_header_lib_headers: [ - "android.hardware.graphics.composer@2.1-hal", + "android.hardware.graphics.composer@2.3-hal", ], export_static_lib_headers: [ @@ -46,8 +48,10 @@ cc_library_shared { ], export_shared_lib_headers: [ - "android.frameworks.vr.composer@1.0", + "android.frameworks.vr.composer@2.0", "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.3", ], export_include_dirs: ["."], @@ -104,8 +108,8 @@ cc_binary { "libvr_hwc-binder", ], shared_libs: [ - "android.frameworks.vr.composer@1.0", - "android.hardware.graphics.composer@2.1", + "android.frameworks.vr.composer@2.0", + "android.hardware.graphics.composer@2.3", "libbase", "libbinder", "liblog", diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp index 786d5fac98..36f6b32e3f 100644 --- a/services/vr/hardware_composer/impl/vr_composer_client.cpp +++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include #include #include @@ -27,8 +27,7 @@ namespace android { namespace dvr { -using android::hardware::graphics::common::V1_0::PixelFormat; -using android::frameworks::vr::composer::V1_0::IVrComposerClient; +using android::frameworks::vr::composer::V2_0::IVrComposerClient; VrComposerClient::VrComposerClient(dvr::VrHwc& hal) : ComposerClient(&hal), mVrHal(hal) { @@ -51,7 +50,8 @@ VrComposerClient::VrCommandEngine::VrCommandEngine(VrComposerClient& client) VrComposerClient::VrCommandEngine::~VrCommandEngine() {} bool VrComposerClient::VrCommandEngine::executeCommand( - IComposerClient::Command command, uint16_t length) { + hardware::graphics::composer::V2_1::IComposerClient::Command command, + uint16_t length) { IVrComposerClient::VrCommand vrCommand = static_cast(command); switch (vrCommand) { @@ -107,12 +107,14 @@ bool VrComposerClient::VrCommandEngine::executeSetLayerBufferMetadata( IVrComposerClient::BufferMetadata VrComposerClient::VrCommandEngine::readBufferMetadata() { IVrComposerClient::BufferMetadata metadata = { - .width = read(), - .height = read(), - .stride = read(), - .layerCount = read(), - .format = static_cast(readSigned()), - .usage = read64(), + .width = read(), + .height = read(), + .stride = read(), + .layerCount = read(), + .format = + static_cast( + readSigned()), + .usage = read64(), }; return metadata; } diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h index 0b7ce5e665..1b2b5f4f56 100644 --- a/services/vr/hardware_composer/impl/vr_composer_client.h +++ b/services/vr/hardware_composer/impl/vr_composer_client.h @@ -17,10 +17,12 @@ #ifndef ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H #define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H -#include -#include +#include +#include #include #include +#include +#include namespace android { namespace dvr { @@ -28,8 +30,8 @@ namespace dvr { class VrHwc; using hardware::graphics::composer::V2_1::hal::ComposerCommandEngine; -using hardware::graphics::composer::V2_1::hal::ComposerHal; -using hardware::graphics::composer::V2_1::hal::detail::ComposerClientImpl; +using hardware::graphics::composer::V2_3::hal::ComposerHal; +using hardware::graphics::composer::V2_3::hal::detail::ComposerClientImpl; using ComposerClient = ComposerClientImpl; @@ -44,8 +46,9 @@ class VrComposerClient : public ComposerClient { explicit VrCommandEngine(VrComposerClient& client); ~VrCommandEngine() override; - bool executeCommand(IComposerClient::Command command, - uint16_t length) override; + bool executeCommand( + hardware::graphics::composer::V2_1::IComposerClient::Command command, + uint16_t length) override; private: bool executeSetLayerInfo(uint16_t length); diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp index 7323277248..e530b16b1b 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.cpp +++ b/services/vr/hardware_composer/impl/vr_hwc.cpp @@ -27,7 +27,7 @@ #include "vr_composer_client.h" using namespace android::hardware::graphics::common::V1_0; -using namespace android::hardware::graphics::composer::V2_1; +using namespace android::hardware::graphics::composer::V2_3; using android::base::StringPrintf; using android::hardware::hidl_handle; @@ -36,12 +36,12 @@ using android::hardware::hidl_vec; using android::hardware::Return; using android::hardware::Void; +namespace types = android::hardware::graphics::common; + namespace android { namespace dvr { namespace { -using android::hardware::graphics::common::V1_0::PixelFormat; - const Display kDefaultDisplayId = 1; const Config kDefaultConfigId = 1; @@ -269,7 +269,8 @@ void VrHwc::registerEventCallback(EventCallback* callback) { // onHotplug() call, so it's important to release mutex_ here. lock.unlock(); event_callback_->onHotplug(kDefaultDisplayId, - IComposerCallback::Connection::CONNECTED); + hardware::graphics::composer::V2_1:: + IComposerCallback::Connection::CONNECTED); lock.lock(); UpdateVsyncCallbackEnabledLocked(); } @@ -282,15 +283,6 @@ void VrHwc::unregisterEventCallback() { uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; } -Error VrHwc::createVirtualDisplay(uint32_t width, uint32_t height, - PixelFormat* format, Display* outDisplay) { - *format = PixelFormat::RGBA_8888; - *outDisplay = display_count_; - displays_[display_count_].reset(new HwcDisplay(width, height)); - display_count_++; - return Error::NONE; -} - Error VrHwc::destroyVirtualDisplay(Display display) { std::lock_guard guard(mutex_); if (display == kDefaultDisplayId || displays_.erase(display) == 0) @@ -332,24 +324,6 @@ Error VrHwc::getActiveConfig(Display display, Config* outConfig) { return Error::NONE; } -Error VrHwc::getClientTargetSupport(Display display, uint32_t /* width */, - uint32_t /* height */, - PixelFormat /* format */, - Dataspace /* dataspace */) { - std::lock_guard guard(mutex_); - if (!FindDisplay(display)) - return Error::BAD_DISPLAY; - - return Error::NONE; -} - -Error VrHwc::getColorModes(Display /* display */, - hidl_vec* outModes) { - std::vector color_modes(1, ColorMode::NATIVE); - *outModes = hidl_vec(color_modes); - return Error::NONE; -} - Error VrHwc::getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) { @@ -441,17 +415,6 @@ Error VrHwc::getDozeSupport(Display display, bool* outSupport) { return Error::NONE; } -Error VrHwc::getHdrCapabilities(Display /* display */, - hidl_vec* /* outTypes */, - float* outMaxLuminance, - float* outMaxAverageLuminance, - float* outMinLuminance) { - *outMaxLuminance = 0; - *outMaxAverageLuminance = 0; - *outMinLuminance = 0; - return Error::NONE; -} - Error VrHwc::setActiveConfig(Display display, Config config) { std::lock_guard guard(mutex_); auto display_ptr = FindDisplay(display); @@ -464,47 +427,6 @@ Error VrHwc::setActiveConfig(Display display, Config config) { return Error::NONE; } -Error VrHwc::setColorMode(Display display, ColorMode mode) { - std::lock_guard guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3) - return Error::BAD_PARAMETER; - - display_ptr->set_color_mode(mode); - return Error::NONE; -} - -Error VrHwc::setPowerMode(Display display, IComposerClient::PowerMode mode) { - bool dozeSupported = false; - - Error dozeSupportError = getDozeSupport(display, &dozeSupported); - - if (dozeSupportError != Error::NONE) - return dozeSupportError; - - std::lock_guard guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - if (mode < IComposerClient::PowerMode::OFF || - mode > IComposerClient::PowerMode::DOZE_SUSPEND) { - return Error::BAD_PARAMETER; - } - - if (!dozeSupported && - (mode == IComposerClient::PowerMode::DOZE || - mode == IComposerClient::PowerMode::DOZE_SUSPEND)) { - return Error::UNSUPPORTED; - } - - display_ptr->set_power_mode(mode); - return Error::NONE; -} - Error VrHwc::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) { std::lock_guard guard(mutex_); auto display_ptr = FindDisplay(display); @@ -956,6 +878,23 @@ Return VrHwc::createClient(createClient_cb hidl_cb) { return Void(); } +Return VrHwc::createClient_2_3(IComposer::createClient_2_3_cb hidl_cb) { + std::lock_guard guard(mutex_); + + Error status = Error::NONE; + sp client; + if (!client_.promote().get()) { + client = new VrComposerClient(*this); + } else { + ALOGE("Already have a client"); + status = Error::NO_RESOURCES; + } + + client_ = client; + hidl_cb(status, client); + return Void(); +} + void VrHwc::ForceDisplaysRefresh() { std::lock_guard guard(mutex_); if (event_callback_ != nullptr) { @@ -1044,5 +983,196 @@ void VrHwc::VsyncCallback::SetEventCallback(EventCallback* callback) { callback_ = callback; } +// composer::V2_2::ComposerHal +Error VrHwc::setReadbackBuffer(Display display, + const native_handle_t* bufferHandle, + android::base::unique_fd fenceFd) { + return Error::NONE; +} + +Error VrHwc::getReadbackBufferFence(Display display, + android::base::unique_fd* outFenceFd) { + return Error::NONE; +} + +Error VrHwc::createVirtualDisplay_2_2(uint32_t width, uint32_t height, + types::V1_1::PixelFormat* format, + Display* outDisplay) { + *format = types::V1_1::PixelFormat::RGBA_8888; + *outDisplay = display_count_; + displays_[display_count_].reset(new HwcDisplay(width, height)); + display_count_++; + return Error::NONE; +} + +Error VrHwc::setPowerMode_2_2(Display display, + IComposerClient::PowerMode mode) { + bool dozeSupported = false; + + Error dozeSupportError = getDozeSupport(display, &dozeSupported); + + if (dozeSupportError != Error::NONE) + return dozeSupportError; + + std::lock_guard guard(mutex_); + auto display_ptr = FindDisplay(display); + if (!display_ptr) + return Error::BAD_DISPLAY; + + if (mode < IComposerClient::PowerMode::OFF || + mode > IComposerClient::PowerMode::DOZE_SUSPEND) { + return Error::BAD_PARAMETER; + } + + if (!dozeSupported && (mode == IComposerClient::PowerMode::DOZE || + mode == IComposerClient::PowerMode::DOZE_SUSPEND)) { + return Error::UNSUPPORTED; + } + + display_ptr->set_power_mode(mode); + return Error::NONE; +} + +Error VrHwc::setLayerFloatColor(Display display, Layer layer, + IComposerClient::FloatColor color) { + return Error::NONE; +} + +Error VrHwc::getRenderIntents(Display display, types::V1_1::ColorMode mode, + std::vector* outIntents) { + return Error::NONE; +} + +std::array VrHwc::getDataspaceSaturationMatrix( + types::V1_1::Dataspace dataspace) { + return {}; +} + +// composer::V2_3::ComposerHal +Error VrHwc::getHdrCapabilities_2_3(Display /*display*/, + hidl_vec* /*outTypes*/, + float* outMaxLuminance, + float* outMaxAverageLuminance, + float* outMinLuminance) { + *outMaxLuminance = 0; + *outMaxAverageLuminance = 0; + *outMinLuminance = 0; + return Error::NONE; +} + +Error VrHwc::setLayerPerFrameMetadata_2_3( + Display display, Layer layer, + const std::vector& metadata) { + return Error::NONE; +} + +Error VrHwc::getPerFrameMetadataKeys_2_3( + Display display, + std::vector* outKeys) { + return Error::NONE; +} + +Error VrHwc::setColorMode_2_3(Display display, ColorMode mode, + RenderIntent intent) { + std::lock_guard guard(mutex_); + auto display_ptr = FindDisplay(display); + if (!display_ptr) + return Error::BAD_DISPLAY; + + if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3) + return Error::BAD_PARAMETER; + + display_ptr->set_color_mode(mode); + return Error::NONE; +} + +Error VrHwc::getRenderIntents_2_3(Display display, ColorMode mode, + std::vector* outIntents) { + return Error::NONE; +} + +Error VrHwc::getColorModes_2_3(Display display, hidl_vec* outModes) { + return Error::NONE; +} + +Error VrHwc::getClientTargetSupport_2_3(Display display, uint32_t width, + uint32_t height, PixelFormat format, + Dataspace dataspace) { + return Error::NONE; +} + +Error VrHwc::getReadbackBufferAttributes_2_3(Display display, + PixelFormat* outFormat, + Dataspace* outDataspace) { + return Error::NONE; +} + +Error VrHwc::getDisplayIdentificationData(Display display, uint8_t* outPort, + std::vector* outData) { + int error = 0; + auto display_client = display::DisplayClient::Create(&error); + if (!display_client) { + ALOGE("Could not connect to display service : %s(%d)", strerror(error), + error); + return Error::BAD_CONFIG; + } + auto edid_data = display_client->GetConfigurationData( + display::ConfigFileType::kDeviceEdid); + auto display_identification_port = + display_client->GetDisplayIdentificationPort(); + *outPort = display_identification_port.get(); + + std::copy(edid_data.get().begin(), edid_data.get().end(), + std::back_inserter(*outData)); + return Error::NONE; +} + +Error VrHwc::setLayerColorTransform(Display display, Layer layer, + const float* matrix) { + return Error::NONE; +} + +Error VrHwc::getDisplayedContentSamplingAttributes( + Display display, PixelFormat& format, Dataspace& dataspace, + hidl_bitfield& componentMask) { + return Error::NONE; +} + +Error VrHwc::setDisplayedContentSamplingEnabled( + Display display, IComposerClient::DisplayedContentSampling enable, + hidl_bitfield componentMask, + uint64_t maxFrames) { + return Error::NONE; +} + +Error VrHwc::getDisplayedContentSample(Display display, uint64_t maxFrames, + uint64_t timestamp, uint64_t& frameCount, + hidl_vec& sampleComponent0, + hidl_vec& sampleComponent1, + hidl_vec& sampleComponent2, + hidl_vec& sampleComponent3) { + return Error::NONE; +} + +Error VrHwc::getDisplayCapabilities( + Display display, + std::vector* outCapabilities) { + return Error::NONE; +} + +Error VrHwc::setLayerPerFrameMetadataBlobs( + Display display, Layer layer, + std::vector& blobs) { + return Error::NONE; +} + +Error VrHwc::getDisplayBrightnessSupport(Display display, bool* outSupport) { + return Error::NONE; +} + +Error VrHwc::setDisplayBrightness(Display display, float brightness) { + return Error::NONE; +} + } // namespace dvr } // namespace android diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h index 15358c57bb..3e3a6307fa 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.h +++ b/services/vr/hardware_composer/impl/vr_hwc.h @@ -17,9 +17,9 @@ #define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_HWC_H #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -28,15 +28,21 @@ #include #include -using namespace android::frameworks::vr::composer::V1_0; +using namespace android::frameworks::vr::composer::V2_0; using namespace android::hardware::graphics::common::V1_0; -using namespace android::hardware::graphics::composer::V2_1; +using namespace android::hardware::graphics::composer::V2_3; +using android::hardware::hidl_bitfield; using android::hardware::hidl_handle; using android::hardware::hidl_string; using android::hardware::hidl_vec; using android::hardware::Return; using android::hardware::Void; +using android::hardware::graphics::composer::V2_1::Config; +using android::hardware::graphics::composer::V2_1::Display; +using android::hardware::graphics::composer::V2_1::Error; +using android::hardware::graphics::composer::V2_1::Layer; +using android::hardware::graphics::composer::V2_3::IComposerClient; namespace android { @@ -46,16 +52,23 @@ namespace dvr { class VrComposerClient; -using android::hardware::graphics::common::V1_0::PixelFormat; -using android::hardware::graphics::composer::V2_1::hal::ComposerHal; +using android::hardware::graphics::composer::V2_3::hal::ComposerHal; + +namespace types = android::hardware::graphics::common; + +using types::V1_1::RenderIntent; +using types::V1_2::ColorMode; +using types::V1_2::Dataspace; +using types::V1_2::Hdr; +using types::V1_2::PixelFormat; class ComposerView { public: struct ComposerLayer { - using Recti = hardware::graphics::composer::V2_1::IComposerClient::Rect; - using Rectf = hardware::graphics::composer::V2_1::IComposerClient::FRect; + using Recti = hardware::graphics::composer::V2_3::IComposerClient::Rect; + using Rectf = hardware::graphics::composer::V2_3::IComposerClient::FRect; using BlendMode = - hardware::graphics::composer::V2_1::IComposerClient::BlendMode; + hardware::graphics::composer::V2_3::IComposerClient::BlendMode; Layer id; sp buffer; @@ -111,7 +124,7 @@ class ComposerView { struct HwcLayer { using Composition = - hardware::graphics::composer::V2_1::IComposerClient::Composition; + hardware::graphics::composer::V2_3::IComposerClient::Composition; explicit HwcLayer(Layer new_id) { info.id = new_id; } @@ -205,90 +218,148 @@ class VrHwc : public IComposer, public ComposerHal, public ComposerView { Display display, Layer layer, const IVrComposerClient::BufferMetadata& metadata); - // ComposerHal + // composer::V2_1::ComposerHal bool hasCapability(hwc2_capability_t capability) override; std::string dumpDebugInfo() override { return {}; } - void registerEventCallback(EventCallback* callback) override; + + void registerEventCallback(ComposerHal::EventCallback* callback) override; void unregisterEventCallback() override; uint32_t getMaxVirtualDisplayCount() override; - Error createVirtualDisplay(uint32_t width, uint32_t height, - PixelFormat* format, Display* outDisplay) override; Error destroyVirtualDisplay(Display display) override; Error createLayer(Display display, Layer* outLayer) override; Error destroyLayer(Display display, Layer layer) override; Error getActiveConfig(Display display, Config* outConfig) override; - Error getClientTargetSupport(Display display, - uint32_t width, uint32_t height, - PixelFormat format, Dataspace dataspace) override; - Error getColorModes(Display display, hidl_vec* outModes) override; Error getDisplayAttribute(Display display, Config config, - IComposerClient::Attribute attribute, int32_t* outValue) override; + IComposerClient::Attribute attribute, + int32_t* outValue) override; Error getDisplayConfigs(Display display, hidl_vec* outConfigs) override; Error getDisplayName(Display display, hidl_string* outName) override; Error getDisplayType(Display display, - IComposerClient::DisplayType* outType) override; + IComposerClient::DisplayType* outType) override; Error getDozeSupport(Display display, bool* outSupport) override; - Error getHdrCapabilities(Display display, hidl_vec* outTypes, - float* outMaxLuminance, float* outMaxAverageLuminance, - float* outMinLuminance) override; Error setActiveConfig(Display display, Config config) override; - Error setColorMode(Display display, ColorMode mode) override; - Error setPowerMode(Display display, IComposerClient::PowerMode mode) override; Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override; Error setColorTransform(Display display, const float* matrix, - int32_t hint) override; + int32_t hint) override; Error setClientTarget(Display display, buffer_handle_t target, - int32_t acquireFence, int32_t dataspace, - const std::vector& damage) override; + int32_t acquireFence, int32_t dataspace, + const std::vector& damage) override; Error setOutputBuffer(Display display, buffer_handle_t buffer, - int32_t releaseFence) override; - Error validateDisplay(Display display, - std::vector* outChangedLayers, - std::vector* outCompositionTypes, - uint32_t* outDisplayRequestMask, - std::vector* outRequestedLayers, - std::vector* outRequestMasks) override; + int32_t releaseFence) override; + Error validateDisplay( + Display display, std::vector* outChangedLayers, + std::vector* outCompositionTypes, + uint32_t* outDisplayRequestMask, std::vector* outRequestedLayers, + std::vector* outRequestMasks) override; Error acceptDisplayChanges(Display display) override; Error presentDisplay(Display display, int32_t* outPresentFence, - std::vector* outLayers, - std::vector* outReleaseFences) override; + std::vector* outLayers, + std::vector* outReleaseFences) override; - Error setLayerCursorPosition(Display display, Layer layer, - int32_t x, int32_t y) override; - Error setLayerBuffer(Display display, Layer layer, - buffer_handle_t buffer, int32_t acquireFence) override; + Error setLayerCursorPosition(Display display, Layer layer, int32_t x, + int32_t y) override; + Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer, + int32_t acquireFence) override; Error setLayerSurfaceDamage(Display display, Layer layer, - const std::vector& damage) override; + const std::vector& damage) override; Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override; Error setLayerColor(Display display, Layer layer, - IComposerClient::Color color) override; + IComposerClient::Color color) override; Error setLayerCompositionType(Display display, Layer layer, - int32_t type) override; + int32_t type) override; Error setLayerDataspace(Display display, Layer layer, - int32_t dataspace) override; + int32_t dataspace) override; Error setLayerDisplayFrame(Display display, Layer layer, - const hwc_rect_t& frame) override; + const hwc_rect_t& frame) override; Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override; Error setLayerSidebandStream(Display display, Layer layer, - buffer_handle_t stream) override; + buffer_handle_t stream) override; Error setLayerSourceCrop(Display display, Layer layer, - const hwc_frect_t& crop) override; + const hwc_frect_t& crop) override; Error setLayerTransform(Display display, Layer layer, - int32_t transform) override; + int32_t transform) override; Error setLayerVisibleRegion(Display display, Layer layer, - const std::vector& visible) override; + const std::vector& visible) override; Error setLayerZOrder(Display display, Layer layer, uint32_t z) override; + // composer::V2_2::ComposerHal + Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle, + android::base::unique_fd fenceFd) override; + Error getReadbackBufferFence(Display display, + android::base::unique_fd* outFenceFd) override; + Error createVirtualDisplay_2_2(uint32_t width, uint32_t height, + types::V1_1::PixelFormat* format, + Display* outDisplay) override; + Error setPowerMode_2_2(Display display, + IComposerClient::PowerMode mode) override; + Error setLayerFloatColor(Display display, Layer layer, + IComposerClient::FloatColor color) override; + Error getRenderIntents(Display display, types::V1_1::ColorMode mode, + std::vector* outIntents) override; + std::array getDataspaceSaturationMatrix( + types::V1_1::Dataspace dataspace) override; + + // composer::V2_3::ComposerHal + Error getHdrCapabilities_2_3(Display display, hidl_vec* outTypes, + float* outMaxLuminance, + float* outMaxAverageLuminance, + float* outMinLuminance) override; + Error setLayerPerFrameMetadata_2_3( + Display display, Layer layer, + const std::vector& metadata) override; + Error getPerFrameMetadataKeys_2_3( + Display display, + std::vector* outKeys) override; + Error setColorMode_2_3(Display display, ColorMode mode, + RenderIntent intent) override; + Error getRenderIntents_2_3(Display display, ColorMode mode, + std::vector* outIntents) override; + Error getColorModes_2_3(Display display, + hidl_vec* outModes) override; + Error getClientTargetSupport_2_3(Display display, uint32_t width, + uint32_t height, PixelFormat format, + Dataspace dataspace) override; + Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat, + Dataspace* outDataspace) override; + Error getDisplayIdentificationData(Display display, uint8_t* outPort, + std::vector* outData) override; + Error setLayerColorTransform(Display display, Layer layer, + const float* matrix) override; + Error getDisplayedContentSamplingAttributes( + Display display, PixelFormat& format, Dataspace& dataspace, + hidl_bitfield& componentMask) + override; + Error setDisplayedContentSamplingEnabled( + Display display, IComposerClient::DisplayedContentSampling enable, + hidl_bitfield componentMask, + uint64_t maxFrames) override; + Error getDisplayedContentSample( + Display display, uint64_t maxFrames, uint64_t timestamp, + uint64_t& frameCount, hidl_vec& sampleComponent0, + hidl_vec& sampleComponent1, + hidl_vec& sampleComponent2, + hidl_vec& sampleComponent3) override; + Error getDisplayCapabilities(Display display, + std::vector* + outCapabilities) override; + Error setLayerPerFrameMetadataBlobs( + Display display, Layer layer, + std::vector& blobs) override; + Error getDisplayBrightnessSupport(Display display, bool* outSupport) override; + Error setDisplayBrightness(Display display, float brightness) override; + // IComposer: Return getCapabilities(getCapabilities_cb hidl_cb) override; Return dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override; Return createClient(createClient_cb hidl_cb) override; + Return createClient_2_3( + IComposer::createClient_2_3_cb hidl_cb) override; // ComposerView: void ForceDisplaysRefresh() override; -- GitLab From b524c931d361d908278a18480878a8b6c4d36cd8 Mon Sep 17 00:00:00 2001 From: Anders Frostad Pedersen Date: Sat, 31 Aug 2019 00:47:20 +0200 Subject: [PATCH 0218/1255] eglSwapBuffersWithDamageKHR robustness Add some additional checking for negative and NULL rects. Bug: 140252008 Change-Id: I932d5115c2c8da5d824e414c807f59a4a1a73e5b Test: Manual (cherry picked from commit b7dc63f26208097f52456e22fe40baa540e37edc) --- opengl/libs/EGL/egl_platform_entries.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index e996be6853..d1b4a4ec33 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -1379,6 +1379,9 @@ EGLBoolean eglSwapBuffersWithDamageKHRImpl(EGLDisplay dpy, EGLSurface draw, if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + if (n_rects < 0 || (n_rects > 0 && rects == NULL)) + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + egl_surface_t* const s = get_surface(draw); if (CC_UNLIKELY(dp->traceGpuCompletion)) { -- GitLab From b15ea8a9b506650b44c8ac21b640114e95ec2cef Mon Sep 17 00:00:00 2001 From: chaviw Date: Tue, 3 Sep 2019 12:40:22 -0700 Subject: [PATCH 0219/1255] Use getLayerStack() instead of layerStack for input info When there's no displayId, the layerStack should be used. The current code was using mDrawingState.layerStack which is incorrect because only the layerStack for the root of the tree is correct. Instead, use getLayerStack() which traverses the hierarchy to find the root's layerStack. Test: Uses correct layerStack instead of 0 for input with unset displayIds Change-Id: Ic8a06c562e970b0f328c539edfa51e206734934f --- services/surfaceflinger/Layer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5121835cae..964bc1d02a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1946,7 +1946,7 @@ InputWindowInfo Layer::fillInputInfo() { InputWindowInfo info = mDrawingState.inputInfo; if (info.displayId == ADISPLAY_ID_NONE) { - info.displayId = mDrawingState.layerStack; + info.displayId = getLayerStack(); } ui::Transform t = getTransform(); -- GitLab From 480f445ebbff57f0e81be2eeb0d513ae3d60b667 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 10 Jul 2019 16:18:48 -0700 Subject: [PATCH 0220/1255] SurfaceFlinger: store fps instead of duration in LayerInfo To get a better average of the content fps, we switch to store the momentarily fps rate instead of the refresh duration. For example: Frame#0 at 0ms Frame#1 at 100ms Frame#2 at 111ms Frame#3 at 122ms Average based on duration is AVERAGE(100, 11, 11) = 40.6ms (25fps) Average based on fps is AVERAGE(10, 90, 90) = 63fps Test: app launch Bug: 136558136 Change-Id: Icab848dd1f312498590f9735b8881ecdf0d24113 (cherry picked from commit 187d2d812711188df2fc649e276f7cb6d0fb81e4) Merged-In: Icab848dd1f312498590f9735b8881ecdf0d24113 --- services/surfaceflinger/Scheduler/LayerInfo.cpp | 3 ++- services/surfaceflinger/Scheduler/LayerInfo.h | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 95d7d31564..49194f9de5 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -43,7 +43,8 @@ void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime) { // Ignore time diff that are too high - those are stale values if (timeDiff > TIME_EPSILON_NS.count()) return; const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration; - mRefreshRateHistory.insertRefreshRate(refreshDuration); + const int fps = 1e9f / refreshDuration; + mRefreshRateHistory.insertRefreshRate(fps); } } // namespace scheduler diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 02b6aefa2b..f08fa939a6 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -46,7 +46,7 @@ class LayerInfo { public: explicit RefreshRateHistory(nsecs_t minRefreshDuration) : mMinRefreshDuration(minRefreshDuration) {} - void insertRefreshRate(nsecs_t refreshRate) { + void insertRefreshRate(int refreshRate) { mElements.push_back(refreshRate); if (mElements.size() > HISTORY_SIZE) { mElements.pop_front(); @@ -54,13 +54,13 @@ class LayerInfo { } float getRefreshRateAvg() const { - nsecs_t refreshDuration = mMinRefreshDuration; - if (mElements.size() == HISTORY_SIZE) { - refreshDuration = scheduler::calculate_mean(mElements); + if (mElements.empty()) { + return 1e9f / mMinRefreshDuration; } - return 1e9f / refreshDuration; + return scheduler::calculate_mean(mElements); } + void clearHistory() { mElements.clear(); } private: -- GitLab From 7849f2a0fedc49f5d6399715c349fed22b4f2655 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 28 May 2019 18:07:44 -0700 Subject: [PATCH 0221/1255] SurfaceFlinger: set refresh rate type when after an attempt to switch When a refresh rate change is starting we change the offsets to the new refresh rate to have a better alignment between buffers and the actual vsync. This change guarantees that we set the correct offset by updating PhaseOffset after desired config changed. Test: Let device go to 60Hz due to idle; Open an app; Get systrace; repeat Bug: 133241520 Change-Id: Id25f5e7d3d280813a106fd311906767d79e4e6ee (cherry picked from commit 53852a5c891ea82b85391eec145c2ac9c2aaed23) Merged-In: Id25f5e7d3d280813a106fd311906767d79e4e6ee --- services/surfaceflinger/SurfaceFlinger.cpp | 41 +++++++++------------- services/surfaceflinger/SurfaceFlinger.h | 4 ++- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 853763cd46..6ca49e4e95 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -940,12 +940,9 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { // Start receiving vsync samples now, so that we can detect a period // switch. mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); - // We should only move to early offsets when we know that the refresh - // rate will change. Otherwise, we may be stuck in early offsets - // forever, as onRefreshRateChangeDetected will not be called. - if (mDesiredActiveConfig.event == Scheduler::ConfigEvent::Changed) { - mVsyncModulator.onRefreshRateChangeInitiated(); - } + // As we called to set period, we will call to onRefreshRateChangeCompleted once + // DispSync model is locked. + mVsyncModulator.onRefreshRateChangeInitiated(); mPhaseOffsets->setRefreshRateType(info.type); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); mVsyncModulator.setPhaseOffsets(early, gl, late); @@ -980,7 +977,6 @@ void SurfaceFlinger::setActiveConfigInternal() { display->setActiveConfig(mUpcomingActiveConfig.configId); - mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); mVsyncModulator.setPhaseOffsets(early, gl, late); @@ -992,6 +988,18 @@ void SurfaceFlinger::setActiveConfigInternal() { } } +void SurfaceFlinger::desiredActiveConfigChangeDone() { + std::lock_guard lock(mActiveConfigLock); + mDesiredActiveConfig.event = Scheduler::ConfigEvent::None; + mDesiredActiveConfigChanged = false; + ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); + + mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); + mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); + const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); + mVsyncModulator.setPhaseOffsets(early, gl, late); +} + bool SurfaceFlinger::performSetActiveConfig() { ATRACE_CALL(); if (mCheckPendingFence) { @@ -1021,14 +1029,7 @@ bool SurfaceFlinger::performSetActiveConfig() { if (!display || display->getActiveConfig() == desiredActiveConfig.configId) { // display is not valid or we are already in the requested mode // on both cases there is nothing left to do - std::lock_guard lock(mActiveConfigLock); - mDesiredActiveConfig.event = Scheduler::ConfigEvent::None; - mDesiredActiveConfigChanged = false; - // Update scheduler with the correct vsync period as a no-op. - // Otherwise, there exists a race condition where we get stuck in the - // incorrect vsync period. - mScheduler->resyncToHardwareVsync(false, getVsyncPeriod()); - ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); + desiredActiveConfigChangeDone(); return false; } @@ -1036,15 +1037,7 @@ bool SurfaceFlinger::performSetActiveConfig() { // allowed configs might have change by the time we process the refresh. // Make sure the desired config is still allowed if (!isDisplayConfigAllowed(desiredActiveConfig.configId)) { - std::lock_guard lock(mActiveConfigLock); - mDesiredActiveConfig.event = Scheduler::ConfigEvent::None; - mDesiredActiveConfig.configId = display->getActiveConfig(); - mDesiredActiveConfigChanged = false; - // Update scheduler with the current vsync period as a no-op. - // Otherwise, there exists a race condition where we get stuck in the - // incorrect vsync period. - mScheduler->resyncToHardwareVsync(false, getVsyncPeriod()); - ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); + desiredActiveConfigChangeDone(); return false; } mUpcomingActiveConfig = desiredActiveConfig; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c09998d32e..6627f14b33 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -518,13 +518,15 @@ private: // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig. void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock); // Once HWC has returned the present fence, this sets the active config and a new refresh - // rate in SF. It also triggers HWC vsync. + // rate in SF. void setActiveConfigInternal() REQUIRES(mStateLock); // Active config is updated on INVALIDATE call in a state machine-like manner. When the // desired config was set, HWC needs to update the panel on the next refresh, and when // we receive the fence back, we know that the process was complete. It returns whether // we need to wait for the next invalidate bool performSetActiveConfig() REQUIRES(mStateLock); + // Called when active config is no longer is progress + void desiredActiveConfigChangeDone() REQUIRES(mStateLock); // called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp& display, int mode) REQUIRES(mStateLock); -- GitLab From b0006974a9038b47774b1b1191f7eb4d1648cf23 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 11 Jun 2019 10:52:26 -0700 Subject: [PATCH 0222/1255] SurfaceFlinger: always turn HWVsync off when display is off Maintain a state in SF about what is the latest HWVsync state in HWC and what it should be. Apply the desired state when screen turns on and always disabled HWVsync when the display is off. Test: display power on/off Bug: 134965007 Change-Id: I9c23d09ea2e32efa0b1f30a3999a08d15d7f35a6 (cherry picked from commit 27c702123056398d0509a8a61b5999d6a222f973) Merged-In: I9c23d09ea2e32efa0b1f30a3999a08d15d7f35a6 --- services/surfaceflinger/SurfaceFlinger.cpp | 24 +++++++++++++--------- services/surfaceflinger/SurfaceFlinger.h | 6 ++++-- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6ca49e4e95..b67260c3b6 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1546,14 +1546,12 @@ void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) { void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) { ATRACE_CALL(); + mHWCVsyncPendingState = enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable; + if (const auto displayId = getInternalDisplayIdLocked()) { sp display = getDefaultDisplayDeviceLocked(); if (display && display->isPoweredOn()) { - getHwComposer().setVsyncEnabled(*displayId, - enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable); - } else { - // Cache the latest vsync state and apply it when screen is on again - mEnableHWVsyncScreenOn = enabled; + setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState); } } } @@ -4444,6 +4442,13 @@ void SurfaceFlinger::initializeDisplays() { new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); })); } +void SurfaceFlinger::setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled) { + if (mHWCVsyncState != enabled) { + getHwComposer().setVsyncEnabled(displayId, enabled); + mHWCVsyncState = enabled; + } +} + void SurfaceFlinger::setPowerModeInternal(const sp& display, int mode) { if (display->isVirtual()) { ALOGE("%s: Invalid operation on virtual display", __FUNCTION__); @@ -4470,11 +4475,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, int // Turn on the display getHwComposer().setPowerMode(*displayId, mode); if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) { - if (mEnableHWVsyncScreenOn) { - setPrimaryVsyncEnabledInternal(mEnableHWVsyncScreenOn); - mEnableHWVsyncScreenOn = false; - } - + setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState); mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); } @@ -4500,6 +4501,9 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, int mScheduler->onScreenReleased(mAppConnectionHandle); } + // Make sure HWVsync is disabled before turning off the display + setVsyncEnabledInHWC(*displayId, HWC2::Vsync::Disable); + getHwComposer().setPowerMode(*displayId, mode); mVisibleRegionsDirty = true; // from this point on, SF will stop drawing on this display diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6627f14b33..a8057aad24 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -845,6 +845,7 @@ private: } bool previousFrameMissed(); + void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled); /* * Debugging & dumpsys @@ -1180,8 +1181,9 @@ private: // be any issues with a raw pointer referencing an invalid object. std::unordered_set mOffscreenLayers; - // Flag to indicate whether to re-enable HWVsync when screen is on - bool mEnableHWVsyncScreenOn = false; + // Flags to capture the state of Vsync in HWC + HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable; + HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable; }; } // namespace android -- GitLab From 7e49aa4cebcdd56ae3ecb2f17ba56d04bf7dd121 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 11 Jun 2019 19:08:58 -0700 Subject: [PATCH 0223/1255] SurfaceFlinger: clear LayerHistory on touch Clear LayerHistory and mark all layers as inactive when getting a touch event to prevent a quick refresh rate bounce as LayerHistory picks up with the FPS. Fixes: 134663749 Test: live wallpaper + Open notification shade + wait for 60Hz + Click on "USB debugging connected" Change-Id: Ifa095fbcdb95ffe413cc77c5e062f1174815158b (cherry picked from commit a9bf4cadf763fe8337c231c44e7d39827c98a0b8) Merged-In: Ifa095fbcdb95ffe413cc77c5e062f1174815158b --- services/surfaceflinger/Scheduler/LayerHistory.cpp | 13 +++++++++++++ services/surfaceflinger/Scheduler/LayerHistory.h | 3 +++ services/surfaceflinger/Scheduler/Scheduler.cpp | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 1db43a32cd..e762af3ec5 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -173,5 +173,18 @@ void LayerHistory::removeIrrelevantLayers() { } } +void LayerHistory::clearHistory() { + std::lock_guard lock(mLock); + + auto it = mActiveLayerInfos.begin(); + while (it != mActiveLayerInfos.end()) { + auto id = it->first; + auto layerInfo = it->second; + layerInfo->clearHistory(); + mInactiveLayerInfos.insert({id, layerInfo}); + it = mActiveLayerInfos.erase(it); + } +} + } // namespace scheduler } // namespace android \ No newline at end of file diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index adc5ce5f64..2569b4638a 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -64,6 +64,9 @@ public: // layers. See go/content-fps-detection-in-scheduler for more information. std::pair getDesiredRefreshRateAndHDR(); + // Clears all layer history. + void clearHistory(); + // Removes the handle and the object from the map. void destroyLayer(const int64_t id); diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index afcf3d45ba..86b29205c7 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -407,6 +407,10 @@ void Scheduler::notifyTouchEvent() { if (mSupportKernelTimer) { resetIdleTimer(); } + + // Touch event will boost the refresh rate to performance. + // Clear Layer History to get fresh FPS detection + mLayerHistory.clearHistory(); } void Scheduler::resetTimerCallback() { -- GitLab From f8713e188492d30c0b7f8fd09ebab66cf7bc7646 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 7 Jun 2019 18:20:51 -0700 Subject: [PATCH 0224/1255] SurfaceFlinger: Some fixes to DispSync Pass negative offsets to DispSync to fix the scheduling when SurfaceFlinger uses negative offsets. Change-Id: I1f9544b064305c87f973120cc1bc59a0268b78e5 Bug: 132284303 Test: UI-Bench (cherry picked from commit 45e4e3634e94171bca7e3df287bcbcb74df6ca4a) Merged-In: I1f9544b064305c87f973120cc1bc59a0268b78e5 --- .../surfaceflinger/Scheduler/DispSync.cpp | 28 ++++++------------- .../Scheduler/DispSyncSource.cpp | 22 ++++++++------- .../surfaceflinger/Scheduler/DispSyncSource.h | 4 ++- .../surfaceflinger/Scheduler/Scheduler.cpp | 11 +++++--- services/surfaceflinger/Scheduler/Scheduler.h | 7 +++-- .../surfaceflinger/Scheduler/VSyncModulator.h | 5 +++- services/surfaceflinger/SurfaceFlinger.cpp | 25 +++++++++++------ .../tests/unittests/DispSyncSourceTest.cpp | 4 ++- .../tests/unittests/SchedulerTest.cpp | 4 +-- 9 files changed, 59 insertions(+), 51 deletions(-) diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index 95ff9d0c73..e59d459242 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -92,7 +92,6 @@ public: mPeriod = period; if (!mModelLocked && referenceTimeChanged) { for (auto& eventListener : mEventListeners) { - eventListener.mHasFired = false; eventListener.mLastEventTime = mReferenceTime - mPeriod + mPhase + eventListener.mPhase; } @@ -123,13 +122,6 @@ public: void unlockModel() { Mutex::Autolock lock(mMutex); - if (mModelLocked) { - for (auto& eventListener : mEventListeners) { - if (eventListener.mLastEventTime > mReferenceTime) { - eventListener.mHasFired = true; - } - } - } mModelLocked = false; ATRACE_INT("DispSync:ModelLocked", mModelLocked); } @@ -259,10 +251,6 @@ public: listener.mLastCallbackTime = lastCallbackTime; } - if (!mModelLocked && listener.mLastEventTime > mReferenceTime) { - listener.mHasFired = true; - } - mEventListeners.push_back(listener); mCond.signal(); @@ -305,7 +293,14 @@ public: } else if (diff < -mPeriod / 2) { diff += mPeriod; } + + if (phase < 0 && oldPhase > 0) { + diff += mPeriod; + } else if (phase > 0 && oldPhase < 0) { + diff -= mPeriod; + } eventListener.mLastEventTime -= diff; + eventListener.mLastCallbackTime -= diff; mCond.signal(); return NO_ERROR; } @@ -320,7 +315,6 @@ private: nsecs_t mLastEventTime; nsecs_t mLastCallbackTime; DispSync::Callback* mCallback; - bool mHasFired = false; }; struct CallbackInvocation { @@ -368,12 +362,7 @@ private: eventListener.mName); continue; } - if (eventListener.mHasFired && !mModelLocked) { - eventListener.mLastEventTime = t; - ALOGV("[%s] [%s] Skipping event due to already firing", mName, - eventListener.mName); - continue; - } + CallbackInvocation ci; ci.mCallback = eventListener.mCallback; ci.mEventTime = t; @@ -382,7 +371,6 @@ private: callbackInvocations.push_back(ci); eventListener.mLastEventTime = t; eventListener.mLastCallbackTime = now; - eventListener.mHasFired = true; } } diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 00948aedb4..265b8aa47f 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -27,14 +27,16 @@ namespace android { -DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, +DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, + nsecs_t offsetThresholdForNextVsync, bool traceVsync, const char* name) : mName(name), mTraceVsync(traceVsync), mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)), mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)), mDispSync(dispSync), - mPhaseOffset(phaseOffset) {} + mPhaseOffset(phaseOffset), + mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {} void DispSyncSource::setVSyncEnabled(bool enable) { std::lock_guard lock(mVsyncMutex); @@ -64,15 +66,15 @@ void DispSyncSource::setCallback(VSyncSource::Callback* callback) { void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) { std::lock_guard lock(mVsyncMutex); - - // Normalize phaseOffset to [0, period) - auto period = mDispSync->getPeriod(); - phaseOffset %= period; - if (phaseOffset < 0) { - // If we're here, then phaseOffset is in (-period, 0). After this - // operation, it will be in (0, period) - phaseOffset += period; + const nsecs_t period = mDispSync->getPeriod(); + // Check if offset should be handled as negative + if (phaseOffset >= mOffsetThresholdForNextVsync) { + phaseOffset -= period; } + + // Normalize phaseOffset to [-period, period) + const int numPeriods = phaseOffset / period; + phaseOffset -= numPeriods * period; mPhaseOffset = phaseOffset; // If we're not enabled, we don't need to mess with the listeners diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h index 4759699c5e..b6785c5f74 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.h +++ b/services/surfaceflinger/Scheduler/DispSyncSource.h @@ -25,7 +25,8 @@ namespace android { class DispSyncSource final : public VSyncSource, private DispSync::Callback { public: - DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name); + DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, nsecs_t offsetThresholdForNextVsync, + bool traceVsync, const char* name); ~DispSyncSource() override = default; @@ -53,6 +54,7 @@ private: std::mutex mVsyncMutex; nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex); + const nsecs_t mOffsetThresholdForNextVsync; bool mEnabled GUARDED_BY(mVsyncMutex) = false; }; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 86b29205c7..ceb6ce5b82 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -119,14 +119,15 @@ Scheduler::~Scheduler() { } sp Scheduler::createConnection( - const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback, + const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync, + ResyncCallback resyncCallback, impl::EventThread::InterceptVSyncsCallback interceptCallback) { const int64_t id = sNextId++; ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id); std::unique_ptr eventThread = makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs, - std::move(interceptCallback)); + offsetThresholdForNextVsync, std::move(interceptCallback)); auto eventThreadConnection = createConnectionInternal(eventThread.get(), std::move(resyncCallback), @@ -139,10 +140,12 @@ sp Scheduler::createConnection( } std::unique_ptr Scheduler::makeEventThread( - const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs, + const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs, + nsecs_t offsetThresholdForNextVsync, impl::EventThread::InterceptVSyncsCallback interceptCallback) { std::unique_ptr eventThreadSource = - std::make_unique(dispSync, phaseOffsetNs, true, connectionName); + std::make_unique(dispSync, phaseOffsetNs, offsetThresholdForNextVsync, + true, connectionName); return std::make_unique(std::move(eventThreadSource), std::move(interceptCallback), connectionName); } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 597f9a2878..f06aada480 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -96,8 +96,8 @@ public: virtual ~Scheduler(); /** Creates an EventThread connection. */ - sp createConnection(const char* connectionName, int64_t phaseOffsetNs, - ResyncCallback, + sp createConnection(const char* connectionName, nsecs_t phaseOffsetNs, + nsecs_t offsetThresholdForNextVsync, ResyncCallback, impl::EventThread::InterceptVSyncsCallback); sp createDisplayEventConnection( @@ -185,7 +185,8 @@ public: protected: virtual std::unique_ptr makeEventThread( - const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs, + const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs, + nsecs_t offsetThresholdForNextVsync, impl::EventThread::InterceptVSyncsCallback interceptCallback); private: diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 41c3a3a605..73a1fb9816 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -56,10 +56,12 @@ public: // appEarly: Like sfEarly, but for the app-vsync // appEarlyGl: Like sfEarlyGl, but for the app-vsync. // appLate: The regular app vsync phase offset. - void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) { + void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, + nsecs_t thresholdForNextVsync) { mEarlyOffsets = early; mEarlyGlOffsets = earlyGl; mLateOffsets = late; + mThresholdForNextVsync = thresholdForNextVsync; if (mSfConnectionHandle && late.sf != mOffsets.load().sf) { mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf); @@ -192,6 +194,7 @@ private: Offsets mLateOffsets; Offsets mEarlyOffsets; Offsets mEarlyGlOffsets; + nsecs_t mThresholdForNextVsync; EventThread* mSfEventThread = nullptr; EventThread* mAppEventThread = nullptr; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b67260c3b6..fecb7c5e78 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -382,7 +382,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mLumaSampling = atoi(value); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late); + mVsyncModulator.setPhaseOffsets(early, gl, late, + mPhaseOffsets->getOffsetThresholdForNextVsync()); // We should be reading 'persist.sys.sf.color_saturation' here // but since /data may be encrypted, we need to wait until after vold @@ -621,13 +622,16 @@ void SurfaceFlinger::init() { mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this)); mAppConnectionHandle = - mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(), + mScheduler->createConnection("app", mVsyncModulator.getOffsets().app, + mPhaseOffsets->getOffsetThresholdForNextVsync(), resyncCallback, impl::EventThread::InterceptVSyncsCallback()); - mSfConnectionHandle = mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(), - resyncCallback, [this](nsecs_t timestamp) { - mInterceptor->saveVSyncEvent(timestamp); - }); + mSfConnectionHandle = + mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf, + mPhaseOffsets->getOffsetThresholdForNextVsync(), + resyncCallback, [this](nsecs_t timestamp) { + mInterceptor->saveVSyncEvent(timestamp); + }); mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle)); mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(), @@ -945,7 +949,8 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { mVsyncModulator.onRefreshRateChangeInitiated(); mPhaseOffsets->setRefreshRateType(info.type); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late); + mVsyncModulator.setPhaseOffsets(early, gl, late, + mPhaseOffsets->getOffsetThresholdForNextVsync()); } mDesiredActiveConfigChanged = true; ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); @@ -979,7 +984,8 @@ void SurfaceFlinger::setActiveConfigInternal() { mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late); + mVsyncModulator.setPhaseOffsets(early, gl, late, + mPhaseOffsets->getOffsetThresholdForNextVsync()); ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId); if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) { @@ -997,7 +1003,8 @@ void SurfaceFlinger::desiredActiveConfigChangeDone() { mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late); + mVsyncModulator.setPhaseOffsets(early, gl, late, + mPhaseOffsets->getOffsetThresholdForNextVsync()); } bool SurfaceFlinger::performSetActiveConfig() { diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp index 2e705dad6d..0aa8cf565d 100644 --- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp +++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp @@ -51,6 +51,7 @@ protected: AsyncCallRecorder mVSyncEventCallRecorder; static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms; + static constexpr std::chrono::nanoseconds mOffsetThresholdForNextVsync = 16ms; static constexpr int mIterations = 100; }; @@ -78,7 +79,8 @@ void DispSyncSourceTest::createDispSync() { void DispSyncSourceTest::createDispSyncSource() { createDispSync(); - mDispSyncSource = std::make_unique(mDispSync.get(), mPhaseOffset.count(), true, + mDispSyncSource = std::make_unique(mDispSync.get(), mPhaseOffset.count(), + mOffsetThresholdForNextVsync.count(), true, "DispSyncSourceTest"); mDispSyncSource->setCallback(this); } diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index af5ccbca21..740115ea32 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -48,7 +48,7 @@ protected: std::unique_ptr makeEventThread( const char* /* connectionName */, DispSync* /* dispSync */, - nsecs_t /* phaseOffsetNs */, + nsecs_t /* phaseOffsetNs */, nsecs_t /* offsetThresholdForNextVsync */, impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override { return std::move(mEventThread); } @@ -85,7 +85,7 @@ SchedulerTest::SchedulerTest() { EXPECT_CALL(*mEventThread, createEventConnection(_, _)) .WillRepeatedly(Return(mEventThreadConnection)); - mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(), + mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, ResyncCallback(), impl::EventThread::InterceptVSyncsCallback()); EXPECT_TRUE(mConnectionHandle != nullptr); } -- GitLab From daceef75545ccc041fc72582fba82625ac57f575 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Tue, 11 Jun 2019 13:49:19 -0700 Subject: [PATCH 0225/1255] libtimeinstate: support concurrent_{active,policy}_time Add support for querying and clearing stats for time each UID spent running concurrently with tasks on all other CPUs and on CPUs in the same cluster. Also add tests for the new functions, including consistency checks comparing time in state vs concurrent times. Finally, because the BPF program cannot update multiple map values atomically, userspace reads occasionally occur in between the updates to a UID's active and policy times. Add a check for this in our reader functions and retry once when it is detected. For the (very rare) case where the same race occurs when retrying, include a comment in our consistency test to help distinguish these transient failures from a more serious bug. Test: libtimeinstate_test passes Bug: 138317993 Change-Id: I429ed39d3ef82b6643fd042a74d9d403c658a8c1 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/cputimeinstate.cpp | 165 ++++++++++++++++-- libs/cputimeinstate/cputimeinstate.h | 12 +- libs/cputimeinstate/testtimeinstate.cpp | 218 +++++++++++++++++++++++- libs/cputimeinstate/timeinstate.h | 8 +- 4 files changed, 375 insertions(+), 28 deletions(-) diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 4c8d52efd9..f255512704 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -53,7 +54,8 @@ static uint32_t gNCpus = 0; static std::vector> gPolicyFreqs; static std::vector> gPolicyCpus; static std::set gAllFreqs; -static unique_fd gMapFd; +static unique_fd gTisMapFd; +static unique_fd gConcurrentMapFd; static std::optional> readNumbersFromFile(const std::string &path) { std::string data; @@ -122,8 +124,12 @@ static bool initGlobals() { gPolicyCpus.emplace_back(*cpus); } - gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")}; - if (gMapFd < 0) return false; + gTisMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")}; + if (gTisMapFd < 0) return false; + + gConcurrentMapFd = + unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")}; + if (gConcurrentMapFd < 0) return false; gInitialized = true; return true; @@ -143,7 +149,7 @@ static bool attachTracepointProgram(const std::string &eventType, const std::str // process dies then it must be called again to resume tracking. // This function should *not* be called while tracking is already active; doing so is unnecessary // and can lead to accounting errors. -bool startTrackingUidCpuFreqTimes() { +bool startTrackingUidTimes() { if (!initGlobals()) return false; unique_fd fd(bpf_obj_get(BPF_FS_PATH "map_time_in_state_cpu_policy_map")); @@ -174,7 +180,7 @@ bool startTrackingUidCpuFreqTimes() { attachTracepointProgram("power", "cpu_frequency"); } -// Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes. +// Retrieve the times in ns that uid spent running at each CPU frequency. // Return contains no value on error, otherwise it contains a vector of vectors using the format: // [[t0_0, t0_1, ...], // [t1_0, t1_1, ...], ...] @@ -189,11 +195,11 @@ std::optional>> getUidCpuFreqTimes(uint32_t ui out.emplace_back(freqList.size(), 0); } - std::vector vals(gNCpus); + std::vector vals(gNCpus); time_key_t key = {.uid = uid}; for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) { key.bucket = i; - if (findMapEntry(gMapFd, &key, vals.data())) { + if (findMapEntry(gTisMapFd, &key, vals.data())) { if (errno != ENOENT) return {}; continue; } @@ -214,7 +220,7 @@ std::optional>> getUidCpuFreqTimes(uint32_t ui return out; } -// Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap. +// Retrieve the times in ns that each uid spent running at each CPU freq. // Return contains no value on error, otherwise it contains a map from uids to vectors of vectors // using the format: // { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...], @@ -225,7 +231,7 @@ getUidsCpuFreqTimes() { if (!gInitialized && !initGlobals()) return {}; time_key_t key, prevKey; std::unordered_map>> map; - if (getFirstMapKey(gMapFd, &key)) { + if (getFirstMapKey(gTisMapFd, &key)) { if (errno == ENOENT) return map; return std::nullopt; } @@ -233,9 +239,9 @@ getUidsCpuFreqTimes() { std::vector> mapFormat; for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0); - std::vector vals(gNCpus); + std::vector vals(gNCpus); do { - if (findMapEntry(gMapFd, &key, vals.data())) return {}; + if (findMapEntry(gTisMapFd, &key, vals.data())) return {}; if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat); auto offset = key.bucket * FREQS_PER_ENTRY; @@ -250,13 +256,129 @@ getUidsCpuFreqTimes() { } } prevKey = key; - } while (!getNextMapKey(gMapFd, &prevKey, &key)); + } while (!getNextMapKey(gTisMapFd, &prevKey, &key)); if (errno != ENOENT) return {}; return map; } +static bool verifyConcurrentTimes(const concurrent_time_t &ct) { + uint64_t activeSum = std::accumulate(ct.active.begin(), ct.active.end(), (uint64_t)0); + uint64_t policySum = 0; + for (const auto &vec : ct.policy) { + policySum += std::accumulate(vec.begin(), vec.end(), (uint64_t)0); + } + return activeSum == policySum; +} + +// Retrieve the times in ns that uid spent running concurrently with each possible number of other +// tasks on each cluster (policy times) and overall (active times). +// Return contains no value on error, otherwise it contains a concurrent_time_t with the format: +// {.active = [a0, a1, ...], .policy = [[p0_0, p0_1, ...], [p1_0, p1_1, ...], ...]} +// where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent +// running on the ith cluster, concurrently with tasks on j other cpus in the same cluster +std::optional getUidConcurrentTimes(uint32_t uid, bool retry) { + if (!gInitialized && !initGlobals()) return {}; + concurrent_time_t ret = {.active = std::vector(gNCpus, 0)}; + for (const auto &cpuList : gPolicyCpus) ret.policy.emplace_back(cpuList.size(), 0); + std::vector vals(gNCpus); + time_key_t key = {.uid = uid}; + for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) { + if (findMapEntry(gConcurrentMapFd, &key, vals.data())) { + if (errno != ENOENT) return {}; + continue; + } + auto offset = key.bucket * CPUS_PER_ENTRY; + auto nextOffset = (key.bucket + 1) * CPUS_PER_ENTRY; + + auto activeBegin = ret.active.begin() + offset; + auto activeEnd = nextOffset < gNCpus ? activeBegin + CPUS_PER_ENTRY : ret.active.end(); + + for (uint32_t cpu = 0; cpu < gNCpus; ++cpu) { + std::transform(activeBegin, activeEnd, std::begin(vals[cpu].active), activeBegin, + std::plus()); + } + + for (uint32_t policy = 0; policy < gNPolicies; ++policy) { + if (offset >= gPolicyCpus[policy].size()) continue; + auto policyBegin = ret.policy[policy].begin() + offset; + auto policyEnd = nextOffset < gPolicyCpus[policy].size() ? policyBegin + CPUS_PER_ENTRY + : ret.policy[policy].end(); + + for (const auto &cpu : gPolicyCpus[policy]) { + std::transform(policyBegin, policyEnd, std::begin(vals[cpu].policy), policyBegin, + std::plus()); + } + } + } + if (!verifyConcurrentTimes(ret) && retry) return getUidConcurrentTimes(uid, false); + return ret; +} + +// Retrieve the times in ns that each uid spent running concurrently with each possible number of +// other tasks on each cluster (policy times) and overall (active times). +// Return contains no value on error, otherwise it contains a map from uids to concurrent_time_t's +// using the format: +// { uid0 -> {.active = [a0, a1, ...], .policy = [[p0_0, p0_1, ...], [p1_0, p1_1, ...], ...] }, ...} +// where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent +// running on the ith cluster, concurrently with tasks on j other cpus in the same cluster. +std::optional> getUidsConcurrentTimes() { + if (!gInitialized && !initGlobals()) return {}; + time_key_t key, prevKey; + std::unordered_map ret; + if (getFirstMapKey(gConcurrentMapFd, &key)) { + if (errno == ENOENT) return ret; + return {}; + } + + concurrent_time_t retFormat = {.active = std::vector(gNCpus, 0)}; + for (const auto &cpuList : gPolicyCpus) retFormat.policy.emplace_back(cpuList.size(), 0); + + std::vector vals(gNCpus); + std::vector::iterator activeBegin, activeEnd, policyBegin, policyEnd; + + do { + if (findMapEntry(gConcurrentMapFd, &key, vals.data())) return {}; + if (ret.find(key.uid) == ret.end()) ret.emplace(key.uid, retFormat); + + auto offset = key.bucket * CPUS_PER_ENTRY; + auto nextOffset = (key.bucket + 1) * CPUS_PER_ENTRY; + + activeBegin = ret[key.uid].active.begin(); + activeEnd = nextOffset < gNCpus ? activeBegin + CPUS_PER_ENTRY : ret[key.uid].active.end(); + + for (uint32_t cpu = 0; cpu < gNCpus; ++cpu) { + std::transform(activeBegin, activeEnd, std::begin(vals[cpu].active), activeBegin, + std::plus()); + } + + for (uint32_t policy = 0; policy < gNPolicies; ++policy) { + if (offset >= gPolicyCpus[policy].size()) continue; + policyBegin = ret[key.uid].policy[policy].begin() + offset; + policyEnd = nextOffset < gPolicyCpus[policy].size() ? policyBegin + CPUS_PER_ENTRY + : ret[key.uid].policy[policy].end(); + + for (const auto &cpu : gPolicyCpus[policy]) { + std::transform(policyBegin, policyEnd, std::begin(vals[cpu].policy), policyBegin, + std::plus()); + } + } + prevKey = key; + } while (!getNextMapKey(gConcurrentMapFd, &prevKey, &key)); + if (errno != ENOENT) return {}; + for (const auto &[key, value] : ret) { + if (!verifyConcurrentTimes(value)) { + auto val = getUidConcurrentTimes(key, false); + if (val.has_value()) ret[key] = val.value(); + } + } + return ret; +} + // Clear all time in state data for a given uid. Returns false on error, true otherwise. -bool clearUidCpuFreqTimes(uint32_t uid) { +// This is only suitable for clearing data when an app is uninstalled; if called on a UID with +// running tasks it will cause time in state vs. concurrent time totals to be inconsistent for that +// UID. +bool clearUidTimes(uint32_t uid) { if (!gInitialized && !initGlobals()) return false; time_key_t key = {.uid = uid}; @@ -266,11 +388,20 @@ bool clearUidCpuFreqTimes(uint32_t uid) { if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size(); } - val_t zeros = {0}; - std::vector vals(gNCpus, zeros); + tis_val_t zeros = {0}; + std::vector vals(gNCpus, zeros); for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) { - if (writeToMapEntry(gMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT) return false; - if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false; + if (writeToMapEntry(gTisMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT) + return false; + if (deleteMapEntry(gTisMapFd, &key) && errno != ENOENT) return false; + } + + concurrent_val_t czeros = {.policy = {0}, .active = {0}}; + std::vector cvals(gNCpus, czeros); + for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) { + if (writeToMapEntry(gConcurrentMapFd, &key, cvals.data(), BPF_EXIST) && errno != ENOENT) + return false; + if (deleteMapEntry(gConcurrentMapFd, &key) && errno != ENOENT) return false; } return true; } diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h index d7b45870ac..f620715dab 100644 --- a/libs/cputimeinstate/cputimeinstate.h +++ b/libs/cputimeinstate/cputimeinstate.h @@ -22,11 +22,19 @@ namespace android { namespace bpf { -bool startTrackingUidCpuFreqTimes(); +bool startTrackingUidTimes(); std::optional>> getUidCpuFreqTimes(uint32_t uid); std::optional>>> getUidsCpuFreqTimes(); -bool clearUidCpuFreqTimes(unsigned int uid); + +struct concurrent_time_t { + std::vector active; + std::vector> policy; +}; + +std::optional getUidConcurrentTimes(uint32_t uid, bool retry = true); +std::optional> getUidsConcurrentTimes(); +bool clearUidTimes(unsigned int uid); } // namespace bpf } // namespace android diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 39007e4603..15f6214bff 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -3,6 +3,7 @@ #include +#include #include #include @@ -21,13 +22,83 @@ static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365; using std::vector; -TEST(TimeInStateTest, SingleUid) { +TEST(TimeInStateTest, SingleUidTimeInState) { auto times = getUidCpuFreqTimes(0); ASSERT_TRUE(times.has_value()); EXPECT_FALSE(times->empty()); } -TEST(TimeInStateTest, AllUid) { +TEST(TimeInStateTest, SingleUidConcurrentTimes) { + auto concurrentTimes = getUidConcurrentTimes(0); + ASSERT_TRUE(concurrentTimes.has_value()); + ASSERT_FALSE(concurrentTimes->active.empty()); + ASSERT_FALSE(concurrentTimes->policy.empty()); + + uint64_t policyEntries = 0; + for (const auto &policyTimeVec : concurrentTimes->policy) policyEntries += policyTimeVec.size(); + ASSERT_EQ(concurrentTimes->active.size(), policyEntries); +} + +static void TestConcurrentTimesConsistent(const struct concurrent_time_t &concurrentTime) { + size_t maxPolicyCpus = 0; + for (const auto &vec : concurrentTime.policy) { + maxPolicyCpus = std::max(maxPolicyCpus, vec.size()); + } + uint64_t policySum = 0; + for (size_t i = 0; i < maxPolicyCpus; ++i) { + for (const auto &vec : concurrentTime.policy) { + if (i < vec.size()) policySum += vec[i]; + } + ASSERT_LE(concurrentTime.active[i], policySum); + policySum -= concurrentTime.active[i]; + } + policySum = 0; + for (size_t i = 0; i < concurrentTime.active.size(); ++i) { + for (const auto &vec : concurrentTime.policy) { + if (i < vec.size()) policySum += vec[vec.size() - 1 - i]; + } + auto activeSum = concurrentTime.active[concurrentTime.active.size() - 1 - i]; + // This check is slightly flaky because we may read a map entry in the middle of an update + // when active times have been updated but policy times have not. This happens infrequently + // and can be distinguished from more serious bugs by re-running the test: if the underlying + // data itself is inconsistent, the test will fail every time. + ASSERT_LE(activeSum, policySum); + policySum -= activeSum; + } +} + +static void TestUidTimesConsistent(const std::vector> &timeInState, + const struct concurrent_time_t &concurrentTime) { + ASSERT_NO_FATAL_FAILURE(TestConcurrentTimesConsistent(concurrentTime)); + ASSERT_EQ(timeInState.size(), concurrentTime.policy.size()); + uint64_t policySum = 0; + for (uint32_t i = 0; i < timeInState.size(); ++i) { + uint64_t tisSum = + std::accumulate(timeInState[i].begin(), timeInState[i].end(), (uint64_t)0); + uint64_t concurrentSum = std::accumulate(concurrentTime.policy[i].begin(), + concurrentTime.policy[i].end(), (uint64_t)0); + if (tisSum < concurrentSum) + ASSERT_LE(concurrentSum - tisSum, NSEC_PER_SEC); + else + ASSERT_LE(tisSum - concurrentSum, NSEC_PER_SEC); + policySum += concurrentSum; + } + uint64_t activeSum = std::accumulate(concurrentTime.active.begin(), concurrentTime.active.end(), + (uint64_t)0); + EXPECT_EQ(activeSum, policySum); +} + +TEST(TimeInStateTest, SingleUidTimesConsistent) { + auto times = getUidCpuFreqTimes(0); + ASSERT_TRUE(times.has_value()); + + auto concurrentTimes = getUidConcurrentTimes(0); + ASSERT_TRUE(concurrentTimes.has_value()); + + ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(*times, *concurrentTimes)); +} + +TEST(TimeInStateTest, AllUidTimeInState) { vector sizes; auto map = getUidsCpuFreqTimes(); ASSERT_TRUE(map.has_value()); @@ -43,7 +114,7 @@ TEST(TimeInStateTest, AllUid) { } } -TEST(TimeInStateTest, SingleAndAllUidConsistent) { +TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) { auto map = getUidsCpuFreqTimes(); ASSERT_TRUE(map.has_value()); ASSERT_FALSE(map->empty()); @@ -64,6 +135,40 @@ TEST(TimeInStateTest, SingleAndAllUidConsistent) { } } +TEST(TimeInStateTest, AllUidConcurrentTimes) { + auto map = getUidsConcurrentTimes(); + ASSERT_TRUE(map.has_value()); + ASSERT_FALSE(map->empty()); + + auto firstEntry = map->begin()->second; + for (const auto &kv : *map) { + ASSERT_EQ(kv.second.active.size(), firstEntry.active.size()); + ASSERT_EQ(kv.second.policy.size(), firstEntry.policy.size()); + for (size_t i = 0; i < kv.second.policy.size(); ++i) { + ASSERT_EQ(kv.second.policy[i].size(), firstEntry.policy[i].size()); + } + } +} + +TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) { + auto map = getUidsConcurrentTimes(); + ASSERT_TRUE(map.has_value()); + for (const auto &kv : *map) { + uint32_t uid = kv.first; + auto times1 = kv.second; + auto times2 = getUidConcurrentTimes(uid); + ASSERT_TRUE(times2.has_value()); + for (uint32_t i = 0; i < times1.active.size(); ++i) { + ASSERT_LE(times2->active[i] - times1.active[i], NSEC_PER_SEC); + } + for (uint32_t i = 0; i < times1.policy.size(); ++i) { + for (uint32_t j = 0; j < times1.policy[i].size(); ++j) { + ASSERT_LE(times2->policy[i][j] - times1.policy[i][j], NSEC_PER_SEC); + } + } + } +} + void TestCheckDelta(uint64_t before, uint64_t after) { // Times should never decrease ASSERT_LE(before, after); @@ -71,7 +176,7 @@ void TestCheckDelta(uint64_t before, uint64_t after) { ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf()); } -TEST(TimeInStateTest, AllUidMonotonic) { +TEST(TimeInStateTest, AllUidTimeInStateMonotonic) { auto map1 = getUidsCpuFreqTimes(); ASSERT_TRUE(map1.has_value()); sleep(1); @@ -92,7 +197,35 @@ TEST(TimeInStateTest, AllUidMonotonic) { } } -TEST(TimeInStateTest, AllUidSanityCheck) { +TEST(TimeInStateTest, AllUidConcurrentTimesMonotonic) { + auto map1 = getUidsConcurrentTimes(); + ASSERT_TRUE(map1.has_value()); + ASSERT_FALSE(map1->empty()); + sleep(1); + auto map2 = getUidsConcurrentTimes(); + ASSERT_TRUE(map2.has_value()); + ASSERT_FALSE(map2->empty()); + + for (const auto &kv : *map1) { + uint32_t uid = kv.first; + auto times = kv.second; + ASSERT_NE(map2->find(uid), map2->end()); + for (uint32_t i = 0; i < times.active.size(); ++i) { + auto before = times.active[i]; + auto after = (*map2)[uid].active[i]; + ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after)); + } + for (uint32_t policy = 0; policy < times.policy.size(); ++policy) { + for (uint32_t idx = 0; idx < times.policy[policy].size(); ++idx) { + auto before = times.policy[policy][idx]; + auto after = (*map2)[uid].policy[policy][idx]; + ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after)); + } + } + } +} + +TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) { auto map = getUidsCpuFreqTimes(); ASSERT_TRUE(map.has_value()); @@ -110,6 +243,48 @@ TEST(TimeInStateTest, AllUidSanityCheck) { ASSERT_TRUE(foundLargeValue); } +TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) { + auto concurrentMap = getUidsConcurrentTimes(); + ASSERT_TRUE(concurrentMap); + + bool activeFoundLargeValue = false; + bool policyFoundLargeValue = false; + for (const auto &kv : *concurrentMap) { + for (const auto &time : kv.second.active) { + ASSERT_LE(time, NSEC_PER_YEAR); + if (time > UINT32_MAX) activeFoundLargeValue = true; + } + for (const auto &policyTimeVec : kv.second.policy) { + for (const auto &time : policyTimeVec) { + ASSERT_LE(time, NSEC_PER_YEAR); + if (time > UINT32_MAX) policyFoundLargeValue = true; + } + } + } + // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using + // uint64_t as expected, we should have some times higher than that. + ASSERT_TRUE(activeFoundLargeValue); + ASSERT_TRUE(policyFoundLargeValue); +} + +TEST(TimeInStateTest, AllUidTimesConsistent) { + auto tisMap = getUidsCpuFreqTimes(); + ASSERT_TRUE(tisMap.has_value()); + + auto concurrentMap = getUidsConcurrentTimes(); + ASSERT_TRUE(concurrentMap.has_value()); + + ASSERT_EQ(tisMap->size(), concurrentMap->size()); + for (const auto &kv : *tisMap) { + uint32_t uid = kv.first; + auto times = kv.second; + ASSERT_NE(concurrentMap->find(uid), concurrentMap->end()); + + auto concurrentTimes = (*concurrentMap)[uid]; + ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(times, concurrentTimes)); + } +} + TEST(TimeInStateTest, RemoveUid) { uint32_t uid = 0; { @@ -122,31 +297,58 @@ TEST(TimeInStateTest, RemoveUid) { } { // Add a map entry for our fake UID by copying a real map entry - android::base::unique_fd fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")}; + android::base::unique_fd fd{ + bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")}; ASSERT_GE(fd, 0); time_key_t k; ASSERT_FALSE(getFirstMapKey(fd, &k)); - std::vector vals(get_nprocs_conf()); + std::vector vals(get_nprocs_conf()); ASSERT_FALSE(findMapEntry(fd, &k, vals.data())); + uint32_t copiedUid = k.uid; k.uid = uid; ASSERT_FALSE(writeToMapEntry(fd, &k, vals.data(), BPF_NOEXIST)); + + android::base::unique_fd fd2{ + bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")}; + k.uid = copiedUid; + k.bucket = 0; + std::vector cvals(get_nprocs_conf()); + ASSERT_FALSE(findMapEntry(fd2, &k, cvals.data())); + k.uid = uid; + ASSERT_FALSE(writeToMapEntry(fd2, &k, cvals.data(), BPF_NOEXIST)); } auto times = getUidCpuFreqTimes(uid); ASSERT_TRUE(times.has_value()); ASSERT_FALSE(times->empty()); + auto concurrentTimes = getUidConcurrentTimes(0); + ASSERT_TRUE(concurrentTimes.has_value()); + ASSERT_FALSE(concurrentTimes->active.empty()); + ASSERT_FALSE(concurrentTimes->policy.empty()); + uint64_t sum = 0; for (size_t i = 0; i < times->size(); ++i) { for (auto x : (*times)[i]) sum += x; } ASSERT_GT(sum, (uint64_t)0); - ASSERT_TRUE(clearUidCpuFreqTimes(uid)); + uint64_t activeSum = 0; + for (size_t i = 0; i < concurrentTimes->active.size(); ++i) { + activeSum += concurrentTimes->active[i]; + } + ASSERT_GT(activeSum, (uint64_t)0); + + ASSERT_TRUE(clearUidTimes(uid)); auto allTimes = getUidsCpuFreqTimes(); ASSERT_TRUE(allTimes.has_value()); ASSERT_FALSE(allTimes->empty()); ASSERT_EQ(allTimes->find(uid), allTimes->end()); + + auto allConcurrentTimes = getUidsConcurrentTimes(); + ASSERT_TRUE(allConcurrentTimes.has_value()); + ASSERT_FALSE(allConcurrentTimes->empty()); + ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end()); } } // namespace bpf diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h index 41d0af07a2..6d4f913f80 100644 --- a/libs/cputimeinstate/timeinstate.h +++ b/libs/cputimeinstate/timeinstate.h @@ -19,16 +19,22 @@ #define BPF_FS_PATH "/sys/fs/bpf/" #define FREQS_PER_ENTRY 32 +#define CPUS_PER_ENTRY 8 struct time_key_t { uint32_t uid; uint32_t bucket; }; -struct val_t { +struct tis_val_t { uint64_t ar[FREQS_PER_ENTRY]; }; +struct concurrent_val_t { + uint64_t active[CPUS_PER_ENTRY]; + uint64_t policy[CPUS_PER_ENTRY]; +}; + struct freq_idx_key_t { uint32_t policy; uint32_t freq; -- GitLab From b2b503075c682c5aca211d840bd06f97332cef00 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 28 Aug 2019 16:15:38 -0700 Subject: [PATCH 0226/1255] libtimeinstate: move map format info into shared header Switch from using timeinstate.h to a shared header in system/bpf that provides key & value struct definitions both to libtimeinstate and to our BPF program Test: build libtimeinstate Bug: 138317993 Change-Id: I302b40bd1dfa7b529888f598cf36c146400f1315 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/Android.bp | 2 ++ libs/cputimeinstate/cputimeinstate.cpp | 2 +- libs/cputimeinstate/testtimeinstate.cpp | 2 +- libs/cputimeinstate/timeinstate.h | 41 ------------------------- 4 files changed, 4 insertions(+), 43 deletions(-) delete mode 100644 libs/cputimeinstate/timeinstate.h diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp index 9080ce13db..a8f7d92b41 100644 --- a/libs/cputimeinstate/Android.bp +++ b/libs/cputimeinstate/Android.bp @@ -8,6 +8,7 @@ cc_library { "liblog", "libnetdutils" ], + header_libs: ["bpf_prog_headers"], cflags: [ "-Werror", "-Wall", @@ -25,6 +26,7 @@ cc_test { "libtimeinstate", "libnetdutils", ], + header_libs: ["bpf_prog_headers"], cflags: [ "-Werror", "-Wall", diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index f255512704..2d2536c397 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -17,7 +17,7 @@ #define LOG_TAG "libtimeinstate" #include "cputimeinstate.h" -#include "timeinstate.h" +#include #include #include diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 15f6214bff..c0cd3e07ff 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -1,5 +1,5 @@ -#include "timeinstate.h" +#include #include diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h deleted file mode 100644 index 6d4f913f80..0000000000 --- a/libs/cputimeinstate/timeinstate.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#define BPF_FS_PATH "/sys/fs/bpf/" - -#define FREQS_PER_ENTRY 32 -#define CPUS_PER_ENTRY 8 - -struct time_key_t { - uint32_t uid; - uint32_t bucket; -}; - -struct tis_val_t { - uint64_t ar[FREQS_PER_ENTRY]; -}; - -struct concurrent_val_t { - uint64_t active[CPUS_PER_ENTRY]; - uint64_t policy[CPUS_PER_ENTRY]; -}; - -struct freq_idx_key_t { - uint32_t policy; - uint32_t freq; -}; -- GitLab From 067fcd36bc53a5f884108df5634cb1ca5549a30c Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Wed, 14 Aug 2019 10:41:12 -0700 Subject: [PATCH 0227/1255] libgui: Add discardFreeBuffers callback to producer This enables buffer producer to clear its buffer caches. Test: Camera CTS, libgui_test Bug: 136677409 Change-Id: I7f46e977f3edc3b08177654531745d8ca0b86889 --- libs/gui/BufferQueueConsumer.cpp | 10 +- libs/gui/BufferQueueCore.cpp | 7 ++ libs/gui/BufferQueueProducer.cpp | 5 +- libs/gui/IProducerListener.cpp | 26 +++++ libs/gui/Surface.cpp | 49 +++++++++ libs/gui/include/gui/BufferQueueCore.h | 6 +- libs/gui/include/gui/IProducerListener.h | 6 ++ libs/gui/include/gui/Surface.h | 44 ++++++++ libs/gui/tests/BufferQueue_test.cpp | 28 ++++- libs/gui/tests/Surface_test.cpp | 126 +++++++++++++++++++++++ 10 files changed, 299 insertions(+), 8 deletions(-) diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 528bfb194e..3a7cb44450 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -166,7 +166,9 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, mCore->mFreeBuffers.push_back(front->mSlot); } - listener = mCore->mConnectedProducerListener; + if (mCore->mBufferReleasedCbEnabled) { + listener = mCore->mConnectedProducerListener; + } ++numDroppedBuffers; } @@ -457,7 +459,9 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, mCore->mFreeBuffers.push_back(slot); } - listener = mCore->mConnectedProducerListener; + if (mCore->mBufferReleasedCbEnabled) { + listener = mCore->mConnectedProducerListener; + } BQ_LOGV("releaseBuffer: releasing slot %d", slot); mCore->mDequeueCondition.notify_all(); @@ -668,7 +672,7 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers; VALIDATE_CONSISTENCY(); - if (delta < 0) { + if (delta < 0 && mCore->mBufferReleasedCbEnabled) { listener = mCore->mConsumerListener; } } diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index b429d387ad..d6009d6cd5 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -65,6 +65,7 @@ BufferQueueCore::BufferQueueCore() : mConnectedApi(NO_CONNECTED_API), mLinkedToDeath(), mConnectedProducerListener(), + mBufferReleasedCbEnabled(false), mSlots(), mQueue(), mFreeSlots(), @@ -264,6 +265,12 @@ void BufferQueueCore::freeAllBuffersLocked() { } void BufferQueueCore::discardFreeBuffersLocked() { + // Notify producer about the discarded buffers. + if (mConnectedProducerListener != nullptr && mFreeBuffers.size() > 0) { + std::vector freeBuffers(mFreeBuffers.begin(), mFreeBuffers.end()); + mConnectedProducerListener->onBuffersDiscarded(freeBuffers); + } + for (int s : mFreeBuffers) { mFreeSlots.insert(s); clearBufferSlotLocked(s); diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index d149674eeb..56746749b9 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1223,9 +1223,8 @@ status_t BufferQueueProducer::connect(const sp& listener, } mCore->mLinkedToDeath = listener; } - if (listener->needsReleaseNotify()) { - mCore->mConnectedProducerListener = listener; - } + mCore->mConnectedProducerListener = listener; + mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify(); } break; default: diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp index 936063a5bd..808e3369f1 100644 --- a/libs/gui/IProducerListener.cpp +++ b/libs/gui/IProducerListener.cpp @@ -24,6 +24,7 @@ namespace android { enum { ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION, NEEDS_RELEASE_NOTIFY, + ON_BUFFERS_DISCARDED, }; class BpProducerListener : public BpInterface @@ -56,6 +57,13 @@ public: } return result; } + + virtual void onBuffersDiscarded(const std::vector& discardedSlots) { + Parcel data, reply; + data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor()); + data.writeInt32Vector(discardedSlots); + remote()->transact(ON_BUFFERS_DISCARDED, data, &reply, IBinder::FLAG_ONEWAY); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -76,6 +84,10 @@ public: virtual bool needsReleaseNotify() override { return mBase->needsReleaseNotify(); } + + virtual void onBuffersDiscarded(const std::vector& discardedSlots) override { + return mBase->onBuffersDiscarded(discardedSlots); + } }; IMPLEMENT_HYBRID_META_INTERFACE(ProducerListener, @@ -92,6 +104,17 @@ status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data, CHECK_INTERFACE(IProducerListener, data, reply); reply->writeBool(needsReleaseNotify()); return NO_ERROR; + case ON_BUFFERS_DISCARDED: { + CHECK_INTERFACE(IProducerListener, data, reply); + std::vector discardedSlots; + status_t result = data.readInt32Vector(&discardedSlots); + if (result != NO_ERROR) { + ALOGE("ON_BUFFERS_DISCARDED failed to read discardedSlots: %d", result); + return result; + } + onBuffersDiscarded(discardedSlots); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } @@ -104,4 +127,7 @@ bool BnProducerListener::needsReleaseNotify() { return true; } +void BnProducerListener::onBuffersDiscarded(const std::vector& /*discardedSlots*/) { +} + } // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index eb2e3f0615..7e356e4eb1 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -1299,6 +1300,14 @@ int Surface::connect(int api, const sp& listener) { return connect(api, listener, false); } +int Surface::connect( + int api, bool reportBufferRemoval, const sp& sListener) { + if (sListener != nullptr) { + mListenerProxy = new ProducerListenerProxy(this, sListener); + } + return connect(api, mListenerProxy, reportBufferRemoval); +} + int Surface::connect( int api, const sp& listener, bool reportBufferRemoval) { ATRACE_CALL(); @@ -1700,6 +1709,28 @@ void Surface::freeAllBuffers() { } } +status_t Surface::getAndFlushBuffersFromSlots(const std::vector& slots, + std::vector>* outBuffers) { + ALOGV("Surface::getAndFlushBuffersFromSlots"); + for (int32_t i : slots) { + if (i < 0 || i >= NUM_BUFFER_SLOTS) { + ALOGE("%s: Invalid slotIndex: %d", __FUNCTION__, i); + return BAD_VALUE; + } + } + + Mutex::Autolock lock(mMutex); + for (int32_t i : slots) { + if (mSlots[i].buffer == nullptr) { + ALOGW("%s: Discarded slot %d doesn't contain buffer!", __FUNCTION__, i); + continue; + } + outBuffers->push_back(mSlots[i].buffer); + mSlots[i].buffer = nullptr; + } + return OK; +} + void Surface::setSurfaceDamage(android_native_rect_t* rects, size_t numRects) { ATRACE_CALL(); ALOGV("Surface::setSurfaceDamage"); @@ -1985,4 +2016,22 @@ int Surface::setAutoPrerotation(bool autoPrerotation) { return err; } +void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vector& slots) { + ATRACE_CALL(); + sp parent = mParent.promote(); + if (parent == nullptr) { + return; + } + + std::vector> discardedBufs; + status_t res = parent->getAndFlushBuffersFromSlots(slots, &discardedBufs); + if (res != OK) { + ALOGE("%s: Failed to get buffers from slots: %s(%d)", __FUNCTION__, + strerror(-res), res); + return; + } + + mSurfaceListener->onBuffersDiscarded(discardedBufs); +} + }; // namespace android diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 205e79c879..3c960894da 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -189,8 +189,12 @@ private: sp mLinkedToDeath; // mConnectedProducerListener is used to handle the onBufferReleased - // notification. + // and onBuffersDiscarded notification. sp mConnectedProducerListener; + // mBufferReleasedCbEnabled is used to indicate whether onBufferReleased() + // callback is registered by the listener. When set to false, + // mConnectedProducerListener will not trigger onBufferReleased() callback. + bool mBufferReleasedCbEnabled; // mSlots is an array of buffer slots that must be mirrored on the producer // side. This allows buffer ownership to be transferred between the producer diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h index a13d8e4945..32a3690ff2 100644 --- a/libs/gui/include/gui/IProducerListener.h +++ b/libs/gui/include/gui/IProducerListener.h @@ -17,6 +17,8 @@ #ifndef ANDROID_GUI_IPRODUCERLISTENER_H #define ANDROID_GUI_IPRODUCERLISTENER_H +#include + #include #include #include @@ -44,6 +46,9 @@ public: // multiple threads. virtual void onBufferReleased() = 0; // Asynchronous virtual bool needsReleaseNotify() = 0; + // onBuffersFreed is called from IGraphicBufferConsumer::discardFreeBuffers + // to notify the producer that certain free buffers are discarded by the consumer. + virtual void onBuffersDiscarded(const std::vector& slots) = 0; // Asynchronous }; class IProducerListener : public ProducerListener, public IInterface @@ -65,6 +70,7 @@ public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); virtual bool needsReleaseNotify(); + virtual void onBuffersDiscarded(const std::vector& slots); }; class DummyProducerListener : public BnProducerListener diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index fe528b3711..28f5a26072 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,21 @@ namespace android { class ISurfaceComposer; +/* This is the same as ProducerListener except that onBuffersDiscarded is + * called with a vector of graphic buffers instead of buffer slots. + */ +class SurfaceListener : public virtual RefBase +{ +public: + SurfaceListener() = default; + virtual ~SurfaceListener() = default; + + virtual void onBufferReleased() = 0; + virtual bool needsReleaseNotify() = 0; + + virtual void onBuffersDiscarded(const std::vector>& buffers) = 0; +}; + /* * An implementation of ANativeWindow that feeds graphics buffers into a * BufferQueue. @@ -285,6 +301,10 @@ public: sp* outFence); virtual int attachBuffer(ANativeWindowBuffer*); + virtual int connect( + int api, bool reportBufferRemoval, + const sp& sListener); + // When client connects to Surface with reportBufferRemoval set to true, any buffers removed // from this Surface will be collected and returned here. Once this method returns, these // buffers will no longer be referenced by this Surface unless they are attached to this @@ -301,6 +321,26 @@ protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; + class ProducerListenerProxy : public BnProducerListener { + public: + ProducerListenerProxy(wp parent, sp listener) + : mParent(parent), mSurfaceListener(listener) {} + virtual ~ProducerListenerProxy() {} + + virtual void onBufferReleased() { + mSurfaceListener->onBufferReleased(); + } + + virtual bool needsReleaseNotify() { + return mSurfaceListener->needsReleaseNotify(); + } + + virtual void onBuffersDiscarded(const std::vector& slots); + private: + wp mParent; + sp mSurfaceListener; + }; + void querySupportedTimestampsLocked() const; void freeAllBuffers(); @@ -470,6 +510,10 @@ protected: bool mReportRemovedBuffers = false; std::vector> mRemovedBuffers; int mMaxBufferCount; + + sp mListenerProxy; + status_t getAndFlushBuffersFromSlots(const std::vector& slots, + std::vector>* outBuffers); }; } // namespace android diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 98dc1e6337..6d7b6bb9c6 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -1010,12 +1010,31 @@ TEST_F(BufferQueueTest, TestOccupancyHistory) { ASSERT_EQ(true, thirdSegment.usedThirdBuffer); } +struct BufferDiscardedListener : public BnProducerListener { +public: + BufferDiscardedListener() = default; + virtual ~BufferDiscardedListener() = default; + + virtual void onBufferReleased() {} + virtual bool needsReleaseNotify() { return false; } + virtual void onBuffersDiscarded(const std::vector& slots) { + mDiscardedSlots.insert(mDiscardedSlots.end(), slots.begin(), slots.end()); + } + + const std::vector& getDiscardedSlots() const { return mDiscardedSlots; } +private: + // No need to use lock given the test triggers the listener in the same + // thread context. + std::vector mDiscardedSlots; +}; + TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, + sp pl(new BufferDiscardedListener); + ASSERT_EQ(OK, mProducer->connect(pl, NATIVE_WINDOW_API_CPU, false, &output)); int slot = BufferQueue::INVALID_BUFFER_SLOT; @@ -1056,12 +1075,19 @@ TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); + int releasedSlot = item.mSlot; + // Acquire 1 buffer, leaving 1 filled buffer in queue ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); // Now discard the free buffers ASSERT_EQ(OK, mConsumer->discardFreeBuffers()); + // Check onBuffersDiscarded is called with correct slots + auto buffersDiscarded = pl->getDiscardedSlots(); + ASSERT_EQ(buffersDiscarded.size(), 1); + ASSERT_EQ(buffersDiscarded[0], releasedSlot); + // Check no free buffers in dump String8 dumpString; mConsumer->dumpState(String8{}, &dumpString); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 7718bc1b8e..5a121d77ab 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -57,6 +57,37 @@ class FakeProducerFrameEventHistory; static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits::max(); +class DummySurfaceListener : public SurfaceListener { +public: + DummySurfaceListener(bool enableReleasedCb = false) : + mEnableReleaseCb(enableReleasedCb), + mBuffersReleased(0) {} + virtual ~DummySurfaceListener() = default; + + virtual void onBufferReleased() { + mBuffersReleased++; + } + virtual bool needsReleaseNotify() { + return mEnableReleaseCb; + } + virtual void onBuffersDiscarded(const std::vector>& buffers) { + mDiscardedBuffers.insert(mDiscardedBuffers.end(), buffers.begin(), buffers.end()); + } + + int getReleaseNotifyCount() const { + return mBuffersReleased; + } + const std::vector>& getDiscardedBuffers() const { + return mDiscardedBuffers; + } +private: + // No need to use lock given the test triggers the listener in the same + // thread context. + bool mEnableReleaseCb; + int32_t mBuffersReleased; + std::vector> mDiscardedBuffers; +}; + class SurfaceTest : public ::testing::Test { protected: SurfaceTest() { @@ -88,6 +119,86 @@ protected: mComposerClient->dispose(); } + void testSurfaceListener(bool hasSurfaceListener, bool enableReleasedCb, + int32_t extraDiscardedBuffers) { + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setConsumerName(String8("TestConsumer")); + + sp surface = new Surface(producer); + sp window(surface); + sp listener; + if (hasSurfaceListener) { + listener = new DummySurfaceListener(enableReleasedCb); + } + ASSERT_EQ(OK, surface->connect( + NATIVE_WINDOW_API_CPU, + /*reportBufferRemoval*/true, + /*listener*/listener)); + const int BUFFER_COUNT = 4 + extraDiscardedBuffers; + ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(window.get(), BUFFER_COUNT)); + + ANativeWindowBuffer* buffers[BUFFER_COUNT]; + // Dequeue first to allocate a number of buffers + for (int i = 0; i < BUFFER_COUNT; i++) { + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffers[i])); + } + for (int i = 0; i < BUFFER_COUNT; i++) { + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffers[i], -1)); + } + + ANativeWindowBuffer* buffer; + // Fill BUFFER_COUNT-1 buffers + for (int i = 0; i < BUFFER_COUNT-1; i++) { + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffer)); + ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, -1)); + } + + // Dequeue 1 buffer + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffer)); + + // Acquire and free 1+extraDiscardedBuffers buffer, check onBufferReleased is called. + std::vector releasedItems; + releasedItems.resize(1+extraDiscardedBuffers); + for (int i = 0; i < releasedItems.size(); i++) { + ASSERT_EQ(NO_ERROR, consumer->acquireBuffer(&releasedItems[i], 0)); + ASSERT_EQ(NO_ERROR, consumer->releaseBuffer(releasedItems[i].mSlot, + releasedItems[i].mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, + Fence::NO_FENCE)); + } + int32_t expectedReleaseCb = (enableReleasedCb ? releasedItems.size() : 0); + if (hasSurfaceListener) { + ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount()); + } + + // Acquire 1 buffer, leaving 1+extraDiscardedBuffers filled buffer in queue + BufferItem item; + ASSERT_EQ(NO_ERROR, consumer->acquireBuffer(&item, 0)); + + // Discard free buffers + ASSERT_EQ(NO_ERROR, consumer->discardFreeBuffers()); + + if (hasSurfaceListener) { + ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount()); + + // Check onBufferDiscarded is called with correct buffer + auto discardedBuffers = listener->getDiscardedBuffers(); + ASSERT_EQ(discardedBuffers.size(), releasedItems.size()); + for (int i = 0; i < releasedItems.size(); i++) { + ASSERT_EQ(discardedBuffers[i], releasedItems[i].mGraphicBuffer); + } + + ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount()); + } + + // Disconnect the surface + ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU)); + } + sp mSurface; sp mComposerClient; sp mSurfaceControl; @@ -480,6 +591,21 @@ TEST_F(SurfaceTest, GetAndFlushRemovedBuffers) { ASSERT_LE(removedBuffers.size(), 1u); } +TEST_F(SurfaceTest, SurfaceListenerTest) { + // Test discarding 1 free buffers with no listener + testSurfaceListener(/*hasListener*/false, /*enableReleaseCb*/false, /*extraDiscardedBuffers*/0); + // Test discarding 2 free buffers with no listener + testSurfaceListener(/*hasListener*/false, /*enableReleaseCb*/false, /*extraDiscardedBuffers*/1); + // Test discarding 1 free buffers with a listener, disabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/false, /*extraDiscardedBuffers*/0); + // Test discarding 2 free buffers with a listener, disabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/false, /*extraDiscardedBuffers*/1); + // Test discarding 1 free buffers with a listener, enabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/true, /*extraDiscardedBuffers*/0); + // Test discarding 3 free buffers with a listener, enabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/true, /*extraDiscardedBuffers*/2); +} + TEST_F(SurfaceTest, TestGetLastDequeueStartTime) { sp anw(mSurface); ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU)); -- GitLab From 83127b7baf618b62d54ba1691330c13aee068ab0 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 12 Jun 2019 17:11:12 -0700 Subject: [PATCH 0228/1255] SurfaceFlinger: get present time from SF and not from Scheduler SF hold the most accurate expected present time as it also knows whether we are operating at negative offset and which vsync we are targeting. Bug: 133241520 Bug: 134589085 Test: systrace when scrolling Change-Id: I934df3a8bf807b0e52555765a6861f252b69c0d1 (cherry picked from commit 8fe1102f1feec1aa8b9a00a22a3cab13166fff0d) Merged-In: I934df3a8bf807b0e52555765a6861f252b69c0d1 --- services/surfaceflinger/BufferQueueLayer.cpp | 4 ++-- services/surfaceflinger/Scheduler/Scheduler.cpp | 2 +- services/surfaceflinger/Scheduler/Scheduler.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 57f1008e85..d6853661a5 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -201,7 +201,7 @@ uint64_t BufferQueueLayer::getFrameNumber() const { uint64_t frameNumber = mQueueItems[0].mFrameNumber; // The head of the queue will be dropped if there are signaled and timely frames behind it - nsecs_t expectedPresentTime = mFlinger->mScheduler->expectedPresentTime(); + nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime(); if (isRemovedFromCurrentState()) { expectedPresentTime = 0; @@ -279,7 +279,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode, getTransformToDisplayInverse(), mFreezeGeometryUpdates); - nsecs_t expectedPresentTime = mFlinger->mScheduler->expectedPresentTime(); + nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime(); if (isRemovedFromCurrentState()) { expectedPresentTime = 0; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index ceb6ce5b82..bb24f73834 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -315,7 +315,7 @@ void Scheduler::setIgnorePresentFences(bool ignore) { mPrimaryDispSync->setIgnorePresentFences(ignore); } -nsecs_t Scheduler::expectedPresentTime() { +nsecs_t Scheduler::getDispSyncExpectedPresentTime() { return mPrimaryDispSync->expectedPresentTime(); } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index f06aada480..eaad37c3ee 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -150,7 +150,7 @@ public: void addResyncSample(const nsecs_t timestamp, bool* periodFlushed); void addPresentFence(const std::shared_ptr& fenceTime); void setIgnorePresentFences(bool ignore); - nsecs_t expectedPresentTime(); + nsecs_t getDispSyncExpectedPresentTime(); // Registers the layer in the scheduler, and returns the handle for future references. std::unique_ptr registerLayer(std::string const& name, int windowType); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index fecb7c5e78..5da3544b51 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1672,7 +1672,7 @@ bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS { nsecs_t SurfaceFlinger::getExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS { DisplayStatInfo stats; mScheduler->getDisplayStatInfo(&stats); - const nsecs_t presentTime = mScheduler->expectedPresentTime(); + const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(); // Inflate the expected present time if we're targetting the next vsync. const nsecs_t correctedTime = mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync() @@ -3686,7 +3686,7 @@ bool SurfaceFlinger::containsAnyInvalidClientState(const Vector& bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, const Vector& states) { - nsecs_t expectedPresentTime = mScheduler->expectedPresentTime(); + nsecs_t expectedPresentTime = getExpectedPresentTime(); // Do not present if the desiredPresentTime has not passed unless it is more than one second // in the future. We ignore timestamps more than 1 second in the future for stability reasons. if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime && -- GitLab From a9c4d556084fb3b8592063b451c72f0ab0f7a65d Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 23 May 2019 10:22:24 -0700 Subject: [PATCH 0229/1255] [SurfaceFlinger] Split VSyncModulator into .cpp/.h files Future changes require this so that trace events can be added for this class. Bug: 133325345 Test: builds Change-Id: I7b70a9df500b0fca5ae14e2b414d44ca11edf3ce (cherry picked from commit b488afaa2addf5b101ef24d0e8fc9812cb3c7f26) Merged-In: I7b70a9df500b0fca5ae14e2b414d44ca11edf3ce --- services/surfaceflinger/Android.bp | 3 +- .../Scheduler/VSyncModulator.cpp | 135 ++++++++++++++++++ .../surfaceflinger/Scheduler/VSyncModulator.h | 127 +++------------- 3 files changed, 158 insertions(+), 107 deletions(-) create mode 100644 services/surfaceflinger/Scheduler/VSyncModulator.cpp diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 4cd0a13861..501d176401 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -149,9 +149,10 @@ filegroup { "Scheduler/LayerHistory.cpp", "Scheduler/LayerInfo.cpp", "Scheduler/MessageQueue.cpp", + "Scheduler/PhaseOffsets.cpp", "Scheduler/Scheduler.cpp", "Scheduler/SchedulerUtils.cpp", - "Scheduler/PhaseOffsets.cpp", + "Scheduler/VSyncModulator.cpp", "StartPropertySetThread.cpp", "SurfaceFlinger.cpp", "SurfaceInterceptor.cpp", diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp new file mode 100644 index 0000000000..af8f445b30 --- /dev/null +++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp @@ -0,0 +1,135 @@ +/* + * 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 "VSyncModulator.h" + +#include +#include + +namespace android { + +void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, + nsecs_t thresholdForNextVsync) { + mEarlyOffsets = early; + mEarlyGlOffsets = earlyGl; + mLateOffsets = late; + mThresholdForNextVsync = thresholdForNextVsync; + + if (mSfConnectionHandle && late.sf != mOffsets.load().sf) { + mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf); + } + + if (mAppConnectionHandle && late.app != mOffsets.load().app) { + mScheduler->setPhaseOffset(mAppConnectionHandle, late.app); + } + mOffsets = late; +} + +void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) { + if (transactionStart == Scheduler::TransactionStart::EARLY) { + mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; + } + + // An early transaction stays an early transaction. + if (transactionStart == mTransactionStart || + mTransactionStart == Scheduler::TransactionStart::EARLY) { + return; + } + mTransactionStart = transactionStart; + updateOffsets(); +} + +void VSyncModulator::onTransactionHandled() { + if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return; + mTransactionStart = Scheduler::TransactionStart::NORMAL; + updateOffsets(); +} + +void VSyncModulator::onRefreshRateChangeInitiated() { + if (mRefreshRateChangePending) { + return; + } + mRefreshRateChangePending = true; + updateOffsets(); +} + +void VSyncModulator::onRefreshRateChangeCompleted() { + if (!mRefreshRateChangePending) { + return; + } + mRefreshRateChangePending = false; + updateOffsets(); +} + +void VSyncModulator::onRefreshed(bool usedRenderEngine) { + bool updateOffsetsNeeded = false; + if (mRemainingEarlyFrameCount > 0) { + mRemainingEarlyFrameCount--; + updateOffsetsNeeded = true; + } + if (usedRenderEngine) { + mRemainingRenderEngineUsageCount = MIN_EARLY_GL_FRAME_COUNT_TRANSACTION; + updateOffsetsNeeded = true; + } else if (mRemainingRenderEngineUsageCount > 0) { + mRemainingRenderEngineUsageCount--; + updateOffsetsNeeded = true; + } + if (updateOffsetsNeeded) { + updateOffsets(); + } +} + +VSyncModulator::Offsets VSyncModulator::getOffsets() { + // Early offsets are used if we're in the middle of a refresh rate + // change, or if we recently begin a transaction. + if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 || + mRefreshRateChangePending) { + return mEarlyOffsets; + } else if (mRemainingRenderEngineUsageCount > 0) { + return mEarlyGlOffsets; + } else { + return mLateOffsets; + } +} + +void VSyncModulator::updateOffsets() { + const Offsets desired = getOffsets(); + const Offsets current = mOffsets; + + bool changed = false; + if (desired.sf != current.sf) { + if (mSfConnectionHandle != nullptr) { + mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); + } else { + mSfEventThread->setPhaseOffset(desired.sf); + } + changed = true; + } + if (desired.app != current.app) { + if (mAppConnectionHandle != nullptr) { + mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); + } else { + mAppEventThread->setPhaseOffset(desired.app); + } + changed = true; + } + + if (changed) { + mOffsets = desired; + } +} + +} // namespace android diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 73a1fb9816..677862e4fe 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -16,8 +16,6 @@ #pragma once -#include - #include #include @@ -41,6 +39,8 @@ private: const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; public: + // Wrapper for a collection of surfaceflinger/app offsets for a particular + // configuration . struct Offsets { nsecs_t sf; nsecs_t app; @@ -57,32 +57,21 @@ public: // appEarlyGl: Like sfEarlyGl, but for the app-vsync. // appLate: The regular app vsync phase offset. void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, - nsecs_t thresholdForNextVsync) { - mEarlyOffsets = early; - mEarlyGlOffsets = earlyGl; - mLateOffsets = late; - mThresholdForNextVsync = thresholdForNextVsync; - - if (mSfConnectionHandle && late.sf != mOffsets.load().sf) { - mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf); - } - - if (mAppConnectionHandle && late.app != mOffsets.load().app) { - mScheduler->setPhaseOffset(mAppConnectionHandle, late.app); - } - - mOffsets = late; - } + nsecs_t thresholdForNextVsync); + // Returns the configured early offsets. Offsets getEarlyOffsets() const { return mEarlyOffsets; } + // Returns the configured early gl offsets. Offsets getEarlyGlOffsets() const { return mEarlyGlOffsets; } + // Sets handles to the SF and app event threads. void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) { mSfEventThread = sfEventThread; mAppEventThread = appEventThread; } + // Sets the scheduler and vsync connection handlers. void setSchedulerAndHandles(Scheduler* scheduler, Scheduler::ConnectionHandle* appConnectionHandle, Scheduler::ConnectionHandle* sfConnectionHandle) { @@ -91,105 +80,31 @@ public: mSfConnectionHandle = sfConnectionHandle; } - void setTransactionStart(Scheduler::TransactionStart transactionStart) { - if (transactionStart == Scheduler::TransactionStart::EARLY) { - mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; - } - - // An early transaction stays an early transaction. - if (transactionStart == mTransactionStart || - mTransactionStart == Scheduler::TransactionStart::EARLY) { - return; - } - mTransactionStart = transactionStart; - updateOffsets(); - } + // Signals that a transaction has started, and changes offsets accordingly. + void setTransactionStart(Scheduler::TransactionStart transactionStart); - void onTransactionHandled() { - if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return; - mTransactionStart = Scheduler::TransactionStart::NORMAL; - updateOffsets(); - } + // Signals that a transaction has been completed, so that we can finish + // special handling for a transaction. + void onTransactionHandled(); // Called when we send a refresh rate change to hardware composer, so that // we can move into early offsets. - void onRefreshRateChangeInitiated() { - if (mRefreshRateChangePending) { - return; - } - mRefreshRateChangePending = true; - updateOffsets(); - } + void onRefreshRateChangeInitiated(); // Called when we detect from vsync signals that the refresh rate changed. // This way we can move out of early offsets if no longer necessary. - void onRefreshRateChangeCompleted() { - if (!mRefreshRateChangePending) { - return; - } - mRefreshRateChangePending = false; - updateOffsets(); - } + void onRefreshRateChangeCompleted(); - void onRefreshed(bool usedRenderEngine) { - bool updateOffsetsNeeded = false; - if (mRemainingEarlyFrameCount > 0) { - mRemainingEarlyFrameCount--; - updateOffsetsNeeded = true; - } - if (usedRenderEngine) { - mRemainingRenderEngineUsageCount = MIN_EARLY_GL_FRAME_COUNT_TRANSACTION; - updateOffsetsNeeded = true; - } else if (mRemainingRenderEngineUsageCount > 0) { - mRemainingRenderEngineUsageCount--; - updateOffsetsNeeded = true; - } - - if (updateOffsetsNeeded) { - updateOffsets(); - } - } + // Called when the display is presenting a new frame. usedRenderEngine + // should be set to true if RenderEngine was involved with composing the new + // frame. + void onRefreshed(bool usedRenderEngine); - Offsets getOffsets() { - // Early offsets are used if we're in the middle of a refresh rate - // change, or if we recently begin a transaction. - if (mTransactionStart == Scheduler::TransactionStart::EARLY || - mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { - return mEarlyOffsets; - } else if (mRemainingRenderEngineUsageCount > 0) { - return mEarlyGlOffsets; - } else { - return mLateOffsets; - } - } + // Returns the offsets that should be used. + Offsets getOffsets(); private: - void updateOffsets() { - const Offsets desired = getOffsets(); - const Offsets current = mOffsets; - - bool changed = false; - if (desired.sf != current.sf) { - if (mSfConnectionHandle != nullptr) { - mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); - } else { - mSfEventThread->setPhaseOffset(desired.sf); - } - changed = true; - } - if (desired.app != current.app) { - if (mAppConnectionHandle != nullptr) { - mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); - } else { - mAppEventThread->setPhaseOffset(desired.app); - } - changed = true; - } - - if (changed) { - mOffsets = desired; - } - } + void updateOffsets(); Offsets mLateOffsets; Offsets mEarlyOffsets; -- GitLab From 43c88661a3df5bec188d82631a403be9e4e47d32 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 13 Jun 2019 17:31:28 -0700 Subject: [PATCH 0230/1255] SurfaceFlinger: Dispsync changePhaseOffset When changing the phase offset of DispSync there is no need to adjust the last event time beyond the diff between the old offset and the new one.. Test: default <-> early offset transition Test: default <-> earlyGL offset transition Bug: 135215384 Change-Id: I436c63914e53ddb53963c590493ee160efb62db8 (cherry picked from commit 2242f72398dfd4a2edc77c0cd1e9987f3ad5f21b) Merged-In: I436c63914e53ddb53963c590493ee160efb62db8 --- services/surfaceflinger/Scheduler/DispSync.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index e59d459242..81be372091 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -288,17 +288,6 @@ public: // new offset to allow for a seamless offset change without double-firing or // skipping. nsecs_t diff = oldPhase - phase; - if (diff > mPeriod / 2) { - diff -= mPeriod; - } else if (diff < -mPeriod / 2) { - diff += mPeriod; - } - - if (phase < 0 && oldPhase > 0) { - diff += mPeriod; - } else if (phase > 0 && oldPhase < 0) { - diff -= mPeriod; - } eventListener.mLastEventTime -= diff; eventListener.mLastCallbackTime -= diff; mCond.signal(); -- GitLab From 38baf72ccb8d1df176255d9756ef697cd4d2ffab Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 22 May 2019 19:58:00 -0700 Subject: [PATCH 0231/1255] [SurfaceFlinger] Add vsync offset information to systrace. * Trace offset values in DispSyncSource * Trace offset type in VSyncModulator * Refactor how offsets are stored so that refresh rate type can be encoded in VSyncModulator * Add locking to catch a potential race condition when updating offsets, as phase offsets can be accessed or updated on multiple threads. Bug: 133325345 Test: verified that correct offsets are reported in systrace Change-Id: I38d43b722cd54728a2e4de3df7dd472aceb1de15 (cherry picked from commit d7599d832c96cc3ba0c2ad19653f29bdfe084284) Merged-In: I38d43b722cd54728a2e4de3df7dd472aceb1de15 --- .../Scheduler/DispSyncSource.cpp | 24 ++++-- .../surfaceflinger/Scheduler/DispSyncSource.h | 6 +- .../surfaceflinger/Scheduler/PhaseOffsets.cpp | 53 +++++++------ .../surfaceflinger/Scheduler/PhaseOffsets.h | 7 +- .../Scheduler/VSyncModulator.cpp | 79 ++++++++++++++----- .../surfaceflinger/Scheduler/VSyncModulator.h | 42 ++++++---- .../tests/unittests/FakePhaseOffsets.h | 14 ++-- 7 files changed, 150 insertions(+), 75 deletions(-) diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 265b8aa47f..026b55707c 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -34,6 +34,8 @@ DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, mTraceVsync(traceVsync), mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)), mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)), + mVsyncOffsetLabel(base::StringPrintf("VsyncOffset-%s", name)), + mVsyncNegativeOffsetLabel(base::StringPrintf("VsyncNegativeOffset-%s", name)), mDispSync(dispSync), mPhaseOffset(phaseOffset), mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {} @@ -41,6 +43,7 @@ DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, void DispSyncSource::setVSyncEnabled(bool enable) { std::lock_guard lock(mVsyncMutex); if (enable) { + tracePhaseOffset(); status_t err = mDispSync->addEventListener(mName, mPhaseOffset, static_cast(this), mLastCallbackTime); @@ -76,6 +79,7 @@ void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) { const int numPeriods = phaseOffset / period; phaseOffset -= numPeriods * period; mPhaseOffset = phaseOffset; + tracePhaseOffset(); // If we're not enabled, we don't need to mess with the listeners if (!mEnabled) { @@ -94,11 +98,11 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) { { std::lock_guard lock(mCallbackMutex); callback = mCallback; + } - if (mTraceVsync) { - mValue = (mValue + 1) % 2; - ATRACE_INT(mVsyncEventLabel.c_str(), mValue); - } + if (mTraceVsync) { + mValue = (mValue + 1) % 2; + ATRACE_INT(mVsyncEventLabel.c_str(), mValue); } if (callback != nullptr) { @@ -106,4 +110,14 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) { } } -} // namespace android \ No newline at end of file +void DispSyncSource::tracePhaseOffset() { + if (mPhaseOffset > 0) { + ATRACE_INT(mVsyncOffsetLabel.c_str(), mPhaseOffset); + ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), 0); + } else { + ATRACE_INT(mVsyncOffsetLabel.c_str(), 0); + ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), -mPhaseOffset); + } +} + +} // namespace android diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h index b6785c5f74..50560a5a2b 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.h +++ b/services/surfaceflinger/Scheduler/DispSyncSource.h @@ -39,12 +39,16 @@ private: // The following method is the implementation of the DispSync::Callback. virtual void onDispSyncEvent(nsecs_t when); + void tracePhaseOffset() REQUIRES(mVsyncMutex); + const char* const mName; int mValue = 0; const bool mTraceVsync; const std::string mVsyncOnLabel; const std::string mVsyncEventLabel; + const std::string mVsyncOffsetLabel; + const std::string mVsyncNegativeOffsetLabel; nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0; DispSync* mDispSync; @@ -58,4 +62,4 @@ private: bool mEnabled GUARDED_BY(mVsyncMutex) = false; }; -} // namespace android \ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 276bce1f89..8a2604f4a3 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -25,6 +25,7 @@ using namespace android::sysprop; namespace scheduler { +using RefreshRateType = RefreshRateConfigs::RefreshRateType; PhaseOffsets::~PhaseOffsets() = default; namespace impl { @@ -72,25 +73,32 @@ PhaseOffsets::PhaseOffsets() { property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1"); const int phaseOffsetThresholdForNextVsyncNs = atoi(value); - mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs - : sfVsyncPhaseOffsetNs, - earlyAppOffsetNs != -1 ? earlyAppOffsetNs - : vsyncPhaseOffsetNs}; - mDefaultRefreshRateOffsets.earlyGl = {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs - : sfVsyncPhaseOffsetNs, - earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs - : vsyncPhaseOffsetNs}; - mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}; - - mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs - : highFpsLateSfOffsetNs, - highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs - : highFpsLateAppOffsetNs}; - mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs - : highFpsLateSfOffsetNs, - highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs - : highFpsLateAppOffsetNs}; - mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}; + Offsets defaultOffsets; + Offsets highFpsOffsets; + defaultOffsets.early = {RefreshRateType::DEFAULT, + earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs, + earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs}; + defaultOffsets.earlyGl = {RefreshRateType::DEFAULT, + earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs, + earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs}; + defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}; + + highFpsOffsets.early = {RefreshRateType::PERFORMANCE, + highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs + : highFpsLateSfOffsetNs, + highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs + : highFpsLateAppOffsetNs}; + highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE, + highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs + : highFpsLateSfOffsetNs, + highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs + : highFpsLateAppOffsetNs}; + highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, + highFpsLateAppOffsetNs}; + + mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets}); + mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets}); + mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets}); mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1 ? phaseOffsetThresholdForNextVsyncNs @@ -99,12 +107,7 @@ PhaseOffsets::PhaseOffsets() { PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate( android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const { - switch (refreshRateType) { - case RefreshRateConfigs::RefreshRateType::PERFORMANCE: - return mHighRefreshRateOffsets; - default: - return mDefaultRefreshRateOffsets; - } + return mOffsets.at(refreshRateType); } void PhaseOffsets::dump(std::string& result) const { diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h index dc71e6eb60..2b5c2f10f1 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.h +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include "RefreshRateConfigs.h" #include "VSyncModulator.h" @@ -79,14 +80,10 @@ public: void dump(std::string& result) const override; private: - Offsets getDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; } - Offsets getHighRefreshRateOffsets() { return mHighRefreshRateOffsets; } - std::atomic mRefreshRateType = RefreshRateConfigs::RefreshRateType::DEFAULT; - Offsets mDefaultRefreshRateOffsets; - Offsets mHighRefreshRateOffsets; + std::unordered_map mOffsets; nsecs_t mOffsetThresholdForNextVsync; }; } // namespace impl diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp index af8f445b30..381308ab34 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp +++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp @@ -14,28 +14,36 @@ * limitations under the License. */ +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + #include "VSyncModulator.h" +#include +#include + #include #include namespace android { +using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; +VSyncModulator::VSyncModulator() { + char value[PROPERTY_VALUE_MAX]; + property_get("debug.sf.vsync_trace_detailed_info", value, "0"); + mTraceDetailedInfo = atoi(value); + // Populate the offset map with some default offsets. + const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0}; + setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0); +} + void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, nsecs_t thresholdForNextVsync) { - mEarlyOffsets = early; - mEarlyGlOffsets = earlyGl; - mLateOffsets = late; + std::lock_guard lock(mMutex); + mOffsetMap.insert_or_assign(OffsetType::Early, early); + mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl); + mOffsetMap.insert_or_assign(OffsetType::Late, late); mThresholdForNextVsync = thresholdForNextVsync; - - if (mSfConnectionHandle && late.sf != mOffsets.load().sf) { - mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf); - } - - if (mAppConnectionHandle && late.app != mOffsets.load().app) { - mScheduler->setPhaseOffset(mAppConnectionHandle, late.app); - } - mOffsets = late; + updateOffsetsLocked(); } void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) { @@ -93,21 +101,35 @@ void VSyncModulator::onRefreshed(bool usedRenderEngine) { } VSyncModulator::Offsets VSyncModulator::getOffsets() { + std::lock_guard lock(mMutex); + return mOffsetMap.at(mOffsetType); +} + +VSyncModulator::Offsets VSyncModulator::getNextOffsets() { + return mOffsetMap.at(getNextOffsetType()); +} + +VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() { // Early offsets are used if we're in the middle of a refresh rate // change, or if we recently begin a transaction. if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { - return mEarlyOffsets; + return OffsetType::Early; } else if (mRemainingRenderEngineUsageCount > 0) { - return mEarlyGlOffsets; + return OffsetType::EarlyGl; } else { - return mLateOffsets; + return OffsetType::Late; } } void VSyncModulator::updateOffsets() { - const Offsets desired = getOffsets(); - const Offsets current = mOffsets; + std::lock_guard lock(mMutex); + updateOffsetsLocked(); +} + +void VSyncModulator::updateOffsetsLocked() { + const Offsets desired = getNextOffsets(); + const Offsets current = mOffsetMap.at(mOffsetType); bool changed = false; if (desired.sf != current.sf) { @@ -128,8 +150,29 @@ void VSyncModulator::updateOffsets() { } if (changed) { - mOffsets = desired; + updateOffsetType(); + } +} + +void VSyncModulator::updateOffsetType() { + mOffsetType = getNextOffsetType(); + if (!mTraceDetailedInfo) { + return; } + OffsetType type = mOffsetType; + Offsets offsets = mOffsetMap.at(type); + ATRACE_INT("Vsync-EarlyOffsetsOn", + offsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early); + ATRACE_INT("Vsync-EarlyGLOffsetsOn", + offsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl); + ATRACE_INT("Vsync-LateOffsetsOn", + offsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late); + ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", + offsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early); + ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", + offsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl); + ATRACE_INT("Vsync-HighFpsLateOffsetsOn", + offsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late); } } // namespace android diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 677862e4fe..c6374be83a 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -39,13 +39,22 @@ private: const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; public: + VSyncModulator(); + // Wrapper for a collection of surfaceflinger/app offsets for a particular // configuration . struct Offsets { + scheduler::RefreshRateConfigs::RefreshRateType fpsMode; nsecs_t sf; nsecs_t app; }; + enum class OffsetType { + Early, + EarlyGl, + Late, + }; + // Sets the phase offsets // // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction @@ -57,13 +66,7 @@ public: // appEarlyGl: Like sfEarlyGl, but for the app-vsync. // appLate: The regular app vsync phase offset. void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, - nsecs_t thresholdForNextVsync); - - // Returns the configured early offsets. - Offsets getEarlyOffsets() const { return mEarlyOffsets; } - - // Returns the configured early gl offsets. - Offsets getEarlyGlOffsets() const { return mEarlyGlOffsets; } + nsecs_t thresholdForNextVsync) EXCLUDES(mMutex); // Sets handles to the SF and app event threads. void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) { @@ -100,15 +103,22 @@ public: // frame. void onRefreshed(bool usedRenderEngine); - // Returns the offsets that should be used. - Offsets getOffsets(); + // Returns the offsets that we are currently using + Offsets getOffsets() EXCLUDES(mMutex); private: - void updateOffsets(); - - Offsets mLateOffsets; - Offsets mEarlyOffsets; - Offsets mEarlyGlOffsets; + // Returns the next offsets that we should be using + Offsets getNextOffsets() REQUIRES(mMutex); + // Returns the next offset type that we should use. + OffsetType getNextOffsetType(); + // Updates offsets and persists them into the scheduler framework. + void updateOffsets() EXCLUDES(mMutex); + void updateOffsetsLocked() REQUIRES(mMutex); + // Updates the internal offset type. + void updateOffsetType() REQUIRES(mMutex); + + mutable std::mutex mMutex; + std::unordered_map mOffsetMap GUARDED_BY(mMutex); nsecs_t mThresholdForNextVsync; EventThread* mSfEventThread = nullptr; @@ -118,13 +128,15 @@ private: Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr; Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr; - std::atomic mOffsets; + OffsetType mOffsetType GUARDED_BY(mMutex) = OffsetType::Late; std::atomic mTransactionStart = Scheduler::TransactionStart::NORMAL; std::atomic mRefreshRateChangePending = false; std::atomic mRemainingEarlyFrameCount = 0; std::atomic mRemainingRenderEngineUsageCount = 0; + + bool mTraceDetailedInfo = false; }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h index 96121bb088..1d7501102e 100644 --- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h +++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h @@ -23,6 +23,8 @@ namespace android { namespace scheduler { +using RefreshRateType = RefreshRateConfigs::RefreshRateType; + class FakePhaseOffsets : public android::scheduler::PhaseOffsets { nsecs_t FAKE_PHASE_OFFSET_NS = 0; @@ -34,20 +36,20 @@ public: nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; } PhaseOffsets::Offsets getOffsetsForRefreshRate( - RefreshRateConfigs::RefreshRateType /*refreshRateType*/) const override { + RefreshRateType /*refreshRateType*/) const override { return getCurrentOffsets(); } // Returns early, early GL, and late offsets for Apps and SF. PhaseOffsets::Offsets getCurrentOffsets() const override { - return Offsets{{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}}; + return Offsets{{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}}; } // This function should be called when the device is switching between different // refresh rates, to properly update the offsets. - void setRefreshRateType(RefreshRateConfigs::RefreshRateType /*refreshRateType*/) override {} + void setRefreshRateType(RefreshRateType /*refreshRateType*/) override {} nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; } @@ -56,4 +58,4 @@ public: }; } // namespace scheduler -} // namespace android \ No newline at end of file +} // namespace android -- GitLab From 886c22b00b944d66389c8ad16354c440f3d10047 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 21 Jun 2019 16:27:05 -0700 Subject: [PATCH 0232/1255] [SurfaceFlinger] Store current offsets in VSyncModulator. This way updated offsets are properly persisted to DispSyncSource. Bug: 135770834 Test: systrace shows correct offsets Change-Id: I34ed81ebecfa8a4f9826d4a7713da0ec0a8b23de (cherry picked from commit b656aed06739e5a5ec7563970452237dca431edd) Merged-In: I34ed81ebecfa8a4f9826d4a7713da0ec0a8b23de --- .../Scheduler/VSyncModulator.cpp | 29 +++++++++---------- .../surfaceflinger/Scheduler/VSyncModulator.h | 6 ++-- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp index 381308ab34..d452c19b68 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp +++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp @@ -102,7 +102,7 @@ void VSyncModulator::onRefreshed(bool usedRenderEngine) { VSyncModulator::Offsets VSyncModulator::getOffsets() { std::lock_guard lock(mMutex); - return mOffsetMap.at(mOffsetType); + return mOffsets; } VSyncModulator::Offsets VSyncModulator::getNextOffsets() { @@ -129,13 +129,13 @@ void VSyncModulator::updateOffsets() { void VSyncModulator::updateOffsetsLocked() { const Offsets desired = getNextOffsets(); - const Offsets current = mOffsetMap.at(mOffsetType); + const Offsets current = mOffsets; bool changed = false; if (desired.sf != current.sf) { if (mSfConnectionHandle != nullptr) { mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); - } else { + } else if (mSfEventThread != nullptr) { mSfEventThread->setPhaseOffset(desired.sf); } changed = true; @@ -143,36 +143,35 @@ void VSyncModulator::updateOffsetsLocked() { if (desired.app != current.app) { if (mAppConnectionHandle != nullptr) { mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); - } else { + } else if (mAppEventThread != nullptr) { mAppEventThread->setPhaseOffset(desired.app); } changed = true; } if (changed) { - updateOffsetType(); + flushOffsets(); } } -void VSyncModulator::updateOffsetType() { - mOffsetType = getNextOffsetType(); +void VSyncModulator::flushOffsets() { + OffsetType type = getNextOffsetType(); + mOffsets = mOffsetMap.at(type); if (!mTraceDetailedInfo) { return; } - OffsetType type = mOffsetType; - Offsets offsets = mOffsetMap.at(type); ATRACE_INT("Vsync-EarlyOffsetsOn", - offsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early); + mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early); ATRACE_INT("Vsync-EarlyGLOffsetsOn", - offsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl); + mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl); ATRACE_INT("Vsync-LateOffsetsOn", - offsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late); + mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late); ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", - offsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early); + mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early); ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", - offsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl); + mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl); ATRACE_INT("Vsync-HighFpsLateOffsetsOn", - offsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late); + mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late); } } // namespace android diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index c6374be83a..10cf8e6cc9 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -114,8 +114,8 @@ private: // Updates offsets and persists them into the scheduler framework. void updateOffsets() EXCLUDES(mMutex); void updateOffsetsLocked() REQUIRES(mMutex); - // Updates the internal offset type. - void updateOffsetType() REQUIRES(mMutex); + // Updates the internal offsets and offset type. + void flushOffsets() REQUIRES(mMutex); mutable std::mutex mMutex; std::unordered_map mOffsetMap GUARDED_BY(mMutex); @@ -128,7 +128,7 @@ private: Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr; Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr; - OffsetType mOffsetType GUARDED_BY(mMutex) = OffsetType::Late; + Offsets mOffsets GUARDED_BY(mMutex) = {Scheduler::RefreshRateType::DEFAULT, 0, 0}; std::atomic mTransactionStart = Scheduler::TransactionStart::NORMAL; -- GitLab From 32e89bc58c6b6f2ac5a802a9abcb24ea8e4489b7 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 19 Jun 2019 17:01:57 -0700 Subject: [PATCH 0233/1255] SurfaceFlinger: DispSync: negative offsets when model is unlocked When getting a HWVsync timestamp in DispSync, we correct the last event time to reflect the actual HWVsync time by setting it based on HWVsync. This logic needs to account for both positive and negative offsets. Bug: 135631964 Test: sanity Change-Id: I77a1e13d739e558d6cdf43c298e6fcee49d517b5 (cherry picked from commit 81ca00ff8cd05913fe0e97e0f97b3a9ae7ed3299) --- services/surfaceflinger/Scheduler/DispSync.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index 81be372091..83fd42b43f 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -92,8 +92,12 @@ public: mPeriod = period; if (!mModelLocked && referenceTimeChanged) { for (auto& eventListener : mEventListeners) { - eventListener.mLastEventTime = - mReferenceTime - mPeriod + mPhase + eventListener.mPhase; + eventListener.mLastEventTime = mReferenceTime + mPhase + eventListener.mPhase; + // If mLastEventTime is after mReferenceTime (can happen when positive phase offsets + // are used) we treat it as like it happened in previous period. + if (eventListener.mLastEventTime > mReferenceTime) { + eventListener.mLastEventTime -= mPeriod; + } } } if (mTraceDetailedInfo) { -- GitLab From 9f10eb9cb8300c6cd5965078c5a767dd077e0707 Mon Sep 17 00:00:00 2001 From: Ana Krulec Date: Wed, 26 Jun 2019 16:28:08 -0700 Subject: [PATCH 0234/1255] SF: Don't bump to PERFORMANCE refresh rate with infrequent updates Testing scenario: 1. Set brightness around 50%-55%, set dark theme. 2. Open Chrome. 3. Click search bar. 4. Can see the cursor show up. Notice the flickering of the screen. Explanation: Kernel idle timer detects inactivity after 100ms, and turns the refresh rate to 60Hz. When a cursor update happens (every 500ms), SF receives a new frame, notifies kernel, the refresh rate bumps to 90Hz. After 100ms the kernel again decreases the refresh rate to 60Hz. Desired goals: Stop the flickering (eg. changing between 60-90Hz too often). Continue having low battery impact. Solution in this AG: Add logic to SF to detect infrequent updates (for all layers). Description of the algorithm: 1) Store the timestamp of the last two buffers. 2) If the first buffer is older than 250 ms, detect inactivity, go into DEFAULT refresh rate. 3) EXIT: on touch event, layer requests 2 or more frames in less than 250ms. NOTE: if the application is explicitly requesting 90Hz, SF does not override that. Idle kernel still kicks in, and the flickering happens. tested on Chrome v74 Beta, and messaging app. Test: manual, b/135009095 Bug: 135718869 Change-Id: I72d8cd48b3ec900989afcf0fab1cdc3046b87274 (cherry picked from commit ad083c40b7593e0cc9283588ac710ddf2124337a) Merged-In: I72d8cd48b3ec900989afcf0fab1cdc3046b87274 --- .../surfaceflinger/Scheduler/LayerHistory.cpp | 4 +- .../surfaceflinger/Scheduler/LayerHistory.h | 3 +- .../surfaceflinger/Scheduler/LayerInfo.cpp | 5 +- services/surfaceflinger/Scheduler/LayerInfo.h | 47 ++++++++++++++++--- .../surfaceflinger/Scheduler/Scheduler.cpp | 7 ++- .../surfaceflinger/Scheduler/SchedulerUtils.h | 15 +++--- .../tests/unittests/LayerHistoryTest.cpp | 17 +++---- 7 files changed, 72 insertions(+), 26 deletions(-) diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index e762af3ec5..f80c2336f7 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -46,11 +46,13 @@ LayerHistory::LayerHistory() { LayerHistory::~LayerHistory() = default; std::unique_ptr LayerHistory::createLayer(const std::string name, + float minRefreshRate, float maxRefreshRate) { const int64_t id = sNextId++; std::lock_guard lock(mLock); - mInactiveLayerInfos.emplace(id, std::make_shared(name, maxRefreshRate)); + mInactiveLayerInfos.emplace(id, + std::make_shared(name, minRefreshRate, maxRefreshRate)); return std::make_unique(*this, id); } diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 2569b4638a..5598cc1cf5 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -53,7 +53,8 @@ public: ~LayerHistory(); // When the layer is first created, register it. - std::unique_ptr createLayer(const std::string name, float maxRefreshRate); + std::unique_ptr createLayer(const std::string name, float minRefreshRate, + float maxRefreshRate); // Method for inserting layers and their requested present time into the unordered map. void insert(const std::unique_ptr& layerHandle, nsecs_t presentTime, bool isHdr); diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 49194f9de5..38afb7ed29 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -24,9 +24,10 @@ namespace android { namespace scheduler { -LayerInfo::LayerInfo(const std::string name, float maxRefreshRate) +LayerInfo::LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate) : mName(name), mMinRefreshDuration(1e9f / maxRefreshRate), + mLowActivityRefreshDuration(1e9f / minRefreshRate), mRefreshRateHistory(mMinRefreshDuration) {} LayerInfo::~LayerInfo() = default; @@ -41,7 +42,7 @@ void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime) { const nsecs_t timeDiff = lastPresentTime - mLastPresentTime; mLastPresentTime = lastPresentTime; // Ignore time diff that are too high - those are stale values - if (timeDiff > TIME_EPSILON_NS.count()) return; + if (timeDiff > OBSOLETE_TIME_EPSILON_NS.count()) return; const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration; const int fps = 1e9f / refreshDuration; mRefreshRateHistory.insertRefreshRate(fps); diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index f08fa939a6..66df9dca20 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -86,13 +86,42 @@ class LayerInfo { // Checks whether the present time that was inserted HISTORY_SIZE ago is within a // certain threshold: TIME_EPSILON_NS. bool isRelevant() const { - const int64_t obsoleteEpsilon = systemTime() - scheduler::TIME_EPSILON_NS.count(); - // The layer had to publish at least HISTORY_SIZE of updates, and the first - // update should not be older than TIME_EPSILON_NS nanoseconds. - if (mElements.size() == HISTORY_SIZE && - mElements.at(HISTORY_SIZE - 1) > obsoleteEpsilon) { + if (mElements.size() < 2) { + return false; + } + + // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates + if (mElements.size() != HISTORY_SIZE && + mElements.at(mElements.size() - 1) - mElements.at(0) < HISTORY_TIME.count()) { + return false; + } + + // The last update should not be older than OBSOLETE_TIME_EPSILON_NS nanoseconds. + const int64_t obsoleteEpsilon = + systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count(); + if (mElements.at(mElements.size() - 1) < obsoleteEpsilon) { + return false; + } + + return true; + } + + bool isLowActivityLayer() const { + // We want to make sure that we received more than two frames from the layer + // in order to check low activity. + if (mElements.size() < 2) { + return false; + } + + const int64_t obsoleteEpsilon = + systemTime() - scheduler::LOW_ACTIVITY_EPSILON_NS.count(); + // Check the frame before last to determine whether there is low activity. + // If that frame is older than LOW_ACTIVITY_EPSILON_NS, the layer is sending + // infrequent updates. + if (mElements.at(mElements.size() - 2) < obsoleteEpsilon) { return true; } + return false; } @@ -101,10 +130,11 @@ class LayerInfo { private: std::deque mElements; static constexpr size_t HISTORY_SIZE = 10; + static constexpr std::chrono::nanoseconds HISTORY_TIME = 500ms; }; public: - LayerInfo(const std::string name, float maxRefreshRate); + LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate); ~LayerInfo(); LayerInfo(const LayerInfo&) = delete; @@ -134,6 +164,10 @@ public: // Calculate the average refresh rate. float getDesiredRefreshRate() const { std::lock_guard lock(mLock); + + if (mPresentTimeHistory.isLowActivityLayer()) { + return 1e9f / mLowActivityRefreshDuration; + } return mRefreshRateHistory.getRefreshRateAvg(); } @@ -165,6 +199,7 @@ public: private: const std::string mName; const nsecs_t mMinRefreshDuration; + const nsecs_t mLowActivityRefreshDuration; mutable std::mutex mLock; nsecs_t mLastUpdatedTime GUARDED_BY(mLock) = 0; nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index bb24f73834..99d6faee1c 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -330,8 +330,11 @@ std::unique_ptr Scheduler::registerLayer( : RefreshRateType::PERFORMANCE; const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType); - const uint32_t fps = (refreshRate) ? refreshRate->fps : 0; - return mLayerHistory.createLayer(name, fps); + const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0; + + const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT); + const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0; + return mLayerHistory.createLayer(name, defaultFps, performanceFps); } void Scheduler::addLayerPresentTimeAndHDR( diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h index 3bf3922edd..ced1899109 100644 --- a/services/surfaceflinger/Scheduler/SchedulerUtils.h +++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h @@ -36,13 +36,16 @@ static constexpr size_t ARRAY_SIZE = 30; static constexpr int SCREEN_OFF_CONFIG_ID = -1; static constexpr uint32_t HWC2_SCREEN_OFF_CONFIG_ID = 0xffffffff; -// This number is used when we try to determine how long does a given layer stay relevant. -// Currently it is set to 100ms, because that would indicate 10Hz rendering. -static constexpr std::chrono::nanoseconds TIME_EPSILON_NS = 100ms; - // This number is used when we try to determine how long do we keep layer information around -// before we remove it. Currently it is set to 100ms. -static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 100ms; +// before we remove it. It is also used to determine how long the layer stays relevant. +// This time period captures infrequent updates when playing YouTube video with static image, +// or waiting idle in messaging app, when cursor is blinking. +static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 1200ms; + +// Layer is considered low activity if the buffers come more than LOW_ACTIVITY_EPSILON_NS +// apart. This is helping SF to vote for lower refresh rates when there is not activity +// in screen. +static constexpr std::chrono::nanoseconds LOW_ACTIVITY_EPSILON_NS = 250ms; // Calculates the statistical mean (average) in the data structure (array, vector). The // function does not modify the contents of the array. diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 2b1dfa8f38..7ec90660ce 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -25,6 +25,7 @@ public: protected: std::unique_ptr mLayerHistory; + static constexpr float MIN_REFRESH_RATE = 30.f; static constexpr float MAX_REFRESH_RATE = 90.f; }; @@ -36,7 +37,7 @@ LayerHistoryTest::~LayerHistoryTest() {} namespace { TEST_F(LayerHistoryTest, oneLayer) { std::unique_ptr testLayer = - mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(testLayer, true); mLayerHistory->insert(testLayer, 0, false /*isHDR*/); @@ -60,7 +61,7 @@ TEST_F(LayerHistoryTest, oneLayer) { TEST_F(LayerHistoryTest, oneHDRLayer) { std::unique_ptr testLayer = - mLayerHistory->createLayer("TestHDRLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("TestHDRLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(testLayer, true); mLayerHistory->insert(testLayer, 0, true /*isHDR*/); @@ -74,7 +75,7 @@ TEST_F(LayerHistoryTest, oneHDRLayer) { TEST_F(LayerHistoryTest, explicitTimestamp) { std::unique_ptr test30FpsLayer = - mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(test30FpsLayer, true); nsecs_t startTime = systemTime(); @@ -87,13 +88,13 @@ TEST_F(LayerHistoryTest, explicitTimestamp) { TEST_F(LayerHistoryTest, multipleLayers) { std::unique_ptr testLayer = - mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(testLayer, true); std::unique_ptr test30FpsLayer = - mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(test30FpsLayer, true); std::unique_ptr testLayer2 = - mLayerHistory->createLayer("TestLayer2", MAX_REFRESH_RATE); + mLayerHistory->createLayer("TestLayer2", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(testLayer2, true); nsecs_t startTime = systemTime(); @@ -119,8 +120,8 @@ TEST_F(LayerHistoryTest, multipleLayers) { mLayerHistory->insert(testLayer2, 0, false /*isHDR*/); } EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); - // After 100 ms frames become obsolete. - std::this_thread::sleep_for(std::chrono::milliseconds(500)); + // After 1200 ms frames become obsolete. + std::this_thread::sleep_for(std::chrono::milliseconds(1500)); // Insert the 31st frame. mLayerHistory->insert(test30FpsLayer, startTime + (30 * 33333333), false /*isHDR*/); EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first); -- GitLab From 4b494ee9adff8b4ed5cd25c1c1e3881fb550d449 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 2 Jul 2019 14:29:18 -0700 Subject: [PATCH 0235/1255] Surfaceflinger: adjust content detection fps selection Select the FPS with minimal error in the first pass and then adjust based on ratio/margin. The CL changes content driven FPS selection logic, before the change, the code switch to 90hz configs when mContentRefreshRate > 64 and with the CL it will switch to 90hz when mContentRefreshRate > 75. The second pass to select 90hz when mContentRefreshRate is 45fps is kept as is. It also simplified and removed 5% margin in the first pass. Test: boot and take SF trace Bug: 136472613 Change-Id: I4445386a301b7fcdd22d71bd49f45540cc414174 (cherry picked from commit 09be73f64603ef71074d9fbf553fec5c7652d283) Merged-In: I4445386a301b7fcdd22d71bd49f45540cc414174 --- .../surfaceflinger/Scheduler/Scheduler.cpp | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 99d6faee1c..cfdbd91e35 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -523,22 +523,19 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { return RefreshRateType::PERFORMANCE; } - // Content detection is on, find the appropriate refresh rate - // Start with the smallest refresh rate which is within a margin of the content - RefreshRateType currRefreshRateType = RefreshRateType::PERFORMANCE; - constexpr float MARGIN = 0.05f; - auto iter = mRefreshRateConfigs.getRefreshRates().cbegin(); - while (iter != mRefreshRateConfigs.getRefreshRates().cend()) { - if (iter->second->fps >= mContentRefreshRate * (1 - MARGIN)) { - currRefreshRateType = iter->first; - break; - } - ++iter; - } + // Content detection is on, find the appropriate refresh rate with minimal error + auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(), + mRefreshRateConfigs.getRefreshRates().cend(), + [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool { + return std::abs(l.second->fps - static_cast(rate)) < + std::abs(r.second->fps - static_cast(rate)); + }); + RefreshRateType currRefreshRateType = iter->first; // Some content aligns better on higher refresh rate. For example for 45fps we should choose // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't // align well with both + constexpr float MARGIN = 0.05f; float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / float(mContentRefreshRate); if (std::abs(std::round(ratio) - ratio) > MARGIN) { -- GitLab From d4043c8873e923e90bd062afeee49688217a39ca Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 9 Jul 2019 18:09:52 -0700 Subject: [PATCH 0236/1255] SurfaceFlinger: add allowed display configs to dumpsys Dump the allowed display configs from SurfaceFlinger to help with debugging issues where the refresh rate does not match the policy. Test: adb shell dumpsys SurfaceFlinger Bug: 136503733 Change-Id: I74ec7d08901ad9edb1a3706249e8809574bf1e5f (cherry picked from commit 42b3beb51f7f3e97762ed1db7ebc0decbfa56bb4) Merged-In: I74ec7d08901ad9edb1a3706249e8809574bf1e5f --- services/surfaceflinger/SurfaceFlinger.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5da3544b51..0b89e9887c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4701,6 +4701,16 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { StringAppendF(&result, "Scheduler enabled."); StringAppendF(&result, "+ Smart 90 for video detection: %s\n\n", mUseSmart90ForVideo ? "on" : "off"); + StringAppendF(&result, "Allowed Display Configs: "); + for (int32_t configId : mAllowedDisplayConfigs) { + for (auto refresh : mRefreshRateConfigs.getRefreshRates()) { + if (refresh.second && refresh.second->configId == configId) { + StringAppendF(&result, "%dHz, ", refresh.second->fps); + } + } + } + StringAppendF(&result, "(config override by backdoor: %s)\n\n", + mDebugDisplayConfigSetByBackdoor ? "yes" : "no"); mScheduler->dump(mAppConnectionHandle, result); } -- GitLab From 5c08044a21b2c711f4bcafdf8a3e2d59f5683a7b Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 27 Jun 2019 11:24:19 -0700 Subject: [PATCH 0237/1255] SurfaceFlinger: correct negative offset when refresh rate changes VsyncModulator sets the phase offset on DispSync source only when it changes. However, negative offsets depends on the vsync period so setting the same negative offset might result in a different wake up time i.e. -5ms on 60Hz is 11ms after the previous vsync where on 90Hz is 6ms after the previous vsync. Test: UI-Bench Bug: 135283780 Bug: 135297302 Change-Id: I6a05cd48d563a51d2ee38927c23d4946dd142f4b (cherry picked from commit 11b6a70c6f6780f2f878ed3e103b5ffbb0b8fc26) Merged-In: I6a05cd48d563a51d2ee38927c23d4946dd142f4b --- .../Scheduler/DispSyncSource.cpp | 4 +++ .../Scheduler/VSyncModulator.cpp | 27 +++++-------------- .../surfaceflinger/Scheduler/VSyncModulator.h | 9 ------- 3 files changed, 11 insertions(+), 29 deletions(-) diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 026b55707c..5faf46e31e 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -78,6 +78,10 @@ void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) { // Normalize phaseOffset to [-period, period) const int numPeriods = phaseOffset / period; phaseOffset -= numPeriods * period; + if (mPhaseOffset == phaseOffset) { + return; + } + mPhaseOffset = phaseOffset; tracePhaseOffset(); diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp index d452c19b68..7a3bf8edaf 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp +++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp @@ -129,29 +129,16 @@ void VSyncModulator::updateOffsets() { void VSyncModulator::updateOffsetsLocked() { const Offsets desired = getNextOffsets(); - const Offsets current = mOffsets; - - bool changed = false; - if (desired.sf != current.sf) { - if (mSfConnectionHandle != nullptr) { - mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); - } else if (mSfEventThread != nullptr) { - mSfEventThread->setPhaseOffset(desired.sf); - } - changed = true; - } - if (desired.app != current.app) { - if (mAppConnectionHandle != nullptr) { - mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); - } else if (mAppEventThread != nullptr) { - mAppEventThread->setPhaseOffset(desired.app); - } - changed = true; + + if (mSfConnectionHandle != nullptr) { + mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); } - if (changed) { - flushOffsets(); + if (mAppConnectionHandle != nullptr) { + mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); } + + flushOffsets(); } void VSyncModulator::flushOffsets() { diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 10cf8e6cc9..ddbd221ef1 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -68,12 +68,6 @@ public: void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, nsecs_t thresholdForNextVsync) EXCLUDES(mMutex); - // Sets handles to the SF and app event threads. - void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) { - mSfEventThread = sfEventThread; - mAppEventThread = appEventThread; - } - // Sets the scheduler and vsync connection handlers. void setSchedulerAndHandles(Scheduler* scheduler, Scheduler::ConnectionHandle* appConnectionHandle, @@ -121,9 +115,6 @@ private: std::unordered_map mOffsetMap GUARDED_BY(mMutex); nsecs_t mThresholdForNextVsync; - EventThread* mSfEventThread = nullptr; - EventThread* mAppEventThread = nullptr; - Scheduler* mScheduler = nullptr; Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr; Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr; -- GitLab From a133f037f065748098152b4c743f50447f3bbaea Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 12 Jul 2019 12:37:57 -0700 Subject: [PATCH 0238/1255] SurfaceFlinger: add display power state timer Coming out of DOZE mode might result in unstable HWVsync which may confuse FPS detection logic to set the desired refresh rate. To mitigate that, this change introduces a new timer that will provide a grace period when coming out of DOZE while in this grace period refresh rate will stay in PERFORMANCE. Test: Toggle DOZE by hitting the power button and collect systrace Bug: 135550670 Change-Id: Ib8ec3c9550336d691dd3868405d20b98aa983302 (cherry picked from commit 24363178b53efbc7a794bc72fe3b6e5fa4078ce6) Merged-In: Ib8ec3c9550336d691dd3868405d20b98aa983302 --- .../surfaceflinger/Scheduler/Scheduler.cpp | 82 ++++++++++++------- services/surfaceflinger/Scheduler/Scheduler.h | 22 ++++- services/surfaceflinger/SurfaceFlinger.cpp | 1 + .../SurfaceFlingerProperties.cpp | 8 ++ .../surfaceflinger/SurfaceFlingerProperties.h | 2 + .../sysprop/SurfaceFlingerProperties.sysprop | 12 +++ .../sysprop/api/system-current.txt | 1 + 7 files changed, 96 insertions(+), 32 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index cfdbd91e35..a7784e9315 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -76,6 +76,7 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, mSupportKernelTimer = support_kernel_idle_timer(false); mSetTouchTimerMs = set_touch_timer_ms(0); + mSetDisplayPowerTimerMs = set_display_power_timer_ms(0); char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.set_idle_timer_ms", value, "0"); @@ -110,10 +111,22 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, [this] { expiredTouchTimerCallback(); }); mTouchTimer->start(); } + + if (mSetDisplayPowerTimerMs > 0) { + mDisplayPowerTimer = + std::make_unique(std::chrono::milliseconds( + mSetDisplayPowerTimerMs), + [this] { resetDisplayPowerTimerCallback(); }, + [this] { + expiredDisplayPowerTimerCallback(); + }); + mDisplayPowerTimer->start(); + } } Scheduler::~Scheduler() { // Ensure the IdleTimer thread is joined before we start destroying state. + mDisplayPowerTimer.reset(); mTouchTimer.reset(); mIdleTimer.reset(); } @@ -419,8 +432,23 @@ void Scheduler::notifyTouchEvent() { mLayerHistory.clearHistory(); } +void Scheduler::setDisplayPowerState(bool normal) { + { + std::lock_guard lock(mFeatureStateLock); + mIsDisplayPowerStateNormal = normal; + } + + if (mDisplayPowerTimer) { + mDisplayPowerTimer->reset(); + } + + // Display Power event will boost the refresh rate to performance. + // Clear Layer History to get fresh FPS detection + mLayerHistory.clearHistory(); +} + void Scheduler::resetTimerCallback() { - timerChangeRefreshRate(IdleTimerState::RESET); + handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::RESET, false); ATRACE_INT("ExpiredIdleTimer", 0); } @@ -433,22 +461,30 @@ void Scheduler::resetKernelTimerCallback() { } void Scheduler::expiredTimerCallback() { - timerChangeRefreshRate(IdleTimerState::EXPIRED); + handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::EXPIRED, false); ATRACE_INT("ExpiredIdleTimer", 1); } void Scheduler::resetTouchTimerCallback() { - // We do not notify the applications about config changes when idle timer is reset. - touchChangeRefreshRate(TouchState::ACTIVE); + handleTimerStateChanged(&mCurrentTouchState, TouchState::ACTIVE, true); ATRACE_INT("TouchState", 1); } void Scheduler::expiredTouchTimerCallback() { - // We do not notify the applications about config changes when idle timer expires. - touchChangeRefreshRate(TouchState::INACTIVE); + handleTimerStateChanged(&mCurrentTouchState, TouchState::INACTIVE, true); ATRACE_INT("TouchState", 0); } +void Scheduler::resetDisplayPowerTimerCallback() { + handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::RESET, true); + ATRACE_INT("ExpiredDisplayPowerTimer", 0); +} + +void Scheduler::expiredDisplayPowerTimerCallback() { + handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::EXPIRED, true); + ATRACE_INT("ExpiredDisplayPowerTimer", 1); +} + void Scheduler::expiredKernelTimerCallback() { ATRACE_INT("ExpiredKernelIdleTimer", 1); // Disable HW Vsync if the timer expired, as we don't need it @@ -463,39 +499,23 @@ std::string Scheduler::doDump() { return stream.str(); } -void Scheduler::timerChangeRefreshRate(IdleTimerState idleTimerState) { - RefreshRateType newRefreshRateType; - { - std::lock_guard lock(mFeatureStateLock); - if (mCurrentIdleTimerState == idleTimerState) { - return; - } - mCurrentIdleTimerState = idleTimerState; - newRefreshRateType = calculateRefreshRateType(); - if (mRefreshRateType == newRefreshRateType) { - return; - } - mRefreshRateType = newRefreshRateType; - } - changeRefreshRate(newRefreshRateType, ConfigEvent::None); -} - -void Scheduler::touchChangeRefreshRate(TouchState touchState) { +template +void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) { ConfigEvent event = ConfigEvent::None; RefreshRateType newRefreshRateType; { std::lock_guard lock(mFeatureStateLock); - if (mCurrentTouchState == touchState) { + if (*currentState == newState) { return; } - mCurrentTouchState = touchState; + *currentState = newState; newRefreshRateType = calculateRefreshRateType(); if (mRefreshRateType == newRefreshRateType) { return; } mRefreshRateType = newRefreshRateType; - // Send an event in case that content detection is on as touch has a higher priority - if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) { + if (eventOnContentDetection && + mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) { event = ConfigEvent::Changed; } } @@ -508,6 +528,12 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { return RefreshRateType::DEFAULT; } + // 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 (!mIsDisplayPowerStateNormal || mDisplayPowerTimerState == DisplayPowerTimerState::RESET) { + return RefreshRateType::PERFORMANCE; + } + // As long as touch is active we want to be in performance mode if (mCurrentTouchState == TouchState::ACTIVE) { return RefreshRateType::PERFORMANCE; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index eaad37c3ee..39c39d7639 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -177,6 +177,9 @@ public: // Function that resets the touch timer. void notifyTouchEvent(); + // Function that sets whether display power mode is normal or not. + void setDisplayPowerState(bool normal); + // Returns relevant information about Scheduler for dumpsys purposes. std::string doDump(); @@ -197,6 +200,7 @@ private: enum class ContentFeatureState { CONTENT_DETECTION_ON, CONTENT_DETECTION_OFF }; enum class IdleTimerState { EXPIRED, RESET }; enum class TouchState { INACTIVE, ACTIVE }; + enum class DisplayPowerTimerState { EXPIRED, RESET }; // Creates a connection on the given EventThread and forwards the given callbacks. sp createConnectionInternal(EventThread*, ResyncCallback&&, @@ -221,12 +225,15 @@ private: void resetTouchTimerCallback(); // Function that is called when the touch timer expires. void expiredTouchTimerCallback(); + // Function that is called when the display power timer resets. + void resetDisplayPowerTimerCallback(); + // Function that is called when the display power timer expires. + void expiredDisplayPowerTimerCallback(); // Sets vsync period. void setVsyncPeriod(const nsecs_t period); - // Idle timer feature's function to change the refresh rate. - void timerChangeRefreshRate(IdleTimerState idleTimerState); - // Touch timer feature's function to change the refresh rate. - void touchChangeRefreshRate(TouchState touchState); + // handles various timer features to change the refresh rate. + template + void handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection); // Calculate the new refresh rate type RefreshRateType calculateRefreshRateType() REQUIRES(mFeatureStateLock); // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters. @@ -282,6 +289,10 @@ private: int64_t mSetTouchTimerMs = 0; std::unique_ptr mTouchTimer; + // Timer used to monitor display power mode. + int64_t mSetDisplayPowerTimerMs = 0; + std::unique_ptr mDisplayPowerTimer; + std::mutex mCallbackLock; ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock); GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock); @@ -293,9 +304,12 @@ private: ContentFeatureState::CONTENT_DETECTION_OFF; IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET; TouchState mCurrentTouchState GUARDED_BY(mFeatureStateLock) = TouchState::INACTIVE; + DisplayPowerTimerState mDisplayPowerTimerState GUARDED_BY(mFeatureStateLock) = + DisplayPowerTimerState::EXPIRED; uint32_t mContentRefreshRate GUARDED_BY(mFeatureStateLock); RefreshRateType mRefreshRateType GUARDED_BY(mFeatureStateLock); bool mIsHDRContent GUARDED_BY(mFeatureStateLock) = false; + bool mIsDisplayPowerStateNormal GUARDED_BY(mFeatureStateLock) = true; const scheduler::RefreshRateConfigs& mRefreshRateConfigs; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a2c87bdfe6..5caf883a69 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4540,6 +4540,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, int if (display->isPrimary()) { mTimeStats->setPowerMode(mode); mRefreshRateStats.setPowerMode(mode); + mScheduler->setDisplayPowerState(mode == HWC_POWER_MODE_NORMAL); } ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str()); diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 2b33ba1746..3eedb67362 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -234,6 +234,14 @@ int32_t set_touch_timer_ms(int32_t defaultValue) { return defaultValue; } +int32_t set_display_power_timer_ms(int32_t defaultValue) { + auto temp = SurfaceFlingerProperties::set_display_power_timer_ms(); + if (temp.has_value()) { + return *temp; + } + return defaultValue; +} + bool use_smart_90_for_video(bool defaultValue) { auto temp = SurfaceFlingerProperties::use_smart_90_for_video(); if (temp.has_value()) { diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index 1964ccd582..68986f7c4c 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -74,6 +74,8 @@ int32_t set_idle_timer_ms(int32_t defaultValue); int32_t set_touch_timer_ms(int32_t defaultValue); +int32_t set_display_power_timer_ms(int32_t defaultValue); + bool use_smart_90_for_video(bool defaultValue); bool enable_protected_contents(bool defaultValue); diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index decabd5e88..c77137a0d7 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -309,6 +309,18 @@ prop { prop_name: "ro.surface_flinger.set_touch_timer_ms" } +# setDisplayPowerTimerMs indicates what is considered a timeout in milliseconds for Scheduler. +# This value is used by the Scheduler to trigger display power inactivity callbacks that will +# keep the display in peak refresh rate as long as display power is not in normal mode. +# Setting this property to 0 means there is no timer. +prop { + api_name: "set_display_power_timer_ms" + type: Integer + scope: System + access: Readonly + prop_name: "ro.surface_flinger.set_display_power_timer_ms" +} + # useSmart90ForVideo indicates whether Scheduler should detect content FPS, and try to adjust the # screen refresh rate based on that. prop { diff --git a/services/surfaceflinger/sysprop/api/system-current.txt b/services/surfaceflinger/sysprop/api/system-current.txt index 6ae3ac15ee..794c1d6ae9 100644 --- a/services/surfaceflinger/sysprop/api/system-current.txt +++ b/services/surfaceflinger/sysprop/api/system-current.txt @@ -17,6 +17,7 @@ package android.sysprop { method public static java.util.Optional present_time_offset_from_vsync_ns(); method public static java.util.Optional primary_display_orientation(); method public static java.util.Optional running_without_sync_framework(); + method public static java.util.Optional set_display_power_timer_ms(); method public static java.util.Optional set_idle_timer_ms(); method public static java.util.Optional set_touch_timer_ms(); method public static java.util.Optional start_graphics_allocator_service(); -- GitLab From 53b5d03f4b3350ec0d971c8174980e705ea240a0 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 11 Jul 2019 13:56:22 -0700 Subject: [PATCH 0239/1255] [SurfaceFlinger] Don't touch hw vsync in DEFAULT RR with kernel timeout As a power optimization, hw vsync shouldn't be enabled when the kernel timer resets if the display is going to run at 60hz anyways. Bug: 136197211 Test: systrace when scrolling at peak refresh rate of 60hz. Change-Id: Ic7df3e7b735f79b183cdd91f770de83082e491b4 (cherry picked from commit 7f01518eae5ce54d1b4bfc682c1c7b68bac89cb5) Merged-In: Ic7df3e7b735f79b183cdd91f770de83082e491b4 --- .../surfaceflinger/Scheduler/Scheduler.cpp | 29 +++++++++++++++---- services/surfaceflinger/Scheduler/Scheduler.h | 6 +++- services/surfaceflinger/SurfaceFlinger.cpp | 19 ++++++++++++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index a7784e9315..a194106112 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -393,11 +393,17 @@ void Scheduler::updateFpsBasedOnContent() { } void Scheduler::setChangeRefreshRateCallback( - const ChangeRefreshRateCallback& changeRefreshRateCallback) { + const ChangeRefreshRateCallback&& changeRefreshRateCallback) { std::lock_guard lock(mCallbackLock); mChangeRefreshRateCallback = changeRefreshRateCallback; } +void Scheduler::setGetCurrentRefreshRateTypeCallback( + const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateTypeCallback) { + std::lock_guard lock(mCallbackLock); + mGetCurrentRefreshRateTypeCallback = getCurrentRefreshRateTypeCallback; +} + void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) { std::lock_guard lock(mCallbackLock); mGetVsyncPeriod = getVsyncPeriod; @@ -455,8 +461,13 @@ void Scheduler::resetTimerCallback() { void Scheduler::resetKernelTimerCallback() { ATRACE_INT("ExpiredKernelIdleTimer", 0); std::lock_guard lock(mCallbackLock); - if (mGetVsyncPeriod) { - resyncToHardwareVsync(true, mGetVsyncPeriod()); + if (mGetVsyncPeriod && mGetCurrentRefreshRateTypeCallback) { + // If we're not in performance mode then the kernel timer shouldn't do + // anything, as the refresh rate during DPU power collapse will be the + // same. + if (mGetCurrentRefreshRateTypeCallback() == Scheduler::RefreshRateType::PERFORMANCE) { + resyncToHardwareVsync(true, mGetVsyncPeriod()); + } } } @@ -486,10 +497,16 @@ void Scheduler::expiredDisplayPowerTimerCallback() { } void Scheduler::expiredKernelTimerCallback() { + std::lock_guard lock(mCallbackLock); ATRACE_INT("ExpiredKernelIdleTimer", 1); - // Disable HW Vsync if the timer expired, as we don't need it - // enabled if we're not pushing frames. - disableHardwareVsync(false); + if (mGetCurrentRefreshRateTypeCallback) { + if (mGetCurrentRefreshRateTypeCallback() != Scheduler::RefreshRateType::PERFORMANCE) { + // Disable HW Vsync if the timer expired, as we don't need it + // enabled if we're not pushing frames, and if we're in PERFORMANCE + // mode then we'll need to re-update the DispSync model anyways. + disableHardwareVsync(false); + } + } } std::string Scheduler::doDump() { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 39c39d7639..5d8bb4cd2f 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -49,6 +49,7 @@ public: } using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; + using GetCurrentRefreshRateTypeCallback = std::function; using ChangeRefreshRateCallback = std::function; using GetVsyncPeriod = std::function; @@ -165,7 +166,9 @@ public: // Updates FPS based on the most content presented. void updateFpsBasedOnContent(); // Callback that gets invoked when Scheduler wants to change the refresh rate. - void setChangeRefreshRateCallback(const ChangeRefreshRateCallback& changeRefreshRateCallback); + void setChangeRefreshRateCallback(const ChangeRefreshRateCallback&& changeRefreshRateCallback); + void setGetCurrentRefreshRateTypeCallback( + const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateType); void setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod); // Returns whether idle timer is enabled or not @@ -294,6 +297,7 @@ private: std::unique_ptr mDisplayPowerTimer; std::mutex mCallbackLock; + GetCurrentRefreshRateTypeCallback mGetCurrentRefreshRateTypeCallback GUARDED_BY(mCallbackLock); ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock); GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5caf883a69..f9ea484c8d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -715,6 +715,24 @@ void SurfaceFlinger::init() { Mutex::Autolock lock(mStateLock); setRefreshRateTo(type, event); }); + mScheduler->setGetCurrentRefreshRateTypeCallback([this] { + Mutex::Autolock lock(mStateLock); + const auto display = getDefaultDisplayDeviceLocked(); + if (!display) { + // If we don't have a default display the fallback to the default + // refresh rate type + return RefreshRateType::DEFAULT; + } + + const int configId = display->getActiveConfig(); + for (const auto& [type, refresh] : mRefreshRateConfigs.getRefreshRates()) { + if (refresh && refresh->configId == configId) { + return type; + } + } + // This should never happen, but just gracefully fallback to default. + return RefreshRateType::DEFAULT; + }); mScheduler->setGetVsyncPeriodCallback([this] { Mutex::Autolock lock(mStateLock); return getVsyncPeriod(); @@ -1047,6 +1065,7 @@ bool SurfaceFlinger::performSetActiveConfig() { desiredActiveConfigChangeDone(); return false; } + mUpcomingActiveConfig = desiredActiveConfig; const auto displayId = display->getId(); LOG_ALWAYS_FATAL_IF(!displayId); -- GitLab From 3a123024a12552f8c6353519114b87d833fa6447 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 12 Jul 2019 16:59:39 -0700 Subject: [PATCH 0240/1255] SurfaceFlinger: tune LayerHistory to be less aggressive Increase the thresholds to mark layer as "relevant" to be less agressive when changing refresh rate based on content. Bug: 136558136 Test: 1) put icons in drawer/folder on homescreen 2) tap drawer to expand 3) tap homescreen to contract drawer 4) goto 2), repeating quickly. Test: libsurfaceflinger_unnittest Change-Id: I2a9b696f267d93720408a41dceb4acb7dc80bd69 (cherry picked from commit cab4c2f2673034356de895fa661aa3dc979ff20e) Merged-In: I2a9b696f267d93720408a41dceb4acb7dc80bd69 --- services/surfaceflinger/Scheduler/LayerInfo.h | 4 +- .../tests/unittests/LayerHistoryTest.cpp | 60 +++++++++++-------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 66df9dca20..a7337817e3 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -129,8 +129,8 @@ class LayerInfo { private: std::deque mElements; - static constexpr size_t HISTORY_SIZE = 10; - static constexpr std::chrono::nanoseconds HISTORY_TIME = 500ms; + static constexpr size_t HISTORY_SIZE = 90; + static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s; }; public: diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 7ec90660ce..8e7440c2e3 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -27,6 +27,15 @@ protected: static constexpr float MIN_REFRESH_RATE = 30.f; static constexpr float MAX_REFRESH_RATE = 90.f; + static constexpr auto RELEVANT_FRAME_THRESHOLD = 90u; + static constexpr uint64_t THIRTY_FPS_INTERVAL = 33'333'333; + + void forceRelevancy(const std::unique_ptr& testLayer) { + mLayerHistory->setVisibility(testLayer, true); + for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) { + mLayerHistory->insert(testLayer, 0, false /*isHDR*/); + } + }; }; LayerHistoryTest::LayerHistoryTest() { @@ -39,24 +48,18 @@ TEST_F(LayerHistoryTest, oneLayer) { std::unique_ptr testLayer = mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(testLayer, true); + for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) { + EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRateAndHDR().first); + mLayerHistory->insert(testLayer, 0, false /*isHDR*/); + } - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRateAndHDR().first); - - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - // This is still 0, because the layer is not considered recently active if it - // has been present in less than 10 frames. - EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRateAndHDR().first); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - // This should be MAX_REFRESH_RATE as we have more than 10 samples - EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); + // Add a few more. This time we should get MAX refresh rate as the layer + // becomes relevant + static constexpr auto A_FEW = 10; + for (auto i = 0u; i < A_FEW; i++) { + EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); + mLayerHistory->insert(testLayer, 0, false /*isHDR*/); + } } TEST_F(LayerHistoryTest, oneHDRLayer) { @@ -79,8 +82,9 @@ TEST_F(LayerHistoryTest, explicitTimestamp) { mLayerHistory->setVisibility(test30FpsLayer, true); nsecs_t startTime = systemTime(); - for (int i = 0; i < 31; i++) { - mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333), false /*isHDR*/); + for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) { + mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL), + false /*isHDR*/); } EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first); @@ -98,19 +102,21 @@ TEST_F(LayerHistoryTest, multipleLayers) { mLayerHistory->setVisibility(testLayer2, true); nsecs_t startTime = systemTime(); - for (int i = 0; i < 10; i++) { + for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) { mLayerHistory->insert(testLayer, 0, false /*isHDR*/); } EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); startTime = systemTime(); - for (int i = 0; i < 10; i++) { - mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333), false /*isHDR*/); + for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) { + mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL), + false /*isHDR*/); } EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); - for (int i = 10; i < 30; i++) { - mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333), false /*isHDR*/); + for (int i = 10; i < RELEVANT_FRAME_THRESHOLD; i++) { + mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL), + false /*isHDR*/); } EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); @@ -122,8 +128,10 @@ TEST_F(LayerHistoryTest, multipleLayers) { EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); // After 1200 ms frames become obsolete. std::this_thread::sleep_for(std::chrono::milliseconds(1500)); - // Insert the 31st frame. - mLayerHistory->insert(test30FpsLayer, startTime + (30 * 33333333), false /*isHDR*/); + + mLayerHistory->insert(test30FpsLayer, + startTime + (RELEVANT_FRAME_THRESHOLD * THIRTY_FPS_INTERVAL), + false /*isHDR*/); EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first); } -- GitLab From e6ad1602402611b74d11144270602f9844f8fcb6 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 16 Jul 2019 13:20:19 -0700 Subject: [PATCH 0241/1255] [SurfaceFlinger] Exclude first vsync duration from period calculation Some displays don't exit from idle state immediately when vsync is enabled through the kernel idle timer, so exclude the first vsync period instead of just the first sample. Bug: 136197211 Test: Scrolling through settings Change-Id: I899fec289c8b08cfaa3264f7f6291a6fac489ab8 (cherry picked from commit 94390a32e24ac0f9286e11efd9ae5232ac3b9ac3) Merged-In: I899fec289c8b08cfaa3264f7f6291a6fac489ab8 --- services/surfaceflinger/Scheduler/DispSync.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index 83fd42b43f..0c94052979 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -668,7 +668,13 @@ void DispSync::updateModelLocked() { nsecs_t durationSum = 0; nsecs_t minDuration = INT64_MAX; nsecs_t maxDuration = 0; - for (size_t i = 1; i < mNumResyncSamples; i++) { + // We skip the first 2 samples because the first vsync duration on some + // devices may be much more inaccurate than on other devices, e.g. due + // to delays in ramping up from a power collapse. By doing so this + // actually increases the accuracy of the DispSync model even though + // we're effectively relying on fewer sample points. + static constexpr size_t numSamplesSkipped = 2; + for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) { size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES; size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES; nsecs_t duration = mResyncSamples[idx] - mResyncSamples[prev]; @@ -679,15 +685,14 @@ void DispSync::updateModelLocked() { // Exclude the min and max from the average durationSum -= minDuration + maxDuration; - mPeriod = durationSum / (mNumResyncSamples - 3); + mPeriod = durationSum / (mNumResyncSamples - numSamplesSkipped - 2); ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod)); double sampleAvgX = 0; double sampleAvgY = 0; double scale = 2.0 * M_PI / double(mPeriod); - // Intentionally skip the first sample - for (size_t i = 1; i < mNumResyncSamples; i++) { + for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) { size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES; nsecs_t sample = mResyncSamples[idx] - mReferenceTime; double samplePhase = double(sample % mPeriod) * scale; @@ -695,8 +700,8 @@ void DispSync::updateModelLocked() { sampleAvgY += sin(samplePhase); } - sampleAvgX /= double(mNumResyncSamples - 1); - sampleAvgY /= double(mNumResyncSamples - 1); + sampleAvgX /= double(mNumResyncSamples - numSamplesSkipped); + sampleAvgY /= double(mNumResyncSamples - numSamplesSkipped); mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale); -- GitLab From ac1aeaffec4ae787a500575da9f224b88b0bb699 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 19 Jul 2019 10:59:45 -0700 Subject: [PATCH 0242/1255] SurfaceFlinger: calculate expected present once Calculate the expected present time in the beginning of the frame and use the same value across the frame composition. Bug: 137873466 Test: App transitions Change-Id: I0b41c62796f6150702e8d50ec7d28838d3a5aa87 (cherry picked from commit 7c03ce6508a7887e732abe03dc2dd53e146c008e) Merged-In: I0b41c62796f6150702e8d50ec7d28838d3a5aa87 --- services/surfaceflinger/SurfaceFlinger.cpp | 10 +++++++--- services/surfaceflinger/SurfaceFlinger.h | 7 +++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f9ea484c8d..42188d1089 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1688,22 +1688,26 @@ bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS { return fence != Fence::NO_FENCE && (fence->getStatus() == Fence::Status::Unsignaled); } -nsecs_t SurfaceFlinger::getExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS { +void SurfaceFlinger::populateExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS { DisplayStatInfo stats; mScheduler->getDisplayStatInfo(&stats); const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(); // Inflate the expected present time if we're targetting the next vsync. - const nsecs_t correctedTime = + mExpectedPresentTime = mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync() ? presentTime : presentTime + stats.vsyncPeriod; - return correctedTime; } void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { ATRACE_CALL(); switch (what) { case MessageQueue::INVALIDATE: { + // calculate the expected present time once and use the cached + // value throughout this frame to make sure all layers are + // seeing this same value. + populateExpectedPresentTime(); + bool frameMissed = previousFrameMissed(); bool hwcFrameMissed = mHadDeviceComposition && frameMissed; bool gpuFrameMissed = mHadClientComposition && frameMissed; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a8057aad24..ec0b7c54be 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -301,10 +301,11 @@ public: // TODO: this should be made accessible only to MessageQueue void onMessageReceived(int32_t what); - // Returns the expected present time for this frame. + // populates the expected present time for this frame. // When we are in negative offsets, we perform a correction so that the // predicted vsync for the *next* frame is used instead. - nsecs_t getExpectedPresentTime(); + void populateExpectedPresentTime(); + nsecs_t getExpectedPresentTime() const { return mExpectedPresentTime; } // for debugging only // TODO: this should be made accessible only to HWComposer @@ -1184,6 +1185,8 @@ private: // Flags to capture the state of Vsync in HWC HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable; HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable; + + nsecs_t mExpectedPresentTime; }; } // namespace android -- GitLab From 4344553ce300584d5c27b29f2345d248e488aa57 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 9 Aug 2019 10:44:59 -0700 Subject: [PATCH 0243/1255] SurfaceFlinger: clamp frame refresh duration to min refresh duration Some applications may send doubles frames which are scheduled to be presented very close to each other. In this case to avoid calculating a very high fps for the layer, clamp the refresh duration to the minimal value allowed for the layer. Test: YouTube play "YouTube 60fps Tester" video. Bug: 139209733 Change-Id: I4bcdfad65b57782ec6e346e8d884bfb6e2abac4d (cherry picked from commit cdd0f9d88e8dec40629f60726212e26397a76475) Merged-In: I4bcdfad65b57782ec6e346e8d884bfb6e2abac4d --- services/surfaceflinger/Scheduler/LayerInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 38afb7ed29..6e5df123b2 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -43,7 +43,7 @@ void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime) { mLastPresentTime = lastPresentTime; // Ignore time diff that are too high - those are stale values if (timeDiff > OBSOLETE_TIME_EPSILON_NS.count()) return; - const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration; + const nsecs_t refreshDuration = std::max(timeDiff, mMinRefreshDuration); const int fps = 1e9f / refreshDuration; mRefreshRateHistory.insertRefreshRate(fps); } -- GitLab From 214c89db99f280cd67ca14357c9ee11adce0acce Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 4 Sep 2019 16:03:53 -0700 Subject: [PATCH 0244/1255] Remove setGeometryAppliesWithResize This function is no longer used so removing the API and any logic implemented for it. Test: go/wm-smoke Change-Id: I4ae2128cd38e818fcd16dafa4ce47c9411bd61c9 --- libs/gui/LayerState.cpp | 3 - libs/gui/SurfaceComposerClient.cpp | 13 -- libs/gui/include/gui/LayerState.h | 2 +- libs/gui/include/gui/SurfaceComposerClient.h | 6 - services/surfaceflinger/BufferQueueLayer.cpp | 2 +- services/surfaceflinger/BufferStateLayer.h | 4 +- services/surfaceflinger/Layer.cpp | 39 ++---- services/surfaceflinger/Layer.h | 6 +- services/surfaceflinger/LayerRejecter.cpp | 28 ++-- services/surfaceflinger/LayerRejecter.h | 12 +- .../surfaceflinger/RefreshRateOverlay.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 7 +- .../surfaceflinger/tests/Transaction_test.cpp | 124 ------------------ .../tests/fakehwc/SFFakeHwc_test.cpp | 18 --- 14 files changed, 32 insertions(+), 234 deletions(-) diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index be58b853d7..523ed1d2ce 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -291,9 +291,6 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eOverrideScalingModeChanged; overrideScalingMode = other.overrideScalingMode; } - if (other.what & eGeometryAppliesWithResize) { - what |= eGeometryAppliesWithResize; - } if (other.what & eReparentChildren) { what |= eReparentChildren; reparentHandle = other.reparentHandle; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 5faf010d72..67dd726eba 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1187,19 +1187,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverr return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometryAppliesWithResize( - const sp& sc) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - s->what |= layer_state_t::eGeometryAppliesWithResize; - - registerSurfaceControlForCallback(sc); - return *this; -} - #ifndef NO_INPUT SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo( const sp& sc, diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index cbd1c8553b..2eb5492558 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -71,7 +71,7 @@ struct layer_state_t { eCropChanged_legacy = 0x00000100, eDeferTransaction_legacy = 0x00000200, eOverrideScalingModeChanged = 0x00000400, - eGeometryAppliesWithResize = 0x00000800, + // AVAILABLE 0x00000800, eReparentChildren = 0x00001000, eDetachChildren = 0x00002000, eRelativeLayerChanged = 0x00004000, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index f303a03254..d65e679e24 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -446,12 +446,6 @@ public: Transaction& setOverrideScalingMode(const sp& sc, int32_t overrideScalingMode); - // If the size changes in this transaction, all geometry updates specified - // in this transaction will not complete until a buffer of the new size - // arrives. As some elements normally apply immediately, this enables - // freezing the total geometry of a surface until a resize is completed. - Transaction& setGeometryAppliesWithResize(const sp& sc); - #ifndef NO_INPUT Transaction& setInputWindowInfo(const sp& sc, const InputWindowInfo& info); Transaction& transferTouchFocus(const sp& fromToken, const sp& toToken); diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 5f494ff3d5..85a00fbe0d 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -276,7 +276,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t const int32_t layerID = getSequence(); LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions, getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode, - getTransformToDisplayInverse(), mFreezeGeometryUpdates); + getTransformToDisplayInverse()); if (isRemovedFromCurrentState()) { expectedPresentTime = 0; diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index cc670087ac..f2a5dffe7c 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -82,13 +82,13 @@ public: // Override to ignore legacy layer state properties that are not used by BufferStateLayer bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; } - bool setPosition(float /*x*/, float /*y*/, bool /*immediate*/) override { return false; } + bool setPosition(float /*x*/, float /*y*/) override { return false; } bool setTransparentRegionHint(const Region& transparent) override; bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/, bool /*allowNonRectPreservingTransforms*/) override { return false; } - bool setCrop_legacy(const Rect& /*crop*/, bool /*immediate*/) override { return false; } + bool setCrop_legacy(const Rect& /*crop*/) override { return false; } bool setOverrideScalingMode(int32_t /*overrideScalingMode*/) override { return false; } void deferTransactionUntil_legacy(const sp& /*barrierHandle*/, uint64_t /*frameNumber*/) override {} diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5121835cae..4c8a6bf465 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -770,11 +770,6 @@ uint32_t Layer::doTransactionResize(uint32_t flags, State* stateToCommit) { if (!(flags & eDontUpdateGeometryState)) { State& editCurrentState(getCurrentState()); - // If mFreezeGeometryUpdates is true we are in the setGeometryAppliesWithResize - // mode, which causes attributes which normally latch regardless of scaling mode, - // to be delayed. We copy the requested state to the active state making sure - // to respect these rules (again see Layer.h for a detailed discussion). - // // There is an awkward asymmetry in the handling of the crop states in the position // states, as can be seen below. Largely this arises from position and transform // being stored in the same data structure while having different latching rules. @@ -782,16 +777,8 @@ uint32_t Layer::doTransactionResize(uint32_t flags, State* stateToCommit) { // // Careful that "stateToCommit" and editCurrentState may not begin as equivalent due to // applyPendingStates in the presence of deferred transactions. - if (mFreezeGeometryUpdates) { - float tx = stateToCommit->active_legacy.transform.tx(); - float ty = stateToCommit->active_legacy.transform.ty(); - stateToCommit->active_legacy = stateToCommit->requested_legacy; - stateToCommit->active_legacy.transform.set(tx, ty); - editCurrentState.active_legacy = stateToCommit->active_legacy; - } else { - editCurrentState.active_legacy = editCurrentState.requested_legacy; - stateToCommit->active_legacy = stateToCommit->requested_legacy; - } + editCurrentState.active_legacy = editCurrentState.requested_legacy; + stateToCommit->active_legacy = stateToCommit->requested_legacy; } return flags; @@ -858,7 +845,7 @@ uint32_t Layer::setTransactionFlags(uint32_t flags) { return mTransactionFlags.fetch_or(flags); } -bool Layer::setPosition(float x, float y, bool immediate) { +bool Layer::setPosition(float x, float y) { if (mCurrentState.requested_legacy.transform.tx() == x && mCurrentState.requested_legacy.transform.ty() == y) return false; @@ -868,14 +855,11 @@ bool Layer::setPosition(float x, float y, bool immediate) { // we want to apply the position portion of the transform matrix immediately, // but still delay scaling when resizing a SCALING_MODE_FREEZE layer. mCurrentState.requested_legacy.transform.set(x, y); - if (immediate && !mFreezeGeometryUpdates) { - // Here we directly update the active state - // unlike other setters, because we store it within - // the transform, but use different latching rules. - // b/38182305 - mCurrentState.active_legacy.transform.set(x, y); - } - mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate; + // Here we directly update the active state + // unlike other setters, because we store it within + // the transform, but use different latching rules. + // b/38182305 + mCurrentState.active_legacy.transform.set(x, y); mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); @@ -1081,14 +1065,11 @@ bool Layer::setFlags(uint8_t flags, uint8_t mask) { return true; } -bool Layer::setCrop_legacy(const Rect& crop, bool immediate) { +bool Layer::setCrop_legacy(const Rect& crop) { if (mCurrentState.requestedCrop_legacy == crop) return false; mCurrentState.sequence++; mCurrentState.requestedCrop_legacy = crop; - if (immediate && !mFreezeGeometryUpdates) { - mCurrentState.crop_legacy = crop; - } - mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate; + mCurrentState.crop_legacy = crop; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 9107189d52..a2409e79d2 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -268,9 +268,9 @@ public: // setPosition operates in parent buffer space (pre parent-transform) or display // space for top-level layers. - virtual bool setPosition(float x, float y, bool immediate); + virtual bool setPosition(float x, float y); // Buffer space - virtual bool setCrop_legacy(const Rect& crop, bool immediate); + virtual bool setCrop_legacy(const Rect& crop); // TODO(b/38182121): Could we eliminate the various latching modes by // using the layer hierarchy? @@ -860,8 +860,6 @@ protected: // This layer can be a cursor on some displays. bool mPotentialCursor{false}; - bool mFreezeGeometryUpdates{false}; - // Child list about to be committed/used for editing. LayerVector mCurrentChildren{LayerVector::StateSet::Current}; // Child list used for rendering. diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp index 72abea8b2d..8a221837ac 100644 --- a/services/surfaceflinger/LayerRejecter.cpp +++ b/services/surfaceflinger/LayerRejecter.cpp @@ -23,22 +23,16 @@ namespace android { -LayerRejecter::LayerRejecter(Layer::State& front, - Layer::State& current, - bool& recomputeVisibleRegions, - bool stickySet, - const char* name, - int32_t overrideScalingMode, - bool transformToDisplayInverse, - bool& freezePositionUpdates) - : mFront(front), - mCurrent(current), - mRecomputeVisibleRegions(recomputeVisibleRegions), - mStickyTransformSet(stickySet), - mName(name), - mOverrideScalingMode(overrideScalingMode), - mTransformToDisplayInverse(transformToDisplayInverse), - mFreezeGeometryUpdates(freezePositionUpdates) {} +LayerRejecter::LayerRejecter(Layer::State& front, Layer::State& current, + bool& recomputeVisibleRegions, bool stickySet, const char* name, + int32_t overrideScalingMode, bool transformToDisplayInverse) + : mFront(front), + mCurrent(current), + mRecomputeVisibleRegions(recomputeVisibleRegions), + mStickyTransformSet(stickySet), + mName(name), + mOverrideScalingMode(overrideScalingMode), + mTransformToDisplayInverse(transformToDisplayInverse) {} bool LayerRejecter::reject(const sp& buf, const BufferItem& item) { if (buf == nullptr) { @@ -83,8 +77,6 @@ bool LayerRejecter::reject(const sp& buf, const BufferItem& item) // recompute visible region mRecomputeVisibleRegions = true; - mFreezeGeometryUpdates = false; - if (mFront.crop_legacy != mFront.requestedCrop_legacy) { mFront.crop_legacy = mFront.requestedCrop_legacy; mCurrent.crop_legacy = mFront.requestedCrop_legacy; diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h index 63d51de0ca..1bd0c26dc6 100644 --- a/services/surfaceflinger/LayerRejecter.h +++ b/services/surfaceflinger/LayerRejecter.h @@ -23,14 +23,9 @@ namespace android { class LayerRejecter : public BufferLayerConsumer::BufferRejecter { public: - LayerRejecter(Layer::State &front, - Layer::State ¤t, - bool &recomputeVisibleRegions, - bool stickySet, - const char *name, - int32_t overrideScalingMode, - bool transformToDisplayInverse, - bool &freezePositionUpdates); + LayerRejecter(Layer::State &front, Layer::State ¤t, bool &recomputeVisibleRegions, + bool stickySet, const char *name, int32_t overrideScalingMode, + bool transformToDisplayInverse); virtual bool reject(const sp &buf, const BufferItem &item); @@ -42,7 +37,6 @@ namespace android { const char *mName; int32_t mOverrideScalingMode; bool mTransformToDisplayInverse; - bool &mFreezeGeometryUpdates; }; } // namespace android diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 5b4bec96ea..976fedb58a 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -39,7 +39,7 @@ bool RefreshRateOverlay::createLayer() { Mutex::Autolock _l(mFlinger.mStateLock); mLayer = mClient->getLayerUser(mIBinder); - mLayer->setCrop_legacy(Rect(50, 70, 200, 100), true); + mLayer->setCrop_legacy(Rect(50, 70, 200, 100)); // setting Layer's Z requires resorting layersSortedByZ ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7a8eb6b2da..c1a8f87d37 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3597,8 +3597,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( uint32_t flags = 0; const uint64_t what = s.what; - bool geometryAppliesWithResize = - what & layer_state_t::eGeometryAppliesWithResize; // If we are deferring transaction, make sure to push the pending state, as otherwise the // pending state will also be deferred. @@ -3607,7 +3605,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( } if (what & layer_state_t::ePositionChanged) { - if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) { + if (layer->setPosition(s.x, s.y)) { flags |= eTraversalNeeded; } } @@ -3698,8 +3696,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } if (what & layer_state_t::eCropChanged_legacy) { - if (layer->setCrop_legacy(s.crop_legacy, !geometryAppliesWithResize)) - flags |= eTraversalNeeded; + if (layer->setCrop_legacy(s.crop_legacy)) flags |= eTraversalNeeded; } if (what & layer_state_t::eCornerRadiusChanged) { if (layer->setCornerRadius(s.cornerRadius)) diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index b1fde22e0e..03c646b0bb 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -842,62 +842,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) { } } -TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResize_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // request setPosition to be applied with the next resize - Transaction().setPosition(layer, 5, 10).setGeometryAppliesWithResize(layer).apply(); - { - SCOPED_TRACE("new position pending"); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); - } - - Transaction().setPosition(layer, 15, 20).apply(); - { - SCOPED_TRACE("pending new position modified"); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); - } - - Transaction().setSize(layer, 64, 64).apply(); - { - SCOPED_TRACE("resize pending"); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); - } - - // finally resize and latch the buffer - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); - { - SCOPED_TRACE("new position applied"); - getScreenCapture()->expectColor(Rect(15, 20, 79, 84), Color::RED); - } -} - -TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResizeScaleToWindow_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // setPosition is not immediate even with SCALE_TO_WINDOW override - Transaction() - .setPosition(layer, 5, 10) - .setSize(layer, 64, 64) - .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) - .setGeometryAppliesWithResize(layer) - .apply(); - { - SCOPED_TRACE("new position pending"); - getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED); - } - - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); - { - SCOPED_TRACE("new position applied"); - getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED); - } -} - TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) { sp layer; ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); @@ -2310,74 +2254,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) { } } -TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResize_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // request setCrop_legacy to be applied with the next resize - Transaction() - .setCrop_legacy(layer, Rect(8, 8, 24, 24)) - .setGeometryAppliesWithResize(layer) - .apply(); - { - SCOPED_TRACE("waiting for next resize"); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); - } - - Transaction().setCrop_legacy(layer, Rect(4, 4, 12, 12)).apply(); - { - SCOPED_TRACE("pending crop modified"); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); - } - - Transaction().setSize(layer, 16, 16).apply(); - { - SCOPED_TRACE("resize pending"); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); - } - - // finally resize - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16)); - { - SCOPED_TRACE("new crop applied"); - auto shot = getScreenCapture(); - shot->expectColor(Rect(4, 4, 12, 12), Color::RED); - shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK); - } -} - -TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResizeScaleToWindow_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // setCrop_legacy is not immediate even with SCALE_TO_WINDOW override - Transaction() - .setCrop_legacy(layer, Rect(4, 4, 12, 12)) - .setSize(layer, 16, 16) - .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) - .setGeometryAppliesWithResize(layer) - .apply(); - { - SCOPED_TRACE("new crop pending"); - auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 16, 16), Color::RED); - shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK); - } - - // XXX crop is never latched without other geometry change (b/69315677) - Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply(); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16)); - Transaction().setPosition(layer, 0, 0).apply(); - { - SCOPED_TRACE("new crop applied"); - auto shot = getScreenCapture(); - shot->expectColor(Rect(4, 4, 12, 12), Color::RED); - shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK); - } -} - TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) { sp layer; ASSERT_NO_FATAL_FAILURE( diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index a892a2abd0..093bcf576d 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -1331,16 +1331,6 @@ TEST_F(LatchingTest, SurfacePositionLatching) { restoreInitialState(); - // Now we repeat with setGeometryAppliesWithResize - // and verify the position DOESN'T latch. - { - TransactionScope ts(*sFakeComposer); - ts.setGeometryAppliesWithResize(mFGSurfaceControl); - ts.setSize(mFGSurfaceControl, 32, 32); - ts.setPosition(mFGSurfaceControl, 100, 100); - } - EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); - completeFGResize(); auto referenceFrame2 = mBaseFrame; @@ -1365,14 +1355,6 @@ TEST_F(LatchingTest, CropLatching) { restoreInitialState(); - { - TransactionScope ts(*sFakeComposer); - ts.setSize(mFGSurfaceControl, 128, 128); - ts.setGeometryAppliesWithResize(mFGSurfaceControl); - ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 63, 63)); - } - EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); - completeFGResize(); auto referenceFrame2 = mBaseFrame; -- GitLab From 0f0ddc1055f2c3c5b976bcb0255937a81313e416 Mon Sep 17 00:00:00 2001 From: Daniel Solomon Date: Mon, 19 Aug 2019 19:31:09 -0700 Subject: [PATCH 0245/1255] SurfaceFlinger: Query Scheduler when updating allowed display configs Currently two entities in SurfaceFlinger can set a new display refresh rate: (1) SurfaceFlinger core, and (2) Scheduler. It's possible for these two entities to get out of sync in the following way: 1) Scheduler updates the refresh rate to some rate 2) Upper layers call into SurfaceFlinger to update allowed display configs 3) SurfaceFlinger always sets display rate to max If the refresh rate from #1 and #3 don't match, it can leave the system in an inconsistent state, potentially causing visual and power issues. This change fixes this problem by changing step #3: Instead of always choosing the max refresh rate, SurfaceFlinger queries the optimal refresh rate from Scheduler. If that rate isn't available, only then does SurfaceFlinger default to the maximum rate. Bug: 139557239 Test: atest libsurfaceflinger_unittest Test: Manual: 1) Start with SurfaceFlinger idling (Scheduler selected RefreshRateType::DEFAULT) 2) Trigger a change in allowed display configs from DisplayModeDirector 3) Make sure the RefreshRateType SurfaceFlinger sets is DEFAULT instead of PERFORMANCE Change-Id: Ia85a60fde55afaed5106462942e0bb77652ec737 --- .../surfaceflinger/Scheduler/Scheduler.cpp | 6 ++++ services/surfaceflinger/Scheduler/Scheduler.h | 3 ++ services/surfaceflinger/SurfaceFlinger.cpp | 30 ++++++++++++------- services/surfaceflinger/SurfaceFlinger.h | 3 ++ 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 8d9357a681..eb52d3fce6 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -512,6 +512,7 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { } // Content detection is on, find the appropriate refresh rate with minimal error + // TODO(b/139751853): Scan allowed refresh rates only (SurfaceFlinger::mAllowedDisplayConfigs) const float rate = static_cast(mFeatures.contentRefreshRate); auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(), mRefreshRateConfigs.getRefreshRates().cend(), @@ -541,6 +542,11 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { return currRefreshRateType; } +Scheduler::RefreshRateType Scheduler::getPreferredRefreshRateType() { + std::lock_guard lock(mFeatureStateLock); + return mFeatures.refreshRateType; +} + void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) { std::lock_guard lock(mCallbackLock); if (mChangeRefreshRateCallback) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index c15f793b1c..34e527cdc6 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -127,6 +127,9 @@ public: void dump(std::string&) const; void dump(ConnectionHandle, std::string&) const; + // Get the appropriate refresh type for current conditions. + RefreshRateType getPreferredRefreshRateType(); + private: friend class TestableScheduler; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ba734d2937..31299638fc 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5634,6 +5634,25 @@ void SurfaceFlinger::traverseLayersInDisplay(const sp& disp } } +void SurfaceFlinger::setPreferredDisplayConfig() { + const auto& type = mScheduler->getPreferredRefreshRateType(); + const auto& config = mRefreshRateConfigs.getRefreshRate(type); + if (config && isDisplayConfigAllowed(config->configId)) { + ALOGV("switching to Scheduler preferred config %d", config->configId); + setDesiredActiveConfig({type, config->configId, Scheduler::ConfigEvent::Changed}); + } else { + // Set the highest allowed config by iterating backwards on available refresh rates + const auto& refreshRates = mRefreshRateConfigs.getRefreshRates(); + for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) { + if (iter->second && isDisplayConfigAllowed(iter->second->configId)) { + ALOGV("switching to allowed config %d", iter->second->configId); + setDesiredActiveConfig({iter->first, iter->second->configId, + Scheduler::ConfigEvent::Changed}); + } + } + } +} + void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp& display, const std::vector& allowedConfigs) { if (!display->isPrimary()) { @@ -5655,16 +5674,7 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp& d mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, display->getActiveConfig()); - // Set the highest allowed config by iterating backwards on available refresh rates - const auto& refreshRates = mRefreshRateConfigs.getRefreshRates(); - for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) { - if (iter->second && isDisplayConfigAllowed(iter->second->configId)) { - ALOGV("switching to config %d", iter->second->configId); - setDesiredActiveConfig( - {iter->first, iter->second->configId, Scheduler::ConfigEvent::Changed}); - break; - } - } + setPreferredDisplayConfig(); } status_t SurfaceFlinger::setAllowedDisplayConfigs(const sp& displayToken, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f6df33a999..316170623c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -528,6 +528,9 @@ private: // called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp& display, int mode) REQUIRES(mStateLock); + // Query the Scheduler or allowed display configs list for a matching config, and set it + void setPreferredDisplayConfig() REQUIRES(mStateLock); + // called on the main thread in response to setAllowedDisplayConfigs() void setAllowedDisplayConfigsInternal(const sp& display, const std::vector& allowedConfigs) -- GitLab From 26d03fdb99ed937981fd6f818a034b43c6790402 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 7 Mar 2019 21:23:23 -0800 Subject: [PATCH 0246/1255] SF: Move OutputLayer creation to computeVisibleRegions This moves part of rebuildLayerStacks to computeVisibleRegions. In particular it eliminates a second loop over all front-end layers to identify the ones that are visible on an output. The first loop computes the visibility, and can immediately create the output layers. This is a bit of nontrivial restructuring prior to moving the code to CompositionEngine, since that will also break things up a bit. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: I8a498195f9b5f976e7a69de717818b57494e2f2b --- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 107 ++++++++++++--------- services/surfaceflinger/SurfaceFlinger.h | 6 +- 3 files changed, 67 insertions(+), 48 deletions(-) diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 23763d2729..23809e85be 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -93,7 +93,7 @@ struct LayerCreationArgs { LayerMetadata metadata; }; -class Layer : public virtual compositionengine::LayerFE { +class Layer : public compositionengine::LayerFE { static std::atomic sSequence; public: diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 50440e8d3b..49a6800409 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2085,6 +2085,12 @@ void SurfaceFlinger::rebuildLayerStacks() { ATRACE_NAME("rebuildLayerStacks VR Dirty"); invalidateHwcGeometry(); + std::vector> layersWithQueuedFrames; + layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size()); + for (sp layer : mLayersWithQueuedFrames) { + layersWithQueuedFrames.push_back(layer); + } + for (const auto& pair : mDisplays) { const auto& displayDevice = pair.second; auto display = displayDevice->getCompositionDisplay(); @@ -2092,59 +2098,44 @@ void SurfaceFlinger::rebuildLayerStacks() { Region opaqueRegion; Region dirtyRegion; compositionengine::Output::OutputLayers layersSortedByZ; - compositionengine::Output::ReleasedLayers releasedLayers; const ui::Transform& tr = displayState.transform; const Rect bounds = displayState.bounds; - if (displayState.isEnabled) { - computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion); + if (!displayState.isEnabled) { + continue; + } - mDrawingState.traverseInZOrder([&](Layer* layer) { - auto compositionLayer = layer->getCompositionLayer(); - if (compositionLayer == nullptr) { - return; - } + computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion, layersSortedByZ); - const auto displayId = displayDevice->getId(); - sp layerFE = compositionLayer->getLayerFE(); - LOG_ALWAYS_FATAL_IF(layerFE.get() == nullptr); + // computeVisibleRegions walks the layers in reverse-Z order. Reverse + // to get a back-to-front ordering. + std::reverse(layersSortedByZ.begin(), layersSortedByZ.end()); - bool needsOutputLayer = false; + display->setOutputLayersOrderedByZ(std::move(layersSortedByZ)); - if (display->belongsInOutput(layer->getLayerStack(), - layer->getPrimaryDisplayOnly())) { - Region drawRegion(tr.transform( - layer->visibleNonTransparentRegion)); - drawRegion.andSelf(bounds); - if (!drawRegion.isEmpty()) { - needsOutputLayer = true; - } + compositionengine::Output::ReleasedLayers releasedLayers; + if (displayDevice->getId() && !layersWithQueuedFrames.empty()) { + // For layers that are being removed from a HWC display, + // and that have queued frames, add them to a a list of + // released layers so we can properly set a fence. + + // Any non-null entries in the current list of layers are layers + // that are no longer going to be visible + for (auto& layer : display->getOutputLayersOrderedByZ()) { + if (!layer) { + continue; } - if (needsOutputLayer) { - layersSortedByZ.emplace_back( - display->getOrCreateOutputLayer(displayId, compositionLayer, - layerFE)); - auto& outputLayerState = layersSortedByZ.back()->editState(); - outputLayerState.visibleRegion = - tr.transform(layer->visibleRegion.intersect(displayState.viewport)); - } else if (displayId) { - // For layers that are being removed from a HWC display, - // and that have queued frames, add them to a a list of - // released layers so we can properly set a fence. - bool hasExistingOutputLayer = - display->getOutputLayerForLayer(compositionLayer.get()) != nullptr; - bool hasQueuedFrames = std::find(mLayersWithQueuedFrames.cbegin(), - mLayersWithQueuedFrames.cend(), - layer) != mLayersWithQueuedFrames.cend(); - - if (hasExistingOutputLayer && hasQueuedFrames) { - releasedLayers.push_back(layer); - } + sp layerFE(&layer->getLayerFE()); + const bool hasQueuedFrames = + std::find(layersWithQueuedFrames.cbegin(), + layersWithQueuedFrames.cend(), + layerFE) != layersWithQueuedFrames.cend(); + + if (hasQueuedFrames) { + releasedLayers.emplace_back(layerFE); } - }); + } } - - display->setOutputLayersOrderedByZ(std::move(layersSortedByZ)); display->setReleasedLayers(std::move(releasedLayers)); Region undefinedRegion{bounds}; @@ -2744,8 +2735,10 @@ void SurfaceFlinger::commitOffscreenLayers() { } } -void SurfaceFlinger::computeVisibleRegions(const sp& displayDevice, - Region& outDirtyRegion, Region& outOpaqueRegion) { +void SurfaceFlinger::computeVisibleRegions( + const sp& displayDevice, Region& outDirtyRegion, + Region& outOpaqueRegion, + std::vector>& outLayersSortedByZ) { ATRACE_CALL(); ALOGV("computeVisibleRegions"); @@ -2758,6 +2751,11 @@ void SurfaceFlinger::computeVisibleRegions(const sp& displa outDirtyRegion.clear(); mDrawingState.traverseInReverseZOrder([&](Layer* layer) { + auto compositionLayer = layer->getCompositionLayer(); + if (compositionLayer == nullptr) { + return; + } + // start with the whole surface at its current location const Layer::State& s(layer->getDrawingState()); @@ -2880,6 +2878,25 @@ void SurfaceFlinger::computeVisibleRegions(const sp& displa layer->setCoveredRegion(coveredRegion); layer->setVisibleNonTransparentRegion( visibleRegion.subtract(transparentRegion)); + + // Setup an output layer for this output if the layer is + // visible on this output + const auto& displayState = display->getState(); + Region drawRegion(displayState.transform.transform(layer->visibleNonTransparentRegion)); + drawRegion.andSelf(displayState.bounds); + if (drawRegion.isEmpty()) { + return; + } + + const auto displayId = displayDevice->getId(); + sp layerFE = compositionLayer->getLayerFE(); + LOG_ALWAYS_FATAL_IF(layerFE.get() == nullptr); + + outLayersSortedByZ.emplace_back( + display->getOrCreateOutputLayer(displayId, compositionLayer, layerFE)); + auto& outputLayerState = outLayersSortedByZ.back()->editState(); + outputLayerState.visibleRegion = displayState.transform.transform( + layer->visibleRegion.intersect(displayState.viewport)); }); outOpaqueRegion = aboveOpaqueLayers; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 0f9a4bdeba..07efba9303 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -98,6 +98,7 @@ class TimeStats; namespace compositionengine { class DisplaySurface; +class OutputLayer; struct CompositionRefreshArgs; } // namespace compositionengine @@ -740,8 +741,9 @@ private: * Compositing */ void invalidateHwcGeometry(); - void computeVisibleRegions(const sp& display, Region& dirtyRegion, - Region& opaqueRegion); + void computeVisibleRegions( + const sp& display, Region& dirtyRegion, Region& opaqueRegion, + std::vector>& outputLayers); void postComposition(); void getCompositorTiming(CompositorTiming* compositorTiming); -- GitLab From a2468669661cd9bcd1258ec908716c4b85ef007e Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 7 Mar 2019 21:31:06 -0800 Subject: [PATCH 0247/1255] SF: Move layer visibility state to CompositionEngine The layer visibility/coverage state was the last bit of display-dependent data that had not yet been moved to OutputLayerCompositionState. This moves it, and fixes up all references to the data to get it in a display-dependent way. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: Id9f314f05b743212dba3a113df2baeb38fd19eb8 --- services/surfaceflinger/BufferLayer.cpp | 3 +- .../LayerFECompositionState.h | 4 -- .../impl/LayerCompositionState.h | 3 +- .../impl/OutputLayerCompositionState.h | 13 +++++- .../CompositionEngine/src/Output.cpp | 2 +- .../CompositionEngine/src/OutputLayer.cpp | 11 ++--- .../src/OutputLayerCompositionState.cpp | 9 ++++ .../tests/OutputLayerTest.cpp | 9 ++-- .../CompositionEngine/tests/OutputTest.cpp | 10 ++--- services/surfaceflinger/Layer.cpp | 44 +++++++------------ services/surfaceflinger/Layer.h | 30 +------------ services/surfaceflinger/SurfaceFlinger.cpp | 35 ++++++++------- .../tests/unittests/CompositionTest.cpp | 22 +++++++++- 13 files changed, 98 insertions(+), 97 deletions(-) diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index a8bdb799e7..a7970db473 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -158,7 +158,8 @@ std::optional BufferLayer::prepareClientComposition finished = true; return; } - under.orSelf(layer->visibleRegion); + + under.orSelf(layer->getScreenBounds()); }); // if not everything below us is covered, we plug the holes! Region holes(targetSettings.clip.subtract(under)); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 6a0caf0746..b066cd1bda 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -56,10 +56,6 @@ struct LayerFECompositionState { Region geomActiveTransparentRegion; FloatRect geomLayerBounds; - // TODO(lpique): b/121291683 Remove this one we are sure we don't need the - // value recomputed / set every frame. - Region geomVisibleRegion; - /* * Presentation */ diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h index ab01c209d1..726c850780 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h @@ -21,6 +21,7 @@ #include #include +#include namespace android { @@ -28,7 +29,7 @@ namespace compositionengine::impl { struct LayerCompositionState { /* - * State intended to be set by LayerFE::getCompositionState + * State set by LayerFE::getCompositionState */ LayerFECompositionState frontEnd; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index de0f08ace8..13474492af 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -40,9 +40,18 @@ class HWComposer; namespace compositionengine::impl { struct OutputLayerCompositionState { - // The region of this layer which is visible on this output + // The portion of the layer that is not obscured by opaque layers on top Region visibleRegion; + // The portion of the layer that is not obscured and is also opaque + Region visibleNonTransparentRegion; + + // The portion of the layer that is obscured by opaque layers on top + Region coveredRegion; + + // The visibleRegion transformed to output space + Region outputSpaceVisibleRegion; + // If true, client composition will be used on this output bool forceClientComposition{false}; @@ -62,7 +71,7 @@ struct OutputLayerCompositionState { ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; // The Z order index of this layer on this output - uint32_t z; + uint32_t z{0}; /* * HWC state diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 903ca9891c..9f4f259f7c 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -601,7 +601,7 @@ std::vector Output::generateClientCompositionReques const auto& layerFEState = layer->getLayer().getState().frontEnd; auto& layerFE = layer->getLayerFE(); - const Region clip(viewportRegion.intersect(layerFEState.geomVisibleRegion)); + const Region clip(viewportRegion.intersect(layerState.visibleRegion)); ALOGV("Layer: %s", layerFE.getDebugName()); if (clip.isEmpty()) { ALOGV(" Skipping for empty clip"); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 73bb03be02..21f0ce8b15 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -315,11 +315,6 @@ void OutputLayer::updateCompositionState(bool includeGeometry) { ? outputState.targetDataspace : layerFEState.dataspace; - // TODO(lpique): b/121291683 Remove this one we are sure we don't need the - // value recomputed / set every frame. - mState.visibleRegion = outputState.transform.transform( - layerFEState.geomVisibleRegion.intersect(outputState.viewport)); - // These are evaluated every frame as they can potentially change at any // time. if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(mState.dataspace)) { @@ -421,13 +416,13 @@ void OutputLayer::writeOutputIndependentGeometryStateToHWC( void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) { const auto& outputDependentState = getState(); - // TODO(lpique): b/121291683 visibleRegion is output-dependent geometry + // TODO(lpique): b/121291683 outputSpaceVisibleRegion is output-dependent geometry // state and should not change every frame. - if (auto error = hwcLayer->setVisibleRegion(outputDependentState.visibleRegion); + if (auto error = hwcLayer->setVisibleRegion(outputDependentState.outputSpaceVisibleRegion); error != HWC2::Error::None) { ALOGE("[%s] Failed to set visible region: %s (%d)", mLayerFE->getDebugName(), to_string(error).c_str(), static_cast(error)); - outputDependentState.visibleRegion.dump(LOG_TAG); + outputDependentState.outputSpaceVisibleRegion.dump(LOG_TAG); } if (auto error = hwcLayer->setDataspace(outputDependentState.dataspace); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp index e320bee4e1..ad668b6b89 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp @@ -41,6 +41,15 @@ void OutputLayerCompositionState::dump(std::string& out) const { out.append(" "); dumpVal(out, "visibleRegion", visibleRegion); + out.append(" "); + dumpVal(out, "visibleNonTransparentRegion", visibleNonTransparentRegion); + + out.append(" "); + dumpVal(out, "coveredRegion", coveredRegion); + + out.append(" "); + dumpVal(out, "output visibleRegion", outputSpaceVisibleRegion); + out.append(" "); dumpVal(out, "forceClientComposition", forceClientComposition); dumpVal(out, "clearClientTarget", clearClientTarget); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 75e960c575..2276dc3691 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -574,7 +574,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static const half4 kColor; static const Rect kDisplayFrame; - static const Region kVisibleRegion; + static const Region kOutputSpaceVisibleRegion; static const mat4 kColorTransform; static const Region kSurfaceDamage; static const HdrMetadata kHdrMetadata; @@ -590,7 +590,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { outputLayerState.sourceCrop = kSourceCrop; outputLayerState.z = kZOrder; outputLayerState.bufferTransform = static_cast(kBufferTransform); - outputLayerState.visibleRegion = kVisibleRegion; + outputLayerState.outputSpaceVisibleRegion = kOutputSpaceVisibleRegion; outputLayerState.dataspace = kDataspace; mLayerState.frontEnd.blendMode = kBlendMode; @@ -629,7 +629,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { } void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None) { - EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(kVisibleRegion))) + EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(kOutputSpaceVisibleRegion))) .WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setDataspace(kDataspace)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform)) @@ -673,7 +673,8 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 83.f / 255.f, 84.f / 255.f}; const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044}; -const Region OutputLayerWriteStateToHWCTest::kVisibleRegion{Rect{1005, 1006, 1007, 1008}}; +const Region OutputLayerWriteStateToHWCTest::kOutputSpaceVisibleRegion{ + Rect{1005, 1006, 1007, 1008}}; const mat4 OutputLayerWriteStateToHWCTest::kColorTransform{ 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 1d5f2f0d54..b0e8e3699c 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -661,9 +661,9 @@ TEST_F(GenerateClientCompositionRequestsTest, worksForLandscapeModeSplitScreen) impl::OutputLayerCompositionState leftOutputLayerState; leftOutputLayerState.clearClientTarget = false; + leftOutputLayerState.visibleRegion = Region{Rect{0, 0, 1000, 1000}}; impl::LayerCompositionState leftLayerState; - leftLayerState.frontEnd.geomVisibleRegion = Region{Rect{0, 0, 1000, 1000}}; leftLayerState.frontEnd.isOpaque = true; const half3 leftLayerColor{1.f, 0.f, 0.f}; @@ -672,9 +672,9 @@ TEST_F(GenerateClientCompositionRequestsTest, worksForLandscapeModeSplitScreen) impl::OutputLayerCompositionState rightOutputLayerState; rightOutputLayerState.clearClientTarget = false; + rightOutputLayerState.visibleRegion = Region{Rect{1000, 0, 2000, 1000}}; impl::LayerCompositionState rightLayerState; - rightLayerState.frontEnd.geomVisibleRegion = Region{Rect{1000, 0, 2000, 1000}}; rightLayerState.frontEnd.isOpaque = true; const half3 rightLayerColor{0.f, 1.f, 0.f}; @@ -735,9 +735,9 @@ TEST_F(GenerateClientCompositionRequestsTest, ignoresLayersThatDoNotIntersectWit impl::OutputLayerCompositionState outputLayerState; outputLayerState.clearClientTarget = false; + outputLayerState.visibleRegion = Region{Rect{3000, 0, 4000, 1000}}; impl::LayerCompositionState layerState; - layerState.frontEnd.geomVisibleRegion = Region{Rect{3000, 0, 4000, 1000}}; layerState.frontEnd.isOpaque = true; EXPECT_CALL(*outputLayer, getState()).WillRepeatedly(ReturnRef(outputLayerState)); @@ -790,16 +790,16 @@ TEST_F(GenerateClientCompositionRequestsTest, clearsDeviceLayesAfterFirst) { impl::OutputLayerCompositionState leftOutputLayerState; leftOutputLayerState.clearClientTarget = true; + leftOutputLayerState.visibleRegion = Region{Rect{0, 0, 1000, 1000}}; impl::LayerCompositionState leftLayerState; - leftLayerState.frontEnd.geomVisibleRegion = Region{Rect{0, 0, 1000, 1000}}; leftLayerState.frontEnd.isOpaque = true; impl::OutputLayerCompositionState rightOutputLayerState; rightOutputLayerState.clearClientTarget = true; + rightOutputLayerState.visibleRegion = Region{Rect{1000, 0, 2000, 1000}}; impl::LayerCompositionState rightLayerState; - rightLayerState.frontEnd.geomVisibleRegion = Region{Rect{1000, 0, 2000, 1000}}; rightLayerState.frontEnd.isOpaque = true; const half3 rightLayerColor{0.f, 1.f, 0.f}; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 557d0bba27..b669421103 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -443,10 +443,6 @@ void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compo const auto& drawingState{getDrawingState()}; compositionState.forceClientComposition = false; - // TODO(lpique): b/121291683 Remove this one we are sure we don't need the - // value recomputed / set every frame. - compositionState.geomVisibleRegion = visibleRegion; - compositionState.isColorspaceAgnostic = isColorSpaceAgnostic(); compositionState.dataspace = mCurrentDataSpace; compositionState.colorTransform = getColorTransform(); @@ -567,27 +563,6 @@ bool Layer::isSecure() const { return (s.flags & layer_state_t::eLayerSecure); } -void Layer::setVisibleRegion(const Region& visibleRegion) { - // always called from main thread - this->visibleRegion = visibleRegion; -} - -void Layer::setCoveredRegion(const Region& coveredRegion) { - // always called from main thread - this->coveredRegion = coveredRegion; -} - -void Layer::setVisibleNonTransparentRegion(const Region& setVisibleNonTransparentRegion) { - // always called from main thread - this->visibleNonTransparentRegion = setVisibleNonTransparentRegion; -} - -void Layer::clearVisibilityRegions() { - visibleRegion.clear(); - visibleNonTransparentRegion.clear(); - coveredRegion.clear(); -} - // ---------------------------------------------------------------------------- // transaction // ---------------------------------------------------------------------------- @@ -1202,7 +1177,8 @@ LayerDebugInfo Layer::getLayerDebugInfo() const { info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string()); info.mType = getType(); info.mTransparentRegion = ds.activeTransparentRegion_legacy; - info.mVisibleRegion = visibleRegion; + + info.mVisibleRegion = debugGetVisibleRegionOnDefaultDisplay(); info.mSurfaceDamageRegion = surfaceDamageRegion; info.mLayerStack = getLayerStack(); info.mX = ds.active_legacy.transform.tx(); @@ -1826,7 +1802,7 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags) LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), [&]() { return layerInfo->mutable_position(); }); LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); - LayerProtoHelper::writeToProto(visibleRegion, + LayerProtoHelper::writeToProto(debugGetVisibleRegionOnDefaultDisplay(), [&]() { return layerInfo->mutable_visible_region(); }); LayerProtoHelper::writeToProto(surfaceDamageRegion, [&]() { return layerInfo->mutable_damage_region(); }); @@ -2003,6 +1979,20 @@ compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( return display->getCompositionDisplay()->getOutputLayerForLayer(getCompositionLayer().get()); } +Region Layer::debugGetVisibleRegionOnDefaultDisplay() const { + sp displayDevice = mFlinger->getDefaultDisplayDeviceLocked(); + if (displayDevice == nullptr) { + return {}; + } + + auto outputLayer = findOutputLayerForDisplay(displayDevice); + if (outputLayer == nullptr) { + return {}; + } + + return outputLayer->getState().visibleRegion; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 23809e85be..02a7d36b4d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -98,10 +98,6 @@ class Layer : public compositionengine::LayerFE { public: mutable bool contentDirty{false}; - // regions below are in window-manager space - Region visibleRegion; - Region coveredRegion; - Region visibleNonTransparentRegion; Region surfaceDamageRegion; // Layer serial number. This gives layers an explicit ordering, so we @@ -518,30 +514,6 @@ public: */ uint32_t doTransaction(uint32_t transactionFlags); - /* - * setVisibleRegion - called to set the new visible region. This gives - * a chance to update the new visible region or record the fact it changed. - */ - void setVisibleRegion(const Region& visibleRegion); - - /* - * setCoveredRegion - called when the covered region changes. The covered - * region corresponds to any area of the surface that is covered - * (transparently or not) by another surface. - */ - void setCoveredRegion(const Region& coveredRegion); - - /* - * setVisibleNonTransparentRegion - called when the visible and - * non-transparent region changes. - */ - void setVisibleNonTransparentRegion(const Region& visibleNonTransparentRegion); - - /* - * Clear the visible, covered, and non-transparent regions. - */ - void clearVisibilityRegions(); - /* * latchBuffer - called each time the screen is redrawn and returns whether * the visible regions need to be recomputed (this is a fairly heavy @@ -684,6 +656,8 @@ public: compositionengine::OutputLayer* findOutputLayerForDisplay( const sp& display) const; + Region debugGetVisibleRegionOnDefaultDisplay() const; + protected: // constant sp mFlinger; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 49a6800409..11e970232d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2793,7 +2793,6 @@ void SurfaceFlinger::computeVisibleRegions( */ Region transparentRegion; - // handle hidden surfaces by setting the visible region to empty if (CC_LIKELY(layer->isVisible())) { const bool translucent = !layer->isOpaque(s); @@ -2826,7 +2825,6 @@ void SurfaceFlinger::computeVisibleRegions( } if (visibleRegion.isEmpty()) { - layer->clearVisibilityRegions(); return; } @@ -2839,12 +2837,21 @@ void SurfaceFlinger::computeVisibleRegions( // subtract the opaque region covered by the layers above us visibleRegion.subtractSelf(aboveOpaqueLayers); + // Get coverage information for the layer as previously displayed + auto prevOutputLayer = display->getOutputLayerForLayer(compositionLayer.get()); + // TODO(b/121291683): Define this as a constant in Region.h + const Region kEmptyRegion; + const Region& oldVisibleRegion = + prevOutputLayer ? prevOutputLayer->getState().visibleRegion : kEmptyRegion; + const Region& oldCoveredRegion = + prevOutputLayer ? prevOutputLayer->getState().coveredRegion : kEmptyRegion; + // compute this layer's dirty region if (layer->contentDirty) { // we need to invalidate the whole region dirty = visibleRegion; // as well, as the old visible region - dirty.orSelf(layer->visibleRegion); + dirty.orSelf(oldVisibleRegion); layer->contentDirty = false; } else { /* compute the exposed region: @@ -2860,8 +2867,6 @@ void SurfaceFlinger::computeVisibleRegions( * exposed because of a resize. */ const Region newExposed = visibleRegion - coveredRegion; - const Region oldVisibleRegion = layer->visibleRegion; - const Region oldCoveredRegion = layer->coveredRegion; const Region oldExposed = oldVisibleRegion - oldCoveredRegion; dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed); } @@ -2873,16 +2878,13 @@ void SurfaceFlinger::computeVisibleRegions( // Update aboveOpaqueLayers for next (lower) layer aboveOpaqueLayers.orSelf(opaqueRegion); - // Store the visible region in screen space - layer->setVisibleRegion(visibleRegion); - layer->setCoveredRegion(coveredRegion); - layer->setVisibleNonTransparentRegion( - visibleRegion.subtract(transparentRegion)); + // Compute the visible non-transparent region + Region visibleNonTransparentRegion = visibleRegion.subtract(transparentRegion); - // Setup an output layer for this output if the layer is - // visible on this output + // Setup an output layer for this output if the layer is visible on this + // output const auto& displayState = display->getState(); - Region drawRegion(displayState.transform.transform(layer->visibleNonTransparentRegion)); + Region drawRegion(displayState.transform.transform(visibleNonTransparentRegion)); drawRegion.andSelf(displayState.bounds); if (drawRegion.isEmpty()) { return; @@ -2895,8 +2897,11 @@ void SurfaceFlinger::computeVisibleRegions( outLayersSortedByZ.emplace_back( display->getOrCreateOutputLayer(displayId, compositionLayer, layerFE)); auto& outputLayerState = outLayersSortedByZ.back()->editState(); - outputLayerState.visibleRegion = displayState.transform.transform( - layer->visibleRegion.intersect(displayState.viewport)); + outputLayerState.visibleRegion = std::move(visibleRegion); + outputLayerState.visibleNonTransparentRegion = std::move(visibleNonTransparentRegion); + outputLayerState.coveredRegion = std::move(coveredRegion); + outputLayerState.outputSpaceVisibleRegion = displayState.transform.transform( + outputLayerState.visibleRegion.intersect(displayState.viewport)); }); outOpaqueRegion = aboveOpaqueLayers; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 425768e244..9e4d57e7dc 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -614,6 +614,12 @@ struct BaseLayerProperties { displaySettings.clip); // screen capture adds an additional color layer as an alpha // prefill, so gtet the back layer. + if (layerSettings.empty()) { + ADD_FAILURE() << "layerSettings was not expected to be empty in " + "setupREBufferCompositionCommonCallExpectations " + "verification lambda"; + return NO_ERROR; + } renderengine::LayerSettings layer = layerSettings.back(); EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull())); EXPECT_THAT(layer.source.buffer.fence, Not(IsNull())); @@ -657,6 +663,12 @@ struct BaseLayerProperties { displaySettings.clip); // screen capture adds an additional color layer as an alpha // prefill, so get the back layer. + if (layerSettings.empty()) { + ADD_FAILURE() + << "layerSettings was not expected to be empty in " + "setupREColorCompositionCallExpectations verification lambda"; + return NO_ERROR; + } renderengine::LayerSettings layer = layerSettings.back(); EXPECT_THAT(layer.source.buffer.buffer, IsNull()); EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1], @@ -727,6 +739,12 @@ struct SecureLayerProperties : public BaseLayerProperties displaySettings.clip); // screen capture adds an additional color layer as an alpha // prefill, so get the back layer. + if (layerSettings.empty()) { + ADD_FAILURE() << "layerSettings was not expected to be empty in " + "setupInsecureREBufferCompositionCommonCallExpectations " + "verification lambda"; + return NO_ERROR; + } renderengine::LayerSettings layer = layerSettings.back(); EXPECT_THAT(layer.source.buffer.buffer, IsNull()); EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor); @@ -786,7 +804,6 @@ struct BaseLayerVariant { layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1], LayerProperties::COLOR[2], LayerProperties::COLOR[3]); layer->computeBounds(FloatRect(0, 0, 100, 100), ui::Transform()); - layer->setVisibleRegion(Region(Rect(0, 0, 100, 100))); return layer; } @@ -801,6 +818,9 @@ struct BaseLayerVariant { layer->getCompositionLayer(), layer)); + outputLayers.back()->editState().visibleRegion = Region(Rect(0, 0, 100, 100)); + outputLayers.back()->editState().outputSpaceVisibleRegion = Region(Rect(0, 0, 100, 100)); + test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(std::move(outputLayers)); Mock::VerifyAndClear(test->mComposer); -- GitLab From 27b537220105b8e01ff6feaa44e2e6d391f78d86 Mon Sep 17 00:00:00 2001 From: Raymond Chiu Date: Tue, 3 Sep 2019 17:55:10 -0700 Subject: [PATCH 0248/1255] Ensure FrameTracer is only initialized once. Bug: 140307339 Test: adb shell service call SurfaceFlinger 1 (This triggers bootFinished) Change-Id: I4a9c5587288d7a67d955e91bf3185fc2f2ccfd77 --- services/surfaceflinger/FrameTracer/FrameTracer.cpp | 11 +++++++---- services/surfaceflinger/FrameTracer/FrameTracer.h | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.cpp b/services/surfaceflinger/FrameTracer/FrameTracer.cpp index 7cbb8d8b7c..006dbfe67e 100644 --- a/services/surfaceflinger/FrameTracer/FrameTracer.cpp +++ b/services/surfaceflinger/FrameTracer/FrameTracer.cpp @@ -23,16 +23,19 @@ #include #include +#include PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::FrameTracer::FrameTracerDataSource); namespace android { void FrameTracer::initialize() { - perfetto::TracingInitArgs args; - args.backends = perfetto::kSystemBackend; - perfetto::Tracing::Initialize(args); - registerDataSource(); + std::call_once(mInitializationFlag, [this]() { + perfetto::TracingInitArgs args; + args.backends = perfetto::kSystemBackend; + perfetto::Tracing::Initialize(args); + registerDataSource(); + }); } void FrameTracer::registerDataSource() { diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.h b/services/surfaceflinger/FrameTracer/FrameTracer.h index d34ad81fee..d4dfab94eb 100644 --- a/services/surfaceflinger/FrameTracer/FrameTracer.h +++ b/services/surfaceflinger/FrameTracer/FrameTracer.h @@ -100,6 +100,7 @@ private: std::mutex mTraceMutex; std::unordered_map mTraceTracker; + std::once_flag mInitializationFlag; }; } // namespace android -- GitLab From c668734cece8d71ead434517e0a4fa9752bd79ce Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 7 Mar 2019 21:34:57 -0800 Subject: [PATCH 0249/1255] SF: Add ability to get basic geometry For computing the layer visibility, CompositionEngine will need to get basic geometry state for every layer, without getting everything. Add a new request type for the basic geometry state, and modify the existing code in computeVisibleRegions to use it rather than accessing directly through the front-end layer pointer. Test: atest libsurfaceflinger_unittest libcompositionengine_test Test: go/wm-smoke Bug: 121291683 Change-Id: Ie286fe1986a4c383ee390c1f646c7a8a5b8c14f4 --- .../include/compositionengine/LayerFE.h | 23 ++++++- .../LayerFECompositionState.h | 56 ++++++++++----- .../include/compositionengine/Output.h | 2 +- .../include/compositionengine/impl/Output.h | 2 +- .../include/compositionengine/mock/LayerFE.h | 3 +- .../include/compositionengine/mock/Output.h | 2 +- .../src/LayerCompositionState.cpp | 2 +- .../CompositionEngine/src/Output.cpp | 9 ++- .../CompositionEngine/src/OutputLayer.cpp | 4 +- .../tests/OutputLayerTest.cpp | 6 +- .../CompositionEngine/tests/OutputTest.cpp | 4 ++ services/surfaceflinger/Layer.cpp | 69 ++++++++++++++----- services/surfaceflinger/Layer.h | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 42 ++++++----- 14 files changed, 158 insertions(+), 69 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index db4f9698e2..57cca69eb2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -39,9 +39,26 @@ public: // process. virtual bool onPreComposition(nsecs_t refreshStartTime) = 0; - // Latches the output-independent state. If includeGeometry is false, the - // geometry state can be skipped. - virtual void latchCompositionState(LayerFECompositionState&, bool includeGeometry) const = 0; + // Used with latchCompositionState() + enum class StateSubset { + // Gets the basic geometry (bounds, transparent region, visibility, + // transforms, alpha) for the layer, for computing visibility and + // coverage. + BasicGeometry, + + // Gets the full geometry (crops, buffer transforms, metadata) and + // content (buffer or color) state for the layer. + GeometryAndContent, + + // Gets the per frame content (buffer or color) state the layer. + Content, + }; + + // Latches 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. diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index b066cd1bda..530f49a600 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -40,6 +40,45 @@ struct LayerFECompositionState { // the next geometry change. bool forceClientComposition{false}; + // TODO(b/121291683): Reorganize and rename the contents of this structure + + /* + * Visibility state + */ + // the layer stack this layer belongs to + std::optional layerStackId; + + // If true, this layer should be only visible on the internal display + bool internalOnly{false}; + + // If false, this layer should not be considered visible + bool isVisible{true}; + + // True if the layer is completely opaque + bool isOpaque{true}; + + // If true, invalidates the entire visible region + bool contentDirty{false}; + + // The alpha value for this layer + float alpha{1.f}; + + // The transform from layer local coordinates to composition coordinates + ui::Transform geomLayerTransform; + + // The inverse of the layer transform + ui::Transform geomInverseLayerTransform; + + // The hint from the layer producer as to what portion of the layer is + // transparent. + Region transparentRegionHint; + + // The blend mode for this layer + Hwc2::IComposerClient::BlendMode blendMode{Hwc2::IComposerClient::BlendMode::INVALID}; + + // The bounds of the layer in layer local coordinates + FloatRect geomLayerBounds; + /* * Geometry state */ @@ -48,23 +87,9 @@ struct LayerFECompositionState { bool geomUsesSourceCrop{false}; bool geomBufferUsesDisplayInverseTransform{false}; uint32_t geomBufferTransform{0}; - ui::Transform geomLayerTransform; - ui::Transform geomInverseLayerTransform; Rect geomBufferSize; Rect geomContentCrop; Rect geomCrop; - Region geomActiveTransparentRegion; - FloatRect geomLayerBounds; - - /* - * Presentation - */ - - // The blend mode for this layer - Hwc2::IComposerClient::BlendMode blendMode{Hwc2::IComposerClient::BlendMode::INVALID}; - - // The alpha value for this layer - float alpha{1.f}; /* * Extra metadata @@ -113,9 +138,6 @@ struct LayerFECompositionState { mat4 colorTransform; bool colorTransformIsIdentity{true}; - // True if the layer is completely opaque - bool isOpaque{true}; - // True if the layer has protected content bool hasProtectedContent{false}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index a509ca8129..43f44af8ca 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -132,7 +132,7 @@ public: // A layer belongs to the output if its layerStackId matches. Additionally // if the layer should only show in the internal (primary) display only and // this output allows that. - virtual bool belongsInOutput(uint32_t layerStackId, bool internalOnly) const = 0; + virtual bool belongsInOutput(std::optional layerStackId, bool internalOnly) 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 diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index d826161a4d..ece5b1c5ee 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -62,7 +62,7 @@ public: OutputCompositionState& editState() override; Region getDirtyRegion(bool repaintEverything) const override; - bool belongsInOutput(uint32_t, bool) const override; + bool belongsInOutput(std::optional, bool) const override; compositionengine::OutputLayer* getOutputLayerForLayer( compositionengine::Layer*) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index e2802954d6..3eada3c6aa 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -32,7 +32,8 @@ public: MOCK_METHOD1(onPreComposition, bool(nsecs_t)); - MOCK_CONST_METHOD2(latchCompositionState, void(LayerFECompositionState&, bool)); + MOCK_CONST_METHOD2(latchCompositionState, + void(LayerFECompositionState&, compositionengine::LayerFE::StateSubset)); MOCK_CONST_METHOD1(latchCursorCompositionState, void(LayerFECompositionState&)); MOCK_METHOD1(prepareClientComposition, std::optional( diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 33925d5691..2f24c15896 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -59,7 +59,7 @@ public: MOCK_METHOD0(editState, OutputCompositionState&()); MOCK_CONST_METHOD1(getDirtyRegion, Region(bool)); - MOCK_CONST_METHOD2(belongsInOutput, bool(uint32_t, bool)); + MOCK_CONST_METHOD2(belongsInOutput, bool(std::optional, bool)); MOCK_CONST_METHOD1(getOutputLayerForLayer, compositionengine::OutputLayer*(compositionengine::Layer*)); diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp index 0dc4bf1559..c5debf6e77 100644 --- a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp @@ -45,7 +45,7 @@ void dumpFrontEnd(std::string& out, const LayerFECompositionState& state) { dumpVal(out, "geomBufferTransform", state.geomBufferTransform); out.append("\n "); - dumpVal(out, "geomActiveTransparentRegion", state.geomActiveTransparentRegion); + dumpVal(out, "transparentRegionHint", state.transparentRegionHint); out.append(" "); dumpVal(out, "geomLayerBounds", state.geomLayerBounds); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 9f4f259f7c..4dfdebae02 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -212,10 +212,11 @@ Region Output::getDirtyRegion(bool repaintEverything) const { return dirty; } -bool Output::belongsInOutput(uint32_t layerStackId, bool internalOnly) const { +bool Output::belongsInOutput(std::optional layerStackId, bool internalOnly) const { // The layerStackId's must match, and also the layer must not be internal // only when not on an internal output. - return (layerStackId == mState.layerStackId) && (!internalOnly || mState.layerStackInternal); + return layerStackId && (*layerStackId == mState.layerStackId) && + (!internalOnly || mState.layerStackInternal); } compositionengine::OutputLayer* Output::getOutputLayerForLayer( @@ -281,7 +282,9 @@ void Output::present(const compositionengine::CompositionRefreshArgs& refreshArg void Output::updateLayerStateFromFE(const CompositionRefreshArgs& args) const { for (auto& layer : mOutputLayersOrderedByZ) { layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd, - args.updatingGeometryThisFrame); + args.updatingGeometryThisFrame + ? LayerFE::StateSubset::GeometryAndContent + : LayerFE::StateSubset::Content); } } diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 21f0ce8b15..3a0ebf8121 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -102,7 +102,7 @@ Rect OutputLayer::calculateInitialCrop() const { // pixels in the buffer. FloatRect activeCropFloat = - reduce(layerState.geomLayerBounds, layerState.geomActiveTransparentRegion); + reduce(layerState.geomLayerBounds, layerState.transparentRegionHint); const Rect& viewport = mOutput.getState().viewport; const ui::Transform& layerTransform = layerState.geomLayerTransform; @@ -209,7 +209,7 @@ Rect OutputLayer::calculateOutputDisplayFrame() const { // apply the layer's transform, followed by the display's global transform // here we're guaranteed that the layer's transform preserves rects - Region activeTransparentRegion = layerState.geomActiveTransparentRegion; + Region activeTransparentRegion = layerState.transparentRegionHint; const ui::Transform& layerTransform = layerState.geomLayerTransform; const ui::Transform& inverseLayerTransform = layerState.geomInverseLayerTransform; const Rect& bufferSize = layerState.geomBufferSize; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 2276dc3691..65691ffbc7 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -124,7 +124,7 @@ struct OutputLayerSourceCropTest : public OutputLayerTest { // set one specific value to something different. mLayerState.frontEnd.geomUsesSourceCrop = true; mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 1920, 1080}; - mLayerState.frontEnd.geomActiveTransparentRegion = Region{}; + mLayerState.frontEnd.transparentRegionHint = Region{}; mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f}; mLayerState.frontEnd.geomLayerTransform = ui::Transform{TR_IDENT}; mLayerState.frontEnd.geomBufferSize = Rect{0, 0, 1920, 1080}; @@ -231,7 +231,7 @@ struct OutputLayerDisplayFrameTest : public OutputLayerTest { // Set reasonable default values for a simple case. Each test will // set one specific value to something different. - mLayerState.frontEnd.geomActiveTransparentRegion = Region{}; + mLayerState.frontEnd.transparentRegionHint = Region{}; mLayerState.frontEnd.geomLayerTransform = ui::Transform{TR_IDENT}; mLayerState.frontEnd.geomBufferSize = Rect{0, 0, 1920, 1080}; mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = false; @@ -256,7 +256,7 @@ TEST_F(OutputLayerDisplayFrameTest, correctForSimpleDefaultCase) { } TEST_F(OutputLayerDisplayFrameTest, fullActiveTransparentRegionReturnsEmptyFrame) { - mLayerState.frontEnd.geomActiveTransparentRegion = Region{Rect{0, 0, 1920, 1080}}; + mLayerState.frontEnd.transparentRegionHint = Region{Rect{0, 0, 1920, 1080}}; const Rect expected{0, 0, 0, 0}; EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected)); } diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index b0e8e3699c..70d98717ae 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -356,6 +356,10 @@ TEST_F(OutputTest, belongsInOutputFiltersAsExpected) { // If the output accepts layerStack1 and internal-only layers.... mOutput.setLayerStackFilter(layerStack1, true); + // A layer with no layerStack does not belong to it, internal-only or not. + EXPECT_FALSE(mOutput.belongsInOutput(std::nullopt, false)); + EXPECT_FALSE(mOutput.belongsInOutput(std::nullopt, true)); + // Any layer with layerStack1 belongs to it, internal-only or not. EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, false)); EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, true)); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5e5302d83c..974488da62 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -417,15 +417,44 @@ void Layer::setupRoundedCornersCropCoordinates(Rect win, win.bottom -= roundedCornersCrop.top; } -void Layer::latchGeometry(compositionengine::LayerFECompositionState& compositionState) const { +void Layer::latchBasicGeometry(compositionengine::LayerFECompositionState& compositionState) const { const auto& drawingState{getDrawingState()}; - auto alpha = static_cast(getAlpha()); - auto blendMode = HWC2::BlendMode::None; - if (!isOpaque(drawingState) || alpha != 1.0f) { - blendMode = - mPremultipliedAlpha ? HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage; + const uint32_t layerStack = getLayerStack(); + const auto alpha = static_cast(getAlpha()); + const bool opaque = isOpaque(drawingState); + const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f; + + auto blendMode = Hwc2::IComposerClient::BlendMode::NONE; + if (!opaque || alpha != 1.0f) { + blendMode = mPremultipliedAlpha ? Hwc2::IComposerClient::BlendMode::PREMULTIPLIED + : 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 = + (layerStack != ~0u) ? std::make_optional(layerStack) : std::nullopt; + compositionState.internalOnly = getPrimaryDisplayOnly(); + compositionState.isVisible = isVisible(); + compositionState.isOpaque = opaque && !usesRoundedCorners && alpha == 1.f; + + compositionState.contentDirty = contentDirty; + contentDirty = false; + + compositionState.geomLayerBounds = mBounds; + compositionState.geomLayerTransform = getTransform(); + compositionState.geomInverseLayerTransform = compositionState.geomLayerTransform.inverse(); + compositionState.transparentRegionHint = getActiveTransparentRegion(drawingState); + + compositionState.blendMode = static_cast(blendMode); + compositionState.alpha = alpha; +} + +void Layer::latchGeometry(compositionengine::LayerFECompositionState& compositionState) const { + const auto& drawingState{getDrawingState()}; + int type = drawingState.metadata.getInt32(METADATA_WINDOW_TYPE, 0); int appId = drawingState.metadata.getInt32(METADATA_OWNER_UID, 0); sp parent = mDrawingParent.promote(); @@ -439,20 +468,14 @@ void Layer::latchGeometry(compositionengine::LayerFECompositionState& compositio } } - compositionState.geomLayerTransform = getTransform(); - compositionState.geomInverseLayerTransform = compositionState.geomLayerTransform.inverse(); compositionState.geomBufferSize = getBufferSize(drawingState); compositionState.geomContentCrop = getContentCrop(); compositionState.geomCrop = getCrop(drawingState); compositionState.geomBufferTransform = mCurrentTransform; compositionState.geomBufferUsesDisplayInverseTransform = getTransformToDisplayInverse(); - compositionState.geomActiveTransparentRegion = getActiveTransparentRegion(drawingState); - compositionState.geomLayerBounds = mBounds; compositionState.geomUsesSourceCrop = usesSourceCrop(); compositionState.isSecure = isSecure(); - compositionState.blendMode = static_cast(blendMode); - compositionState.alpha = alpha; compositionState.type = type; compositionState.appId = appId; } @@ -498,12 +521,24 @@ bool Layer::onPreComposition(nsecs_t) { } void Layer::latchCompositionState(compositionengine::LayerFECompositionState& compositionState, - bool includeGeometry) const { - if (includeGeometry) { - latchGeometry(compositionState); - } + compositionengine::LayerFE::StateSubset subset) const { + using StateSubset = compositionengine::LayerFE::StateSubset; + + switch (subset) { + case StateSubset::BasicGeometry: + latchBasicGeometry(compositionState); + break; - latchPerFrameState(compositionState); + case StateSubset::GeometryAndContent: + latchBasicGeometry(compositionState); + latchGeometry(compositionState); + latchPerFrameState(compositionState); + break; + + case StateSubset::Content: + latchPerFrameState(compositionState); + break; + } } const char* Layer::getDebugName() const { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 1486efe8ae..02c78c9d66 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -471,7 +471,7 @@ public: */ bool onPreComposition(nsecs_t) override; void latchCompositionState(compositionengine::LayerFECompositionState&, - bool includeGeometry) const override; + compositionengine::LayerFE::StateSubset subset) const override; void latchCursorCompositionState(compositionengine::LayerFECompositionState&) const override; std::optional prepareClientComposition( compositionengine::LayerFE::ClientCompositionTargetSettings&) override; @@ -479,6 +479,7 @@ public: 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; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3498419cdf..6d853f957a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2757,11 +2757,22 @@ void SurfaceFlinger::computeVisibleRegions( return; } - // start with the whole surface at its current location - const Layer::State& s(layer->getDrawingState()); + // Note: Converts a wp to a sp + auto layerFE = compositionLayer->getLayerFE(); + if (layerFE == nullptr) { + return; + } + + // Request a snapshot of the subset of state relevant to visibility + // determination + layerFE->latchCompositionState(compositionLayer->editState().frontEnd, + compositionengine::LayerFE::StateSubset::BasicGeometry); + + // Work with a read-only copy of the snapshot + const auto& layerFEState = compositionLayer->getState().frontEnd; // only consider the layers on the given layer stack - if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) { + if (!display->belongsInOutput(layerFEState.layerStackId, layerFEState.internalOnly)) { return; } @@ -2795,18 +2806,17 @@ void SurfaceFlinger::computeVisibleRegions( Region transparentRegion; // handle hidden surfaces by setting the visible region to empty - if (CC_LIKELY(layer->isVisible())) { - const bool translucent = !layer->isOpaque(s); - Rect bounds(layer->getScreenBounds()); - - visibleRegion.set(bounds); - ui::Transform tr = layer->getTransform(); + if (CC_LIKELY(layerFEState.isVisible)) { + // Get the visible region + visibleRegion.set( + Rect(layerFEState.geomLayerTransform.transform(layerFEState.geomLayerBounds))); + const ui::Transform& tr = layerFEState.geomLayerTransform; if (!visibleRegion.isEmpty()) { // Remove the transparent area from the visible region - if (translucent) { + if (!layerFEState.isOpaque) { if (tr.preserveRects()) { // transform the transparent region - transparentRegion = tr.transform(layer->getActiveTransparentRegion(s)); + transparentRegion = tr.transform(layerFEState.transparentRegionHint); } else { // transformation too complex, can't do the // transparent region optimization. @@ -2816,9 +2826,8 @@ void SurfaceFlinger::computeVisibleRegions( // compute the opaque region const int32_t layerOrientation = tr.getOrientation(); - if (layer->getAlpha() == 1.0f && !translucent && - layer->getRoundedCornerState().radius == 0.0f && - ((layerOrientation & ui::Transform::ROT_INVALID) == false)) { + if (layerFEState.isOpaque && + ((layerOrientation & ui::Transform::ROT_INVALID) == false)) { // the opaque region is the layer's footprint opaqueRegion = visibleRegion; } @@ -2848,12 +2857,11 @@ void SurfaceFlinger::computeVisibleRegions( prevOutputLayer ? prevOutputLayer->getState().coveredRegion : kEmptyRegion; // compute this layer's dirty region - if (layer->contentDirty) { + if (layerFEState.contentDirty) { // we need to invalidate the whole region dirty = visibleRegion; // as well, as the old visible region dirty.orSelf(oldVisibleRegion); - layer->contentDirty = false; } else { /* compute the exposed region: * the exposed region consists of two components: @@ -2892,8 +2900,6 @@ void SurfaceFlinger::computeVisibleRegions( } const auto displayId = displayDevice->getId(); - sp layerFE = compositionLayer->getLayerFE(); - LOG_ALWAYS_FATAL_IF(layerFE.get() == nullptr); outLayersSortedByZ.emplace_back( display->getOrCreateOutputLayer(displayId, compositionLayer, layerFE)); -- GitLab From 4244e0356083fba0a367b9cb5422cd24d567518a Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 4 Sep 2019 11:27:49 -0700 Subject: [PATCH 0250/1255] Created bufferInfo to track buffer data in a single place (1/2) This is in preparation for layer mirroring since mirrored buffer layers should just copy the bufferInfo instead of the entire BufferQueue or parts of BufferState Test: go/wm-smoke Change-Id: Iba1be05c4b038f0b678150deed8e673bf1e7710b --- services/surfaceflinger/BufferLayer.cpp | 124 +++++++++++------- services/surfaceflinger/BufferLayer.h | 46 ++++--- services/surfaceflinger/BufferQueueLayer.cpp | 65 +++------- services/surfaceflinger/BufferQueueLayer.h | 15 +-- services/surfaceflinger/BufferStateLayer.cpp | 126 +++++++------------ services/surfaceflinger/BufferStateLayer.h | 20 +-- services/surfaceflinger/ColorLayer.cpp | 9 +- services/surfaceflinger/ColorLayer.h | 2 +- services/surfaceflinger/Layer.cpp | 42 ++----- services/surfaceflinger/Layer.h | 12 +- 10 files changed, 204 insertions(+), 257 deletions(-) diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 90a02b3ad9..bca15e6903 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -81,7 +81,7 @@ void BufferLayer::useSurfaceDamage() { if (mFlinger->mForceFullDamage) { surfaceDamageRegion = Region::INVALID_REGION; } else { - surfaceDamageRegion = getDrawingSurfaceDamage(); + surfaceDamageRegion = mBufferInfo.mSurfaceDamage; } } @@ -187,7 +187,7 @@ std::optional BufferLayer::prepareClientComposition // Query the texture matrix given our current filtering mode. float textureMatrix[16]; setFilteringEnabled(useFiltering); - getDrawingTransformMatrix(textureMatrix); + memcpy(textureMatrix, mBufferInfo.mTransformMatrix, sizeof(mBufferInfo.mTransformMatrix)); if (getTransformToDisplayInverse()) { /* @@ -254,8 +254,8 @@ std::optional BufferLayer::prepareClientComposition bool BufferLayer::isHdrY410() const { // pixel format is HDR Y410 masquerading as RGBA_1010102 - return (mCurrentDataSpace == ui::Dataspace::BT2020_ITU_PQ && - getDrawingApi() == NATIVE_WINDOW_API_MEDIA && + return (mBufferInfo.mDataspace == ui::Dataspace::BT2020_ITU_PQ && + mBufferInfo.mApi == NATIVE_WINDOW_API_MEDIA && mActiveBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102); } @@ -268,7 +268,7 @@ void BufferLayer::latchPerFrameState( compositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND; } else { // Normal buffer layers - compositionState.hdrMetadata = getDrawingHdrMetadata(); + compositionState.hdrMetadata = mBufferInfo.mHdrMetadata; compositionState.compositionType = mPotentialCursor ? Hwc2::IComposerClient::Composition::CURSOR : Hwc2::IComposerClient::Composition::DEVICE; @@ -300,13 +300,13 @@ bool BufferLayer::onPostComposition(const std::optional& displayId, } // Update mFrameTracker. - nsecs_t desiredPresentTime = getDesiredPresentTime(); + nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime; mFrameTracker.setDesiredPresentTime(desiredPresentTime); const int32_t layerID = getSequence(); mFlinger->mTimeStats->setDesiredTime(layerID, mCurrentFrameNumber, desiredPresentTime); - std::shared_ptr frameReadyFence = getCurrentFenceTime(); + std::shared_ptr frameReadyFence = mBufferInfo.mFenceTime; if (frameReadyFence->isValid()) { mFrameTracker.setFrameReadyFence(std::move(frameReadyFence)); } else { @@ -394,6 +394,9 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, return false; } + BufferInfo oldBufferInfo = mBufferInfo; + gatherBufferInfo(); + mRefreshPending = true; mFrameLatencyNeeded = true; if (oldBuffer == nullptr) { @@ -402,43 +405,10 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, recomputeVisibleRegions = true; } - ui::Dataspace dataSpace = getDrawingDataSpace(); - // translate legacy dataspaces to modern dataspaces - switch (dataSpace) { - case ui::Dataspace::SRGB: - dataSpace = ui::Dataspace::V0_SRGB; - break; - case ui::Dataspace::SRGB_LINEAR: - dataSpace = ui::Dataspace::V0_SRGB_LINEAR; - break; - case ui::Dataspace::JFIF: - dataSpace = ui::Dataspace::V0_JFIF; - break; - case ui::Dataspace::BT601_625: - dataSpace = ui::Dataspace::V0_BT601_625; - break; - case ui::Dataspace::BT601_525: - dataSpace = ui::Dataspace::V0_BT601_525; - break; - case ui::Dataspace::BT709: - dataSpace = ui::Dataspace::V0_BT709; - break; - default: - break; - } - mCurrentDataSpace = dataSpace; - - Rect crop(getDrawingCrop()); - const uint32_t transform(getDrawingTransform()); - const uint32_t scalingMode(getDrawingScalingMode()); - const bool transformToDisplayInverse(getTransformToDisplayInverse()); - if ((crop != mCurrentCrop) || (transform != mCurrentTransform) || - (scalingMode != mCurrentScalingMode) || - (transformToDisplayInverse != mTransformToDisplayInverse)) { - mCurrentCrop = crop; - mCurrentTransform = transform; - mCurrentScalingMode = scalingMode; - mTransformToDisplayInverse = transformToDisplayInverse; + if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) || + (mBufferInfo.mTransform != oldBufferInfo.mTransform) || + (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) || + (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) { recomputeVisibleRegions = true; } @@ -510,7 +480,7 @@ uint32_t BufferLayer::getEffectiveScalingMode() const { return mOverrideScalingMode; } - return mCurrentScalingMode; + return mBufferInfo.mScaleMode; } bool BufferLayer::isProtected() const { @@ -626,7 +596,7 @@ Rect BufferLayer::getBufferSize(const State& s) const { uint32_t bufHeight = mActiveBuffer->getHeight(); // Undo any transformations on the buffer and return the result. - if (mCurrentTransform & ui::Transform::ROT_90) { + if (mBufferInfo.mTransform & ui::Transform::ROT_90) { std::swap(bufWidth, bufHeight); } @@ -662,7 +632,7 @@ FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const uint32_t bufHeight = mActiveBuffer->getHeight(); // Undo any transformations on the buffer and return the result. - if (mCurrentTransform & ui::Transform::ROT_90) { + if (mBufferInfo.mTransform & ui::Transform::ROT_90) { std::swap(bufWidth, bufHeight); } @@ -685,6 +655,66 @@ void BufferLayer::latchAndReleaseBuffer() { releasePendingBuffer(systemTime()); } +PixelFormat BufferLayer::getPixelFormat() const { + return mBufferInfo.mPixelFormat; +} + +bool BufferLayer::getTransformToDisplayInverse() const { + return mBufferInfo.mTransformToDisplayInverse; +} + +Rect BufferLayer::getBufferCrop() const { + // this is the crop rectangle that applies to the buffer + // itself (as opposed to the window) + if (!mBufferInfo.mCrop.isEmpty()) { + // if the buffer crop is defined, we use that + return mBufferInfo.mCrop; + } else if (mActiveBuffer != nullptr) { + // otherwise we use the whole buffer + return mActiveBuffer->getBounds(); + } else { + // if we don't have a buffer yet, we use an empty/invalid crop + return Rect(); + } +} + +uint32_t BufferLayer::getBufferTransform() const { + return mBufferInfo.mTransform; +} + +ui::Dataspace BufferLayer::getDataSpace() const { + return mBufferInfo.mDataspace; +} + +ui::Dataspace BufferLayer::translateDataspace(ui::Dataspace dataspace) { + ui::Dataspace updatedDataspace = dataspace; + // translate legacy dataspaces to modern dataspaces + switch (dataspace) { + case ui::Dataspace::SRGB: + updatedDataspace = ui::Dataspace::V0_SRGB; + break; + case ui::Dataspace::SRGB_LINEAR: + updatedDataspace = ui::Dataspace::V0_SRGB_LINEAR; + break; + case ui::Dataspace::JFIF: + updatedDataspace = ui::Dataspace::V0_JFIF; + break; + case ui::Dataspace::BT601_625: + updatedDataspace = ui::Dataspace::V0_BT601_625; + break; + case ui::Dataspace::BT601_525: + updatedDataspace = ui::Dataspace::V0_BT601_525; + break; + case ui::Dataspace::BT709: + updatedDataspace = ui::Dataspace::V0_BT709; + break; + default: + break; + } + + return updatedDataspace; +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index ee44cbe836..e8838e812c 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -106,6 +106,14 @@ public: // Should only be called on the main thread. void latchAndReleaseBuffer() override; + bool getTransformToDisplayInverse() const override; + + Rect getBufferCrop() const override; + + uint32_t getBufferTransform() const override; + + ui::Dataspace getDataSpace() const override; + // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- @@ -115,18 +123,7 @@ private: virtual bool fenceHasSignaled() const = 0; virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0; - virtual nsecs_t getDesiredPresentTime() = 0; - virtual std::shared_ptr getCurrentFenceTime() const = 0; - - virtual void getDrawingTransformMatrix(float *matrix) = 0; - virtual uint32_t getDrawingTransform() const = 0; - virtual ui::Dataspace getDrawingDataSpace() const = 0; - virtual Rect getDrawingCrop() const = 0; - virtual uint32_t getDrawingScalingMode() const = 0; - virtual Region getDrawingSurfaceDamage() const = 0; - virtual const HdrMetadata& getDrawingHdrMetadata() const = 0; - virtual int getDrawingApi() const = 0; - virtual PixelFormat getPixelFormat() const = 0; + PixelFormat getPixelFormat() const; virtual uint64_t getFrameNumber(nsecs_t expectedPresentTime) const = 0; @@ -148,6 +145,25 @@ private: virtual status_t updateFrameNumber(nsecs_t latchTime) = 0; protected: + struct BufferInfo { + nsecs_t mDesiredPresentTime; + std::shared_ptr mFenceTime; + sp mFence; + float mTransformMatrix[16]; + uint32_t mTransform{0}; + ui::Dataspace mDataspace; + Rect mCrop; + uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE}; + Region mSurfaceDamage; + HdrMetadata mHdrMetadata; + int mApi; + PixelFormat mPixelFormat; + bool mTransformToDisplayInverse{false}; + }; + + BufferInfo mBufferInfo; + virtual void gatherBufferInfo() = 0; + /* * compositionengine::LayerFE overrides */ @@ -171,16 +187,14 @@ protected: bool mRefreshPending{false}; + ui::Dataspace translateDataspace(ui::Dataspace dataspace); + private: // Returns true if this layer requires filtering bool needsFiltering(const sp& displayDevice) const override; uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const; - uint32_t mCurrentScalingMode{NATIVE_WINDOW_SCALING_MODE_FREEZE}; - - bool mTransformToDisplayInverse{false}; - // main thread. bool mBufferLatched{false}; // TODO: Use mActiveBuffer? diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 4da39e4d6f..e9e8e6e9dc 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -70,10 +70,6 @@ std::vector BufferQueueLayer::getOccupancyHistory(boo return history; } -bool BufferQueueLayer::getTransformToDisplayInverse() const { - return mConsumer->getTransformToDisplayInverse(); -} - void BufferQueueLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { if (!mConsumer->releasePendingBuffer()) { return; @@ -155,55 +151,12 @@ bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) co return mQueueItems[0].mTimestamp <= expectedPresentTime; } -nsecs_t BufferQueueLayer::getDesiredPresentTime() { - return mConsumer->getTimestamp(); -} - -std::shared_ptr BufferQueueLayer::getCurrentFenceTime() const { - return mConsumer->getCurrentFenceTime(); -} - -void BufferQueueLayer::getDrawingTransformMatrix(float *matrix) { - return mConsumer->getTransformMatrix(matrix); -} - // NOTE: SurfaceFlinger's definitions of "Current" and "Drawing" do not neatly map to BufferQueue's // These functions get the fields for the frame that is currently in SurfaceFlinger's Drawing state // so the functions start with "getDrawing". The data is retrieved from the BufferQueueConsumer's // current buffer so the consumer functions start with "getCurrent". // // This results in the rather confusing functions below. -uint32_t BufferQueueLayer::getDrawingTransform() const { - return mConsumer->getCurrentTransform(); -} - -ui::Dataspace BufferQueueLayer::getDrawingDataSpace() const { - return mConsumer->getCurrentDataSpace(); -} - -Rect BufferQueueLayer::getDrawingCrop() const { - return mConsumer->getCurrentCrop(); -} - -uint32_t BufferQueueLayer::getDrawingScalingMode() const { - return mConsumer->getCurrentScalingMode(); -} - -Region BufferQueueLayer::getDrawingSurfaceDamage() const { - return mConsumer->getSurfaceDamage(); -} - -const HdrMetadata& BufferQueueLayer::getDrawingHdrMetadata() const { - return mConsumer->getCurrentHdrMetadata(); -} - -int BufferQueueLayer::getDrawingApi() const { - return mConsumer->getCurrentApi(); -} - -PixelFormat BufferQueueLayer::getPixelFormat() const { - return mFormat; -} uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const { Mutex::Autolock lock(mQueueItemLock); @@ -422,7 +375,7 @@ void BufferQueueLayer::latchPerFrameState( compositionState.buffer = mActiveBuffer; compositionState.bufferSlot = (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot; - compositionState.acquireFence = mConsumer->getCurrentFence(); + compositionState.acquireFence = mBufferInfo.mFence; } // ----------------------------------------------------------------------- @@ -573,4 +526,20 @@ uint32_t BufferQueueLayer::getProducerStickyTransform() const { return static_cast(producerStickyTransform); } +void BufferQueueLayer::gatherBufferInfo() { + mBufferInfo.mDesiredPresentTime = mConsumer->getTimestamp(); + mBufferInfo.mFenceTime = mConsumer->getCurrentFenceTime(); + mBufferInfo.mFence = mConsumer->getCurrentFence(); + mConsumer->getTransformMatrix(mBufferInfo.mTransformMatrix); + mBufferInfo.mTransform = mConsumer->getCurrentTransform(); + mBufferInfo.mDataspace = translateDataspace(mConsumer->getCurrentDataSpace()); + mBufferInfo.mCrop = mConsumer->getCurrentCrop(); + mBufferInfo.mScaleMode = mConsumer->getCurrentScalingMode(); + mBufferInfo.mSurfaceDamage = mConsumer->getSurfaceDamage(); + mBufferInfo.mHdrMetadata = mConsumer->getCurrentHdrMetadata(); + mBufferInfo.mApi = mConsumer->getCurrentApi(); + mBufferInfo.mPixelFormat = mFormat; + mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse(); +} + } // namespace android diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index bf3f917196..6cbafb31ce 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -46,7 +46,6 @@ public: std::vector getOccupancyHistory(bool forceFlush) override; - bool getTransformToDisplayInverse() const override; // If a buffer was replaced this frame, release the former buffer void releasePendingBuffer(nsecs_t dequeueReadyTime) override; @@ -66,18 +65,6 @@ public: bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override; private: - nsecs_t getDesiredPresentTime() override; - std::shared_ptr getCurrentFenceTime() const override; - - void getDrawingTransformMatrix(float *matrix) override; - uint32_t getDrawingTransform() const override; - ui::Dataspace getDrawingDataSpace() const override; - Rect getDrawingCrop() const override; - uint32_t getDrawingScalingMode() const override; - Region getDrawingSurfaceDamage() const override; - const HdrMetadata& getDrawingHdrMetadata() const override; - int getDrawingApi() const override; - PixelFormat getPixelFormat() const override; uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override; @@ -103,6 +90,8 @@ private: // Interface implementation for BufferLayerConsumer::ContentsChangedListener // ----------------------------------------------------------------------- protected: + void gatherBufferInfo() override; + void onFrameAvailable(const BufferItem& item) override; void onFrameReplaced(const BufferItem& item) override; void onSidebandStreamChanged() override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index e7d1b63b03..07a83b9d35 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -125,10 +125,6 @@ bool BufferStateLayer::willPresentCurrentTransaction() const { (mCurrentState.buffer != nullptr || mCurrentState.bgColorLayer != nullptr)); } -bool BufferStateLayer::getTransformToDisplayInverse() const { - return mCurrentState.transformToDisplayInverse; -} - void BufferStateLayer::pushPendingState() { if (!mCurrentState.modified) { return; @@ -400,75 +396,6 @@ bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) co return mCurrentState.desiredPresentTime <= expectedPresentTime; } -nsecs_t BufferStateLayer::getDesiredPresentTime() { - return getDrawingState().desiredPresentTime; -} - -std::shared_ptr BufferStateLayer::getCurrentFenceTime() const { - return std::make_shared(getDrawingState().acquireFence); -} - -void BufferStateLayer::getDrawingTransformMatrix(float *matrix) { - std::copy(std::begin(mTransformMatrix), std::end(mTransformMatrix), matrix); -} - -uint32_t BufferStateLayer::getDrawingTransform() const { - return getDrawingState().transform; -} - -ui::Dataspace BufferStateLayer::getDrawingDataSpace() const { - return getDrawingState().dataspace; -} - -// Crop that applies to the buffer -Rect BufferStateLayer::getDrawingCrop() const { - const State& s(getDrawingState()); - - if (s.crop.isEmpty() && s.buffer) { - return s.buffer->getBounds(); - } else if (s.buffer) { - Rect crop = s.crop; - crop.left = std::max(crop.left, 0); - crop.top = std::max(crop.top, 0); - uint32_t bufferWidth = s.buffer->getWidth(); - uint32_t bufferHeight = s.buffer->getHeight(); - if (bufferHeight <= std::numeric_limits::max() && - bufferWidth <= std::numeric_limits::max()) { - crop.right = std::min(crop.right, static_cast(bufferWidth)); - crop.bottom = std::min(crop.bottom, static_cast(bufferHeight)); - } - if (!crop.isValid()) { - // Crop rect is out of bounds, return whole buffer - return s.buffer->getBounds(); - } - return crop; - } - return s.crop; -} - -uint32_t BufferStateLayer::getDrawingScalingMode() const { - return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; -} - -Region BufferStateLayer::getDrawingSurfaceDamage() const { - return getDrawingState().surfaceDamageRegion; -} - -const HdrMetadata& BufferStateLayer::getDrawingHdrMetadata() const { - return getDrawingState().hdrMetadata; -} - -int BufferStateLayer::getDrawingApi() const { - return getDrawingState().api; -} - -PixelFormat BufferStateLayer::getPixelFormat() const { - if (!mActiveBuffer) { - return PIXEL_FORMAT_NONE; - } - return mActiveBuffer->format; -} - uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const { return mFrameNumber; } @@ -506,8 +433,8 @@ bool BufferStateLayer::hasFrameUpdate() const { } void BufferStateLayer::setFilteringEnabled(bool enabled) { - GLConsumer::computeTransformMatrix(mTransformMatrix.data(), mActiveBuffer, mCurrentCrop, - mCurrentTransform, enabled); + GLConsumer::computeTransformMatrix(mTransformMatrix.data(), mActiveBuffer, mBufferInfo.mCrop, + mBufferInfo.mTransform, enabled); } status_t BufferStateLayer::bindTextureImage() { @@ -576,8 +503,8 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse } const uint64_t bufferID = getCurrentBufferId(); - mFlinger->mTimeStats->setAcquireFence(layerID, mFrameNumber, getCurrentFenceTime()); - mFlinger->mFrameTracer->traceFence(layerID, bufferID, mFrameNumber, getCurrentFenceTime(), + mFlinger->mTimeStats->setAcquireFence(layerID, mFrameNumber, mBufferInfo.mFenceTime); + mFlinger->mFrameTracer->traceFence(layerID, bufferID, mFrameNumber, mBufferInfo.mFenceTime, FrameTracer::FrameEvent::ACQUIRE_FENCE); mFlinger->mTimeStats->setLatchTime(layerID, mFrameNumber, latchTime); mFlinger->mFrameTracer->traceTimestamp(layerID, bufferID, mFrameNumber, latchTime, @@ -622,7 +549,7 @@ void BufferStateLayer::latchPerFrameState( compositionState.buffer = s.buffer; compositionState.bufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId); - compositionState.acquireFence = s.acquireFence; + compositionState.acquireFence = mBufferInfo.mFence; mFrameNumber++; } @@ -707,4 +634,47 @@ void BufferStateLayer::HwcSlotGenerator::eraseBufferLocked(const client_cache_t& mFreeHwcCacheSlots.push(hwcCacheSlot); mCachedBuffers.erase(clientCacheId); } + +void BufferStateLayer::gatherBufferInfo() { + const State& s(getDrawingState()); + + mBufferInfo.mDesiredPresentTime = s.desiredPresentTime; + mBufferInfo.mFenceTime = std::make_shared(s.acquireFence); + mBufferInfo.mFence = s.acquireFence; + std::copy(std::begin(mTransformMatrix), std::end(mTransformMatrix), + mBufferInfo.mTransformMatrix); + mBufferInfo.mTransform = s.transform; + mBufferInfo.mDataspace = translateDataspace(s.dataspace); + mBufferInfo.mCrop = computeCrop(s); + mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; + mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion; + mBufferInfo.mHdrMetadata = s.hdrMetadata; + mBufferInfo.mApi = s.api; + mBufferInfo.mPixelFormat = !mActiveBuffer ? PIXEL_FORMAT_NONE : mActiveBuffer->format; + mBufferInfo.mTransformToDisplayInverse = s.transformToDisplayInverse; +} + +Rect BufferStateLayer::computeCrop(const State& s) { + if (s.crop.isEmpty() && s.buffer) { + return s.buffer->getBounds(); + } else if (s.buffer) { + Rect crop = s.crop; + crop.left = std::max(crop.left, 0); + crop.top = std::max(crop.top, 0); + uint32_t bufferWidth = s.buffer->getWidth(); + uint32_t bufferHeight = s.buffer->getHeight(); + if (bufferHeight <= std::numeric_limits::max() && + bufferWidth <= std::numeric_limits::max()) { + crop.right = std::min(crop.right, static_cast(bufferWidth)); + crop.bottom = std::min(crop.bottom, static_cast(bufferHeight)); + } + if (!crop.isValid()) { + // Crop rect is out of bounds, return whole buffer + return s.buffer->getBounds(); + } + return crop; + } + return s.crop; +} + } // namespace android diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index c060ca8e76..086fd0a6ba 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -48,8 +48,6 @@ public: bool shouldPresentNow(nsecs_t expectedPresentTime) const override; - bool getTransformToDisplayInverse() const override; - uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override { return flags; } @@ -106,19 +104,10 @@ public: bool fenceHasSignaled() const override; bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override; +protected: + void gatherBufferInfo() override; + private: - nsecs_t getDesiredPresentTime() override; - std::shared_ptr getCurrentFenceTime() const override; - - void getDrawingTransformMatrix(float *matrix) override; - uint32_t getDrawingTransform() const override; - ui::Dataspace getDrawingDataSpace() const override; - Rect getDrawingCrop() const override; - uint32_t getDrawingScalingMode() const override; - Region getDrawingSurfaceDamage() const override; - const HdrMetadata& getDrawingHdrMetadata() const override; - int getDrawingApi() const override; - PixelFormat getPixelFormat() const override; uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override; @@ -140,6 +129,9 @@ private: void latchPerFrameState(compositionengine::LayerFECompositionState&) const override; + // Crop that applies to the buffer + Rect computeCrop(const State& s); + private: friend class SlotGenerationTest; void onFirstRef() override; diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp index 2ad7591b86..49b18102c7 100644 --- a/services/surfaceflinger/ColorLayer.cpp +++ b/services/surfaceflinger/ColorLayer.cpp @@ -99,11 +99,6 @@ void ColorLayer::latchPerFrameState( compositionState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; } -void ColorLayer::commitTransaction(const State& stateToCommit) { - Layer::commitTransaction(stateToCommit); - mCurrentDataSpace = mDrawingState.dataspace; -} - std::shared_ptr ColorLayer::getCompositionLayer() const { return mCompositionLayer; } @@ -112,6 +107,10 @@ bool ColorLayer::isOpaque(const Layer::State& s) const { return (s.flags & layer_state_t::eLayerOpaque) != 0; } +ui::Dataspace ColorLayer::getDataSpace() const { + return mDrawingState.dataspace; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h index 57c54c7e2c..16921df356 100644 --- a/services/surfaceflinger/ColorLayer.h +++ b/services/surfaceflinger/ColorLayer.h @@ -37,7 +37,7 @@ public: bool setDataspace(ui::Dataspace dataspace) override; - void commitTransaction(const State& stateToCommit) override; + ui::Dataspace getDataSpace() const override; bool isOpaque(const Layer::State& s) const override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index c916f74291..f1a5175424 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -78,7 +78,6 @@ Layer::Layer(const LayerCreationArgs& args) mName(args.name), mClientRef(args.client), mWindowType(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0)) { - mCurrentCrop.makeInvalid(); uint32_t layerFlags = 0; if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden; @@ -259,23 +258,6 @@ sp Layer::getHandle() { // h/w composer set-up // --------------------------------------------------------------------------- -Rect Layer::getContentCrop() const { - // this is the crop rectangle that applies to the buffer - // itself (as opposed to the window) - Rect crop; - if (!mCurrentCrop.isEmpty()) { - // if the buffer crop is defined, we use that - crop = mCurrentCrop; - } else if (mActiveBuffer != nullptr) { - // otherwise we use the whole buffer - crop = mActiveBuffer->getBounds(); - } else { - // if we don't have a buffer yet, we use an empty/invalid crop - crop.makeInvalid(); - } - return crop; -} - static Rect reduce(const Rect& win, const Region& exclude) { if (CC_LIKELY(exclude.isEmpty())) { return win; @@ -335,7 +317,7 @@ ui::Transform Layer::getBufferScaleTransform() const { int bufferWidth = mActiveBuffer->getWidth(); int bufferHeight = mActiveBuffer->getHeight(); - if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { + if (getBufferTransform() & NATIVE_WINDOW_TRANSFORM_ROT_90) { std::swap(bufferWidth, bufferHeight); } @@ -442,9 +424,9 @@ void Layer::latchGeometry(compositionengine::LayerFECompositionState& compositio compositionState.geomLayerTransform = getTransform(); compositionState.geomInverseLayerTransform = compositionState.geomLayerTransform.inverse(); compositionState.geomBufferSize = getBufferSize(drawingState); - compositionState.geomContentCrop = getContentCrop(); + compositionState.geomContentCrop = getBufferCrop(); compositionState.geomCrop = getCrop(drawingState); - compositionState.geomBufferTransform = mCurrentTransform; + compositionState.geomBufferTransform = getBufferTransform(); compositionState.geomBufferUsesDisplayInverseTransform = getTransformToDisplayInverse(); compositionState.geomActiveTransparentRegion = getActiveTransparentRegion(drawingState); compositionState.geomLayerBounds = mBounds; @@ -466,7 +448,7 @@ void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compo compositionState.geomVisibleRegion = visibleRegion; compositionState.isColorspaceAgnostic = isColorSpaceAgnostic(); - compositionState.dataspace = mCurrentDataSpace; + compositionState.dataspace = getDataSpace(); compositionState.colorTransform = getColorTransform(); compositionState.colorTransformIsIdentity = !hasColorTransform(); compositionState.surfaceDamage = surfaceDamageRegion; @@ -543,7 +525,7 @@ std::optional Layer::prepareClientComposition( layerSettings.geometry.roundedCornersCrop = roundedCornerState.cropRect; layerSettings.alpha = alpha; - layerSettings.sourceDataspace = mCurrentDataSpace; + layerSettings.sourceDataspace = getDataSpace(); return layerSettings; } @@ -726,7 +708,7 @@ uint32_t Layer::doTransactionResize(uint32_t flags, State* stateToCommit) { " requested={ wh={%4u,%4u} }}\n" " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" " requested={ wh={%4u,%4u} }}\n", - this, getName().string(), mCurrentTransform, getEffectiveScalingMode(), + this, getName().string(), getBufferTransform(), getEffectiveScalingMode(), stateToCommit->active_legacy.w, stateToCommit->active_legacy.h, stateToCommit->crop_legacy.left, stateToCommit->crop_legacy.top, stateToCommit->crop_legacy.right, stateToCommit->crop_legacy.bottom, @@ -1232,7 +1214,7 @@ LayerDebugInfo Layer::getLayerDebugInfo() const { info.mColor = ds.color; info.mFlags = ds.flags; info.mPixelFormat = getPixelFormat(); - info.mDataSpace = static_cast(mCurrentDataSpace); + info.mDataSpace = static_cast(getDataSpace()); info.mMatrix[0][0] = ds.active_legacy.transform[0][0]; info.mMatrix[0][1] = ds.active_legacy.transform[0][1]; info.mMatrix[1][0] = ds.active_legacy.transform[1][0]; @@ -1551,8 +1533,9 @@ bool Layer::hasColorTransform() const { bool Layer::isLegacyDataSpace() const { // return true when no higher bits are set - return !(mCurrentDataSpace & (ui::Dataspace::STANDARD_MASK | - ui::Dataspace::TRANSFER_MASK | ui::Dataspace::RANGE_MASK)); + return !(getDataSpace() & + (ui::Dataspace::STANDARD_MASK | ui::Dataspace::TRANSFER_MASK | + ui::Dataspace::RANGE_MASK)); } void Layer::setParent(const sp& layer) { @@ -1834,13 +1817,12 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags) if (buffer != nullptr) { LayerProtoHelper::writeToProto(buffer, [&]() { return layerInfo->mutable_active_buffer(); }); - LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform), + LayerProtoHelper::writeToProto(ui::Transform(getBufferTransform()), layerInfo->mutable_buffer_transform()); } layerInfo->set_invalidate(contentDirty); layerInfo->set_is_protected(isProtected()); - layerInfo->set_dataspace( - dataspaceDetails(static_cast(mCurrentDataSpace))); + layerInfo->set_dataspace(dataspaceDetails(static_cast(getDataSpace()))); layerInfo->set_queued_frames(getQueuedFrameCount()); layerInfo->set_refresh_pending(isBufferLatched()); layerInfo->set_curr_frame(mCurrentFrameNumber); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 23c1acd759..ea5b8447ad 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -330,7 +330,7 @@ public: virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace); virtual bool setColorSpaceAgnostic(const bool agnostic); - ui::Dataspace getDataSpace() const { return mCurrentDataSpace; } + virtual ui::Dataspace getDataSpace() const { return ui::Dataspace::UNKNOWN; } // Before color management is introduced, contents on Android have to be // desaturated in order to match what they appears like visually. @@ -587,7 +587,12 @@ public: * returns the rectangle that crops the content of the layer and scales it * to the layer's size. */ - Rect getContentCrop() const; + virtual Rect getBufferCrop() const { return Rect(); } + + /* + * Returns the transform applied to the buffer. + */ + virtual uint32_t getBufferTransform() const { return 0; } /* * Returns if a frame is ready @@ -846,9 +851,6 @@ protected: // composition, true otherwise. bool mIsActiveBufferUpdatedForGpu = true; - ui::Dataspace mCurrentDataSpace = ui::Dataspace::UNKNOWN; - Rect mCurrentCrop; - uint32_t mCurrentTransform{0}; // We encode unset as -1. int32_t mOverrideScalingMode{-1}; std::atomic mCurrentFrameNumber{0}; -- GitLab From e271df9437d7212474ffe11dc0e2b5f16ecf8aa5 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Fri, 6 Sep 2019 09:23:22 -0700 Subject: [PATCH 0251/1255] Transaction_test refactoring continued Minor refactor Bug: 140128949 Test: build, boot, SurfaceFlinger_test Change-Id: Ibeed4b4feb102d8ee6cf57c2deabb53f41177f0a --- .../surfaceflinger/tests/Transaction_test.cpp | 185 +++++++++------- .../tests/utils/ScreenshotUtils.h | 2 +- .../tests/utils/TransactionUtils.h | 203 +++++++++--------- 3 files changed, 202 insertions(+), 188 deletions(-) diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index acb263afd8..ece61df310 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -136,7 +136,9 @@ protected: int32_t bufferWidth, int32_t bufferHeight) { ANativeWindow_Buffer buffer; ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer)); - fillANativeWindowBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color); + TransactionUtils::fillANativeWindowBufferColor(buffer, + Rect(0, 0, bufferWidth, bufferHeight), + color); postBufferQueueLayerBuffer(layer); } @@ -147,7 +149,8 @@ protected: BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY, "test"); - fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), + color); Transaction().setBuffer(layer, buffer).apply(); } @@ -193,11 +196,15 @@ protected: const int32_t halfW = bufferWidth / 2; const int32_t halfH = bufferHeight / 2; - fillANativeWindowBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft); - fillANativeWindowBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight); - fillANativeWindowBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft); - fillANativeWindowBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight), - bottomRight); + TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft); + TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), + topRight); + TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), + bottomLeft); + TransactionUtils::fillANativeWindowBufferColor(buffer, + Rect(halfW, halfH, bufferWidth, + bufferHeight), + bottomRight); postBufferQueueLayerBuffer(layer); } @@ -216,10 +223,14 @@ protected: const int32_t halfW = bufferWidth / 2; const int32_t halfH = bufferHeight / 2; - fillGraphicBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft); - fillGraphicBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight); - fillGraphicBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft); - fillGraphicBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight), bottomRight); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), + topRight); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), + bottomLeft); + TransactionUtils::fillGraphicBufferColor(buffer, + Rect(halfW, halfH, bufferWidth, bufferHeight), + bottomRight); Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply(); } @@ -1093,8 +1104,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferQueue ANativeWindow_Buffer buffer; ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer)); - ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, top, Color::TRANSPARENT)); - ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, bottom, Color::RED)); + ASSERT_NO_FATAL_FAILURE( + TransactionUtils::fillANativeWindowBufferColor(buffer, top, Color::TRANSPARENT)); + ASSERT_NO_FATAL_FAILURE( + TransactionUtils::fillANativeWindowBufferColor(buffer, bottom, Color::RED)); // setTransparentRegionHint always applies to the following buffer Transaction().setTransparentRegionHint(layer, Region(top)).apply(); ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer)); @@ -1114,8 +1127,10 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferQueue } ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer)); - ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, top, Color::RED)); - ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, bottom, Color::TRANSPARENT)); + ASSERT_NO_FATAL_FAILURE( + TransactionUtils::fillANativeWindowBufferColor(buffer, top, Color::RED)); + ASSERT_NO_FATAL_FAILURE( + TransactionUtils::fillANativeWindowBufferColor(buffer, bottom, Color::TRANSPARENT)); ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer)); { SCOPED_TRACE("bottom transparent"); @@ -1138,8 +1153,9 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState BufferUsage::COMPOSER_OVERLAY, "test"); - ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, top, Color::TRANSPARENT)); - ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, bottom, Color::RED)); + ASSERT_NO_FATAL_FAILURE( + TransactionUtils::fillGraphicBufferColor(buffer, top, Color::TRANSPARENT)); + ASSERT_NO_FATAL_FAILURE(TransactionUtils::fillGraphicBufferColor(buffer, bottom, Color::RED)); Transaction() .setTransparentRegionHint(layer, Region(top)) .setBuffer(layer, buffer) @@ -1165,8 +1181,9 @@ TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState BufferUsage::COMPOSER_OVERLAY, "test"); - ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, top, Color::RED)); - ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, bottom, Color::TRANSPARENT)); + ASSERT_NO_FATAL_FAILURE(TransactionUtils::fillGraphicBufferColor(buffer, top, Color::RED)); + ASSERT_NO_FATAL_FAILURE( + TransactionUtils::fillGraphicBufferColor(buffer, bottom, Color::TRANSPARENT)); Transaction().setBuffer(layer, buffer).apply(); { SCOPED_TRACE("bottom transparent"); @@ -1907,8 +1924,8 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY, "test"); - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE); - fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED); Transaction().setFrame(layer, Rect(0, 0, 64, 64)).apply(); @@ -2302,7 +2319,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) { BufferUsage::COMPOSER_OVERLAY, "test"); Color color = colors[idx % colors.size()]; - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color); idx++; } @@ -2338,7 +2355,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_Buffer BufferUsage::COMPOSER_OVERLAY, "test"); Color color = colors[idx % colors.size()]; - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color); idx++; } @@ -2374,7 +2391,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferSt BufferUsage::COMPOSER_OVERLAY, "test"); Color color = colors[idx % colors.size()]; - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color); idx++; } @@ -2471,7 +2488,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetFenceBasic_BufferState) { BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY, "test"); - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); sp fence; if (getBuffer(nullptr, &fence) != NO_ERROR) { @@ -2500,7 +2517,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_BufferState) { BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY, "test"); - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); sp fence = Fence::NO_FENCE; @@ -2524,7 +2541,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) { BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY, "test"); - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); Transaction() .setBuffer(layer, buffer) @@ -2546,7 +2563,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) { BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY, "test"); - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); HdrMetadata hdrMetadata; hdrMetadata.validTypes = 0; @@ -2570,7 +2587,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY, "test"); - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); Region region; region.set(32, 32); @@ -2594,7 +2611,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) { BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY, "test"); - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); Transaction() .setBuffer(layer, buffer) @@ -3661,7 +3678,7 @@ protected: displayHeight, 0); ASSERT_TRUE(mBGSurfaceControl != nullptr); ASSERT_TRUE(mBGSurfaceControl->isValid()); - fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195); + TransactionUtils::fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195); // Foreground surface mFGSurfaceControl = createLayer(String8("FG Test Surface"), 64, 64, 0); @@ -3669,14 +3686,14 @@ protected: ASSERT_TRUE(mFGSurfaceControl != nullptr); ASSERT_TRUE(mFGSurfaceControl->isValid()); - fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); // Synchronization surface mSyncSurfaceControl = createLayer(String8("Sync Test Surface"), 1, 1, 0); ASSERT_TRUE(mSyncSurfaceControl != nullptr); ASSERT_TRUE(mSyncSurfaceControl->isValid()); - fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); asTransaction([&](Transaction& t) { t.setDisplayLayerStack(display, 0); @@ -3705,9 +3722,9 @@ protected: // posting three buffers to it should ensure that at least two // SurfaceFlinger::handlePageFlip calls have been made, which should // guaranteed that a buffer posted to another Surface has been retired. - fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); - fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); - fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); } @@ -3724,7 +3741,7 @@ TEST_F(LayerUpdateTest, RelativesAreNotDetached) { std::unique_ptr sc; sp relative = createLayer(String8("relativeTestSurface"), 10, 10, 0); - fillSurfaceRGBA8(relative, 10, 10, 10); + TransactionUtils::fillSurfaceRGBA8(relative, 10, 10, 10); waitForPostedBuffers(); Transaction{} @@ -3765,7 +3782,9 @@ protected: sc->expectBGColor(128, 128); } - void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63, false); } + void lockAndFillFGBuffer() { + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63, false); + } void unlockFGBuffer() { sp s = mFGSurfaceControl->getSurface(); @@ -3774,7 +3793,7 @@ protected: } void completeFGResize() { - fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); waitForPostedBuffers(); } void restoreInitialState() { @@ -3842,7 +3861,7 @@ TEST_F(LayerUpdateTest, DeferredTransactionTest) { } // should trigger the first deferred transaction, but not the second one - fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); { SCOPED_TRACE("after first trigger"); ScreenCapture::captureScreen(&sc); @@ -3855,7 +3874,7 @@ TEST_F(LayerUpdateTest, DeferredTransactionTest) { asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 1.0); }); // trigger the second deferred transaction - fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); + TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); { SCOPED_TRACE("after second trigger"); ScreenCapture::captureScreen(&sc); @@ -3873,7 +3892,7 @@ TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) { PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); sp childBuffer = createSurface(mClient, "Buffered child", 20, 20, PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get()); - fillSurfaceRGBA8(childBuffer, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(childBuffer, 200, 200, 200); SurfaceComposerClient::Transaction{} .setCrop_legacy(childNoBuffer, Rect(0, 0, 10, 10)) .show(childNoBuffer) @@ -3948,7 +3967,7 @@ protected: LayerUpdateTest::SetUp(); mChild = createSurface(mClient, "Child surface", 10, 15, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - fillSurfaceRGBA8(mChild, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200); { SCOPED_TRACE("before anything"); @@ -4079,9 +4098,9 @@ TEST_F(ChildLayerTest, ChildLayerScalingCroppedByParent) { } TEST_F(ChildLayerTest, ChildLayerAlpha) { - fillSurfaceRGBA8(mBGSurfaceControl, 0, 0, 254); - fillSurfaceRGBA8(mFGSurfaceControl, 254, 0, 0); - fillSurfaceRGBA8(mChild, 0, 254, 0); + TransactionUtils::fillSurfaceRGBA8(mBGSurfaceControl, 0, 0, 254); + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 254, 0, 0); + TransactionUtils::fillSurfaceRGBA8(mChild, 0, 254, 0); waitForPostedBuffers(); asTransaction([&](Transaction& t) { @@ -4149,7 +4168,7 @@ TEST_F(ChildLayerTest, ReparentChildren) { TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) { sp mGrandChild = createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get()); - fillSurfaceRGBA8(mGrandChild, 111, 111, 111); + TransactionUtils::fillSurfaceRGBA8(mGrandChild, 111, 111, 111); { SCOPED_TRACE("Grandchild visible"); @@ -4179,7 +4198,7 @@ TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) { TEST_F(ChildLayerTest, ChildrenRelativeZSurvivesParentDestruction) { sp mGrandChild = createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get()); - fillSurfaceRGBA8(mGrandChild, 111, 111, 111); + TransactionUtils::fillSurfaceRGBA8(mGrandChild, 111, 111, 111); // draw grand child behind the foreground surface asTransaction([&](Transaction& t) { @@ -4244,7 +4263,7 @@ TEST_F(ChildLayerTest, DetachChildrenDifferentClient) { ASSERT_TRUE(mChildNewClient->isValid()); - fillSurfaceRGBA8(mChildNewClient, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(mChildNewClient, 200, 200, 200); asTransaction([&](Transaction& t) { t.hide(mChild); @@ -4285,7 +4304,7 @@ TEST_F(ChildLayerTest, DetachChildrenThenAttach) { ASSERT_TRUE(childNewClient != nullptr); ASSERT_TRUE(childNewClient->isValid()); - fillSurfaceRGBA8(childNewClient, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(childNewClient, 200, 200, 200); Transaction() .hide(mChild) @@ -4339,7 +4358,7 @@ TEST_F(ChildLayerTest, DetachChildrenWithDeferredTransaction) { ASSERT_TRUE(childNewClient != nullptr); ASSERT_TRUE(childNewClient->isValid()); - fillSurfaceRGBA8(childNewClient, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(childNewClient, 200, 200, 200); Transaction() .hide(mChild) @@ -4428,7 +4447,7 @@ TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) { auto anw = static_cast(s.get()); native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); native_window_set_buffers_dimensions(anw, 64, 128); - fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); waitForPostedBuffers(); { @@ -4448,7 +4467,7 @@ TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) { t.setPosition(mFGSurfaceControl, 0, 0); t.setSize(mChild, 100, 100); }); - fillSurfaceRGBA8(mChild, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200); { mCapture = screenshot(); @@ -4464,7 +4483,7 @@ TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) { // Apply a 90 transform on the buffer. native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); native_window_set_buffers_dimensions(anw, 64, 128); - fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); waitForPostedBuffers(); // The child should be cropped by the new parent bounds. @@ -4485,7 +4504,7 @@ TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) { t.setPosition(mFGSurfaceControl, 0, 0); t.setSize(mChild, 200, 200); }); - fillSurfaceRGBA8(mChild, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200); { mCapture = screenshot(); @@ -4537,7 +4556,7 @@ TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) { // have an effective scale of 2.0 applied to the buffer along with a rotation transform. native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90); native_window_set_buffers_dimensions(anw, 32, 64); - fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); waitForPostedBuffers(); // The child should ignore the buffer transform but apply the 2.0 scale from parent. @@ -4570,13 +4589,13 @@ TEST_F(ChildLayerTest, Bug36858924) { // frame because SurfaceFlinger would never process the deferred transaction and would therefore // never acquire/release the first buffer ALOGI("Filling 1"); - fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0); + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0); ALOGI("Filling 2"); - fillSurfaceRGBA8(mFGSurfaceControl, 0, 0, 255); + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 0, 255); ALOGI("Filling 3"); - fillSurfaceRGBA8(mFGSurfaceControl, 255, 0, 0); + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 255, 0, 0); ALOGI("Filling 4"); - fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0); + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0); } TEST_F(ChildLayerTest, Reparent) { @@ -4641,7 +4660,7 @@ TEST_F(ChildLayerTest, ReparentFromNoParent) { ASSERT_TRUE(newSurface != nullptr); ASSERT_TRUE(newSurface->isValid()); - fillSurfaceRGBA8(newSurface, 63, 195, 63); + TransactionUtils::fillSurfaceRGBA8(newSurface, 63, 195, 63); asTransaction([&](Transaction& t) { t.hide(mChild); t.show(newSurface); @@ -4673,7 +4692,7 @@ TEST_F(ChildLayerTest, ReparentFromNoParent) { TEST_F(ChildLayerTest, NestedChildren) { sp grandchild = createSurface(mClient, "Grandchild surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get()); - fillSurfaceRGBA8(grandchild, 50, 50, 50); + TransactionUtils::fillSurfaceRGBA8(grandchild, 50, 50, 50); { mCapture = screenshot(); @@ -4685,7 +4704,7 @@ TEST_F(ChildLayerTest, NestedChildren) { TEST_F(ChildLayerTest, ChildLayerRelativeLayer) { sp relative = createLayer(String8("Relative surface"), 128, 128, 0); - fillSurfaceRGBA8(relative, 255, 255, 255); + TransactionUtils::fillSurfaceRGBA8(relative, 255, 255, 255); Transaction t; t.setLayer(relative, INT32_MAX) @@ -4922,7 +4941,7 @@ TEST_F(ScreenCaptureTest, CaptureLayerWithChild) { sp child = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - fillSurfaceRGBA8(child, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200); SurfaceComposerClient::Transaction().show(child).apply(true); @@ -4937,7 +4956,7 @@ TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) { sp child = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - fillSurfaceRGBA8(child, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200); SurfaceComposerClient::Transaction().show(child).apply(true); @@ -4952,10 +4971,10 @@ TEST_F(ScreenCaptureTest, CaptureLayerExclude) { sp child = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - fillSurfaceRGBA8(child, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200); sp child2 = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - fillSurfaceRGBA8(child2, 200, 0, 200); + TransactionUtils::fillSurfaceRGBA8(child2, 200, 0, 200); SurfaceComposerClient::Transaction() .show(child) @@ -4976,13 +4995,13 @@ TEST_F(ScreenCaptureTest, CaptureLayerExcludeTree) { sp child = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - fillSurfaceRGBA8(child, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200); sp child2 = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - fillSurfaceRGBA8(child2, 200, 0, 200); + TransactionUtils::fillSurfaceRGBA8(child2, 200, 0, 200); sp child3 = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, child2.get()); - fillSurfaceRGBA8(child2, 200, 0, 200); + TransactionUtils::fillSurfaceRGBA8(child2, 200, 0, 200); SurfaceComposerClient::Transaction() .show(child) @@ -5002,7 +5021,7 @@ TEST_F(ScreenCaptureTest, CaptureTransparent) { sp child = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - fillSurfaceRGBA8(child, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200); SurfaceComposerClient::Transaction().show(child).apply(true); @@ -5022,8 +5041,8 @@ TEST_F(ScreenCaptureTest, DontCaptureRelativeOutsideTree) { PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); ASSERT_NE(nullptr, child.get()) << "failed to create surface"; sp relative = createLayer(String8("Relative surface"), 10, 10, 0); - fillSurfaceRGBA8(child, 200, 200, 200); - fillSurfaceRGBA8(relative, 100, 100, 100); + TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(relative, 100, 100, 100); SurfaceComposerClient::Transaction() .show(child) @@ -5045,8 +5064,8 @@ TEST_F(ScreenCaptureTest, CaptureRelativeInTree) { PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); sp relative = createSurface(mClient, "Relative surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - fillSurfaceRGBA8(child, 200, 200, 200); - fillSurfaceRGBA8(relative, 100, 100, 100); + TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(relative, 100, 100, 100); SurfaceComposerClient::Transaction() .show(child) @@ -5075,7 +5094,7 @@ public: mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - fillSurfaceRGBA8(mChild, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200); SurfaceComposerClient::Transaction().show(mChild).apply(true); } @@ -5138,12 +5157,12 @@ TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) { sp child = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - fillSurfaceRGBA8(child, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200); sp grandchild = createSurface(mClient, "Grandchild surface", 5, 5, PIXEL_FORMAT_RGBA_8888, 0, child.get()); - fillSurfaceRGBA8(grandchild, 50, 50, 50); + TransactionUtils::fillSurfaceRGBA8(grandchild, 50, 50, 50); SurfaceComposerClient::Transaction() .show(child) .setPosition(grandchild, 5, 5) @@ -5160,7 +5179,7 @@ TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) { TEST_F(ScreenCaptureTest, CaptureChildOnly) { sp child = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - fillSurfaceRGBA8(child, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200); auto childHandle = child->getHandle(); SurfaceComposerClient::Transaction().setPosition(child, 5, 5).show(child).apply(true); @@ -5174,12 +5193,12 @@ TEST_F(ScreenCaptureTest, CaptureChildOnly) { TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) { sp child = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - fillSurfaceRGBA8(child, 200, 200, 200); + TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200); auto childHandle = child->getHandle(); sp grandchild = createSurface(mClient, "Grandchild surface", 5, 5, PIXEL_FORMAT_RGBA_8888, 0, child.get()); - fillSurfaceRGBA8(grandchild, 50, 50, 50); + TransactionUtils::fillSurfaceRGBA8(grandchild, 50, 50, 50); SurfaceComposerClient::Transaction() .show(child) @@ -5674,8 +5693,8 @@ TEST_F(LayerTransactionTest, DISABLED_BufferQueueLayerMergeDamageRegionWhenDropp ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot1, &buf1)); sp buf2; ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot2, &buf2)); - fillGraphicBufferColor(buf1, Rect(width, height), color); - fillGraphicBufferColor(buf2, Rect(width, height), color); + TransactionUtils::fillGraphicBufferColor(buf1, Rect(width, height), color); + TransactionUtils::fillGraphicBufferColor(buf2, Rect(width, height), color); const auto displayTime = systemTime() + milliseconds_to_nanoseconds(100); ASSERT_NO_FATAL_FAILURE(queue(slot1, Region::INVALID_REGION, displayTime)); diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h index 02e7623dbd..5480b00a4d 100644 --- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -76,7 +76,7 @@ public: void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) { ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat()); - expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance); + TransactionUtils::expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance); } void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) { diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h index f6b33a9bc3..22df2559b1 100644 --- a/services/surfaceflinger/tests/utils/TransactionUtils.h +++ b/services/surfaceflinger/tests/utils/TransactionUtils.h @@ -16,13 +16,7 @@ #pragma once -//#include #include -//#include -//#include -//#include -//#include -//#include #include #include @@ -39,130 +33,131 @@ #include #include "ColorUtils.h" -//#include -//#include namespace android { namespace { using namespace std::chrono_literals; +using Transaction = SurfaceComposerClient::Transaction; std::ostream& operator<<(std::ostream& os, const Color& color) { os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a); return os; } -// Fill a region with the specified color. -void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect, - const Color& color) { - Rect r(0, 0, buffer.width, buffer.height); - if (!r.intersect(rect, &r)) { - return; - } +class TransactionUtils { +public: + // Fill a region with the specified color. + static void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect, + const Color& color) { + Rect r(0, 0, buffer.width, buffer.height); + if (!r.intersect(rect, &r)) { + return; + } - int32_t width = r.right - r.left; - int32_t height = r.bottom - r.top; - - for (int32_t row = 0; row < height; row++) { - uint8_t* dst = - static_cast(buffer.bits) + (buffer.stride * (r.top + row) + r.left) * 4; - for (int32_t column = 0; column < width; column++) { - dst[0] = color.r; - dst[1] = color.g; - dst[2] = color.b; - dst[3] = color.a; - dst += 4; + int32_t width = r.right - r.left; + int32_t height = r.bottom - r.top; + + for (int32_t row = 0; row < height; row++) { + uint8_t* dst = static_cast(buffer.bits) + + (buffer.stride * (r.top + row) + r.left) * 4; + for (int32_t column = 0; column < width; column++) { + dst[0] = color.r; + dst[1] = color.g; + dst[2] = color.b; + dst[3] = color.a; + dst += 4; + } } } -} -// Fill a region with the specified color. -void fillGraphicBufferColor(const sp& buffer, const Rect& rect, const Color& color) { - Rect r(0, 0, buffer->width, buffer->height); - if (!r.intersect(rect, &r)) { - return; - } + // Fill a region with the specified color. + static void fillGraphicBufferColor(const sp& buffer, const Rect& rect, + const Color& color) { + Rect r(0, 0, buffer->width, buffer->height); + if (!r.intersect(rect, &r)) { + return; + } - int32_t width = r.right - r.left; - int32_t height = r.bottom - r.top; - - uint8_t* pixels; - buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); - - for (int32_t row = 0; row < height; row++) { - uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4; - for (int32_t column = 0; column < width; column++) { - dst[0] = color.r; - dst[1] = color.g; - dst[2] = color.b; - dst[3] = color.a; - dst += 4; + int32_t width = r.right - r.left; + int32_t height = r.bottom - r.top; + + uint8_t* pixels; + buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); + + for (int32_t row = 0; row < height; row++) { + uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4; + for (int32_t column = 0; column < width; column++) { + dst[0] = color.r; + dst[1] = color.g; + dst[2] = color.b; + dst[3] = color.a; + dst += 4; + } } + buffer->unlock(); } - buffer->unlock(); -} -// Check if a region has the specified color. -void expectBufferColor(const sp& outBuffer, uint8_t* pixels, const Rect& rect, - const Color& color, uint8_t tolerance) { - int32_t x = rect.left; - int32_t y = rect.top; - int32_t width = rect.right - rect.left; - int32_t height = rect.bottom - rect.top; - - int32_t bufferWidth = int32_t(outBuffer->getWidth()); - int32_t bufferHeight = int32_t(outBuffer->getHeight()); - if (x + width > bufferWidth) { - x = std::min(x, bufferWidth); - width = bufferWidth - x; - } - if (y + height > bufferHeight) { - y = std::min(y, bufferHeight); - height = bufferHeight - y; - } + // Check if a region has the specified color. + static void expectBufferColor(const sp& outBuffer, uint8_t* pixels, + const Rect& rect, const Color& color, uint8_t tolerance) { + int32_t x = rect.left; + int32_t y = rect.top; + int32_t width = rect.right - rect.left; + int32_t height = rect.bottom - rect.top; + + int32_t bufferWidth = int32_t(outBuffer->getWidth()); + int32_t bufferHeight = int32_t(outBuffer->getHeight()); + if (x + width > bufferWidth) { + x = std::min(x, bufferWidth); + width = bufferWidth - x; + } + if (y + height > bufferHeight) { + y = std::min(y, bufferHeight); + height = bufferHeight - y; + } - auto colorCompare = [tolerance](uint8_t a, uint8_t b) { - uint8_t tmp = a >= b ? a - b : b - a; - return tmp <= tolerance; - }; - for (int32_t j = 0; j < height; j++) { - const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4; - for (int32_t i = 0; i < width; i++) { - const uint8_t expected[4] = {color.r, color.g, color.b, color.a}; - EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare)) - << "pixel @ (" << x + i << ", " << y + j << "): " - << "expected (" << color << "), " - << "got (" << Color{src[0], src[1], src[2], src[3]} << ")"; - src += 4; + auto colorCompare = [tolerance](uint8_t a, uint8_t b) { + uint8_t tmp = a >= b ? a - b : b - a; + return tmp <= tolerance; + }; + for (int32_t j = 0; j < height; j++) { + const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4; + for (int32_t i = 0; i < width; i++) { + const uint8_t expected[4] = {color.r, color.g, color.b, color.a}; + EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare)) + << "pixel @ (" << x + i << ", " << y + j << "): " + << "expected (" << color << "), " + << "got (" << Color{src[0], src[1], src[2], src[3]} << ")"; + src += 4; + } } } -} - -using Transaction = SurfaceComposerClient::Transaction; -// Fill an RGBA_8888 formatted surface with a single color. -static void fillSurfaceRGBA8(const sp& sc, uint8_t r, uint8_t g, uint8_t b, - bool unlock = true) { - ANativeWindow_Buffer outBuffer; - sp s = sc->getSurface(); - ASSERT_TRUE(s != nullptr); - ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr)); - uint8_t* img = reinterpret_cast(outBuffer.bits); - for (int y = 0; y < outBuffer.height; y++) { - for (int x = 0; x < outBuffer.width; x++) { - uint8_t* pixel = img + (4 * (y * outBuffer.stride + x)); - pixel[0] = r; - pixel[1] = g; - pixel[2] = b; - pixel[3] = 255; + // Fill an RGBA_8888 formatted surface with a single color. + static void fillSurfaceRGBA8(const sp& sc, uint8_t r, uint8_t g, uint8_t b, + bool unlock = true) { + ANativeWindow_Buffer outBuffer; + sp s = sc->getSurface(); + ASSERT_TRUE(s != nullptr); + ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr)); + uint8_t* img = reinterpret_cast(outBuffer.bits); + for (int y = 0; y < outBuffer.height; y++) { + for (int x = 0; x < outBuffer.width; x++) { + uint8_t* pixel = img + (4 * (y * outBuffer.stride + x)); + pixel[0] = r; + pixel[1] = g; + pixel[2] = b; + pixel[3] = 255; + } + } + if (unlock) { + ASSERT_EQ(NO_ERROR, s->unlockAndPost()); } } - if (unlock) { - ASSERT_EQ(NO_ERROR, s->unlockAndPost()); - } -} +}; enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY }; -- GitLab From d62d30645c41d703a241443de761ab9eaa0c99af Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 4 Sep 2019 14:48:02 -0700 Subject: [PATCH 0252/1255] Moved info about activeBuffer into bufferInfo (2/2) This is in preparation for layer mirroring since mirrored buffer layers should just copy the bufferInfo instead of the entire BufferQueue or parts of BufferState Test: go/wm-smoke Change-Id: I48c34141151370d9905c312239883f8374b884b9 --- services/surfaceflinger/BufferLayer.cpp | 53 +++++++++++--------- services/surfaceflinger/BufferLayer.h | 8 +-- services/surfaceflinger/BufferQueueLayer.cpp | 14 +++--- services/surfaceflinger/BufferQueueLayer.h | 1 - services/surfaceflinger/BufferStateLayer.cpp | 19 +++---- services/surfaceflinger/Layer.cpp | 16 +++--- services/surfaceflinger/Layer.h | 7 ++- 7 files changed, 62 insertions(+), 56 deletions(-) diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index bca15e6903..6a3d60f50c 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -92,7 +92,7 @@ void BufferLayer::useEmptyDamage() { bool BufferLayer::isOpaque(const Layer::State& s) const { // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the // layer's opaque flag. - if ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) { + if ((mSidebandStream == nullptr) && (mBufferInfo.mBuffer == nullptr)) { return false; } @@ -103,7 +103,7 @@ bool BufferLayer::isOpaque(const Layer::State& s) const { bool BufferLayer::isVisible() const { bool visible = !(isHiddenByPolicy()) && getAlpha() > 0.0f && - (mActiveBuffer != nullptr || mSidebandStream != nullptr); + (mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr); mFlinger->mScheduler->setLayerVisibility(mSchedulerLayerHandle, visible); return visible; @@ -144,7 +144,7 @@ std::optional BufferLayer::prepareClientComposition return result; } - if (CC_UNLIKELY(mActiveBuffer == 0)) { + if (CC_UNLIKELY(mBufferInfo.mBuffer == 0)) { // the texture has not been created yet, this Layer has // in fact never been drawn into. This happens frequently with // SurfaceView because the WindowManager can't know when the client @@ -175,9 +175,9 @@ std::optional BufferLayer::prepareClientComposition const State& s(getDrawingState()); auto& layer = *result; if (!blackOutLayer) { - layer.source.buffer.buffer = mActiveBuffer; + layer.source.buffer.buffer = mBufferInfo.mBuffer; layer.source.buffer.isOpaque = isOpaque(s); - layer.source.buffer.fence = mActiveBufferFence; + layer.source.buffer.fence = mBufferInfo.mFence; layer.source.buffer.textureName = mTextureName; layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha(); layer.source.buffer.isY410BT2020 = isHdrY410(); @@ -256,7 +256,7 @@ bool BufferLayer::isHdrY410() const { // pixel format is HDR Y410 masquerading as RGBA_1010102 return (mBufferInfo.mDataspace == ui::Dataspace::BT2020_ITU_PQ && mBufferInfo.mApi == NATIVE_WINDOW_API_MEDIA && - mActiveBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102); + mBufferInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102); } void BufferLayer::latchPerFrameState( @@ -276,7 +276,7 @@ void BufferLayer::latchPerFrameState( } bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) { - if (mBufferLatched) { + if (mBufferInfo.mBuffer != nullptr) { Mutex::Autolock lock(mFrameEventHistoryMutex); mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime); } @@ -370,7 +370,8 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, // Capture the old state of the layer for comparisons later const State& s(getDrawingState()); const bool oldOpacity = isOpaque(s); - sp oldBuffer = mActiveBuffer; + + BufferInfo oldBufferInfo = mBufferInfo; if (!allTransactionsSignaled(expectedPresentTime)) { mFlinger->setTransactionFlags(eTraversalNeeded); @@ -387,19 +388,16 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, return false; } - mBufferLatched = true; - err = updateFrameNumber(latchTime); if (err != NO_ERROR) { return false; } - BufferInfo oldBufferInfo = mBufferInfo; gatherBufferInfo(); mRefreshPending = true; mFrameLatencyNeeded = true; - if (oldBuffer == nullptr) { + if (oldBufferInfo.mBuffer == nullptr) { // the first time we receive a buffer, we need to trigger a // geometry invalidation. recomputeVisibleRegions = true; @@ -412,10 +410,11 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, recomputeVisibleRegions = true; } - if (oldBuffer != nullptr) { - uint32_t bufWidth = mActiveBuffer->getWidth(); - uint32_t bufHeight = mActiveBuffer->getHeight(); - if (bufWidth != uint32_t(oldBuffer->width) || bufHeight != uint32_t(oldBuffer->height)) { + if (oldBufferInfo.mBuffer != nullptr) { + uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); + if (bufWidth != uint32_t(oldBufferInfo.mBuffer->width) || + bufHeight != uint32_t(oldBufferInfo.mBuffer->height)) { recomputeVisibleRegions = true; } } @@ -484,7 +483,7 @@ uint32_t BufferLayer::getEffectiveScalingMode() const { } bool BufferLayer::isProtected() const { - const sp& buffer(mActiveBuffer); + const sp& buffer(mBufferInfo.mBuffer); return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED); } @@ -588,12 +587,12 @@ Rect BufferLayer::getBufferSize(const State& s) const { return Rect(getActiveWidth(s), getActiveHeight(s)); } - if (mActiveBuffer == nullptr) { + if (mBufferInfo.mBuffer == nullptr) { return Rect::INVALID_RECT; } - uint32_t bufWidth = mActiveBuffer->getWidth(); - uint32_t bufHeight = mActiveBuffer->getHeight(); + uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { @@ -624,12 +623,12 @@ FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s)); } - if (mActiveBuffer == nullptr) { + if (mBufferInfo.mBuffer == nullptr) { return parentBounds; } - uint32_t bufWidth = mActiveBuffer->getWidth(); - uint32_t bufHeight = mActiveBuffer->getHeight(); + uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { @@ -669,9 +668,9 @@ Rect BufferLayer::getBufferCrop() const { if (!mBufferInfo.mCrop.isEmpty()) { // if the buffer crop is defined, we use that return mBufferInfo.mCrop; - } else if (mActiveBuffer != nullptr) { + } else if (mBufferInfo.mBuffer != nullptr) { // otherwise we use the whole buffer - return mActiveBuffer->getBounds(); + return mBufferInfo.mBuffer->getBounds(); } else { // if we don't have a buffer yet, we use an empty/invalid crop return Rect(); @@ -715,6 +714,10 @@ ui::Dataspace BufferLayer::translateDataspace(ui::Dataspace dataspace) { return updatedDataspace; } +sp BufferLayer::getBuffer() const { + return mBufferInfo.mBuffer; +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index e8838e812c..a685ea2305 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -114,6 +114,8 @@ public: ui::Dataspace getDataSpace() const override; + sp getBuffer() const override; + // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- @@ -159,6 +161,9 @@ protected: int mApi; PixelFormat mPixelFormat; bool mTransformToDisplayInverse{false}; + + sp mBuffer; + int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT}; }; BufferInfo mBufferInfo; @@ -195,9 +200,6 @@ private: uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const; - // main thread. - bool mBufferLatched{false}; // TODO: Use mActiveBuffer? - // BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame // and its parent layer is not bounded Rect getBufferSize(const State& s) const override; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index e9e8e6e9dc..a4f7bc23a4 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -343,11 +343,12 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t status_t BufferQueueLayer::updateActiveBuffer() { // update the active buffer mPreviousBufferId = getCurrentBufferId(); - mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence); + mBufferInfo.mBuffer = + mConsumer->getCurrentBuffer(&mBufferInfo.mBufferSlot, &mBufferInfo.mFence); auto& layerCompositionState = getCompositionLayer()->editState().frontEnd; - layerCompositionState.buffer = mActiveBuffer; + layerCompositionState.buffer = mBufferInfo.mBuffer; - if (mActiveBuffer == nullptr) { + if (mBufferInfo.mBuffer == nullptr) { // this can only happen if the very first buffer was rejected. return BAD_VALUE; } @@ -372,9 +373,10 @@ void BufferQueueLayer::latchPerFrameState( return; } - compositionState.buffer = mActiveBuffer; - compositionState.bufferSlot = - (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot; + compositionState.buffer = mBufferInfo.mBuffer; + compositionState.bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) + ? 0 + : mBufferInfo.mBufferSlot; compositionState.acquireFence = mBufferInfo.mFence; } diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 6cbafb31ce..43eb3eaab8 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -127,7 +127,6 @@ private: std::atomic mLastFrameNumberReceived{0}; bool mAutoRefresh{false}; - int mActiveBufferSlot{BufferQueue::INVALID_BUFFER_SLOT}; // thread-safe std::atomic mQueuedFrames{0}; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 07a83b9d35..afbe22854f 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -53,12 +53,12 @@ BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) } BufferStateLayer::~BufferStateLayer() { - if (mActiveBuffer != nullptr) { - // Ensure that mActiveBuffer is uncached from RenderEngine here, as + if (mBufferInfo.mBuffer != nullptr) { + // Ensure that mBuffer is uncached from RenderEngine here, as // RenderEngine may have been using the buffer as an external texture // after the client uncached the buffer. auto& engine(mFlinger->getRenderEngine()); - engine.unbindExternalTextureBuffer(mActiveBuffer->getId()); + engine.unbindExternalTextureBuffer(mBufferInfo.mBuffer->getId()); } } @@ -433,8 +433,8 @@ bool BufferStateLayer::hasFrameUpdate() const { } void BufferStateLayer::setFilteringEnabled(bool enabled) { - GLConsumer::computeTransformMatrix(mTransformMatrix.data(), mActiveBuffer, mBufferInfo.mCrop, - mBufferInfo.mTransform, enabled); + GLConsumer::computeTransformMatrix(mTransformMatrix.data(), mBufferInfo.mBuffer, + mBufferInfo.mCrop, mBufferInfo.mTransform, enabled); } status_t BufferStateLayer::bindTextureImage() { @@ -523,10 +523,10 @@ status_t BufferStateLayer::updateActiveBuffer() { } mPreviousBufferId = getCurrentBufferId(); - mActiveBuffer = s.buffer; - mActiveBufferFence = s.acquireFence; + mBufferInfo.mBuffer = s.buffer; + mBufferInfo.mFence = s.acquireFence; auto& layerCompositionState = getCompositionLayer()->editState().frontEnd; - layerCompositionState.buffer = mActiveBuffer; + layerCompositionState.buffer = mBufferInfo.mBuffer; return NO_ERROR; } @@ -650,7 +650,8 @@ void BufferStateLayer::gatherBufferInfo() { mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion; mBufferInfo.mHdrMetadata = s.hdrMetadata; mBufferInfo.mApi = s.api; - mBufferInfo.mPixelFormat = !mActiveBuffer ? PIXEL_FORMAT_NONE : mActiveBuffer->format; + mBufferInfo.mPixelFormat = + !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->format; mBufferInfo.mTransformToDisplayInverse = s.transformToDisplayInverse; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index f1a5175424..d0b9187d56 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -302,7 +302,7 @@ ui::Transform Layer::getBufferScaleTransform() const { // If the layer is not using NATIVE_WINDOW_SCALING_MODE_FREEZE (e.g. // it isFixedSize) then there may be additional scaling not accounted // for in the layer transform. - if (!isFixedSize() || !mActiveBuffer) { + if (!isFixedSize() || getBuffer() == nullptr) { return {}; } @@ -314,8 +314,8 @@ ui::Transform Layer::getBufferScaleTransform() const { return {}; } - int bufferWidth = mActiveBuffer->getWidth(); - int bufferHeight = mActiveBuffer->getHeight(); + int bufferWidth = getBuffer()->getWidth(); + int bufferHeight = getBuffer()->getHeight(); if (getBufferTransform() & NATIVE_WINDOW_TRANSFORM_ROT_90) { std::swap(bufferWidth, bufferHeight); @@ -332,7 +332,7 @@ ui::Transform Layer::getBufferScaleTransform() const { ui::Transform Layer::getTransformWithScale(const ui::Transform& bufferScaleTransform) const { // We need to mirror this scaling to child surfaces or we will break the contract where WM can // treat child surfaces as pixels in the parent surface. - if (!isFixedSize() || !mActiveBuffer) { + if (!isFixedSize() || getBuffer() == nullptr) { return mEffectiveTransform; } return mEffectiveTransform * bufferScaleTransform; @@ -341,7 +341,7 @@ ui::Transform Layer::getTransformWithScale(const ui::Transform& bufferScaleTrans FloatRect Layer::getBoundsPreScaling(const ui::Transform& bufferScaleTransform) const { // We need the pre scaled layer bounds when computing child bounds to make sure the child is // cropped to its parent layer after any buffer transform scaling is applied. - if (!isFixedSize() || !mActiveBuffer) { + if (!isFixedSize() || getBuffer() == nullptr) { return mBounds; } return bufferScaleTransform.inverse().transform(mBounds); @@ -740,7 +740,7 @@ uint32_t Layer::doTransactionResize(uint32_t flags, State* stateToCommit) { const bool resizePending = ((stateToCommit->requested_legacy.w != stateToCommit->active_legacy.w) || (stateToCommit->requested_legacy.h != stateToCommit->active_legacy.h)) && - (mActiveBuffer != nullptr); + (getBuffer() != nullptr); if (!isFixedSize()) { if (resizePending && mSidebandStream == nullptr) { flags |= eDontUpdateGeometryState; @@ -1220,7 +1220,7 @@ LayerDebugInfo Layer::getLayerDebugInfo() const { info.mMatrix[1][0] = ds.active_legacy.transform[1][0]; info.mMatrix[1][1] = ds.active_legacy.transform[1][1]; { - sp buffer = mActiveBuffer; + sp buffer = getBuffer(); if (buffer != 0) { info.mActiveBufferWidth = buffer->getWidth(); info.mActiveBufferHeight = buffer->getHeight(); @@ -1813,7 +1813,7 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags) } } - auto buffer = mActiveBuffer; + auto buffer = getBuffer(); if (buffer != nullptr) { LayerProtoHelper::writeToProto(buffer, [&]() { return layerInfo->mutable_active_buffer(); }); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index ea5b8447ad..d6cc27a801 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -382,7 +382,7 @@ public: // creates its tracks by buffer id and has no way of associating a buffer back to the process // that created it, the current implementation is only sufficient for cases where a buffer is // only used within a single layer. - uint64_t getCurrentBufferId() const { return mActiveBuffer ? mActiveBuffer->getId() : 0; } + uint64_t getCurrentBufferId() const { return getBuffer() ? getBuffer()->getId() : 0; } // ----------------------------------------------------------------------- // Virtuals @@ -594,6 +594,8 @@ public: */ virtual uint32_t getBufferTransform() const { return 0; } + virtual sp getBuffer() const { return nullptr; } + /* * Returns if a frame is ready */ @@ -844,9 +846,6 @@ protected: // main thread sp mSidebandStream; - // Active buffer fields - sp mActiveBuffer; - sp mActiveBufferFence; // False if the buffer and its contents have been previously used for GPU // composition, true otherwise. bool mIsActiveBufferUpdatedForGpu = true; -- GitLab From 3f4a4ee8c69b170bf3268fe010894be55d097ddd Mon Sep 17 00:00:00 2001 From: Raymond Chiu Date: Fri, 6 Sep 2019 10:54:38 -0700 Subject: [PATCH 0253/1255] Remove perfetto_src_tracing_ipc dependency Test: mma Change-Id: Iaf226f48090c3590d15962ea858a887a3506e1a2 --- services/surfaceflinger/Android.bp | 2 -- 1 file changed, 2 deletions(-) diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 93c738d231..bec33f21a4 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -75,7 +75,6 @@ cc_defaults { "libtrace_proto", "libvr_manager", "libvrflinger", - "perfetto_src_tracing_ipc", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", @@ -84,7 +83,6 @@ cc_defaults { ], export_static_lib_headers: [ "libcompositionengine", - "libperfetto_client_experimental", "librenderengine", "libserviceutils", "libtimestats", -- GitLab From 0d1398b2da8aee028c52a90be6d3b75b4f12b9d6 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 14 Aug 2019 10:53:50 -0700 Subject: [PATCH 0254/1255] [ANativeWindow] Add apex header for getLastQueueDuration Bug: 137012798 Test: libnativewindow_test Change-Id: I46d5ab9c11161923ebbbc67400b10b2e7c0c6b61 --- libs/nativewindow/ANativeWindow.cpp | 4 +++ libs/nativewindow/include/apex/window.h | 8 +++++ libs/nativewindow/libnativewindow.map.txt | 1 + libs/nativewindow/tests/ANativeWindowTest.cpp | 35 +++++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 4c59e6ce98..5c91d587bc 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -274,3 +274,7 @@ int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation int ANativeWindow_getLastDequeueDuration(ANativeWindow* window) { return query(window, NATIVE_WINDOW_LAST_DEQUEUE_DURATION); } + +int ANativeWindow_getLastQueueDuration(ANativeWindow* window) { + return query(window, NATIVE_WINDOW_LAST_QUEUE_DURATION); +} diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h index 0260cbcfb4..82ff50d2d5 100644 --- a/libs/nativewindow/include/apex/window.h +++ b/libs/nativewindow/include/apex/window.h @@ -31,4 +31,12 @@ __BEGIN_DECLS */ int ANativeWindow_getLastDequeueDuration(ANativeWindow* window); +/** + * Retrieves how long it took for the last time a buffer was queued. + * + * \return a negative value on error, otherwise returns the duration in + * microseconds + */ +int ANativeWindow_getLastQueueDuration(ANativeWindow* window); + __END_DECLS diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 7fe4df0606..b8b45ae62b 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -23,6 +23,7 @@ LIBNATIVEWINDOW { ANativeWindow_getFormat; ANativeWindow_getHeight; ANativeWindow_getLastDequeueDuration; # apex # introduced=30 + ANativeWindow_getLastQueueDuration; # apex # introduced=30 ANativeWindow_getWidth; ANativeWindow_lock; ANativeWindow_query; # vndk diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp index 5247e04c32..9b358da4b5 100644 --- a/libs/nativewindow/tests/ANativeWindowTest.cpp +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -36,6 +36,9 @@ public: // Exposes the internal last dequeue duration that's stored on the Surface. nsecs_t getLastDequeueDuration() const { return mLastDequeueDuration; } + + // Exposes the internal last queue duration that's stored on the Surface. + nsecs_t getLastQueueDuration() const { return mLastQueueDuration; } }; class ANativeWindowTest : public ::testing::Test { @@ -82,3 +85,35 @@ TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) { EXPECT_GT(result, 0); EXPECT_EQ(result, mWindow->getLastDequeueDuration() / 1000); } + +TEST_F(ANativeWindowTest, getLastQueueDuration_noDequeue_returnsZero) { + int result = ANativeWindow_getLastQueueDuration(mWindow.get()); + EXPECT_EQ(0, result); + EXPECT_EQ(0, mWindow->getLastQueueDuration()); +} + +TEST_F(ANativeWindowTest, getLastQueueDuration_noQueue_returnsZero) { + ANativeWindowBuffer* buffer; + int fd; + int result = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd); + close(fd); + EXPECT_EQ(0, result); + + result = ANativeWindow_getLastQueueDuration(mWindow.get()); + EXPECT_EQ(result, 0); + EXPECT_EQ(result, mWindow->getLastQueueDuration()); +} + +TEST_F(ANativeWindowTest, getLastQueueDuration_withQueue_returnsTime) { + ANativeWindowBuffer* buffer; + int fd; + int result = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd); + close(fd); + EXPECT_EQ(0, result); + + result = ANativeWindow_queueBuffer(mWindow.get(), buffer, 0); + + result = ANativeWindow_getLastQueueDuration(mWindow.get()); + EXPECT_GT(result, 0); + EXPECT_EQ(result, mWindow->getLastQueueDuration() / 1000); +} -- GitLab From a161966a658f46f8bec93ea0490bef799843c3c6 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 21 Aug 2019 19:30:48 -0700 Subject: [PATCH 0255/1255] [ANativeWindow] Add apex stub for getLastDequeueStartTime Also adding private query64 hook so that timing queries can have nanosecond precision. Otherwise with a 32-bit width we can only have millisecond precision for timestamps and microsecond precision for time intervals, and really we shouldn't need to be less precise if we can help it. Bug: 137012798 Test: libnativewindow_test Change-Id: I62233a588eee80f7ea70b74824c8e47461a3be81 --- libs/gui/Surface.cpp | 14 ++++++++----- libs/gui/include/gui/Surface.h | 4 +--- libs/gui/tests/Surface_test.cpp | 2 +- libs/nativewindow/ANativeWindow.cpp | 6 ++++++ libs/nativewindow/include/apex/window.h | 9 ++++++++ libs/nativewindow/include/system/window.h | 2 +- libs/nativewindow/libnativewindow.map.txt | 1 + libs/nativewindow/tests/ANativeWindowTest.cpp | 21 +++++++++++++++++++ 8 files changed, 49 insertions(+), 10 deletions(-) diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 7e356e4eb1..aad18491b4 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1081,6 +1081,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_AUTO_PREROTATION: res = dispatchSetAutoPrerotation(args); break; + case NATIVE_WINDOW_GET_LAST_DEQUEUE_START: + res = dispatchGetLastDequeueStartTime(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1286,6 +1289,12 @@ int Surface::dispatchSetAutoPrerotation(va_list args) { return setAutoPrerotation(autoPrerotation); } +int Surface::dispatchGetLastDequeueStartTime(va_list args) { + int64_t* lastDequeueStartTime = va_arg(args, int64_t*); + *lastDequeueStartTime = mLastDequeueStartTime; + return NO_ERROR; +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; @@ -1950,11 +1959,6 @@ int Surface::getConsumerUsage(uint64_t* outUsage) const { return mGraphicBufferProducer->getConsumerUsage(outUsage); } -nsecs_t Surface::getLastDequeueStartTime() const { - Mutex::Autolock lock(mMutex); - return mLastDequeueStartTime; -} - status_t Surface::getAndFlushRemovedBuffers(std::vector>* out) { if (out == nullptr) { ALOGE("%s: out must not be null!", __FUNCTION__); diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 28f5a26072..5bcfcda6ad 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -179,9 +179,6 @@ public: status_t getUniqueId(uint64_t* outId) const; status_t getConsumerUsage(uint64_t* outUsage) const; - // Returns the CLOCK_MONOTONIC start time of the last dequeueBuffer call - nsecs_t getLastDequeueStartTime() const; - protected: virtual ~Surface(); @@ -247,6 +244,7 @@ private: int dispatchGetHdrSupport(va_list args); int dispatchGetConsumerUsage64(va_list args); int dispatchSetAutoPrerotation(va_list args); + int dispatchGetLastDequeueStartTime(va_list args); bool transformToDisplayInverse(); protected: diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 5a121d77ab..0b61d9231c 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -617,7 +617,7 @@ TEST_F(SurfaceTest, TestGetLastDequeueStartTime) { anw->dequeueBuffer(anw.get(), &buffer, &fenceFd); nsecs_t after = systemTime(CLOCK_MONOTONIC); - nsecs_t lastDequeueTime = mSurface->getLastDequeueStartTime(); + nsecs_t lastDequeueTime = ANativeWindow_getLastDequeueStartTime(anw.get()); ASSERT_LE(before, lastDequeueTime); ASSERT_GE(after, lastDequeueTime); } diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 5c91d587bc..3b195f7913 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -278,3 +278,9 @@ int ANativeWindow_getLastDequeueDuration(ANativeWindow* window) { int ANativeWindow_getLastQueueDuration(ANativeWindow* window) { return query(window, NATIVE_WINDOW_LAST_QUEUE_DURATION); } + +int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window) { + int64_t time; + int success = window->perform(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START, &time); + return success < 0 ? success : time; +} diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h index 82ff50d2d5..3ddd5493ac 100644 --- a/libs/nativewindow/include/apex/window.h +++ b/libs/nativewindow/include/apex/window.h @@ -39,4 +39,13 @@ int ANativeWindow_getLastDequeueDuration(ANativeWindow* window); */ int ANativeWindow_getLastQueueDuration(ANativeWindow* window); +/** + * Retrieves the system time in nanoseconds when the last time a buffer + * was dequeued. + * + * \return a negative value on error, otherwise returns the duration in + * nanoseconds. + */ +int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window); + __END_DECLS diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 78354bba6b..b7ae28a93c 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -93,7 +93,6 @@ enum { */ NATIVE_WINDOW_CONCRETE_TYPE = 5, - /* * Default width and height of ANativeWindow buffers, these are the * dimensions of the window buffers irrespective of the @@ -240,6 +239,7 @@ enum { NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33, NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34, NATIVE_WINDOW_SET_AUTO_PREROTATION = 35, + NATIVE_WINDOW_GET_LAST_DEQUEUE_START = 36, /* private */ // clang-format on }; diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index b8b45ae62b..33c6400d52 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -23,6 +23,7 @@ LIBNATIVEWINDOW { ANativeWindow_getFormat; ANativeWindow_getHeight; ANativeWindow_getLastDequeueDuration; # apex # introduced=30 + ANativeWindow_getLastDequeueStartTime; # apex # introduced=30 ANativeWindow_getLastQueueDuration; # apex # introduced=30 ANativeWindow_getWidth; ANativeWindow_lock; diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp index 9b358da4b5..947217d52c 100644 --- a/libs/nativewindow/tests/ANativeWindowTest.cpp +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -39,6 +39,9 @@ public: // Exposes the internal last queue duration that's stored on the Surface. nsecs_t getLastQueueDuration() const { return mLastQueueDuration; } + + // Exposes the internal last dequeue start time that's stored on the Surface. + nsecs_t getLastDequeueStartTime() const { return mLastDequeueStartTime; } }; class ANativeWindowTest : public ::testing::Test { @@ -117,3 +120,21 @@ TEST_F(ANativeWindowTest, getLastQueueDuration_withQueue_returnsTime) { EXPECT_GT(result, 0); EXPECT_EQ(result, mWindow->getLastQueueDuration() / 1000); } + +TEST_F(ANativeWindowTest, getLastDequeueStartTime_noDequeue_returnsZero) { + int64_t result = ANativeWindow_getLastDequeueStartTime(mWindow.get()); + EXPECT_EQ(0, result); + EXPECT_EQ(0, mWindow->getLastQueueDuration()); +} + +TEST_F(ANativeWindowTest, getLastDequeueStartTime_withDequeue_returnsTime) { + ANativeWindowBuffer* buffer; + int fd; + int dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd); + close(fd); + EXPECT_EQ(0, dequeueResult); + + int64_t result = ANativeWindow_getLastDequeueStartTime(mWindow.get()); + EXPECT_GT(result, 0); + EXPECT_EQ(result, mWindow->getLastDequeueStartTime()); +} -- GitLab From 04fdb60d01038d4d1e82b4c71f9bd3e9c74cb031 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 23 Aug 2019 19:41:43 -0700 Subject: [PATCH 0256/1255] [ANativeWindow] Add stub for ANativeWindow_setDequeueTimeout HWUI and media both require setting a dequeue timeout so that dequeue calls don't hang. Bug: 137012798 Test: libnativewindow_test Change-Id: Ic85b07096d490918ae4a722516b8c4b6cb0ab678 --- libs/gui/Surface.cpp | 8 ++++++ libs/gui/include/gui/Surface.h | 1 + libs/nativewindow/ANativeWindow.cpp | 4 +++ libs/nativewindow/include/apex/window.h | 9 ++++++ libs/nativewindow/include/system/window.h | 1 + libs/nativewindow/libnativewindow.map.txt | 1 + libs/nativewindow/tests/ANativeWindowTest.cpp | 28 +++++++++++++++++++ 7 files changed, 52 insertions(+) diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index aad18491b4..fb9d7427d7 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1084,6 +1084,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_GET_LAST_DEQUEUE_START: res = dispatchGetLastDequeueStartTime(args); break; + case NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT: + res = dispatchSetDequeueTimeout(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1295,6 +1298,11 @@ int Surface::dispatchGetLastDequeueStartTime(va_list args) { return NO_ERROR; } +int Surface::dispatchSetDequeueTimeout(va_list args) { + nsecs_t timeout = va_arg(args, int64_t); + return setDequeueTimeout(timeout); +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 5bcfcda6ad..2527ec0a75 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -245,6 +245,7 @@ private: int dispatchGetConsumerUsage64(va_list args); int dispatchSetAutoPrerotation(va_list args); int dispatchGetLastDequeueStartTime(va_list args); + int dispatchSetDequeueTimeout(va_list args); bool transformToDisplayInverse(); protected: diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 3b195f7913..fecfa193df 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -284,3 +284,7 @@ int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window) { int success = window->perform(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START, &time); return success < 0 ? success : time; } + +int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout) { + return window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, timeout); +} diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h index 3ddd5493ac..9798c2fd47 100644 --- a/libs/nativewindow/include/apex/window.h +++ b/libs/nativewindow/include/apex/window.h @@ -48,4 +48,13 @@ int ANativeWindow_getLastQueueDuration(ANativeWindow* window); */ int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window); +/** + * Sets a timeout in nanoseconds for dequeue calls. All subsequent dequeue calls + * made by the window will return -ETIMEDOUT after the timeout if the dequeue + * takes too long. + * + * \return NO_ERROR on succes, -errno on error. + */ +int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout); + __END_DECLS diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index b7ae28a93c..8f850070b6 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -240,6 +240,7 @@ enum { NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34, NATIVE_WINDOW_SET_AUTO_PREROTATION = 35, NATIVE_WINDOW_GET_LAST_DEQUEUE_START = 36, /* private */ + NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT = 37, /* private */ // clang-format on }; diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 33c6400d52..b741faa11f 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -40,6 +40,7 @@ LIBNATIVEWINDOW { ANativeWindow_setBuffersGeometry; ANativeWindow_setBuffersTimestamp; # vndk ANativeWindow_setBuffersTransform; + ANativeWindow_setDequeueTimeout; # apex # introduced=30 ANativeWindow_setSharedBufferMode; # vndk ANativeWindow_setSwapInterval; # vndk ANativeWindow_setUsage; # vndk diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp index 947217d52c..4d2b8c8f3b 100644 --- a/libs/nativewindow/tests/ANativeWindowTest.cpp +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -138,3 +138,31 @@ TEST_F(ANativeWindowTest, getLastDequeueStartTime_withDequeue_returnsTime) { EXPECT_GT(result, 0); EXPECT_EQ(result, mWindow->getLastDequeueStartTime()); } + +TEST_F(ANativeWindowTest, setDequeueTimeout_causesDequeueTimeout) { + nsecs_t timeout = milliseconds_to_nanoseconds(100); + int result = ANativeWindow_setDequeueTimeout(mWindow.get(), timeout); + EXPECT_EQ(0, result); + + // The two dequeues should not timeout... + ANativeWindowBuffer* buffer; + int fd; + int dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd); + close(fd); + EXPECT_EQ(0, dequeueResult); + int queueResult = ANativeWindow_queueBuffer(mWindow.get(), buffer, -1); + EXPECT_EQ(0, queueResult); + dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd); + close(fd); + EXPECT_EQ(0, dequeueResult); + queueResult = ANativeWindow_queueBuffer(mWindow.get(), buffer, -1); + EXPECT_EQ(0, queueResult); + + // ...but the third one should since the queue depth is too deep. + nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC); + dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd); + nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC); + close(fd); + EXPECT_EQ(TIMED_OUT, dequeueResult); + EXPECT_GE(end - start, timeout); +} -- GitLab From 72670c57aa1a158ab05055d65a618307d57bf154 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Sat, 31 Aug 2019 01:54:33 -0700 Subject: [PATCH 0257/1255] [ANativeWindow] Increase precision for duration queries. Use perform() instead in query() to retrieve dequeue/queue durations for nanosecond resolution. Bug: 137012798 Test: atest Change-Id: I894a8784f3321d4ab6f538d7e7fc1457de26f289 --- libs/gui/Surface.cpp | 18 ++++++++++++++++++ libs/gui/include/gui/Surface.h | 2 ++ libs/nativewindow/ANativeWindow.cpp | 18 +++++++++++------- libs/nativewindow/include/apex/window.h | 8 ++++---- libs/nativewindow/include/system/window.h | 12 +++++++++--- libs/nativewindow/tests/ANativeWindowTest.cpp | 6 +++--- 6 files changed, 47 insertions(+), 17 deletions(-) diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index fb9d7427d7..e490d6d17d 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1087,6 +1087,12 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT: res = dispatchSetDequeueTimeout(args); break; + case NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION: + res = dispatchGetLastDequeueDuration(args); + break; + case NATIVE_WINDOW_GET_LAST_QUEUE_DURATION: + res = dispatchGetLastQueueDuration(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1303,6 +1309,18 @@ int Surface::dispatchSetDequeueTimeout(va_list args) { return setDequeueTimeout(timeout); } +int Surface::dispatchGetLastDequeueDuration(va_list args) { + int64_t* lastDequeueDuration = va_arg(args, int64_t*); + *lastDequeueDuration = mLastDequeueDuration; + return NO_ERROR; +} + +int Surface::dispatchGetLastQueueDuration(va_list args) { + int64_t* lastQueueDuration = va_arg(args, int64_t*); + *lastQueueDuration = mLastQueueDuration; + return NO_ERROR; +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 2527ec0a75..e582509b6e 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -246,6 +246,8 @@ private: int dispatchSetAutoPrerotation(va_list args); int dispatchGetLastDequeueStartTime(va_list args); int dispatchSetDequeueTimeout(va_list args); + int dispatchGetLastDequeueDuration(va_list args); + int dispatchGetLastQueueDuration(va_list args); bool transformToDisplayInverse(); protected: diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index fecfa193df..0ba01f4da4 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -33,6 +33,12 @@ static int32_t query(ANativeWindow* window, int what) { return res < 0 ? res : value; } +static int64_t query64(ANativeWindow* window, int what) { + int64_t value; + int res = window->perform(window, what, &value); + return res < 0 ? res : value; +} + static bool isDataSpaceValid(ANativeWindow* window, int32_t dataSpace) { bool supported = false; switch (dataSpace) { @@ -271,18 +277,16 @@ int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation * apex-stable **************************************************************************************************/ -int ANativeWindow_getLastDequeueDuration(ANativeWindow* window) { - return query(window, NATIVE_WINDOW_LAST_DEQUEUE_DURATION); +int64_t ANativeWindow_getLastDequeueDuration(ANativeWindow* window) { + return query64(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION); } -int ANativeWindow_getLastQueueDuration(ANativeWindow* window) { - return query(window, NATIVE_WINDOW_LAST_QUEUE_DURATION); +int64_t ANativeWindow_getLastQueueDuration(ANativeWindow* window) { + return query64(window, NATIVE_WINDOW_GET_LAST_QUEUE_DURATION); } int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window) { - int64_t time; - int success = window->perform(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START, &time); - return success < 0 ? success : time; + return query64(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START); } int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout) { diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h index 9798c2fd47..869b22ec19 100644 --- a/libs/nativewindow/include/apex/window.h +++ b/libs/nativewindow/include/apex/window.h @@ -27,17 +27,17 @@ __BEGIN_DECLS * Retrieves how long it took for the last time a buffer was dequeued. * * \return a negative value on error, otherwise returns the duration in - * microseconds. + * nanoseconds */ -int ANativeWindow_getLastDequeueDuration(ANativeWindow* window); +int64_t ANativeWindow_getLastDequeueDuration(ANativeWindow* window); /** * Retrieves how long it took for the last time a buffer was queued. * * \return a negative value on error, otherwise returns the duration in - * microseconds + * nanoseconds. */ -int ANativeWindow_getLastQueueDuration(ANativeWindow* window); +int64_t ANativeWindow_getLastQueueDuration(ANativeWindow* window); /** * Retrieves the system time in nanoseconds when the last time a buffer diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 8f850070b6..1814ab5568 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -63,9 +63,9 @@ __BEGIN_DECLS /* attributes queriable with query() */ enum { - NATIVE_WINDOW_WIDTH = 0, - NATIVE_WINDOW_HEIGHT = 1, - NATIVE_WINDOW_FORMAT = 2, + NATIVE_WINDOW_WIDTH = 0, + NATIVE_WINDOW_HEIGHT = 1, + NATIVE_WINDOW_FORMAT = 2, /* see ANativeWindowQuery in vndk/window.h */ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS = ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS, @@ -147,11 +147,15 @@ enum { /* * Returns the duration of the last dequeueBuffer call in microseconds + * Deprecated: please use NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION in + * perform() instead, which supports nanosecond precision. */ NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14, /* * Returns the duration of the last queueBuffer call in microseconds + * Deprecated: please use NATIVE_WINDOW_GET_LAST_QUEUE_DURATION in + * perform() instead, which supports nanosecond precision. */ NATIVE_WINDOW_LAST_QUEUE_DURATION = 15, @@ -241,6 +245,8 @@ enum { NATIVE_WINDOW_SET_AUTO_PREROTATION = 35, NATIVE_WINDOW_GET_LAST_DEQUEUE_START = 36, /* private */ NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT = 37, /* private */ + NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION = 38, /* private */ + NATIVE_WINDOW_GET_LAST_QUEUE_DURATION = 39, /* private */ // clang-format on }; diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp index 4d2b8c8f3b..6cf8291da2 100644 --- a/libs/nativewindow/tests/ANativeWindowTest.cpp +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -74,7 +74,7 @@ protected: TEST_F(ANativeWindowTest, getLastDequeueDuration_noDequeue_returnsZero) { int result = ANativeWindow_getLastDequeueDuration(mWindow.get()); EXPECT_EQ(0, result); - EXPECT_EQ(0, mWindow->getLastDequeueDuration() / 1000); + EXPECT_EQ(0, mWindow->getLastDequeueDuration()); } TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) { @@ -86,7 +86,7 @@ TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) { result = ANativeWindow_getLastDequeueDuration(mWindow.get()); EXPECT_GT(result, 0); - EXPECT_EQ(result, mWindow->getLastDequeueDuration() / 1000); + EXPECT_EQ(result, mWindow->getLastDequeueDuration()); } TEST_F(ANativeWindowTest, getLastQueueDuration_noDequeue_returnsZero) { @@ -118,7 +118,7 @@ TEST_F(ANativeWindowTest, getLastQueueDuration_withQueue_returnsTime) { result = ANativeWindow_getLastQueueDuration(mWindow.get()); EXPECT_GT(result, 0); - EXPECT_EQ(result, mWindow->getLastQueueDuration() / 1000); + EXPECT_EQ(result, mWindow->getLastQueueDuration()); } TEST_F(ANativeWindowTest, getLastDequeueStartTime_noDequeue_returnsZero) { -- GitLab From df336d9f770ba18e4a25513694b3e4fc7b2bbc65 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 7 Mar 2019 21:38:42 -0800 Subject: [PATCH 0258/1255] SF: Restructure OutputLayer creation to remove displayId argument The existing code was explicitly passing the displayId when creating an OutputLayer, so that a HWC2::Layer could be created if applicable. This patch makes a quick adjustment to the code so that the compositionengine::Display instance overrides the base createOutputLayer logic to create the HWC2::Layer, as it knows the displayId itself. This is a minor cleanup prior to moving computeVisibleLayers to the Output class. Test: atest libsurfaceflinger_unittest libcompositionengine_test Test: go/wm-smoke Bug: 121291683 Change-Id: Ic7224ba445084b833b8c344436397372b2153d42 --- .../include/compositionengine/Output.h | 7 +++-- .../include/compositionengine/OutputLayer.h | 3 ++ .../include/compositionengine/impl/Display.h | 2 ++ .../include/compositionengine/impl/Output.h | 5 ++-- .../compositionengine/impl/OutputLayer.h | 10 +++---- .../include/compositionengine/mock/Output.h | 8 +++-- .../compositionengine/mock/OutputLayer.h | 2 ++ .../CompositionEngine/src/Display.cpp | 25 ++++++++++++++++ .../CompositionEngine/src/Output.cpp | 12 ++++++-- .../CompositionEngine/src/OutputLayer.cpp | 30 +++++++------------ .../CompositionEngine/tests/DisplayTest.cpp | 21 +++++++++++++ .../tests/OutputLayerTest.cpp | 24 +++++---------- .../CompositionEngine/tests/OutputTest.cpp | 4 +-- services/surfaceflinger/SurfaceFlinger.cpp | 5 +--- .../tests/unittests/CompositionTest.cpp | 4 +-- 15 files changed, 103 insertions(+), 59 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 43f44af8ca..2e44c075ae 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -138,11 +138,14 @@ public: // this output, or nullptr if the layer does not have one virtual OutputLayer* getOutputLayerForLayer(Layer*) const = 0; + // Creates an OutputLayer instance for this output + virtual std::unique_ptr createOutputLayer(const std::shared_ptr&, + const sp&) const = 0; + // Gets the OutputLayer corresponding to the input Layer instance from the // current ordered set of output layers. If there is no such layer, a new // one is created and returned. - virtual std::unique_ptr getOrCreateOutputLayer(std::optional, - std::shared_ptr, + virtual std::unique_ptr getOrCreateOutputLayer(std::shared_ptr, sp) = 0; // Sets the new ordered set of output layers for this output diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index cedd728588..389b6059f3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -48,6 +48,9 @@ class OutputLayer { public: virtual ~OutputLayer(); + // Sets the HWC2::Layer associated with this layer + virtual void setHwcLayer(std::shared_ptr) = 0; + // Gets the output which owns this output layer virtual const Output& getOutput() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index bd1aa08fde..2e595d6e23 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -40,6 +40,8 @@ public: // compositionengine::Output overrides void dump(std::string&) const override; + std::unique_ptr createOutputLayer( + const std::shared_ptr&, const sp&) const override; void setColorTransform(const compositionengine::CompositionRefreshArgs&) override; void setColorProfile(const ColorProfile&) override; void chooseCompositionStrategy() override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index ece5b1c5ee..bdb35c22e9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -66,9 +66,10 @@ public: compositionengine::OutputLayer* getOutputLayerForLayer( compositionengine::Layer*) const override; + std::unique_ptr createOutputLayer( + const std::shared_ptr&, const sp&) const override; std::unique_ptr getOrCreateOutputLayer( - std::optional, std::shared_ptr, - sp) override; + std::shared_ptr, sp) override; void setOutputLayersOrderedByZ(OutputLayers&&) override; const OutputLayers& getOutputLayersOrderedByZ() const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index fa4d8cd6db..1199fea71d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -34,11 +34,11 @@ namespace impl { class OutputLayer : public compositionengine::OutputLayer { public: - OutputLayer(const compositionengine::Output&, std::shared_ptr, - sp); + OutputLayer(const compositionengine::Output&, const std::shared_ptr&, + const sp&); ~OutputLayer() override; - void initialize(const CompositionEngine&, std::optional); + void setHwcLayer(std::shared_ptr) override; const compositionengine::Output& getOutput() const override; compositionengine::Layer& getLayer() const override; @@ -86,8 +86,8 @@ private: }; std::unique_ptr createOutputLayer( - const CompositionEngine&, std::optional, const compositionengine::Output&, - std::shared_ptr, sp); + const compositionengine::Output&, const std::shared_ptr&, + const sp&); } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 2f24c15896..93274e79ff 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -63,9 +63,13 @@ public: MOCK_CONST_METHOD1(getOutputLayerForLayer, compositionengine::OutputLayer*(compositionengine::Layer*)); - MOCK_METHOD3(getOrCreateOutputLayer, + MOCK_CONST_METHOD2(createOutputLayer, + std::unique_ptr( + const std::shared_ptr&, + const sp&)); + MOCK_METHOD2(getOrCreateOutputLayer, std::unique_ptr( - std::optional, std::shared_ptr, + std::shared_ptr, sp)); MOCK_METHOD1(setOutputLayersOrderedByZ, void(OutputLayers&&)); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h index 6b2224ac60..4f2afacd63 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -31,6 +31,8 @@ public: OutputLayer(); virtual ~OutputLayer(); + MOCK_METHOD1(setHwcLayer, void(std::shared_ptr)); + MOCK_CONST_METHOD0(getOutput, const compositionengine::Output&()); MOCK_CONST_METHOD0(getLayer, compositionengine::Layer&()); MOCK_CONST_METHOD0(getLayerFE, compositionengine::LayerFE&()); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 000a294c75..49727dfed5 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -133,6 +134,30 @@ void Display::createRenderSurface(RenderSurfaceCreationArgs&& args) { std::move(args))); } +std::unique_ptr Display::createOutputLayer( + const std::shared_ptr& layer, + const sp& layerFE) const { + auto result = Output::createOutputLayer(layer, layerFE); + + if (result && mId) { + auto& hwc = getCompositionEngine().getHwComposer(); + auto displayId = *mId; + // Note: For the moment we ensure it is safe to take a reference to the + // HWComposer implementation by destroying all the OutputLayers (and + // hence the HWC2::Layers they own) before setting a new HWComposer. See + // for example SurfaceFlinger::updateVrFlinger(). + // TODO(b/121291683): Make this safer. + auto hwcLayer = std::shared_ptr(hwc.createLayer(displayId), + [&hwc, displayId](HWC2::Layer* layer) { + hwc.destroyLayer(displayId, layer); + }); + ALOGE_IF(!hwcLayer, "Failed to create a HWC layer for a HWC supported display %s", + getName().c_str()); + result->setHwcLayer(std::move(hwcLayer)); + } + return result; +} + void Display::chooseCompositionStrategy() { ATRACE_CALL(); ALOGV(__FUNCTION__); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 4dfdebae02..cb04e95cf3 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -230,14 +230,20 @@ compositionengine::OutputLayer* Output::getOutputLayerForLayer( } std::unique_ptr Output::getOrCreateOutputLayer( - std::optional displayId, std::shared_ptr layer, - sp layerFE) { + std::shared_ptr layer, sp layerFE) { for (auto& outputLayer : mOutputLayersOrderedByZ) { if (outputLayer && &outputLayer->getLayer() == layer.get()) { return std::move(outputLayer); } } - return createOutputLayer(mCompositionEngine, displayId, *this, layer, layerFE); + + return createOutputLayer(layer, layerFE); +} + +std::unique_ptr Output::createOutputLayer( + const std::shared_ptr& layer, + const sp& layerFE) const { + return impl::createOutputLayer(*this, layer, layerFE); } void Output::setOutputLayersOrderedByZ(OutputLayers&& layers) { diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 3a0ebf8121..4eb256f94c 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -15,7 +15,6 @@ */ #include -#include #include #include #include @@ -46,31 +45,24 @@ FloatRect reduce(const FloatRect& win, const Region& exclude) { } // namespace std::unique_ptr createOutputLayer( - const CompositionEngine& compositionEngine, std::optional displayId, - const compositionengine::Output& output, std::shared_ptr layer, - sp layerFE) { - auto result = std::make_unique(output, layer, layerFE); - result->initialize(compositionEngine, displayId); - return result; + const compositionengine::Output& output, + const std::shared_ptr& layer, + const sp& layerFE) { + return std::make_unique(output, layer, layerFE); } -OutputLayer::OutputLayer(const Output& output, std::shared_ptr layer, sp layerFE) +OutputLayer::OutputLayer(const Output& output, const std::shared_ptr& layer, + const sp& layerFE) : mOutput(output), mLayer(layer), mLayerFE(layerFE) {} OutputLayer::~OutputLayer() = default; -void OutputLayer::initialize(const CompositionEngine& compositionEngine, - std::optional displayId) { - if (!displayId) { - return; +void OutputLayer::setHwcLayer(std::shared_ptr hwcLayer) { + if (hwcLayer) { + mState.hwc.emplace(hwcLayer); + } else { + mState.hwc.reset(); } - - auto& hwc = compositionEngine.getHwComposer(); - - mState.hwc.emplace(std::shared_ptr(hwc.createLayer(*displayId), - [&hwc, displayId](HWC2::Layer* layer) { - hwc.destroyLayer(*displayId, layer); - })); } const compositionengine::Output& OutputLayer::getOutput() const { diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 008e631deb..6821ec1301 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include #include @@ -255,6 +257,25 @@ TEST_F(DisplayTest, createRenderSurfaceSetsRenderSurface) { EXPECT_TRUE(mDisplay.getRenderSurface() != nullptr); } +/* + * Display::createOutputLayer() + */ + +TEST_F(DisplayTest, createOutputLayerSetsHwcLayer) { + sp layerFE = new StrictMock(); + auto layer = std::make_shared>(); + StrictMock hwcLayer; + + EXPECT_CALL(mHwComposer, createLayer(DEFAULT_DISPLAY_ID)).WillOnce(Return(&hwcLayer)); + + auto outputLayer = mDisplay.createOutputLayer(layer, layerFE); + + EXPECT_EQ(&hwcLayer, outputLayer->getHwcLayer()); + + EXPECT_CALL(mHwComposer, destroyLayer(DEFAULT_DISPLAY_ID, &hwcLayer)); + outputLayer.reset(); +} + /* * Display::chooseCompositionStrategy() */ diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 65691ffbc7..b73c47ba17 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -36,8 +36,6 @@ using testing::Return; using testing::ReturnRef; using testing::StrictMock; -constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42}; - constexpr auto TR_IDENT = 0u; constexpr auto TR_FLP_H = HAL_TRANSFORM_FLIP_H; constexpr auto TR_FLP_V = HAL_TRANSFORM_FLIP_V; @@ -83,35 +81,27 @@ struct OutputLayerTest : public testing::Test { TEST_F(OutputLayerTest, canInstantiateOutputLayer) {} /* - * OutputLayer::initialize() + * OutputLayer::setHwcLayer() */ -TEST_F(OutputLayerTest, initializingOutputLayerWithoutHwcDoesNothingInteresting) { +TEST_F(OutputLayerTest, settingNullHwcLayerSetsEmptyHwcState) { StrictMock compositionEngine; - mOutputLayer.initialize(compositionEngine, std::nullopt); + mOutputLayer.setHwcLayer(nullptr); EXPECT_FALSE(mOutputLayer.getState().hwc); } -TEST_F(OutputLayerTest, initializingOutputLayerWithHwcDisplayCreatesHwcLayer) { - StrictMock compositionEngine; - StrictMock hwc; - StrictMock hwcLayer; - - EXPECT_CALL(compositionEngine, getHwComposer()).WillOnce(ReturnRef(hwc)); - EXPECT_CALL(hwc, createLayer(DEFAULT_DISPLAY_ID)).WillOnce(Return(&hwcLayer)); +TEST_F(OutputLayerTest, settingHwcLayerSetsHwcState) { + auto hwcLayer = std::make_shared>(); - mOutputLayer.initialize(compositionEngine, DEFAULT_DISPLAY_ID); + mOutputLayer.setHwcLayer(hwcLayer); const auto& outputLayerState = mOutputLayer.getState(); ASSERT_TRUE(outputLayerState.hwc); const auto& hwcState = *outputLayerState.hwc; - EXPECT_EQ(&hwcLayer, hwcState.hwcLayer.get()); - - EXPECT_CALL(hwc, destroyLayer(DEFAULT_DISPLAY_ID, &hwcLayer)); - mOutputLayer.editState().hwc.reset(); + EXPECT_EQ(hwcLayer, hwcState.hwcLayer); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 70d98717ae..10ec1ee314 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -429,7 +429,7 @@ TEST_F(OutputTest, getOrCreateOutputLayerWorks) { // If there is no OutputLayer corresponding to the input layer, a // new OutputLayer is constructed and returned. EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(otherLayer)); - auto result = mOutput.getOrCreateOutputLayer(std::nullopt, layer, layerFE); + auto result = mOutput.getOrCreateOutputLayer(layer, layerFE); EXPECT_NE(existingOutputLayer, result.get()); EXPECT_TRUE(result.get() != nullptr); EXPECT_EQ(layer.get(), &result->getLayer()); @@ -445,7 +445,7 @@ TEST_F(OutputTest, getOrCreateOutputLayerWorks) { // If there is an existing OutputLayer for the requested layer, an owned // pointer is returned EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(*layer)); - auto result = mOutput.getOrCreateOutputLayer(std::nullopt, layer, layerFE); + auto result = mOutput.getOrCreateOutputLayer(layer, layerFE); EXPECT_EQ(existingOutputLayer, result.get()); // The corresponding entry in the ordered array should be cleared. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6d853f957a..9479cb67c3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2899,10 +2899,7 @@ void SurfaceFlinger::computeVisibleRegions( return; } - const auto displayId = displayDevice->getId(); - - outLayersSortedByZ.emplace_back( - display->getOrCreateOutputLayer(displayId, compositionLayer, layerFE)); + outLayersSortedByZ.emplace_back(display->getOrCreateOutputLayer(compositionLayer, layerFE)); auto& outputLayerState = outLayersSortedByZ.back()->editState(); outputLayerState.visibleRegion = std::move(visibleRegion); outputLayerState.visibleNonTransparentRegion = std::move(visibleNonTransparentRegion); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 9e4d57e7dc..20dfed65e2 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -814,9 +814,7 @@ struct BaseLayerVariant { std::vector> outputLayers; outputLayers.emplace_back(test->mDisplay->getCompositionDisplay() - ->getOrCreateOutputLayer(DEFAULT_DISPLAY_ID, - layer->getCompositionLayer(), - layer)); + ->createOutputLayer(layer->getCompositionLayer(), layer)); outputLayers.back()->editState().visibleRegion = Region(Rect(0, 0, 100, 100)); outputLayers.back()->editState().outputSpaceVisibleRegion = Region(Rect(0, 0, 100, 100)); -- GitLab From b6e543718a0421a8a821c44a4d15cde23d4ddd35 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 4 Sep 2019 14:06:28 -0700 Subject: [PATCH 0259/1255] SF: Add dumpsys flag to dump raw EDID Bug: 140429990 Test: adb shell dumpsys SurfaceFlinger --edid | xxd Test: adb shell dumpsys SurfaceFlinger --edid | parse-edid Change-Id: Iccfaf3a0ac7c4b0eb05f0ac6a9d0de31a8de46dc --- services/surfaceflinger/SurfaceFlinger.cpp | 26 +++++++++++++--------- services/surfaceflinger/SurfaceFlinger.h | 1 + 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3498419cdf..191cfe85cb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -112,6 +112,7 @@ #include +#include "android-base/parseint.h" #include "android-base/stringprintf.h" #include @@ -4053,6 +4054,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)}, {"--dispsync"s, dumper([this](std::string& s) { mScheduler->getPrimaryDispSync().dump(s); })}, + {"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)}, {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)}, {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)}, {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)}, @@ -4281,21 +4283,13 @@ void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const { } if (!isEdid(data)) { - result.append("unknown identification data: "); - for (uint8_t byte : data) { - StringAppendF(&result, "%x ", byte); - } - result.append("\n"); + result.append("unknown identification data\n"); continue; } const auto edid = parseEdid(data); if (!edid) { - result.append("invalid EDID: "); - for (uint8_t byte : data) { - StringAppendF(&result, "%x ", byte); - } - result.append("\n"); + result.append("invalid EDID\n"); continue; } @@ -4305,6 +4299,18 @@ void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const { } } +void SurfaceFlinger::dumpRawDisplayIdentificationData(const DumpArgs& args, + std::string& result) const { + hwc2_display_t hwcDisplayId; + uint8_t port; + DisplayIdentificationData data; + + if (args.size() > 1 && base::ParseUint(String8(args[1]), &hwcDisplayId) && + getHwComposer().getDisplayIdentificationData(hwcDisplayId, &port, &data)) { + result.append(reinterpret_cast(data.data()), data.size()); + } +} + void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { StringAppendF(&result, "Device has wide color built-in display: %d\n", hasWideColorDisplay); StringAppendF(&result, "Device uses color management: %d\n", useColorManagement); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f220c26bdf..beb43d0d9d 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -865,6 +865,7 @@ private: std::vector&& history); void dumpBufferingStats(std::string& result) const; void dumpDisplayIdentificationData(std::string& result) const; + void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const; void dumpWideColorInfo(std::string& result) const; LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; void dumpOffscreenLayersProto(LayersProto& layersProto, -- GitLab From 67968805e429c4d3dfd0b0714a899cfd3064d212 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 6 Sep 2019 13:05:40 -0700 Subject: [PATCH 0260/1255] SurfaceFlinger: do not choose POWER_SAVING as refresh rate Skip POWER_SAVING when looking for a content based refresh rate as it is not a real config. Test: Play 29fps video Bug: 140374873 Change-Id: Ia1be8b849e4ad3c59fdff084f2394e52bdb3828c --- services/surfaceflinger/Scheduler/Scheduler.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index eb52d3fce6..e2a880a7fe 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -514,8 +514,13 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { // Content detection is on, find the appropriate refresh rate with minimal error // TODO(b/139751853): Scan allowed refresh rates only (SurfaceFlinger::mAllowedDisplayConfigs) const float rate = static_cast(mFeatures.contentRefreshRate); - auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(), - mRefreshRateConfigs.getRefreshRates().cend(), + auto begin = mRefreshRateConfigs.getRefreshRates().cbegin(); + + // Skip POWER_SAVING config as it is not a real config + if (begin->first == RefreshRateType::POWER_SAVING) { + ++begin; + } + auto iter = min_element(begin, mRefreshRateConfigs.getRefreshRates().cend(), [rate](const auto& lhs, const auto& rhs) -> bool { return std::abs(lhs.second->fps - rate) < std::abs(rhs.second->fps - rate); -- GitLab From 3a64e7433553171a1708aa4a4d1ecf2d5cb845fd Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 5 Sep 2019 14:40:46 -0700 Subject: [PATCH 0261/1255] libbinder: -= unimplemented readRequestHeaders. This symbol isn't defined. Bug: N/A Test: N/A Change-Id: Ia43d6dae61a0cac314a0ec012d44cb97b0bd0135 --- libs/binder/include/binder/Parcel.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index db6854e47a..b1b8ff18f4 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -384,7 +384,6 @@ public: // Returns the work source provided by the caller. This can only be trusted for trusted calling // uid. uid_t readCallingWorkSourceUid() const; - void readRequestHeaders() const; private: typedef void (*release_func)(Parcel* parcel, -- GitLab From b3885adbaaff4df57e242edb75c153e125e46696 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 6 Sep 2019 17:08:55 -0700 Subject: [PATCH 0262/1255] [SfStats] Temporarily enable timestats by default. Dogfood devices right now don't have telemetry enabled while we move onto statsd, so this code is not exercised at all in dogfood. Bug: 136597024 Bug: 140266250 Test: adb shell dumpsys SurfaceFlinger --timestats -dump Change-Id: Ia11b980107efc8a8788aa3720ebd735f63a5fb8a --- services/surfaceflinger/TimeStats/TimeStats.cpp | 8 ++++++++ services/surfaceflinger/TimeStats/TimeStats.h | 2 +- services/surfaceflinger/tests/unittests/TimeStatsTest.cpp | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index b01fa81594..3df8360a80 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -34,6 +34,14 @@ namespace android { namespace impl { +TimeStats::TimeStats() { + // Temporarily enable TimeStats by default. Telemetry is disabled while + // we move onto statsd, so TimeStats is currently not exercised at all + // during testing. + // TODO: remove this. + enable(); +} + void TimeStats::parseArgs(bool asProto, const Vector& args, std::string& result) { ATRACE_CALL(); diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 9ebc1adc90..1313132920 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -106,7 +106,7 @@ class TimeStats : public android::TimeStats { }; public: - TimeStats() = default; + TimeStats(); void parseArgs(bool asProto, const Vector& args, std::string& result) override; bool isEnabled() override; diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index ffacbfef16..dee2cae9e0 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -209,6 +209,10 @@ int32_t TimeStatsTest::genRandomInt32(int32_t begin, int32_t end) { return distr(mRandomEngine); } +TEST_F(TimeStatsTest, enabledByDefault) { + ASSERT_TRUE(mTimeStats->isEnabled()); +} + TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) { EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); ASSERT_TRUE(mTimeStats->isEnabled()); -- GitLab From c326a94d15828aee6a9261763bb40b82824f0c6c Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 9 Sep 2019 16:07:52 -0700 Subject: [PATCH 0263/1255] libbinder: Hide AppOpsManager/Service from vendor. Vendor apps can still use these behind stable SDK or NDK APIs as applicable, but native code on the vendor image can't use these APIs because they are using /dev/vndbinder and have an incompatible copy of libbinder. Since no vendor binary is serving this, removing extra pound defines and making the vendor version of this library slightly smaller. Bug: 124524556 Test: builds (no vendor code has added dependencies on this yet) Change-Id: Idf01641d4b340ca6fe33c181969507ec071ef930 --- libs/binder/Android.bp | 2 ++ libs/binder/AppOpsManager.cpp | 13 ------------- libs/binder/IAppOpsService.cpp | 4 ---- libs/binder/include/binder/AppOpsManager.h | 8 ++++---- libs/binder/include/binder/IAppOpsService.h | 13 ++++--------- 5 files changed, 10 insertions(+), 30 deletions(-) diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 6ece4a2162..86f19c5873 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -86,8 +86,10 @@ cc_library_shared { vendor: { exclude_srcs: [ "ActivityManager.cpp", + "AppOpsManager.cpp", "IActivityManager.cpp", "IAppOpsCallback.cpp", + "IAppOpsService.cpp", "IBatteryStats.cpp", "IMediaResourceMonitor.cpp", "IPermissionController.cpp", diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index e2af01c161..711fed96a1 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -32,7 +32,6 @@ namespace android { namespace { -#ifndef __ANDROID_VNDK__ #if defined(__BRILLO__) // Because Brillo has no application model, security policy is managed // statically (at build time) with SELinux controls. @@ -41,17 +40,13 @@ const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_ALLOWED; #else const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_IGNORED; #endif // defined(__BRILLO__) -#endif // __ANDROID_VNDK__ } // namespace static String16 _appops("appops"); -#ifndef __ANDROID_VNDK__ static pthread_mutex_t gTokenMutex = PTHREAD_MUTEX_INITIALIZER; -#endif // __ANDROID_VNDK__ static sp gToken; -#ifndef __ANDROID_VNDK__ static const sp& getToken(const sp& service) { pthread_mutex_lock(&gTokenMutex); if (gToken == nullptr || gToken->pingBinder() != NO_ERROR) { @@ -60,17 +55,12 @@ static const sp& getToken(const sp& service) { pthread_mutex_unlock(&gTokenMutex); return gToken; } -#endif // __ANDROID_VNDK__ thread_local uint64_t notedAppOpsInThisBinderTransaction[2]; thread_local int32_t uidOfThisBinderTransaction = -1; // Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note -#ifndef __ANDROID_VNDK__ uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0}; -#else -uint8_t appOpsToNote[128] = {0}; -#endif // __ANDROID_VNDK__ AppOpsManager::AppOpsManager() { @@ -108,7 +98,6 @@ sp AppOpsManager::getService() } #endif // defined(__BRILLO__) -#ifndef __ANDROID_VNDK__ int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage) { sp service = getService(); @@ -200,8 +189,6 @@ void AppOpsManager::setCameraAudioRestriction(int32_t mode) { } } -#endif // __ANDROID_VNDK__ - bool AppOpsManager::shouldCollectNotes(int32_t opcode) { sp service = getService(); if (service != nullptr) { diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index b6360cbffd..c58ea029b3 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -34,7 +34,6 @@ public: { } -#ifndef __ANDROID_VNDK__ virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); @@ -145,7 +144,6 @@ public: remote()->transact(SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION, data, &reply); } -#endif virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, int32_t opCode, const String16& message) { Parcel data, reply; @@ -195,7 +193,6 @@ status_t BnAppOpsService::onTransact( { //printf("AppOpsService received: "); data.print(); switch(code) { -#ifndef __ANDROID_VNDK__ case CHECK_OPERATION_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); int32_t code = data.readInt32(); @@ -288,7 +285,6 @@ status_t BnAppOpsService::onTransact( reply->writeNoException(); return NO_ERROR; } break; -#endif // __ANDROID_VNDK__ case NOTE_ASYNC_OP_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); String16 callingPackageName = data.readString16(); diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index dff4d49596..f5a54cea4c 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -21,6 +21,10 @@ #include +#ifdef __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif + // --------------------------------------------------------------------------- namespace android { @@ -33,7 +37,6 @@ public: MODE_ERRORED = IAppOpsService::MODE_ERRORED }; -#ifndef __ANDROID_VNDK__ enum { OP_NONE = -1, OP_COARSE_LOCATION = 0, @@ -121,11 +124,9 @@ public: OP_READ_DEVICE_IDENTIFIERS = 89, _NUM_OP = 90 }; -#endif // __ANDROID_VNDK__ AppOpsManager(); -#ifndef __ANDROID_VNDK__ int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage); int32_t checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid, const String16& callingPackage); @@ -145,7 +146,6 @@ public: void stopWatchingMode(const sp& callback); int32_t permissionToOpCode(const String16& permission); void setCameraAudioRestriction(int32_t mode); -#endif // __ANDROID_VNDK__ void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, int32_t opCode, const String16& message); diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index 009ef6c7a7..978400304e 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -18,11 +18,13 @@ #ifndef ANDROID_IAPP_OPS_SERVICE_H #define ANDROID_IAPP_OPS_SERVICE_H -#ifndef __ANDROID_VNDK__ #include -#endif #include +#ifdef __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif + namespace android { // ---------------------------------------------------------------------- @@ -32,7 +34,6 @@ class IAppOpsService : public IInterface public: DECLARE_META_INTERFACE(AppOpsService) -#ifndef __ANDROID_VNDK__ virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, @@ -47,13 +48,11 @@ public: virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid, const String16& packageName) = 0; virtual void setCameraAudioRestriction(int32_t mode) = 0; -#endif // __ANDROID_VNDK__ virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, int32_t opCode, const String16& message) = 0; virtual bool shouldCollectNotes(int32_t opCode) = 0; enum { -#ifndef __ANDROID_VNDK__ CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, NOTE_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+1, START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2, @@ -63,13 +62,9 @@ public: GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6, PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7, CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8, -#endif // __ANDROID_VNDK__ NOTE_ASYNC_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9, SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10, -#ifndef __ANDROID_VNDK__ SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+11, -#endif // __ANDROID_VNDK__ - }; enum { -- GitLab From 3578917f82c84ad1be334105624084c7b1c95b54 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Mon, 9 Sep 2019 16:50:14 -0700 Subject: [PATCH 0264/1255] Add SCROLL, RELATIVE_X and RELATIVE_Y axes labels. CTS tests then can use this to obtain axis value and sets them. Bug: 133368243 Test: We can obtain values of these axes. Change-Id: I2d94c9345639feb40c8486e07535bfd6fe059066 --- include/input/InputEventLabels.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h index 59d16d15af..eaa562bb7b 100644 --- a/include/input/InputEventLabels.h +++ b/include/input/InputEventLabels.h @@ -359,6 +359,9 @@ static const InputEventLabel AXES[] = { DEFINE_AXIS(BRAKE), DEFINE_AXIS(DISTANCE), DEFINE_AXIS(TILT), + DEFINE_AXIS(SCROLL), + DEFINE_AXIS(RELATIVE_X), + DEFINE_AXIS(RELATIVE_Y), DEFINE_AXIS(GENERIC_1), DEFINE_AXIS(GENERIC_2), DEFINE_AXIS(GENERIC_3), -- GitLab From 66c20c4d9b6ee3e587017cb501aaae5bf7d5c3b7 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 7 Mar 2019 21:44:02 -0800 Subject: [PATCH 0265/1255] SF: Cleanup Layer membership test Rather than passing the individual data for the layer (stack id, primaryOnly flag), pass the entire layer, and have the Output class look for the right data. This makes it easier to change the membership logic later if desired. Test: atest libsurfaceflinger_unittest libcompositionengine_test Test: go/wm-smoke Bug: 121291683 Change-Id: Ieccb3986dd4f045b68329825a7e3e05734811cc0 --- .../include/compositionengine/Output.h | 3 + .../include/compositionengine/impl/Output.h | 1 + .../include/compositionengine/mock/Output.h | 1 + .../CompositionEngine/src/Output.cpp | 9 +++ .../CompositionEngine/tests/OutputTest.cpp | 65 +++++++++++++++++++ services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 6 files changed, 80 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 2e44c075ae..80fce2cd5c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -134,6 +134,9 @@ public: // this output allows that. virtual bool belongsInOutput(std::optional layerStackId, bool internalOnly) const = 0; + // Determines if a layer belongs to the output. + virtual bool belongsInOutput(const compositionengine::Layer*) 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; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index bdb35c22e9..6dde86d706 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -63,6 +63,7 @@ public: Region getDirtyRegion(bool repaintEverything) const override; bool belongsInOutput(std::optional, bool) const override; + bool belongsInOutput(const compositionengine::Layer*) const override; compositionengine::OutputLayer* getOutputLayerForLayer( compositionengine::Layer*) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 93274e79ff..8cf7f79513 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -60,6 +60,7 @@ public: MOCK_CONST_METHOD1(getDirtyRegion, Region(bool)); MOCK_CONST_METHOD2(belongsInOutput, bool(std::optional, bool)); + MOCK_CONST_METHOD1(belongsInOutput, bool(const compositionengine::Layer*)); MOCK_CONST_METHOD1(getOutputLayerForLayer, compositionengine::OutputLayer*(compositionengine::Layer*)); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index cb04e95cf3..a9b1d5540b 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -219,6 +219,15 @@ bool Output::belongsInOutput(std::optional layerStackId, bool internal (!internalOnly || mState.layerStackInternal); } +bool Output::belongsInOutput(const compositionengine::Layer* layer) const { + if (!layer) { + return false; + } + + const auto& layerFEState = layer->getState().frontEnd; + return belongsInOutput(layerFEState.layerStackId, layerFEState.internalOnly); +} + compositionengine::OutputLayer* Output::getOutputLayerForLayer( compositionengine::Layer* layer) const { for (const auto& outputLayer : mOutputLayersOrderedByZ) { diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 10ec1ee314..a0b8017264 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -376,6 +376,71 @@ TEST_F(OutputTest, belongsInOutputFiltersAsExpected) { EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false)); } +TEST_F(OutputTest, belongsInOutputFiltersLayersAsExpected) { + StrictMock layer; + impl::LayerCompositionState layerState; + + EXPECT_CALL(layer, getState()).WillRepeatedly(ReturnRef(layerState)); + + const uint32_t layerStack1 = 123u; + const uint32_t layerStack2 = 456u; + + // 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. + layerState.frontEnd.layerStackId = std::nullopt; + layerState.frontEnd.internalOnly = false; + EXPECT_FALSE(mOutput.belongsInOutput(&layer)); + + layerState.frontEnd.layerStackId = std::nullopt; + layerState.frontEnd.internalOnly = true; + EXPECT_FALSE(mOutput.belongsInOutput(&layer)); + + // Any layer with layerStack1 belongs to it, internal-only or not. + layerState.frontEnd.layerStackId = layerStack1; + layerState.frontEnd.internalOnly = false; + EXPECT_TRUE(mOutput.belongsInOutput(&layer)); + + layerState.frontEnd.layerStackId = layerStack1; + layerState.frontEnd.internalOnly = true; + EXPECT_TRUE(mOutput.belongsInOutput(&layer)); + + layerState.frontEnd.layerStackId = layerStack2; + layerState.frontEnd.internalOnly = true; + EXPECT_FALSE(mOutput.belongsInOutput(&layer)); + + layerState.frontEnd.layerStackId = layerStack2; + layerState.frontEnd.internalOnly = false; + EXPECT_FALSE(mOutput.belongsInOutput(&layer)); + + // 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. + layerState.frontEnd.layerStackId = layerStack1; + layerState.frontEnd.internalOnly = false; + EXPECT_TRUE(mOutput.belongsInOutput(&layer)); + + layerState.frontEnd.layerStackId = layerStack1; + layerState.frontEnd.internalOnly = true; + EXPECT_FALSE(mOutput.belongsInOutput(&layer)); + + layerState.frontEnd.layerStackId = layerStack2; + layerState.frontEnd.internalOnly = true; + EXPECT_FALSE(mOutput.belongsInOutput(&layer)); + + layerState.frontEnd.layerStackId = layerStack2; + layerState.frontEnd.internalOnly = false; + EXPECT_FALSE(mOutput.belongsInOutput(&layer)); +} + /* * Output::getOutputLayerForLayer() */ diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4361a94e64..344c5e7d9f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2773,7 +2773,7 @@ void SurfaceFlinger::computeVisibleRegions( const auto& layerFEState = compositionLayer->getState().frontEnd; // only consider the layers on the given layer stack - if (!display->belongsInOutput(layerFEState.layerStackId, layerFEState.internalOnly)) { + if (!display->belongsInOutput(compositionLayer.get())) { return; } -- GitLab From c29e4c66c2a32d84e75976a0d7d95d2a7ed4739a Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 7 Mar 2019 21:48:19 -0800 Subject: [PATCH 0266/1255] SF: Move/Refactor rebuildLayerStacks and computeVisibleRegions This is the one big final move of code to CompositionEngine. The logic is restructured, though the basic blocks still correspond to what existed before to allow for easier conflict resolution across the move. The function to compute the per-layer visibility information is still much bigger than I like -- perhaps this can be cleaned up later after more unit test coverage is introduced. Test: atest libsurfaceflinger_unittest libcompositionengine_test Test: atest CtsColorModeTestCases Test: atest CtsDisplayTestCases Test: atest CtsGraphicsTestCases Test: atest CtsUiRenderingTestCases Test: atest CtsViewTestCases Test: atest android.media.cts.EncodeVirtualDisplayWithCompositionTest Test: go/wm-smoke Bug: 121291683 Change-Id: Ia3fb6c0fb0bb847ab737a1f92617d3724c08ea54 --- .../CompositionRefreshArgs.h | 8 + .../include/compositionengine/LayerFE.h | 9 + .../include/compositionengine/Output.h | 26 +- .../include/compositionengine/impl/Display.h | 2 + .../include/compositionengine/impl/Output.h | 13 +- .../include/compositionengine/mock/Output.h | 13 +- .../src/CompositionEngine.cpp | 16 +- .../CompositionEngine/src/Display.cpp | 33 ++ .../CompositionEngine/src/Output.cpp | 302 +++++++++++++++++- .../CompositionEngine/tests/DisplayTest.cpp | 73 +++++ services/surfaceflinger/SurfaceFlinger.cpp | 266 +-------------- services/surfaceflinger/SurfaceFlinger.h | 4 - 12 files changed, 490 insertions(+), 275 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index 6f689ad4be..90158c721d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -28,6 +29,7 @@ namespace android::compositionengine { using Layers = std::vector>; using Outputs = std::vector>; +using RawLayers = std::vector; /** * A parameter object for refreshing a set of outputs @@ -41,6 +43,9 @@ struct CompositionRefreshArgs { // front. Layers layers; + // All the layers that have queued updates. + RawLayers layersWithQueuedFrames; + // If true, forces the entire display to be considered dirty and repainted bool repaintEverything{false}; @@ -53,6 +58,9 @@ struct CompositionRefreshArgs { // Forces a color mode on the outputs being refreshed ui::ColorMode forceOutputColorMode{ui::ColorMode::NATIVE}; + // If true, the complete output geometry needs to be recomputed this frame + bool updatingOutputGeometryThisFrame{false}; + // If true, there was a geometry update this frame bool updatingGeometryThisFrame{false}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 57cca69eb2..e5857694b9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include @@ -99,5 +100,13 @@ public: virtual const char* getDebugName() const = 0; }; +// TODO(b/121291683): Specialize std::hash<> for sp so these and others can +// be removed. +struct LayerFESpHash { + size_t operator()(const sp& p) const { return std::hash()(p.get()); } +}; + +using LayerFESet = std::unordered_set, LayerFESpHash>; + } // namespace compositionengine } // namespace android diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 80fce2cd5c..d374baa388 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -71,6 +72,22 @@ public: ui::Dataspace colorSpaceAgnosticDataspace{ui::Dataspace::UNKNOWN}; }; + // Use internally to incrementally compute visibility/coverage + struct CoverageState { + explicit CoverageState(LayerFESet& latchedLayers) : latchedLayers(latchedLayers) {} + + // The set of layers that had been latched for the coverage calls, to + // avoid duplicate requests to obtain the same front-end layer state. + LayerFESet& latchedLayers; + + // The region of the output which is covered by layers + Region aboveCoveredLayers; + // The region of the output which is opaquely covered by layers + Region aboveOpaqueLayers; + // The region of the output which should be considered dirty + Region dirtyRegion; + }; + virtual ~Output(); // Returns true if the output is valid. This is meant to be checked post- @@ -164,7 +181,7 @@ public: virtual ReleasedLayers takeReleasedLayers() = 0; // Prepare the output, updating the OutputLayers used in the output - virtual void prepare(CompositionRefreshArgs&) = 0; + virtual void prepare(const CompositionRefreshArgs&, LayerFESet&) = 0; // Presents the output, finalizing all composition details virtual void present(const CompositionRefreshArgs&) = 0; @@ -176,6 +193,13 @@ protected: virtual void setDisplayColorProfile(std::unique_ptr) = 0; virtual void setRenderSurface(std::unique_ptr) = 0; + virtual void rebuildLayerStacks(const compositionengine::CompositionRefreshArgs&, + LayerFESet&) = 0; + virtual void collectVisibleLayers(const CompositionRefreshArgs&, CoverageState&) = 0; + virtual std::unique_ptr getOutputLayerIfVisible( + std::shared_ptr, CoverageState&) = 0; + virtual void setReleasedLayers(const compositionengine::CompositionRefreshArgs&) = 0; + virtual void updateAndWriteCompositionState(const CompositionRefreshArgs&) = 0; virtual void setColorTransform(const CompositionRefreshArgs&) = 0; virtual void updateColorProfile(const CompositionRefreshArgs&) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index 2e595d6e23..b5d8325040 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -42,6 +42,8 @@ public: void dump(std::string&) const override; std::unique_ptr createOutputLayer( const std::shared_ptr&, const sp&) const override; + using compositionengine::impl::Output::setReleasedLayers; + void setReleasedLayers(const compositionengine::CompositionRefreshArgs&) override; void setColorTransform(const compositionengine::CompositionRefreshArgs&) override; void setColorProfile(const ColorProfile&) override; void chooseCompositionStrategy() override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 6dde86d706..fa6cd27e1a 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -77,9 +77,17 @@ public: void setReleasedLayers(ReleasedLayers&&) override; ReleasedLayers takeReleasedLayers() override; - void prepare(compositionengine::CompositionRefreshArgs&) override; + void prepare(const compositionengine::CompositionRefreshArgs&, LayerFESet&) override; void present(const compositionengine::CompositionRefreshArgs&) override; + void rebuildLayerStacks(const compositionengine::CompositionRefreshArgs&, LayerFESet&) override; + void collectVisibleLayers(const compositionengine::CompositionRefreshArgs&, + compositionengine::Output::CoverageState&) override; + std::unique_ptr getOutputLayerIfVisible( + std::shared_ptr, + compositionengine::Output::CoverageState&) override; + void setReleasedLayers(const compositionengine::CompositionRefreshArgs&) override; + void updateLayerStateFromFE(const CompositionRefreshArgs&) const override; void updateAndWriteCompositionState(const compositionengine::CompositionRefreshArgs&) override; void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override; @@ -91,11 +99,14 @@ public: void postFramebuffer() override; // Testing + const ReleasedLayers& getReleasedLayersForTest() const; void setDisplayColorProfileForTest(std::unique_ptr); void setRenderSurfaceForTest(std::unique_ptr); protected: const CompositionEngine& getCompositionEngine() const; + std::unique_ptr takeOutputLayerForLayer( + compositionengine::Layer*); void chooseCompositionStrategy() override; bool getSkipColorTransform() const override; compositionengine::Output::FrameFences presentAndGetFrameFences() override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 8cf7f79513..286a20f5af 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -79,9 +79,20 @@ public: MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&)); MOCK_METHOD0(takeReleasedLayers, ReleasedLayers()); - MOCK_METHOD1(prepare, void(compositionengine::CompositionRefreshArgs&)); + MOCK_METHOD2(prepare, void(const compositionengine::CompositionRefreshArgs&, LayerFESet&)); MOCK_METHOD1(present, void(const compositionengine::CompositionRefreshArgs&)); + MOCK_METHOD2(rebuildLayerStacks, + void(const compositionengine::CompositionRefreshArgs&, LayerFESet&)); + MOCK_METHOD2(collectVisibleLayers, + void(const compositionengine::CompositionRefreshArgs&, + compositionengine::Output::CoverageState&)); + MOCK_METHOD2(getOutputLayerIfVisible, + std::unique_ptr( + std::shared_ptr, + compositionengine::Output::CoverageState&)); + MOCK_METHOD1(setReleasedLayers, void(const compositionengine::CompositionRefreshArgs&)); + MOCK_CONST_METHOD1(updateLayerStateFromFE, void(const CompositionRefreshArgs&)); MOCK_METHOD1(updateAndWriteCompositionState, void(const CompositionRefreshArgs&)); MOCK_METHOD1(updateColorProfile, void(const compositionengine::CompositionRefreshArgs&)); diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp index 590c596a6d..713266ff85 100644 --- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp +++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp @@ -72,8 +72,20 @@ nsecs_t CompositionEngine::getLastFrameRefreshTimestamp() const { } void CompositionEngine::present(CompositionRefreshArgs& args) { - for (const auto& output : args.outputs) { - output->prepare(args); + ATRACE_CALL(); + ALOGV(__FUNCTION__); + + preComposition(args); + + { + // latchedLayers is used to track the set of front-end layer state that + // has been latched across all outputs for the prepare step, and is not + // needed for anything else. + LayerFESet latchedLayers; + + for (const auto& output : args.outputs) { + output->prepare(args, latchedLayers); + } } updateLayerStateFromFE(args); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 49727dfed5..fe8fa21a8c 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -158,6 +158,39 @@ std::unique_ptr Display::createOutputLayer( return result; } +void Display::setReleasedLayers(const compositionengine::CompositionRefreshArgs& refreshArgs) { + Output::setReleasedLayers(refreshArgs); + + if (!mId || refreshArgs.layersWithQueuedFrames.empty()) { + return; + } + + // For layers that are being removed from a HWC display, and that have + // queued frames, add them to a a list of released layers so we can properly + // set a fence. + compositionengine::Output::ReleasedLayers releasedLayers; + + // 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) { + continue; + } + + sp layerFE(&layer->getLayerFE()); + const bool hasQueuedFrames = + std::find(refreshArgs.layersWithQueuedFrames.cbegin(), + refreshArgs.layersWithQueuedFrames.cend(), + &layer->getLayer()) != refreshArgs.layersWithQueuedFrames.cend(); + + if (hasQueuedFrames) { + releasedLayers.emplace_back(layerFE); + } + } + + setReleasedLayers(std::move(releasedLayers)); +} + void Display::chooseCompositionStrategy() { ATRACE_CALL(); ALOGV(__FUNCTION__); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index a9b1d5540b..83df628f25 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -40,6 +40,27 @@ Output::~Output() = default; namespace impl { +namespace { + +template +class Reversed { +public: + explicit Reversed(const T& container) : mContainer(container) {} + auto begin() { return mContainer.rbegin(); } + auto end() { return mContainer.rend(); } + +private: + const T& mContainer; +}; + +// Helper for enumerating over a container in reverse order +template +Reversed reversed(const T& c) { + return Reversed(c); +} + +} // namespace + Output::Output(const CompositionEngine& compositionEngine) : mCompositionEngine(compositionEngine) {} @@ -176,6 +197,10 @@ void Output::setDisplayColorProfile(std::unique_ptr mode) { mDisplayColorProfile = std::move(mode); @@ -238,15 +263,24 @@ compositionengine::OutputLayer* Output::getOutputLayerForLayer( return nullptr; } -std::unique_ptr Output::getOrCreateOutputLayer( - std::shared_ptr layer, sp layerFE) { +std::unique_ptr Output::takeOutputLayerForLayer( + compositionengine::Layer* layer) { + // Removes the outputLayer from mOutputLayersorderedByZ and transfers ownership to the caller. for (auto& outputLayer : mOutputLayersOrderedByZ) { - if (outputLayer && &outputLayer->getLayer() == layer.get()) { + if (outputLayer && &outputLayer->getLayer() == layer) { return std::move(outputLayer); } } + return nullptr; +} - return createOutputLayer(layer, layerFE); +std::unique_ptr Output::getOrCreateOutputLayer( + std::shared_ptr layer, sp layerFE) { + auto result = takeOutputLayerForLayer(layer.get()); + if (!result) { + result = createOutputLayer(layer, layerFE); + } + return result; } std::unique_ptr Output::createOutputLayer( @@ -271,19 +305,18 @@ Output::ReleasedLayers Output::takeReleasedLayers() { return std::move(mReleasedLayers); } -void Output::prepare(compositionengine::CompositionRefreshArgs& refreshArgs) { - if (CC_LIKELY(!refreshArgs.updatingGeometryThisFrame)) { - return; - } +void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArgs, + LayerFESet& geomSnapshots) { + ATRACE_CALL(); + ALOGV(__FUNCTION__); - uint32_t zOrder = 0; - for (auto& layer : mOutputLayersOrderedByZ) { - // Assign a simple Z order sequence to each visible layer. - layer->editState().z = zOrder++; - } + rebuildLayerStacks(refreshArgs, geomSnapshots); } void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + updateColorProfile(refreshArgs); updateAndWriteCompositionState(refreshArgs); setColorTransform(refreshArgs); @@ -294,6 +327,249 @@ void Output::present(const compositionengine::CompositionRefreshArgs& refreshArg postFramebuffer(); } +void Output::rebuildLayerStacks(const compositionengine::CompositionRefreshArgs& refreshArgs, + LayerFESet& layerFESet) { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + + // Do nothing if this output is not enabled or there is no need to perform this update + if (!mState.isEnabled || CC_LIKELY(!refreshArgs.updatingOutputGeometryThisFrame)) { + return; + } + + // Process the layers to determine visibility and coverage + compositionengine::Output::CoverageState coverage{layerFESet}; + collectVisibleLayers(refreshArgs, coverage); + + // Compute the resulting coverage for this output, and store it for later + const ui::Transform& tr = mState.transform; + Region undefinedRegion{mState.bounds}; + undefinedRegion.subtractSelf(tr.transform(coverage.aboveOpaqueLayers)); + + mState.undefinedRegion = undefinedRegion; + mState.dirtyRegion.orSelf(coverage.dirtyRegion); +} + +void Output::collectVisibleLayers(const compositionengine::CompositionRefreshArgs& refreshArgs, + compositionengine::Output::CoverageState& coverage) { + // We build up a list of all layers that are going to be visible in the new + // frame. + compositionengine::Output::OutputLayers newLayersSortedByZ; + + // 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)) { + // Incrementally process the coverage for each layer, obtaining an + // optional outputLayer if the layer is visible. + auto outputLayer = getOutputLayerIfVisible(layer, coverage); + if (outputLayer) { + newLayersSortedByZ.emplace_back(std::move(outputLayer)); + } + + // TODO(b/121291683): Stop early if the output is completely covered and + // no more layers could even be visible underneath the ones on top. + } + + // Since we walked the layers in reverse order, we need to reverse + // newLayersSortedByZ to get the back-to-front ordered list of layers. + std::reverse(newLayersSortedByZ.begin(), newLayersSortedByZ.end()); + + // Generate a simple Z-order values to each visible output layer + uint32_t zOrder = 0; + for (auto& outputLayer : newLayersSortedByZ) { + outputLayer->editState().z = zOrder++; + } + + setReleasedLayers(refreshArgs); + + mOutputLayersOrderedByZ = std::move(newLayersSortedByZ); +} + +std::unique_ptr Output::getOutputLayerIfVisible( + std::shared_ptr layer, + compositionengine::Output::CoverageState& coverage) { + // Note: Converts a wp to a sp + auto layerFE = layer->getLayerFE(); + if (layerFE == nullptr) { + return nullptr; + } + + // 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->editState().frontEnd, + compositionengine::LayerFE::StateSubset::BasicGeometry); + } + + // Obtain a read-only reference to the front-end layer state + const auto& layerFEState = layer->getState().frontEnd; + + // Only consider the layers on the given layer stack + if (!belongsInOutput(layer.get())) { + return nullptr; + } + + /* + * opaqueRegion: area of a surface that is fully opaque. + */ + Region opaqueRegion; + + /* + * visibleRegion: area of a surface that is visible on screen and not fully + * transparent. This is essentially the layer's footprint minus the opaque + * regions above it. Areas covered by a translucent surface are considered + * visible. + */ + Region visibleRegion; + + /* + * coveredRegion: area of a surface that is covered by all visible regions + * above it (which includes the translucent areas). + */ + Region coveredRegion; + + /* + * transparentRegion: area of a surface that is hinted to be completely + * transparent. This is only used to tell when the layer has no visible non- + * transparent regions and can be removed from the layer list. It does not + * affect the visibleRegion of this layer or any layers beneath it. The hint + * may not be correct if apps don't respect the SurfaceView restrictions + * (which, sadly, some don't). + */ + Region transparentRegion; + + // handle hidden surfaces by setting the visible region to empty + if (CC_UNLIKELY(!layerFEState.isVisible)) { + return nullptr; + } + + 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? + visibleRegion.set(Rect(tr.transform(layerFEState.geomLayerBounds))); + + if (visibleRegion.isEmpty()) { + return nullptr; + } + + // Remove the transparent area from the visible region + if (!layerFEState.isOpaque) { + if (tr.preserveRects()) { + // transform the transparent region + transparentRegion = tr.transform(layerFEState.transparentRegionHint); + } else { + // transformation too complex, can't do the + // transparent region optimization. + transparentRegion.clear(); + } + } + + // compute the opaque region + const int32_t layerOrientation = tr.getOrientation(); + if (layerFEState.isOpaque && ((layerOrientation & ui::Transform::ROT_INVALID) == 0)) { + // If we one of the simple category of transforms (0/90/180/270 rotation + // + any flip), then the opaque region is the layer's footprint. + // Otherwise we don't try and compute the opaque region since there may + // be errors at the edges, and we treat the entire layer as + // translucent. + opaqueRegion = visibleRegion; + } + + // Clip the covered region to the visible region + coveredRegion = coverage.aboveCoveredLayers.intersect(visibleRegion); + + // Update accumAboveCoveredLayers for next (lower) layer + coverage.aboveCoveredLayers.orSelf(visibleRegion); + + // subtract the opaque region covered by the layers above us + visibleRegion.subtractSelf(coverage.aboveOpaqueLayers); + + if (visibleRegion.isEmpty()) { + return nullptr; + } + + // Get coverage information for the layer as previously displayed, + // also taking over ownership from mOutputLayersorderedByZ. + auto prevOutputLayer = takeOutputLayerForLayer(layer.get()); + + // Get coverage information for the layer as previously displayed + // TODO(b/121291683): Define kEmptyRegion as a constant in Region.h + const Region kEmptyRegion; + const Region& oldVisibleRegion = + prevOutputLayer ? prevOutputLayer->getState().visibleRegion : kEmptyRegion; + const Region& oldCoveredRegion = + prevOutputLayer ? prevOutputLayer->getState().coveredRegion : kEmptyRegion; + + // compute this layer's dirty region + Region dirty; + if (layerFEState.contentDirty) { + // we need to invalidate the whole region + dirty = visibleRegion; + // as well, as the old visible region + dirty.orSelf(oldVisibleRegion); + } else { + /* compute the exposed region: + * the exposed region consists of two components: + * 1) what's VISIBLE now and was COVERED before + * 2) what's EXPOSED now less what was EXPOSED before + * + * note that (1) is conservative, we start with the whole visible region + * but only keep what used to be covered by something -- which mean it + * may have been exposed. + * + * (2) handles areas that were not covered by anything but got exposed + * because of a resize. + * + */ + const Region newExposed = visibleRegion - coveredRegion; + const Region oldExposed = oldVisibleRegion - oldCoveredRegion; + dirty = (visibleRegion & oldCoveredRegion) | (newExposed - oldExposed); + } + dirty.subtractSelf(coverage.aboveOpaqueLayers); + + // accumulate to the screen dirty region + coverage.dirtyRegion.orSelf(dirty); + + // Update accumAboveOpaqueLayers for next (lower) layer + coverage.aboveOpaqueLayers.orSelf(opaqueRegion); + + // Compute the visible non-transparent region + Region visibleNonTransparentRegion = visibleRegion.subtract(transparentRegion); + + // Peform the final check to see if this layer is visible on this output + // TODO(b/121291683): Why does this not use visibleRegion? (see outputSpaceVisibleRegion below) + Region drawRegion(mState.transform.transform(visibleNonTransparentRegion)); + drawRegion.andSelf(mState.bounds); + if (drawRegion.isEmpty()) { + return nullptr; + } + + // The layer is visible. Either reuse the existing outputLayer if we have + // one, or create a new one if we do not. + std::unique_ptr result = + prevOutputLayer ? std::move(prevOutputLayer) : createOutputLayer(layer, layerFE); + + // Store the layer coverage information into the layer state as some of it + // is useful later. + auto& outputLayerState = result->editState(); + outputLayerState.visibleRegion = visibleRegion; + outputLayerState.visibleNonTransparentRegion = visibleNonTransparentRegion; + outputLayerState.coveredRegion = coveredRegion; + outputLayerState.outputSpaceVisibleRegion = + mState.transform.transform(outputLayerState.visibleRegion.intersect(mState.viewport)); + + return result; +} + +void Output::setReleasedLayers(const compositionengine::CompositionRefreshArgs&) { + // The base class does nothing with this call. +} + void Output::updateLayerStateFromFE(const CompositionRefreshArgs& args) const { for (auto& layer : mOutputLayersOrderedByZ) { layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd, diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 6821ec1301..74b3adaa95 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -276,6 +276,79 @@ TEST_F(DisplayTest, createOutputLayerSetsHwcLayer) { outputLayer.reset(); } +/* + * Display::setReleasedLayers() + */ + +TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNotHwcDisplay) { + std::shared_ptr nonHwcDisplay{ + impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; + + sp layerXLayerFE = new StrictMock(); + mock::Layer layerXLayer; + + { + Output::ReleasedLayers releasedLayers; + releasedLayers.emplace_back(layerXLayerFE); + nonHwcDisplay->setReleasedLayers(std::move(releasedLayers)); + } + + CompositionRefreshArgs refreshArgs; + refreshArgs.layersWithQueuedFrames.push_back(&layerXLayer); + + nonHwcDisplay->setReleasedLayers(refreshArgs); + + const auto& releasedLayers = nonHwcDisplay->getReleasedLayersForTest(); + ASSERT_EQ(1, releasedLayers.size()); +} + +TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNoLayersWithQueuedFrames) { + sp layerXLayerFE = new StrictMock(); + + { + Output::ReleasedLayers releasedLayers; + releasedLayers.emplace_back(layerXLayerFE); + mDisplay.setReleasedLayers(std::move(releasedLayers)); + } + + CompositionRefreshArgs refreshArgs; + mDisplay.setReleasedLayers(refreshArgs); + + const auto& releasedLayers = mDisplay.getReleasedLayersForTest(); + ASSERT_EQ(1, releasedLayers.size()); +} + +TEST_F(DisplayTest, setReleasedLayers) { + sp layer1LayerFE = new StrictMock(); + sp layer2LayerFE = new StrictMock(); + sp layer3LayerFE = new StrictMock(); + sp layerXLayerFE = new StrictMock(); + 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())); + + CompositionRefreshArgs refreshArgs; + refreshArgs.layersWithQueuedFrames.push_back(&layer1Layer); + refreshArgs.layersWithQueuedFrames.push_back(&layer2Layer); + refreshArgs.layersWithQueuedFrames.push_back(&layerXLayer); + refreshArgs.layersWithQueuedFrames.push_back(nullptr); + + 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()); +} + /* * Display::chooseCompositionStrategy() */ diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 344c5e7d9f..f1508c7b49 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1784,6 +1784,7 @@ void SurfaceFlinger::handleMessageRefresh() { mRefreshPending = false; compositionengine::CompositionRefreshArgs refreshArgs; + refreshArgs.outputs.reserve(mDisplays.size()); for (const auto& [_, display] : mDisplays) { refreshArgs.outputs.push_back(display->getCompositionDisplay()); } @@ -1791,13 +1792,21 @@ void SurfaceFlinger::handleMessageRefresh() { auto compositionLayer = layer->getCompositionLayer(); if (compositionLayer) refreshArgs.layers.push_back(compositionLayer); }); + refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size()); + for (sp layer : mLayersWithQueuedFrames) { + auto compositionLayer = layer->getCompositionLayer(); + if (compositionLayer) refreshArgs.layersWithQueuedFrames.push_back(compositionLayer.get()); + } + refreshArgs.repaintEverything = mRepaintEverything.exchange(false); refreshArgs.outputColorSetting = useColorManagement ? mDisplayColorSetting : compositionengine::OutputColorSetting::kUnmanaged; refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace; refreshArgs.forceOutputColorMode = mForceColorMode; - refreshArgs.updatingGeometryThisFrame = mGeometryInvalid; + + refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty; + refreshArgs.updatingGeometryThisFrame = mGeometryInvalid || mVisibleRegionsDirty; if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) { refreshArgs.colorTransformMatrix = mDrawingState.colorMatrix; @@ -1811,13 +1820,10 @@ void SurfaceFlinger::handleMessageRefresh() { std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0); } - mCompositionEngine->preComposition(refreshArgs); - rebuildLayerStacks(); - refreshArgs.updatingGeometryThisFrame = mGeometryInvalid; // Can be set by rebuildLayerStacks() - mCompositionEngine->present(refreshArgs); - mGeometryInvalid = false; + mCompositionEngine->present(refreshArgs); + postFrame(); postComposition(); @@ -2079,77 +2085,6 @@ void SurfaceFlinger::computeLayerBounds() { } } -void SurfaceFlinger::rebuildLayerStacks() { - ATRACE_CALL(); - ALOGV("rebuildLayerStacks"); - - // rebuild the visible layer list per screen - if (CC_UNLIKELY(mVisibleRegionsDirty)) { - ATRACE_NAME("rebuildLayerStacks VR Dirty"); - invalidateHwcGeometry(); - - std::vector> layersWithQueuedFrames; - layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size()); - for (sp layer : mLayersWithQueuedFrames) { - layersWithQueuedFrames.push_back(layer); - } - - for (const auto& pair : mDisplays) { - const auto& displayDevice = pair.second; - auto display = displayDevice->getCompositionDisplay(); - const auto& displayState = display->getState(); - Region opaqueRegion; - Region dirtyRegion; - compositionengine::Output::OutputLayers layersSortedByZ; - const ui::Transform& tr = displayState.transform; - const Rect bounds = displayState.bounds; - if (!displayState.isEnabled) { - continue; - } - - computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion, layersSortedByZ); - - // computeVisibleRegions walks the layers in reverse-Z order. Reverse - // to get a back-to-front ordering. - std::reverse(layersSortedByZ.begin(), layersSortedByZ.end()); - - display->setOutputLayersOrderedByZ(std::move(layersSortedByZ)); - - compositionengine::Output::ReleasedLayers releasedLayers; - if (displayDevice->getId() && !layersWithQueuedFrames.empty()) { - // For layers that are being removed from a HWC display, - // and that have queued frames, add them to a a list of - // released layers so we can properly set a fence. - - // Any non-null entries in the current list of layers are layers - // that are no longer going to be visible - for (auto& layer : display->getOutputLayersOrderedByZ()) { - if (!layer) { - continue; - } - - sp layerFE(&layer->getLayerFE()); - const bool hasQueuedFrames = - std::find(layersWithQueuedFrames.cbegin(), - layersWithQueuedFrames.cend(), - layerFE) != layersWithQueuedFrames.cend(); - - if (hasQueuedFrames) { - releasedLayers.emplace_back(layerFE); - } - } - } - display->setReleasedLayers(std::move(releasedLayers)); - - Region undefinedRegion{bounds}; - undefinedRegion.subtractSelf(tr.transform(opaqueRegion)); - - display->editState().undefinedRegion = undefinedRegion; - display->editState().dirtyRegion.orSelf(dirtyRegion); - } - } -} - void SurfaceFlinger::postFrame() { // |mStateLock| not needed as we are on the main thread @@ -2506,7 +2441,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // display is used to calculate the hint, otherwise we use the // default display. // - // NOTE: we do this here, rather than in rebuildLayerStacks() so that + // NOTE: we do this here, rather than when presenting the display so that // the hint is set before we acquire a buffer from the surface texture. // // NOTE: layer transactions have taken place already, so we use their @@ -2737,181 +2672,6 @@ void SurfaceFlinger::commitOffscreenLayers() { } } -void SurfaceFlinger::computeVisibleRegions( - const sp& displayDevice, Region& outDirtyRegion, - Region& outOpaqueRegion, - std::vector>& outLayersSortedByZ) { - ATRACE_CALL(); - ALOGV("computeVisibleRegions"); - - auto display = displayDevice->getCompositionDisplay(); - - Region aboveOpaqueLayers; - Region aboveCoveredLayers; - Region dirty; - - outDirtyRegion.clear(); - - mDrawingState.traverseInReverseZOrder([&](Layer* layer) { - auto compositionLayer = layer->getCompositionLayer(); - if (compositionLayer == nullptr) { - return; - } - - // Note: Converts a wp to a sp - auto layerFE = compositionLayer->getLayerFE(); - if (layerFE == nullptr) { - return; - } - - // Request a snapshot of the subset of state relevant to visibility - // determination - layerFE->latchCompositionState(compositionLayer->editState().frontEnd, - compositionengine::LayerFE::StateSubset::BasicGeometry); - - // Work with a read-only copy of the snapshot - const auto& layerFEState = compositionLayer->getState().frontEnd; - - // only consider the layers on the given layer stack - if (!display->belongsInOutput(compositionLayer.get())) { - return; - } - - /* - * opaqueRegion: area of a surface that is fully opaque. - */ - Region opaqueRegion; - - /* - * visibleRegion: area of a surface that is visible on screen - * and not fully transparent. This is essentially the layer's - * footprint minus the opaque regions above it. - * Areas covered by a translucent surface are considered visible. - */ - Region visibleRegion; - - /* - * coveredRegion: area of a surface that is covered by all - * visible regions above it (which includes the translucent areas). - */ - Region coveredRegion; - - /* - * transparentRegion: area of a surface that is hinted to be completely - * transparent. This is only used to tell when the layer has no visible - * non-transparent regions and can be removed from the layer list. It - * does not affect the visibleRegion of this layer or any layers - * beneath it. The hint may not be correct if apps don't respect the - * SurfaceView restrictions (which, sadly, some don't). - */ - Region transparentRegion; - - // handle hidden surfaces by setting the visible region to empty - if (CC_LIKELY(layerFEState.isVisible)) { - // Get the visible region - visibleRegion.set( - Rect(layerFEState.geomLayerTransform.transform(layerFEState.geomLayerBounds))); - const ui::Transform& tr = layerFEState.geomLayerTransform; - if (!visibleRegion.isEmpty()) { - // Remove the transparent area from the visible region - if (!layerFEState.isOpaque) { - if (tr.preserveRects()) { - // transform the transparent region - transparentRegion = tr.transform(layerFEState.transparentRegionHint); - } else { - // transformation too complex, can't do the - // transparent region optimization. - transparentRegion.clear(); - } - } - - // compute the opaque region - const int32_t layerOrientation = tr.getOrientation(); - if (layerFEState.isOpaque && - ((layerOrientation & ui::Transform::ROT_INVALID) == false)) { - // the opaque region is the layer's footprint - opaqueRegion = visibleRegion; - } - } - } - - if (visibleRegion.isEmpty()) { - return; - } - - // Clip the covered region to the visible region - coveredRegion = aboveCoveredLayers.intersect(visibleRegion); - - // Update aboveCoveredLayers for next (lower) layer - aboveCoveredLayers.orSelf(visibleRegion); - - // subtract the opaque region covered by the layers above us - visibleRegion.subtractSelf(aboveOpaqueLayers); - - // Get coverage information for the layer as previously displayed - auto prevOutputLayer = display->getOutputLayerForLayer(compositionLayer.get()); - // TODO(b/121291683): Define this as a constant in Region.h - const Region kEmptyRegion; - const Region& oldVisibleRegion = - prevOutputLayer ? prevOutputLayer->getState().visibleRegion : kEmptyRegion; - const Region& oldCoveredRegion = - prevOutputLayer ? prevOutputLayer->getState().coveredRegion : kEmptyRegion; - - // compute this layer's dirty region - if (layerFEState.contentDirty) { - // we need to invalidate the whole region - dirty = visibleRegion; - // as well, as the old visible region - dirty.orSelf(oldVisibleRegion); - } else { - /* compute the exposed region: - * the exposed region consists of two components: - * 1) what's VISIBLE now and was COVERED before - * 2) what's EXPOSED now less what was EXPOSED before - * - * note that (1) is conservative, we start with the whole - * visible region but only keep what used to be covered by - * something -- which mean it may have been exposed. - * - * (2) handles areas that were not covered by anything but got - * exposed because of a resize. - */ - const Region newExposed = visibleRegion - coveredRegion; - const Region oldExposed = oldVisibleRegion - oldCoveredRegion; - dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed); - } - dirty.subtractSelf(aboveOpaqueLayers); - - // accumulate to the screen dirty region - outDirtyRegion.orSelf(dirty); - - // Update aboveOpaqueLayers for next (lower) layer - aboveOpaqueLayers.orSelf(opaqueRegion); - - // Compute the visible non-transparent region - Region visibleNonTransparentRegion = visibleRegion.subtract(transparentRegion); - - // Setup an output layer for this output if the layer is visible on this - // output - const auto& displayState = display->getState(); - Region drawRegion(displayState.transform.transform(visibleNonTransparentRegion)); - drawRegion.andSelf(displayState.bounds); - if (drawRegion.isEmpty()) { - return; - } - - outLayersSortedByZ.emplace_back(display->getOrCreateOutputLayer(compositionLayer, layerFE)); - auto& outputLayerState = outLayersSortedByZ.back()->editState(); - outputLayerState.visibleRegion = std::move(visibleRegion); - outputLayerState.visibleNonTransparentRegion = std::move(visibleNonTransparentRegion); - outputLayerState.coveredRegion = std::move(coveredRegion); - outputLayerState.outputSpaceVisibleRegion = displayState.transform.transform( - outputLayerState.visibleRegion.intersect(displayState.viewport)); - }); - - outOpaqueRegion = aboveOpaqueLayers; -} - void SurfaceFlinger::invalidateLayerStack(const sp& layer, const Region& dirty) { for (const auto& [token, displayDevice] : mDisplays) { auto display = displayDevice->getCompositionDisplay(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index beb43d0d9d..17cd8213c2 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -745,9 +745,6 @@ private: * Compositing */ void invalidateHwcGeometry(); - void computeVisibleRegions( - const sp& display, Region& dirtyRegion, Region& opaqueRegion, - std::vector>& outputLayers); void postComposition(); void getCompositorTiming(CompositorTiming* compositorTiming); @@ -755,7 +752,6 @@ private: std::shared_ptr& presentFenceTime); void setCompositorTimingSnapped(const DisplayStatInfo& stats, nsecs_t compositeToPresentLatency); - void rebuildLayerStacks(); void postFrame(); -- GitLab From d6f1fc25ee57327a262064a87bb4a4396ba12860 Mon Sep 17 00:00:00 2001 From: Huihong Luo Date: Tue, 10 Sep 2019 14:29:20 -0700 Subject: [PATCH 0267/1255] Add layerStack field to DisplayInfo screenrecord utility requires display layer stack in order to record external displays. Bug: 140814450 Bug: 136165419 Test: screenrecord --display-id Change-Id: I1ec562e4df2db684eb9f216bd4439bb267a7d3e3 --- libs/ui/include/ui/DisplayInfo.h | 5 ++++- services/surfaceflinger/DisplayDevice.h | 7 ++----- services/surfaceflinger/SurfaceFlinger.cpp | 4 ++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h index 8976d2d584..07722104de 100644 --- a/libs/ui/include/ui/DisplayInfo.h +++ b/libs/ui/include/ui/DisplayInfo.h @@ -24,6 +24,8 @@ namespace android { +constexpr uint32_t NO_LAYER_STACK = static_cast(-1); + struct DisplayInfo { uint32_t w{0}; uint32_t h{0}; @@ -37,6 +39,7 @@ struct DisplayInfo { nsecs_t presentationDeadline{0}; uint32_t viewportW{0}; uint32_t viewportH{0}; + uint32_t layerStack{NO_LAYER_STACK}; }; /* Display orientations as defined in Surface.java and ISurfaceComposer.h. */ @@ -47,6 +50,6 @@ enum { DISPLAY_ORIENTATION_270 = 3 }; -}; // namespace android +} // namespace android #endif // ANDROID_COMPOSER_DISPLAY_INFO_H diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 52773204b9..ce4e1e6b09 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -65,10 +66,6 @@ public: constexpr static float sDefaultMinLumiance = 0.0; constexpr static float sDefaultMaxLumiance = 500.0; - enum { - NO_LAYER_STACK = 0xFFFFFFFF, - }; - explicit DisplayDevice(DisplayDeviceCreationArgs&& args); virtual ~DisplayDevice(); @@ -201,7 +198,7 @@ struct DisplayDeviceState { int32_t sequenceId = sNextSequenceId++; std::optional displayId; sp surface; - uint32_t layerStack = DisplayDevice::NO_LAYER_STACK; + uint32_t layerStack = NO_LAYER_STACK; Rect viewport; Rect frame; uint8_t orientation = 0; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4361a94e64..cc34f50a58 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -874,11 +874,15 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, 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; info.orientation = 0; + + const auto display = getDisplayDeviceLocked(displayToken); + info.layerStack = display->getLayerStack(); } info.xdpi = xdpi; -- GitLab From 9da14733afb5da5cb362f3c865d85d303cc62b15 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Mon, 2 Sep 2019 16:16:58 +0800 Subject: [PATCH 0268/1255] Fix touch can't work after enabled the associated viewport If a device has associated port but there is no viewport found, it would be expeced to be disabled. But for some devices, such as touch screen or joystick, they have to read the axis ranges info in InputMapper at first time configuration changed. So we have to defer disabling the device after info has been read when the device plugged. Bug: 140205788 Test: atest inputflinger_tests Change-Id: I9dd55e0016b6a020aab211dada45880195aec8dd --- services/inputflinger/InputReader.cpp | 13 +++++++- .../inputflinger/tests/InputReader_test.cpp | 33 ++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index 1cbf78eb43..d59f274ab0 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -1141,13 +1141,24 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config } } - setEnabled(enabled, when); + if (changes) { + // For first-time configuration, only allow device to be disabled after mappers have + // finished configuring. This is because we need to read some of the properties from + // the device's open fd. + setEnabled(enabled, when); + } } for (InputMapper* mapper : mMappers) { mapper->configure(when, config, changes); mSources |= mapper->getSources(); } + + // If a device is just plugged but it might be disabled, we need to update some info like + // axis range of touch from each InputMapper first, then disable it. + if (!changes) { + setEnabled(config->disabledDevices.find(mId) == config->disabledDevices.end(), when); + } } } diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 348a12bf3a..09df2a70c7 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -527,7 +527,7 @@ private: virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const { Device* device = getDevice(deviceId); - if (device) { + if (device && device->enabled) { ssize_t index = device->absoluteAxes.indexOfKey(axis); if (index >= 0) { *outAxisInfo = device->absoluteAxes.valueAt(index); @@ -6554,4 +6554,35 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreRotated) { ASSERT_EQ(frames, motionArgs.videoFrames); } +/** + * If we had defined port associations, but the viewport is not ready, the touch device would be + * expected to be disabled, and it should be enabled after the viewport has found. + */ +TEST_F(MultiTouchInputMapperTest, Configure_EnabledForAssociatedDisplay) { + MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); + constexpr uint8_t hdmi2 = 1; + const std::string secondaryUniqueId = "uniqueId2"; + constexpr ViewportType type = ViewportType::VIEWPORT_EXTERNAL; + + mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi2); + + addConfigurationProperty("touch.deviceType", "touchScreen"); + prepareAxes(POSITION); + addMapperAndConfigure(mapper); + + ASSERT_EQ(mDevice->isEnabled(), false); + + // Add display on hdmi2, the device should be enabled and can receive touch event. + prepareSecondaryDisplay(type, hdmi2); + ASSERT_EQ(mDevice->isEnabled(), true); + + // Send a touch event. + processPosition(mapper, 100, 100); + processSync(mapper); + + NotifyMotionArgs args; + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(SECONDARY_DISPLAY_ID, args.displayId); +} + } // namespace android -- GitLab From 0802618f60366e69bbbf4277d83e9c6f6aa473d6 Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Thu, 12 Sep 2019 15:01:28 +0100 Subject: [PATCH 0269/1255] Replace libnativeloader-dummy-headers with libnativeloader-headers The libnativeloader-dummy-headers target has been deprecated in favour of the more appropriately named by otherwise identical libnativeloader-headers Test: m checkbuild Change-Id: I0d4018734f91a7da68d4c730f3c5bfb65c163ab8 --- libs/graphicsenv/Android.bp | 2 +- vulkan/libvulkan/Android.bp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp index f11cf62e50..642c5f2cc0 100644 --- a/libs/graphicsenv/Android.bp +++ b/libs/graphicsenv/Android.bp @@ -33,7 +33,7 @@ cc_library_shared { ], header_libs: [ - "libnativeloader-dummy-headers", + "libnativeloader-headers", ], export_include_dirs: ["include"], diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp index 651c94d896..83a52506fc 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -75,7 +75,7 @@ cc_library_shared { header_libs: [ "hwvulkan_headers", - "libnativeloader-dummy-headers", + "libnativeloader-headers", "vulkan_headers", ], export_header_lib_headers: ["vulkan_headers"], -- GitLab From 82353e993cd4889a231a0b2d243dccc98e323395 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 12 Sep 2019 12:38:47 -0700 Subject: [PATCH 0270/1255] Changed BufferLayer's canReceiveInput to check if its hidden by policy WM does not consider window size or alpha value when setting it as the focused window. However, SF will check if the window has a buffer and that its alpha is not 0. Because of this difference, Input Dispatcher will not be able to send input to the window while WM thinks the window is focused. This will cause apps to stop responding. While we define what the intended behavior should be, this fix reverts to previous behavior in P. Bug: 139494112 Test: adb shell monkey 10000; make sure monkey does not get stuck Test: check test app from can receive input b/140478820 Change-Id: I4160b49161dd1780713980707a5c911034f414b5 --- libs/gui/tests/EndToEndNativeInputTest.cpp | 4 ++++ services/surfaceflinger/ContainerLayer.cpp | 4 ---- services/surfaceflinger/ContainerLayer.h | 2 -- services/surfaceflinger/Layer.cpp | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 386f731d23..2ab34da5ec 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -435,6 +435,9 @@ TEST_F(InputSurfacesTest, input_ignores_transparent_region) { surface->expectTap(1, 1); } +/** + * TODO(b/139494112) fix tests once we define expected behavior + * // Ensure we send the input to the right surface when the surface visibility changes due to the // first buffer being submitted. ref: b/120839715 TEST_F(InputSurfacesTest, input_respects_buffer_layer_buffer) { @@ -486,6 +489,7 @@ TEST_F(InputSurfacesTest, input_respects_color_layer_alpha) { injectTap(11, 11); bgSurface->expectTap(1, 1); } +*/ TEST_F(InputSurfacesTest, input_respects_container_layer_visiblity) { std::unique_ptr bgSurface = makeSurface(100, 100); diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp index d40a38c811..4a1130365a 100644 --- a/services/surfaceflinger/ContainerLayer.cpp +++ b/services/surfaceflinger/ContainerLayer.cpp @@ -30,8 +30,4 @@ bool ContainerLayer::isVisible() const { return false; } -bool ContainerLayer::canReceiveInput() const { - return !isHiddenByPolicy(); -} - } // namespace android diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h index f0fbb6104f..c3624f6d7d 100644 --- a/services/surfaceflinger/ContainerLayer.h +++ b/services/surfaceflinger/ContainerLayer.h @@ -31,8 +31,6 @@ public: const char* getType() const override { return "ContainerLayer"; } bool isVisible() const override; - bool canReceiveInput() const override; - bool isCreatedFromMainThread() const override { return true; } }; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 79ee827f0d..d117c1bb70 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2020,7 +2020,7 @@ std::shared_ptr Layer::getCompositionLayer() const { } bool Layer::canReceiveInput() const { - return isVisible(); + return !isHiddenByPolicy(); } compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( -- GitLab From 2bbaabe1b67b501121b72a789c52f385a1df1f90 Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Wed, 28 Aug 2019 16:08:35 -0700 Subject: [PATCH 0271/1255] Add a flag for refresh rate switching Some devices don't do refresh rate switching, so we should take that into account when filtering display manager config settings and deciding scheduling behavior. This CL adds a sysprop that can be set to indicate if surface flinger should do refresh rate switching, and modifies surface flinger to have the correct behavior when we're not doing refresh rate switching. Bug: 136592946 Bug: 138261472 Test: Ran through various 60/90 switching scenarios on a device with refresh rate switching. Test: Set the refresh rate switching sysprop to false, and confirmed we get a consistent 60Hz. Test: Inspected dumpsys output and confirmed it looks correct. In particular, refresh rate stats are output correctly. Test: Ran automated tests: RefreshRateConfigsTest, RefreshRateStatsTest, SchedulerTest. Change-Id: I54cd5be9d2c1b9abc8475c3ce39846cbe9f9fe53 --- .../surfaceflinger/Scheduler/PhaseOffsets.cpp | 1 - .../Scheduler/RefreshRateConfigs.h | 184 ++++++++++----- .../Scheduler/RefreshRateStats.h | 71 +++--- .../surfaceflinger/Scheduler/Scheduler.cpp | 103 ++++----- services/surfaceflinger/Scheduler/Scheduler.h | 29 +-- .../surfaceflinger/Scheduler/SchedulerUtils.h | 6 - services/surfaceflinger/SurfaceFlinger.cpp | 216 +++++++++--------- services/surfaceflinger/SurfaceFlinger.h | 8 +- .../SurfaceFlingerProperties.cpp | 8 + .../surfaceflinger/SurfaceFlingerProperties.h | 2 + .../sysprop/SurfaceFlingerProperties.sysprop | 17 +- .../api/SurfaceFlingerProperties-current.txt | 4 + .../unittests/RefreshRateConfigsTest.cpp | 112 ++------- .../tests/unittests/RefreshRateStatsTest.cpp | 139 +++++------ .../tests/unittests/SchedulerTest.cpp | 55 +++-- .../tests/unittests/TestableScheduler.h | 2 +- .../tests/unittests/TestableSurfaceFlinger.h | 13 +- 17 files changed, 459 insertions(+), 511 deletions(-) diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 04e902bda8..6be88f89f9 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -51,7 +51,6 @@ PhaseOffsets::PhaseOffsets() { const Offsets defaultOffsets = getDefaultOffsets(thresholdForNextVsync); const Offsets highFpsOffsets = getHighFpsOffsets(thresholdForNextVsync); - mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets}); mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets}); mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets}); } diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 9d4774962a..2fd100f876 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -41,10 +41,9 @@ inline RefreshRateConfigEvent operator|(RefreshRateConfigEvent lhs, RefreshRateC */ class RefreshRateConfigs { public: - // Enum to indicate which vsync rate to run at. Power saving is intended to be the lowest - // (eg. when the screen is in AOD mode or off), default is the old 60Hz, and performance + // Enum to indicate which vsync rate to run at. Default is the old 60Hz, and performance // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs. - enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE }; + enum class RefreshRateType { DEFAULT, PERFORMANCE }; struct RefreshRate { // This config ID corresponds to the position of the config in the vector that is stored @@ -54,26 +53,57 @@ public: std::string name; // Refresh rate in frames per second, rounded to the nearest integer. uint32_t fps = 0; - // config Id (returned from HWC2::Display::Config::getId()) - hwc2_config_t id; + // Vsync period in nanoseconds. + nsecs_t vsyncPeriod; + // Hwc config Id (returned from HWC2::Display::Config::getId()) + hwc2_config_t hwcId; }; + // Returns true if this device is doing refresh rate switching. This won't change at runtime. + bool refreshRateSwitchingSupported() const { return mRefreshRateSwitchingSupported; } + + // Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access + // from multiple threads. This can only be called if refreshRateSwitching() returns true. // TODO(b/122916473): Get this information from configs prepared by vendors, instead of // baking them in. - const std::map>& getRefreshRates() const { - return mRefreshRates; + const std::map& getRefreshRateMap() const { + LOG_ALWAYS_FATAL_IF(!mRefreshRateSwitchingSupported); + return mRefreshRateMap; } - std::shared_ptr getRefreshRate(RefreshRateType type) const { - const auto& refreshRate = mRefreshRates.find(type); - if (refreshRate != mRefreshRates.end()) { + + const RefreshRate& getRefreshRateFromType(RefreshRateType type) const { + if (!mRefreshRateSwitchingSupported) { + return getCurrentRefreshRate().second; + } else { + auto refreshRate = mRefreshRateMap.find(type); + LOG_ALWAYS_FATAL_IF(refreshRate == mRefreshRateMap.end()); return refreshRate->second; } - return nullptr; } - RefreshRateType getRefreshRateType(hwc2_config_t id) const { - for (const auto& [type, refreshRate] : mRefreshRates) { - if (refreshRate->id == id) { + std::pair getCurrentRefreshRate() const { + int currentConfig = mCurrentConfig; + if (mRefreshRateSwitchingSupported) { + for (const auto& [type, refresh] : mRefreshRateMap) { + if (refresh.configId == currentConfig) { + return {type, refresh}; + } + } + LOG_ALWAYS_FATAL(); + } + return {RefreshRateType::DEFAULT, mRefreshRates[currentConfig]}; + } + + const RefreshRate& getRefreshRateFromConfigId(int configId) const { + LOG_ALWAYS_FATAL_IF(configId >= mRefreshRates.size()); + return mRefreshRates[configId]; + } + + RefreshRateType getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const { + if (!mRefreshRateSwitchingSupported) return RefreshRateType::DEFAULT; + + for (const auto& [type, refreshRate] : mRefreshRateMap) { + if (refreshRate.hwcId == hwcId) { return type; } } @@ -81,64 +111,102 @@ public: return RefreshRateType::DEFAULT; } - void populate(const std::vector>& configs) { - mRefreshRates.clear(); + void setCurrentConfig(int config) { + LOG_ALWAYS_FATAL_IF(config >= mRefreshRates.size()); + mCurrentConfig = config; + } - // This is the rate that HWC encapsulates right now when the device is in DOZE mode. - mRefreshRates.emplace(RefreshRateType::POWER_SAVING, - std::make_shared( - RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, - HWC2_SCREEN_OFF_CONFIG_ID})); + struct InputConfig { + hwc2_config_t hwcId = 0; + nsecs_t vsyncPeriod = 0; + }; - if (configs.size() < 1) { - ALOGE("Device does not have valid configs. Config size is 0."); - return; + RefreshRateConfigs(bool refreshRateSwitching, const std::vector& configs, + int currentConfig) { + init(refreshRateSwitching, configs, currentConfig); + } + + RefreshRateConfigs(bool refreshRateSwitching, + const std::vector>& configs, + int currentConfig) { + std::vector inputConfigs; + for (const auto& config : configs) { + inputConfigs.push_back({config->getId(), config->getVsyncPeriod()}); } + init(refreshRateSwitching, inputConfigs, currentConfig); + } + +private: + void init(bool refreshRateSwitching, const std::vector& configs, + int currentConfig) { + mRefreshRateSwitchingSupported = refreshRateSwitching; + LOG_ALWAYS_FATAL_IF(configs.empty()); + LOG_ALWAYS_FATAL_IF(currentConfig >= configs.size()); + mCurrentConfig = currentConfig; + + auto buildRefreshRate = [&](int configId) -> RefreshRate { + const nsecs_t vsyncPeriod = configs[configId].vsyncPeriod; + const float fps = 1e9 / vsyncPeriod; + return {configId, base::StringPrintf("%2.ffps", fps), static_cast(fps), + vsyncPeriod, configs[configId].hwcId}; + }; - // Create a map between config index and vsync period. This is all the info we need - // from the configs. - std::vector> configIdToVsyncPeriod; for (int i = 0; i < configs.size(); ++i) { - configIdToVsyncPeriod.emplace_back(i, configs.at(i)->getVsyncPeriod()); + mRefreshRates.push_back(buildRefreshRate(i)); } - std::sort(configIdToVsyncPeriod.begin(), configIdToVsyncPeriod.end(), - [](const std::pair& a, const std::pair& b) { - return a.second > b.second; - }); + if (!mRefreshRateSwitchingSupported) return; - // When the configs are ordered by the resync rate. We assume that the first one is DEFAULT. - nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second; - if (vsyncPeriod != 0) { - const float fps = 1e9 / vsyncPeriod; - const int configId = configIdToVsyncPeriod[0].first; - mRefreshRates.emplace(RefreshRateType::DEFAULT, - std::make_shared( - RefreshRate{configId, base::StringPrintf("%2.ffps", fps), - static_cast(fps), - configs.at(configId)->getId()})); - } + auto findDefaultAndPerfConfigs = [&]() -> std::optional> { + if (configs.size() < 2) { + return {}; + } - if (configs.size() < 2) { + std::vector sortedRefreshRates; + for (const auto& refreshRate : mRefreshRates) { + sortedRefreshRates.push_back(&refreshRate); + } + std::sort(sortedRefreshRates.begin(), sortedRefreshRates.end(), + [](const RefreshRate* refreshRate1, const RefreshRate* refreshRate2) { + return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod; + }); + + // When the configs are ordered by the resync rate, we assume that + // the first one is DEFAULT and the second one is PERFORMANCE, + // i.e. the higher rate. + if (sortedRefreshRates[0]->vsyncPeriod == 0 || + sortedRefreshRates[1]->vsyncPeriod == 0) { + return {}; + } + + return std::pair(sortedRefreshRates[0]->configId, + sortedRefreshRates[1]->configId); + }; + + auto defaultAndPerfConfigs = findDefaultAndPerfConfigs(); + if (!defaultAndPerfConfigs) { + mRefreshRateSwitchingSupported = false; return; } - // When the configs are ordered by the resync rate. We assume that the second one is - // PERFORMANCE, eg. the higher rate. - vsyncPeriod = configIdToVsyncPeriod[1].second; - if (vsyncPeriod != 0) { - const float fps = 1e9 / vsyncPeriod; - const int configId = configIdToVsyncPeriod[1].first; - mRefreshRates.emplace(RefreshRateType::PERFORMANCE, - std::make_shared( - RefreshRate{configId, base::StringPrintf("%2.ffps", fps), - static_cast(fps), - configs.at(configId)->getId()})); - } + mRefreshRateMap[RefreshRateType::DEFAULT] = mRefreshRates[defaultAndPerfConfigs->first]; + mRefreshRateMap[RefreshRateType::PERFORMANCE] = + mRefreshRates[defaultAndPerfConfigs->second]; } -private: - std::map> mRefreshRates; + // Whether this device is doing refresh rate switching or not. This must not change after this + // object is initialized. + bool mRefreshRateSwitchingSupported; + // The list of refresh rates, indexed by display config ID. This must not change after this + // object is initialized. + std::vector mRefreshRates; + // The mapping of refresh rate type to RefreshRate. This must not change after this object is + // initialized. + std::map mRefreshRateMap; + // The ID of the current config. This will change at runtime. This is set by SurfaceFlinger on + // the main thread, and read by the Scheduler (and other objects) on other threads, so it's + // atomic. + std::atomic mCurrentConfig; }; } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h index 1f097db08d..8afc93e8db 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateStats.h +++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h @@ -41,21 +41,18 @@ class RefreshRateStats { static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR; public: - RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats) - : mRefreshRateConfigs(refreshRateConfigs), mTimeStats(timeStats) {} - - // Sets power mode. We only collect the information when the power mode is not - // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based - // on config mode. + RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats, + int currentConfigMode, int currentPowerMode) + : mRefreshRateConfigs(refreshRateConfigs), + mTimeStats(timeStats), + mCurrentConfigMode(currentConfigMode), + mCurrentPowerMode(currentPowerMode) {} + + // Sets power mode. void setPowerMode(int mode) { if (mCurrentPowerMode == mode) { return; } - // If power mode is normal, the time is going to be recorded under config modes. - if (mode == HWC_POWER_MODE_NORMAL) { - mCurrentPowerMode = mode; - return; - } flushTime(); mCurrentPowerMode = mode; } @@ -79,16 +76,15 @@ public: flushTime(); std::unordered_map totalTime; - for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) { - int64_t totalTimeForConfig = 0; - if (!config) { - continue; - } - if (mConfigModesTotalTime.find(config->configId) != mConfigModesTotalTime.end()) { - totalTimeForConfig = mConfigModesTotalTime.at(config->configId); - } - totalTime[config->name] = totalTimeForConfig; + // Multiple configs may map to the same name, e.g. "60fps". Add the + // times for such configs together. + for (const auto& [config, time] : mConfigModesTotalTime) { + totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] = 0; + } + for (const auto& [config, time] : mConfigModesTotalTime) { + totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] += time; } + totalTime["ScreenOff"] = mScreenOffTime; return totalTime; } @@ -104,32 +100,26 @@ public: } private: - void flushTime() { - // Normal power mode is counted under different config modes. - if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) { - flushTimeForMode(mCurrentConfigMode); - } else { - flushTimeForMode(SCREEN_OFF_CONFIG_ID); - } - } - // Calculates the time that passed in ms between the last time we recorded time and the time // this method was called. - void flushTimeForMode(int mode) { + void flushTime() { nsecs_t currentTime = systemTime(); nsecs_t timeElapsed = currentTime - mPreviousRecordedTime; int64_t timeElapsedMs = ns2ms(timeElapsed); mPreviousRecordedTime = currentTime; - mConfigModesTotalTime[mode] += timeElapsedMs; - for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) { - if (!config) { - continue; - } - if (config->configId == mode) { - mTimeStats.recordRefreshRate(config->fps, timeElapsed); + uint32_t fps = 0; + if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) { + // Normal power mode is counted under different config modes. + if (mConfigModesTotalTime.find(mCurrentConfigMode) == mConfigModesTotalTime.end()) { + mConfigModesTotalTime[mCurrentConfigMode] = 0; } + mConfigModesTotalTime[mCurrentConfigMode] += timeElapsedMs; + fps = mRefreshRateConfigs.getRefreshRateFromConfigId(mCurrentConfigMode).fps; + } else { + mScreenOffTime += timeElapsedMs; } + mTimeStats.recordRefreshRate(fps, timeElapsed); } // Formats the time in milliseconds into easy to read format. @@ -149,10 +139,11 @@ private: // Aggregate refresh rate statistics for telemetry. TimeStats& mTimeStats; - int64_t mCurrentConfigMode = SCREEN_OFF_CONFIG_ID; - int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF; + int mCurrentConfigMode; + int32_t mCurrentPowerMode; - std::unordered_map mConfigModesTotalTime; + std::unordered_map mConfigModesTotalTime; + int64_t mScreenOffTime = 0; nsecs_t mPreviousRecordedTime = systemTime(); }; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index e2a880a7fe..ffcd94820e 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -118,20 +118,18 @@ DispSync& Scheduler::getPrimaryDispSync() { Scheduler::ConnectionHandle Scheduler::createConnection( const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync, - ResyncCallback resyncCallback, impl::EventThread::InterceptVSyncsCallback interceptCallback) { auto eventThread = makeEventThread(connectionName, phaseOffsetNs, offsetThresholdForNextVsync, std::move(interceptCallback)); - return createConnection(std::move(eventThread), std::move(resyncCallback)); + return createConnection(std::move(eventThread)); } -Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr eventThread, - ResyncCallback&& resyncCallback) { +Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr eventThread) { const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++}; ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id); - auto connection = createConnectionInternal(eventThread.get(), std::move(resyncCallback), - ISurfaceComposer::eConfigChangedSuppress); + auto connection = + createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress); mConnections.emplace(handle, Connection{connection, std::move(eventThread)}); return handle; @@ -148,17 +146,14 @@ std::unique_ptr Scheduler::makeEventThread( } sp Scheduler::createConnectionInternal( - EventThread* eventThread, ResyncCallback&& resyncCallback, - ISurfaceComposer::ConfigChanged configChanged) { - return eventThread->createEventConnection(std::move(resyncCallback), configChanged); + EventThread* eventThread, ISurfaceComposer::ConfigChanged configChanged) { + return eventThread->createEventConnection([&] { resync(); }, configChanged); } sp Scheduler::createDisplayEventConnection( - ConnectionHandle handle, ResyncCallback resyncCallback, - ISurfaceComposer::ConfigChanged configChanged) { + ConnectionHandle handle, ISurfaceComposer::ConfigChanged configChanged) { RETURN_IF_INVALID_HANDLE(handle, nullptr); - return createConnectionInternal(mConnections[handle].thread.get(), std::move(resyncCallback), - configChanged); + return createConnectionInternal(mConnections[handle].thread.get(), configChanged); } EventThread* Scheduler::getEventThread(ConnectionHandle handle) { @@ -248,23 +243,15 @@ void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) { setVsyncPeriod(period); } -ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) { - std::weak_ptr ptr = mPrimaryVsyncState; - return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() { - if (const auto vsync = ptr.lock()) { - vsync->resync(getVsyncPeriod); - } - }; -} - -void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) { +void Scheduler::resync() { static constexpr nsecs_t kIgnoreDelay = ms2ns(500); const nsecs_t now = systemTime(); - const nsecs_t last = lastResyncTime.exchange(now); + const nsecs_t last = mLastResyncTime.exchange(now); if (now - last > kIgnoreDelay) { - scheduler.resyncToHardwareVsync(false, getVsyncPeriod()); + resyncToHardwareVsync(false, + mRefreshRateConfigs.getCurrentRefreshRate().second.vsyncPeriod); } } @@ -314,15 +301,19 @@ nsecs_t Scheduler::getDispSyncExpectedPresentTime() { std::unique_ptr Scheduler::registerLayer( std::string const& name, int windowType) { - RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER) - ? RefreshRateType::DEFAULT - : RefreshRateType::PERFORMANCE; - - const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType); - const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0; - - const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT); - const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0; + uint32_t defaultFps, performanceFps; + if (mRefreshRateConfigs.refreshRateSwitchingSupported()) { + defaultFps = mRefreshRateConfigs.getRefreshRateFromType(RefreshRateType::DEFAULT).fps; + performanceFps = + mRefreshRateConfigs + .getRefreshRateFromType((windowType == InputWindowInfo::TYPE_WALLPAPER) + ? RefreshRateType::DEFAULT + : RefreshRateType::PERFORMANCE) + .fps; + } else { + defaultFps = mRefreshRateConfigs.getCurrentRefreshRate().second.fps; + performanceFps = defaultFps; + } return mLayerHistory.createLayer(name, defaultFps, performanceFps); } @@ -368,16 +359,6 @@ void Scheduler::setChangeRefreshRateCallback(ChangeRefreshRateCallback&& callbac mChangeRefreshRateCallback = std::move(callback); } -void Scheduler::setGetCurrentRefreshRateTypeCallback(GetCurrentRefreshRateTypeCallback&& callback) { - std::lock_guard lock(mCallbackLock); - mGetCurrentRefreshRateTypeCallback = std::move(callback); -} - -void Scheduler::setGetVsyncPeriodCallback(GetVsyncPeriod&& callback) { - std::lock_guard lock(mCallbackLock); - mGetVsyncPeriod = std::move(callback); -} - void Scheduler::resetIdleTimer() { if (mIdleTimer) { mIdleTimer->reset(); @@ -416,16 +397,13 @@ void Scheduler::setDisplayPowerState(bool normal) { void Scheduler::kernelIdleTimerCallback(TimerState state) { ATRACE_INT("ExpiredKernelIdleTimer", static_cast(state)); - std::lock_guard lock(mCallbackLock); - if (!mGetCurrentRefreshRateTypeCallback || !mGetVsyncPeriod) return; - - const auto type = mGetCurrentRefreshRateTypeCallback(); - if (state == TimerState::Reset && type == RefreshRateType::PERFORMANCE) { + const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate(); + if (state == TimerState::Reset && refreshRate.first == RefreshRateType::PERFORMANCE) { // If we're not in performance mode then the kernel timer shouldn't do // anything, as the refresh rate during DPU power collapse will be the // same. - resyncToHardwareVsync(true /* makeAvailable */, mGetVsyncPeriod()); - } else if (state == TimerState::Expired && type != RefreshRateType::PERFORMANCE) { + resyncToHardwareVsync(true /* makeAvailable */, refreshRate.second.vsyncPeriod); + } else if (state == TimerState::Expired && refreshRate.first != RefreshRateType::PERFORMANCE) { // Disable HW VSYNC if the timer expired, as we don't need it enabled if // we're not pushing frames, and if we're in PERFORMANCE mode then we'll // need to update the DispSync model anyway. @@ -485,6 +463,10 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO } Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { + if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) { + return RefreshRateType::DEFAULT; + } + // HDR content is not supported on PERFORMANCE mode if (mForceHDRContentToDefaultRefreshRate && mFeatures.isHDRContent) { return RefreshRateType::DEFAULT; @@ -514,16 +496,11 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { // Content detection is on, find the appropriate refresh rate with minimal error // TODO(b/139751853): Scan allowed refresh rates only (SurfaceFlinger::mAllowedDisplayConfigs) const float rate = static_cast(mFeatures.contentRefreshRate); - auto begin = mRefreshRateConfigs.getRefreshRates().cbegin(); - - // Skip POWER_SAVING config as it is not a real config - if (begin->first == RefreshRateType::POWER_SAVING) { - ++begin; - } - auto iter = min_element(begin, mRefreshRateConfigs.getRefreshRates().cend(), + auto iter = min_element(mRefreshRateConfigs.getRefreshRateMap().cbegin(), + mRefreshRateConfigs.getRefreshRateMap().cend(), [rate](const auto& lhs, const auto& rhs) -> bool { - return std::abs(lhs.second->fps - rate) < - std::abs(rhs.second->fps - rate); + return std::abs(lhs.second.fps - rate) < + std::abs(rhs.second.fps - rate); }); RefreshRateType currRefreshRateType = iter->first; @@ -531,10 +508,10 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't // align well with both constexpr float MARGIN = 0.05f; - float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / rate; + float ratio = mRefreshRateConfigs.getRefreshRateFromType(currRefreshRateType).fps / rate; if (std::abs(std::round(ratio) - ratio) > MARGIN) { - while (iter != mRefreshRateConfigs.getRefreshRates().cend()) { - ratio = iter->second->fps / rate; + while (iter != mRefreshRateConfigs.getRefreshRateMap().cend()) { + ratio = iter->second.fps / rate; if (std::abs(std::round(ratio) - ratio) <= MARGIN) { currRefreshRateType = iter->first; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 34e527cdc6..0c8c335bf6 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -43,9 +43,7 @@ public: using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; using ConfigEvent = scheduler::RefreshRateConfigEvent; - using GetCurrentRefreshRateTypeCallback = std::function; using ChangeRefreshRateCallback = std::function; - using GetVsyncPeriod = std::function; // Indicates whether to start the transaction early, or at vsync time. enum class TransactionStart { EARLY, NORMAL }; @@ -59,10 +57,10 @@ public: using ConnectionHandle = scheduler::ConnectionHandle; ConnectionHandle createConnection(const char* connectionName, nsecs_t phaseOffsetNs, - nsecs_t offsetThresholdForNextVsync, ResyncCallback, + nsecs_t offsetThresholdForNextVsync, impl::EventThread::InterceptVSyncsCallback); - sp createDisplayEventConnection(ConnectionHandle, ResyncCallback, + sp createDisplayEventConnection(ConnectionHandle, ISurfaceComposer::ConfigChanged); EventThread* getEventThread(ConnectionHandle); @@ -88,7 +86,7 @@ public: // no-op. // The period is the vsync period from the current display configuration. void resyncToHardwareVsync(bool makeAvailable, nsecs_t period); - ResyncCallback makeResyncCallback(GetVsyncPeriod&&); + void resync(); // Passes a vsync sample to DispSync. periodFlushed will be true if // DispSync detected that the vsync period changed, and false otherwise. @@ -113,9 +111,6 @@ public: // Called by Scheduler to change refresh rate. void setChangeRefreshRateCallback(ChangeRefreshRateCallback&&); - void setGetCurrentRefreshRateTypeCallback(GetCurrentRefreshRateTypeCallback&&); - void setGetVsyncPeriodCallback(GetVsyncPeriod&&); - bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); } void resetIdleTimer(); @@ -149,8 +144,8 @@ private: impl::EventThread::InterceptVSyncsCallback&&); // Create a connection on the given EventThread and forward the resync callback. - ConnectionHandle createConnection(std::unique_ptr, ResyncCallback&&); - sp createConnectionInternal(EventThread*, ResyncCallback&&, + ConnectionHandle createConnection(std::unique_ptr); + sp createConnectionInternal(EventThread*, ISurfaceComposer::ConfigChanged); // Update feature state machine to given state when corresponding timer resets or expires. @@ -182,17 +177,7 @@ private: bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock) = false; bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock) = false; - // Stores per-display state about VSYNC. - struct VsyncState { - explicit VsyncState(Scheduler& scheduler) : scheduler(scheduler) {} - - void resync(const GetVsyncPeriod&); - - Scheduler& scheduler; - std::atomic lastResyncTime = 0; - }; - - const std::shared_ptr mPrimaryVsyncState{std::make_shared(*this)}; + std::atomic mLastResyncTime = 0; std::unique_ptr mPrimaryDispSync; std::unique_ptr mEventControlThread; @@ -211,9 +196,7 @@ private: std::optional mDisplayPowerTimer; std::mutex mCallbackLock; - GetCurrentRefreshRateTypeCallback mGetCurrentRefreshRateTypeCallback GUARDED_BY(mCallbackLock); ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock); - GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock); // In order to make sure that the features don't override themselves, we need a state machine // to keep track which feature requested the config change. diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h index ab0c0ffedd..3bb3a6f182 100644 --- a/services/surfaceflinger/Scheduler/SchedulerUtils.h +++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h @@ -40,12 +40,6 @@ inline bool operator==(ConnectionHandle lhs, ConnectionHandle rhs) { using namespace std::chrono_literals; -// This number is used to have a place holder for when the screen is not NORMAL/ON. Currently -// the config is not visible to SF, and is completely maintained by HWC. However, we would -// still like to keep track of time when the device is in this config. -static constexpr int SCREEN_OFF_CONFIG_ID = -1; -static constexpr uint32_t HWC2_SCREEN_OFF_CONFIG_ID = 0xffffffff; - // This number is used when we try to determine how long do we keep layer information around // before we remove it. It is also used to determine how long the layer stays relevant. // This time period captures infrequent updates when playing YouTube video with static image, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4361a94e64..289903433d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -549,14 +549,16 @@ void SurfaceFlinger::bootFinished() readPersistentProperties(); mBootStage = BootStage::FINISHED; - // set the refresh rate according to the policy - const auto& performanceRefreshRate = - mRefreshRateConfigs.getRefreshRate(RefreshRateType::PERFORMANCE); + if (mRefreshRateConfigs->refreshRateSwitchingSupported()) { + // set the refresh rate according to the policy + const auto& performanceRefreshRate = + mRefreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE); - if (performanceRefreshRate && isDisplayConfigAllowed(performanceRefreshRate->configId)) { - setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); - } else { - setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); + if (isDisplayConfigAllowed(performanceRefreshRate.configId)) { + setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); + } else { + setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); + } } })); } @@ -595,37 +597,9 @@ void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { void SurfaceFlinger::init() { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); - ALOGI("Phase offset: %" PRId64 " ns", mPhaseOffsets->getCurrentAppOffset()); Mutex::Autolock _l(mStateLock); - // start the EventThread - mScheduler = - getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); }, - mRefreshRateConfigs); - auto resyncCallback = - mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this)); - - mAppConnectionHandle = - mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(), - mPhaseOffsets->getOffsetThresholdForNextVsync(), - resyncCallback, - impl::EventThread::InterceptVSyncsCallback()); - mSfConnectionHandle = - mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(), - mPhaseOffsets->getOffsetThresholdForNextVsync(), - resyncCallback, [this](nsecs_t timestamp) { - mInterceptor->saveVSyncEvent(timestamp); - }); - - mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle)); - - mVSyncModulator.emplace(*mScheduler, mAppConnectionHandle, mSfConnectionHandle, - mPhaseOffsets->getCurrentOffsets()); - - mRegionSamplingThread = - new RegionSamplingThread(*this, *mScheduler, - RegionSamplingThread::EnvironmentTimingTunables()); // Get a RenderEngine for the given display / config (can't fail) int32_t renderEngineFeature = 0; @@ -700,37 +674,6 @@ void SurfaceFlinger::init() { ALOGE("Run StartPropertySetThread failed!"); } - mScheduler->setChangeRefreshRateCallback( - [this](RefreshRateType type, Scheduler::ConfigEvent event) { - Mutex::Autolock lock(mStateLock); - setRefreshRateTo(type, event); - }); - mScheduler->setGetCurrentRefreshRateTypeCallback([this] { - Mutex::Autolock lock(mStateLock); - const auto display = getDefaultDisplayDeviceLocked(); - if (!display) { - // If we don't have a default display the fallback to the default - // refresh rate type - return RefreshRateType::DEFAULT; - } - - const int configId = display->getActiveConfig(); - for (const auto& [type, refresh] : mRefreshRateConfigs.getRefreshRates()) { - if (refresh && refresh->configId == configId) { - return type; - } - } - // This should never happen, but just gracefully fallback to default. - return RefreshRateType::DEFAULT; - }); - mScheduler->setGetVsyncPeriodCallback([this] { - Mutex::Autolock lock(mStateLock); - return getVsyncPeriod(); - }); - - mRefreshRateConfigs.populate(getHwComposer().getConfigs(*display->getId())); - mRefreshRateStats.setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId())); - ALOGV("Done initializing"); } @@ -884,7 +827,8 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, info.xdpi = xdpi; info.ydpi = ydpi; info.fps = 1e9 / hwConfig->getVsyncPeriod(); - const auto refreshRateType = mRefreshRateConfigs.getRefreshRateType(hwConfig->getId()); + const auto refreshRateType = + mRefreshRateConfigs->getRefreshRateTypeFromHwcConfigId(hwConfig->getId()); const auto offset = mPhaseOffsets->getOffsetsForRefreshRate(refreshRateType); info.appVsyncOffset = offset.late.app; @@ -983,7 +927,8 @@ void SurfaceFlinger::setActiveConfigInternal() { } std::lock_guard lock(mActiveConfigLock); - mRefreshRateStats.setConfigMode(mUpcomingActiveConfig.configId); + mRefreshRateConfigs->setCurrentConfig(mUpcomingActiveConfig.configId); + mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId); display->setActiveConfig(mUpcomingActiveConfig.configId); @@ -1259,9 +1204,6 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { return; } - auto resyncCallback = - mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this)); - // TODO(b/128863962): Part of the Injector should be refactored, so that it // can be passed to Scheduler. if (enable) { @@ -1273,11 +1215,11 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { impl::EventThread::InterceptVSyncsCallback(), "injEventThread"); } - mEventQueue->setEventThread(mInjectorEventThread.get(), std::move(resyncCallback)); + mEventQueue->setEventThread(mInjectorEventThread.get(), [&] { mScheduler->resync(); }); } else { ALOGV("VSync Injections disabled"); mEventQueue->setEventThread(mScheduler->getEventThread(mSfConnectionHandle), - std::move(resyncCallback)); + [&] { mScheduler->resync(); }); } mInjectVSyncs = enable; @@ -1388,16 +1330,10 @@ status_t SurfaceFlinger::notifyPowerHint(int32_t hintId) { sp SurfaceFlinger::createDisplayEventConnection( ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) { - auto resyncCallback = mScheduler->makeResyncCallback([this] { - Mutex::Autolock lock(mStateLock); - return getVsyncPeriod(); - }); - const auto& handle = vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle; - return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback), - configChanged); + return mScheduler->createDisplayEventConnection(handle, configChanged); } // ---------------------------------------------------------------------------- @@ -1494,13 +1430,8 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::Co ATRACE_CALL(); // Don't do any updating if the current fps is the same as the new one. - const auto& refreshRateConfig = mRefreshRateConfigs.getRefreshRate(refreshRate); - if (!refreshRateConfig) { - ALOGV("Skipping refresh rate change request for unsupported rate."); - return; - } - - const int desiredConfigId = refreshRateConfig->configId; + const auto& refreshRateConfig = mRefreshRateConfigs->getRefreshRateFromType(refreshRate); + const int desiredConfigId = refreshRateConfig.configId; if (!isDisplayConfigAllowed(desiredConfigId)) { ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId); @@ -2202,6 +2133,9 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { if (event.connection == HWC2::Connection::Connected) { if (!mPhysicalDisplayTokens.count(info->id)) { ALOGV("Creating display %s", to_string(info->id).c_str()); + if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) { + initScheduler(info->id); + } mPhysicalDisplayTokens[info->id] = new BBinder(); DisplayDeviceState state; state.displayId = info->id; @@ -2656,6 +2590,55 @@ void SurfaceFlinger::updateCursorAsync() mCompositionEngine->updateCursorAsync(refreshArgs); } +void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { + if (mScheduler) { + // In practice it's not allowed to hotplug in/out the primary display once it's been + // connected during startup, but some tests do it, so just warn and return. + ALOGW("Can't re-init scheduler"); + return; + } + + int currentConfig = getHwComposer().getActiveConfigIndex(primaryDisplayId); + mRefreshRateConfigs = + std::make_unique(refresh_rate_switching(false), + getHwComposer().getConfigs( + primaryDisplayId), + currentConfig); + mRefreshRateStats = + std::make_unique(*mRefreshRateConfigs, *mTimeStats, + currentConfig, HWC_POWER_MODE_OFF); + mRefreshRateStats->setConfigMode(currentConfig); + + // start the EventThread + mScheduler = + getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); }, + *mRefreshRateConfigs); + mAppConnectionHandle = + mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(), + mPhaseOffsets->getOffsetThresholdForNextVsync(), + impl::EventThread::InterceptVSyncsCallback()); + mSfConnectionHandle = + mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(), + mPhaseOffsets->getOffsetThresholdForNextVsync(), + [this](nsecs_t timestamp) { + mInterceptor->saveVSyncEvent(timestamp); + }); + + mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle)); + mVSyncModulator.emplace(*mScheduler, mAppConnectionHandle, mSfConnectionHandle, + mPhaseOffsets->getCurrentOffsets()); + + mRegionSamplingThread = + new RegionSamplingThread(*this, *mScheduler, + RegionSamplingThread::EnvironmentTimingTunables()); + + mScheduler->setChangeRefreshRateCallback( + [this](RefreshRateType type, Scheduler::ConfigEvent event) { + Mutex::Autolock lock(mStateLock); + setRefreshRateTo(type, event); + }); +} + void SurfaceFlinger::commitTransaction() { withTracingLock([&]() { @@ -4000,7 +3983,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, int if (display->isPrimary()) { mTimeStats->setPowerMode(mode); - mRefreshRateStats.setPowerMode(mode); + mRefreshRateStats->setPowerMode(mode); mScheduler->setDisplayPowerState(mode == HWC_POWER_MODE_NORMAL); } @@ -4164,9 +4147,11 @@ void SurfaceFlinger::appendSfConfigString(std::string& result) const { void SurfaceFlinger::dumpVSync(std::string& result) const { mScheduler->dump(result); + StringAppendF(&result, "+ Refresh rate switching: %s\n", + mRefreshRateConfigs->refreshRateSwitchingSupported() ? "on" : "off"); StringAppendF(&result, "+ Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off"); - mRefreshRateStats.dump(result); + mRefreshRateStats->dump(result); result.append("\n"); mPhaseOffsets->dump(result); @@ -4175,10 +4160,9 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { dispSyncPresentTimeOffset, getVsyncPeriod()); StringAppendF(&result, "Allowed Display Configs: "); - for (const auto& [type, rate] : mRefreshRateConfigs.getRefreshRates()) { - if (rate && isDisplayConfigAllowed(rate->configId)) { - StringAppendF(&result, "%" PRIu32 " Hz, ", rate->fps); - } + for (int32_t configId : mAllowedDisplayConfigs) { + StringAppendF(&result, "%" PRIu32 " Hz, ", + mRefreshRateConfigs->getRefreshRateFromConfigId(configId).fps); } StringAppendF(&result, "(config override by backdoor: %s)\n\n", mDebugDisplayConfigSetByBackdoor ? "yes" : "no"); @@ -5020,7 +5004,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r case 1034: { // TODO(b/129297325): expose this via developer menu option n = data.readInt32(); - if (n && !mRefreshRateOverlay) { + if (n && !mRefreshRateOverlay && + mRefreshRateConfigs->refreshRateSwitchingSupported()) { RefreshRateType type; { std::lock_guard lock(mActiveConfigLock); @@ -5606,25 +5591,6 @@ void SurfaceFlinger::traverseLayersInDisplay(const sp& disp } } -void SurfaceFlinger::setPreferredDisplayConfig() { - const auto& type = mScheduler->getPreferredRefreshRateType(); - const auto& config = mRefreshRateConfigs.getRefreshRate(type); - if (config && isDisplayConfigAllowed(config->configId)) { - ALOGV("switching to Scheduler preferred config %d", config->configId); - setDesiredActiveConfig({type, config->configId, Scheduler::ConfigEvent::Changed}); - } else { - // Set the highest allowed config by iterating backwards on available refresh rates - const auto& refreshRates = mRefreshRateConfigs.getRefreshRates(); - for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) { - if (iter->second && isDisplayConfigAllowed(iter->second->configId)) { - ALOGV("switching to allowed config %d", iter->second->configId); - setDesiredActiveConfig({iter->first, iter->second->configId, - Scheduler::ConfigEvent::Changed}); - } - } - } -} - void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp& display, const std::vector& allowedConfigs) { if (!display->isPrimary()) { @@ -5646,7 +5612,29 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp& d mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, display->getActiveConfig()); - setPreferredDisplayConfig(); + if (mRefreshRateConfigs->refreshRateSwitchingSupported()) { + const auto& type = mScheduler->getPreferredRefreshRateType(); + const auto& config = mRefreshRateConfigs->getRefreshRateFromType(type); + if (isDisplayConfigAllowed(config.configId)) { + ALOGV("switching to Scheduler preferred config %d", config.configId); + setDesiredActiveConfig({type, config.configId, Scheduler::ConfigEvent::Changed}); + } else { + // Set the highest allowed config by iterating backwards on available refresh rates + const auto& refreshRates = mRefreshRateConfigs->getRefreshRateMap(); + for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) { + if (isDisplayConfigAllowed(iter->second.configId)) { + ALOGV("switching to allowed config %d", iter->second.configId); + setDesiredActiveConfig( + {iter->first, iter->second.configId, Scheduler::ConfigEvent::Changed}); + break; + } + } + } + } else if (!allowedConfigs.empty()) { + ALOGV("switching to config %d", allowedConfigs[0]); + setDesiredActiveConfig( + {RefreshRateType::DEFAULT, allowedConfigs[0], Scheduler::ConfigEvent::Changed}); + } } status_t SurfaceFlinger::setAllowedDisplayConfigs(const sp& displayToken, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index beb43d0d9d..d357c3d9ab 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -529,9 +529,6 @@ private: // called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp& display, int mode) REQUIRES(mStateLock); - // Query the Scheduler or allowed display configs list for a matching config, and set it - void setPreferredDisplayConfig() REQUIRES(mStateLock); - // called on the main thread in response to setAllowedDisplayConfigs() void setAllowedDisplayConfigsInternal(const sp& display, const std::vector& allowedConfigs) @@ -554,6 +551,7 @@ private: void executeInputWindowCommands(); void setInputWindowsFinished(); void updateCursorAsync(); + void initScheduler(DisplayId primaryDisplayId); /* handlePageFlip - latch a new buffer if available and compute the dirty * region. Returns whether a new buffer has been latched, i.e., whether it @@ -1102,8 +1100,8 @@ private: // Optional to defer construction until scheduler connections are created. std::optional mVSyncModulator; - scheduler::RefreshRateConfigs mRefreshRateConfigs; - scheduler::RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, *mTimeStats}; + std::unique_ptr mRefreshRateConfigs; + std::unique_ptr mRefreshRateStats; std::atomic mExpectedPresentTime = 0; diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 768074a6cd..b4716eb61e 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -226,6 +226,14 @@ int64_t color_space_agnostic_dataspace(Dataspace defaultValue) { return static_cast(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 5f88322f71..e394ccab7b 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -73,6 +73,8 @@ int32_t wcg_composition_pixel_format( 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/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index 56ab4e3f33..51b20cb7e5 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -15,7 +15,7 @@ module: "android.sysprop.SurfaceFlingerProperties" owner: Platform -# The following two propertiess define (respectively): +# The following two properties define (respectively): # # - The phase offset between hardware vsync and when apps are woken up by the # Choreographer callback @@ -301,9 +301,18 @@ prop { prop_name: "ro.surface_flinger.display_primary_white" } -# setIdleTimerMs indicates what is considered a timeout in milliseconds for Scheduler. This value is -# used by the Scheduler to trigger inactivity callbacks that will switch the display to a lower -# refresh rate. Setting this property to 0 means there is no timer. +# 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 b66e56ecc7..2d525073b9 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -72,6 +72,10 @@ props { prop_name: "ro.surface_flinger.primary_display_orientation" 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/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 5067fe890b..f315a8a86c 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -23,7 +23,6 @@ #include "DisplayHardware/HWC2.h" #include "Scheduler/RefreshRateConfigs.h" -#include "mock/DisplayHardware/MockDisplay.h" using namespace std::chrono_literals; using testing::_; @@ -50,9 +49,8 @@ protected: ASSERT_EQ(left.configId, right.configId); ASSERT_EQ(left.name, right.name); ASSERT_EQ(left.fps, right.fps); + ASSERT_EQ(left.vsyncPeriod, right.vsyncPeriod); } - - RefreshRateConfigs mConfigs; }; RefreshRateConfigsTest::RefreshRateConfigsTest() { @@ -71,101 +69,39 @@ namespace { /* ------------------------------------------------------------------------ * Test cases */ -TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) { - std::vector> displayConfigs; - mConfigs.populate(displayConfigs); - - // We always store a configuration for screen off. - const auto& rates = mConfigs.getRefreshRates(); - ASSERT_EQ(1, rates.size()); - const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); - ASSERT_NE(rates.end(), powerSavingRate); - ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE)); - ASSERT_EQ(rates.end(), rates.find(RefreshRateType::DEFAULT)); - - RefreshRate expectedConfig = - RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID}; - assertRatesEqual(expectedConfig, *powerSavingRate->second); - - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - assertRatesEqual(expectedConfig, *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); - ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - - // Sanity check that getRefreshRate() does not modify the underlying configs. - ASSERT_EQ(1, mConfigs.getRefreshRates().size()); +TEST_F(RefreshRateConfigsTest, oneDeviceConfig_isRejected) { + std::vector configs{{HWC2_CONFIG_ID_60, VSYNC_60}}; + auto refreshRateConfigs = + std::make_unique(/*refreshRateSwitching=*/true, configs, + /*currentConfig=*/0); + ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported()); } -TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) { - auto display = new Hwc2::mock::Display(); - std::vector> displayConfigs; - auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); - config60.setVsyncPeriod(VSYNC_60); - displayConfigs.push_back(config60.build()); - mConfigs.populate(displayConfigs); +TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) { + std::vector configs{{HWC2_CONFIG_ID_60, VSYNC_60}, + {HWC2_CONFIG_ID_90, VSYNC_90}}; + auto refreshRateConfigs = + std::make_unique(/*refreshRateSwitching=*/true, configs, + /*currentConfig=*/0); - const auto& rates = mConfigs.getRefreshRates(); + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + const auto& rates = refreshRateConfigs->getRefreshRateMap(); ASSERT_EQ(2, rates.size()); - const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); - const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); - ASSERT_NE(rates.end(), powerSavingRate); - ASSERT_NE(rates.end(), defaultRate); - ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE)); - - RefreshRate expectedPowerSavingConfig = - RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID}; - assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second); - RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60, HWC2_CONFIG_ID_60}; - assertRatesEqual(expectedDefaultConfig, *defaultRate->second); - - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - assertRatesEqual(expectedPowerSavingConfig, - *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); - - // Sanity check that getRefreshRate() does not modify the underlying configs. - ASSERT_EQ(2, mConfigs.getRefreshRates().size()); -} - -TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) { - auto display = new Hwc2::mock::Display(); - std::vector> displayConfigs; - auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); - config60.setVsyncPeriod(VSYNC_60); - displayConfigs.push_back(config60.build()); - auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90); - config90.setVsyncPeriod(VSYNC_90); - displayConfigs.push_back(config90.build()); - mConfigs.populate(displayConfigs); - - const auto& rates = mConfigs.getRefreshRates(); - ASSERT_EQ(3, rates.size()); - const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE); - ASSERT_NE(rates.end(), powerSavingRate); ASSERT_NE(rates.end(), defaultRate); ASSERT_NE(rates.end(), performanceRate); - RefreshRate expectedPowerSavingConfig = - RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID}; - assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second); - RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60, HWC2_CONFIG_ID_60}; - assertRatesEqual(expectedDefaultConfig, *defaultRate->second); - RefreshRate expectedPerformanceConfig = - RefreshRate{CONFIG_ID_90, "90fps", 90, HWC2_CONFIG_ID_90}; - assertRatesEqual(expectedPerformanceConfig, *performanceRate->second); - - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - assertRatesEqual(expectedPowerSavingConfig, - *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); + RefreshRate expectedDefaultConfig = {CONFIG_ID_60, "60fps", 60, VSYNC_60, HWC2_CONFIG_ID_60}; + assertRatesEqual(expectedDefaultConfig, defaultRate->second); + RefreshRate expectedPerformanceConfig = {CONFIG_ID_90, "90fps", 90, VSYNC_90, + HWC2_CONFIG_ID_90}; + assertRatesEqual(expectedPerformanceConfig, performanceRate->second); + + assertRatesEqual(expectedDefaultConfig, + refreshRateConfigs->getRefreshRateFromType(RefreshRateType::DEFAULT)); assertRatesEqual(expectedPerformanceConfig, - *mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); + refreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE)); } } // namespace } // namespace scheduler diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index 411ec61770..cec0b32a6b 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -22,7 +22,6 @@ #include #include "Scheduler/RefreshRateStats.h" -#include "mock/DisplayHardware/MockDisplay.h" #include "mock/MockTimeStats.h" using namespace std::chrono_literals; @@ -42,9 +41,18 @@ protected: RefreshRateStatsTest(); ~RefreshRateStatsTest(); + void init(const std::vector& configs) { + mRefreshRateConfigs = std::make_unique( + /*refreshRateSwitching=*/true, configs, /*currentConfig=*/0); + mRefreshRateStats = + std::make_unique(*mRefreshRateConfigs, mTimeStats, + /*currentConfig=*/0, + /*currentPowerMode=*/HWC_POWER_MODE_OFF); + } + mock::TimeStats mTimeStats; - RefreshRateConfigs mRefreshRateConfigs; - RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, mTimeStats}; + std::unique_ptr mRefreshRateConfigs; + std::unique_ptr mRefreshRateStats; }; RefreshRateStatsTest::RefreshRateStatsTest() { @@ -63,63 +71,46 @@ namespace { /* ------------------------------------------------------------------------ * Test cases */ -TEST_F(RefreshRateStatsTest, canCreateAndDestroyTest) { - std::vector> configs; - mRefreshRateConfigs.populate(configs); - - // There is one default config, so the refresh rates should have one item. - EXPECT_EQ(1, mRefreshRateStats.getTotalTimes().size()); -} - TEST_F(RefreshRateStatsTest, oneConfigTest) { - auto display = new Hwc2::mock::Display(); - - auto config = HWC2::Display::Config::Builder(*display, CONFIG_ID_90); - config.setVsyncPeriod(VSYNC_90); - std::vector> configs; - configs.push_back(config.build()); - - mRefreshRateConfigs.populate(configs); + init({{CONFIG_ID_90, VSYNC_90}}); EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); - std::unordered_map times = mRefreshRateStats.getTotalTimes(); - EXPECT_EQ(2, times.size()); + std::unordered_map times = mRefreshRateStats->getTotalTimes(); + ASSERT_EQ(1, times.size()); EXPECT_NE(0u, times.count("ScreenOff")); - EXPECT_EQ(1u, times.count("90fps")); - EXPECT_EQ(0, times["90fps"]); // Setting up tests on mobile harness can be flaky with time passing, so testing for // exact time changes can result in flaxy numbers. To avoid that remember old // numbers to make sure the correct values are increasing in the next test. int screenOff = times["ScreenOff"]; - int ninety = times["90fps"]; // Screen is off by default. std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(0, times["90fps"]); + EXPECT_EQ(0u, times.count("90fps")); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL); - screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); + screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_LT(ninety, times["90fps"]); + ASSERT_EQ(1u, times.count("90fps")); + EXPECT_LT(0, times["90fps"]); - mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE); - ninety = mRefreshRateStats.getTotalTimes()["90fps"]; + mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE); + int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config // does not update refresh rates that come from the config. EXPECT_LT(screenOff, times["ScreenOff"]); @@ -127,93 +118,75 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { } TEST_F(RefreshRateStatsTest, twoConfigsTest) { - auto display = new Hwc2::mock::Display(); - - auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90); - config90.setVsyncPeriod(VSYNC_90); - std::vector> configs; - configs.push_back(config90.build()); - - auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); - config60.setVsyncPeriod(VSYNC_60); - configs.push_back(config60.build()); - - mRefreshRateConfigs.populate(configs); + init({{CONFIG_ID_90, VSYNC_90}, {CONFIG_ID_60, VSYNC_60}}); EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); - std::unordered_map times = mRefreshRateStats.getTotalTimes(); - EXPECT_EQ(3, times.size()); + std::unordered_map times = mRefreshRateStats->getTotalTimes(); + ASSERT_EQ(1, times.size()); EXPECT_NE(0u, times.count("ScreenOff")); - EXPECT_EQ(1u, times.count("60fps")); - EXPECT_EQ(0, times["60fps"]); - EXPECT_EQ(1u, times.count("90fps")); - EXPECT_EQ(0, times["90fps"]); // Setting up tests on mobile harness can be flaky with time passing, so testing for // exact time changes can result in flaxy numbers. To avoid that remember old // numbers to make sure the correct values are increasing in the next test. int screenOff = times["ScreenOff"]; - int sixty = times["60fps"]; - int ninety = times["90fps"]; // Screen is off by default. std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(sixty, times["60fps"]); - EXPECT_EQ(ninety, times["90fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL); - screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); + screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_EQ(sixty, times["60fps"]); - EXPECT_LT(ninety, times["90fps"]); + ASSERT_EQ(1u, times.count("90fps")); + EXPECT_LT(0, times["90fps"]); // When power mode is normal, time for configs updates. - mRefreshRateStats.setConfigMode(CONFIG_ID_60); - ninety = mRefreshRateStats.getTotalTimes()["90fps"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_60); + int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); - EXPECT_LT(sixty, times["60fps"]); + ASSERT_EQ(1u, times.count("60fps")); + EXPECT_LT(0, times["60fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - sixty = mRefreshRateStats.getTotalTimes()["60fps"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + int sixty = mRefreshRateStats->getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_LT(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_60); - ninety = mRefreshRateStats.getTotalTimes()["90fps"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_60); + ninety = mRefreshRateStats->getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_LT(sixty, times["60fps"]); // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config // does not update refresh rates that come from the config. - mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - sixty = mRefreshRateStats.getTotalTimes()["60fps"]; + mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE); + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + sixty = mRefreshRateStats->getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_60); - screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_60); + screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index ebcb9d8736..bf531248f8 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -9,6 +9,7 @@ #include "Scheduler/EventControlThread.h" #include "Scheduler/EventThread.h" +#include "Scheduler/RefreshRateConfigs.h" #include "TestableScheduler.h" #include "mock/MockEventThread.h" @@ -36,8 +37,8 @@ protected: SchedulerTest(); ~SchedulerTest() override; - scheduler::RefreshRateConfigs mRefreshRateConfigs; - TestableScheduler mScheduler{mRefreshRateConfigs}; + std::unique_ptr mRefreshRateConfigs; + std::unique_ptr mScheduler; Scheduler::ConnectionHandle mConnectionHandle; mock::EventThread* mEventThread; @@ -49,6 +50,13 @@ SchedulerTest::SchedulerTest() { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + std::vector configs{{/*hwcId=*/0, 16666667}}; + mRefreshRateConfigs = + std::make_unique(/*refreshRateSwitching=*/false, configs, + /*currentConfig=*/0); + + mScheduler = std::make_unique(*mRefreshRateConfigs); + auto eventThread = std::make_unique(); mEventThread = eventThread.get(); EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0)); @@ -60,7 +68,7 @@ SchedulerTest::SchedulerTest() { EXPECT_CALL(*mEventThread, createEventConnection(_, _)) .WillRepeatedly(Return(mEventThreadConnection)); - mConnectionHandle = mScheduler.createConnection(std::move(eventThread)); + mConnectionHandle = mScheduler->createConnection(std::move(eventThread)); EXPECT_TRUE(mConnectionHandle); } @@ -80,61 +88,60 @@ TEST_F(SchedulerTest, invalidConnectionHandle) { sp connection; ASSERT_NO_FATAL_FAILURE( - connection = mScheduler.createDisplayEventConnection(handle, ResyncCallback(), - ISurfaceComposer:: - eConfigChangedSuppress)); + connection = mScheduler->createDisplayEventConnection(handle, + ISurfaceComposer:: + eConfigChangedSuppress)); EXPECT_FALSE(connection); - EXPECT_FALSE(mScheduler.getEventThread(handle)); - EXPECT_FALSE(mScheduler.getEventConnection(handle)); + EXPECT_FALSE(mScheduler->getEventThread(handle)); + EXPECT_FALSE(mScheduler->getEventConnection(handle)); // The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads. EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0); - ASSERT_NO_FATAL_FAILURE(mScheduler.onHotplugReceived(handle, PHYSICAL_DISPLAY_ID, false)); + ASSERT_NO_FATAL_FAILURE(mScheduler->onHotplugReceived(handle, PHYSICAL_DISPLAY_ID, false)); EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0); - ASSERT_NO_FATAL_FAILURE(mScheduler.onScreenAcquired(handle)); + ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(handle)); EXPECT_CALL(*mEventThread, onScreenReleased()).Times(0); - ASSERT_NO_FATAL_FAILURE(mScheduler.onScreenReleased(handle)); + ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(handle)); std::string output; EXPECT_CALL(*mEventThread, dump(_)).Times(0); - ASSERT_NO_FATAL_FAILURE(mScheduler.dump(handle, output)); + ASSERT_NO_FATAL_FAILURE(mScheduler->dump(handle, output)); EXPECT_TRUE(output.empty()); EXPECT_CALL(*mEventThread, setPhaseOffset(_)).Times(0); - ASSERT_NO_FATAL_FAILURE(mScheduler.setPhaseOffset(handle, 10)); + ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(handle, 10)); } TEST_F(SchedulerTest, validConnectionHandle) { sp connection; ASSERT_NO_FATAL_FAILURE( - connection = - mScheduler.createDisplayEventConnection(mConnectionHandle, ResyncCallback(), - ISurfaceComposer:: - eConfigChangedSuppress)); + connection = mScheduler->createDisplayEventConnection(mConnectionHandle, + ISurfaceComposer:: + eConfigChangedSuppress)); ASSERT_EQ(mEventThreadConnection, connection); - EXPECT_TRUE(mScheduler.getEventThread(mConnectionHandle)); - EXPECT_TRUE(mScheduler.getEventConnection(mConnectionHandle)); + EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle)); + EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle)); EXPECT_CALL(*mEventThread, onHotplugReceived(PHYSICAL_DISPLAY_ID, false)).Times(1); ASSERT_NO_FATAL_FAILURE( - mScheduler.onHotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false)); + mScheduler->onHotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false)); EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1); - ASSERT_NO_FATAL_FAILURE(mScheduler.onScreenAcquired(mConnectionHandle)); + ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle)); EXPECT_CALL(*mEventThread, onScreenReleased()).Times(1); - ASSERT_NO_FATAL_FAILURE(mScheduler.onScreenReleased(mConnectionHandle)); + ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(mConnectionHandle)); std::string output("dump"); EXPECT_CALL(*mEventThread, dump(output)).Times(1); - ASSERT_NO_FATAL_FAILURE(mScheduler.dump(mConnectionHandle, output)); + ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, output)); EXPECT_FALSE(output.empty()); EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1); - ASSERT_NO_FATAL_FAILURE(mScheduler.setPhaseOffset(mConnectionHandle, 10)); + ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10)); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 780b608e59..ae7246780a 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -37,7 +37,7 @@ public: // Used to inject mock event thread. ConnectionHandle createConnection(std::unique_ptr eventThread) { - return Scheduler::createConnection(std::move(eventThread), ResyncCallback()); + return Scheduler::createConnection(std::move(eventThread)); } /* ------------------------------------------------------------------------ diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 9536dd13fb..5e075b6a4b 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -32,6 +32,7 @@ #include "Layer.h" #include "NativeWindowSurface.h" #include "Scheduler/MessageQueue.h" +#include "Scheduler/RefreshRateConfigs.h" #include "StartPropertySetThread.h" #include "SurfaceFlinger.h" #include "SurfaceFlingerFactory.h" @@ -194,9 +195,19 @@ public: std::unique_ptr eventControlThread, std::unique_ptr appEventThread, std::unique_ptr sfEventThread) { + std::vector configs{{/*hwcId=*/0, 16666667}}; + mFlinger->mRefreshRateConfigs = + std::make_unique(/*refreshRateSwitching=*/false, + configs, /*currentConfig=*/0); + mFlinger->mRefreshRateStats = + std::make_unique(*mFlinger->mRefreshRateConfigs, + *mFlinger->mTimeStats, + /*currentConfig=*/0, + /*powerMode=*/HWC_POWER_MODE_OFF); + mScheduler = new TestableScheduler(std::move(primaryDispSync), std::move(eventControlThread), - mFlinger->mRefreshRateConfigs); + *mFlinger->mRefreshRateConfigs); mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread)); mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread)); -- GitLab From f83ce183aa13db5e66b5fd5e6bd09de5169373c5 Mon Sep 17 00:00:00 2001 From: chaviw Date: Thu, 12 Sep 2019 14:43:08 -0700 Subject: [PATCH 0272/1255] Corrected drawingTransformMatrix The transformMatrix needed to be calculated in prepareClientComposition so storing it in BufferInfo was incorrect. Instead, allow the transformMatrix to get calculated when prepareClientComposition but avoid using the consumer for BufferQueueLayer. Also combined getDrawingTransformMatrix and setFilteringEnabled since setFilteringEnabled was only used to update the transformMatrix before getting it. BufferQueueLayers no longer go through the consumer to get the transformMatrix and just directly calculate the matrix using the GLUtils class. Fixes: 140759442 Test: atest android.view.cts.ASurfaceControlTest Change-Id: I09179de275bd905960fb366e45e36fb9874bc0b3 --- services/surfaceflinger/BufferLayer.cpp | 9 +++++++-- services/surfaceflinger/BufferLayer.h | 9 +++++---- services/surfaceflinger/BufferQueueLayer.cpp | 12 ------------ services/surfaceflinger/BufferQueueLayer.h | 4 ---- services/surfaceflinger/BufferStateLayer.cpp | 14 +++----------- services/surfaceflinger/BufferStateLayer.h | 6 ------ 6 files changed, 15 insertions(+), 39 deletions(-) diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 486b042873..b060b047af 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -187,8 +188,7 @@ std::optional BufferLayer::prepareClientComposition // Query the texture matrix given our current filtering mode. float textureMatrix[16]; - setFilteringEnabled(useFiltering); - memcpy(textureMatrix, mBufferInfo.mTransformMatrix, sizeof(mBufferInfo.mTransformMatrix)); + getDrawingTransformMatrix(useFiltering, textureMatrix); if (getTransformToDisplayInverse()) { /* @@ -719,6 +719,11 @@ sp BufferLayer::getBuffer() const { return mBufferInfo.mBuffer; } +void BufferLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) { + GLConsumer::computeTransformMatrix(outMatrix, mBufferInfo.mBuffer, mBufferInfo.mCrop, + mBufferInfo.mTransform, filteringEnabled); +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index a685ea2305..f0a30e319a 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -127,6 +127,10 @@ private: PixelFormat getPixelFormat() const; + // Computes the transform matrix using the setFilteringEnabled to determine whether the + // transform matrix should be computed for use with bilinear filtering. + void getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]); + virtual uint64_t getFrameNumber(nsecs_t expectedPresentTime) const = 0; virtual bool getAutoRefresh() const = 0; @@ -137,8 +141,6 @@ private: virtual bool hasFrameUpdate() const = 0; - virtual void setFilteringEnabled(bool enabled) = 0; - virtual status_t bindTextureImage() = 0; virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) = 0; @@ -151,9 +153,8 @@ protected: nsecs_t mDesiredPresentTime; std::shared_ptr mFenceTime; sp mFence; - float mTransformMatrix[16]; uint32_t mTransform{0}; - ui::Dataspace mDataspace; + ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN}; Rect mCrop; uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE}; Region mSurfaceDamage; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index a9e364a00d..5f7975085a 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -151,13 +151,6 @@ bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) co return mQueueItems[0].mTimestamp <= expectedPresentTime; } -// NOTE: SurfaceFlinger's definitions of "Current" and "Drawing" do not neatly map to BufferQueue's -// These functions get the fields for the frame that is currently in SurfaceFlinger's Drawing state -// so the functions start with "getDrawing". The data is retrieved from the BufferQueueConsumer's -// current buffer so the consumer functions start with "getCurrent". -// -// This results in the rather confusing functions below. - uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const { Mutex::Autolock lock(mQueueItemLock); uint64_t frameNumber = mQueueItems[0].mFrameNumber; @@ -220,10 +213,6 @@ bool BufferQueueLayer::hasFrameUpdate() const { return mQueuedFrames > 0; } -void BufferQueueLayer::setFilteringEnabled(bool enabled) { - return mConsumer->setFilteringEnabled(enabled); -} - status_t BufferQueueLayer::bindTextureImage() { return mConsumer->bindTextureImage(); } @@ -532,7 +521,6 @@ void BufferQueueLayer::gatherBufferInfo() { mBufferInfo.mDesiredPresentTime = mConsumer->getTimestamp(); mBufferInfo.mFenceTime = mConsumer->getCurrentFenceTime(); mBufferInfo.mFence = mConsumer->getCurrentFence(); - mConsumer->getTransformMatrix(mBufferInfo.mTransformMatrix); mBufferInfo.mTransform = mConsumer->getCurrentTransform(); mBufferInfo.mDataspace = translateDataspace(mConsumer->getCurrentDataSpace()); mBufferInfo.mCrop = mConsumer->getCurrentCrop(); diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 43eb3eaab8..9374741ddb 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -46,7 +46,6 @@ public: std::vector getOccupancyHistory(bool forceFlush) override; - // If a buffer was replaced this frame, release the former buffer void releasePendingBuffer(nsecs_t dequeueReadyTime) override; @@ -65,7 +64,6 @@ public: bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override; private: - uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override; bool getAutoRefresh() const override; @@ -75,8 +73,6 @@ private: bool hasFrameUpdate() const override; - void setFilteringEnabled(bool enabled) override; - status_t bindTextureImage() override; status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index afbe22854f..509deaf996 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -432,11 +432,6 @@ bool BufferStateLayer::hasFrameUpdate() const { return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr); } -void BufferStateLayer::setFilteringEnabled(bool enabled) { - GLConsumer::computeTransformMatrix(mTransformMatrix.data(), mBufferInfo.mBuffer, - mBufferInfo.mCrop, mBufferInfo.mTransform, enabled); -} - status_t BufferStateLayer::bindTextureImage() { const State& s(getDrawingState()); auto& engine(mFlinger->getRenderEngine()); @@ -545,10 +540,8 @@ void BufferStateLayer::latchPerFrameState( return; } - const State& s(getDrawingState()); - - compositionState.buffer = s.buffer; - compositionState.bufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId); + compositionState.buffer = mBufferInfo.mBuffer; + compositionState.bufferSlot = mBufferInfo.mBufferSlot; compositionState.acquireFence = mBufferInfo.mFence; mFrameNumber++; @@ -641,8 +634,6 @@ void BufferStateLayer::gatherBufferInfo() { mBufferInfo.mDesiredPresentTime = s.desiredPresentTime; mBufferInfo.mFenceTime = std::make_shared(s.acquireFence); mBufferInfo.mFence = s.acquireFence; - std::copy(std::begin(mTransformMatrix), std::end(mTransformMatrix), - mBufferInfo.mTransformMatrix); mBufferInfo.mTransform = s.transform; mBufferInfo.mDataspace = translateDataspace(s.dataspace); mBufferInfo.mCrop = computeCrop(s); @@ -653,6 +644,7 @@ void BufferStateLayer::gatherBufferInfo() { mBufferInfo.mPixelFormat = !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->format; mBufferInfo.mTransformToDisplayInverse = s.transformToDisplayInverse; + mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId); } Rect BufferStateLayer::computeCrop(const State& s) { diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 0b27d640ce..52063fcc58 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -19,7 +19,6 @@ #include "BufferLayer.h" #include "Layer.h" -#include #include #include #include @@ -108,7 +107,6 @@ protected: void gatherBufferInfo() override; private: - uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override; bool getAutoRefresh() const override; @@ -118,8 +116,6 @@ private: bool hasFrameUpdate() const override; - void setFilteringEnabled(bool enabled) override; - status_t bindTextureImage() override; status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) override; @@ -141,8 +137,6 @@ private: std::unique_ptr mTextureImage; - std::array mTransformMatrix{IDENTITY_MATRIX}; - std::atomic mSidebandStreamChanged{false}; mutable uint32_t mFrameNumber{0}; -- GitLab From 146ecfd99c77fac65597648726f4567100b96d9a Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 29 Jul 2019 16:04:31 -0700 Subject: [PATCH 0273/1255] Use unordered_map for connections Currently, keyedvector is used for keeping track of connections by file descriptors. Instead, use supported api std::unordered_map. Also, no longer remove raw indices into the map, because that's implementation detail of map that should not be user-facing. Bug: 70668286 Test: SANITIZE_TARGET=hwaddress atest libinput_tests inputflinger_tests Change-Id: Id31b0002a7ff2310dcc506f834722b1e69a05571 --- services/inputflinger/InputDispatcher.cpp | 145 ++++++++++++---------- services/inputflinger/InputDispatcher.h | 4 +- 2 files changed, 80 insertions(+), 69 deletions(-) diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 1eb979ef19..c516ab7eed 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -262,12 +262,32 @@ static void dumpRegion(std::string& dump, const Region& region) { * if the entry is not found. * Also useful when the entries are sp<>. If an entry is not found, nullptr is returned. */ -template -static T getValueByKey(const std::unordered_map& map, U key) { +template +static V getValueByKey(const std::unordered_map& map, K key) { auto it = map.find(key); - return it != map.end() ? it->second : T{}; + return it != map.end() ? it->second : V{}; } +/** + * Find the entry in std::unordered_map by value, and remove it. + * If more than one entry has the same value, then all matching + * key-value pairs will be removed. + * + * Return true if at least one value has been removed. + */ +template +static bool removeByValue(std::unordered_map& map, const V& value) { + bool removed = false; + for (auto it = map.begin(); it != map.end();) { + if (it->second == value) { + it = map.erase(it); + removed = true; + } else { + it++; + } + } + return removed; +} // --- InputDispatcher --- @@ -300,8 +320,9 @@ InputDispatcher::~InputDispatcher() { drainInboundQueueLocked(); } - while (mConnectionsByFd.size() != 0) { - unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel); + while (!mConnectionsByFd.empty()) { + sp connection = mConnectionsByFd.begin()->second; + unregisterInputChannel(connection->inputChannel); } } @@ -1072,9 +1093,8 @@ void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, pokeUserActivityLocked(eventEntry); for (const InputTarget& inputTarget : inputTargets) { - ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); - if (connectionIndex >= 0) { - sp connection = mConnectionsByFd.valueAt(connectionIndex); + sp connection = getConnectionLocked(inputTarget.inputChannel); + if (connection != nullptr) { prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); } else { #if DEBUG_FOCUS @@ -1172,21 +1192,18 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout mInputTargetWaitTimeoutExpired = true; // Input state will not be realistic. Mark it out of sync. - if (inputChannel.get()) { - ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); - if (connectionIndex >= 0) { - sp connection = mConnectionsByFd.valueAt(connectionIndex); - sp token = connection->inputChannel->getToken(); - - if (token != nullptr) { - removeWindowByTokenLocked(token); - } + sp connection = getConnectionLocked(inputChannel); + if (connection != nullptr) { + sp token = connection->inputChannel->getToken(); - if (connection->status == Connection::STATUS_NORMAL) { - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, - "application not responding"); - synthesizeCancelationEventsForConnectionLocked(connection, options); - } + if (token != nullptr) { + removeWindowByTokenLocked(token); + } + + if (connection->status == Connection::STATUS_NORMAL) { + CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, + "application not responding"); + synthesizeCancelationEventsForConnectionLocked(connection, options); } } } @@ -1857,16 +1874,15 @@ std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentT } // If the window's connection is not registered then keep waiting. - ssize_t connectionIndex = getConnectionIndexLocked( - getInputChannelLocked(windowHandle->getToken())); - if (connectionIndex < 0) { + sp connection = + getConnectionLocked(getInputChannelLocked(windowHandle->getToken())); + if (connection == nullptr) { return StringPrintf("Waiting because the %s window's input channel is not " "registered with the input dispatcher. The window may be in the process " "of being removed.", targetType); } // If the connection is dead then keep waiting. - sp connection = mConnectionsByFd.valueAt(connectionIndex); if (connection->status != Connection::STATUS_NORMAL) { return StringPrintf("Waiting because the %s window's input connection is %s." "The window may be in the process of being removed.", targetType, @@ -2410,15 +2426,14 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { { // acquire lock std::scoped_lock _l(d->mLock); - ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd); - if (connectionIndex < 0) { + if (d->mConnectionsByFd.find(fd) == d->mConnectionsByFd.end()) { ALOGE("Received spurious receive callback for unknown input channel. " "fd=%d, events=0x%x", fd, events); return 0; // remove the callback } bool notify; - sp connection = d->mConnectionsByFd.valueAt(connectionIndex); + sp connection = d->mConnectionsByFd[fd]; if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) { if (!(events & ALOOPER_EVENT_INPUT)) { ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " @@ -2470,9 +2485,8 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked ( const CancelationOptions& options) { - for (size_t i = 0; i < mConnectionsByFd.size(); i++) { - synthesizeCancelationEventsForConnectionLocked( - mConnectionsByFd.valueAt(i), options); + for (const auto& pair : mConnectionsByFd) { + synthesizeCancelationEventsForConnectionLocked(pair.second, options); } } @@ -2495,11 +2509,12 @@ void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked( void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( const sp& channel, const CancelationOptions& options) { - ssize_t index = getConnectionIndexLocked(channel); - if (index >= 0) { - synthesizeCancelationEventsForConnectionLocked( - mConnectionsByFd.valueAt(index), options); + sp connection = getConnectionLocked(channel); + if (connection == nullptr) { + return; } + + synthesizeCancelationEventsForConnectionLocked(connection, options); } void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( @@ -3586,15 +3601,11 @@ Found: return false; } - sp fromChannel = getInputChannelLocked(fromToken); sp toChannel = getInputChannelLocked(toToken); - ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel); - ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel); - if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) { - sp fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex); - sp toConnection = mConnectionsByFd.valueAt(toConnectionIndex); - + sp fromConnection = getConnectionLocked(fromChannel); + sp toConnection = getConnectionLocked(toChannel); + if (fromConnection != nullptr && toConnection != nullptr) { fromConnection->inputState.copyPointerStateTo(toConnection->inputState); CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "transferring touch focus from this window to another window"); @@ -3815,16 +3826,16 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT "ReplacedKeys: \n"; } - if (!mConnectionsByFd.isEmpty()) { + if (!mConnectionsByFd.empty()) { dump += INDENT "Connections:\n"; - for (size_t i = 0; i < mConnectionsByFd.size(); i++) { - const sp& connection = mConnectionsByFd.valueAt(i); - dump += StringPrintf(INDENT2 "%zu: channelName='%s', windowName='%s', " - "status=%s, monitor=%s, inputPublisherBlocked=%s\n", - i, connection->getInputChannelName().c_str(), - connection->getWindowName().c_str(), - connection->getStatusLabel(), toString(connection->monitor), - toString(connection->inputPublisherBlocked)); + for (const auto& pair : mConnectionsByFd) { + const sp& connection = pair.second; + dump += StringPrintf(INDENT2 "%i: channelName='%s', windowName='%s', " + "status=%s, monitor=%s, inputPublisherBlocked=%s\n", + pair.first, connection->getInputChannelName().c_str(), + connection->getWindowName().c_str(), connection->getStatusLabel(), + toString(connection->monitor), + toString(connection->inputPublisherBlocked)); if (!connection->outboundQueue.empty()) { dump += StringPrintf(INDENT3 "OutboundQueue: length=%zu\n", @@ -3893,8 +3904,8 @@ status_t InputDispatcher::registerInputChannel(const sp& inputChan { // acquire lock std::scoped_lock _l(mLock); - - if (getConnectionIndexLocked(inputChannel) >= 0) { + sp existingConnection = getConnectionLocked(inputChannel); + if (existingConnection != nullptr) { ALOGW("Attempted to register already registered input channel '%s'", inputChannel->getName().c_str()); return BAD_VALUE; @@ -3903,7 +3914,7 @@ status_t InputDispatcher::registerInputChannel(const sp& inputChan sp connection = new Connection(inputChannel, false /*monitor*/); int fd = inputChannel->getFd(); - mConnectionsByFd.add(fd, connection); + mConnectionsByFd[fd] = connection; mInputChannelsByToken[inputChannel->getToken()] = inputChannel; mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); @@ -3932,7 +3943,7 @@ status_t InputDispatcher::registerInputMonitor(const sp& inputChan sp connection = new Connection(inputChannel, true /*monitor*/); const int fd = inputChannel->getFd(); - mConnectionsByFd.add(fd, connection); + mConnectionsByFd[fd] = connection; mInputChannelsByToken[inputChannel->getToken()] = inputChannel; auto& monitorsByDisplay = isGestureMonitor @@ -3970,16 +3981,15 @@ status_t InputDispatcher::unregisterInputChannel(const sp& inputCh status_t InputDispatcher::unregisterInputChannelLocked(const sp& inputChannel, bool notify) { - ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); - if (connectionIndex < 0) { + sp connection = getConnectionLocked(inputChannel); + if (connection == nullptr) { ALOGW("Attempted to unregister already unregistered input channel '%s'", inputChannel->getName().c_str()); return BAD_VALUE; } - sp connection = mConnectionsByFd.valueAt(connectionIndex); - mConnectionsByFd.removeItemsAt(connectionIndex); - + const bool removed = removeByValue(mConnectionsByFd, connection); + ALOG_ASSERT(removed); mInputChannelsByToken.erase(inputChannel->getToken()); if (connection->monitor) { @@ -4079,19 +4089,20 @@ std::optional InputDispatcher::findGestureMonitorDisplayByTokenLocked( return std::nullopt; } -ssize_t InputDispatcher::getConnectionIndexLocked(const sp& inputChannel) { +sp InputDispatcher::getConnectionLocked( + const sp& inputChannel) { if (inputChannel == nullptr) { - return -1; + return nullptr; } - for (size_t i = 0; i < mConnectionsByFd.size(); i++) { - sp connection = mConnectionsByFd.valueAt(i); + for (const auto& pair : mConnectionsByFd) { + sp connection = pair.second; if (connection->inputChannel->getToken() == inputChannel->getToken()) { - return i; + return connection; } } - return -1; + return nullptr; } void InputDispatcher::onDispatchCycleFinishedLocked( diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 92e1e5feb7..e35ba2756b 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -887,7 +887,7 @@ private: bool addOutsideTargets = false, bool addPortalWindows = false) REQUIRES(mLock); // All registered connections mapped by channel file descriptor. - KeyedVector > mConnectionsByFd GUARDED_BY(mLock); + std::unordered_map> mConnectionsByFd GUARDED_BY(mLock); struct IBinderHash { std::size_t operator()(const sp& b) const { @@ -901,7 +901,7 @@ private: std::optional findGestureMonitorDisplayByTokenLocked(const sp& token) REQUIRES(mLock); - ssize_t getConnectionIndexLocked(const sp& inputChannel) REQUIRES(mLock); + sp getConnectionLocked(const sp& inputChannel) REQUIRES(mLock); // Input channels that will receive a copy of all input events sent to the provided display. std::unordered_map> mGlobalMonitorsByDisplay -- GitLab From 913cc1303cb856dd2e0cebc5a94b69a571fd81f9 Mon Sep 17 00:00:00 2001 From: mamik Date: Fri, 13 Sep 2019 14:58:43 -0700 Subject: [PATCH 0274/1255] EDID support for external display hotplug The hardware_composer caches the edid when a new hotplug event fires (connected and disconnected). The display services uses this cached edid when the edid is requested. Bug: 141007548 Test: Manual, ran on mtp device with wave optics plugged in and unplugged and verified edid with: "adb shell dumpsys SurfaceFlinger --display-id" Change-Id: I4556e1d8a3f8677b1d9301d9afbc40d514c86e27 --- libs/vr/libvrflinger/display_service.cpp | 26 ++++++++-------------- libs/vr/libvrflinger/display_service.h | 5 ----- libs/vr/libvrflinger/hardware_composer.cpp | 19 ++++++++++++++++ libs/vr/libvrflinger/hardware_composer.h | 14 ++++++++++++ 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index 5a9360c2ae..582fed3a4a 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -18,6 +18,8 @@ #include #include +#include "DisplayHardware/DisplayIdentification.h" + using android::dvr::display::DisplayProtocol; using android::pdx::Channel; using android::pdx::ErrorStatus; @@ -44,19 +46,6 @@ DisplayService::DisplayService(Hwc2::Composer* hidl, Endpoint::Create(display::DisplayProtocol::kClientPath)) { hardware_composer_.Initialize( hidl, primary_display_id, request_display_callback); - - uint8_t port; - const auto error = hidl->getDisplayIdentificationData( - primary_display_id, &display_identification_port_, - &display_identification_data_); - if (error != android::hardware::graphics::composer::V2_1::Error::NONE) { - if (error != - android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) { - ALOGI("DisplayService: identification data error\n"); - } else { - ALOGI("DisplayService: identification data unsupported\n"); - } - } } bool DisplayService::IsInitialized() const { @@ -212,6 +201,7 @@ Status DisplayService::OnGetMetrics( pdx::Status DisplayService::OnGetConfigurationData( pdx::Message& /*message*/, display::ConfigFileType config_type) { std::string property_name; + DisplayIdentificationData display_identification_data; switch (config_type) { case display::ConfigFileType::kLensMetrics: property_name = kDvrLensMetricsProperty; @@ -223,11 +213,13 @@ pdx::Status DisplayService::OnGetConfigurationData( property_name = kDvrDeviceConfigProperty; break; case display::ConfigFileType::kDeviceEdid: - if (display_identification_data_.size() == 0) { + display_identification_data = + hardware_composer_.GetCurrentDisplayIdentificationData(); + if (display_identification_data.size() == 0) { return ErrorStatus(ENOENT); } - return std::string(display_identification_data_.begin(), - display_identification_data_.end()); + return std::string(display_identification_data.begin(), + display_identification_data.end()); default: return ErrorStatus(EINVAL); } @@ -246,7 +238,7 @@ pdx::Status DisplayService::OnGetConfigurationData( pdx::Status DisplayService::OnGetDisplayIdentificationPort( pdx::Message& /*message*/) { - return display_identification_port_; + return hardware_composer_.GetCurrentDisplayPort(); } // Creates a new DisplaySurface and associates it with this channel. This may diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index 06ba566d32..89f1eaee33 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -18,8 +18,6 @@ #include "epoll_event_dispatcher.h" #include "hardware_composer.h" -#include "DisplayHardware/DisplayIdentification.h" - namespace android { namespace dvr { @@ -120,9 +118,6 @@ class DisplayService : public pdx::ServiceBase { DisplayService(const DisplayService&) = delete; void operator=(const DisplayService&) = delete; - - DisplayIdentificationData display_identification_data_; - uint8_t display_identification_port_; }; } // namespace dvr diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index 9072d89d76..67607af6c4 100644 --- a/libs/vr/libvrflinger/hardware_composer.cpp +++ b/libs/vr/libvrflinger/hardware_composer.cpp @@ -137,6 +137,20 @@ HardwareComposer::~HardwareComposer(void) { composer_callback_->SetVsyncService(nullptr); } +void HardwareComposer::UpdateEdidData(Hwc2::Composer* composer, + hwc2_display_t hw_id) { + const auto error = composer->getDisplayIdentificationData( + hw_id, &display_port_, &display_identification_data_); + if (error != android::hardware::graphics::composer::V2_1::Error::NONE) { + if (error != + android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) { + ALOGI("hardware_composer: identification data error\n"); + } else { + ALOGI("hardware_composer: identification data unsupported\n"); + } + } +} + bool HardwareComposer::Initialize( Hwc2::Composer* composer, hwc2_display_t primary_display_id, RequestDisplayCallback request_display_callback) { @@ -164,6 +178,8 @@ bool HardwareComposer::Initialize( "HardwareComposer: Failed to create interrupt event fd : %s", strerror(errno)); + UpdateEdidData(composer, primary_display_id); + post_thread_ = std::thread(&HardwareComposer::PostThread, this); initialized_ = true; @@ -988,6 +1004,9 @@ bool HardwareComposer::UpdateTargetDisplay() { EnableDisplay(*external_display_, false); } + // Update the cached edid data for the current display. + UpdateEdidData(composer_.get(), target_display_->id); + // Turn the new target display on. EnableDisplay(*target_display_, true); diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h index db0d6a7670..989ce3588d 100644 --- a/libs/vr/libvrflinger/hardware_composer.h +++ b/libs/vr/libvrflinger/hardware_composer.h @@ -25,6 +25,7 @@ #include #include +#include "DisplayHardware/DisplayIdentification.h" #include "acquired_buffer.h" #include "display_surface.h" @@ -334,6 +335,14 @@ class HardwareComposer { int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer); void OnDeletedGlobalBuffer(DvrGlobalBufferKey key); + // Gets the edid data for the current active display (internal or external) + DisplayIdentificationData GetCurrentDisplayIdentificationData() { + return display_identification_data_; + } + + // Gets the edid port for the current active display (internal or external) + uint8_t GetCurrentDisplayPort() { return display_port_; } + private: DisplayParams GetDisplayParams(Hwc2::Composer* composer, hwc2_display_t display, bool is_primary); @@ -544,6 +553,11 @@ class HardwareComposer { bool vsync_trace_parity_ = false; sp vsync_service_; + // Edid section. + void UpdateEdidData(Hwc2::Composer* composer, hwc2_display_t hw_id); + DisplayIdentificationData display_identification_data_; + uint8_t display_port_; + static constexpr int kPostThreadInterrupted = 1; HardwareComposer(const HardwareComposer&) = delete; -- GitLab From c97117b7243afa5244d7f41a7d501edd29250a4b Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Wed, 28 Aug 2019 16:08:35 -0700 Subject: [PATCH 0275/1255] Add a flag for refresh rate switching Some devices don't do refresh rate switching, so we should take that into account when filtering display manager config settings and deciding scheduling behavior. This CL adds a sysprop that can be set to indicate if surface flinger should do refresh rate switching, and modifies surface flinger to have the correct behavior when we're not doing refresh rate switching. Bug: 136592946 Bug: 138261472 Test: Ran through various 60/90 switching scenarios on a device with refresh rate switching. Test: Set the refresh rate switching sysprop to false, and confirmed we get a consistent 60Hz. Test: Inspected dumpsys output and confirmed it looks correct. In particular, refresh rate stats are output correctly. Test: Ran automated tests: RefreshRateConfigsTest, RefreshRateStatsTest, SchedulerTest. Change-Id: I54cd5be9d2c1b9abc8475c3ce39846cbe9f9fe53 Merged-In: I54cd5be9d2c1b9abc8475c3ce39846cbe9f9fe53 --- .../surfaceflinger/Scheduler/PhaseOffsets.cpp | 1 - .../Scheduler/RefreshRateConfigs.h | 184 +++++++++++------ .../Scheduler/RefreshRateStats.h | 71 +++---- .../surfaceflinger/Scheduler/Scheduler.cpp | 108 ++++------ services/surfaceflinger/Scheduler/Scheduler.h | 30 +-- .../surfaceflinger/Scheduler/SchedulerUtils.h | 6 - services/surfaceflinger/SurfaceFlinger.cpp | 194 +++++++++--------- services/surfaceflinger/SurfaceFlinger.h | 5 +- .../SurfaceFlingerProperties.cpp | 8 + .../surfaceflinger/SurfaceFlingerProperties.h | 2 + .../sysprop/SurfaceFlingerProperties.sysprop | 14 +- .../sysprop/api/system-current.txt | 1 + .../tests/unittests/CompositionTest.cpp | 2 +- .../unittests/DisplayTransactionTest.cpp | 12 +- .../unittests/RefreshRateConfigsTest.cpp | 112 +++------- .../tests/unittests/RefreshRateStatsTest.cpp | 139 +++++-------- .../tests/unittests/SchedulerTest.cpp | 19 +- .../tests/unittests/TestableSurfaceFlinger.h | 4 +- 18 files changed, 435 insertions(+), 477 deletions(-) diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 8a2604f4a3..9fa2bbc96e 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -96,7 +96,6 @@ PhaseOffsets::PhaseOffsets() { highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}; - mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets}); mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets}); mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets}); diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index d7300583c3..d8137085dd 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -34,10 +34,9 @@ namespace scheduler { */ class RefreshRateConfigs { public: - // Enum to indicate which vsync rate to run at. Power saving is intended to be the lowest - // (eg. when the screen is in AOD mode or off), default is the old 60Hz, and performance + // Enum to indicate which vsync rate to run at. Default is the old 60Hz, and performance // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs. - enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE }; + enum class RefreshRateType { DEFAULT, PERFORMANCE }; struct RefreshRate { // This config ID corresponds to the position of the config in the vector that is stored @@ -47,26 +46,57 @@ public: std::string name; // Refresh rate in frames per second, rounded to the nearest integer. uint32_t fps = 0; - // config Id (returned from HWC2::Display::Config::getId()) - hwc2_config_t id; + // Vsync period in nanoseconds. + nsecs_t vsyncPeriod; + // Hwc config Id (returned from HWC2::Display::Config::getId()) + hwc2_config_t hwcId; }; + // Returns true if this device is doing refresh rate switching. This won't change at runtime. + bool refreshRateSwitchingSupported() const { return mRefreshRateSwitchingSupported; } + + // Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access + // from multiple threads. This can only be called if refreshRateSwitching() returns true. // TODO(b/122916473): Get this information from configs prepared by vendors, instead of // baking them in. - const std::map>& getRefreshRates() const { - return mRefreshRates; + const std::map& getRefreshRateMap() const { + LOG_ALWAYS_FATAL_IF(!mRefreshRateSwitchingSupported); + return mRefreshRateMap; } - std::shared_ptr getRefreshRate(RefreshRateType type) const { - const auto& refreshRate = mRefreshRates.find(type); - if (refreshRate != mRefreshRates.end()) { + + const RefreshRate& getRefreshRateFromType(RefreshRateType type) const { + if (!mRefreshRateSwitchingSupported) { + return getCurrentRefreshRate().second; + } else { + auto refreshRate = mRefreshRateMap.find(type); + LOG_ALWAYS_FATAL_IF(refreshRate == mRefreshRateMap.end()); return refreshRate->second; } - return nullptr; } - RefreshRateType getRefreshRateType(hwc2_config_t id) const { - for (const auto& [type, refreshRate] : mRefreshRates) { - if (refreshRate->id == id) { + std::pair getCurrentRefreshRate() const { + int currentConfig = mCurrentConfig; + if (mRefreshRateSwitchingSupported) { + for (const auto& [type, refresh] : mRefreshRateMap) { + if (refresh.configId == currentConfig) { + return {type, refresh}; + } + } + LOG_ALWAYS_FATAL(); + } + return {RefreshRateType::DEFAULT, mRefreshRates[currentConfig]}; + } + + const RefreshRate& getRefreshRateFromConfigId(int configId) const { + LOG_ALWAYS_FATAL_IF(configId >= mRefreshRates.size()); + return mRefreshRates[configId]; + } + + RefreshRateType getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const { + if (!mRefreshRateSwitchingSupported) return RefreshRateType::DEFAULT; + + for (const auto& [type, refreshRate] : mRefreshRateMap) { + if (refreshRate.hwcId == hwcId) { return type; } } @@ -74,64 +104,102 @@ public: return RefreshRateType::DEFAULT; } - void populate(const std::vector>& configs) { - mRefreshRates.clear(); + void setCurrentConfig(int config) { + LOG_ALWAYS_FATAL_IF(config >= mRefreshRates.size()); + mCurrentConfig = config; + } - // This is the rate that HWC encapsulates right now when the device is in DOZE mode. - mRefreshRates.emplace(RefreshRateType::POWER_SAVING, - std::make_shared( - RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, - HWC2_SCREEN_OFF_CONFIG_ID})); + struct InputConfig { + hwc2_config_t hwcId = 0; + nsecs_t vsyncPeriod = 0; + }; - if (configs.size() < 1) { - ALOGE("Device does not have valid configs. Config size is 0."); - return; + RefreshRateConfigs(bool refreshRateSwitching, const std::vector& configs, + int currentConfig) { + init(refreshRateSwitching, configs, currentConfig); + } + + RefreshRateConfigs(bool refreshRateSwitching, + const std::vector>& configs, + int currentConfig) { + std::vector inputConfigs; + for (const auto& config : configs) { + inputConfigs.push_back({config->getId(), config->getVsyncPeriod()}); } + init(refreshRateSwitching, inputConfigs, currentConfig); + } + +private: + void init(bool refreshRateSwitching, const std::vector& configs, + int currentConfig) { + mRefreshRateSwitchingSupported = refreshRateSwitching; + LOG_ALWAYS_FATAL_IF(configs.empty()); + LOG_ALWAYS_FATAL_IF(currentConfig >= configs.size()); + mCurrentConfig = currentConfig; + + auto buildRefreshRate = [&](int configId) -> RefreshRate { + const nsecs_t vsyncPeriod = configs[configId].vsyncPeriod; + const float fps = 1e9 / vsyncPeriod; + return {configId, base::StringPrintf("%2.ffps", fps), static_cast(fps), + vsyncPeriod, configs[configId].hwcId}; + }; - // Create a map between config index and vsync period. This is all the info we need - // from the configs. - std::vector> configIdToVsyncPeriod; for (int i = 0; i < configs.size(); ++i) { - configIdToVsyncPeriod.emplace_back(i, configs.at(i)->getVsyncPeriod()); + mRefreshRates.push_back(buildRefreshRate(i)); } - std::sort(configIdToVsyncPeriod.begin(), configIdToVsyncPeriod.end(), - [](const std::pair& a, const std::pair& b) { - return a.second > b.second; - }); + if (!mRefreshRateSwitchingSupported) return; - // When the configs are ordered by the resync rate. We assume that the first one is DEFAULT. - nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second; - if (vsyncPeriod != 0) { - const float fps = 1e9 / vsyncPeriod; - const int configId = configIdToVsyncPeriod[0].first; - mRefreshRates.emplace(RefreshRateType::DEFAULT, - std::make_shared( - RefreshRate{configId, base::StringPrintf("%2.ffps", fps), - static_cast(fps), - configs.at(configId)->getId()})); - } + auto findDefaultAndPerfConfigs = [&]() -> std::optional> { + if (configs.size() < 2) { + return {}; + } - if (configs.size() < 2) { + std::vector sortedRefreshRates; + for (const auto& refreshRate : mRefreshRates) { + sortedRefreshRates.push_back(&refreshRate); + } + std::sort(sortedRefreshRates.begin(), sortedRefreshRates.end(), + [](const RefreshRate* refreshRate1, const RefreshRate* refreshRate2) { + return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod; + }); + + // When the configs are ordered by the resync rate, we assume that + // the first one is DEFAULT and the second one is PERFORMANCE, + // i.e. the higher rate. + if (sortedRefreshRates[0]->vsyncPeriod == 0 || + sortedRefreshRates[1]->vsyncPeriod == 0) { + return {}; + } + + return std::pair(sortedRefreshRates[0]->configId, + sortedRefreshRates[1]->configId); + }; + + auto defaultAndPerfConfigs = findDefaultAndPerfConfigs(); + if (!defaultAndPerfConfigs) { + mRefreshRateSwitchingSupported = false; return; } - // When the configs are ordered by the resync rate. We assume that the second one is - // PERFORMANCE, eg. the higher rate. - vsyncPeriod = configIdToVsyncPeriod[1].second; - if (vsyncPeriod != 0) { - const float fps = 1e9 / vsyncPeriod; - const int configId = configIdToVsyncPeriod[1].first; - mRefreshRates.emplace(RefreshRateType::PERFORMANCE, - std::make_shared( - RefreshRate{configId, base::StringPrintf("%2.ffps", fps), - static_cast(fps), - configs.at(configId)->getId()})); - } + mRefreshRateMap[RefreshRateType::DEFAULT] = mRefreshRates[defaultAndPerfConfigs->first]; + mRefreshRateMap[RefreshRateType::PERFORMANCE] = + mRefreshRates[defaultAndPerfConfigs->second]; } -private: - std::map> mRefreshRates; + // Whether this device is doing refresh rate switching or not. This must not change after this + // object is initialized. + bool mRefreshRateSwitchingSupported; + // The list of refresh rates, indexed by display config ID. This must not change after this + // object is initialized. + std::vector mRefreshRates; + // The mapping of refresh rate type to RefreshRate. This must not change after this object is + // initialized. + std::map mRefreshRateMap; + // The ID of the current config. This will change at runtime. This is set by SurfaceFlinger on + // the main thread, and read by the Scheduler (and other objects) on other threads, so it's + // atomic. + std::atomic mCurrentConfig; }; } // namespace scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h index 7e7c6307a4..947eb08d90 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateStats.h +++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h @@ -41,21 +41,18 @@ class RefreshRateStats { static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR; public: - RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats) - : mRefreshRateConfigs(refreshRateConfigs), mTimeStats(timeStats) {} - - // Sets power mode. We only collect the information when the power mode is not - // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based - // on config mode. + RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats, + int currentConfigMode, int currentPowerMode) + : mRefreshRateConfigs(refreshRateConfigs), + mTimeStats(timeStats), + mCurrentConfigMode(currentConfigMode), + mCurrentPowerMode(currentPowerMode) {} + + // Sets power mode. void setPowerMode(int mode) { if (mCurrentPowerMode == mode) { return; } - // If power mode is normal, the time is going to be recorded under config modes. - if (mode == HWC_POWER_MODE_NORMAL) { - mCurrentPowerMode = mode; - return; - } flushTime(); mCurrentPowerMode = mode; } @@ -79,16 +76,15 @@ public: flushTime(); std::unordered_map totalTime; - for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) { - int64_t totalTimeForConfig = 0; - if (!config) { - continue; - } - if (mConfigModesTotalTime.find(config->configId) != mConfigModesTotalTime.end()) { - totalTimeForConfig = mConfigModesTotalTime.at(config->configId); - } - totalTime[config->name] = totalTimeForConfig; + // Multiple configs may map to the same name, e.g. "60fps". Add the + // times for such configs together. + for (const auto& [config, time] : mConfigModesTotalTime) { + totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] = 0; + } + for (const auto& [config, time] : mConfigModesTotalTime) { + totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] += time; } + totalTime["ScreenOff"] = mScreenOffTime; return totalTime; } @@ -104,32 +100,26 @@ public: } private: - void flushTime() { - // Normal power mode is counted under different config modes. - if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) { - flushTimeForMode(mCurrentConfigMode); - } else { - flushTimeForMode(SCREEN_OFF_CONFIG_ID); - } - } - // Calculates the time that passed in ms between the last time we recorded time and the time // this method was called. - void flushTimeForMode(int mode) { + void flushTime() { nsecs_t currentTime = systemTime(); nsecs_t timeElapsed = currentTime - mPreviousRecordedTime; int64_t timeElapsedMs = ns2ms(timeElapsed); mPreviousRecordedTime = currentTime; - mConfigModesTotalTime[mode] += timeElapsedMs; - for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) { - if (!config) { - continue; - } - if (config->configId == mode) { - mTimeStats.recordRefreshRate(config->fps, timeElapsed); + uint32_t fps = 0; + if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) { + // Normal power mode is counted under different config modes. + if (mConfigModesTotalTime.find(mCurrentConfigMode) == mConfigModesTotalTime.end()) { + mConfigModesTotalTime[mCurrentConfigMode] = 0; } + mConfigModesTotalTime[mCurrentConfigMode] += timeElapsedMs; + fps = mRefreshRateConfigs.getRefreshRateFromConfigId(mCurrentConfigMode).fps; + } else { + mScreenOffTime += timeElapsedMs; } + mTimeStats.recordRefreshRate(fps, timeElapsed); } // Formats the time in milliseconds into easy to read format. @@ -149,10 +139,11 @@ private: // Aggregate refresh rate statistics for telemetry. TimeStats& mTimeStats; - int64_t mCurrentConfigMode = SCREEN_OFF_CONFIG_ID; - int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF; + int mCurrentConfigMode; + int32_t mCurrentPowerMode; - std::unordered_map mConfigModesTotalTime; + std::unordered_map mConfigModesTotalTime; + int64_t mScreenOffTime = 0; nsecs_t mPreviousRecordedTime = systemTime(); }; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index a194106112..3b02541ef4 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -133,7 +133,6 @@ Scheduler::~Scheduler() { sp Scheduler::createConnection( const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync, - ResyncCallback resyncCallback, impl::EventThread::InterceptVSyncsCallback interceptCallback) { const int64_t id = sNextId++; ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id); @@ -143,8 +142,7 @@ sp Scheduler::createConnection( offsetThresholdForNextVsync, std::move(interceptCallback)); auto eventThreadConnection = - createConnectionInternal(eventThread.get(), std::move(resyncCallback), - ISurfaceComposer::eConfigChangedSuppress); + createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress); mConnections.emplace(id, std::make_unique(new ConnectionHandle(id), eventThreadConnection, @@ -164,17 +162,15 @@ std::unique_ptr Scheduler::makeEventThread( } sp Scheduler::createConnectionInternal( - EventThread* eventThread, ResyncCallback&& resyncCallback, - ISurfaceComposer::ConfigChanged configChanged) { - return eventThread->createEventConnection(std::move(resyncCallback), configChanged); + EventThread* eventThread, ISurfaceComposer::ConfigChanged configChanged) { + return eventThread->createEventConnection([&] { resync(); }, configChanged); } sp Scheduler::createDisplayEventConnection( - const sp& handle, ResyncCallback resyncCallback, + const sp& handle, ISurfaceComposer::ConfigChanged configChanged) { RETURN_VALUE_IF_INVALID(nullptr); - return createConnectionInternal(mConnections[handle->id]->thread.get(), - std::move(resyncCallback), configChanged); + return createConnectionInternal(mConnections[handle->id]->thread.get(), configChanged); } EventThread* Scheduler::getEventThread(const sp& handle) { @@ -264,23 +260,15 @@ void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) { setVsyncPeriod(period); } -ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) { - std::weak_ptr ptr = mPrimaryVsyncState; - return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() { - if (const auto vsync = ptr.lock()) { - vsync->resync(getVsyncPeriod); - } - }; -} - -void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) { +void Scheduler::resync() { static constexpr nsecs_t kIgnoreDelay = ms2ns(500); const nsecs_t now = systemTime(); - const nsecs_t last = lastResyncTime.exchange(now); + const nsecs_t last = mLastResyncTime.exchange(now); if (now - last > kIgnoreDelay) { - scheduler.resyncToHardwareVsync(false, getVsyncPeriod()); + resyncToHardwareVsync(false, + mRefreshRateConfigs.getCurrentRefreshRate().second.vsyncPeriod); } } @@ -338,15 +326,19 @@ void Scheduler::dumpPrimaryDispSync(std::string& result) const { std::unique_ptr Scheduler::registerLayer( std::string const& name, int windowType) { - RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER) - ? RefreshRateType::DEFAULT - : RefreshRateType::PERFORMANCE; - - const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType); - const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0; - - const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT); - const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0; + uint32_t defaultFps, performanceFps; + if (mRefreshRateConfigs.refreshRateSwitchingSupported()) { + defaultFps = mRefreshRateConfigs.getRefreshRateFromType(RefreshRateType::DEFAULT).fps; + performanceFps = + mRefreshRateConfigs + .getRefreshRateFromType((windowType == InputWindowInfo::TYPE_WALLPAPER) + ? RefreshRateType::DEFAULT + : RefreshRateType::PERFORMANCE) + .fps; + } else { + defaultFps = mRefreshRateConfigs.getCurrentRefreshRate().second.fps; + performanceFps = defaultFps; + } return mLayerHistory.createLayer(name, defaultFps, performanceFps); } @@ -398,17 +390,6 @@ void Scheduler::setChangeRefreshRateCallback( mChangeRefreshRateCallback = changeRefreshRateCallback; } -void Scheduler::setGetCurrentRefreshRateTypeCallback( - const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateTypeCallback) { - std::lock_guard lock(mCallbackLock); - mGetCurrentRefreshRateTypeCallback = getCurrentRefreshRateTypeCallback; -} - -void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) { - std::lock_guard lock(mCallbackLock); - mGetVsyncPeriod = getVsyncPeriod; -} - void Scheduler::updateFrameSkipping(const int64_t skipCount) { ATRACE_INT("FrameSkipCount", skipCount); if (mSkipCount != skipCount) { @@ -460,14 +441,12 @@ void Scheduler::resetTimerCallback() { void Scheduler::resetKernelTimerCallback() { ATRACE_INT("ExpiredKernelIdleTimer", 0); - std::lock_guard lock(mCallbackLock); - if (mGetVsyncPeriod && mGetCurrentRefreshRateTypeCallback) { - // If we're not in performance mode then the kernel timer shouldn't do - // anything, as the refresh rate during DPU power collapse will be the - // same. - if (mGetCurrentRefreshRateTypeCallback() == Scheduler::RefreshRateType::PERFORMANCE) { - resyncToHardwareVsync(true, mGetVsyncPeriod()); - } + const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate(); + // If we're not in performance mode then the kernel timer shouldn't do + // anything, as the refresh rate during DPU power collapse will be the + // same. + if (refreshRate.first == Scheduler::RefreshRateType::PERFORMANCE) { + resyncToHardwareVsync(true, refreshRate.second.vsyncPeriod); } } @@ -499,13 +478,12 @@ void Scheduler::expiredDisplayPowerTimerCallback() { void Scheduler::expiredKernelTimerCallback() { std::lock_guard lock(mCallbackLock); ATRACE_INT("ExpiredKernelIdleTimer", 1); - if (mGetCurrentRefreshRateTypeCallback) { - if (mGetCurrentRefreshRateTypeCallback() != Scheduler::RefreshRateType::PERFORMANCE) { - // Disable HW Vsync if the timer expired, as we don't need it - // enabled if we're not pushing frames, and if we're in PERFORMANCE - // mode then we'll need to re-update the DispSync model anyways. - disableHardwareVsync(false); - } + if (mRefreshRateConfigs.getCurrentRefreshRate().first != + Scheduler::RefreshRateType::PERFORMANCE) { + // Disable HW Vsync if the timer expired, as we don't need it + // enabled if we're not pushing frames, and if we're in PERFORMANCE + // mode then we'll need to re-update the DispSync model anyways. + disableHardwareVsync(false); } } @@ -540,6 +518,10 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO } Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { + if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) { + return RefreshRateType::DEFAULT; + } + // HDR content is not supported on PERFORMANCE mode if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) { return RefreshRateType::DEFAULT; @@ -567,11 +549,11 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { } // Content detection is on, find the appropriate refresh rate with minimal error - auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(), - mRefreshRateConfigs.getRefreshRates().cend(), + auto iter = min_element(mRefreshRateConfigs.getRefreshRateMap().cbegin(), + mRefreshRateConfigs.getRefreshRateMap().cend(), [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool { - return std::abs(l.second->fps - static_cast(rate)) < - std::abs(r.second->fps - static_cast(rate)); + return std::abs(l.second.fps - static_cast(rate)) < + std::abs(r.second.fps - static_cast(rate)); }); RefreshRateType currRefreshRateType = iter->first; @@ -579,11 +561,11 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't // align well with both constexpr float MARGIN = 0.05f; - float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / + float ratio = mRefreshRateConfigs.getRefreshRateFromType(currRefreshRateType).fps / float(mContentRefreshRate); if (std::abs(std::round(ratio) - ratio) > MARGIN) { - while (iter != mRefreshRateConfigs.getRefreshRates().cend()) { - ratio = iter->second->fps / float(mContentRefreshRate); + while (iter != mRefreshRateConfigs.getRefreshRateMap().cend()) { + ratio = iter->second.fps / float(mContentRefreshRate); if (std::abs(std::round(ratio) - ratio) <= MARGIN) { currRefreshRateType = iter->first; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 5d8bb4cd2f..da0a015109 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -49,9 +49,7 @@ public: } using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; - using GetCurrentRefreshRateTypeCallback = std::function; using ChangeRefreshRateCallback = std::function; - using GetVsyncPeriod = std::function; // Enum to indicate whether to start the transaction early, or at vsync time. enum class TransactionStart { EARLY, NORMAL }; @@ -81,16 +79,6 @@ public: const std::unique_ptr thread; }; - // Stores per-display state about VSYNC. - struct VsyncState { - explicit VsyncState(Scheduler& scheduler) : scheduler(scheduler) {} - - void resync(const GetVsyncPeriod&); - - Scheduler& scheduler; - std::atomic lastResyncTime = 0; - }; - explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, const scheduler::RefreshRateConfigs& refreshRateConfig); @@ -98,12 +86,11 @@ public: /** Creates an EventThread connection. */ sp createConnection(const char* connectionName, nsecs_t phaseOffsetNs, - nsecs_t offsetThresholdForNextVsync, ResyncCallback, + nsecs_t offsetThresholdForNextVsync, impl::EventThread::InterceptVSyncsCallback); sp createDisplayEventConnection( - const sp& handle, ResyncCallback, - ISurfaceComposer::ConfigChanged configChanged); + const sp& handle, ISurfaceComposer::ConfigChanged configChanged); // Getter methods. EventThread* getEventThread(const sp& handle); @@ -143,8 +130,7 @@ public: // no-op. // The period is the vsync period from the current display configuration. void resyncToHardwareVsync(bool makeAvailable, nsecs_t period); - // Creates a callback for resyncing. - ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod); + void resync(); void setRefreshSkipCount(int count); // Passes a vsync sample to DispSync. periodFlushed will be true if // DispSync detected that the vsync period changed, and false otherwise. @@ -167,9 +153,6 @@ public: void updateFpsBasedOnContent(); // Callback that gets invoked when Scheduler wants to change the refresh rate. void setChangeRefreshRateCallback(const ChangeRefreshRateCallback&& changeRefreshRateCallback); - void setGetCurrentRefreshRateTypeCallback( - const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateType); - void setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod); // Returns whether idle timer is enabled or not bool isIdleTimerEnabled() { return mSetIdleTimerMs > 0; } @@ -206,7 +189,7 @@ private: enum class DisplayPowerTimerState { EXPIRED, RESET }; // Creates a connection on the given EventThread and forwards the given callbacks. - sp createConnectionInternal(EventThread*, ResyncCallback&&, + sp createConnectionInternal(EventThread*, ISurfaceComposer::ConfigChanged); nsecs_t calculateAverage() const; @@ -261,7 +244,8 @@ private: std::mutex mHWVsyncLock; bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock); bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock); - const std::shared_ptr mPrimaryVsyncState{std::make_shared(*this)}; + + std::atomic mLastResyncTime = 0; std::unique_ptr mPrimaryDispSync; std::unique_ptr mEventControlThread; @@ -297,9 +281,7 @@ private: std::unique_ptr mDisplayPowerTimer; std::mutex mCallbackLock; - GetCurrentRefreshRateTypeCallback mGetCurrentRefreshRateTypeCallback GUARDED_BY(mCallbackLock); ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock); - GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock); // In order to make sure that the features don't override themselves, we need a state machine // to keep track which feature requested the config change. diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h index ced1899109..8649a16af2 100644 --- a/services/surfaceflinger/Scheduler/SchedulerUtils.h +++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h @@ -30,12 +30,6 @@ using namespace std::chrono_literals; // about layers. static constexpr size_t ARRAY_SIZE = 30; -// This number is used to have a place holder for when the screen is not NORMAL/ON. Currently -// the config is not visible to SF, and is completely maintained by HWC. However, we would -// still like to keep track of time when the device is in this config. -static constexpr int SCREEN_OFF_CONFIG_ID = -1; -static constexpr uint32_t HWC2_SCREEN_OFF_CONFIG_ID = 0xffffffff; - // This number is used when we try to determine how long do we keep layer information around // before we remove it. It is also used to determine how long the layer stays relevant. // This time period captures infrequent updates when playing YouTube video with static image, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 42188d1089..da184873df 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -564,14 +564,16 @@ void SurfaceFlinger::bootFinished() readPersistentProperties(); mBootStage = BootStage::FINISHED; - // set the refresh rate according to the policy - const auto& performanceRefreshRate = - mRefreshRateConfigs.getRefreshRate(RefreshRateType::PERFORMANCE); + if (mRefreshRateConfigs->refreshRateSwitchingSupported()) { + // set the refresh rate according to the policy + const auto& performanceRefreshRate = + mRefreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE); - if (performanceRefreshRate && isDisplayConfigAllowed(performanceRefreshRate->configId)) { - setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); - } else { - setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); + if (isDisplayConfigAllowed(performanceRefreshRate.configId)) { + setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); + } else { + setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); + } } })); } @@ -614,32 +616,6 @@ void SurfaceFlinger::init() { ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset()); Mutex::Autolock _l(mStateLock); - // start the EventThread - mScheduler = - getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); }, - mRefreshRateConfigs); - auto resyncCallback = - mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this)); - - mAppConnectionHandle = - mScheduler->createConnection("app", mVsyncModulator.getOffsets().app, - mPhaseOffsets->getOffsetThresholdForNextVsync(), - resyncCallback, - impl::EventThread::InterceptVSyncsCallback()); - mSfConnectionHandle = - mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf, - mPhaseOffsets->getOffsetThresholdForNextVsync(), - resyncCallback, [this](nsecs_t timestamp) { - mInterceptor->saveVSyncEvent(timestamp); - }); - - mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle)); - mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(), - mSfConnectionHandle.get()); - - mRegionSamplingThread = - new RegionSamplingThread(*this, *mScheduler, - RegionSamplingThread::EnvironmentTimingTunables()); // Get a RenderEngine for the given display / config (can't fail) int32_t renderEngineFeature = 0; @@ -710,37 +686,6 @@ void SurfaceFlinger::init() { ALOGE("Run StartPropertySetThread failed!"); } - mScheduler->setChangeRefreshRateCallback( - [this](RefreshRateType type, Scheduler::ConfigEvent event) { - Mutex::Autolock lock(mStateLock); - setRefreshRateTo(type, event); - }); - mScheduler->setGetCurrentRefreshRateTypeCallback([this] { - Mutex::Autolock lock(mStateLock); - const auto display = getDefaultDisplayDeviceLocked(); - if (!display) { - // If we don't have a default display the fallback to the default - // refresh rate type - return RefreshRateType::DEFAULT; - } - - const int configId = display->getActiveConfig(); - for (const auto& [type, refresh] : mRefreshRateConfigs.getRefreshRates()) { - if (refresh && refresh->configId == configId) { - return type; - } - } - // This should never happen, but just gracefully fallback to default. - return RefreshRateType::DEFAULT; - }); - mScheduler->setGetVsyncPeriodCallback([this] { - Mutex::Autolock lock(mStateLock); - return getVsyncPeriod(); - }); - - mRefreshRateConfigs.populate(getHwComposer().getConfigs(*display->getId())); - mRefreshRateStats.setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId())); - ALOGV("Done initializing"); } @@ -894,7 +839,8 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, info.xdpi = xdpi; info.ydpi = ydpi; info.fps = 1e9 / hwConfig->getVsyncPeriod(); - const auto refreshRateType = mRefreshRateConfigs.getRefreshRateType(hwConfig->getId()); + const auto refreshRateType = + mRefreshRateConfigs->getRefreshRateTypeFromHwcConfigId(hwConfig->getId()); const auto offset = mPhaseOffsets->getOffsetsForRefreshRate(refreshRateType); info.appVsyncOffset = offset.late.app; @@ -996,7 +942,8 @@ void SurfaceFlinger::setActiveConfigInternal() { } std::lock_guard lock(mActiveConfigLock); - mRefreshRateStats.setConfigMode(mUpcomingActiveConfig.configId); + mRefreshRateConfigs->setCurrentConfig(mUpcomingActiveConfig.configId); + mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId); display->setActiveConfig(mUpcomingActiveConfig.configId); @@ -1275,9 +1222,6 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { return; } - auto resyncCallback = - mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this)); - // TODO(b/128863962): Part of the Injector should be refactored, so that it // can be passed to Scheduler. if (enable) { @@ -1289,11 +1233,11 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { impl::EventThread::InterceptVSyncsCallback(), "injEventThread"); } - mEventQueue->setEventThread(mInjectorEventThread.get(), std::move(resyncCallback)); + mEventQueue->setEventThread(mInjectorEventThread.get(), [&] { mScheduler->resync(); }); } else { ALOGV("VSync Injections disabled"); mEventQueue->setEventThread(mScheduler->getEventThread(mSfConnectionHandle), - std::move(resyncCallback)); + [&] { mScheduler->resync(); }); } mInjectVSyncs = enable; @@ -1404,16 +1348,10 @@ status_t SurfaceFlinger::notifyPowerHint(int32_t hintId) { sp SurfaceFlinger::createDisplayEventConnection( ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) { - auto resyncCallback = mScheduler->makeResyncCallback([this] { - Mutex::Autolock lock(mStateLock); - return getVsyncPeriod(); - }); - const auto& handle = vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle; - return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback), - configChanged); + return mScheduler->createDisplayEventConnection(handle, configChanged); } // ---------------------------------------------------------------------------- @@ -1510,13 +1448,8 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::Co ATRACE_CALL(); // Don't do any updating if the current fps is the same as the new one. - const auto& refreshRateConfig = mRefreshRateConfigs.getRefreshRate(refreshRate); - if (!refreshRateConfig) { - ALOGV("Skipping refresh rate change request for unsupported rate."); - return; - } - - const int desiredConfigId = refreshRateConfig->configId; + const auto& refreshRateConfig = mRefreshRateConfigs->getRefreshRateFromType(refreshRate); + const int desiredConfigId = refreshRateConfig.configId; if (!isDisplayConfigAllowed(desiredConfigId)) { ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId); @@ -2599,6 +2532,9 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { if (event.connection == HWC2::Connection::Connected) { if (!mPhysicalDisplayTokens.count(info->id)) { ALOGV("Creating display %s", to_string(info->id).c_str()); + if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) { + initScheduler(info->id); + } mPhysicalDisplayTokens[info->id] = new BBinder(); DisplayDeviceState state; state.displayId = info->id; @@ -3057,6 +2993,56 @@ void SurfaceFlinger::latchAndReleaseBuffer(const sp& layer) { layer->releasePendingBuffer(systemTime()); } +void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { + if (mScheduler) { + // In practice it's not allowed to hotplug in/out the primary display once it's been + // connected during startup, but some tests do it, so just warn and return. + ALOGW("Can't re-init scheduler"); + return; + } + + int currentConfig = getHwComposer().getActiveConfigIndex(primaryDisplayId); + mRefreshRateConfigs = + std::make_unique(refresh_rate_switching(false), + getHwComposer().getConfigs( + primaryDisplayId), + currentConfig); + mRefreshRateStats = + std::make_unique(*mRefreshRateConfigs, *mTimeStats, + currentConfig, HWC_POWER_MODE_OFF); + mRefreshRateStats->setConfigMode(currentConfig); + + // start the EventThread + mScheduler = + getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); }, + *mRefreshRateConfigs); + + mAppConnectionHandle = + mScheduler->createConnection("app", mVsyncModulator.getOffsets().app, + mPhaseOffsets->getOffsetThresholdForNextVsync(), + impl::EventThread::InterceptVSyncsCallback()); + mSfConnectionHandle = + mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf, + mPhaseOffsets->getOffsetThresholdForNextVsync(), + [this](nsecs_t timestamp) { + mInterceptor->saveVSyncEvent(timestamp); + }); + + mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle)); + mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(), + mSfConnectionHandle.get()); + + mRegionSamplingThread = + new RegionSamplingThread(*this, *mScheduler, + RegionSamplingThread::EnvironmentTimingTunables()); + + mScheduler->setChangeRefreshRateCallback( + [this](RefreshRateType type, Scheduler::ConfigEvent event) { + Mutex::Autolock lock(mStateLock); + setRefreshRateTo(type, event); + }); +} + void SurfaceFlinger::commitTransaction() { if (!mLayersPendingRemoval.isEmpty()) { @@ -4562,7 +4548,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, int if (display->isPrimary()) { mTimeStats->setPowerMode(mode); - mRefreshRateStats.setPowerMode(mode); + mRefreshRateStats->setPowerMode(mode); mScheduler->setDisplayPowerState(mode == HWC_POWER_MODE_NORMAL); } @@ -4730,11 +4716,8 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { mUseSmart90ForVideo ? "on" : "off"); StringAppendF(&result, "Allowed Display Configs: "); for (int32_t configId : mAllowedDisplayConfigs) { - for (auto refresh : mRefreshRateConfigs.getRefreshRates()) { - if (refresh.second && refresh.second->configId == configId) { - StringAppendF(&result, "%dHz, ", refresh.second->fps); - } - } + StringAppendF(&result, "%" PRIu32 " Hz, ", + mRefreshRateConfigs->getRefreshRateFromConfigId(configId).fps); } StringAppendF(&result, "(config override by backdoor: %s)\n\n", mDebugDisplayConfigSetByBackdoor ? "yes" : "no"); @@ -5100,8 +5083,10 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co */ result.append("\nScheduler state:\n"); result.append(mScheduler->doDump() + "\n"); + StringAppendF(&result, "+ Refresh rate switching: %s\n", + mRefreshRateConfigs->refreshRateSwitchingSupported() ? "on" : "off"); StringAppendF(&result, "+ Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off"); - result.append(mRefreshRateStats.doDump() + "\n"); + result.append(mRefreshRateStats->doDump() + "\n"); result.append(mTimeStats->miniDump()); result.append("\n"); @@ -5567,7 +5552,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r case 1034: { // TODO(b/129297325): expose this via developer menu option n = data.readInt32(); - if (n && !mRefreshRateOverlay) { + if (n && !mRefreshRateOverlay && + mRefreshRateConfigs->refreshRateSwitchingSupported()) { RefreshRateType type; { std::lock_guard lock(mActiveConfigLock); @@ -6154,15 +6140,21 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp& d ALOGV("Updating allowed configs"); mAllowedDisplayConfigs = DisplayConfigs(allowedConfigs.begin(), allowedConfigs.end()); - // Set the highest allowed config by iterating backwards on available refresh rates - const auto& refreshRates = mRefreshRateConfigs.getRefreshRates(); - for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) { - if (iter->second && isDisplayConfigAllowed(iter->second->configId)) { - ALOGV("switching to config %d", iter->second->configId); - setDesiredActiveConfig( - {iter->first, iter->second->configId, Scheduler::ConfigEvent::Changed}); - break; + if (mRefreshRateConfigs->refreshRateSwitchingSupported()) { + // Set the highest allowed config by iterating backwards on available refresh rates + const auto& refreshRates = mRefreshRateConfigs->getRefreshRateMap(); + for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) { + if (isDisplayConfigAllowed(iter->second.configId)) { + ALOGV("switching to allowed config %d", iter->second.configId); + setDesiredActiveConfig( + {iter->first, iter->second.configId, Scheduler::ConfigEvent::Changed}); + break; + } } + } else if (!allowedConfigs.empty()) { + ALOGV("switching to config %d", allowedConfigs[0]); + setDesiredActiveConfig( + {RefreshRateType::DEFAULT, allowedConfigs[0], Scheduler::ConfigEvent::Changed}); } } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index ec0b7c54be..17642d4fba 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -553,6 +553,7 @@ private: void executeInputWindowCommands(); void setInputWindowsFinished(); void updateCursorAsync(); + void initScheduler(DisplayId primaryDisplayId); /* handlePageFlip - latch a new buffer if available and compute the dirty * region. Returns whether a new buffer has been latched, i.e., whether it @@ -1129,8 +1130,8 @@ private: sp mAppConnectionHandle; sp mSfConnectionHandle; - scheduler::RefreshRateConfigs mRefreshRateConfigs; - scheduler::RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, *mTimeStats}; + std::unique_ptr mRefreshRateConfigs; + std::unique_ptr mRefreshRateStats; // All configs are allowed if the set is empty. using DisplayConfigs = std::set; diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 3eedb67362..327e9bb43f 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -218,6 +218,14 @@ int32_t wcg_composition_pixel_format(PixelFormat defaultValue) { return static_cast(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 68986f7c4c..ac350295f3 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -70,6 +70,8 @@ int64_t wcg_composition_dataspace( int32_t wcg_composition_pixel_format( android::hardware::graphics::common::V1_2::PixelFormat 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/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index c77137a0d7..b7a909d0d0 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -15,7 +15,7 @@ module: "android.sysprop.SurfaceFlingerProperties" owner: Platform -# The following two propertiess define (respectively): +# The following two properties define (respectively): # # - The phase offset between hardware vsync and when apps are woken up by the # Choreographer callback @@ -287,6 +287,18 @@ prop { 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" +} + # setIdleTimerMs indicates what is considered a timeout in milliseconds for Scheduler. This value is # used by the Scheduler to trigger inactivity callbacks that will switch the display to a lower # refresh rate. Setting this property to 0 means there is no timer. diff --git a/services/surfaceflinger/sysprop/api/system-current.txt b/services/surfaceflinger/sysprop/api/system-current.txt index 794c1d6ae9..f26ad16bc1 100644 --- a/services/surfaceflinger/sysprop/api/system-current.txt +++ b/services/surfaceflinger/sysprop/api/system-current.txt @@ -16,6 +16,7 @@ package android.sysprop { method public static java.util.Optional max_virtual_display_dimension(); method public static java.util.Optional present_time_offset_from_vsync_ns(); method public static java.util.Optional primary_display_orientation(); + method public static java.util.Optional refresh_rate_switching(); method public static java.util.Optional running_without_sync_framework(); method public static java.util.Optional set_display_power_timer_ms(); method public static java.util.Optional set_idle_timer_ms(); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 4f8ed1ae1c..57df9a2c68 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -125,7 +125,7 @@ public: } void setupScheduler() { - mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs()); + mScheduler = new TestableScheduler(*mFlinger.mutableRefreshRateConfigs()); mScheduler->mutableEventControlThread().reset(mEventControlThread); mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync); EXPECT_CALL(*mEventThread.get(), registerDisplayEventConnection(_)); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 5f58e7dce9..f40996eecf 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -29,6 +29,7 @@ #include #include "DisplayIdentificationTest.h" +#include "Scheduler/RefreshRateConfigs.h" #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" @@ -179,7 +180,16 @@ DisplayTransactionTest::~DisplayTransactionTest() { } void DisplayTransactionTest::setupScheduler() { - mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs()); + std::vector configs{{/*hwcId=*/0, 16666667}}; + mFlinger.mutableRefreshRateConfigs() = + std::make_unique(/*refreshRateSwitching=*/false, configs, + /*currentConfig=*/0); + mFlinger.mutableRefreshRateStats() = + std::make_unique(*mFlinger.mutableRefreshRateConfigs(), + *mFlinger.mutableTimeStats(), + /*currentConfig=*/0, + /*powerMode=*/HWC_POWER_MODE_OFF); + mScheduler = new TestableScheduler(*mFlinger.mutableRefreshRateConfigs()); mScheduler->mutableEventControlThread().reset(mEventControlThread); mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync); EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 5067fe890b..f315a8a86c 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -23,7 +23,6 @@ #include "DisplayHardware/HWC2.h" #include "Scheduler/RefreshRateConfigs.h" -#include "mock/DisplayHardware/MockDisplay.h" using namespace std::chrono_literals; using testing::_; @@ -50,9 +49,8 @@ protected: ASSERT_EQ(left.configId, right.configId); ASSERT_EQ(left.name, right.name); ASSERT_EQ(left.fps, right.fps); + ASSERT_EQ(left.vsyncPeriod, right.vsyncPeriod); } - - RefreshRateConfigs mConfigs; }; RefreshRateConfigsTest::RefreshRateConfigsTest() { @@ -71,101 +69,39 @@ namespace { /* ------------------------------------------------------------------------ * Test cases */ -TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) { - std::vector> displayConfigs; - mConfigs.populate(displayConfigs); - - // We always store a configuration for screen off. - const auto& rates = mConfigs.getRefreshRates(); - ASSERT_EQ(1, rates.size()); - const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); - ASSERT_NE(rates.end(), powerSavingRate); - ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE)); - ASSERT_EQ(rates.end(), rates.find(RefreshRateType::DEFAULT)); - - RefreshRate expectedConfig = - RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID}; - assertRatesEqual(expectedConfig, *powerSavingRate->second); - - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - assertRatesEqual(expectedConfig, *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); - ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - - // Sanity check that getRefreshRate() does not modify the underlying configs. - ASSERT_EQ(1, mConfigs.getRefreshRates().size()); +TEST_F(RefreshRateConfigsTest, oneDeviceConfig_isRejected) { + std::vector configs{{HWC2_CONFIG_ID_60, VSYNC_60}}; + auto refreshRateConfigs = + std::make_unique(/*refreshRateSwitching=*/true, configs, + /*currentConfig=*/0); + ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported()); } -TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) { - auto display = new Hwc2::mock::Display(); - std::vector> displayConfigs; - auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); - config60.setVsyncPeriod(VSYNC_60); - displayConfigs.push_back(config60.build()); - mConfigs.populate(displayConfigs); +TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) { + std::vector configs{{HWC2_CONFIG_ID_60, VSYNC_60}, + {HWC2_CONFIG_ID_90, VSYNC_90}}; + auto refreshRateConfigs = + std::make_unique(/*refreshRateSwitching=*/true, configs, + /*currentConfig=*/0); - const auto& rates = mConfigs.getRefreshRates(); + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + const auto& rates = refreshRateConfigs->getRefreshRateMap(); ASSERT_EQ(2, rates.size()); - const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); - const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); - ASSERT_NE(rates.end(), powerSavingRate); - ASSERT_NE(rates.end(), defaultRate); - ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE)); - - RefreshRate expectedPowerSavingConfig = - RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID}; - assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second); - RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60, HWC2_CONFIG_ID_60}; - assertRatesEqual(expectedDefaultConfig, *defaultRate->second); - - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - assertRatesEqual(expectedPowerSavingConfig, - *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); - - // Sanity check that getRefreshRate() does not modify the underlying configs. - ASSERT_EQ(2, mConfigs.getRefreshRates().size()); -} - -TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) { - auto display = new Hwc2::mock::Display(); - std::vector> displayConfigs; - auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); - config60.setVsyncPeriod(VSYNC_60); - displayConfigs.push_back(config60.build()); - auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90); - config90.setVsyncPeriod(VSYNC_90); - displayConfigs.push_back(config90.build()); - mConfigs.populate(displayConfigs); - - const auto& rates = mConfigs.getRefreshRates(); - ASSERT_EQ(3, rates.size()); - const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE); - ASSERT_NE(rates.end(), powerSavingRate); ASSERT_NE(rates.end(), defaultRate); ASSERT_NE(rates.end(), performanceRate); - RefreshRate expectedPowerSavingConfig = - RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID}; - assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second); - RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60, HWC2_CONFIG_ID_60}; - assertRatesEqual(expectedDefaultConfig, *defaultRate->second); - RefreshRate expectedPerformanceConfig = - RefreshRate{CONFIG_ID_90, "90fps", 90, HWC2_CONFIG_ID_90}; - assertRatesEqual(expectedPerformanceConfig, *performanceRate->second); - - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - assertRatesEqual(expectedPowerSavingConfig, - *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); - ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); + RefreshRate expectedDefaultConfig = {CONFIG_ID_60, "60fps", 60, VSYNC_60, HWC2_CONFIG_ID_60}; + assertRatesEqual(expectedDefaultConfig, defaultRate->second); + RefreshRate expectedPerformanceConfig = {CONFIG_ID_90, "90fps", 90, VSYNC_90, + HWC2_CONFIG_ID_90}; + assertRatesEqual(expectedPerformanceConfig, performanceRate->second); + + assertRatesEqual(expectedDefaultConfig, + refreshRateConfigs->getRefreshRateFromType(RefreshRateType::DEFAULT)); assertRatesEqual(expectedPerformanceConfig, - *mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); + refreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE)); } } // namespace } // namespace scheduler diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index 411ec61770..cec0b32a6b 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -22,7 +22,6 @@ #include #include "Scheduler/RefreshRateStats.h" -#include "mock/DisplayHardware/MockDisplay.h" #include "mock/MockTimeStats.h" using namespace std::chrono_literals; @@ -42,9 +41,18 @@ protected: RefreshRateStatsTest(); ~RefreshRateStatsTest(); + void init(const std::vector& configs) { + mRefreshRateConfigs = std::make_unique( + /*refreshRateSwitching=*/true, configs, /*currentConfig=*/0); + mRefreshRateStats = + std::make_unique(*mRefreshRateConfigs, mTimeStats, + /*currentConfig=*/0, + /*currentPowerMode=*/HWC_POWER_MODE_OFF); + } + mock::TimeStats mTimeStats; - RefreshRateConfigs mRefreshRateConfigs; - RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, mTimeStats}; + std::unique_ptr mRefreshRateConfigs; + std::unique_ptr mRefreshRateStats; }; RefreshRateStatsTest::RefreshRateStatsTest() { @@ -63,63 +71,46 @@ namespace { /* ------------------------------------------------------------------------ * Test cases */ -TEST_F(RefreshRateStatsTest, canCreateAndDestroyTest) { - std::vector> configs; - mRefreshRateConfigs.populate(configs); - - // There is one default config, so the refresh rates should have one item. - EXPECT_EQ(1, mRefreshRateStats.getTotalTimes().size()); -} - TEST_F(RefreshRateStatsTest, oneConfigTest) { - auto display = new Hwc2::mock::Display(); - - auto config = HWC2::Display::Config::Builder(*display, CONFIG_ID_90); - config.setVsyncPeriod(VSYNC_90); - std::vector> configs; - configs.push_back(config.build()); - - mRefreshRateConfigs.populate(configs); + init({{CONFIG_ID_90, VSYNC_90}}); EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); - std::unordered_map times = mRefreshRateStats.getTotalTimes(); - EXPECT_EQ(2, times.size()); + std::unordered_map times = mRefreshRateStats->getTotalTimes(); + ASSERT_EQ(1, times.size()); EXPECT_NE(0u, times.count("ScreenOff")); - EXPECT_EQ(1u, times.count("90fps")); - EXPECT_EQ(0, times["90fps"]); // Setting up tests on mobile harness can be flaky with time passing, so testing for // exact time changes can result in flaxy numbers. To avoid that remember old // numbers to make sure the correct values are increasing in the next test. int screenOff = times["ScreenOff"]; - int ninety = times["90fps"]; // Screen is off by default. std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(0, times["90fps"]); + EXPECT_EQ(0u, times.count("90fps")); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL); - screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); + screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_LT(ninety, times["90fps"]); + ASSERT_EQ(1u, times.count("90fps")); + EXPECT_LT(0, times["90fps"]); - mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE); - ninety = mRefreshRateStats.getTotalTimes()["90fps"]; + mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE); + int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config // does not update refresh rates that come from the config. EXPECT_LT(screenOff, times["ScreenOff"]); @@ -127,93 +118,75 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { } TEST_F(RefreshRateStatsTest, twoConfigsTest) { - auto display = new Hwc2::mock::Display(); - - auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90); - config90.setVsyncPeriod(VSYNC_90); - std::vector> configs; - configs.push_back(config90.build()); - - auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); - config60.setVsyncPeriod(VSYNC_60); - configs.push_back(config60.build()); - - mRefreshRateConfigs.populate(configs); + init({{CONFIG_ID_90, VSYNC_90}, {CONFIG_ID_60, VSYNC_60}}); EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); - std::unordered_map times = mRefreshRateStats.getTotalTimes(); - EXPECT_EQ(3, times.size()); + std::unordered_map times = mRefreshRateStats->getTotalTimes(); + ASSERT_EQ(1, times.size()); EXPECT_NE(0u, times.count("ScreenOff")); - EXPECT_EQ(1u, times.count("60fps")); - EXPECT_EQ(0, times["60fps"]); - EXPECT_EQ(1u, times.count("90fps")); - EXPECT_EQ(0, times["90fps"]); // Setting up tests on mobile harness can be flaky with time passing, so testing for // exact time changes can result in flaxy numbers. To avoid that remember old // numbers to make sure the correct values are increasing in the next test. int screenOff = times["ScreenOff"]; - int sixty = times["60fps"]; - int ninety = times["90fps"]; // Screen is off by default. std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(sixty, times["60fps"]); - EXPECT_EQ(ninety, times["90fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL); - screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); + screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_EQ(sixty, times["60fps"]); - EXPECT_LT(ninety, times["90fps"]); + ASSERT_EQ(1u, times.count("90fps")); + EXPECT_LT(0, times["90fps"]); // When power mode is normal, time for configs updates. - mRefreshRateStats.setConfigMode(CONFIG_ID_60); - ninety = mRefreshRateStats.getTotalTimes()["90fps"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_60); + int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); - EXPECT_LT(sixty, times["60fps"]); + ASSERT_EQ(1u, times.count("60fps")); + EXPECT_LT(0, times["60fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - sixty = mRefreshRateStats.getTotalTimes()["60fps"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + int sixty = mRefreshRateStats->getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_LT(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_60); - ninety = mRefreshRateStats.getTotalTimes()["90fps"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_60); + ninety = mRefreshRateStats->getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_LT(sixty, times["60fps"]); // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config // does not update refresh rates that come from the config. - mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE); - mRefreshRateStats.setConfigMode(CONFIG_ID_90); - sixty = mRefreshRateStats.getTotalTimes()["60fps"]; + mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE); + mRefreshRateStats->setConfigMode(CONFIG_ID_90); + sixty = mRefreshRateStats->getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats.setConfigMode(CONFIG_ID_60); - screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; + mRefreshRateStats->setConfigMode(CONFIG_ID_60); + screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats.getTotalTimes(); + times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 740115ea32..571fdfd9fc 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -3,13 +3,13 @@ #include #include - #include #include #include "Scheduler/EventControlThread.h" #include "Scheduler/EventThread.h" +#include "Scheduler/RefreshRateConfigs.h" #include "Scheduler/Scheduler.h" #include "mock/MockEventThread.h" @@ -34,7 +34,7 @@ protected: MOCK_METHOD0(requestNextVsync, void()); }; - scheduler::RefreshRateConfigs mRefreshRateConfigs; + std::unique_ptr mRefreshRateConfigs; /** * This mock Scheduler class uses implementation of mock::EventThread but keeps everything else @@ -73,9 +73,14 @@ SchedulerTest::SchedulerTest() { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + std::vector configs{{/*hwcId=*/0, 16666667}}; + mRefreshRateConfigs = + std::make_unique(/*refreshRateSwitching=*/false, configs, + /*currentConfig=*/0); + std::unique_ptr eventThread = std::make_unique(); mEventThread = eventThread.get(); - mScheduler = std::make_unique(mRefreshRateConfigs, std::move(eventThread)); + mScheduler = std::make_unique(*mRefreshRateConfigs, std::move(eventThread)); EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0)); mEventThreadConnection = new MockEventThreadConnection(mEventThread); @@ -85,7 +90,7 @@ SchedulerTest::SchedulerTest() { EXPECT_CALL(*mEventThread, createEventConnection(_, _)) .WillRepeatedly(Return(mEventThreadConnection)); - mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, ResyncCallback(), + mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, impl::EventThread::InterceptVSyncsCallback()); EXPECT_TRUE(mConnectionHandle != nullptr); } @@ -107,7 +112,7 @@ TEST_F(SchedulerTest, testNullPtr) { sp returnedValue; ASSERT_NO_FATAL_FAILURE( returnedValue = - mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(), + mScheduler->createDisplayEventConnection(nullptr, ISurfaceComposer:: eConfigChangedSuppress)); EXPECT_TRUE(returnedValue == nullptr); @@ -130,7 +135,7 @@ TEST_F(SchedulerTest, invalidConnectionHandle) { sp returnedValue; ASSERT_NO_FATAL_FAILURE( returnedValue = - mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(), + mScheduler->createDisplayEventConnection(connectionHandle, ISurfaceComposer:: eConfigChangedSuppress)); EXPECT_TRUE(returnedValue == nullptr); @@ -161,7 +166,7 @@ TEST_F(SchedulerTest, validConnectionHandle) { sp returnedValue; ASSERT_NO_FATAL_FAILURE( returnedValue = - mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(), + mScheduler->createDisplayEventConnection(mConnectionHandle, ISurfaceComposer:: eConfigChangedSuppress)); EXPECT_TRUE(returnedValue != nullptr); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 64d34ee102..1c1b0201d9 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -32,11 +32,11 @@ #include "Layer.h" #include "NativeWindowSurface.h" #include "Scheduler/MessageQueue.h" +#include "Scheduler/RefreshRateConfigs.h" #include "StartPropertySetThread.h" #include "SurfaceFlinger.h" #include "SurfaceFlingerFactory.h" #include "SurfaceInterceptor.h" - #include "TimeStats/TimeStats.h" namespace android { @@ -342,6 +342,8 @@ public: auto& mutableAppConnectionHandle() { return mFlinger->mAppConnectionHandle; } auto& mutableSfConnectionHandle() { return mFlinger->mSfConnectionHandle; } auto& mutableRefreshRateConfigs() { return mFlinger->mRefreshRateConfigs; } + auto& mutableRefreshRateStats() { return mFlinger->mRefreshRateStats; } + auto& mutableTimeStats() { return mFlinger->mTimeStats; } ~TestableSurfaceFlinger() { // All these pointer and container clears help ensure that GMock does -- GitLab From e62556119d09a071fe5d46a4158082b5f7c3e522 Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Fri, 13 Sep 2019 15:22:52 -0700 Subject: [PATCH 0276/1255] DO NOT MERGE: Turn refresh rate switching on by default Bug: 141020755 Test: Booted the device, confirmed we get refresh rate switching by default. Change-Id: I631fdcdced2321c33692579063b84cbe3e414fa4 --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index da184873df..6950d07e4c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3003,7 +3003,7 @@ void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { int currentConfig = getHwComposer().getActiveConfigIndex(primaryDisplayId); mRefreshRateConfigs = - std::make_unique(refresh_rate_switching(false), + std::make_unique(refresh_rate_switching(true), getHwComposer().getConfigs( primaryDisplayId), currentConfig); -- GitLab From 6cbb97591535868d629a562dfd7d8e24865cf551 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Thu, 5 Sep 2019 16:38:18 +0800 Subject: [PATCH 0277/1255] Revert "Fix drag and drop (2/3)" This reverts commit fbe5d9c4233dcd802a122f70ca5a3641fcd556ca. Bug: 137819199 Test: manual Change-Id: I7afec569519b9c69eb03225672db6db141b20241 --- include/input/IInputFlinger.h | 4 +- libs/gui/tests/EndToEndNativeInputTest.cpp | 50 ---------------------- libs/input/IInputFlinger.cpp | 17 -------- services/inputflinger/InputManager.cpp | 4 -- services/inputflinger/InputManager.h | 1 - services/inputflinger/host/InputFlinger.h | 1 - services/surfaceflinger/SurfaceFlinger.cpp | 15 +------ services/surfaceflinger/SurfaceFlinger.h | 1 - 8 files changed, 2 insertions(+), 91 deletions(-) diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h index 4365a3c4e3..d23e3b7767 100644 --- a/include/input/IInputFlinger.h +++ b/include/input/IInputFlinger.h @@ -37,7 +37,6 @@ public: virtual void setInputWindows(const std::vector& inputHandles, const sp& setInputWindowsListener) = 0; - virtual void transferTouchFocus(const sp& fromToken, const sp& toToken) = 0; virtual void registerInputChannel(const sp& channel) = 0; virtual void unregisterInputChannel(const sp& channel) = 0; }; @@ -51,8 +50,7 @@ public: enum { SET_INPUT_WINDOWS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, REGISTER_INPUT_CHANNEL_TRANSACTION, - UNREGISTER_INPUT_CHANNEL_TRANSACTION, - TRANSFER_TOUCH_FOCUS + UNREGISTER_INPUT_CHANNEL_TRANSACTION }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 386f731d23..f158e566e6 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -133,27 +133,6 @@ public: EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction()); } - void expectMotionEvent(int motionEventType, int x, int y) { - InputEvent *ev = consumeEvent(); - ASSERT_NE(ev, nullptr); - ASSERT_EQ(ev->getType(), AINPUT_EVENT_TYPE_MOTION); - MotionEvent *mev = static_cast(ev); - EXPECT_EQ(motionEventType, mev->getAction()); - EXPECT_EQ(x, mev->getX(0)); - EXPECT_EQ(y, mev->getY(0)); - } - - void expectNoMotionEvent(int motionEventType) { - InputEvent *ev = consumeEvent(); - if (ev == nullptr || ev->getType() != AINPUT_EVENT_TYPE_MOTION) { - // Didn't find an event or a motion event so assume action didn't occur. - return; - } - - MotionEvent *mev = static_cast(ev); - EXPECT_NE(motionEventType, mev->getAction()); - } - ~InputSurface() { mInputFlinger->unregisterInputChannel(mServerChannel); } @@ -278,15 +257,6 @@ void injectTap(int x, int y) { } } -void injectMotionEvent(std::string event, int x, int y) { - char *buf1, *buf2; - asprintf(&buf1, "%d", x); - asprintf(&buf2, "%d", y); - if (fork() == 0) { - execlp("input", "input", "motionevent", event.c_str(), buf1, buf2, NULL); - } -} - TEST_F(InputSurfacesTest, can_receive_input) { std::unique_ptr surface = makeSurface(100, 100); surface->showAt(100, 100); @@ -504,26 +474,6 @@ TEST_F(InputSurfacesTest, input_respects_container_layer_visiblity) { bgSurface->expectTap(1, 1); } -TEST_F(InputSurfacesTest, transfer_touch_focus) { - std::unique_ptr fromSurface = makeSurface(100, 100); - - fromSurface->showAt(10, 10); - injectMotionEvent("DOWN", 11, 11); - fromSurface->expectMotionEvent(AMOTION_EVENT_ACTION_DOWN, 1, 1); - - std::unique_ptr toSurface = makeSurface(100, 100); - toSurface->showAt(10, 10); - - sp fromToken = fromSurface->mServerChannel->getToken(); - sp toToken = toSurface->mServerChannel->getToken(); - SurfaceComposerClient::Transaction t; - t.transferTouchFocus(fromToken, toToken).apply(true); - - injectMotionEvent("UP", 11, 11); - toSurface->expectMotionEvent(AMOTION_EVENT_ACTION_UP, 1, 1); - fromSurface->expectNoMotionEvent(AMOTION_EVENT_ACTION_UP); -} - TEST_F(InputSurfacesTest, input_respects_outscreen) { std::unique_ptr surface = makeSurface(100, 100); surface->showAt(-1, -1); diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp index 90f6e09a69..8ec51653a8 100644 --- a/libs/input/IInputFlinger.cpp +++ b/libs/input/IInputFlinger.cpp @@ -45,16 +45,6 @@ public: IBinder::FLAG_ONEWAY); } - virtual void transferTouchFocus(const sp& fromToken, const sp& toToken) { - Parcel data, reply; - data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor()); - - data.writeStrongBinder(fromToken); - data.writeStrongBinder(toToken); - remote()->transact(BnInputFlinger::TRANSFER_TOUCH_FOCUS, data, &reply, - IBinder::FLAG_ONEWAY); - } - virtual void registerInputChannel(const sp& channel) { Parcel data, reply; data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor()); @@ -102,13 +92,6 @@ status_t BnInputFlinger::onTransact( unregisterInputChannel(channel); break; } - case TRANSFER_TOUCH_FOCUS: { - CHECK_INTERFACE(IInputFlinger, data, reply); - sp fromToken = data.readStrongBinder(); - sp toToken = data.readStrongBinder(); - transferTouchFocus(fromToken, toToken); - break; - } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index 3996cca646..acb53be69e 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -117,10 +117,6 @@ void InputManager::setInputWindows(const std::vector& infos, } } -void InputManager::transferTouchFocus(const sp& fromToken, const sp& toToken) { - mDispatcher->transferTouchFocus(fromToken, toToken); -} - // Used by tests only. void InputManager::registerInputChannel(const sp& channel) { IPCThreadState* ipc = IPCThreadState::self(); diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index e568df54df..32f7ae0058 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -96,7 +96,6 @@ public: virtual void setInputWindows(const std::vector& handles, const sp& setInputWindowsListener); - virtual void transferTouchFocus(const sp& fromToken, const sp& toToken); virtual void registerInputChannel(const sp& channel); virtual void unregisterInputChannel(const sp& channel); diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h index d8b352cbc6..973b4f92fa 100644 --- a/services/inputflinger/host/InputFlinger.h +++ b/services/inputflinger/host/InputFlinger.h @@ -42,7 +42,6 @@ public: virtual status_t dump(int fd, const Vector& args); void setInputWindows(const std::vector&, const sp&) {} - void transferTouchFocus(const sp&, const sp&) {} void registerInputChannel(const sp&) {} void unregisterInputChannel(const sp&) {} diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3498419cdf..a35426e8d4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2606,7 +2606,7 @@ void SurfaceFlinger::updateInputFlinger() { setInputWindowsFinished(); } - executeInputWindowCommands(); + mInputWindowCommands.clear(); } void SurfaceFlinger::updateInputWindowInfo() { @@ -2630,19 +2630,6 @@ void SurfaceFlinger::commitInputWindowCommands() { mPendingInputWindowCommands.clear(); } -void SurfaceFlinger::executeInputWindowCommands() { - for (const auto& transferTouchFocusCommand : mInputWindowCommands.transferTouchFocusCommands) { - if (transferTouchFocusCommand.fromToken != nullptr && - transferTouchFocusCommand.toToken != nullptr && - transferTouchFocusCommand.fromToken != transferTouchFocusCommand.toToken) { - mInputFlinger->transferTouchFocus(transferTouchFocusCommand.fromToken, - transferTouchFocusCommand.toToken); - } - } - - mInputWindowCommands.clear(); -} - void SurfaceFlinger::updateCursorAsync() { compositionengine::CompositionRefreshArgs refreshArgs; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f220c26bdf..e0259c80ec 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -551,7 +551,6 @@ private: void updateInputFlinger(); void updateInputWindowInfo(); void commitInputWindowCommands() REQUIRES(mStateLock); - void executeInputWindowCommands(); void setInputWindowsFinished(); void updateCursorAsync(); -- GitLab From acb7299dfc8e9270923141183bbde04b135e8492 Mon Sep 17 00:00:00 2001 From: Ytai Ben-Tsvi Date: Thu, 5 Sep 2019 15:14:30 -0700 Subject: [PATCH 0278/1255] Improve visibility of IMemory security risks This change renames the IMemory raw pointer accessors to unsecure*() to make it apparent to coders and code reviewers that the returned buffer may potentially be shared with untrusted processes, who may, after the fact, attempt to read and/or modify the contents. This may lead to hard to find security bugs and hopefully the rename makes it harder to forget. The change also attempts to fix all the callsites to make everything build correctly, but in the processes, wherever the callsite code was not obviously secure, I added a TODO requesting the owners to either document why it's secure or to change the code. Apologies in advance to the owners if there are some false positives here - I don't have enough context to reason about all the different callsites. Test: Completely syntactic change. Made sure code still builds. Change-Id: If8474d0c6a2f0a23cb0514eac1a86c71e334fcc9 --- libs/binder/IMemory.cpp | 4 +++- libs/binder/include/binder/IMemory.h | 27 +++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp index caf2318281..a7662e9fd2 100644 --- a/libs/binder/IMemory.cpp +++ b/libs/binder/IMemory.cpp @@ -149,7 +149,7 @@ void* IMemory::fastPointer(const sp& binder, ssize_t offset) const return static_cast(base) + offset; } -void* IMemory::pointer() const { +void* IMemory::unsecurePointer() const { ssize_t offset; sp heap = getMemory(&offset); void* const base = heap!=nullptr ? heap->base() : MAP_FAILED; @@ -158,6 +158,8 @@ void* IMemory::pointer() const { return static_cast(base) + offset; } +void* IMemory::pointer() const { return unsecurePointer(); } + size_t IMemory::size() const { size_t size; getMemory(nullptr, &size); diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h index 071946f50c..8791741f48 100644 --- a/libs/binder/include/binder/IMemory.h +++ b/libs/binder/include/binder/IMemory.h @@ -77,10 +77,33 @@ public: virtual sp getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const = 0; // helpers - void* fastPointer(const sp& heap, ssize_t offset) const; - void* pointer() const; + + // Accessing the underlying pointer must be done with caution, as there are + // some inherent security risks associated with it. When receiving an + // IMemory from an untrusted process, there is currently no way to guarantee + // that this process would't change the content after the fact. This may + // lead to TOC/TOU class of security bugs. In most cases, when performance + // is not an issue, the recommended practice is to immediately copy the + // buffer upon reception, then work with the copy, e.g.: + // + // std::string private_copy(mem.size(), '\0'); + // memcpy(private_copy.data(), mem.unsecurePointer(), mem.size()); + // + // In cases where performance is an issue, this matter must be addressed on + // an ad-hoc basis. + void* unsecurePointer() const; + size_t size() const; ssize_t offset() const; + +private: + // These are now deprecated and are left here for backward-compatibility + // with prebuilts that may reference these symbol at runtime. + // Instead, new code should use unsecurePointer()/unsecureFastPointer(), + // which do the same thing, but make it more obvious that there are some + // security-related pitfalls associated with them. + void* pointer() const; + void* fastPointer(const sp& heap, ssize_t offset) const; }; class BnMemory : public BnInterface -- GitLab From 3d8df0e9c84d313bfe2ed7f88dccb984c041bac1 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 17 Sep 2019 14:53:07 +0100 Subject: [PATCH 0279/1255] Crash if too many open files If there are too many open files, and we can't dup a socket because we received EMFILE or ENFILE, let's crash immediately to make this problem obvious. Otherwise, we are simply propagating null pointers through the system and witness null pointer dereference later (in the good cases), or undefined behaviour. Bug: 141111452 Test: none Change-Id: I012bc050e5246456e00c22f0c17a5752b2708875 --- libs/input/InputTransport.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 7835651f11..8a2fc2a2d0 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -362,6 +362,13 @@ sp InputChannel::dup() const { if (!newFd.ok()) { ALOGE("Could not duplicate fd %i for channel %s: %s", getFd(), mName.c_str(), strerror(errno)); + const bool hitFdLimit = errno == EMFILE || errno == ENFILE; + // If this process is out of file descriptors, then throwing that might end up exploding + // on the other side of a binder call, which isn't really helpful. + // Better to just crash here and hope that the FD leak is slow. + // Other failures could be client errors, so we still propagate those back to the caller. + LOG_ALWAYS_FATAL_IF(hitFdLimit, "Too many open files, could not duplicate input channel %s", + getName().c_str()); return nullptr; } return InputChannel::create(mName, std::move(newFd)); -- GitLab From f0229a72afc7a3f65e7dc780a895bb7e45b88eb1 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 9 Sep 2019 19:28:02 -0700 Subject: [PATCH 0280/1255] TimeStats: Remove TimeStats from SurfaceFlingerFactory Bug: 140266250 Test: atest libsurfaceflinger_unittest:TimeStatsTest Change-Id: Id99bef0f0571dffc74b0b630694ecfb057e97d38 Merged-In: Id99bef0f0571dffc74b0b630694ecfb057e97d38 --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- services/surfaceflinger/SurfaceFlingerFactory.cpp | 5 ----- services/surfaceflinger/SurfaceFlingerFactory.h | 3 --- .../surfaceflinger/tests/unittests/TestableSurfaceFlinger.h | 6 ------ 4 files changed, 1 insertion(+), 15 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4361a94e64..ddc84961b5 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -258,7 +258,7 @@ SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {} SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) : mFactory(factory), mInterceptor(mFactory.createSurfaceInterceptor(this)), - mTimeStats(mFactory.createTimeStats()), + mTimeStats(std::make_shared()), mFrameTracer(std::make_unique()), mEventQueue(mFactory.createMessageQueue()), mCompositionEngine(mFactory.createCompositionEngine()), diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp index 041ff8d722..4ddc132a2e 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp @@ -35,7 +35,6 @@ #include "Scheduler/MessageQueue.h" #include "Scheduler/PhaseOffsets.h" #include "Scheduler/Scheduler.h" -#include "TimeStats/TimeStats.h" namespace android::surfaceflinger { @@ -123,10 +122,6 @@ sp createSurfaceFlinger() { sp createColorLayer(const LayerCreationArgs& args) override { return new ColorLayer(args); } - - std::shared_ptr createTimeStats() override { - return std::make_shared(); - } }; static Factory factory; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index 5d487e6da5..4f303a37be 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -44,7 +44,6 @@ class Scheduler; class StartPropertySetThread; class SurfaceFlinger; class SurfaceInterceptor; -class TimeStats; struct DisplayDeviceCreationArgs; struct LayerCreationArgs; @@ -94,8 +93,6 @@ public: virtual sp createColorLayer(const LayerCreationArgs& args) = 0; virtual sp createContainerLayer(const LayerCreationArgs& args) = 0; - virtual std::shared_ptr createTimeStats() = 0; - protected: ~Factory() = default; }; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 9536dd13fb..968f317ca7 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -37,7 +37,6 @@ #include "SurfaceFlingerFactory.h" #include "SurfaceInterceptor.h" #include "TestableScheduler.h" -#include "TimeStats/TimeStats.h" namespace android { @@ -151,11 +150,6 @@ public: return nullptr; } - std::shared_ptr createTimeStats() override { - // TODO: Use test-fixture controlled factory - return std::make_shared(); - } - using CreateBufferQueueFunction = std::function* /* outProducer */, sp* /* outConsumer */, -- GitLab From 0fc2fa7e6b85d90f449ba8ba843784d1284db862 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Thu, 29 Aug 2019 17:22:15 -0700 Subject: [PATCH 0281/1255] Move InputDispatcher code into a folder. Note this is an intermediate stage so that the following change won't ruin git history. Should never let the HEAD be this commit. Bug: 140139676 Test: Builds. Change-Id: I263929e2d2dd17858eaea69121564335bcc2ef1c --- services/inputflinger/Android.bp | 3 +- .../{ => dispatcher}/InputDispatcher.cpp | 2483 ++++++++--------- .../{ => dispatcher}/InputDispatcher.h | 307 +- .../tests/InputDispatcher_test.cpp | 2 +- 4 files changed, 1390 insertions(+), 1405 deletions(-) rename services/inputflinger/{ => dispatcher}/InputDispatcher.cpp (68%) rename services/inputflinger/{ => dispatcher}/InputDispatcher.h (82%) diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index bdee6fe043..8649c1ebc6 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -30,7 +30,7 @@ cc_library_shared { srcs: [ "InputClassifier.cpp", "InputClassifierConverter.cpp", - "InputDispatcher.cpp", + "dispatcher/InputDispatcher.cpp", "InputManager.cpp", ], @@ -58,6 +58,7 @@ cc_library_shared { export_include_dirs: [ ".", "include", + "dispatcher", ], } diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp similarity index 68% rename from services/inputflinger/InputDispatcher.cpp rename to services/inputflinger/dispatcher/InputDispatcher.cpp index c516ab7eed..4b8c51be5e 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -56,10 +56,10 @@ #include #include +#include #include -#include #include -#include +#include #define INDENT " " #define INDENT2 " " @@ -101,7 +101,6 @@ constexpr size_t RECENT_QUEUE_MAX_SIZE = 10; // Sequence number for synthesized or injected events. constexpr uint32_t SYNTHESIZED_EVENT_SEQUENCE_NUM = 0; - static inline nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); } @@ -112,7 +111,7 @@ static inline const char* toString(bool value) { static std::string motionActionToString(int32_t action) { // Convert MotionEvent action to string - switch(action & AMOTION_EVENT_ACTION_MASK) { + switch (action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: return "DOWN"; case AMOTION_EVENT_ACTION_MOVE: @@ -159,22 +158,22 @@ static std::string dispatchModeToString(int32_t dispatchMode) { } static inline int32_t getMotionEventActionPointerIndex(int32_t action) { - return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> + AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } static bool isValidKeyAction(int32_t action) { switch (action) { - case AKEY_EVENT_ACTION_DOWN: - case AKEY_EVENT_ACTION_UP: - return true; - default: - return false; + case AKEY_EVENT_ACTION_DOWN: + case AKEY_EVENT_ACTION_UP: + return true; + default: + return false; } } static bool validateKeyEvent(int32_t action) { - if (! isValidKeyAction(action)) { + if (!isValidKeyAction(action)) { ALOGE("Key event has invalid action code 0x%x", action); return false; } @@ -183,46 +182,46 @@ static bool validateKeyEvent(int32_t action) { static bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) { switch (action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: - case AMOTION_EVENT_ACTION_MOVE: - case AMOTION_EVENT_ACTION_OUTSIDE: - case AMOTION_EVENT_ACTION_HOVER_ENTER: - case AMOTION_EVENT_ACTION_HOVER_MOVE: - case AMOTION_EVENT_ACTION_HOVER_EXIT: - case AMOTION_EVENT_ACTION_SCROLL: - return true; - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_POINTER_UP: { - int32_t index = getMotionEventActionPointerIndex(action); - return index >= 0 && index < pointerCount; - } - case AMOTION_EVENT_ACTION_BUTTON_PRESS: - case AMOTION_EVENT_ACTION_BUTTON_RELEASE: - return actionButton != 0; - default: - return false; + case AMOTION_EVENT_ACTION_DOWN: + case AMOTION_EVENT_ACTION_UP: + case AMOTION_EVENT_ACTION_CANCEL: + case AMOTION_EVENT_ACTION_MOVE: + case AMOTION_EVENT_ACTION_OUTSIDE: + case AMOTION_EVENT_ACTION_HOVER_ENTER: + case AMOTION_EVENT_ACTION_HOVER_MOVE: + case AMOTION_EVENT_ACTION_HOVER_EXIT: + case AMOTION_EVENT_ACTION_SCROLL: + return true; + case AMOTION_EVENT_ACTION_POINTER_DOWN: + case AMOTION_EVENT_ACTION_POINTER_UP: { + int32_t index = getMotionEventActionPointerIndex(action); + return index >= 0 && index < pointerCount; + } + case AMOTION_EVENT_ACTION_BUTTON_PRESS: + case AMOTION_EVENT_ACTION_BUTTON_RELEASE: + return actionButton != 0; + default: + return false; } } static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount, - const PointerProperties* pointerProperties) { - if (! isValidMotionAction(action, actionButton, pointerCount)) { + const PointerProperties* pointerProperties) { + if (!isValidMotionAction(action, actionButton, pointerCount)) { ALOGE("Motion event has invalid action code 0x%x", action); return false; } if (pointerCount < 1 || pointerCount > MAX_POINTERS) { ALOGE("Motion event has invalid pointer count %zu; value must be between 1 and %d.", - pointerCount, MAX_POINTERS); + pointerCount, MAX_POINTERS); return false; } BitSet32 pointerIdBits; for (size_t i = 0; i < pointerCount; i++) { int32_t id = pointerProperties[i].id; if (id < 0 || id > MAX_POINTER_ID) { - ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", - id, MAX_POINTER_ID); + ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", id, + MAX_POINTER_ID); return false; } if (pointerIdBits.hasBit(id)) { @@ -379,7 +378,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { // Ready to start a new event. // If we don't already have a pending event, go grab one. - if (! mPendingEvent) { + if (!mPendingEvent) { if (mInboundQueue.empty()) { if (isAppSwitchDue) { // The inbound queue is empty so the app switch key we were waiting @@ -435,63 +434,59 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { } switch (mPendingEvent->type) { - case EventEntry::TYPE_CONFIGURATION_CHANGED: { - ConfigurationChangedEntry* typedEntry = - static_cast(mPendingEvent); - done = dispatchConfigurationChangedLocked(currentTime, typedEntry); - dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped - break; - } - - case EventEntry::TYPE_DEVICE_RESET: { - DeviceResetEntry* typedEntry = - static_cast(mPendingEvent); - done = dispatchDeviceResetLocked(currentTime, typedEntry); - dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped - break; - } - - case EventEntry::TYPE_KEY: { - KeyEntry* typedEntry = static_cast(mPendingEvent); - if (isAppSwitchDue) { - if (isAppSwitchKeyEvent(typedEntry)) { - resetPendingAppSwitchLocked(true); - isAppSwitchDue = false; - } else if (dropReason == DROP_REASON_NOT_DROPPED) { - dropReason = DROP_REASON_APP_SWITCH; - } - } - if (dropReason == DROP_REASON_NOT_DROPPED - && isStaleEvent(currentTime, typedEntry)) { - dropReason = DROP_REASON_STALE; - } - if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { - dropReason = DROP_REASON_BLOCKED; + case EventEntry::TYPE_CONFIGURATION_CHANGED: { + ConfigurationChangedEntry* typedEntry = + static_cast(mPendingEvent); + done = dispatchConfigurationChangedLocked(currentTime, typedEntry); + dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped + break; } - done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); - break; - } - case EventEntry::TYPE_MOTION: { - MotionEntry* typedEntry = static_cast(mPendingEvent); - if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { - dropReason = DROP_REASON_APP_SWITCH; + case EventEntry::TYPE_DEVICE_RESET: { + DeviceResetEntry* typedEntry = static_cast(mPendingEvent); + done = dispatchDeviceResetLocked(currentTime, typedEntry); + dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped + break; } - if (dropReason == DROP_REASON_NOT_DROPPED - && isStaleEvent(currentTime, typedEntry)) { - dropReason = DROP_REASON_STALE; + + case EventEntry::TYPE_KEY: { + KeyEntry* typedEntry = static_cast(mPendingEvent); + if (isAppSwitchDue) { + if (isAppSwitchKeyEvent(typedEntry)) { + resetPendingAppSwitchLocked(true); + isAppSwitchDue = false; + } else if (dropReason == DROP_REASON_NOT_DROPPED) { + dropReason = DROP_REASON_APP_SWITCH; + } + } + if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) { + dropReason = DROP_REASON_STALE; + } + if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { + dropReason = DROP_REASON_BLOCKED; + } + done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); + break; } - if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { - dropReason = DROP_REASON_BLOCKED; + + case EventEntry::TYPE_MOTION: { + MotionEntry* typedEntry = static_cast(mPendingEvent); + if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { + dropReason = DROP_REASON_APP_SWITCH; + } + if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) { + dropReason = DROP_REASON_STALE; + } + if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { + dropReason = DROP_REASON_BLOCKED; + } + done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); + break; } - done = dispatchMotionLocked(currentTime, typedEntry, - &dropReason, nextWakeupTime); - break; - } - default: - ALOG_ASSERT(false); - break; + default: + ALOG_ASSERT(false); + break; } if (done) { @@ -501,7 +496,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { mLastDropReason = dropReason; releasePendingEventLocked(); - *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately + *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately } } @@ -511,55 +506,56 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { traceInboundQueueLengthLocked(); switch (entry->type) { - case EventEntry::TYPE_KEY: { - // Optimize app switch latency. - // If the application takes too long to catch up then we drop all events preceding - // the app switch key. - KeyEntry* keyEntry = static_cast(entry); - if (isAppSwitchKeyEvent(keyEntry)) { - if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { - mAppSwitchSawKeyDown = true; - } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { - if (mAppSwitchSawKeyDown) { + case EventEntry::TYPE_KEY: { + // Optimize app switch latency. + // If the application takes too long to catch up then we drop all events preceding + // the app switch key. + KeyEntry* keyEntry = static_cast(entry); + if (isAppSwitchKeyEvent(keyEntry)) { + if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { + mAppSwitchSawKeyDown = true; + } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { + if (mAppSwitchSawKeyDown) { #if DEBUG_APP_SWITCH - ALOGD("App switch is pending!"); + ALOGD("App switch is pending!"); #endif - mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; - mAppSwitchSawKeyDown = false; - needWake = true; + mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; + mAppSwitchSawKeyDown = false; + needWake = true; + } } } + break; } - break; - } - - case EventEntry::TYPE_MOTION: { - // Optimize case where the current application is unresponsive and the user - // decides to touch a window in a different application. - // If the application takes too long to catch up then we drop all events preceding - // the touch into the other window. - MotionEntry* motionEntry = static_cast(entry); - if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN - && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) - && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY - && mInputTargetWaitApplicationToken != nullptr) { - int32_t displayId = motionEntry->displayId; - int32_t x = int32_t(motionEntry->pointerCoords[0]. - getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(motionEntry->pointerCoords[0]. - getAxisValue(AMOTION_EVENT_AXIS_Y)); - sp touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); - if (touchedWindowHandle != nullptr - && touchedWindowHandle->getApplicationToken() - != mInputTargetWaitApplicationToken) { - // User touched a different application than the one we are waiting on. - // Flag the event, and start pruning the input queue. - mNextUnblockedEvent = motionEntry; - needWake = true; + + case EventEntry::TYPE_MOTION: { + // Optimize case where the current application is unresponsive and the user + // decides to touch a window in a different application. + // If the application takes too long to catch up then we drop all events preceding + // the touch into the other window. + MotionEntry* motionEntry = static_cast(entry); + if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN && + (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && + mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY && + mInputTargetWaitApplicationToken != nullptr) { + int32_t displayId = motionEntry->displayId; + int32_t x = + int32_t(motionEntry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); + int32_t y = + int32_t(motionEntry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); + sp touchedWindowHandle = + findTouchedWindowAtLocked(displayId, x, y); + if (touchedWindowHandle != nullptr && + touchedWindowHandle->getApplicationToken() != + mInputTargetWaitApplicationToken) { + // User touched a different application than the one we are waiting on. + // Flag the event, and start pruning the input queue. + mNextUnblockedEvent = motionEntry; + needWake = true; + } } + break; } - break; - } } return needWake; @@ -574,8 +570,9 @@ void InputDispatcher::addRecentEventLocked(EventEntry* entry) { } } -sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, - int32_t x, int32_t y, bool addOutsideTargets, bool addPortalWindows) { +sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x, + int32_t y, bool addOutsideTargets, + bool addPortalWindows) { // Traverse windows from front to back to find touched window. const std::vector> windowHandles = getWindowHandlesLocked(displayId); for (const sp& windowHandle : windowHandles) { @@ -585,18 +582,19 @@ sp InputDispatcher::findTouchedWindowAtLocked(int32_t display if (windowInfo->visible) { if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { - bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE - | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; + bool isTouchModal = (flags & + (InputWindowInfo::FLAG_NOT_FOCUSABLE | + InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { int32_t portalToDisplayId = windowInfo->portalToDisplayId; - if (portalToDisplayId != ADISPLAY_ID_NONE - && portalToDisplayId != displayId) { + if (portalToDisplayId != ADISPLAY_ID_NONE && + portalToDisplayId != displayId) { if (addPortalWindows) { // For the monitoring channels of the display. mTempTouchState.addPortalWindow(windowHandle); } - return findTouchedWindowAtLocked( - portalToDisplayId, x, y, addOutsideTargets, addPortalWindows); + return findTouchedWindowAtLocked(portalToDisplayId, x, y, + addOutsideTargets, addPortalWindows); } // Found window. return windowHandle; @@ -604,8 +602,9 @@ sp InputDispatcher::findTouchedWindowAtLocked(int32_t display } if (addOutsideTargets && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) { - mTempTouchState.addOrUpdateWindow( - windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0)); + mTempTouchState.addOrUpdateWindow(windowHandle, + InputTarget::FLAG_DISPATCH_AS_OUTSIDE, + BitSet32(0)); } } } @@ -622,14 +621,15 @@ std::vector InputDispatcher::findTouchedGesture for (const sp& portalWindow : portalWindows) { const InputWindowInfo* windowInfo = portalWindow->getInfo(); monitors = getValueByKey(mGestureMonitorsByDisplay, windowInfo->portalToDisplayId); - addGestureMonitors(monitors, touchedMonitors, - -windowInfo->frameLeft, -windowInfo->frameTop); + addGestureMonitors(monitors, touchedMonitors, -windowInfo->frameLeft, + -windowInfo->frameTop); } return touchedMonitors; } void InputDispatcher::addGestureMonitors(const std::vector& monitors, - std::vector& outTouchedMonitors, float xOffset, float yOffset) { + std::vector& outTouchedMonitors, + float xOffset, float yOffset) { if (monitors.empty()) { return; } @@ -642,68 +642,66 @@ void InputDispatcher::addGestureMonitors(const std::vector& monitors, void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { const char* reason; switch (dropReason) { - case DROP_REASON_POLICY: + case DROP_REASON_POLICY: #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("Dropped event because policy consumed it."); + ALOGD("Dropped event because policy consumed it."); #endif - reason = "inbound event was dropped because the policy consumed it"; - break; - case DROP_REASON_DISABLED: - if (mLastDropReason != DROP_REASON_DISABLED) { - ALOGI("Dropped event because input dispatch is disabled."); - } - reason = "inbound event was dropped because input dispatch is disabled"; - break; - case DROP_REASON_APP_SWITCH: - ALOGI("Dropped event because of pending overdue app switch."); - reason = "inbound event was dropped because of pending overdue app switch"; - break; - case DROP_REASON_BLOCKED: - ALOGI("Dropped event because the current application is not responding and the user " - "has started interacting with a different application."); - reason = "inbound event was dropped because the current application is not responding " - "and the user has started interacting with a different application"; - break; - case DROP_REASON_STALE: - ALOGI("Dropped event because it is stale."); - reason = "inbound event was dropped because it is stale"; - break; - default: - ALOG_ASSERT(false); - return; + reason = "inbound event was dropped because the policy consumed it"; + break; + case DROP_REASON_DISABLED: + if (mLastDropReason != DROP_REASON_DISABLED) { + ALOGI("Dropped event because input dispatch is disabled."); + } + reason = "inbound event was dropped because input dispatch is disabled"; + break; + case DROP_REASON_APP_SWITCH: + ALOGI("Dropped event because of pending overdue app switch."); + reason = "inbound event was dropped because of pending overdue app switch"; + break; + case DROP_REASON_BLOCKED: + ALOGI("Dropped event because the current application is not responding and the user " + "has started interacting with a different application."); + reason = "inbound event was dropped because the current application is not responding " + "and the user has started interacting with a different application"; + break; + case DROP_REASON_STALE: + ALOGI("Dropped event because it is stale."); + reason = "inbound event was dropped because it is stale"; + break; + default: + ALOG_ASSERT(false); + return; } switch (entry->type) { - case EventEntry::TYPE_KEY: { - CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - break; - } - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast(entry); - if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } else { + case EventEntry::TYPE_KEY: { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); synthesizeCancelationEventsForAllConnectionsLocked(options); + break; + } + case EventEntry::TYPE_MOTION: { + MotionEntry* motionEntry = static_cast(entry); + if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { + CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason); + synthesizeCancelationEventsForAllConnectionsLocked(options); + } else { + CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); + synthesizeCancelationEventsForAllConnectionsLocked(options); + } + break; } - break; - } } } static bool isAppSwitchKeyCode(int32_t keyCode) { - return keyCode == AKEYCODE_HOME - || keyCode == AKEYCODE_ENDCALL - || keyCode == AKEYCODE_APP_SWITCH; + return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL || + keyCode == AKEYCODE_APP_SWITCH; } bool InputDispatcher::isAppSwitchKeyEvent(KeyEntry* keyEntry) { - return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) - && isAppSwitchKeyCode(keyEntry->keyCode) - && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) - && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); + return !(keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) && isAppSwitchKeyCode(keyEntry->keyCode) && + (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) && + (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); } bool InputDispatcher::isAppSwitchPendingLocked() { @@ -801,10 +799,11 @@ InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t cu entry->policyFlags = policyFlags; entry->repeatCount += 1; } else { - KeyEntry* newEntry = new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, - entry->deviceId, entry->source, entry->displayId, policyFlags, - entry->action, entry->flags, entry->keyCode, entry->scanCode, - entry->metaState, entry->repeatCount + 1, entry->downTime); + KeyEntry* newEntry = + new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, entry->deviceId, + entry->source, entry->displayId, policyFlags, entry->action, + entry->flags, entry->keyCode, entry->scanCode, entry->metaState, + entry->repeatCount + 1, entry->downTime); mKeyRepeatState.lastKeyEntry = newEntry; entry->release(); @@ -821,8 +820,8 @@ InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t cu return entry; } -bool InputDispatcher::dispatchConfigurationChangedLocked( - nsecs_t currentTime, ConfigurationChangedEntry* entry) { +bool InputDispatcher::dispatchConfigurationChangedLocked(nsecs_t currentTime, + ConfigurationChangedEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry->eventTime); #endif @@ -838,30 +837,27 @@ bool InputDispatcher::dispatchConfigurationChangedLocked( return true; } -bool InputDispatcher::dispatchDeviceResetLocked( - nsecs_t currentTime, DeviceResetEntry* entry) { +bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime, DeviceResetEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry->eventTime, - entry->deviceId); + entry->deviceId); #endif - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, - "device was reset"); + CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, "device was reset"); options.deviceId = entry->deviceId; synthesizeCancelationEventsForAllConnectionsLocked(options); return true; } bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime) { + DropReason* dropReason, nsecs_t* nextWakeupTime) { // Preprocessing. - if (! entry->dispatchInProgress) { - if (entry->repeatCount == 0 - && entry->action == AKEY_EVENT_ACTION_DOWN - && (entry->policyFlags & POLICY_FLAG_TRUSTED) - && (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) { - if (mKeyRepeatState.lastKeyEntry - && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { + if (!entry->dispatchInProgress) { + if (entry->repeatCount == 0 && entry->action == AKEY_EVENT_ACTION_DOWN && + (entry->policyFlags & POLICY_FLAG_TRUSTED) && + (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) { + if (mKeyRepeatState.lastKeyEntry && + mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { // We have seen two identical key downs in a row which indicates that the device // driver is automatically generating key repeats itself. We take note of the // repeat here, but we disable our own next key repeat timer since it is clear that @@ -876,7 +872,7 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, } mKeyRepeatState.lastKeyEntry = entry; entry->refCount += 1; - } else if (! entry->syntheticRepeat) { + } else if (!entry->syntheticRepeat) { resetKeyRepeatLocked(); } @@ -911,8 +907,7 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, sp focusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry)); if (focusedWindowHandle != nullptr) { - commandEntry->inputChannel = - getInputChannelLocked(focusedWindowHandle->getToken()); + commandEntry->inputChannel = getInputChannelLocked(focusedWindowHandle->getToken()); } commandEntry->keyEntry = entry; postCommandLocked(std::move(commandEntry)); @@ -929,16 +924,17 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, // Clean up if dropping the event. if (*dropReason != DROP_REASON_NOT_DROPPED) { - setInjectionResult(entry, *dropReason == DROP_REASON_POLICY - ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); + setInjectionResult(entry, + *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED + : INPUT_EVENT_INJECTION_FAILED); mReporter->reportDroppedKey(entry->sequenceNum); return true; } // Identify targets. std::vector inputTargets; - int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime); + int32_t injectionResult = + findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; } @@ -959,20 +955,19 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", " - "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, " - "metaState=0x%x, repeatCount=%d, downTime=%" PRId64, - prefix, - entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags, - entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, - entry->repeatCount, entry->downTime); + "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, " + "metaState=0x%x, repeatCount=%d, downTime=%" PRId64, + prefix, entry->eventTime, entry->deviceId, entry->source, entry->displayId, + entry->policyFlags, entry->action, entry->flags, entry->keyCode, entry->scanCode, + entry->metaState, entry->repeatCount, entry->downTime); #endif } -bool InputDispatcher::dispatchMotionLocked( - nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { +bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry, + DropReason* dropReason, nsecs_t* nextWakeupTime) { ATRACE_CALL(); // Preprocessing. - if (! entry->dispatchInProgress) { + if (!entry->dispatchInProgress) { entry->dispatchInProgress = true; logOutboundMotionDetails("dispatchMotion - ", entry); @@ -980,8 +975,9 @@ bool InputDispatcher::dispatchMotionLocked( // Clean up if dropping the event. if (*dropReason != DROP_REASON_NOT_DROPPED) { - setInjectionResult(entry, *dropReason == DROP_REASON_POLICY - ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); + setInjectionResult(entry, + *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED + : INPUT_EVENT_INJECTION_FAILED); return true; } @@ -994,12 +990,13 @@ bool InputDispatcher::dispatchMotionLocked( int32_t injectionResult; if (isPointerEvent) { // Pointer event. (eg. touchscreen) - injectionResult = findTouchedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime, &conflictingPointerActions); + injectionResult = + findTouchedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime, + &conflictingPointerActions); } else { // Non touch event. (eg. trackball) - injectionResult = findFocusedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime); + injectionResult = + findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); } if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; @@ -1008,9 +1005,9 @@ bool InputDispatcher::dispatchMotionLocked( setInjectionResult(entry, injectionResult); if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) { - CancelationOptions::Mode mode(isPointerEvent ? - CancelationOptions::CANCEL_POINTER_EVENTS : - CancelationOptions::CANCEL_NON_POINTER_EVENTS); + CancelationOptions::Mode mode(isPointerEvent + ? CancelationOptions::CANCEL_POINTER_EVENTS + : CancelationOptions::CANCEL_NON_POINTER_EVENTS); CancelationOptions options(mode, "input event injection failed"); synthesizeCancelationEventsForMonitorsLocked(options); } @@ -1030,7 +1027,7 @@ bool InputDispatcher::dispatchMotionLocked( for (size_t i = 0; i < state.portalWindows.size(); i++) { const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo(); addGlobalMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId, - -windowInfo->frameLeft, -windowInfo->frameTop); + -windowInfo->frameLeft, -windowInfo->frameTop); } } } @@ -1039,50 +1036,46 @@ bool InputDispatcher::dispatchMotionLocked( // Dispatch the motion. if (conflictingPointerActions) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "conflicting pointer actions"); + "conflicting pointer actions"); synthesizeCancelationEventsForAllConnectionsLocked(options); } dispatchEventLocked(currentTime, entry, inputTargets); return true; } - void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 - ", policyFlags=0x%x, " - "action=0x%x, actionButton=0x%x, flags=0x%x, " - "metaState=0x%x, buttonState=0x%x," - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, - prefix, - entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags, - entry->action, entry->actionButton, entry->flags, - entry->metaState, entry->buttonState, - entry->edgeFlags, entry->xPrecision, entry->yPrecision, - entry->downTime); + ", policyFlags=0x%x, " + "action=0x%x, actionButton=0x%x, flags=0x%x, " + "metaState=0x%x, buttonState=0x%x," + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, + prefix, entry->eventTime, entry->deviceId, entry->source, entry->displayId, + entry->policyFlags, entry->action, entry->actionButton, entry->flags, entry->metaState, + entry->buttonState, entry->edgeFlags, entry->xPrecision, entry->yPrecision, + entry->downTime); for (uint32_t i = 0; i < entry->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " - "x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, entry->pointerProperties[i].id, - entry->pointerProperties[i].toolType, - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); + "x=%f, y=%f, pressure=%f, size=%f, " + "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " + "orientation=%f", + i, entry->pointerProperties[i].id, entry->pointerProperties[i].toolType, + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); } #endif } -void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, - EventEntry* eventEntry, const std::vector& inputTargets) { +void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, + const std::vector& inputTargets) { ATRACE_CALL(); #if DEBUG_DISPATCH_CYCLE ALOGD("dispatchEventToCurrentInputTargets"); @@ -1099,18 +1092,17 @@ void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, } else { #if DEBUG_FOCUS ALOGD("Dropping event delivery to target with channel '%s' because it " - "is no longer registered with the input dispatcher.", - inputTarget.inputChannel->getName().c_str()); + "is no longer registered with the input dispatcher.", + inputTarget.inputChannel->getName().c_str()); #endif } } } -int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, - const EventEntry* entry, +int32_t InputDispatcher::handleTargetsNotReadyLocked( + nsecs_t currentTime, const EventEntry* entry, const sp& applicationHandle, - const sp& windowHandle, - nsecs_t* nextWakeupTime, const char* reason) { + const sp& windowHandle, nsecs_t* nextWakeupTime, const char* reason) { if (applicationHandle == nullptr && windowHandle == nullptr) { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) { #if DEBUG_FOCUS @@ -1126,15 +1118,14 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { #if DEBUG_FOCUS ALOGD("Waiting for application to become ready for input: %s. Reason: %s", - getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), - reason); + getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), reason); #endif nsecs_t timeout; if (windowHandle != nullptr) { timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else if (applicationHandle != nullptr) { - timeout = applicationHandle->getDispatchingTimeout( - DEFAULT_INPUT_DISPATCHING_TIMEOUT); + timeout = + applicationHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else { timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; } @@ -1159,8 +1150,8 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, } if (currentTime >= mInputTargetWaitTimeoutTime) { - onANRLocked(currentTime, applicationHandle, windowHandle, - entry->eventTime, mInputTargetWaitStartTime, reason); + onANRLocked(currentTime, applicationHandle, windowHandle, entry->eventTime, + mInputTargetWaitStartTime, reason); // Force poll loop to wake up immediately on next iteration once we get the // ANR response back from the policy. @@ -1182,8 +1173,8 @@ void InputDispatcher::removeWindowByTokenLocked(const sp& token) { } } -void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, - const sp& inputChannel) { +void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked( + nsecs_t newTimeout, const sp& inputChannel) { if (newTimeout > 0) { // Extend the timeout. mInputTargetWaitTimeoutTime = now() + newTimeout; @@ -1209,8 +1200,7 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout } } -nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked( - nsecs_t currentTime) { +nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) { if (mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { return currentTime - mInputTargetWaitStartTime; } @@ -1219,7 +1209,7 @@ nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked( void InputDispatcher::resetANRTimeoutsLocked() { #if DEBUG_FOCUS - ALOGD("Resetting ANR timeouts."); + ALOGD("Resetting ANR timeouts."); #endif // Reset input target wait timeout. @@ -1235,26 +1225,28 @@ void InputDispatcher::resetANRTimeoutsLocked() { int32_t InputDispatcher::getTargetDisplayId(const EventEntry* entry) { int32_t displayId; switch (entry->type) { - case EventEntry::TYPE_KEY: { - const KeyEntry* typedEntry = static_cast(entry); - displayId = typedEntry->displayId; - break; - } - case EventEntry::TYPE_MOTION: { - const MotionEntry* typedEntry = static_cast(entry); - displayId = typedEntry->displayId; - break; - } - default: { - ALOGE("Unsupported event type '%" PRId32 "' for target display.", entry->type); - return ADISPLAY_ID_NONE; - } + case EventEntry::TYPE_KEY: { + const KeyEntry* typedEntry = static_cast(entry); + displayId = typedEntry->displayId; + break; + } + case EventEntry::TYPE_MOTION: { + const MotionEntry* typedEntry = static_cast(entry); + displayId = typedEntry->displayId; + break; + } + default: { + ALOGE("Unsupported event type '%" PRId32 "' for target display.", entry->type); + return ADISPLAY_ID_NONE; + } } return displayId == ADISPLAY_ID_NONE ? mFocusedDisplayId : displayId; } int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, - const EventEntry* entry, std::vector& inputTargets, nsecs_t* nextWakeupTime) { + const EventEntry* entry, + std::vector& inputTargets, + nsecs_t* nextWakeupTime) { int32_t injectionResult; std::string reason; @@ -1268,16 +1260,18 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, // then drop the event. if (focusedWindowHandle == nullptr) { if (focusedApplicationHandle != nullptr) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - focusedApplicationHandle, nullptr, nextWakeupTime, - "Waiting because no window has focus but there is a " - "focused application that may eventually add a window " - "when it finishes starting up."); + injectionResult = + handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle, + nullptr, nextWakeupTime, + "Waiting because no window has focus but there is " + "a focused application that may eventually add a " + "window when it finishes starting up."); goto Unresponsive; } ALOGI("Dropping event because there is no focused window or focused application in display " - "%" PRId32 ".", displayId); + "%" PRId32 ".", + displayId); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } @@ -1289,19 +1283,19 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, } // Check whether the window is ready for more input. - reason = checkWindowReadyForMoreInputLocked(currentTime, - focusedWindowHandle, entry, "focused"); + reason = checkWindowReadyForMoreInputLocked(currentTime, focusedWindowHandle, entry, "focused"); if (!reason.empty()) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - focusedApplicationHandle, focusedWindowHandle, nextWakeupTime, reason.c_str()); + injectionResult = + handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle, + focusedWindowHandle, nextWakeupTime, reason.c_str()); goto Unresponsive; } // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; addWindowTargetLocked(focusedWindowHandle, - InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0), - inputTargets); + InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, + BitSet32(0), inputTargets); // Done. Failed: @@ -1310,15 +1304,17 @@ Unresponsive: updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication); #if DEBUG_FOCUS ALOGD("findFocusedWindow finished: injectionResult=%d, " - "timeSpentWaitingForApplication=%0.1fms", - injectionResult, timeSpentWaitingForApplication / 1000000.0); + "timeSpentWaitingForApplication=%0.1fms", + injectionResult, timeSpentWaitingForApplication / 1000000.0); #endif return injectionResult; } int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, - const MotionEntry* entry, std::vector& inputTargets, nsecs_t* nextWakeupTime, - bool* outConflictingPointerActions) { + const MotionEntry* entry, + std::vector& inputTargets, + nsecs_t* nextWakeupTime, + bool* outConflictingPointerActions) { ATRACE_CALL(); enum InjectionPermission { INJECTION_PERMISSION_UNKNOWN, @@ -1348,16 +1344,14 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } bool isSplit = mTempTouchState.split; - bool switchedDevice = mTempTouchState.deviceId >= 0 && mTempTouchState.displayId >= 0 - && (mTempTouchState.deviceId != entry->deviceId - || mTempTouchState.source != entry->source - || mTempTouchState.displayId != displayId); - bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE - || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER - || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); - bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN - || maskedAction == AMOTION_EVENT_ACTION_SCROLL - || isHoverAction); + bool switchedDevice = mTempTouchState.deviceId >= 0 && mTempTouchState.displayId >= 0 && + (mTempTouchState.deviceId != entry->deviceId || + mTempTouchState.source != entry->source || mTempTouchState.displayId != displayId); + bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE || + maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || + maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); + bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN || + maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction); const bool isFromMouse = entry->source == AINPUT_SOURCE_MOUSE; bool wrongDevice = false; if (newGesture) { @@ -1365,7 +1359,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (switchedDevice && mTempTouchState.down && !down && !isHoverAction) { #if DEBUG_FOCUS ALOGD("Dropping event because a pointer for a different device is already down " - "in display %" PRId32, displayId); + "in display %" PRId32, + displayId); #endif // TODO: test multiple simultaneous input streams. injectionResult = INPUT_EVENT_INJECTION_FAILED; @@ -1382,7 +1377,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) { #if DEBUG_FOCUS ALOGI("Dropping move event because a pointer for a different device is already active " - "in display %" PRId32, displayId); + "in display %" PRId32, + displayId); #endif // TODO: test multiple simultaneous input streams. injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; @@ -1406,16 +1402,17 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, y = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)); } bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN; - sp newTouchedWindowHandle = findTouchedWindowAtLocked( - displayId, x, y, isDown /*addOutsideTargets*/, true /*addPortalWindows*/); + sp newTouchedWindowHandle = + findTouchedWindowAtLocked(displayId, x, y, isDown /*addOutsideTargets*/, + true /*addPortalWindows*/); std::vector newGestureMonitors = isDown ? findTouchedGestureMonitorsLocked(displayId, mTempTouchState.portalWindows) : std::vector{}; // Figure out whether splitting will be allowed for this window. - if (newTouchedWindowHandle != nullptr - && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { + if (newTouchedWindowHandle != nullptr && + newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { // New window supports splitting, but we should never split mouse events. isSplit = !isFromMouse; } else if (isSplit) { @@ -1432,7 +1429,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) { ALOGI("Dropping event because there is no touchable window or gesture monitor at " - "(%d, %d) in display %" PRId32 ".", x, y, displayId); + "(%d, %d) in display %" PRId32 ".", + x, y, displayId); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } @@ -1470,19 +1468,19 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ // If the pointer is not currently down, then ignore the event. - if (! mTempTouchState.down) { + if (!mTempTouchState.down) { #if DEBUG_FOCUS ALOGD("Dropping event because the pointer is not down or we previously " - "dropped the pointer down event in display %" PRId32, displayId); + "dropped the pointer down event in display %" PRId32, + displayId); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } // Check whether touches should slip outside of the current foreground window. - if (maskedAction == AMOTION_EVENT_ACTION_MOVE - && entry->pointerCount == 1 - && mTempTouchState.isSlippery()) { + if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry->pointerCount == 1 && + mTempTouchState.isSlippery()) { int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); @@ -1490,26 +1488,25 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, mTempTouchState.getFirstForegroundWindowHandle(); sp newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); - if (oldTouchedWindowHandle != newTouchedWindowHandle - && oldTouchedWindowHandle != nullptr - && newTouchedWindowHandle != nullptr) { + if (oldTouchedWindowHandle != newTouchedWindowHandle && + oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32, - oldTouchedWindowHandle->getName().c_str(), - newTouchedWindowHandle->getName().c_str(), - displayId); + oldTouchedWindowHandle->getName().c_str(), + newTouchedWindowHandle->getName().c_str(), displayId); #endif // Make a slippery exit from the old window. mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0)); + InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, + BitSet32(0)); // Make a slippery entrance into the new window. if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { isSplit = true; } - int32_t targetFlags = InputTarget::FLAG_FOREGROUND - | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER; + int32_t targetFlags = + InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER; if (isSplit) { targetFlags |= InputTarget::FLAG_SPLIT; } @@ -1531,20 +1528,22 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (mLastHoverWindowHandle != nullptr) { #if DEBUG_HOVER ALOGD("Sending hover exit event to window %s.", - mLastHoverWindowHandle->getName().c_str()); + mLastHoverWindowHandle->getName().c_str()); #endif mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0)); + InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, + BitSet32(0)); } // Let the new window know that the hover sequence is starting. if (newHoverWindowHandle != nullptr) { #if DEBUG_HOVER ALOGD("Sending hover enter event to window %s.", - newHoverWindowHandle->getName().c_str()); + newHoverWindowHandle->getName().c_str()); #endif mTempTouchState.addOrUpdateWindow(newHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0)); + InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, + BitSet32(0)); } } @@ -1555,8 +1554,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { haveForegroundWindow = true; - if (! checkInjectionPermission(touchedWindow.windowHandle, - entry->injectionState)) { + if (!checkInjectionPermission(touchedWindow.windowHandle, entry->injectionState)) { injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; injectionPermission = INJECTION_PERMISSION_DENIED; goto Failed; @@ -1566,8 +1564,9 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, bool hasGestureMonitor = !mTempTouchState.gestureMonitors.empty(); if (!haveForegroundWindow && !hasGestureMonitor) { #if DEBUG_FOCUS - ALOGD("Dropping event because there is no touched foreground window in display %" - PRId32 " or gesture monitor to receive it.", displayId); + ALOGD("Dropping event because there is no touched foreground window in display %" PRId32 + " or gesture monitor to receive it.", + displayId); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; @@ -1589,7 +1588,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, sp inputWindowHandle = touchedWindow.windowHandle; if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) { mTempTouchState.addOrUpdateWindow(inputWindowHandle, - InputTarget::FLAG_ZERO_COORDS, BitSet32(0)); + InputTarget::FLAG_ZERO_COORDS, + BitSet32(0)); } } } @@ -1600,11 +1600,13 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { // Check whether the window is ready for more input. - std::string reason = checkWindowReadyForMoreInputLocked(currentTime, - touchedWindow.windowHandle, entry, "touched"); + std::string reason = + checkWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, + entry, "touched"); if (!reason.empty()) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - nullptr, touchedWindow.windowHandle, nextWakeupTime, reason.c_str()); + injectionResult = handleTargetsNotReadyLocked(currentTime, entry, nullptr, + touchedWindow.windowHandle, + nextWakeupTime, reason.c_str()); goto Unresponsive; } } @@ -1624,14 +1626,15 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, getWindowHandlesLocked(displayId); for (const sp& windowHandle : windowHandles) { const InputWindowInfo* info = windowHandle->getInfo(); - if (info->displayId == displayId - && windowHandle->getInfo()->layoutParamsType - == InputWindowInfo::TYPE_WALLPAPER) { - mTempTouchState.addOrUpdateWindow(windowHandle, - InputTarget::FLAG_WINDOW_IS_OBSCURED - | InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED - | InputTarget::FLAG_DISPATCH_AS_IS, - BitSet32(0)); + if (info->displayId == displayId && + windowHandle->getInfo()->layoutParamsType == InputWindowInfo::TYPE_WALLPAPER) { + mTempTouchState + .addOrUpdateWindow(windowHandle, + InputTarget::FLAG_WINDOW_IS_OBSCURED | + InputTarget:: + FLAG_WINDOW_IS_PARTIALLY_OBSCURED | + InputTarget::FLAG_DISPATCH_AS_IS, + BitSet32(0)); } } } @@ -1642,12 +1645,12 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, - touchedWindow.pointerIds, inputTargets); + touchedWindow.pointerIds, inputTargets); } for (const TouchedMonitor& touchedMonitor : mTempTouchState.gestureMonitors) { addMonitoringTargetLocked(touchedMonitor.monitor, touchedMonitor.xOffset, - touchedMonitor.yOffset, inputTargets); + touchedMonitor.yOffset, inputTargets); } // Drop the outside or hover touch windows since we will not care about them @@ -1683,14 +1686,14 @@ Failed: *outConflictingPointerActions = true; } mTempTouchState.reset(); - if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER - || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { + if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || + maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { mTempTouchState.deviceId = entry->deviceId; mTempTouchState.source = entry->source; mTempTouchState.displayId = displayId; } - } else if (maskedAction == AMOTION_EVENT_ACTION_UP - || maskedAction == AMOTION_EVENT_ACTION_CANCEL) { + } else if (maskedAction == AMOTION_EVENT_ACTION_UP || + maskedAction == AMOTION_EVENT_ACTION_CANCEL) { // All pointers up or canceled. mTempTouchState.reset(); } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { @@ -1707,7 +1710,7 @@ Failed: int32_t pointerIndex = getMotionEventActionPointerIndex(action); uint32_t pointerId = entry->pointerProperties[pointerIndex].id; - for (size_t i = 0; i < mTempTouchState.windows.size(); ) { + for (size_t i = 0; i < mTempTouchState.windows.size();) { TouchedWindow& touchedWindow = mTempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) { touchedWindow.pointerIds.clearBit(pointerId); @@ -1752,14 +1755,15 @@ Unresponsive: updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication); #if DEBUG_FOCUS ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, " - "timeSpentWaitingForApplication=%0.1fms", - injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0); + "timeSpentWaitingForApplication=%0.1fms", + injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0); #endif return injectionResult; } void InputDispatcher::addWindowTargetLocked(const sp& windowHandle, - int32_t targetFlags, BitSet32 pointerIds, std::vector& inputTargets) { + int32_t targetFlags, BitSet32 pointerIds, + std::vector& inputTargets) { sp inputChannel = getInputChannelLocked(windowHandle->getToken()); if (inputChannel == nullptr) { ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str()); @@ -1770,8 +1774,8 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowH InputTarget target; target.inputChannel = inputChannel; target.flags = targetFlags; - target.xOffset = - windowInfo->frameLeft; - target.yOffset = - windowInfo->frameTop; + target.xOffset = -windowInfo->frameLeft; + target.yOffset = -windowInfo->frameTop; target.globalScaleFactor = windowInfo->globalScaleFactor; target.windowXScale = windowInfo->windowXScale; target.windowYScale = windowInfo->windowYScale; @@ -1780,8 +1784,8 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowH } void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector& inputTargets, - int32_t displayId, float xOffset, float yOffset) { - + int32_t displayId, float xOffset, + float yOffset) { std::unordered_map>::const_iterator it = mGlobalMonitorsByDisplay.find(displayId); @@ -1793,8 +1797,9 @@ void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector& } } -void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, - float xOffset, float yOffset, std::vector& inputTargets) { +void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, float xOffset, + float yOffset, + std::vector& inputTargets) { InputTarget target; target.inputChannel = monitor.inputChannel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; @@ -1806,28 +1811,27 @@ void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, } bool InputDispatcher::checkInjectionPermission(const sp& windowHandle, - const InjectionState* injectionState) { - if (injectionState - && (windowHandle == nullptr - || windowHandle->getInfo()->ownerUid != injectionState->injectorUid) - && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { + const InjectionState* injectionState) { + if (injectionState && + (windowHandle == nullptr || + windowHandle->getInfo()->ownerUid != injectionState->injectorUid) && + !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { if (windowHandle != nullptr) { ALOGW("Permission denied: injecting event from pid %d uid %d to window %s " - "owned by uid %d", - injectionState->injectorPid, injectionState->injectorUid, - windowHandle->getName().c_str(), - windowHandle->getInfo()->ownerUid); + "owned by uid %d", + injectionState->injectorPid, injectionState->injectorUid, + windowHandle->getName().c_str(), windowHandle->getInfo()->ownerUid); } else { ALOGW("Permission denied: injecting event from pid %d uid %d", - injectionState->injectorPid, injectionState->injectorUid); + injectionState->injectorPid, injectionState->injectorUid); } return false; } return true; } -bool InputDispatcher::isWindowObscuredAtPointLocked( - const sp& windowHandle, int32_t x, int32_t y) const { +bool InputDispatcher::isWindowObscuredAtPointLocked(const sp& windowHandle, + int32_t x, int32_t y) const { int32_t displayId = windowHandle->getInfo()->displayId; const std::vector> windowHandles = getWindowHandlesLocked(displayId); for (const sp& otherHandle : windowHandles) { @@ -1836,16 +1840,14 @@ bool InputDispatcher::isWindowObscuredAtPointLocked( } const InputWindowInfo* otherInfo = otherHandle->getInfo(); - if (otherInfo->displayId == displayId - && otherInfo->visible && !otherInfo->isTrustedOverlay() - && otherInfo->frameContainsPoint(x, y)) { + if (otherInfo->displayId == displayId && otherInfo->visible && + !otherInfo->isTrustedOverlay() && otherInfo->frameContainsPoint(x, y)) { return true; } } return false; } - bool InputDispatcher::isWindowObscuredLocked(const sp& windowHandle) const { int32_t displayId = windowHandle->getInfo()->displayId; const std::vector> windowHandles = getWindowHandlesLocked(displayId); @@ -1856,18 +1858,17 @@ bool InputDispatcher::isWindowObscuredLocked(const sp& window } const InputWindowInfo* otherInfo = otherHandle->getInfo(); - if (otherInfo->displayId == displayId - && otherInfo->visible && !otherInfo->isTrustedOverlay() - && otherInfo->overlaps(windowInfo)) { + if (otherInfo->displayId == displayId && otherInfo->visible && + !otherInfo->isTrustedOverlay() && otherInfo->overlaps(windowInfo)) { return true; } } return false; } -std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime, - const sp& windowHandle, const EventEntry* eventEntry, - const char* targetType) { +std::string InputDispatcher::checkWindowReadyForMoreInputLocked( + nsecs_t currentTime, const sp& windowHandle, + const EventEntry* eventEntry, const char* targetType) { // If the window is paused then keep waiting. if (windowHandle->getInfo()->paused) { return StringPrintf("Waiting because the %s window is paused.", targetType); @@ -1878,15 +1879,16 @@ std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentT getConnectionLocked(getInputChannelLocked(windowHandle->getToken())); if (connection == nullptr) { return StringPrintf("Waiting because the %s window's input channel is not " - "registered with the input dispatcher. The window may be in the process " - "of being removed.", targetType); + "registered with the input dispatcher. The window may be in the " + "process of being removed.", + targetType); } // If the connection is dead then keep waiting. if (connection->status != Connection::STATUS_NORMAL) { return StringPrintf("Waiting because the %s window's input connection is %s." - "The window may be in the process of being removed.", targetType, - connection->getStatusLabel()); + "The window may be in the process of being removed.", + targetType, connection->getStatusLabel()); } // If the connection is backed up then keep waiting. @@ -1986,25 +1988,25 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { int32_t eventType = USER_ACTIVITY_EVENT_OTHER; switch (eventEntry->type) { - case EventEntry::TYPE_MOTION: { - const MotionEntry* motionEntry = static_cast(eventEntry); - if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) { - return; - } + case EventEntry::TYPE_MOTION: { + const MotionEntry* motionEntry = static_cast(eventEntry); + if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) { + return; + } - if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) { - eventType = USER_ACTIVITY_EVENT_TOUCH; + if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) { + eventType = USER_ACTIVITY_EVENT_TOUCH; + } + break; } - break; - } - case EventEntry::TYPE_KEY: { - const KeyEntry* keyEntry = static_cast(eventEntry); - if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) { - return; + case EventEntry::TYPE_KEY: { + const KeyEntry* keyEntry = static_cast(eventEntry); + if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) { + return; + } + eventType = USER_ACTIVITY_EVENT_BUTTON; + break; } - eventType = USER_ACTIVITY_EVENT_BUTTON; - break; - } } std::unique_ptr commandEntry = @@ -2015,22 +2017,22 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { } void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, - const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { + const sp& connection, + EventEntry* eventEntry, + const InputTarget* inputTarget) { if (ATRACE_ENABLED()) { - std::string message = StringPrintf( - "prepareDispatchCycleLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")", - connection->getInputChannelName().c_str(), eventEntry->sequenceNum); + std::string message = + StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")", + connection->getInputChannelName().c_str(), eventEntry->sequenceNum); ATRACE_NAME(message.c_str()); } #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, " - "xOffset=%f, yOffset=%f, globalScaleFactor=%f, " - "windowScaleFactor=(%f, %f), pointerIds=0x%x", - connection->getInputChannelName().c_str(), inputTarget->flags, - inputTarget->xOffset, inputTarget->yOffset, - inputTarget->globalScaleFactor, - inputTarget->windowXScale, inputTarget->windowYScale, - inputTarget->pointerIds.value); + "xOffset=%f, yOffset=%f, globalScaleFactor=%f, " + "windowScaleFactor=(%f, %f), pointerIds=0x%x", + connection->getInputChannelName().c_str(), inputTarget->flags, inputTarget->xOffset, + inputTarget->yOffset, inputTarget->globalScaleFactor, inputTarget->windowXScale, + inputTarget->windowYScale, inputTarget->pointerIds.value); #endif // Skip this event if the connection status is not normal. @@ -2038,7 +2040,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, if (connection->status != Connection::STATUS_NORMAL) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Dropping event because the channel status is %s", - connection->getInputChannelName().c_str(), connection->getStatusLabel()); + connection->getInputChannelName().c_str(), connection->getStatusLabel()); #endif return; } @@ -2049,18 +2051,16 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, MotionEntry* originalMotionEntry = static_cast(eventEntry); if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) { - MotionEntry* splitMotionEntry = splitMotionEvent( - originalMotionEntry, inputTarget->pointerIds); + MotionEntry* splitMotionEntry = + splitMotionEvent(originalMotionEntry, inputTarget->pointerIds); if (!splitMotionEntry) { return; // split event was dropped } #if DEBUG_FOCUS - ALOGD("channel '%s' ~ Split motion event.", - connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ Split motion event.", connection->getInputChannelName().c_str()); logOutboundMotionDetails(" ", splitMotionEntry); #endif - enqueueDispatchEntriesLocked(currentTime, connection, - splitMotionEntry, inputTarget); + enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget); splitMotionEntry->release(); return; } @@ -2071,11 +2071,14 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, } void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, - const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { + const sp& connection, + EventEntry* eventEntry, + const InputTarget* inputTarget) { if (ATRACE_ENABLED()) { - std::string message = StringPrintf( - "enqueueDispatchEntriesLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")", - connection->getInputChannelName().c_str(), eventEntry->sequenceNum); + std::string message = + StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, sequenceNum=%" PRIu32 + ")", + connection->getInputChannelName().c_str(), eventEntry->sequenceNum); ATRACE_NAME(message.c_str()); } @@ -2083,17 +2086,17 @@ void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, // Enqueue dispatch entries for the requested modes. enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); + InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_OUTSIDE); + InputTarget::FLAG_DISPATCH_AS_OUTSIDE); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); + InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_IS); + InputTarget::FLAG_DISPATCH_AS_IS); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); + InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); + InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); // If the outbound queue was previously empty, start the dispatch cycle going. if (wasEmpty && !connection->outboundQueue.empty()) { @@ -2101,14 +2104,14 @@ void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, } } -void InputDispatcher::enqueueDispatchEntryLocked( - const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget, - int32_t dispatchMode) { +void InputDispatcher::enqueueDispatchEntryLocked(const sp& connection, + EventEntry* eventEntry, + const InputTarget* inputTarget, + int32_t dispatchMode) { if (ATRACE_ENABLED()) { - std::string message = StringPrintf( - "enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)", - connection->getInputChannelName().c_str(), - dispatchModeToString(dispatchMode).c_str()); + std::string message = StringPrintf("enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)", + connection->getInputChannelName().c_str(), + dispatchModeToString(dispatchMode).c_str()); ATRACE_NAME(message.c_str()); } int32_t inputTargetFlags = inputTarget->flags; @@ -2119,78 +2122,81 @@ void InputDispatcher::enqueueDispatchEntryLocked( // This is a new event. // Enqueue a new dispatch entry onto the outbound queue for this connection. - DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref - inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, - inputTarget->globalScaleFactor, inputTarget->windowXScale, - inputTarget->windowYScale); + DispatchEntry* dispatchEntry = + new DispatchEntry(eventEntry, // increments ref + inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, + inputTarget->globalScaleFactor, inputTarget->windowXScale, + inputTarget->windowYScale); // Apply target flags and update the connection's input state. switch (eventEntry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast(eventEntry); - dispatchEntry->resolvedAction = keyEntry->action; - dispatchEntry->resolvedFlags = keyEntry->flags; + case EventEntry::TYPE_KEY: { + KeyEntry* keyEntry = static_cast(eventEntry); + dispatchEntry->resolvedAction = keyEntry->action; + dispatchEntry->resolvedFlags = keyEntry->flags; - if (!connection->inputState.trackKey(keyEntry, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { + if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction, + dispatchEntry->resolvedFlags)) { #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event", - connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event", + connection->getInputChannelName().c_str()); #endif - delete dispatchEntry; - return; // skip the inconsistent event - } - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast(eventEntry); - if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN; - } else { - dispatchEntry->resolvedAction = motionEntry->action; + delete dispatchEntry; + return; // skip the inconsistent event + } + break; } - if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE - && !connection->inputState.isHovering( - motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) { + + case EventEntry::TYPE_MOTION: { + MotionEntry* motionEntry = static_cast(eventEntry); + if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE; + } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT; + } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; + } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL; + } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN; + } else { + dispatchEntry->resolvedAction = motionEntry->action; + } + if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE && + !connection->inputState.isHovering(motionEntry->deviceId, motionEntry->source, + motionEntry->displayId)) { #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event", - connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter " + "event", + connection->getInputChannelName().c_str()); #endif - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; - } + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; + } - dispatchEntry->resolvedFlags = motionEntry->flags; - if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { - dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; - } - if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) { - dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; - } + dispatchEntry->resolvedFlags = motionEntry->flags; + if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { + dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; + } + if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) { + dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + } - if (!connection->inputState.trackMotion(motionEntry, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { + if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction, + dispatchEntry->resolvedFlags)) { #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event", - connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion " + "event", + connection->getInputChannelName().c_str()); #endif - delete dispatchEntry; - return; // skip the inconsistent event - } + delete dispatchEntry; + return; // skip the inconsistent event + } - dispatchPointerDownOutsideFocus(motionEntry->source, - dispatchEntry->resolvedAction, inputTarget->inputChannel->getToken()); + dispatchPointerDownOutsideFocus(motionEntry->source, dispatchEntry->resolvedAction, + inputTarget->inputChannel->getToken()); - break; - } + break; + } } // Remember that we are waiting for this dispatch to complete. @@ -2201,11 +2207,10 @@ void InputDispatcher::enqueueDispatchEntryLocked( // Enqueue the dispatch entry. connection->outboundQueue.push_back(dispatchEntry); traceOutboundQueueLength(connection); - } void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, - const sp& newToken) { + const sp& newToken) { int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; uint32_t maskedSource = source & AINPUT_SOURCE_CLASS_MASK; if (maskedSource != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) { @@ -2233,15 +2238,14 @@ void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t a } void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, - const sp& connection) { + const sp& connection) { if (ATRACE_ENABLED()) { std::string message = StringPrintf("startDispatchCycleLocked(inputChannel=%s)", - connection->getInputChannelName().c_str()); + connection->getInputChannelName().c_str()); ATRACE_NAME(message.c_str()); } #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ startDispatchCycle", - connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str()); #endif while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) { @@ -2252,76 +2256,79 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, status_t status; EventEntry* eventEntry = dispatchEntry->eventEntry; switch (eventEntry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast(eventEntry); - - // Publish the key event. - status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, - keyEntry->deviceId, keyEntry->source, keyEntry->displayId, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, - keyEntry->keyCode, keyEntry->scanCode, - keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, - keyEntry->eventTime); - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast(eventEntry); + case EventEntry::TYPE_KEY: { + KeyEntry* keyEntry = static_cast(eventEntry); + + // Publish the key event. + status = connection->inputPublisher + .publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId, + keyEntry->source, keyEntry->displayId, + dispatchEntry->resolvedAction, + dispatchEntry->resolvedFlags, keyEntry->keyCode, + keyEntry->scanCode, keyEntry->metaState, + keyEntry->repeatCount, keyEntry->downTime, + keyEntry->eventTime); + break; + } - PointerCoords scaledCoords[MAX_POINTERS]; - const PointerCoords* usingCoords = motionEntry->pointerCoords; - - // Set the X and Y offset depending on the input source. - float xOffset, yOffset; - if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) - && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { - float globalScaleFactor = dispatchEntry->globalScaleFactor; - float wxs = dispatchEntry->windowXScale; - float wys = dispatchEntry->windowYScale; - xOffset = dispatchEntry->xOffset * wxs; - yOffset = dispatchEntry->yOffset * wys; - if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) { - for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { - scaledCoords[i] = motionEntry->pointerCoords[i]; - scaledCoords[i].scale(globalScaleFactor, wxs, wys); + case EventEntry::TYPE_MOTION: { + MotionEntry* motionEntry = static_cast(eventEntry); + + PointerCoords scaledCoords[MAX_POINTERS]; + const PointerCoords* usingCoords = motionEntry->pointerCoords; + + // Set the X and Y offset depending on the input source. + float xOffset, yOffset; + if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && + !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { + float globalScaleFactor = dispatchEntry->globalScaleFactor; + float wxs = dispatchEntry->windowXScale; + float wys = dispatchEntry->windowYScale; + xOffset = dispatchEntry->xOffset * wxs; + yOffset = dispatchEntry->yOffset * wys; + if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) { + for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { + scaledCoords[i] = motionEntry->pointerCoords[i]; + scaledCoords[i].scale(globalScaleFactor, wxs, wys); + } + usingCoords = scaledCoords; } - usingCoords = scaledCoords; - } - } else { - xOffset = 0.0f; - yOffset = 0.0f; + } else { + xOffset = 0.0f; + yOffset = 0.0f; - // We don't want the dispatch target to know. - if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { - for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { - scaledCoords[i].clear(); + // We don't want the dispatch target to know. + if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { + for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { + scaledCoords[i].clear(); + } + usingCoords = scaledCoords; } - usingCoords = scaledCoords; } - } - // Publish the motion event. - status = - connection->inputPublisher - .publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, - motionEntry->source, motionEntry->displayId, - dispatchEntry->resolvedAction, - motionEntry->actionButton, - dispatchEntry->resolvedFlags, - motionEntry->edgeFlags, motionEntry->metaState, - motionEntry->buttonState, - motionEntry->classification, xOffset, yOffset, - motionEntry->xPrecision, motionEntry->yPrecision, - motionEntry->xCursorPosition, - motionEntry->yCursorPosition, motionEntry->downTime, - motionEntry->eventTime, motionEntry->pointerCount, - motionEntry->pointerProperties, usingCoords); - break; - } + // Publish the motion event. + status = connection->inputPublisher + .publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, + motionEntry->source, motionEntry->displayId, + dispatchEntry->resolvedAction, + motionEntry->actionButton, + dispatchEntry->resolvedFlags, + motionEntry->edgeFlags, motionEntry->metaState, + motionEntry->buttonState, + motionEntry->classification, xOffset, yOffset, + motionEntry->xPrecision, + motionEntry->yPrecision, + motionEntry->xCursorPosition, + motionEntry->yCursorPosition, + motionEntry->downTime, motionEntry->eventTime, + motionEntry->pointerCount, + motionEntry->pointerProperties, usingCoords); + break; + } - default: - ALOG_ASSERT(false); - return; + default: + ALOG_ASSERT(false); + return; } // Check the result. @@ -2329,24 +2336,25 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, if (status == WOULD_BLOCK) { if (connection->waitQueue.empty()) { ALOGE("channel '%s' ~ Could not publish event because the pipe is full. " - "This is unexpected because the wait queue is empty, so the pipe " - "should be empty and we shouldn't have any problems writing an " - "event to it, status=%d", connection->getInputChannelName().c_str(), - status); + "This is unexpected because the wait queue is empty, so the pipe " + "should be empty and we shouldn't have any problems writing an " + "event to it, status=%d", + connection->getInputChannelName().c_str(), status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } else { // Pipe is full and we are waiting for the app to finish process some events // before sending more events to it. #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Could not publish event because the pipe is full, " - "waiting for the application to catch up", - connection->getInputChannelName().c_str()); + "waiting for the application to catch up", + connection->getInputChannelName().c_str()); #endif connection->inputPublisherBlocked = true; } } else { ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, " - "status=%d", connection->getInputChannelName().c_str(), status); + "status=%d", + connection->getInputChannelName().c_str(), status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } return; @@ -2363,16 +2371,17 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, } void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, - const sp& connection, uint32_t seq, bool handled) { + const sp& connection, uint32_t seq, + bool handled) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s", - connection->getInputChannelName().c_str(), seq, toString(handled)); + connection->getInputChannelName().c_str(), seq, toString(handled)); #endif connection->inputPublisherBlocked = false; - if (connection->status == Connection::STATUS_BROKEN - || connection->status == Connection::STATUS_ZOMBIE) { + if (connection->status == Connection::STATUS_BROKEN || + connection->status == Connection::STATUS_ZOMBIE) { return; } @@ -2381,10 +2390,11 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, } void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, - const sp& connection, bool notify) { + const sp& connection, + bool notify) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s", - connection->getInputChannelName().c_str(), toString(notify)); + connection->getInputChannelName().c_str(), toString(notify)); #endif // Clear the dispatch queues. @@ -2428,7 +2438,8 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { if (d->mConnectionsByFd.find(fd) == d->mConnectionsByFd.end()) { ALOGE("Received spurious receive callback for unknown input channel. " - "fd=%d, events=0x%x", fd, events); + "fd=%d, events=0x%x", + fd, events); return 0; // remove the callback } @@ -2437,7 +2448,8 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) { if (!(events & ALOOPER_EVENT_INPUT)) { ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " - "events=0x%x", connection->getInputChannelName().c_str(), events); + "events=0x%x", + connection->getInputChannelName().c_str(), events); return 1; } @@ -2464,7 +2476,7 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { notify = status != DEAD_OBJECT || !connection->monitor; if (notify) { ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d", - connection->getInputChannelName().c_str(), status); + connection->getInputChannelName().c_str(), status); } } else { // Monitor channels are never explicitly unregistered. @@ -2473,24 +2485,25 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { notify = !connection->monitor; if (notify) { ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. " - "events=0x%x", connection->getInputChannelName().c_str(), events); + "events=0x%x", + connection->getInputChannelName().c_str(), events); } } // Unregister the channel. d->unregisterInputChannelLocked(connection->inputChannel, notify); return 0; // remove the callback - } // release lock + } // release lock } -void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked ( +void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( const CancelationOptions& options) { for (const auto& pair : mConnectionsByFd) { synthesizeCancelationEventsForConnectionLocked(pair.second, options); } } -void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked ( +void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked( const CancelationOptions& options) { synthesizeCancelationEventsForMonitorsLocked(options, mGlobalMonitorsByDisplay); synthesizeCancelationEventsForMonitorsLocked(options, mGestureMonitorsByDisplay); @@ -2526,32 +2539,31 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( nsecs_t currentTime = now(); std::vector cancelationEvents; - connection->inputState.synthesizeCancelationEvents(currentTime, - cancelationEvents, options); + connection->inputState.synthesizeCancelationEvents(currentTime, cancelationEvents, options); if (!cancelationEvents.empty()) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync " - "with reality: %s, mode=%d.", - connection->getInputChannelName().c_str(), cancelationEvents.size(), - options.reason, options.mode); + "with reality: %s, mode=%d.", + connection->getInputChannelName().c_str(), cancelationEvents.size(), options.reason, + options.mode); #endif for (size_t i = 0; i < cancelationEvents.size(); i++) { EventEntry* cancelationEventEntry = cancelationEvents[i]; switch (cancelationEventEntry->type) { - case EventEntry::TYPE_KEY: - logOutboundKeyDetails("cancel - ", - static_cast(cancelationEventEntry)); - break; - case EventEntry::TYPE_MOTION: - logOutboundMotionDetails("cancel - ", - static_cast(cancelationEventEntry)); - break; + case EventEntry::TYPE_KEY: + logOutboundKeyDetails("cancel - ", + static_cast(cancelationEventEntry)); + break; + case EventEntry::TYPE_MOTION: + logOutboundMotionDetails("cancel - ", + static_cast(cancelationEventEntry)); + break; } InputTarget target; - sp windowHandle = getWindowHandleLocked( - connection->inputChannel->getToken()); + sp windowHandle = + getWindowHandleLocked(connection->inputChannel->getToken()); if (windowHandle != nullptr) { const InputWindowInfo* windowInfo = windowHandle->getInfo(); target.xOffset = -windowInfo->frameLeft; @@ -2568,7 +2580,7 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( target.flags = InputTarget::FLAG_DISPATCH_AS_IS; enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref - &target, InputTarget::FLAG_DISPATCH_AS_IS); + &target, InputTarget::FLAG_DISPATCH_AS_IS); cancelationEventEntry->release(); } @@ -2577,8 +2589,8 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( } } -InputDispatcher::MotionEntry* -InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) { +InputDispatcher::MotionEntry* InputDispatcher::splitMotionEvent( + const MotionEntry* originalMotionEntry, BitSet32 pointerIds) { ALOG_ASSERT(pointerIds.value != 0); uint32_t splitPointerIndexMap[MAX_POINTERS]; @@ -2589,7 +2601,7 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet uint32_t splitPointerCount = 0; for (uint32_t originalPointerIndex = 0; originalPointerIndex < originalPointerCount; - originalPointerIndex++) { + originalPointerIndex++) { const PointerProperties& pointerProperties = originalMotionEntry->pointerProperties[originalPointerIndex]; uint32_t pointerId = uint32_t(pointerProperties.id); @@ -2609,16 +2621,16 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet // or ACTION_POINTER_DOWN events that caused us to decide to split the pointers // in this way. ALOGW("Dropping split motion event because the pointer count is %d but " - "we expected there to be %d pointers. This probably means we received " - "a broken sequence of pointer ids from the input device.", - splitPointerCount, pointerIds.count()); + "we expected there to be %d pointers. This probably means we received " + "a broken sequence of pointer ids from the input device.", + splitPointerCount, pointerIds.count()); return nullptr; } int32_t action = originalMotionEntry->action; int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; - if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN - || maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { + if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN || + maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { int32_t originalPointerIndex = getMotionEventActionPointerIndex(action); const PointerProperties& pointerProperties = originalMotionEntry->pointerProperties[originalPointerIndex]; @@ -2627,15 +2639,16 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet if (pointerIds.count() == 1) { // The first/last pointer went down/up. action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN - ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; + ? AMOTION_EVENT_ACTION_DOWN + : AMOTION_EVENT_ACTION_UP; } else { // A secondary pointer went down/up. uint32_t splitPointerIndex = 0; while (pointerId != uint32_t(splitPointerProperties[splitPointerIndex].id)) { splitPointerIndex += 1; } - action = maskedAction | (splitPointerIndex - << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + action = maskedAction | + (splitPointerIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); } } else { // An unrelated pointer changed. @@ -2689,7 +2702,7 @@ void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChange * This will potentially overwrite keyCode and metaState. */ void InputDispatcher::accelerateMetaShortcuts(const int32_t deviceId, const int32_t action, - int32_t& keyCode, int32_t& metaState) { + int32_t& keyCode, int32_t& metaState) { if (metaState & AMETA_META_ON && action == AKEY_EVENT_ACTION_DOWN) { int32_t newKeyCode = AKEYCODE_UNKNOWN; if (keyCode == AKEYCODE_DEL) { @@ -2721,12 +2734,12 @@ void InputDispatcher::accelerateMetaShortcuts(const int32_t deviceId, const int3 void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyKey - eventTime=%" PRId64 - ", deviceId=%d, source=0x%x, displayId=%" PRId32 "policyFlags=0x%x, action=0x%x, " - "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64, - args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, - args->action, args->flags, args->keyCode, args->scanCode, - args->metaState, args->downTime); + ALOGD("notifyKey - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 + "policyFlags=0x%x, action=0x%x, " + "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64, + args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, + args->action, args->flags, args->keyCode, args->scanCode, args->metaState, + args->downTime); #endif if (!validateKeyEvent(args->action)) { return; @@ -2752,15 +2765,14 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState); KeyEvent event; - event.initialize(args->deviceId, args->source, args->displayId, args->action, - flags, keyCode, args->scanCode, metaState, repeatCount, - args->downTime, args->eventTime); + event.initialize(args->deviceId, args->source, args->displayId, args->action, flags, keyCode, + args->scanCode, metaState, repeatCount, args->downTime, args->eventTime); android::base::Timer t; mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms", - std::to_string(t.duration().count()).c_str()); + std::to_string(t.duration().count()).c_str()); } bool needWake; @@ -2778,10 +2790,10 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { mLock.lock(); } - KeyEntry* newEntry = new KeyEntry(args->sequenceNum, args->eventTime, - args->deviceId, args->source, args->displayId, policyFlags, - args->action, flags, keyCode, args->scanCode, - metaState, repeatCount, args->downTime); + KeyEntry* newEntry = + new KeyEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source, + args->displayId, policyFlags, args->action, flags, keyCode, + args->scanCode, metaState, repeatCount, args->downTime); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); @@ -2809,24 +2821,23 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->yCursorPosition, args->downTime); for (uint32_t i = 0; i < args->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " - "x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, args->pointerProperties[i].id, - args->pointerProperties[i].toolType, - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); + "x=%f, y=%f, pressure=%f, size=%f, " + "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " + "orientation=%f", + i, args->pointerProperties[i].id, args->pointerProperties[i].toolType, + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); } #endif - if (!validateMotionEvent(args->action, args->actionButton, - args->pointerCount, args->pointerProperties)) { + if (!validateMotionEvent(args->action, args->actionButton, args->pointerCount, + args->pointerProperties)) { return; } @@ -2837,7 +2848,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mPolicy->interceptMotionBeforeQueueing(args->displayId, args->eventTime, /*byref*/ policyFlags); if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms", - std::to_string(t.duration().count()).c_str()); + std::to_string(t.duration().count()).c_str()); } bool needWake; @@ -2889,20 +2900,19 @@ bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, " - "switchMask=0x%08x", - args->eventTime, args->policyFlags, args->switchValues, args->switchMask); + "switchMask=0x%08x", + args->eventTime, args->policyFlags, args->switchValues, args->switchMask); #endif uint32_t policyFlags = args->policyFlags; policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->notifySwitch(args->eventTime, - args->switchValues, args->switchMask, policyFlags); + mPolicy->notifySwitch(args->eventTime, args->switchValues, args->switchMask, policyFlags); } void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", - args->eventTime, args->deviceId); + ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args->eventTime, + args->deviceId); #endif bool needWake; @@ -2919,13 +2929,13 @@ void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { } } -int32_t InputDispatcher::injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags) { +int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injectorPid, + int32_t injectorUid, int32_t syncMode, + int32_t timeoutMillis, uint32_t policyFlags) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " - "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x", - event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags); + "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x", + event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags); #endif nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis); @@ -2937,87 +2947,74 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, std::queue injectedEntries; switch (event->getType()) { - case AINPUT_EVENT_TYPE_KEY: { - KeyEvent keyEvent; - keyEvent.initialize(*static_cast(event)); - int32_t action = keyEvent.getAction(); - if (! validateKeyEvent(action)) { - return INPUT_EVENT_INJECTION_FAILED; - } - - int32_t flags = keyEvent.getFlags(); - int32_t keyCode = keyEvent.getKeyCode(); - int32_t metaState = keyEvent.getMetaState(); - accelerateMetaShortcuts(keyEvent.getDeviceId(), action, - /*byref*/ keyCode, /*byref*/ metaState); - keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(), - action, flags, keyCode, keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(), - keyEvent.getDownTime(), keyEvent.getEventTime()); + case AINPUT_EVENT_TYPE_KEY: { + KeyEvent keyEvent; + keyEvent.initialize(*static_cast(event)); + int32_t action = keyEvent.getAction(); + if (!validateKeyEvent(action)) { + return INPUT_EVENT_INJECTION_FAILED; + } - if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { - policyFlags |= POLICY_FLAG_VIRTUAL; - } + int32_t flags = keyEvent.getFlags(); + int32_t keyCode = keyEvent.getKeyCode(); + int32_t metaState = keyEvent.getMetaState(); + accelerateMetaShortcuts(keyEvent.getDeviceId(), action, + /*byref*/ keyCode, /*byref*/ metaState); + keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), + keyEvent.getDisplayId(), action, flags, keyCode, + keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(), + keyEvent.getDownTime(), keyEvent.getEventTime()); + + if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { + policyFlags |= POLICY_FLAG_VIRTUAL; + } - if (!(policyFlags & POLICY_FLAG_FILTERED)) { - android::base::Timer t; - mPolicy->interceptKeyBeforeQueueing(&keyEvent, /*byref*/ policyFlags); - if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { - ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms", - std::to_string(t.duration().count()).c_str()); + if (!(policyFlags & POLICY_FLAG_FILTERED)) { + android::base::Timer t; + mPolicy->interceptKeyBeforeQueueing(&keyEvent, /*byref*/ policyFlags); + if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { + ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms", + std::to_string(t.duration().count()).c_str()); + } } - } - mLock.lock(); - KeyEntry* injectedEntry = - new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(), - keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(), - policyFlags, action, flags, keyEvent.getKeyCode(), - keyEvent.getScanCode(), keyEvent.getMetaState(), - keyEvent.getRepeatCount(), keyEvent.getDownTime()); - injectedEntries.push(injectedEntry); - break; - } - - case AINPUT_EVENT_TYPE_MOTION: { - const MotionEvent* motionEvent = static_cast(event); - int32_t action = motionEvent->getAction(); - size_t pointerCount = motionEvent->getPointerCount(); - const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); - int32_t actionButton = motionEvent->getActionButton(); - int32_t displayId = motionEvent->getDisplayId(); - if (! validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) { - return INPUT_EVENT_INJECTION_FAILED; + mLock.lock(); + KeyEntry* injectedEntry = + new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(), + keyEvent.getDeviceId(), keyEvent.getSource(), + keyEvent.getDisplayId(), policyFlags, action, flags, + keyEvent.getKeyCode(), keyEvent.getScanCode(), + keyEvent.getMetaState(), keyEvent.getRepeatCount(), + keyEvent.getDownTime()); + injectedEntries.push(injectedEntry); + break; } - if (!(policyFlags & POLICY_FLAG_FILTERED)) { - nsecs_t eventTime = motionEvent->getEventTime(); - android::base::Timer t; - mPolicy->interceptMotionBeforeQueueing(displayId, eventTime, /*byref*/ policyFlags); - if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { - ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms", - std::to_string(t.duration().count()).c_str()); + case AINPUT_EVENT_TYPE_MOTION: { + const MotionEvent* motionEvent = static_cast(event); + int32_t action = motionEvent->getAction(); + size_t pointerCount = motionEvent->getPointerCount(); + const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); + int32_t actionButton = motionEvent->getActionButton(); + int32_t displayId = motionEvent->getDisplayId(); + if (!validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) { + return INPUT_EVENT_INJECTION_FAILED; } - } - mLock.lock(); - const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); - const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); - MotionEntry* injectedEntry = - new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), - motionEvent->getDisplayId(), policyFlags, action, actionButton, - motionEvent->getFlags(), motionEvent->getMetaState(), - motionEvent->getButtonState(), motionEvent->getClassification(), - motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), - motionEvent->getYPrecision(), motionEvent->getRawXCursorPosition(), - motionEvent->getRawYCursorPosition(), motionEvent->getDownTime(), - uint32_t(pointerCount), pointerProperties, samplePointerCoords, - motionEvent->getXOffset(), motionEvent->getYOffset()); - injectedEntries.push(injectedEntry); - for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { - sampleEventTimes += 1; - samplePointerCoords += pointerCount; - MotionEntry* nextInjectedEntry = + if (!(policyFlags & POLICY_FLAG_FILTERED)) { + nsecs_t eventTime = motionEvent->getEventTime(); + android::base::Timer t; + mPolicy->interceptMotionBeforeQueueing(displayId, eventTime, /*byref*/ policyFlags); + if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { + ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms", + std::to_string(t.duration().count()).c_str()); + } + } + + mLock.lock(); + const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); + const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); + MotionEntry* injectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, motionEvent->getDeviceId(), motionEvent->getSource(), motionEvent->getDisplayId(), policyFlags, action, actionButton, @@ -3030,14 +3027,32 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, motionEvent->getDownTime(), uint32_t(pointerCount), pointerProperties, samplePointerCoords, motionEvent->getXOffset(), motionEvent->getYOffset()); - injectedEntries.push(nextInjectedEntry); + injectedEntries.push(injectedEntry); + for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { + sampleEventTimes += 1; + samplePointerCoords += pointerCount; + MotionEntry* nextInjectedEntry = + new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, + motionEvent->getDeviceId(), motionEvent->getSource(), + motionEvent->getDisplayId(), policyFlags, action, + actionButton, motionEvent->getFlags(), + motionEvent->getMetaState(), motionEvent->getButtonState(), + motionEvent->getClassification(), + motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), + motionEvent->getYPrecision(), + motionEvent->getRawXCursorPosition(), + motionEvent->getRawYCursorPosition(), + motionEvent->getDownTime(), uint32_t(pointerCount), + pointerProperties, samplePointerCoords, + motionEvent->getXOffset(), motionEvent->getYOffset()); + injectedEntries.push(nextInjectedEntry); + } + break; } - break; - } - default: - ALOGW("Cannot inject event of type %d", event->getType()); - return INPUT_EVENT_INJECTION_FAILED; + default: + ALOGW("Cannot inject event of type %d", event->getType()); + return INPUT_EVENT_INJECTION_FAILED; } InjectionState* injectionState = new InjectionState(injectorPid, injectorUid); @@ -3077,7 +3092,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, if (remainingTimeout <= 0) { #if DEBUG_INJECTION ALOGD("injectInputEvent - Timed out waiting for injection result " - "to become available."); + "to become available."); #endif injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; break; @@ -3086,18 +3101,18 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, mInjectionResultAvailable.wait_for(_l, std::chrono::nanoseconds(remainingTimeout)); } - if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED - && syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) { + if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED && + syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) { while (injectionState->pendingForegroundDispatches != 0) { #if DEBUG_INJECTION ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.", - injectionState->pendingForegroundDispatches); + injectionState->pendingForegroundDispatches); #endif nsecs_t remainingTimeout = endTime - now(); if (remainingTimeout <= 0) { #if DEBUG_INJECTION - ALOGD("injectInputEvent - Timed out waiting for pending foreground " - "dispatches to finish."); + ALOGD("injectInputEvent - Timed out waiting for pending foreground " + "dispatches to finish."); #endif injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; break; @@ -3113,16 +3128,16 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, #if DEBUG_INJECTION ALOGD("injectInputEvent - Finished with result %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectorPid, injectorUid); + "injectorPid=%d, injectorUid=%d", + injectionResult, injectorPid, injectorUid); #endif return injectionResult; } bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { - return injectorUid == 0 - || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); + return injectorUid == 0 || + mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); } void InputDispatcher::setInjectionResult(EventEntry* entry, int32_t injectionResult) { @@ -3130,26 +3145,25 @@ void InputDispatcher::setInjectionResult(EventEntry* entry, int32_t injectionRes if (injectionState) { #if DEBUG_INJECTION ALOGD("Setting input event injection result to %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectionState->injectorPid, injectionState->injectorUid); + "injectorPid=%d, injectorUid=%d", + injectionResult, injectionState->injectorPid, injectionState->injectorUid); #endif - if (injectionState->injectionIsAsync - && !(entry->policyFlags & POLICY_FLAG_FILTERED)) { + if (injectionState->injectionIsAsync && !(entry->policyFlags & POLICY_FLAG_FILTERED)) { // Log the outcome since the injector did not wait for the injection result. switch (injectionResult) { - case INPUT_EVENT_INJECTION_SUCCEEDED: - ALOGV("Asynchronous input event injection succeeded."); - break; - case INPUT_EVENT_INJECTION_FAILED: - ALOGW("Asynchronous input event injection failed."); - break; - case INPUT_EVENT_INJECTION_PERMISSION_DENIED: - ALOGW("Asynchronous input event injection permission denied."); - break; - case INPUT_EVENT_INJECTION_TIMED_OUT: - ALOGW("Asynchronous input event injection timed out."); - break; + case INPUT_EVENT_INJECTION_SUCCEEDED: + ALOGV("Asynchronous input event injection succeeded."); + break; + case INPUT_EVENT_INJECTION_FAILED: + ALOGW("Asynchronous input event injection failed."); + break; + case INPUT_EVENT_INJECTION_PERMISSION_DENIED: + ALOGW("Asynchronous input event injection permission denied."); + break; + case INPUT_EVENT_INJECTION_TIMED_OUT: + ALOGW("Asynchronous input event injection timed out."); + break; } } @@ -3201,9 +3215,9 @@ bool InputDispatcher::hasWindowHandleLocked(const sp& windowH if (handle->getToken() == windowHandle->getToken()) { if (windowHandle->getInfo()->displayId != it.first) { ALOGE("Found window %s in display %" PRId32 - ", but it should belong to display %" PRId32, - windowHandle->getName().c_str(), it.first, - windowHandle->getInfo()->displayId); + ", but it should belong to display %" PRId32, + windowHandle->getName().c_str(), it.first, + windowHandle->getInfo()->displayId); } return true; } @@ -3285,7 +3299,8 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( * For removed handle, check if need to send a cancel event if already in touch. */ void InputDispatcher::setInputWindows(const std::vector>& inputWindowHandles, - int32_t displayId, const sp& setInputWindowsListener) { + int32_t displayId, + const sp& setInputWindowsListener) { #if DEBUG_FOCUS ALOGD("setInputWindows displayId=%" PRId32, displayId); #endif @@ -3322,22 +3337,21 @@ void InputDispatcher::setInputWindows(const std::vector>& if (oldFocusedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Focus left window: %s in display %" PRId32, - oldFocusedWindowHandle->getName().c_str(), displayId); + oldFocusedWindowHandle->getName().c_str(), displayId); #endif - sp focusedInputChannel = getInputChannelLocked( - oldFocusedWindowHandle->getToken()); + sp focusedInputChannel = + getInputChannelLocked(oldFocusedWindowHandle->getToken()); if (focusedInputChannel != nullptr) { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, - "focus left window"); - synthesizeCancelationEventsForInputChannelLocked( - focusedInputChannel, options); + "focus left window"); + synthesizeCancelationEventsForInputChannelLocked(focusedInputChannel, options); } mFocusedWindowHandlesByDisplay.erase(displayId); } if (newFocusedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Focus entered window: %s in display %" PRId32, - newFocusedWindowHandle->getName().c_str(), displayId); + newFocusedWindowHandle->getName().c_str(), displayId); #endif mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle; } @@ -3345,30 +3359,29 @@ void InputDispatcher::setInputWindows(const std::vector>& if (mFocusedDisplayId == displayId) { onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle); } - } ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId); if (stateIndex >= 0) { TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex); - for (size_t i = 0; i < state.windows.size(); ) { + for (size_t i = 0; i < state.windows.size();) { TouchedWindow& touchedWindow = state.windows[i]; if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { #if DEBUG_FOCUS ALOGD("Touched window was removed: %s in display %" PRId32, - touchedWindow.windowHandle->getName().c_str(), displayId); + touchedWindow.windowHandle->getName().c_str(), displayId); #endif sp touchedInputChannel = getInputChannelLocked(touchedWindow.windowHandle->getToken()); if (touchedInputChannel != nullptr) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "touched window was removed"); - synthesizeCancelationEventsForInputChannelLocked( - touchedInputChannel, options); + "touched window was removed"); + synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, + options); } state.windows.erase(state.windows.begin() + i); } else { - ++i; + ++i; } } } @@ -3419,7 +3432,7 @@ void InputDispatcher::setFocusedApplication( } #if DEBUG_FOCUS - //logDispatchStateLocked(); + // logDispatchStateLocked(); #endif } // release lock @@ -3448,11 +3461,11 @@ void InputDispatcher::setFocusedDisplay(int32_t displayId) { getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId); if (oldFocusedWindowHandle != nullptr) { sp inputChannel = - getInputChannelLocked(oldFocusedWindowHandle->getToken()); + getInputChannelLocked(oldFocusedWindowHandle->getToken()); if (inputChannel != nullptr) { - CancelationOptions options( - CancelationOptions::CANCEL_NON_POINTER_EVENTS, - "The display which contains this window no longer has focus."); + CancelationOptions + options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, + "The display which contains this window no longer has focus."); options.displayId = ADISPLAY_ID_NONE; synthesizeCancelationEventsForInputChannelLocked(inputChannel, options); } @@ -3471,8 +3484,8 @@ void InputDispatcher::setFocusedDisplay(int32_t displayId) { for (auto& it : mFocusedWindowHandlesByDisplay) { const int32_t displayId = it.first; const sp& windowHandle = it.second; - ALOGE("Display #%" PRId32 " has focused window: '%s'\n", - displayId, windowHandle->getName().c_str()); + ALOGE("Display #%" PRId32 " has focused window: '%s'\n", displayId, + windowHandle->getName().c_str()); } } } @@ -3562,7 +3575,7 @@ bool InputDispatcher::transferTouchFocus(const sp& fromToken, const sp< } #if DEBUG_FOCUS ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s", - fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str()); + fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str()); #endif if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) { #if DEBUG_FOCUS @@ -3582,9 +3595,9 @@ bool InputDispatcher::transferTouchFocus(const sp& fromToken, const sp< state.windows.erase(state.windows.begin() + i); - int32_t newTargetFlags = oldTargetFlags - & (InputTarget::FLAG_FOREGROUND - | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); + int32_t newTargetFlags = oldTargetFlags & + (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT | + InputTarget::FLAG_DISPATCH_AS_IS); state.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); found = true; @@ -3592,9 +3605,9 @@ bool InputDispatcher::transferTouchFocus(const sp& fromToken, const sp< } } } -Found: + Found: - if (! found) { + if (!found) { #if DEBUG_FOCUS ALOGD("Focus transfer failed because from window did not have focus."); #endif @@ -3607,8 +3620,9 @@ Found: sp toConnection = getConnectionLocked(toChannel); if (fromConnection != nullptr && toConnection != nullptr) { fromConnection->inputState.copyPointerStateTo(toConnection->inputState); - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "transferring touch focus from this window to another window"); + CancelationOptions + options(CancelationOptions::CANCEL_POINTER_EVENTS, + "transferring touch focus from this window to another window"); synthesizeCancelationEventsForConnectionLocked(fromConnection, options); } @@ -3663,12 +3677,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (auto& it : mFocusedApplicationHandlesByDisplay) { const int32_t displayId = it.first; const sp& applicationHandle = it.second; - dump += StringPrintf( - INDENT2 "displayId=%" PRId32 ", name='%s', dispatchingTimeout=%0.3fms\n", - displayId, - applicationHandle->getName().c_str(), - applicationHandle->getDispatchingTimeout( - DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0); + dump += StringPrintf(INDENT2 "displayId=%" PRId32 + ", name='%s', dispatchingTimeout=%0.3fms\n", + displayId, applicationHandle->getName().c_str(), + applicationHandle->getDispatchingTimeout( + DEFAULT_INPUT_DISPATCHING_TIMEOUT) / + 1000000.0); } } else { dump += StringPrintf(INDENT "FocusedApplications: \n"); @@ -3679,8 +3693,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (auto& it : mFocusedWindowHandlesByDisplay) { const int32_t displayId = it.first; const sp& windowHandle = it.second; - dump += StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", - displayId, windowHandle->getName().c_str()); + dump += StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", displayId, + windowHandle->getName().c_str()); } } else { dump += StringPrintf(INDENT "FocusedWindows: \n"); @@ -3691,16 +3705,16 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (size_t i = 0; i < mTouchStatesByDisplay.size(); i++) { const TouchState& state = mTouchStatesByDisplay.valueAt(i); dump += StringPrintf(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n", - state.displayId, toString(state.down), toString(state.split), - state.deviceId, state.source); + state.displayId, toString(state.down), toString(state.split), + state.deviceId, state.source); if (!state.windows.empty()) { dump += INDENT3 "Windows:\n"; for (size_t i = 0; i < state.windows.size(); i++) { const TouchedWindow& touchedWindow = state.windows[i]; - dump += StringPrintf(INDENT4 "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", - i, touchedWindow.windowHandle->getName().c_str(), - touchedWindow.pointerIds.value, - touchedWindow.targetFlags); + dump += StringPrintf(INDENT4 + "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", + i, touchedWindow.windowHandle->getName().c_str(), + touchedWindow.pointerIds.value, touchedWindow.targetFlags); } } else { dump += INDENT3 "Windows: \n"; @@ -3709,8 +3723,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT3 "Portal windows:\n"; for (size_t i = 0; i < state.portalWindows.size(); i++) { const sp portalWindowHandle = state.portalWindows[i]; - dump += StringPrintf(INDENT4 "%zu: name='%s'\n", - i, portalWindowHandle->getName().c_str()); + dump += StringPrintf(INDENT4 "%zu: name='%s'\n", i, + portalWindowHandle->getName().c_str()); } } } @@ -3719,7 +3733,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { } if (!mWindowHandlesByDisplay.empty()) { - for (auto& it : mWindowHandlesByDisplay) { + for (auto& it : mWindowHandlesByDisplay) { const std::vector> windowHandles = it.second; dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first); if (!windowHandles.empty()) { @@ -3729,28 +3743,31 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { const InputWindowInfo* windowInfo = windowHandle->getInfo(); dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, " - "portalToDisplayId=%d, paused=%s, hasFocus=%s, hasWallpaper=%s, " - "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " - "frame=[%d,%d][%d,%d], globalScale=%f, windowScale=(%f,%f), " - "touchableRegion=", - i, windowInfo->name.c_str(), windowInfo->displayId, - windowInfo->portalToDisplayId, - toString(windowInfo->paused), - toString(windowInfo->hasFocus), - toString(windowInfo->hasWallpaper), - toString(windowInfo->visible), - toString(windowInfo->canReceiveKeys), - windowInfo->layoutParamsFlags, windowInfo->layoutParamsType, - windowInfo->layer, - windowInfo->frameLeft, windowInfo->frameTop, - windowInfo->frameRight, windowInfo->frameBottom, - windowInfo->globalScaleFactor, - windowInfo->windowXScale, windowInfo->windowYScale); + "portalToDisplayId=%d, paused=%s, hasFocus=%s, " + "hasWallpaper=%s, " + "visible=%s, canReceiveKeys=%s, flags=0x%08x, " + "type=0x%08x, layer=%d, " + "frame=[%d,%d][%d,%d], globalScale=%f, " + "windowScale=(%f,%f), " + "touchableRegion=", + i, windowInfo->name.c_str(), windowInfo->displayId, + windowInfo->portalToDisplayId, + toString(windowInfo->paused), + toString(windowInfo->hasFocus), + toString(windowInfo->hasWallpaper), + toString(windowInfo->visible), + toString(windowInfo->canReceiveKeys), + windowInfo->layoutParamsFlags, + windowInfo->layoutParamsType, windowInfo->layer, + windowInfo->frameLeft, windowInfo->frameTop, + windowInfo->frameRight, windowInfo->frameBottom, + windowInfo->globalScaleFactor, windowInfo->windowXScale, + windowInfo->windowYScale); dumpRegion(dump, windowInfo->touchableRegion); dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", - windowInfo->ownerPid, windowInfo->ownerUid, - windowInfo->dispatchingTimeout / 1000000.0); + windowInfo->ownerPid, windowInfo->ownerUid, + windowInfo->dispatchingTimeout / 1000000.0); } } else { dump += INDENT2 "Windows: \n"; @@ -3761,16 +3778,16 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { } if (!mGlobalMonitorsByDisplay.empty() || !mGestureMonitorsByDisplay.empty()) { - for (auto& it : mGlobalMonitorsByDisplay) { + for (auto& it : mGlobalMonitorsByDisplay) { const std::vector& monitors = it.second; dump += StringPrintf(INDENT "Global monitors in display %" PRId32 ":\n", it.first); dumpMonitors(dump, monitors); - } - for (auto& it : mGestureMonitorsByDisplay) { + } + for (auto& it : mGestureMonitorsByDisplay) { const std::vector& monitors = it.second; dump += StringPrintf(INDENT "Gesture monitors in display %" PRId32 ":\n", it.first); dumpMonitors(dump, monitors); - } + } } else { dump += INDENT "Monitors: \n"; } @@ -3783,8 +3800,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (EventEntry* entry : mRecentQueue) { dump += INDENT2; entry->appendDescription(dump); - dump += StringPrintf(", age=%0.1fms\n", - (currentTime - entry->eventTime) * 0.000001f); + dump += StringPrintf(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f); } } else { dump += INDENT "RecentQueue: \n"; @@ -3796,7 +3812,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT2; mPendingEvent->appendDescription(dump); dump += StringPrintf(", age=%0.1fms\n", - (currentTime - mPendingEvent->eventTime) * 0.000001f); + (currentTime - mPendingEvent->eventTime) * 0.000001f); } else { dump += INDENT "PendingEvent: \n"; } @@ -3807,8 +3823,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (EventEntry* entry : mInboundQueue) { dump += INDENT2; entry->appendDescription(dump); - dump += StringPrintf(", age=%0.1fms\n", - (currentTime - entry->eventTime) * 0.000001f); + dump += StringPrintf(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f); } } else { dump += INDENT "InboundQueue: \n"; @@ -3819,8 +3834,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (size_t i = 0; i < mReplacedKeys.size(); i++) { const KeyReplacement& replacement = mReplacedKeys.keyAt(i); int32_t newKeyCode = mReplacedKeys.valueAt(i); - dump += StringPrintf(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n", - i, replacement.keyCode, replacement.deviceId, newKeyCode); + dump += StringPrintf(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n", i, + replacement.keyCode, replacement.deviceId, newKeyCode); } } else { dump += INDENT "ReplacedKeys: \n"; @@ -3844,8 +3859,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump.append(INDENT4); entry->eventEntry->appendDescription(dump); dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n", - entry->targetFlags, entry->resolvedAction, - (currentTime - entry->eventEntry->eventTime) * 0.000001f); + entry->targetFlags, entry->resolvedAction, + (currentTime - entry->eventEntry->eventTime) * 0.000001f); } } else { dump += INDENT3 "OutboundQueue: \n"; @@ -3858,10 +3873,10 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT4; entry->eventEntry->appendDescription(dump); dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, " - "age=%0.1fms, wait=%0.1fms\n", - entry->targetFlags, entry->resolvedAction, - (currentTime - entry->eventEntry->eventTime) * 0.000001f, - (currentTime - entry->deliveryTime) * 0.000001f); + "age=%0.1fms, wait=%0.1fms\n", + entry->targetFlags, entry->resolvedAction, + (currentTime - entry->eventEntry->eventTime) * 0.000001f, + (currentTime - entry->deliveryTime) * 0.000001f); } } else { dump += INDENT3 "WaitQueue: \n"; @@ -3873,16 +3888,15 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { if (isAppSwitchPendingLocked()) { dump += StringPrintf(INDENT "AppSwitch: pending, due in %0.1fms\n", - (mAppSwitchDueTime - now()) / 1000000.0); + (mAppSwitchDueTime - now()) / 1000000.0); } else { dump += INDENT "AppSwitch: not pending\n"; } dump += INDENT "Configuration:\n"; - dump += StringPrintf(INDENT2 "KeyRepeatDelay: %0.1fms\n", - mConfig.keyRepeatDelay * 0.000001f); + dump += StringPrintf(INDENT2 "KeyRepeatDelay: %0.1fms\n", mConfig.keyRepeatDelay * 0.000001f); dump += StringPrintf(INDENT2 "KeyRepeatTimeout: %0.1fms\n", - mConfig.keyRepeatTimeout * 0.000001f); + mConfig.keyRepeatTimeout * 0.000001f); } void InputDispatcher::dumpMonitors(std::string& dump, const std::vector& monitors) { @@ -3896,10 +3910,10 @@ void InputDispatcher::dumpMonitors(std::string& dump, const std::vector } status_t InputDispatcher::registerInputChannel(const sp& inputChannel, - int32_t displayId) { + int32_t displayId) { #if DEBUG_REGISTRATION ALOGD("channel '%s' ~ registerInputChannel - displayId=%" PRId32, - inputChannel->getName().c_str(), displayId); + inputChannel->getName().c_str(), displayId); #endif { // acquire lock @@ -3907,7 +3921,7 @@ status_t InputDispatcher::registerInputChannel(const sp& inputChan sp existingConnection = getConnectionLocked(inputChannel); if (existingConnection != nullptr) { ALOGW("Attempted to register already registered input channel '%s'", - inputChannel->getName().c_str()); + inputChannel->getName().c_str()); return BAD_VALUE; } @@ -3926,7 +3940,7 @@ status_t InputDispatcher::registerInputChannel(const sp& inputChan } status_t InputDispatcher::registerInputMonitor(const sp& inputChannel, - int32_t displayId, bool isGestureMonitor) { + int32_t displayId, bool isGestureMonitor) { { // acquire lock std::scoped_lock _l(mLock); @@ -3946,13 +3960,11 @@ status_t InputDispatcher::registerInputMonitor(const sp& inputChan mConnectionsByFd[fd] = connection; mInputChannelsByToken[inputChannel->getToken()] = inputChannel; - auto& monitorsByDisplay = isGestureMonitor - ? mGestureMonitorsByDisplay - : mGlobalMonitorsByDisplay; + auto& monitorsByDisplay = + isGestureMonitor ? mGestureMonitorsByDisplay : mGlobalMonitorsByDisplay; monitorsByDisplay[displayId].emplace_back(inputChannel); mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); - } // Wake the looper because some connections have changed. mLooper->wake(); @@ -3980,11 +3992,11 @@ status_t InputDispatcher::unregisterInputChannel(const sp& inputCh } status_t InputDispatcher::unregisterInputChannelLocked(const sp& inputChannel, - bool notify) { + bool notify) { sp connection = getConnectionLocked(inputChannel); if (connection == nullptr) { ALOGW("Attempted to unregister already unregistered input channel '%s'", - inputChannel->getName().c_str()); + inputChannel->getName().c_str()); return BAD_VALUE; } @@ -4010,16 +4022,17 @@ void InputDispatcher::removeMonitorChannelLocked(const sp& inputCh removeMonitorChannelLocked(inputChannel, mGestureMonitorsByDisplay); } -void InputDispatcher::removeMonitorChannelLocked(const sp& inputChannel, +void InputDispatcher::removeMonitorChannelLocked( + const sp& inputChannel, std::unordered_map>& monitorsByDisplay) { - for (auto it = monitorsByDisplay.begin(); it != monitorsByDisplay.end(); ) { + for (auto it = monitorsByDisplay.begin(); it != monitorsByDisplay.end();) { std::vector& monitors = it->second; const size_t numMonitors = monitors.size(); for (size_t i = 0; i < numMonitors; i++) { - if (monitors[i].inputChannel == inputChannel) { - monitors.erase(monitors.begin() + i); - break; - } + if (monitors[i].inputChannel == inputChannel) { + monitors.erase(monitors.begin() + i); + break; + } } if (monitors.empty()) { it = monitorsByDisplay.erase(it); @@ -4055,14 +4068,14 @@ status_t InputDispatcher::pilferPointers(const sp& token) { } if (!foundDeviceId || !state.down) { ALOGW("Attempted to pilfer points from a monitor without any on-going pointer streams." - " Ignoring."); + " Ignoring."); return BAD_VALUE; } int32_t deviceId = foundDeviceId.value(); // Send cancel events to all the input channels we're stealing from. CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "gesture monitor stole pointer stream"); + "gesture monitor stole pointer stream"); options.deviceId = deviceId; options.displayId = displayId; for (const TouchedWindow& window : state.windows) { @@ -4075,7 +4088,6 @@ status_t InputDispatcher::pilferPointers(const sp& token) { return OK; } - std::optional InputDispatcher::findGestureMonitorDisplayByTokenLocked( const sp& token) { for (const auto& it : mGestureMonitorsByDisplay) { @@ -4105,8 +4117,9 @@ sp InputDispatcher::getConnectionLocked( return nullptr; } -void InputDispatcher::onDispatchCycleFinishedLocked( - nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled) { +void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime, + const sp& connection, uint32_t seq, + bool handled) { std::unique_ptr commandEntry = std::make_unique( &InputDispatcher::doDispatchCycleFinishedLockedInterruptible); commandEntry->connection = connection; @@ -4116,10 +4129,10 @@ void InputDispatcher::onDispatchCycleFinishedLocked( postCommandLocked(std::move(commandEntry)); } -void InputDispatcher::onDispatchCycleBrokenLocked( - nsecs_t currentTime, const sp& connection) { +void InputDispatcher::onDispatchCycleBrokenLocked(nsecs_t currentTime, + const sp& connection) { ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!", - connection->getInputChannelName().c_str()); + connection->getInputChannelName().c_str()); std::unique_ptr commandEntry = std::make_unique( &InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); @@ -4128,7 +4141,7 @@ void InputDispatcher::onDispatchCycleBrokenLocked( } void InputDispatcher::onFocusChangedLocked(const sp& oldFocus, - const sp& newFocus) { + const sp& newFocus) { sp oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr; sp newToken = newFocus != nullptr ? newFocus->getToken() : nullptr; std::unique_ptr commandEntry = std::make_unique( @@ -4138,16 +4151,16 @@ void InputDispatcher::onFocusChangedLocked(const sp& oldFocus postCommandLocked(std::move(commandEntry)); } -void InputDispatcher::onANRLocked( - nsecs_t currentTime, const sp& applicationHandle, - const sp& windowHandle, - nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) { +void InputDispatcher::onANRLocked(nsecs_t currentTime, + const sp& applicationHandle, + const sp& windowHandle, nsecs_t eventTime, + nsecs_t waitStartTime, const char* reason) { float dispatchLatency = (currentTime - eventTime) * 0.000001f; float waitDuration = (currentTime - waitStartTime) * 0.000001f; ALOGI("Application is not responding: %s. " - "It has been %0.1fms since event, %0.1fms since wait started. Reason: %s", - getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), - dispatchLatency, waitDuration, reason); + "It has been %0.1fms since event, %0.1fms since wait started. Reason: %s", + getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), dispatchLatency, + waitDuration, reason); // Capture a record of the InputDispatcher state at the time of the ANR. time_t t = time(nullptr); @@ -4158,8 +4171,9 @@ void InputDispatcher::onANRLocked( mLastANRState.clear(); mLastANRState += INDENT "ANR:\n"; mLastANRState += StringPrintf(INDENT2 "Time: %s\n", timestr); - mLastANRState += StringPrintf(INDENT2 "Window: %s\n", - getApplicationWindowLabel(applicationHandle, windowHandle).c_str()); + mLastANRState += + StringPrintf(INDENT2 "Window: %s\n", + getApplicationWindowLabel(applicationHandle, windowHandle).c_str()); mLastANRState += StringPrintf(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency); mLastANRState += StringPrintf(INDENT2 "WaitDuration: %0.1fms\n", waitDuration); mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason); @@ -4168,14 +4182,13 @@ void InputDispatcher::onANRLocked( std::unique_ptr commandEntry = std::make_unique(&InputDispatcher::doNotifyANRLockedInterruptible); commandEntry->inputApplicationHandle = applicationHandle; - commandEntry->inputChannel = windowHandle != nullptr ? - getInputChannelLocked(windowHandle->getToken()) : nullptr; + commandEntry->inputChannel = + windowHandle != nullptr ? getInputChannelLocked(windowHandle->getToken()) : nullptr; commandEntry->reason = reason; postCommandLocked(std::move(commandEntry)); } -void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible ( - CommandEntry* commandEntry) { +void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry) { mLock.unlock(); mPolicy->notifyConfigurationChanged(commandEntry->eventTime); @@ -4183,8 +4196,7 @@ void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible ( mLock.lock(); } -void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( - CommandEntry* commandEntry) { +void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) { sp connection = commandEntry->connection; if (connection->status != Connection::STATUS_ZOMBIE) { @@ -4196,8 +4208,7 @@ void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( } } -void InputDispatcher::doNotifyFocusChangedLockedInterruptible( - CommandEntry* commandEntry) { +void InputDispatcher::doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) { sp oldToken = commandEntry->oldToken; sp newToken = commandEntry->newToken; mLock.unlock(); @@ -4205,19 +4216,18 @@ void InputDispatcher::doNotifyFocusChangedLockedInterruptible( mLock.lock(); } -void InputDispatcher::doNotifyANRLockedInterruptible( - CommandEntry* commandEntry) { +void InputDispatcher::doNotifyANRLockedInterruptible(CommandEntry* commandEntry) { mLock.unlock(); - nsecs_t newTimeout = mPolicy->notifyANR( - commandEntry->inputApplicationHandle, - commandEntry->inputChannel ? commandEntry->inputChannel->getToken() : nullptr, - commandEntry->reason); + nsecs_t newTimeout = + mPolicy->notifyANR(commandEntry->inputApplicationHandle, + commandEntry->inputChannel ? commandEntry->inputChannel->getToken() + : nullptr, + commandEntry->reason); mLock.lock(); - resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, - commandEntry->inputChannel); + resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, commandEntry->inputChannel); } void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( @@ -4230,13 +4240,13 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( mLock.unlock(); android::base::Timer t; - sp token = commandEntry->inputChannel != nullptr ? - commandEntry->inputChannel->getToken() : nullptr; - nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, - &event, entry->policyFlags); + sp token = commandEntry->inputChannel != nullptr + ? commandEntry->inputChannel->getToken() + : nullptr; + nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, &event, entry->policyFlags); if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms", - std::to_string(t.duration().count()).c_str()); + std::to_string(t.duration().count()).c_str()); } mLock.lock(); @@ -4258,8 +4268,7 @@ void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntr mLock.lock(); } -void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( - CommandEntry* commandEntry) { +void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) { sp connection = commandEntry->connection; const nsecs_t finishTime = commandEntry->eventTime; uint32_t seq = commandEntry->seq; @@ -4317,7 +4326,8 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( } bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& connection, - DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) { + DispatchEntry* dispatchEntry, + KeyEntry* keyEntry, bool handled) { if (keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK) { if (!handled) { // Report the key as unhandled, since the fallback was not handled. @@ -4342,9 +4352,9 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& con // Dispatch the unhandled key to the policy with the cancel flag. #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Asking policy to cancel fallback action. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); + "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", + keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, + keyEntry->policyFlags); #endif KeyEvent event; initializeKeyEvent(&event, keyEntry); @@ -4352,8 +4362,8 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& con mLock.unlock(); - mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(), - &event, keyEntry->policyFlags, &event); + mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(), &event, + keyEntry->policyFlags, &event); mLock.lock(); @@ -4372,15 +4382,13 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& con // If the application did not handle a non-fallback key, first check // that we are in a good state to perform unhandled key event processing // Then ask the policy what to do with it. - bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN - && keyEntry->repeatCount == 0; + bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN && keyEntry->repeatCount == 0; if (fallbackKeyCode == -1 && !initialDown) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Skipping unhandled key event processing " - "since this is not an initial down. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - originalKeyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); + "since this is not an initial down. " + "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", + originalKeyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags); #endif return false; } @@ -4388,17 +4396,16 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& con // Dispatch the unhandled key to the policy. #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Asking policy to perform fallback action. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); + "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", + keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags); #endif KeyEvent event; initializeKeyEvent(&event, keyEntry); mLock.unlock(); - bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(), - &event, keyEntry->policyFlags, &event); + bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(), &event, + keyEntry->policyFlags, &event); mLock.lock(); @@ -4423,19 +4430,19 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& con // Cancel the fallback key if the policy decides not to send it anymore. // We will continue to dispatch the key to the policy but we will no // longer dispatch a fallback key to the application. - if (fallbackKeyCode != AKEYCODE_UNKNOWN - && (!fallback || fallbackKeyCode != event.getKeyCode())) { + if (fallbackKeyCode != AKEYCODE_UNKNOWN && + (!fallback || fallbackKeyCode != event.getKeyCode())) { #if DEBUG_OUTBOUND_EVENT_DETAILS if (fallback) { ALOGD("Unhandled key event: Policy requested to send key %d" - "as a fallback for %d, but on the DOWN it had requested " - "to send %d instead. Fallback canceled.", - event.getKeyCode(), originalKeyCode, fallbackKeyCode); + "as a fallback for %d, but on the DOWN it had requested " + "to send %d instead. Fallback canceled.", + event.getKeyCode(), originalKeyCode, fallbackKeyCode); } else { ALOGD("Unhandled key event: Policy did not request fallback for %d, " - "but on the DOWN it had requested to send %d. " - "Fallback canceled.", - originalKeyCode, fallbackKeyCode); + "but on the DOWN it had requested to send %d. " + "Fallback canceled.", + originalKeyCode, fallbackKeyCode); } #endif @@ -4447,8 +4454,7 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& con fallback = false; fallbackKeyCode = AKEYCODE_UNKNOWN; if (keyEntry->action != AKEY_EVENT_ACTION_UP) { - connection->inputState.setFallbackKey(originalKeyCode, - fallbackKeyCode); + connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode); } } @@ -4458,11 +4464,10 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& con const KeyedVector& fallbackKeys = connection->inputState.getFallbackKeys(); for (size_t i = 0; i < fallbackKeys.size(); i++) { - msg += StringPrintf(", %d->%d", fallbackKeys.keyAt(i), - fallbackKeys.valueAt(i)); + msg += StringPrintf(", %d->%d", fallbackKeys.keyAt(i), fallbackKeys.valueAt(i)); } ALOGD("Unhandled key event: %zu currently tracked fallback keys%s.", - fallbackKeys.size(), msg.c_str()); + fallbackKeys.size(), msg.c_str()); } #endif @@ -4482,8 +4487,8 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& con #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Dispatching fallback key. " - "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x", - originalKeyCode, fallbackKeyCode, keyEntry->metaState); + "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x", + originalKeyCode, fallbackKeyCode, keyEntry->metaState); #endif return true; // restart the event } else { @@ -4499,7 +4504,8 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& con } bool InputDispatcher::afterMotionEventLockedInterruptible(const sp& connection, - DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) { + DispatchEntry* dispatchEntry, + MotionEntry* motionEntry, bool handled) { return false; } @@ -4513,12 +4519,13 @@ void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* comman void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) { event->initialize(entry->deviceId, entry->source, entry->displayId, entry->action, entry->flags, - entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, - entry->downTime, entry->eventTime); + entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, + entry->downTime, entry->eventTime); } void InputDispatcher::updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry, - int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) { + int32_t injectionResult, + nsecs_t timeSpentWaitingForApplication) { // TODO Write some statistics about how long we spend waiting. } @@ -4563,18 +4570,17 @@ void InputDispatcher::monitor() { mDispatcherIsAlive.wait(_l); } - // --- InputDispatcher::InjectionState --- -InputDispatcher::InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) : - refCount(1), - injectorPid(injectorPid), injectorUid(injectorUid), - injectionResult(INPUT_EVENT_INJECTION_PENDING), injectionIsAsync(false), - pendingForegroundDispatches(0) { -} +InputDispatcher::InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) + : refCount(1), + injectorPid(injectorPid), + injectorUid(injectorUid), + injectionResult(INPUT_EVENT_INJECTION_PENDING), + injectionIsAsync(false), + pendingForegroundDispatches(0) {} -InputDispatcher::InjectionState::~InjectionState() { -} +InputDispatcher::InjectionState::~InjectionState() {} void InputDispatcher::InjectionState::release() { refCount -= 1; @@ -4585,14 +4591,17 @@ void InputDispatcher::InjectionState::release() { } } - // --- InputDispatcher::EventEntry --- -InputDispatcher::EventEntry::EventEntry(uint32_t sequenceNum, int32_t type, - nsecs_t eventTime, uint32_t policyFlags) : - sequenceNum(sequenceNum), refCount(1), type(type), eventTime(eventTime), - policyFlags(policyFlags), injectionState(nullptr), dispatchInProgress(false) { -} +InputDispatcher::EventEntry::EventEntry(uint32_t sequenceNum, int32_t type, nsecs_t eventTime, + uint32_t policyFlags) + : sequenceNum(sequenceNum), + refCount(1), + type(type), + eventTime(eventTime), + policyFlags(policyFlags), + injectionState(nullptr), + dispatchInProgress(false) {} InputDispatcher::EventEntry::~EventEntry() { releaseInjectionState(); @@ -4614,62 +4623,60 @@ void InputDispatcher::EventEntry::releaseInjectionState() { } } - // --- InputDispatcher::ConfigurationChangedEntry --- -InputDispatcher::ConfigurationChangedEntry::ConfigurationChangedEntry( - uint32_t sequenceNum, nsecs_t eventTime) : - EventEntry(sequenceNum, TYPE_CONFIGURATION_CHANGED, eventTime, 0) { -} +InputDispatcher::ConfigurationChangedEntry::ConfigurationChangedEntry(uint32_t sequenceNum, + nsecs_t eventTime) + : EventEntry(sequenceNum, TYPE_CONFIGURATION_CHANGED, eventTime, 0) {} -InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() { -} +InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() {} void InputDispatcher::ConfigurationChangedEntry::appendDescription(std::string& msg) const { msg += StringPrintf("ConfigurationChangedEvent(), policyFlags=0x%08x", policyFlags); } - // --- InputDispatcher::DeviceResetEntry --- -InputDispatcher::DeviceResetEntry::DeviceResetEntry( - uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId) : - EventEntry(sequenceNum, TYPE_DEVICE_RESET, eventTime, 0), - deviceId(deviceId) { -} +InputDispatcher::DeviceResetEntry::DeviceResetEntry(uint32_t sequenceNum, nsecs_t eventTime, + int32_t deviceId) + : EventEntry(sequenceNum, TYPE_DEVICE_RESET, eventTime, 0), deviceId(deviceId) {} -InputDispatcher::DeviceResetEntry::~DeviceResetEntry() { -} +InputDispatcher::DeviceResetEntry::~DeviceResetEntry() {} void InputDispatcher::DeviceResetEntry::appendDescription(std::string& msg) const { - msg += StringPrintf("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x", - deviceId, policyFlags); + msg += StringPrintf("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x", deviceId, policyFlags); } - // --- InputDispatcher::KeyEntry --- -InputDispatcher::KeyEntry::KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, - int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action, - int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, - int32_t repeatCount, nsecs_t downTime) : - EventEntry(sequenceNum, TYPE_KEY, eventTime, policyFlags), - deviceId(deviceId), source(source), displayId(displayId), action(action), flags(flags), - keyCode(keyCode), scanCode(scanCode), metaState(metaState), - repeatCount(repeatCount), downTime(downTime), - syntheticRepeat(false), interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN), - interceptKeyWakeupTime(0) { -} +InputDispatcher::KeyEntry::KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, + uint32_t source, int32_t displayId, uint32_t policyFlags, + int32_t action, int32_t flags, int32_t keyCode, + int32_t scanCode, int32_t metaState, int32_t repeatCount, + nsecs_t downTime) + : EventEntry(sequenceNum, TYPE_KEY, eventTime, policyFlags), + deviceId(deviceId), + source(source), + displayId(displayId), + action(action), + flags(flags), + keyCode(keyCode), + scanCode(scanCode), + metaState(metaState), + repeatCount(repeatCount), + downTime(downTime), + syntheticRepeat(false), + interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN), + interceptKeyWakeupTime(0) {} -InputDispatcher::KeyEntry::~KeyEntry() { -} +InputDispatcher::KeyEntry::~KeyEntry() {} void InputDispatcher::KeyEntry::appendDescription(std::string& msg) const { msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32 ", action=%s, " - "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, " - "repeatCount=%d), policyFlags=0x%08x", - deviceId, source, displayId, keyActionToString(action).c_str(), flags, keyCode, - scanCode, metaState, repeatCount, policyFlags); + "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, " + "repeatCount=%d), policyFlags=0x%08x", + deviceId, source, displayId, keyActionToString(action).c_str(), flags, + keyCode, scanCode, metaState, repeatCount, policyFlags); } void InputDispatcher::KeyEntry::recycle() { @@ -4681,7 +4688,6 @@ void InputDispatcher::KeyEntry::recycle() { interceptKeyWakeupTime = 0; } - // --- InputDispatcher::MotionEntry --- InputDispatcher::MotionEntry::MotionEntry( @@ -4719,8 +4725,7 @@ InputDispatcher::MotionEntry::MotionEntry( } } -InputDispatcher::MotionEntry::~MotionEntry() { -} +InputDispatcher::MotionEntry::~MotionEntry() {} void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const { msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32 @@ -4737,25 +4742,30 @@ void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const { if (i) { msg += ", "; } - msg += StringPrintf("%d: (%.1f, %.1f)", pointerProperties[i].id, - pointerCoords[i].getX(), pointerCoords[i].getY()); + msg += StringPrintf("%d: (%.1f, %.1f)", pointerProperties[i].id, pointerCoords[i].getX(), + pointerCoords[i].getY()); } msg += StringPrintf("]), policyFlags=0x%08x", policyFlags); } - // --- InputDispatcher::DispatchEntry --- volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic; -InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry, - int32_t targetFlags, float xOffset, float yOffset, float globalScaleFactor, - float windowXScale, float windowYScale) : - seq(nextSeq()), - eventEntry(eventEntry), targetFlags(targetFlags), - xOffset(xOffset), yOffset(yOffset), globalScaleFactor(globalScaleFactor), - windowXScale(windowXScale), windowYScale(windowYScale), - deliveryTime(0), resolvedAction(0), resolvedFlags(0) { +InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, + float xOffset, float yOffset, float globalScaleFactor, + float windowXScale, float windowYScale) + : seq(nextSeq()), + eventEntry(eventEntry), + targetFlags(targetFlags), + xOffset(xOffset), + yOffset(yOffset), + globalScaleFactor(globalScaleFactor), + windowXScale(windowXScale), + windowYScale(windowYScale), + deliveryTime(0), + resolvedAction(0), + resolvedFlags(0) { eventEntry->refCount += 1; } @@ -4772,192 +4782,185 @@ uint32_t InputDispatcher::DispatchEntry::nextSeq() { return seq; } - // --- InputDispatcher::InputState --- -InputDispatcher::InputState::InputState() { -} +InputDispatcher::InputState::InputState() {} -InputDispatcher::InputState::~InputState() { -} +InputDispatcher::InputState::~InputState() {} bool InputDispatcher::InputState::isNeutral() const { return mKeyMementos.empty() && mMotionMementos.empty(); } bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source, - int32_t displayId) const { + int32_t displayId) const { for (const MotionMemento& memento : mMotionMementos) { - if (memento.deviceId == deviceId - && memento.source == source - && memento.displayId == displayId - && memento.hovering) { + if (memento.deviceId == deviceId && memento.source == source && + memento.displayId == displayId && memento.hovering) { return true; } } return false; } -bool InputDispatcher::InputState::trackKey(const KeyEntry* entry, - int32_t action, int32_t flags) { +bool InputDispatcher::InputState::trackKey(const KeyEntry* entry, int32_t action, int32_t flags) { switch (action) { - case AKEY_EVENT_ACTION_UP: { - if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) { - for (size_t i = 0; i < mFallbackKeys.size(); ) { - if (mFallbackKeys.valueAt(i) == entry->keyCode) { - mFallbackKeys.removeItemsAt(i); - } else { - i += 1; + case AKEY_EVENT_ACTION_UP: { + if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) { + for (size_t i = 0; i < mFallbackKeys.size();) { + if (mFallbackKeys.valueAt(i) == entry->keyCode) { + mFallbackKeys.removeItemsAt(i); + } else { + i += 1; + } } } - } - ssize_t index = findKeyMemento(entry); - if (index >= 0) { - mKeyMementos.erase(mKeyMementos.begin() + index); + ssize_t index = findKeyMemento(entry); + if (index >= 0) { + mKeyMementos.erase(mKeyMementos.begin() + index); + return true; + } + /* FIXME: We can't just drop the key up event because that prevents creating + * popup windows that are automatically shown when a key is held and then + * dismissed when the key is released. The problem is that the popup will + * not have received the original key down, so the key up will be considered + * to be inconsistent with its observed state. We could perhaps handle this + * by synthesizing a key down but that will cause other problems. + * + * So for now, allow inconsistent key up events to be dispatched. + * + #if DEBUG_OUTBOUND_EVENT_DETAILS + ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, " + "keyCode=%d, scanCode=%d", + entry->deviceId, entry->source, entry->keyCode, entry->scanCode); + #endif + return false; + */ return true; } - /* FIXME: We can't just drop the key up event because that prevents creating - * popup windows that are automatically shown when a key is held and then - * dismissed when the key is released. The problem is that the popup will - * not have received the original key down, so the key up will be considered - * to be inconsistent with its observed state. We could perhaps handle this - * by synthesizing a key down but that will cause other problems. - * - * So for now, allow inconsistent key up events to be dispatched. - * -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, " - "keyCode=%d, scanCode=%d", - entry->deviceId, entry->source, entry->keyCode, entry->scanCode); -#endif - return false; - */ - return true; - } - case AKEY_EVENT_ACTION_DOWN: { - ssize_t index = findKeyMemento(entry); - if (index >= 0) { - mKeyMementos.erase(mKeyMementos.begin() + index); + case AKEY_EVENT_ACTION_DOWN: { + ssize_t index = findKeyMemento(entry); + if (index >= 0) { + mKeyMementos.erase(mKeyMementos.begin() + index); + } + addKeyMemento(entry, flags); + return true; } - addKeyMemento(entry, flags); - return true; - } - default: - return true; + default: + return true; } } -bool InputDispatcher::InputState::trackMotion(const MotionEntry* entry, - int32_t action, int32_t flags) { +bool InputDispatcher::InputState::trackMotion(const MotionEntry* entry, int32_t action, + int32_t flags) { int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK; switch (actionMasked) { - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: { - ssize_t index = findMotionMemento(entry, false /*hovering*/); - if (index >= 0) { - mMotionMementos.erase(mMotionMementos.begin() + index); - return true; - } + case AMOTION_EVENT_ACTION_UP: + case AMOTION_EVENT_ACTION_CANCEL: { + ssize_t index = findMotionMemento(entry, false /*hovering*/); + if (index >= 0) { + mMotionMementos.erase(mMotionMementos.begin() + index); + return true; + } #if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, " - "displayId=%" PRId32 ", actionMasked=%d", - entry->deviceId, entry->source, entry->displayId, actionMasked); + ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, " + "displayId=%" PRId32 ", actionMasked=%d", + entry->deviceId, entry->source, entry->displayId, actionMasked); #endif - return false; - } - - case AMOTION_EVENT_ACTION_DOWN: { - ssize_t index = findMotionMemento(entry, false /*hovering*/); - if (index >= 0) { - mMotionMementos.erase(mMotionMementos.begin() + index); + return false; } - addMotionMemento(entry, flags, false /*hovering*/); - return true; - } - case AMOTION_EVENT_ACTION_POINTER_UP: - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_MOVE: { - if (entry->source & AINPUT_SOURCE_CLASS_NAVIGATION) { - // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need to - // generate cancellation events for these since they're based in relative rather than - // absolute units. + case AMOTION_EVENT_ACTION_DOWN: { + ssize_t index = findMotionMemento(entry, false /*hovering*/); + if (index >= 0) { + mMotionMementos.erase(mMotionMementos.begin() + index); + } + addMotionMemento(entry, flags, false /*hovering*/); return true; } - ssize_t index = findMotionMemento(entry, false /*hovering*/); + case AMOTION_EVENT_ACTION_POINTER_UP: + case AMOTION_EVENT_ACTION_POINTER_DOWN: + case AMOTION_EVENT_ACTION_MOVE: { + if (entry->source & AINPUT_SOURCE_CLASS_NAVIGATION) { + // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need + // to generate cancellation events for these since they're based in relative rather + // than absolute units. + return true; + } + + ssize_t index = findMotionMemento(entry, false /*hovering*/); + + if (entry->source & AINPUT_SOURCE_CLASS_JOYSTICK) { + // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all + // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral. + // Any other value and we need to track the motion so we can send cancellation + // events for anything generating fallback events (e.g. DPad keys for joystick + // movements). + if (index >= 0) { + if (entry->pointerCoords[0].isEmpty()) { + mMotionMementos.erase(mMotionMementos.begin() + index); + } else { + MotionMemento& memento = mMotionMementos[index]; + memento.setPointers(entry); + } + } else if (!entry->pointerCoords[0].isEmpty()) { + addMotionMemento(entry, flags, false /*hovering*/); + } - if (entry->source & AINPUT_SOURCE_CLASS_JOYSTICK) { - // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all - // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral. Any - // other value and we need to track the motion so we can send cancellation events for - // anything generating fallback events (e.g. DPad keys for joystick movements). + // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP. + return true; + } if (index >= 0) { - if (entry->pointerCoords[0].isEmpty()) { - mMotionMementos.erase(mMotionMementos.begin() + index); - } else { - MotionMemento& memento = mMotionMementos[index]; - memento.setPointers(entry); - } - } else if (!entry->pointerCoords[0].isEmpty()) { - addMotionMemento(entry, flags, false /*hovering*/); + MotionMemento& memento = mMotionMementos[index]; + memento.setPointers(entry); + return true; } - - // 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 DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion pointer up/down or move event: " - "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d", - entry->deviceId, entry->source, entry->displayId, actionMasked); + ALOGD("Dropping inconsistent motion pointer up/down or move event: " + "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d", + entry->deviceId, entry->source, entry->displayId, actionMasked); #endif - return false; - } - - case AMOTION_EVENT_ACTION_HOVER_EXIT: { - ssize_t index = findMotionMemento(entry, true /*hovering*/); - if (index >= 0) { - mMotionMementos.erase(mMotionMementos.begin() + index); - return true; + return false; } + + case AMOTION_EVENT_ACTION_HOVER_EXIT: { + ssize_t index = findMotionMemento(entry, true /*hovering*/); + if (index >= 0) { + mMotionMementos.erase(mMotionMementos.begin() + index); + return true; + } #if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, " - "displayId=%" PRId32, - entry->deviceId, entry->source, entry->displayId); + ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, " + "displayId=%" PRId32, + entry->deviceId, entry->source, entry->displayId); #endif - return false; - } + return false; + } - case AMOTION_EVENT_ACTION_HOVER_ENTER: - case AMOTION_EVENT_ACTION_HOVER_MOVE: { - ssize_t index = findMotionMemento(entry, true /*hovering*/); - if (index >= 0) { - mMotionMementos.erase(mMotionMementos.begin() + index); + case AMOTION_EVENT_ACTION_HOVER_ENTER: + case AMOTION_EVENT_ACTION_HOVER_MOVE: { + ssize_t index = findMotionMemento(entry, true /*hovering*/); + if (index >= 0) { + mMotionMementos.erase(mMotionMementos.begin() + index); + } + addMotionMemento(entry, flags, true /*hovering*/); + return true; } - addMotionMemento(entry, flags, true /*hovering*/); - return true; - } - default: - return true; + default: + return true; } } ssize_t InputDispatcher::InputState::findKeyMemento(const KeyEntry* entry) const { for (size_t i = 0; i < mKeyMementos.size(); i++) { const KeyMemento& memento = mKeyMementos[i]; - if (memento.deviceId == entry->deviceId - && memento.source == entry->source - && memento.displayId == entry->displayId - && memento.keyCode == entry->keyCode - && memento.scanCode == entry->scanCode) { + if (memento.deviceId == entry->deviceId && memento.source == entry->source && + memento.displayId == entry->displayId && memento.keyCode == entry->keyCode && + memento.scanCode == entry->scanCode) { return i; } } @@ -4965,13 +4968,11 @@ ssize_t InputDispatcher::InputState::findKeyMemento(const KeyEntry* entry) const } ssize_t InputDispatcher::InputState::findMotionMemento(const MotionEntry* entry, - bool hovering) const { + bool hovering) const { for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos[i]; - if (memento.deviceId == entry->deviceId - && memento.source == entry->source - && memento.displayId == entry->displayId - && memento.hovering == hovering) { + if (memento.deviceId == entry->deviceId && memento.source == entry->source && + memento.displayId == entry->displayId && memento.hovering == hovering) { return i; } } @@ -4992,8 +4993,8 @@ void InputDispatcher::InputState::addKeyMemento(const KeyEntry* entry, int32_t f mKeyMementos.push_back(memento); } -void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry, - int32_t flags, bool hovering) { +void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry, int32_t flags, + bool hovering) { MotionMemento memento; memento.deviceId = entry->deviceId; memento.source = entry->source; @@ -5019,20 +5020,23 @@ void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* } void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime, - std::vector& outEvents, const CancelationOptions& options) { + std::vector& outEvents, + const CancelationOptions& options) { for (KeyMemento& memento : mKeyMementos) { if (shouldCancelKey(memento, options)) { outEvents.push_back(new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, - memento.deviceId, memento.source, memento.displayId, memento.policyFlags, - AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED, - memento.keyCode, memento.scanCode, memento.metaState, 0, memento.downTime)); + memento.deviceId, memento.source, memento.displayId, + memento.policyFlags, AKEY_EVENT_ACTION_UP, + memento.flags | AKEY_EVENT_FLAG_CANCELED, + memento.keyCode, memento.scanCode, memento.metaState, + 0, memento.downTime)); } } for (const MotionMemento& memento : mMotionMementos) { if (shouldCancelMotion(memento, options)) { - const int32_t action = memento.hovering ? - AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL; + const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT + : AMOTION_EVENT_ACTION_CANCEL; outEvents.push_back( new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, memento.deviceId, memento.source, memento.displayId, memento.policyFlags, action, @@ -5057,11 +5061,11 @@ void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const { for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos[i]; if (memento.source & AINPUT_SOURCE_CLASS_POINTER) { - for (size_t j = 0; j < other.mMotionMementos.size(); ) { + for (size_t j = 0; j < other.mMotionMementos.size();) { const MotionMemento& otherMemento = other.mMotionMementos[j]; - if (memento.deviceId == otherMemento.deviceId - && memento.source == otherMemento.source - && memento.displayId == otherMemento.displayId) { + if (memento.deviceId == otherMemento.deviceId && + memento.source == otherMemento.source && + memento.displayId == otherMemento.displayId) { other.mMotionMementos.erase(other.mMotionMementos.begin() + j); } else { j += 1; @@ -5077,8 +5081,7 @@ int32_t InputDispatcher::InputState::getFallbackKey(int32_t originalKeyCode) { return index >= 0 ? mFallbackKeys.valueAt(index) : -1; } -void InputDispatcher::InputState::setFallbackKey(int32_t originalKeyCode, - int32_t fallbackKeyCode) { +void InputDispatcher::InputState::setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode) { ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); if (index >= 0) { mFallbackKeys.replaceValueAt(index, fallbackKeyCode); @@ -5092,12 +5095,12 @@ void InputDispatcher::InputState::removeFallbackKey(int32_t originalKeyCode) { } bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, - const CancelationOptions& options) { + const CancelationOptions& options) { if (options.keyCode && memento.keyCode != options.keyCode.value()) { return false; } - if (options.deviceId && memento.deviceId != options.deviceId.value()) { + if (options.deviceId && memento.deviceId != options.deviceId.value()) { return false; } @@ -5106,18 +5109,18 @@ bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, } switch (options.mode) { - case CancelationOptions::CANCEL_ALL_EVENTS: - case CancelationOptions::CANCEL_NON_POINTER_EVENTS: - return true; - case CancelationOptions::CANCEL_FALLBACK_EVENTS: - return memento.flags & AKEY_EVENT_FLAG_FALLBACK; - default: - return false; + case CancelationOptions::CANCEL_ALL_EVENTS: + case CancelationOptions::CANCEL_NON_POINTER_EVENTS: + return true; + case CancelationOptions::CANCEL_FALLBACK_EVENTS: + return memento.flags & AKEY_EVENT_FLAG_FALLBACK; + default: + return false; } } bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento, - const CancelationOptions& options) { + const CancelationOptions& options) { if (options.deviceId && memento.deviceId != options.deviceId.value()) { return false; } @@ -5127,28 +5130,27 @@ bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& mement } switch (options.mode) { - case CancelationOptions::CANCEL_ALL_EVENTS: - return true; - case CancelationOptions::CANCEL_POINTER_EVENTS: - return memento.source & AINPUT_SOURCE_CLASS_POINTER; - case CancelationOptions::CANCEL_NON_POINTER_EVENTS: - return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); - default: - return false; + case CancelationOptions::CANCEL_ALL_EVENTS: + return true; + case CancelationOptions::CANCEL_POINTER_EVENTS: + return memento.source & AINPUT_SOURCE_CLASS_POINTER; + case CancelationOptions::CANCEL_NON_POINTER_EVENTS: + return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); + default: + return false; } } - // --- InputDispatcher::Connection --- -InputDispatcher::Connection::Connection(const sp& inputChannel, bool monitor) : - status(STATUS_NORMAL), inputChannel(inputChannel), +InputDispatcher::Connection::Connection(const sp& inputChannel, bool monitor) + : status(STATUS_NORMAL), + inputChannel(inputChannel), monitor(monitor), - inputPublisher(inputChannel), inputPublisherBlocked(false) { -} + inputPublisher(inputChannel), + inputPublisherBlocked(false) {} -InputDispatcher::Connection::~Connection() { -} +InputDispatcher::Connection::~Connection() {} const std::string InputDispatcher::Connection::getWindowName() const { if (inputChannel != nullptr) { @@ -5162,17 +5164,17 @@ const std::string InputDispatcher::Connection::getWindowName() const { const char* InputDispatcher::Connection::getStatusLabel() const { switch (status) { - case STATUS_NORMAL: - return "NORMAL"; + case STATUS_NORMAL: + return "NORMAL"; - case STATUS_BROKEN: - return "BROKEN"; + case STATUS_BROKEN: + return "BROKEN"; - case STATUS_ZOMBIE: - return "ZOMBIE"; + case STATUS_ZOMBIE: + return "ZOMBIE"; - default: - return "UNKNOWN"; + default: + return "UNKNOWN"; } } @@ -5187,34 +5189,32 @@ InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) { } // --- InputDispatcher::Monitor -InputDispatcher::Monitor::Monitor(const sp& inputChannel) : - inputChannel(inputChannel) { -} - +InputDispatcher::Monitor::Monitor(const sp& inputChannel) + : inputChannel(inputChannel) {} // --- InputDispatcher::CommandEntry --- // -InputDispatcher::CommandEntry::CommandEntry(Command command) : - command(command), eventTime(0), keyEntry(nullptr), userActivityEventType(0), - seq(0), handled(false) { -} +InputDispatcher::CommandEntry::CommandEntry(Command command) + : command(command), + eventTime(0), + keyEntry(nullptr), + userActivityEventType(0), + seq(0), + handled(false) {} -InputDispatcher::CommandEntry::~CommandEntry() { -} +InputDispatcher::CommandEntry::~CommandEntry() {} // --- InputDispatcher::TouchedMonitor --- InputDispatcher::TouchedMonitor::TouchedMonitor(const Monitor& monitor, float xOffset, - float yOffset) : monitor(monitor), xOffset(xOffset), yOffset(yOffset) { -} + float yOffset) + : monitor(monitor), xOffset(xOffset), yOffset(yOffset) {} // --- InputDispatcher::TouchState --- -InputDispatcher::TouchState::TouchState() : - down(false), split(false), deviceId(-1), source(0), displayId(ADISPLAY_ID_NONE) { -} +InputDispatcher::TouchState::TouchState() + : down(false), split(false), deviceId(-1), source(0), displayId(ADISPLAY_ID_NONE) {} -InputDispatcher::TouchState::~TouchState() { -} +InputDispatcher::TouchState::~TouchState() {} void InputDispatcher::TouchState::reset() { down = false; @@ -5239,7 +5239,7 @@ void InputDispatcher::TouchState::copyFrom(const TouchState& other) { } void InputDispatcher::TouchState::addOrUpdateWindow(const sp& windowHandle, - int32_t targetFlags, BitSet32 pointerIds) { + int32_t targetFlags, BitSet32 pointerIds) { if (targetFlags & InputTarget::FLAG_SPLIT) { split = true; } @@ -5277,8 +5277,8 @@ void InputDispatcher::TouchState::addGestureMonitors( const std::vector& newMonitors) { const size_t newSize = gestureMonitors.size() + newMonitors.size(); gestureMonitors.reserve(newSize); - gestureMonitors.insert(std::end(gestureMonitors), - std::begin(newMonitors), std::end(newMonitors)); + gestureMonitors.insert(std::end(gestureMonitors), std::begin(newMonitors), + std::end(newMonitors)); } void InputDispatcher::TouchState::removeWindow(const sp& windowHandle) { @@ -5300,10 +5300,10 @@ void InputDispatcher::TouchState::removeWindowByToken(const sp& token) } void InputDispatcher::TouchState::filterNonAsIsTouchWindows() { - for (size_t i = 0 ; i < windows.size(); ) { + for (size_t i = 0; i < windows.size();) { TouchedWindow& window = windows[i]; - if (window.targetFlags & (InputTarget::FLAG_DISPATCH_AS_IS - | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) { + if (window.targetFlags & + (InputTarget::FLAG_DISPATCH_AS_IS | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) { window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK; window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS; i += 1; @@ -5333,9 +5333,9 @@ bool InputDispatcher::TouchState::isSlippery() const { bool haveSlipperyForegroundWindow = false; for (const TouchedWindow& window : windows) { if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { - if (haveSlipperyForegroundWindow - || !(window.windowHandle->getInfo()->layoutParamsFlags - & InputWindowInfo::FLAG_SLIPPERY)) { + if (haveSlipperyForegroundWindow || + !(window.windowHandle->getInfo()->layoutParamsFlags & + InputWindowInfo::FLAG_SLIPPERY)) { return false; } haveSlipperyForegroundWindow = true; @@ -5344,15 +5344,12 @@ bool InputDispatcher::TouchState::isSlippery() const { return haveSlipperyForegroundWindow; } - // --- InputDispatcherThread --- -InputDispatcherThread::InputDispatcherThread(const sp& dispatcher) : - Thread(/*canCallJava*/ true), mDispatcher(dispatcher) { -} +InputDispatcherThread::InputDispatcherThread(const sp& dispatcher) + : Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {} -InputDispatcherThread::~InputDispatcherThread() { -} +InputDispatcherThread::~InputDispatcherThread() {} bool InputDispatcherThread::threadLoop() { mDispatcher->dispatchOnce(); diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h similarity index 82% rename from services/inputflinger/InputDispatcher.h rename to services/inputflinger/dispatcher/InputDispatcher.h index e35ba2756b..a90f958e79 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -17,20 +17,20 @@ #ifndef _UI_INPUT_DISPATCHER_H #define _UI_INPUT_DISPATCHER_H -#include +#include +#include

Because installd query all of crates in specified userId, the install may return the list + * whose elements have the same crate id but different uid and package name. + * It needs to tell the caller the difference between these elements. + */ + int uid; + + /** + * To tell which the package the crate belong to. + *

Because installd query all of crates in specified uid, the install may return the list + * whose elements have the same uid and crate id but different package name. + * It needs to tell the caller the difference between these elements. + */ + @utf8InCpp String packageName; + + /** + * To tell the crate id that is the child directory/folder name in crates + * root. + */ + @utf8InCpp String id; +} diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index 4eb1df0b2e..6012822f69 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -278,6 +278,15 @@ std::string create_data_dalvik_cache_path() { return "/data/dalvik-cache"; } +std::string create_system_user_ce_path(userid_t userId) { + return StringPrintf("%s/system_ce/%u", create_data_path(nullptr).c_str(), userId); +} + +std::string create_system_user_ce_package_path(userid_t userId, const char* package_name) { + check_package_name(package_name); + return StringPrintf("%s/%s", create_system_user_ce_path(userId).c_str(), package_name); +} + // Keep profile paths in sync with ActivityThread and LoadedApk. const std::string PROFILE_EXT = ".prof"; const std::string CURRENT_PROFILE_EXT = ".cur"; diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index 6a420261a1..6a39adc41f 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -82,6 +82,10 @@ std::string create_data_misc_legacy_path(userid_t userid); std::string create_data_dalvik_cache_path(); +std::string create_system_user_ce_path(userid_t userId); + +std::string create_system_user_ce_package_path(userid_t userId, const char* package_name); + std::string create_primary_cur_profile_dir_path(userid_t userid); std::string create_primary_current_profile_package_dir_path( userid_t user, const std::string& package_name); -- GitLab From 06c97753112bb7a03d6e58c3774b2e44d19d7681 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Tue, 3 Sep 2019 09:52:43 -0400 Subject: [PATCH 0558/1255] Add AndroidBitmap_getDataSpace Bug:135133301 Test: I7a5fcb726fba0c832bbb86a424d7534a7cfa35b6 This supplements AndroidBitmap_getInfo, allowing NDK clients to know how to interpret the colors in an android.graphics.Bitmap. Change-Id: Ia46dfb39d0f2708ce873343ec74bcc52e7bccd3a --- include/android/bitmap.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/android/bitmap.h b/include/android/bitmap.h index 01cf2f88ea..41718b2904 100644 --- a/include/android/bitmap.h +++ b/include/android/bitmap.h @@ -100,6 +100,19 @@ typedef struct { int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, AndroidBitmapInfo* info); +#if __ANDROID_API__ >= 30 + +/** + * Given a java bitmap object, return its ADataSpace. + * + * Note that ADataSpace only exposes a few values. This may return + * ADATASPACE_UNKNOWN, even for Named ColorSpaces, if they have no + * corresponding ADataSpace. + */ +int32_t AndroidBitmap_getDataSpace(JNIEnv* env, jobject jbitmap) __INTRODUCED_IN(30); + +#endif // __ANDROID_API__ >= 30 + /** * Given a java bitmap object, attempt to lock the pixel address. * Locking will ensure that the memory for the pixels will not move -- GitLab From 324191fd2e3bb91da082975de2cb30769df4f56e Mon Sep 17 00:00:00 2001 From: Charlie Lao Date: Fri, 13 Dec 2019 11:03:16 -0800 Subject: [PATCH 0559/1255] Vulkan: dynamically advertise surface formats Adds dynamic validation of AHardwareBufferFormats and return as VkSurfaceFormatKHR instead of hardware coded values Test: verified on Pixel 4 with test app that it returned two pair of surface formats Bug: b/143296550 Change-Id: I972ea97d7930be56057c18584e84bf01331ae31f --- vulkan/libvulkan/swapchain.cpp | 99 +++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 42 deletions(-) diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index a020e744cd..aa7c19a844 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -694,20 +694,6 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, const InstanceData& instance_data = GetData(pdev); - // TODO(b/143296550): Fill out the set of supported formats. Longer term, - // add a new gralloc method to query whether a (format, usage) pair is - // supported, and check that for each gralloc format that corresponds to a - // Vulkan format. Shorter term, just add a few more formats to the ones - // hardcoded below. - - const VkSurfaceFormatKHR kFormats[] = { - {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, - {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, - {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, - }; - const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]); - uint32_t total_num_formats = kNumFormats; - bool wide_color_support = false; Surface& surface = *SurfaceFromHandle(surface_handle); int err = native_window_get_wide_color_support(surface.window.get(), @@ -720,43 +706,72 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, wide_color_support && instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace); - const VkSurfaceFormatKHR kWideColorFormats[] = { - {VK_FORMAT_R8G8B8A8_UNORM, - VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}, - {VK_FORMAT_R8G8B8A8_SRGB, - VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}, - {VK_FORMAT_R16G16B16A16_SFLOAT, - VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT}, - {VK_FORMAT_R16G16B16A16_SFLOAT, - VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT}, - {VK_FORMAT_A2B10G10R10_UNORM_PACK32, - VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}, - }; - const uint32_t kNumWideColorFormats = - sizeof(kWideColorFormats) / sizeof(kWideColorFormats[0]); + AHardwareBuffer_Desc desc = {}; + desc.width = 1; + desc.height = 1; + desc.layers = 1; + desc.usage = surface.consumer_usage | + AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | + AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER; + + // We must support R8G8B8A8 + std::vector all_formats = { + {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, + {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}}; + if (wide_color_support) { - total_num_formats += kNumWideColorFormats; + all_formats.emplace_back(VkSurfaceFormatKHR{ + VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}); + all_formats.emplace_back(VkSurfaceFormatKHR{ + VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}); + } + + desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM; + if (AHardwareBuffer_isSupported(&desc)) { + all_formats.emplace_back(VkSurfaceFormatKHR{ + VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}); + } + + desc.format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT; + if (AHardwareBuffer_isSupported(&desc)) { + all_formats.emplace_back(VkSurfaceFormatKHR{ + VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}); + if (wide_color_support) { + all_formats.emplace_back( + VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT, + VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT}); + all_formats.emplace_back( + VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT, + VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT}); + } + } + + desc.format = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM; + if (AHardwareBuffer_isSupported(&desc)) { + all_formats.emplace_back( + VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32, + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}); + if (wide_color_support) { + all_formats.emplace_back( + VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32, + VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}); + } } VkResult result = VK_SUCCESS; if (formats) { - uint32_t out_count = 0; - uint32_t transfer_count = 0; - if (*count < total_num_formats) + uint32_t transfer_count = all_formats.size(); + if (transfer_count > *count) { + transfer_count = *count; result = VK_INCOMPLETE; - transfer_count = std::min(*count, kNumFormats); - std::copy(kFormats, kFormats + transfer_count, formats); - out_count += transfer_count; - if (wide_color_support) { - transfer_count = std::min(*count - out_count, kNumWideColorFormats); - std::copy(kWideColorFormats, kWideColorFormats + transfer_count, - formats + out_count); - out_count += transfer_count; } - *count = out_count; + std::copy(all_formats.begin(), all_formats.begin() + transfer_count, + formats); + *count = transfer_count; } else { - *count = total_num_formats; + *count = all_formats.size(); } + return result; } -- GitLab From a32c5528f5cfdb3b67d455c63f58b74fab44d8b0 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Mon, 9 Dec 2019 10:11:08 -0800 Subject: [PATCH 0560/1255] Fixing triple buffer bug Bug: 141939236 Test: build, boot, libgui_test, manual Change-Id: I2d7b2e70142fa04825f02580425e7899c7c56d45 --- libs/gui/BLASTBufferQueue.cpp | 85 +++++++++++++++--------- libs/gui/include/gui/BLASTBufferQueue.h | 20 +++--- libs/gui/tests/BLASTBufferQueue_test.cpp | 4 +- 3 files changed, 67 insertions(+), 42 deletions(-) diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index b9cf9e1285..a5e5693ff4 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -17,10 +17,14 @@ #undef LOG_TAG #define LOG_TAG "BLASTBufferQueue" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + #include #include #include +#include + #include using namespace std::chrono_literals; @@ -29,23 +33,29 @@ namespace android { BLASTBufferQueue::BLASTBufferQueue(const sp& surface, int width, int height) : mSurfaceControl(surface), - mPendingCallbacks(0), mWidth(width), mHeight(height), mNextTransaction(nullptr) { BufferQueue::createBufferQueue(&mProducer, &mConsumer); mConsumer->setMaxBufferCount(MAX_BUFFERS); mProducer->setMaxDequeuedBufferCount(MAX_BUFFERS - 1); + mConsumer->setMaxAcquiredBufferCount(MAX_ACQUIRED_BUFFERS); mBufferItemConsumer = new BufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true); - mBufferItemConsumer->setName(String8("BLAST Consumer")); + static int32_t id = 0; + auto name = std::string("BLAST Consumer") + std::to_string(id); + id++; + mBufferItemConsumer->setName(String8(name.c_str())); mBufferItemConsumer->setFrameAvailableListener(this); mBufferItemConsumer->setBufferFreedListener(this); mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight); mBufferItemConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888); mBufferItemConsumer->setTransformHint(mSurfaceControl->getTransformHint()); - mAcquired = false; + mNumAcquired = 0; + mNumFrameAvailable = 0; + mPendingReleaseItem.item = BufferItem(); + mPendingReleaseItem.releaseFence = nullptr; } void BLASTBufferQueue::update(const sp& surface, int width, int height) { @@ -70,34 +80,46 @@ static void transactionCallbackThunk(void* context, nsecs_t latchTime, void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp& /*presentFence*/, const std::vector& stats) { std::unique_lock _lock{mMutex}; - - if (stats.size() > 0 && !mShadowQueue.empty()) { - mBufferItemConsumer->releaseBuffer(mNextCallbackBufferItem, - stats[0].previousReleaseFence - ? stats[0].previousReleaseFence + ATRACE_CALL(); + + if (mPendingReleaseItem.item.mGraphicBuffer != nullptr) { + if (stats.size() > 0) { + mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence; + mTransformHint = stats[0].transformHint; + } else { + ALOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback"); + mPendingReleaseItem.releaseFence = nullptr; + } + mBufferItemConsumer->releaseBuffer(mPendingReleaseItem.item, + mPendingReleaseItem.releaseFence + ? mPendingReleaseItem.releaseFence : Fence::NO_FENCE); - mAcquired = false; - mNextCallbackBufferItem = BufferItem(); - mBufferItemConsumer->setTransformHint(stats[0].transformHint); + mNumAcquired--; + mPendingReleaseItem.item = BufferItem(); + mPendingReleaseItem.releaseFence = nullptr; + } + + if (mSubmitted.empty()) { + ALOGE("ERROR: callback with no corresponding submitted buffer item"); } - mPendingCallbacks--; + mPendingReleaseItem.item = std::move(mSubmitted.front()); + mSubmitted.pop(); processNextBufferLocked(); mCallbackCV.notify_all(); decStrong((void*)transactionCallbackThunk); } void BLASTBufferQueue::processNextBufferLocked() { - if (mShadowQueue.empty()) { + ATRACE_CALL(); + if (mNumFrameAvailable == 0) { return; } - if (mAcquired) { + if (mSurfaceControl == nullptr) { + ALOGE("ERROR : surface control is null"); return; } - BufferItem item = std::move(mShadowQueue.front()); - mShadowQueue.pop(); - SurfaceComposerClient::Transaction localTransaction; bool applyTransaction = true; SurfaceComposerClient::Transaction* t = &localTransaction; @@ -107,33 +129,34 @@ void BLASTBufferQueue::processNextBufferLocked() { applyTransaction = false; } - mNextCallbackBufferItem = mLastSubmittedBufferItem; - mLastSubmittedBufferItem = BufferItem(); + BufferItem bufferItem; - status_t status = mBufferItemConsumer->acquireBuffer(&mLastSubmittedBufferItem, -1, false); - mAcquired = true; + status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, -1, false); if (status != OK) { - ALOGE("Failed to acquire?"); + return; } - - auto buffer = mLastSubmittedBufferItem.mGraphicBuffer; + auto buffer = bufferItem.mGraphicBuffer; + mNumFrameAvailable--; if (buffer == nullptr) { - ALOGE("Null buffer"); + mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE); return; } + mNumAcquired++; + mSubmitted.push(bufferItem); + // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. incStrong((void*)transactionCallbackThunk); t->setBuffer(mSurfaceControl, buffer); t->setAcquireFence(mSurfaceControl, - item.mFence ? new Fence(item.mFence->dup()) : Fence::NO_FENCE); + bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE); t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast(this)); t->setFrame(mSurfaceControl, {0, 0, (int32_t)buffer->getWidth(), (int32_t)buffer->getHeight()}); - t->setCrop(mSurfaceControl, computeCrop(mLastSubmittedBufferItem)); - t->setTransform(mSurfaceControl, mLastSubmittedBufferItem.mTransform); + t->setCrop(mSurfaceControl, computeCrop(bufferItem)); + t->setTransform(mSurfaceControl, bufferItem.mTransform); if (applyTransaction) { t->apply(); @@ -147,13 +170,13 @@ Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { return item.mCrop; } -void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { +void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) { + ATRACE_CALL(); std::lock_guard _lock{mMutex}; // add to shadow queue - mShadowQueue.push(item); + mNumFrameAvailable++; processNextBufferLocked(); - mPendingCallbacks++; } void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) { diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index dd0b4709e5..0a0a03c8f6 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -68,23 +68,25 @@ private: std::mutex mMutex; std::condition_variable mCallbackCV; - uint64_t mPendingCallbacks GUARDED_BY(mMutex); static const int MAX_BUFFERS = 3; - struct BufferInfo { - sp buffer; - int fence; + static const int MAX_ACQUIRED_BUFFERS = 2; + + int32_t mNumFrameAvailable GUARDED_BY(mMutex); + int32_t mNumAcquired GUARDED_BY(mMutex); + + struct PendingReleaseItem { + BufferItem item; + sp releaseFence; }; - std::queue mShadowQueue GUARDED_BY(mMutex); - bool mAcquired GUARDED_BY(mMutex); + std::queue mSubmitted GUARDED_BY(mMutex); + PendingReleaseItem mPendingReleaseItem GUARDED_BY(mMutex); int mWidth GUARDED_BY(mMutex); int mHeight GUARDED_BY(mMutex); - BufferItem mLastSubmittedBufferItem GUARDED_BY(mMutex); - BufferItem mNextCallbackBufferItem GUARDED_BY(mMutex); - sp mLastFence GUARDED_BY(mMutex); + uint32_t mTransformHint GUARDED_BY(mMutex); sp mConsumer; sp mProducer; diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 48a5cb63f3..0f618f181c 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -69,7 +69,7 @@ public: void waitForCallbacks() { std::unique_lock lock{mBlastBufferQueueAdapter->mMutex}; - while (mBlastBufferQueueAdapter->mPendingCallbacks > 0) { + while (mBlastBufferQueueAdapter->mSubmitted.size() > 0) { mBlastBufferQueueAdapter->mCallbackCV.wait(lock); } } @@ -302,7 +302,7 @@ TEST_F(BLASTBufferQueueTest, TripleBuffering) { igbProducer->cancelBuffer(allocated[i].first, allocated[i].second); } - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 100; i++) { int slot; sp fence; sp buf; -- GitLab From ef785e119167cc5c5ccac99dafbe37d675a7d7fd Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 12 Dec 2019 14:26:59 -0800 Subject: [PATCH 0561/1255] gralloc: add gralloc4 HDR metadata support Add the ability to get and set HDR metadata. Bug: 141632767 Test: VtsHalGraphicsMapperV4_0TargetTest Change-Id: I2fb06eb0bb43d2a5689228f3bd3b76e904d647b6 --- libs/gralloc/types/Gralloc4.cpp | 193 +++++++++++++++++- libs/gralloc/types/fuzzer/gralloctypes.cpp | 3 + .../types/include/gralloctypes/Gralloc4.h | 46 ++++- libs/ui/Gralloc4.cpp | 18 ++ libs/ui/GraphicBufferMapper.cpp | 15 ++ libs/ui/include/ui/Gralloc.h | 13 ++ libs/ui/include/ui/Gralloc4.h | 6 + libs/ui/include/ui/GraphicBufferMapper.h | 4 + libs/ui/include/ui/GraphicTypes.h | 4 + 9 files changed, 295 insertions(+), 7 deletions(-) diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp index b762f1ebd3..d02e839b78 100644 --- a/libs/gralloc/types/Gralloc4.cpp +++ b/libs/gralloc/types/Gralloc4.cpp @@ -28,6 +28,7 @@ using android::hardware::hidl_vec; using aidl::android::hardware::graphics::common::BlendMode; using aidl::android::hardware::graphics::common::ChromaSiting; using aidl::android::hardware::graphics::common::Compression; +using aidl::android::hardware::graphics::common::Cta861_3; using aidl::android::hardware::graphics::common::Dataspace; using aidl::android::hardware::graphics::common::ExtendableType; using aidl::android::hardware::graphics::common::Interlaced; @@ -35,7 +36,9 @@ using aidl::android::hardware::graphics::common::PlaneLayout; using aidl::android::hardware::graphics::common::PlaneLayoutComponent; using aidl::android::hardware::graphics::common::PlaneLayoutComponentType; using aidl::android::hardware::graphics::common::Rect; +using aidl::android::hardware::graphics::common::Smpte2086; using aidl::android::hardware::graphics::common::StandardMetadataType; +using aidl::android::hardware::graphics::common::XyColor; using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType; @@ -154,6 +157,13 @@ public: return mVec->size() > mOffset; } + size_t getRemainingSize() { + if (!mVec) { + return 0; + } + return mVec->size() - mOffset; + } + private: const hidl_vec* mVec; size_t mOffset = 0; @@ -218,6 +228,15 @@ status_t encode(const MetadataType& metadataType, const T& input, hidl_vec +status_t encodeOptional(const MetadataType& metadataType, const std::optional& input, + hidl_vec* output, EncodeHelper encodeHelper) { + if (!input) { + return NO_ERROR; + } + return encode(metadataType, *input, output, encodeHelper); +} + /** * decode is the main decode function. It takes in a hidl_vec and uses the decodeHelper function to * turn the hidl_vec byte stream into T. If an error occurs, the errorHandler function cleans up @@ -249,13 +268,32 @@ status_t decode(const MetadataType& metadataType, const hidl_vec& input return NO_ERROR; } +template +status_t decodeOptional(const MetadataType& metadataType, const hidl_vec& input, + std::optional* output, DecodeHelper decodeHelper) { + if (!output) { + return BAD_VALUE; + } + if (input.size() <= 0) { + output->reset(); + return NO_ERROR; + } + T tmp; + status_t err = decode(metadataType, input, &tmp, decodeHelper); + if (!err) { + *output = tmp; + } + return err; +} + /** * Private helper functions */ template status_t encodeInteger(const T& input, OutputHidlVec* output) { static_assert(std::is_same::value || std::is_same::value || - std::is_same::value || std::is_same::value); + std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value); if (!output) { return BAD_VALUE; } @@ -267,7 +305,8 @@ status_t encodeInteger(const T& input, OutputHidlVec* output) { template status_t decodeInteger(InputHidlVec* input, T* output) { static_assert(std::is_same::value || std::is_same::value || - std::is_same::value || std::is_same::value); + std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value); if (!output) { return BAD_VALUE; } @@ -306,6 +345,38 @@ status_t decodeString(InputHidlVec* input, std::string* output) { return input->decode(output, size); } +status_t encodeByteVector(const std::vector& input, OutputHidlVec* output) { + if (!output) { + return BAD_VALUE; + } + + status_t err = encodeInteger(input.size(), output); + if (err) { + return err; + } + + return output->encode(input.data(), input.size()); +} + +status_t decodeByteVector(InputHidlVec* input, std::vector* output) { + if (!output) { + return BAD_VALUE; + } + + int64_t size = 0; + status_t err = decodeInteger(input, &size); + if (err || size < 0) { + return err; + } + + if (size > input->getRemainingSize()) { + return BAD_VALUE; + } + output->resize(size); + + return input->decode(output->data(), size); +} + status_t encodeExtendableType(const ExtendableType& input, OutputHidlVec* output) { status_t err = encodeString(input.name, output); if (err) { @@ -391,6 +462,30 @@ status_t validateMetadataType(InputHidlVec* input, const MetadataType& expectedM return NO_ERROR; } +status_t encodeXyColor(const XyColor& input, OutputHidlVec* output) { + status_t err = encodeInteger(input.x, output); + if (err) { + return err; + } + return encodeInteger(input.y, output); +} + +status_t decodeXyColor(InputHidlVec* input, XyColor* output) { + status_t err = decodeInteger(input, &output->x); + if (err) { + return err; + } + return decodeInteger(input, &output->y); +} + +void clearXyColor(XyColor* output) { + if (!output) { + return; + } + output->x = 0; + output->y = 0; +} + status_t encodeRect(const Rect& input, OutputHidlVec* output) { status_t err = encodeInteger(static_cast(input.left), output); if (err) { @@ -635,6 +730,70 @@ void clearPlaneLayouts(std::vector* output) { output->clear(); } +status_t encodeSmpte2086Helper(const Smpte2086& smpte2086, OutputHidlVec* outOutputHidlVec) { + status_t err = encodeXyColor(smpte2086.primaryRed, outOutputHidlVec); + if (err) { + return err; + } + err = encodeXyColor(smpte2086.primaryGreen, outOutputHidlVec); + if (err) { + return err; + } + err = encodeXyColor(smpte2086.primaryBlue, outOutputHidlVec); + if (err) { + return err; + } + err = encodeXyColor(smpte2086.whitePoint, outOutputHidlVec); + if (err) { + return err; + } + err = encodeInteger(smpte2086.maxLuminance, outOutputHidlVec); + if (err) { + return err; + } + return encodeInteger(smpte2086.minLuminance, outOutputHidlVec); +} + +status_t decodeSmpte2086Helper(InputHidlVec* inputHidlVec, Smpte2086* outSmpte2086) { + status_t err = decodeXyColor(inputHidlVec, &outSmpte2086->primaryRed); + if (err) { + return err; + } + err = decodeXyColor(inputHidlVec, &outSmpte2086->primaryGreen); + if (err) { + return err; + } + err = decodeXyColor(inputHidlVec, &outSmpte2086->primaryBlue); + if (err) { + return err; + } + err = decodeXyColor(inputHidlVec, &outSmpte2086->whitePoint); + if (err) { + return err; + } + err = decodeInteger(inputHidlVec, &outSmpte2086->maxLuminance); + if (err) { + return err; + } + return decodeInteger(inputHidlVec, &outSmpte2086->minLuminance); +} + +status_t encodeCta861_3Helper(const Cta861_3& cta861_3, OutputHidlVec* outOutputHidlVec) { + status_t err = encodeInteger(cta861_3.maxContentLightLevel, outOutputHidlVec); + if (err) { + return err; + } + return encodeInteger(cta861_3.maxFrameAverageLightLevel, outOutputHidlVec); +} + +status_t decodeCta861_3Helper(InputHidlVec* inputHidlVec, Cta861_3* outCta861_3) { + status_t err = decodeInteger(inputHidlVec, &outCta861_3->maxContentLightLevel); + if (err) { + return err; + } + return decodeInteger(inputHidlVec, &outCta861_3->maxFrameAverageLightLevel); +} + /** * Public API functions */ @@ -798,6 +957,36 @@ status_t decodeBlendMode(const hidl_vec& blendMode, BlendMode* outBlend decodeInteger); } +status_t encodeSmpte2086(const std::optional& smpte2086, + hidl_vec* outSmpte2086) { + return encodeOptional(MetadataType_Smpte2086, smpte2086, outSmpte2086, encodeSmpte2086Helper); +} + +status_t decodeSmpte2086(const hidl_vec& smpte2086, + std::optional* outSmpte2086) { + return decodeOptional(MetadataType_Smpte2086, smpte2086, outSmpte2086, decodeSmpte2086Helper); +} + +status_t encodeCta861_3(const std::optional& cta861_3, hidl_vec* outCta861_3) { + return encodeOptional(MetadataType_Cta861_3, cta861_3, outCta861_3, encodeCta861_3Helper); +} + +status_t decodeCta861_3(const hidl_vec& cta861_3, std::optional* outCta861_3) { + return decodeOptional(MetadataType_Cta861_3, cta861_3, outCta861_3, decodeCta861_3Helper); +} + +status_t encodeSmpte2094_40(const std::optional>& smpte2094_40, + hidl_vec* outSmpte2094_40) { + return encodeOptional(MetadataType_Smpte2094_40, smpte2094_40, outSmpte2094_40, + encodeByteVector); +} + +status_t decodeSmpte2094_40(const hidl_vec& smpte2094_40, + std::optional>* outSmpte2094_40) { + return decodeOptional(MetadataType_Smpte2094_40, smpte2094_40, outSmpte2094_40, + decodeByteVector); +} + bool isStandardMetadataType(const MetadataType& metadataType) { return !std::strncmp(metadataType.name.c_str(), GRALLOC4_STANDARD_METADATA_TYPE, metadataType.name.size()); diff --git a/libs/gralloc/types/fuzzer/gralloctypes.cpp b/libs/gralloc/types/fuzzer/gralloctypes.cpp index 23c90b823d..da8cf97d4c 100644 --- a/libs/gralloc/types/fuzzer/gralloctypes.cpp +++ b/libs/gralloc/types/fuzzer/gralloctypes.cpp @@ -60,5 +60,8 @@ std::vector GRALLOCTYPES_DECODE_FUNCTIONS { GRALLOCTYPES_DECODE(std::vector, ::android::gralloc4::decodePlaneLayouts), GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::Dataspace, ::android::gralloc4::decodeDataspace), GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::BlendMode, ::android::gralloc4::decodeBlendMode), + GRALLOCTYPES_DECODE(std::optional, ::android::gralloc4::decodeSmpte2086), + GRALLOCTYPES_DECODE(std::optional, ::android::gralloc4::decodeCta861_3), + GRALLOCTYPES_DECODE(std::optional>, ::android::gralloc4::decodeSmpte2094_40), }; // clang-format on diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h index a5d3bb2975..94de8f115f 100644 --- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h +++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h @@ -17,16 +17,17 @@ #pragma once #include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include #include - +#include +#include +#include #include namespace android { @@ -113,6 +114,22 @@ static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType Me GRALLOC4_STANDARD_METADATA_TYPE, static_cast(aidl::android::hardware::graphics::common::StandardMetadataType::BLEND_MODE) }; +static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType + MetadataType_Smpte2086 = {GRALLOC4_STANDARD_METADATA_TYPE, + static_cast(aidl::android::hardware::graphics::common:: + StandardMetadataType::SMPTE2086)}; + +static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType + MetadataType_Cta861_3 = {GRALLOC4_STANDARD_METADATA_TYPE, + static_cast(aidl::android::hardware::graphics::common:: + StandardMetadataType::CTA861_3)}; + +static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType + MetadataType_Smpte2094_40 = {GRALLOC4_STANDARD_METADATA_TYPE, + static_cast( + aidl::android::hardware::graphics::common:: + StandardMetadataType::SMPTE2094_40)}; + /*---------------------------------------------------------------------------------------------*/ /** @@ -272,6 +289,25 @@ status_t decodeDataspace(const android::hardware::hidl_vec& dataspace, status_t encodeBlendMode(const aidl::android::hardware::graphics::common::BlendMode& blendMode, android::hardware::hidl_vec* outBlendMode); status_t decodeBlendMode(const android::hardware::hidl_vec& blendMode, aidl::android::hardware::graphics::common::BlendMode* outBlendMode); +status_t encodeSmpte2086( + const std::optional& smpte2086, + android::hardware::hidl_vec* outSmpte2086); +status_t decodeSmpte2086( + const android::hardware::hidl_vec& smpte2086, + std::optional* outSmpte2086); + +status_t encodeCta861_3( + const std::optional& cta861_3, + android::hardware::hidl_vec* outCta861_3); +status_t decodeCta861_3( + const android::hardware::hidl_vec& cta861_3, + std::optional* outCta861_3); + +status_t encodeSmpte2094_40(const std::optional>& smpte2094_40, + android::hardware::hidl_vec* outSmpte2094_40); +status_t decodeSmpte2094_40(const android::hardware::hidl_vec& smpte2094_40, + std::optional>* outSmpte2094_40); + /** * The functions below can be used to parse extendable types. */ diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp index 2c897cf4ff..30c48c8dc6 100644 --- a/libs/ui/Gralloc4.cpp +++ b/libs/ui/Gralloc4.cpp @@ -614,6 +614,24 @@ status_t Gralloc4Mapper::getBlendMode(buffer_handle_t bufferHandle, outBlendMode); } +status_t Gralloc4Mapper::getSmpte2086(buffer_handle_t bufferHandle, + std::optional* outSmpte2086) const { + return get(bufferHandle, gralloc4::MetadataType_Smpte2086, gralloc4::decodeSmpte2086, + outSmpte2086); +} + +status_t Gralloc4Mapper::getCta861_3(buffer_handle_t bufferHandle, + std::optional* outCta861_3) const { + return get(bufferHandle, gralloc4::MetadataType_Cta861_3, gralloc4::decodeCta861_3, + outCta861_3); +} + +status_t Gralloc4Mapper::getSmpte2094_40( + buffer_handle_t bufferHandle, std::optional>* outSmpte2094_40) const { + return get(bufferHandle, gralloc4::MetadataType_Smpte2094_40, gralloc4::decodeSmpte2094_40, + outSmpte2094_40); +} + template status_t Gralloc4Mapper::getDefault(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp index 8540fd304b..d20bd7a899 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -286,6 +286,21 @@ status_t GraphicBufferMapper::getBlendMode(buffer_handle_t bufferHandle, return mMapper->getBlendMode(bufferHandle, outBlendMode); } +status_t GraphicBufferMapper::getSmpte2086(buffer_handle_t bufferHandle, + std::optional* outSmpte2086) { + return mMapper->getSmpte2086(bufferHandle, outSmpte2086); +} + +status_t GraphicBufferMapper::getCta861_3(buffer_handle_t bufferHandle, + std::optional* outCta861_3) { + return mMapper->getCta861_3(bufferHandle, outCta861_3); +} + +status_t GraphicBufferMapper::getSmpte2094_40( + buffer_handle_t bufferHandle, std::optional>* outSmpte2094_40) { + return mMapper->getSmpte2094_40(bufferHandle, outSmpte2094_40); +} + status_t GraphicBufferMapper::getDefaultPixelFormatFourCC(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h index fcd959c2cc..e199648a8b 100644 --- a/libs/ui/include/ui/Gralloc.h +++ b/libs/ui/include/ui/Gralloc.h @@ -165,6 +165,19 @@ public: ui::BlendMode* /*outBlendMode*/) const { return INVALID_OPERATION; } + virtual status_t getSmpte2086(buffer_handle_t /*bufferHandle*/, + std::optional* /*outSmpte2086*/) const { + return INVALID_OPERATION; + } + virtual status_t getCta861_3(buffer_handle_t /*bufferHandle*/, + std::optional* /*outCta861_3*/) const { + return INVALID_OPERATION; + } + virtual status_t getSmpte2094_40( + buffer_handle_t /*bufferHandle*/, + std::optional>* /*outSmpte2094_40*/) const { + return INVALID_OPERATION; + } virtual status_t getDefaultPixelFormatFourCC(uint32_t /*width*/, uint32_t /*height*/, PixelFormat /*format*/, uint32_t /*layerCount*/, diff --git a/libs/ui/include/ui/Gralloc4.h b/libs/ui/include/ui/Gralloc4.h index af7c076221..4729cbaf67 100644 --- a/libs/ui/include/ui/Gralloc4.h +++ b/libs/ui/include/ui/Gralloc4.h @@ -102,6 +102,12 @@ public: std::vector* outPlaneLayouts) const override; status_t getDataspace(buffer_handle_t bufferHandle, ui::Dataspace* outDataspace) const override; status_t getBlendMode(buffer_handle_t bufferHandle, ui::BlendMode* outBlendMode) const override; + status_t getSmpte2086(buffer_handle_t bufferHandle, + std::optional* outSmpte2086) const override; + status_t getCta861_3(buffer_handle_t bufferHandle, + std::optional* outCta861_3) const override; + status_t getSmpte2094_40(buffer_handle_t bufferHandle, + std::optional>* outSmpte2094_40) const override; status_t getDefaultPixelFormatFourCC(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h index 77c00ae8e9..837e3d826b 100644 --- a/libs/ui/include/ui/GraphicBufferMapper.h +++ b/libs/ui/include/ui/GraphicBufferMapper.h @@ -122,6 +122,10 @@ public: std::vector* outPlaneLayouts); status_t getDataspace(buffer_handle_t bufferHandle, ui::Dataspace* outDataspace); status_t getBlendMode(buffer_handle_t bufferHandle, ui::BlendMode* outBlendMode); + status_t getSmpte2086(buffer_handle_t bufferHandle, std::optional* outSmpte2086); + status_t getCta861_3(buffer_handle_t bufferHandle, std::optional* outCta861_3); + status_t getSmpte2094_40(buffer_handle_t bufferHandle, + std::optional>* outSmpte2094_40); /** * Gets the default metadata for a gralloc buffer allocated with the given parameters. diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h index ad5ee8043a..4bdacb0883 100644 --- a/libs/ui/include/ui/GraphicTypes.h +++ b/libs/ui/include/ui/GraphicTypes.h @@ -19,8 +19,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -47,7 +49,9 @@ using android::hardware::graphics::common::V1_2::PixelFormat; * Stable AIDL types */ using aidl::android::hardware::graphics::common::BlendMode; +using aidl::android::hardware::graphics::common::Cta861_3; using aidl::android::hardware::graphics::common::PlaneLayout; +using aidl::android::hardware::graphics::common::Smpte2086; /** * The following stable AIDL types below have standard platform definitions -- GitLab From f91e9236bc80482b1c327f8fb7306c5b0b419e65 Mon Sep 17 00:00:00 2001 From: Kevin DuBois Date: Thu, 21 Nov 2019 10:51:23 -0800 Subject: [PATCH 0562/1255] SF: VSyncReactor add event subscription functions Adds 3 more functions from the DispSync interface to VSyncReactor, {add,remove}EventListener and changePhaseOffset. Bug: 140303479 Test: about 10 new units Change-Id: I2135f87a21cd0e43613367d31e006bb574380bc6 --- .../surfaceflinger/Scheduler/VSyncReactor.cpp | 126 +++++++++++ .../surfaceflinger/Scheduler/VSyncReactor.h | 11 + .../tests/unittests/VSyncReactorTest.cpp | 205 ++++++++++++++++-- 3 files changed, 329 insertions(+), 13 deletions(-) diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index f2a7791ada..49ab6c1f85 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -14,7 +14,9 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 #include "VSyncReactor.h" +#include #include "TimeKeeper.h" #include "VSyncDispatch.h" #include "VSyncTracker.h" @@ -30,6 +32,84 @@ VSyncReactor::VSyncReactor(std::unique_ptr clock, std::unique_ptr lk(mMutex); + mRegistration.cancel(); + } + + void start(nsecs_t offset) { + std::lock_guard lk(mMutex); + mStopped = false; + mOffset = offset; + + // TODO: (b/145213786) check the return code here sensibly + mRegistration.schedule(calculateWorkload(), mLastCallTime); + } + + void setPeriod(nsecs_t period) { + std::lock_guard lk(mMutex); + if (period == mPeriod) { + return; + } + mPeriod = period; + } + + void stop() { + std::lock_guard lk(mMutex); + LOG_ALWAYS_FATAL_IF(mStopped, "DispSyncInterface misuse: callback already stopped"); + mStopped = true; + mRegistration.cancel(); + } + +private: + void callback(nsecs_t vsynctime) { + nsecs_t period = 0; + { + std::lock_guard lk(mMutex); + period = mPeriod; + mLastCallTime = vsynctime; + } + + mCallback->onDispSyncEvent(vsynctime - period); + + { + std::lock_guard lk(mMutex); + mRegistration.schedule(calculateWorkload(), vsynctime); + } + } + + // DispSync offsets are defined as time after the vsync before presentation. + // VSyncReactor workloads are defined as time before the intended presentation vsync. + // Note change in sign between the two defnitions. + nsecs_t calculateWorkload() REQUIRES(mMutex) { return mPeriod - mOffset; } + + DispSync::Callback* const mCallback; + + std::mutex mutable mMutex; + VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex); + bool mStopped GUARDED_BY(mMutex) = false; + nsecs_t mPeriod GUARDED_BY(mMutex); + nsecs_t mOffset GUARDED_BY(mMutex); + nsecs_t mLastCallTime GUARDED_BY(mMutex); +}; + bool VSyncReactor::addPresentFence(const std::shared_ptr& fence) { if (!fence) { return false; @@ -92,6 +172,9 @@ void VSyncReactor::setPeriod(nsecs_t period) { { std::lock_guard lk(mMutex); mPeriodChangeInProgress = true; + for (auto& entry : mCallbacks) { + entry.second->setPeriod(period); + } } } @@ -114,4 +197,47 @@ bool VSyncReactor::addResyncSample(nsecs_t timestamp, bool* periodFlushed) { return false; } +status_t VSyncReactor::addEventListener(const char* name, nsecs_t phase, + DispSync::Callback* callback, + nsecs_t /* lastCallbackTime */) { + std::lock_guard lk(mMutex); + auto it = mCallbacks.find(callback); + if (it == mCallbacks.end()) { + // TODO (b/146557561): resolve lastCallbackTime semantics in DispSync i/f. + static auto constexpr maxListeners = 3; + if (mCallbacks.size() >= maxListeners) { + ALOGE("callback %s not added, exceeded callback limit of %i (currently %zu)", name, + maxListeners, mCallbacks.size()); + return NO_MEMORY; + } + + auto const period = mTracker->currentPeriod(); + auto repeater = std::make_unique(*mDispatch, callback, name, period, + phase, mClock->now()); + it = mCallbacks.emplace(std::pair(callback, std::move(repeater))).first; + } + + it->second->start(phase); + return NO_ERROR; +} + +status_t VSyncReactor::removeEventListener(DispSync::Callback* callback, + nsecs_t* /* outLastCallback */) { + std::lock_guard lk(mMutex); + auto const it = mCallbacks.find(callback); + LOG_ALWAYS_FATAL_IF(it == mCallbacks.end(), "callback %p not registered", callback); + + it->second->stop(); + return NO_ERROR; +} + +status_t VSyncReactor::changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) { + std::lock_guard lk(mMutex); + auto const it = mCallbacks.find(callback); + LOG_ALWAYS_FATAL_IF(it == mCallbacks.end(), "callback was %p not registered", callback); + + it->second->start(phase); + return NO_ERROR; +} + } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index 786ee98cca..837eb75005 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -20,19 +20,23 @@ #include #include #include +#include #include +#include "DispSync.h" namespace android::scheduler { class Clock; class VSyncDispatch; class VSyncTracker; +class CallbackRepeater; // TODO (b/145217110): consider renaming. class VSyncReactor /* TODO (b/140201379): : public android::DispSync */ { public: VSyncReactor(std::unique_ptr clock, std::unique_ptr dispatch, std::unique_ptr tracker, size_t pendingFenceLimit); + ~VSyncReactor(); bool addPresentFence(const std::shared_ptr& fence); void setIgnorePresentFences(bool ignoration); @@ -48,6 +52,11 @@ public: bool addResyncSample(nsecs_t timestamp, bool* periodFlushed); void endResync(); + status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback, + nsecs_t lastCallbackTime); + status_t removeEventListener(DispSync::Callback* callback, nsecs_t* outLastCallback); + status_t changePhaseOffset(DispSync::Callback* callback, nsecs_t phase); + private: std::unique_ptr const mClock; std::unique_ptr const mDispatch; @@ -58,6 +67,8 @@ private: bool mIgnorePresentFences GUARDED_BY(mMutex) = false; std::vector> mUnfiredFences GUARDED_BY(mMutex); bool mPeriodChangeInProgress GUARDED_BY(mMutex) = false; + std::unordered_map> mCallbacks + GUARDED_BY(mMutex); }; } // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index 84df019d53..652a7b86db 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -122,21 +122,53 @@ std::shared_ptr generateSignalledFenceWithTime(nsecs_t time) { return ft; } +class StubCallback : public DispSync::Callback { +public: + void onDispSyncEvent(nsecs_t when) final { + std::lock_guard lk(mMutex); + mLastCallTime = when; + } + std::optional lastCallTime() const { + std::lock_guard lk(mMutex); + return mLastCallTime; + } + +private: + std::mutex mutable mMutex; + std::optional mLastCallTime GUARDED_BY(mMutex); +}; + class VSyncReactorTest : public testing::Test { protected: VSyncReactorTest() - : mMockDispatch(std::make_shared()), + : mMockDispatch(std::make_shared>()), mMockTracker(std::make_shared>()), mMockClock(std::make_shared>()), mReactor(std::make_unique(mMockClock), std::make_unique(mMockDispatch), - std::make_unique(mMockTracker), kPendingLimit) {} + std::make_unique(mMockTracker), kPendingLimit) { + ON_CALL(*mMockClock, now()).WillByDefault(Return(mFakeNow)); + ON_CALL(*mMockTracker, currentPeriod()).WillByDefault(Return(period)); + } std::shared_ptr mMockDispatch; std::shared_ptr mMockTracker; std::shared_ptr mMockClock; static constexpr size_t kPendingLimit = 3; - static constexpr nsecs_t dummyTime = 47; + static constexpr nsecs_t mDummyTime = 47; + static constexpr nsecs_t mPhase = 3000; + static constexpr nsecs_t mAnotherPhase = 5200; + static constexpr nsecs_t period = 10000; + static constexpr nsecs_t mAnotherPeriod = 23333; + static constexpr nsecs_t mFakeCbTime = 2093; + static constexpr nsecs_t mFakeNow = 2214; + static constexpr const char mName[] = "callbacky"; + VSyncDispatch::CallbackToken const mFakeToken{2398}; + + nsecs_t lastCallbackTime = 0; + StubCallback outerCb; + std::function innerCb; + VSyncReactor mReactor; }; @@ -149,8 +181,8 @@ TEST_F(VSyncReactorTest, addingInvalidFenceSignalsNeedsMoreInfo) { } TEST_F(VSyncReactorTest, addingSignalledFenceAddsToTracker) { - EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime)); - EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime))); + EXPECT_CALL(*mMockTracker, addVsyncTimestamp(mDummyTime)); + EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime))); } TEST_F(VSyncReactorTest, addingPendingFenceAddsSignalled) { @@ -161,9 +193,9 @@ TEST_F(VSyncReactorTest, addingPendingFenceAddsSignalled) { EXPECT_FALSE(mReactor.addPresentFence(pendingFence)); Mock::VerifyAndClearExpectations(mMockTracker.get()); - signalFenceWithTime(pendingFence, dummyTime); + signalFenceWithTime(pendingFence, mDummyTime); - EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime)); + EXPECT_CALL(*mMockTracker, addVsyncTimestamp(mDummyTime)); EXPECT_CALL(*mMockTracker, addVsyncTimestamp(anotherDummyTime)); EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(anotherDummyTime))); } @@ -193,15 +225,15 @@ TEST_F(VSyncReactorTest, limitsPendingFences) { TEST_F(VSyncReactorTest, ignoresPresentFencesWhenToldTo) { static constexpr size_t aFewTimes = 8; - EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime)).Times(1); + EXPECT_CALL(*mMockTracker, addVsyncTimestamp(mDummyTime)).Times(1); mReactor.setIgnorePresentFences(true); for (auto i = 0; i < aFewTimes; i++) { - mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime)); + mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime)); } mReactor.setIgnorePresentFences(false); - EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime))); + EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime))); } TEST_F(VSyncReactorTest, queriesTrackerForNextRefreshNow) { @@ -227,11 +259,11 @@ TEST_F(VSyncReactorTest, queriesTrackerForExpectedPresentTime) { TEST_F(VSyncReactorTest, queriesTrackerForNextRefreshFuture) { nsecs_t const fakeTimestamp = 4839; nsecs_t const fakePeriod = 1010; - nsecs_t const fakeNow = 2214; + nsecs_t const mFakeNow = 2214; int const numPeriodsOut = 3; - EXPECT_CALL(*mMockClock, now()).WillOnce(Return(fakeNow)); + EXPECT_CALL(*mMockClock, now()).WillOnce(Return(mFakeNow)); EXPECT_CALL(*mMockTracker, currentPeriod()).WillOnce(Return(fakePeriod)); - EXPECT_CALL(*mMockTracker, nextAnticipatedVSyncTimeFrom(fakeNow + numPeriodsOut * fakePeriod)) + EXPECT_CALL(*mMockTracker, nextAnticipatedVSyncTimeFrom(mFakeNow + numPeriodsOut * fakePeriod)) .WillOnce(Return(fakeTimestamp)); EXPECT_THAT(mReactor.computeNextRefresh(numPeriodsOut), Eq(fakeTimestamp)); } @@ -267,4 +299,151 @@ TEST_F(VSyncReactorTest, addResyncSamplePeriodChanges) { EXPECT_TRUE(periodFlushed); } +static nsecs_t computeWorkload(nsecs_t period, nsecs_t phase) { + return period - phase; +} + +TEST_F(VSyncReactorTest, addEventListener) { + Sequence seq; + EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) + .InSequence(seq) + .WillOnce(Return(mFakeToken)); + EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) + .InSequence(seq); + EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq); + EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq); + + mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); + mReactor.removeEventListener(&outerCb, &lastCallbackTime); +} + +TEST_F(VSyncReactorTest, addEventListenerTwiceChangesPhase) { + Sequence seq; + EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) + .InSequence(seq) + .WillOnce(Return(mFakeToken)); + EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) + .InSequence(seq); + EXPECT_CALL(*mMockDispatch, + schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _)) // mFakeNow)) + .InSequence(seq); + EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq); + EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq); + + mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); + mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime); +} + +TEST_F(VSyncReactorTest, eventListenerGetsACallbackAndReschedules) { + Sequence seq; + EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) + .InSequence(seq) + .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken))); + EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) + .InSequence(seq); + EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeCbTime)) + .Times(2) + .InSequence(seq); + EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq); + EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq); + + mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); + ASSERT_TRUE(innerCb); + innerCb(mFakeCbTime); + innerCb(mFakeCbTime); +} + +TEST_F(VSyncReactorTest, callbackTimestampReadapted) { + Sequence seq; + EXPECT_CALL(*mMockDispatch, registerCallback(_, _)) + .InSequence(seq) + .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken))); + EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) + .InSequence(seq); + EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeCbTime)) + .InSequence(seq); + + mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); + ASSERT_TRUE(innerCb); + innerCb(mFakeCbTime); + EXPECT_THAT(outerCb.lastCallTime(), Optional(mFakeCbTime - period)); +} + +TEST_F(VSyncReactorTest, eventListenersRemovedOnDestruction) { + Sequence seq; + EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) + .InSequence(seq) + .WillOnce(Return(mFakeToken)); + EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) + .InSequence(seq); + EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq); + EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq); + + mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); +} + +TEST_F(VSyncReactorTest, addEventListenerChangePeriod) { + Sequence seq; + EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) + .InSequence(seq) + .WillOnce(Return(mFakeToken)); + EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) + .InSequence(seq); + EXPECT_CALL(*mMockDispatch, + schedule(mFakeToken, computeWorkload(period, mAnotherPhase), mFakeNow)) + .InSequence(seq); + EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq); + EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq); + + mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); + mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime); +} + +TEST_F(VSyncReactorTest, changingPeriodChangesOfsetsOnNextCb) { + Sequence seq; + EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) + .InSequence(seq) + .WillOnce(Return(mFakeToken)); + EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) + .InSequence(seq); + EXPECT_CALL(*mMockTracker, setPeriod(mAnotherPeriod)); + EXPECT_CALL(*mMockDispatch, + schedule(mFakeToken, computeWorkload(mAnotherPeriod, mPhase), mFakeNow)) + .InSequence(seq); + + mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); + mReactor.setPeriod(mAnotherPeriod); + mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); +} + +TEST_F(VSyncReactorTest, negativeOffsetsApplied) { + nsecs_t const negativePhase = -4000; + Sequence seq; + EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) + .InSequence(seq) + .WillOnce(Return(mFakeToken)); + EXPECT_CALL(*mMockDispatch, + schedule(mFakeToken, computeWorkload(period, negativePhase), mFakeNow)) + .InSequence(seq); + mReactor.addEventListener(mName, negativePhase, &outerCb, lastCallbackTime); +} + +using VSyncReactorDeathTest = VSyncReactorTest; +TEST_F(VSyncReactorDeathTest, invalidRemoval) { + mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); + mReactor.removeEventListener(&outerCb, &lastCallbackTime); + EXPECT_DEATH(mReactor.removeEventListener(&outerCb, &lastCallbackTime), ".*"); +} + +TEST_F(VSyncReactorDeathTest, invalidChange) { + EXPECT_DEATH(mReactor.changePhaseOffset(&outerCb, mPhase), ".*"); + + // the current DispSync-interface usage pattern has evolved around an implementation quirk, + // which is a callback is assumed to always exist, and it is valid api usage to change the + // offset of an object that is in the removed state. + mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); + mReactor.removeEventListener(&outerCb, &lastCallbackTime); + mReactor.changePhaseOffset(&outerCb, mPhase); +} + } // namespace android::scheduler -- GitLab From 8588cc99829d4f02ecff1fd5e4d3d8a719402949 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 12 Dec 2018 18:17:58 -0800 Subject: [PATCH 0563/1255] Native tests for EventHub Currently, there is no test coverage for EventHub. Add some basic tests for EventHub here. This should establish a place for future EventHub tests. Test: atest -a inputflinger_tests Bug: 62940136 Bug: 111431676 Change-Id: If7d1da814b1b296bd731dd82d227256067d085fd --- services/inputflinger/tests/Android.bp | 2 + services/inputflinger/tests/EventHub_test.cpp | 238 ++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 services/inputflinger/tests/EventHub_test.cpp diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index ada2266333..09ecb13b0a 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -4,6 +4,7 @@ cc_test { name: "inputflinger_tests", srcs: [ "BlockingQueue_test.cpp", + "EventHub_test.cpp", "TestInputListener.cpp", "InputClassifier_test.cpp", "InputClassifierConverter_test.cpp", @@ -36,4 +37,5 @@ cc_test { header_libs: [ "libinputreader_headers", ], + require_root: true, } diff --git a/services/inputflinger/tests/EventHub_test.cpp b/services/inputflinger/tests/EventHub_test.cpp new file mode 100644 index 0000000000..6504738fc7 --- /dev/null +++ b/services/inputflinger/tests/EventHub_test.cpp @@ -0,0 +1,238 @@ +/* + * Copyright (C) 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 "EventHub.h" + +#include +#include +#include +#include +#include +#include + +#define TAG "EventHub_test" + +using android::EventHub; +using android::EventHubInterface; +using android::InputDeviceIdentifier; +using android::RawEvent; +using android::sp; +using android::base::StringPrintf; +using std::chrono_literals::operator""ms; + +static constexpr bool DEBUG = false; +static const char* DEVICE_NAME = "EventHub Test Device"; + +static void dumpEvents(const std::vector& events) { + for (const RawEvent& event : events) { + if (event.type >= EventHubInterface::FIRST_SYNTHETIC_EVENT) { + switch (event.type) { + case EventHubInterface::DEVICE_ADDED: + ALOGI("Device added: %i", event.deviceId); + break; + case EventHubInterface::DEVICE_REMOVED: + ALOGI("Device removed: %i", event.deviceId); + break; + case EventHubInterface::FINISHED_DEVICE_SCAN: + ALOGI("Finished device scan."); + break; + } + } else { + ALOGI("Device %" PRId32 " : time = %" PRId64 ", type %i, code %i, value %i", + event.deviceId, event.when, event.type, event.code, event.value); + } + } +} + +// --- EventHubTest --- +class EventHubTest : public testing::Test { +protected: + std::unique_ptr mEventHub; + // We are only going to emulate a single input device currently. + android::base::unique_fd mDeviceFd; + int32_t mDeviceId; + virtual void SetUp() override { + mEventHub = std::make_unique(); + consumeInitialDeviceAddedEvents(); + createDevice(); + mDeviceId = waitForDeviceCreation(); + } + virtual void TearDown() override { + mDeviceFd.reset(); + waitForDeviceClose(mDeviceId); + } + + void createDevice(); + /** + * Return the device id of the created device. + */ + int32_t waitForDeviceCreation(); + void waitForDeviceClose(int32_t deviceId); + void consumeInitialDeviceAddedEvents(); + void sendEvent(uint16_t type, uint16_t code, int32_t value); + std::vector getEvents(std::chrono::milliseconds timeout = 5ms); +}; + +std::vector EventHubTest::getEvents(std::chrono::milliseconds timeout) { + static constexpr size_t EVENT_BUFFER_SIZE = 256; + std::array eventBuffer; + std::vector events; + + while (true) { + size_t count = + mEventHub->getEvents(timeout.count(), eventBuffer.data(), eventBuffer.size()); + if (count == 0) { + break; + } + events.insert(events.end(), eventBuffer.begin(), eventBuffer.begin() + count); + } + if (DEBUG) { + dumpEvents(events); + } + return events; +} + +void EventHubTest::createDevice() { + mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK)); + if (mDeviceFd < 0) { + FAIL() << "Can't open /dev/uinput :" << strerror(errno); + } + + /** + * Signal which type of events this input device supports. + * We will emulate a keyboard here. + */ + // enable key press/release event + if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_KEY)) { + ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno); + } + + // enable set of KEY events + if (ioctl(mDeviceFd, UI_SET_KEYBIT, KEY_HOME)) { + ADD_FAILURE() << "Error in ioctl : UI_SET_KEYBIT : KEY_HOME: " << strerror(errno); + } + + // enable synchronization event + if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_SYN)) { + ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno); + } + + struct uinput_user_dev keyboard = {}; + strlcpy(keyboard.name, DEVICE_NAME, UINPUT_MAX_NAME_SIZE); + keyboard.id.bustype = BUS_USB; + keyboard.id.vendor = 0x01; + keyboard.id.product = 0x01; + keyboard.id.version = 1; + + if (write(mDeviceFd, &keyboard, sizeof(keyboard)) < 0) { + FAIL() << "Could not write uinput_user_dev struct into uinput file descriptor: " + << strerror(errno); + } + + if (ioctl(mDeviceFd, UI_DEV_CREATE)) { + FAIL() << "Error in ioctl : UI_DEV_CREATE: " << strerror(errno); + } +} + +/** + * Since the test runs on a real platform, there will be existing devices + * in addition to the test devices being added. Therefore, when EventHub is first created, + * it will return a lot of "device added" type of events. + */ +void EventHubTest::consumeInitialDeviceAddedEvents() { + std::vector events = getEvents(0ms); + std::set existingDevices; + // All of the events should be DEVICE_ADDED type, except the last one. + for (size_t i = 0; i < events.size() - 1; i++) { + const RawEvent& event = events[i]; + EXPECT_EQ(EventHubInterface::DEVICE_ADDED, event.type); + existingDevices.insert(event.deviceId); + } + // None of the existing system devices should be changing while this test is run. + // Check that the returned device ids are unique for all of the existing devices. + EXPECT_EQ(existingDevices.size(), events.size() - 1); + // The last event should be "finished device scan" + EXPECT_EQ(EventHubInterface::FINISHED_DEVICE_SCAN, events[events.size() - 1].type); +} + +int32_t EventHubTest::waitForDeviceCreation() { + // Wait a little longer than usual, to ensure input device has time to be created + std::vector events = getEvents(20ms); + EXPECT_EQ(2U, events.size()); // Using "expect" because the function is non-void. + const RawEvent& deviceAddedEvent = events[0]; + EXPECT_EQ(static_cast(EventHubInterface::DEVICE_ADDED), deviceAddedEvent.type); + InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceAddedEvent.deviceId); + const int32_t deviceId = deviceAddedEvent.deviceId; + EXPECT_EQ(identifier.name, DEVICE_NAME); + const RawEvent& finishedDeviceScanEvent = events[1]; + EXPECT_EQ(static_cast(EventHubInterface::FINISHED_DEVICE_SCAN), + finishedDeviceScanEvent.type); + return deviceId; +} + +void EventHubTest::waitForDeviceClose(int32_t deviceId) { + std::vector events = getEvents(20ms); + ASSERT_EQ(2U, events.size()); + const RawEvent& deviceRemovedEvent = events[0]; + EXPECT_EQ(static_cast(EventHubInterface::DEVICE_REMOVED), deviceRemovedEvent.type); + EXPECT_EQ(deviceId, deviceRemovedEvent.deviceId); + const RawEvent& finishedDeviceScanEvent = events[1]; + EXPECT_EQ(static_cast(EventHubInterface::FINISHED_DEVICE_SCAN), + finishedDeviceScanEvent.type); +} + +void EventHubTest::sendEvent(uint16_t type, uint16_t code, int32_t value) { + struct input_event event = {}; + event.type = type; + event.code = code; + event.value = value; + event.time = {}; // uinput ignores the timestamp + + if (write(mDeviceFd, &event, sizeof(input_event)) < 0) { + std::string msg = StringPrintf("Could not write event %" PRIu16 " %" PRIu16 + " with value %" PRId32 " : %s", + type, code, value, strerror(errno)); + ALOGE("%s", msg.c_str()); + ADD_FAILURE() << msg.c_str(); + } +} + +/** + * Ensure that input_events are generated with monotonic clock. + * That means input_event should receive a timestamp that is in the future of the time + * before the event was sent. + * Input system uses CLOCK_MONOTONIC everywhere in the code base. + */ +TEST_F(EventHubTest, InputEvent_TimestampIsMonotonic) { + nsecs_t lastEventTime = systemTime(SYSTEM_TIME_MONOTONIC); + // key press + sendEvent(EV_KEY, KEY_HOME, 1); + sendEvent(EV_SYN, SYN_REPORT, 0); + + // key release + sendEvent(EV_KEY, KEY_HOME, 0); + sendEvent(EV_SYN, SYN_REPORT, 0); + + std::vector events = getEvents(); + ASSERT_EQ(4U, events.size()) << "Expected to receive 2 keys and 2 syncs, total of 4 events"; + for (const RawEvent& event : events) { + // Cannot use strict comparison because the events may happen too quickly + ASSERT_LE(lastEventTime, event.when) << "Event must have occurred after the key was sent"; + ASSERT_LT(std::chrono::nanoseconds(event.when - lastEventTime), 100ms) + << "Event times are too far apart"; + lastEventTime = event.when; // Ensure all returned events are monotonic + } +} -- GitLab From 81e2bb96bf4b7f3bfdcdcc33c9247e5b94748243 Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 18 Dec 2019 15:03:51 -0800 Subject: [PATCH 0564/1255] Consume batches in dispatcher tests We are currently calling consume with consumeBatches=false. But that means we don't want to consume any batched events. As a result, when events are simply stored internally in inputconsumer, they are not returned to callers of consume(..). We never had tests that included MOVE events, and since DOWN events are never batched, we did not encounter this case. Now that we are adding a MOVE test, we need to ensure batches are consumed as well. Bug: none Test: atest inputflinger_tests Change-Id: Ieb13e1bb43bbf96f7f9352a283387ffdb11ba54a --- libs/input/InputTransport.cpp | 4 +-- .../tests/InputDispatcher_test.cpp | 28 ++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 200e1f39d9..d53a557b28 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -301,8 +301,8 @@ status_t InputChannel::sendMessage(const InputMessage* msg) { if (nWrite < 0) { int error = errno; #if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.c_str(), - msg->header.type, error); + ALOGD("channel '%s' ~ error sending message of type %d, %s", mName.c_str(), + msg->header.type, strerror(error)); #endif if (error == EAGAIN || error == EWOULDBLOCK) { return WOULD_BLOCK; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 0701f3b3ee..994010ba0e 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -418,7 +418,7 @@ public: std::chrono::time_point start = std::chrono::steady_clock::now(); status_t status = WOULD_BLOCK; while (status == WOULD_BLOCK) { - status = mConsumer->consume(&mEventFactory, false /*consumeBatches*/, -1, &consumeSeq, + status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event); std::chrono::duration elapsed = std::chrono::steady_clock::now() - start; if (elapsed > 100ms) { @@ -932,6 +932,32 @@ TEST_F(InputDispatcherTest, GestureMonitor_CanPilferAfterWindowIsRemovedMidStrea monitor->consumeMotionUp(ADISPLAY_ID_DEFAULT); } +TEST_F(InputDispatcherTest, TestMoveEvent) { + sp application = new FakeApplicationHandle(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + + mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + + NotifyMotionArgs motionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + + mDispatcher->notifyMotion(&motionArgs); + // Window should receive motion down event. + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + + motionArgs.action = AMOTION_EVENT_ACTION_MOVE; + motionArgs.sequenceNum += 1; + motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC); + motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, + motionArgs.pointerCoords[0].getX() - 10); + + mDispatcher->notifyMotion(&motionArgs); + window->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_MOVE, ADISPLAY_ID_DEFAULT, + 0 /*expectedFlags*/); +} + /* Test InputDispatcher for MultiDisplay */ class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest { public: -- GitLab From c94ca83964accc75b08060a265abe2a346de1c2d Mon Sep 17 00:00:00 2001 From: Kevin DuBois Date: Tue, 26 Nov 2019 12:56:24 -0800 Subject: [PATCH 0565/1255] SF: VSyncDispatch: correct vsync prediction drift Refine VSyncDispatch::schedule implementation so that refining the prediction by small amounts would not lead to skipped callbacks. The current implementation did not account for a case where a valid vsync callback would be skipped. (exposed in unit testing). Like the rest of VSyncDispatch, this code is flagged off (ie, latent, not production code yet) Fixes: 145213786 Bug: 146050690 Test: 6 new unit tests, 3 unit test change Test: validation via systrace Change-Id: I400fc5e3c181b49ab237b0dd0da2a62e38522fa0 --- .../surfaceflinger/Scheduler/VSyncDispatch.h | 3 +- .../Scheduler/VSyncDispatchTimerQueue.cpp | 48 +++++-- .../Scheduler/VSyncDispatchTimerQueue.h | 14 +- .../surfaceflinger/Scheduler/VSyncReactor.cpp | 11 +- .../unittests/VSyncDispatchRealtimeTest.cpp | 10 +- .../unittests/VSyncDispatchTimerQueueTest.cpp | 131 ++++++++++++++---- .../tests/unittests/VSyncReactorTest.cpp | 43 ++++++ 7 files changed, 212 insertions(+), 48 deletions(-) diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h index e001080015..56b3252272 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatch.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h @@ -26,7 +26,7 @@ namespace android::scheduler { class TimeKeeper; class VSyncTracker; -enum class ScheduleResult { Scheduled, ReScheduled, CannotSchedule, Error }; +enum class ScheduleResult { Scheduled, CannotSchedule, Error }; enum class CancelResult { Cancelled, TooLate, Error }; /* @@ -83,7 +83,6 @@ public: * \param [in] earliestVsync The targeted display time. This will be snapped to the closest * predicted vsync time after earliestVsync. * \return A ScheduleResult::Scheduled if callback was scheduled. - * A ScheduleResult::ReScheduled if callback was rescheduled. * A ScheduleResult::CannotSchedule * if (workDuration - earliestVsync) is in the past, or * if a callback was dispatched for the predictedVsync already. diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp index a79fe98a27..48f2abb7aa 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp @@ -29,8 +29,13 @@ VSyncTracker::~VSyncTracker() = default; TimeKeeper::~TimeKeeper() = default; VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string const& name, - std::function const& cb) - : mName(name), mCallback(cb), mWorkDuration(0), mEarliestVsync(0) {} + std::function const& cb, + nsecs_t minVsyncDistance) + : mName(name), + mCallback(cb), + mWorkDuration(0), + mEarliestVsync(0), + mMinVsyncDistance(minVsyncDistance) {} std::optional VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const { return mLastDispatchTime; @@ -49,18 +54,28 @@ std::optional VSyncDispatchTimerQueueEntry::wakeupTime() const { ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync, VSyncTracker& tracker, nsecs_t now) { - auto const nextVsyncTime = + auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(std::max(earliestVsync, now + workDuration)); - if (mLastDispatchTime >= nextVsyncTime) { // already dispatched a callback for this vsync - return ScheduleResult::CannotSchedule; + + bool const wouldSkipAVsyncTarget = + mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance)); + if (wouldSkipAVsyncTarget) { + return ScheduleResult::Scheduled; + } + + bool const alreadyDispatchedForVsync = mLastDispatchTime && + ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime && + (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime); + if (alreadyDispatchedForVsync) { + nextVsyncTime = + tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance); } auto const nextWakeupTime = nextVsyncTime - workDuration; - auto result = mArmedInfo ? ScheduleResult::ReScheduled : ScheduleResult::Scheduled; mWorkDuration = workDuration; mEarliestVsync = earliestVsync; mArmedInfo = {nextWakeupTime, nextVsyncTime}; - return result; + return ScheduleResult::Scheduled; } void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) { @@ -101,8 +116,12 @@ void VSyncDispatchTimerQueueEntry::ensureNotRunning() { } VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr tk, - VSyncTracker& tracker, nsecs_t timerSlack) - : mTimeKeeper(std::move(tk)), mTracker(tracker), mTimerSlack(timerSlack) {} + VSyncTracker& tracker, nsecs_t timerSlack, + nsecs_t minVsyncDistance) + : mTimeKeeper(std::move(tk)), + mTracker(tracker), + mTimerSlack(timerSlack), + mMinVsyncDistance(minVsyncDistance) {} VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() { std::lock_guard lk(mMutex); @@ -187,7 +206,8 @@ VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback mCallbacks .emplace(++mCallbackToken, std::make_shared(callbackName, - callbackFn)) + callbackFn, + mMinVsyncDistance)) .first->first}; } @@ -277,12 +297,16 @@ VSyncCallbackRegistration::~VSyncCallbackRegistration() { } ScheduleResult VSyncCallbackRegistration::schedule(nsecs_t workDuration, nsecs_t earliestVsync) { - if (!mValidToken) return ScheduleResult::Error; + if (!mValidToken) { + return ScheduleResult::Error; + } return mDispatch.get().schedule(mToken, workDuration, earliestVsync); } CancelResult VSyncCallbackRegistration::cancel() { - if (!mValidToken) return CancelResult::Error; + if (!mValidToken) { + return CancelResult::Error; + } return mDispatch.get().cancel(mToken); } diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h index fc78da3977..0c9b4fe53e 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h @@ -36,7 +36,8 @@ public: // Valid transition: disarmed -> armed ( when scheduled ) // Valid transition: armed -> running -> disarmed ( when timer is called) // Valid transition: armed -> disarmed ( when cancelled ) - VSyncDispatchTimerQueueEntry(std::string const& name, std::function const& fn); + VSyncDispatchTimerQueueEntry(std::string const& name, std::function const& fn, + nsecs_t minVsyncDistance); std::string_view name() const; // Start: functions that are not threadsafe. @@ -72,6 +73,7 @@ private: nsecs_t mWorkDuration; nsecs_t mEarliestVsync; + nsecs_t const mMinVsyncDistance; struct ArmingInfo { nsecs_t mActualWakeupTime; @@ -91,8 +93,15 @@ private: */ class VSyncDispatchTimerQueue : public VSyncDispatch { public: + // Constructs a VSyncDispatchTimerQueue. + // \param[in] tk A timekeeper. + // \param[in] tracker A tracker. + // \param[in] timerSlack The threshold at which different similarly timed callbacks + // should be grouped into one wakeup. + // \param[in] minVsyncDistance The minimum distance between two vsync estimates before the + // vsyncs are considered the same vsync event. explicit VSyncDispatchTimerQueue(std::unique_ptr tk, VSyncTracker& tracker, - nsecs_t timerSlack); + nsecs_t timerSlack, nsecs_t minVsyncDistance); ~VSyncDispatchTimerQueue(); CallbackToken registerCallback(std::function const& callbackFn, @@ -119,6 +128,7 @@ private: std::unique_ptr const mTimeKeeper; VSyncTracker& mTracker; nsecs_t const mTimerSlack; + nsecs_t const mMinVsyncDistance; std::mutex mutable mMutex; size_t mCallbackToken GUARDED_BY(mMutex) = 0; diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index 49ab6c1f85..47e3f4f9e9 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#undef LOG_TAG +#define LOG_TAG "VSyncReactor" //#define LOG_NDEBUG 0 #include "VSyncReactor.h" #include @@ -59,8 +61,9 @@ public: mStopped = false; mOffset = offset; - // TODO: (b/145213786) check the return code here sensibly - mRegistration.schedule(calculateWorkload(), mLastCallTime); + auto const schedule_result = mRegistration.schedule(calculateWorkload(), mLastCallTime); + LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled), + "Error scheduling callback: rc %X", schedule_result); } void setPeriod(nsecs_t period) { @@ -91,7 +94,9 @@ private: { std::lock_guard lk(mMutex); - mRegistration.schedule(calculateWorkload(), vsynctime); + auto const schedule_result = mRegistration.schedule(calculateWorkload(), vsynctime); + LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled), + "Error rescheduling callback: rc %X", schedule_result); } } diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp index 484947d3f3..5846c77533 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp @@ -92,6 +92,7 @@ private: struct VSyncDispatchRealtimeTest : testing::Test { static nsecs_t constexpr mDispatchGroupThreshold = toNs(100us); + static nsecs_t constexpr mVsyncMoveThreshold = toNs(500us); static size_t constexpr mIterations = 20; }; @@ -148,7 +149,8 @@ private: TEST_F(VSyncDispatchRealtimeTest, triple_alarm) { FixedRateIdealStubTracker tracker; - VSyncDispatchTimerQueue dispatch(std::make_unique(), tracker, mDispatchGroupThreshold); + VSyncDispatchTimerQueue dispatch(std::make_unique(), tracker, mDispatchGroupThreshold, + mVsyncMoveThreshold); static size_t constexpr num_clients = 3; std::array @@ -176,7 +178,8 @@ TEST_F(VSyncDispatchRealtimeTest, triple_alarm) { TEST_F(VSyncDispatchRealtimeTest, vascillating_vrr) { auto next_vsync_interval = toNs(3ms); VRRStubTracker tracker(next_vsync_interval); - VSyncDispatchTimerQueue dispatch(std::make_unique(), tracker, mDispatchGroupThreshold); + VSyncDispatchTimerQueue dispatch(std::make_unique(), tracker, mDispatchGroupThreshold, + mVsyncMoveThreshold); RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms)); @@ -193,7 +196,8 @@ TEST_F(VSyncDispatchRealtimeTest, vascillating_vrr) { // starts at 333hz, jumps to 200hz at frame 10 TEST_F(VSyncDispatchRealtimeTest, fixed_jump) { VRRStubTracker tracker(toNs(3ms)); - VSyncDispatchTimerQueue dispatch(std::make_unique(), tracker, mDispatchGroupThreshold); + VSyncDispatchTimerQueue dispatch(std::make_unique(), tracker, mDispatchGroupThreshold, + mVsyncMoveThreshold); RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms)); diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index d668a41bf1..5aff4296f9 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -196,16 +196,18 @@ protected: NiceMock mMockClock; static nsecs_t constexpr mDispatchGroupThreshold = 5; nsecs_t const mPeriod = 1000; + nsecs_t const mVsyncMoveThreshold = 300; NiceMock mStubTracker{mPeriod}; - VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold}; + VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold, + mVsyncMoveThreshold}; }; TEST_F(VSyncDispatchTimerQueueTest, unregistersSetAlarmOnDestruction) { EXPECT_CALL(mMockClock, alarmIn(_, 900)); EXPECT_CALL(mMockClock, alarmCancel()); { - VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, - mDispatchGroupThreshold}; + VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold, + mVsyncMoveThreshold}; CountingCallback cb(mDispatch); EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::Scheduled); } @@ -468,14 +470,24 @@ TEST_F(VSyncDispatchTimerQueueTest, callbackReentrancy) { TEST_F(VSyncDispatchTimerQueueTest, callbackReentrantWithPastWakeup) { VSyncDispatch::CallbackToken tmp; + std::optional lastTarget; tmp = mDispatch.registerCallback( - [&](auto) { - EXPECT_EQ(mDispatch.schedule(tmp, 400, 1000), ScheduleResult::CannotSchedule); + [&](auto timestamp) { + EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp - mVsyncMoveThreshold), + ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp + mVsyncMoveThreshold), + ScheduleResult::Scheduled); + lastTarget = timestamp; }, "oo"); mDispatch.schedule(tmp, 999, 1000); advanceToNextCallback(); + EXPECT_THAT(lastTarget, Eq(1000)); + + advanceToNextCallback(); + EXPECT_THAT(lastTarget, Eq(2000)); } TEST_F(VSyncDispatchTimerQueueTest, modificationsAroundVsyncTime) { @@ -547,10 +559,33 @@ TEST_F(VSyncDispatchTimerQueueTest, makingUpIdsError) { EXPECT_THAT(mDispatch.cancel(token), Eq(CancelResult::Error)); } -TEST_F(VSyncDispatchTimerQueueTest, distinguishesScheduleAndReschedule) { +TEST_F(VSyncDispatchTimerQueueTest, canMoveCallbackBackwardsInTime) { CountingCallback cb0(mDispatch); EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled); - EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::ReScheduled); + EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::Scheduled); +} + +// b/1450138150 +TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync) { + EXPECT_CALL(mMockClock, alarmIn(_, 500)); + CountingCallback cb(mDispatch); + EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled); + mMockClock.advanceBy(400); + + EXPECT_EQ(mDispatch.schedule(cb, 800, 1000), ScheduleResult::Scheduled); + advanceToNextCallback(); + ASSERT_THAT(cb.mCalls.size(), Eq(1)); +} + +TEST_F(VSyncDispatchTimerQueueTest, targetOffsetMovingBackALittleCanStillSchedule) { + EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000)) + .Times(2) + .WillOnce(Return(1000)) + .WillOnce(Return(1002)); + CountingCallback cb(mDispatch); + EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled); + mMockClock.advanceBy(400); + EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled); } TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) { @@ -570,13 +605,15 @@ TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) { EXPECT_EQ(mDispatch.schedule(cb0, 1900, 2000), ScheduleResult::Scheduled); } -TEST_F(VSyncDispatchTimerQueueTest, cannotScheduleDoesNotAffectSchedulingState) { +TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) { EXPECT_CALL(mMockClock, alarmIn(_, 600)); CountingCallback cb(mDispatch); EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled); + + EXPECT_EQ(mDispatch.schedule(cb, 1400, 1000), ScheduleResult::Scheduled); + advanceToNextCallback(); - EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::CannotSchedule); } TEST_F(VSyncDispatchTimerQueueTest, helperMove) { @@ -612,19 +649,22 @@ TEST_F(VSyncDispatchTimerQueueTest, helperMoveAssign) { class VSyncDispatchTimerQueueEntryTest : public testing::Test { protected: nsecs_t const mPeriod = 1000; + nsecs_t const mVsyncMoveThreshold = 200; NiceMock mStubTracker{mPeriod}; }; TEST_F(VSyncDispatchTimerQueueEntryTest, stateAfterInitialization) { std::string name("basicname"); - VSyncDispatchTimerQueueEntry entry(name, [](auto) {}); + VSyncDispatchTimerQueueEntry entry( + name, [](auto) {}, mVsyncMoveThreshold); EXPECT_THAT(entry.name(), Eq(name)); EXPECT_FALSE(entry.lastExecutedVsyncTarget()); EXPECT_FALSE(entry.wakeupTime()); } TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) { - VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); + VSyncDispatchTimerQueueEntry entry( + "test", [](auto) {}, mVsyncMoveThreshold); EXPECT_FALSE(entry.wakeupTime()); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); @@ -643,7 +683,8 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, stateSchedulingReallyLongWakeupLatency) EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + duration)) .Times(1) .WillOnce(Return(10000)); - VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); + VSyncDispatchTimerQueueEntry entry( + "test", [](auto) {}, mVsyncMoveThreshold); EXPECT_FALSE(entry.wakeupTime()); EXPECT_THAT(entry.schedule(500, 994, mStubTracker, now), Eq(ScheduleResult::Scheduled)); @@ -655,10 +696,13 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, stateSchedulingReallyLongWakeupLatency) TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) { auto callCount = 0; auto calledTime = 0; - VSyncDispatchTimerQueueEntry entry("test", [&](auto time) { - callCount++; - calledTime = time; - }); + VSyncDispatchTimerQueueEntry entry( + "test", + [&](auto time) { + callCount++; + calledTime = time; + }, + mVsyncMoveThreshold); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); auto const wakeup = entry.wakeupTime(); @@ -681,7 +725,8 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) { .WillOnce(Return(1000)) .WillOnce(Return(1020)); - VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); + VSyncDispatchTimerQueueEntry entry( + "test", [](auto) {}, mVsyncMoveThreshold); EXPECT_FALSE(entry.wakeupTime()); entry.update(mStubTracker, 0); @@ -699,7 +744,8 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) { } TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) { - VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); + VSyncDispatchTimerQueueEntry entry( + "test", [](auto) {}, mVsyncMoveThreshold); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); entry.update(mStubTracker, 0); @@ -708,19 +754,52 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) { EXPECT_THAT(*wakeup, Eq(wakeup)); } -TEST_F(VSyncDispatchTimerQueueEntryTest, reportsCannotScheduleIfMissedOpportunity) { - VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); +TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) { + VSyncDispatchTimerQueueEntry entry( + "test", [](auto) {}, mVsyncMoveThreshold); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); - entry.executing(); - EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::CannotSchedule)); - EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::CannotSchedule)); + entry.executing(); // 1000 is executing + // had 1000 not been executing, this could have been scheduled for time 800. + EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(*entry.wakeupTime(), Eq(1800)); + + EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(*entry.wakeupTime(), Eq(1950)); + EXPECT_THAT(entry.schedule(200, 1001, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(*entry.wakeupTime(), Eq(1800)); +} + +TEST_F(VSyncDispatchTimerQueueEntryTest, + willRequestNextEstimateWhenSnappingToNextTargettableVSync) { + VSyncDispatchTimerQueueEntry entry( + "test", [](auto) {}, mVsyncMoveThreshold); + + Sequence seq; + EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500)) + .InSequence(seq) + .WillOnce(Return(1000)); + EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500)) + .InSequence(seq) + .WillOnce(Return(1000)); + EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000 + mVsyncMoveThreshold)) + .InSequence(seq) + .WillOnce(Return(2000)); + + EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + + entry.executing(); // 1000 is executing + + EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); } -TEST_F(VSyncDispatchTimerQueueEntryTest, reportsReScheduleIfStillTime) { - VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); +TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) { + VSyncDispatchTimerQueueEntry entry( + "test", [](auto) {}, mVsyncMoveThreshold); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); - EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::ReScheduled)); + EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule(1200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); } } // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index 652a7b86db..537cc80bed 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -416,6 +416,29 @@ TEST_F(VSyncReactorTest, changingPeriodChangesOfsetsOnNextCb) { mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); } +TEST_F(VSyncReactorTest, offsetsAppliedOnNextOpportunity) { + Sequence seq; + EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) + .InSequence(seq) + .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken))); + EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), _)) + .InSequence(seq) + .WillOnce(Return(ScheduleResult::Scheduled)); + + EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _)) + .InSequence(seq) + .WillOnce(Return(ScheduleResult::Scheduled)); + + EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _)) + .InSequence(seq) + .WillOnce(Return(ScheduleResult::Scheduled)); + + mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); + mReactor.changePhaseOffset(&outerCb, mAnotherPhase); + ASSERT_TRUE(innerCb); + innerCb(mFakeCbTime); +} + TEST_F(VSyncReactorTest, negativeOffsetsApplied) { nsecs_t const negativePhase = -4000; Sequence seq; @@ -446,4 +469,24 @@ TEST_F(VSyncReactorDeathTest, invalidChange) { mReactor.changePhaseOffset(&outerCb, mPhase); } +TEST_F(VSyncReactorDeathTest, cannotScheduleOnRegistration) { + ON_CALL(*mMockDispatch, schedule(_, _, _)) + .WillByDefault(Return(ScheduleResult::CannotSchedule)); + EXPECT_DEATH(mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime), ".*"); +} + +TEST_F(VSyncReactorDeathTest, cannotScheduleOnCallback) { + EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) + .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken))); + EXPECT_CALL(*mMockDispatch, schedule(_, _, _)).WillOnce(Return(ScheduleResult::Scheduled)); + + mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); + ASSERT_TRUE(innerCb); + Mock::VerifyAndClearExpectations(mMockDispatch.get()); + + ON_CALL(*mMockDispatch, schedule(_, _, _)) + .WillByDefault(Return(ScheduleResult::CannotSchedule)); + EXPECT_DEATH(innerCb(mFakeCbTime), ".*"); +} + } // namespace android::scheduler -- GitLab From 705c2e6bbe601c421be3931248967ca33eb7bb98 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Wed, 18 Dec 2019 23:12:43 -0800 Subject: [PATCH 0566/1255] Vulkan: implement timeout for vkAcquireNextImageKHR ANativeWindow api allows to set dequeueBuffer timeout through binder IPC. It's difficult to change IGBP api to merge dequeueBuffer and setting timeout into one binder without reving up the HAL. Thus we just cache the timeout at swapchain and only update when the timeout set in vkAcquireNextImageKHR has changed. To be noted, IGBP api takes nsecs_t which is backed by int64_t, and it uses -1 as the hint to be blocking. So the uint64_t timeout set in vkAcquireNextImageKHR will be trimmed internally. Bug: 146534593 Test: dEQP-VK.wsi.android.swapchain.acquire.too_many Test: dEQP-VK.wsi.android.swapchain.acquire.too_many_timeout Change-Id: I9bd73a17dba8d86994c5863082534a082317f700 --- vulkan/libvulkan/swapchain.cpp | 37 ++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index a020e744cd..2dd88782b4 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -228,8 +229,10 @@ struct Swapchain { mailbox_mode(present_mode == VK_PRESENT_MODE_MAILBOX_KHR), pre_transform(pre_transform_), frame_timestamps_enabled(false), + acquire_next_image_timeout(-1), shared(present_mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || - present_mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { + present_mode == + VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { ANativeWindow* window = surface.window.get(); native_window_get_refresh_cycle_duration( window, @@ -251,6 +254,7 @@ struct Swapchain { int pre_transform; bool frame_timestamps_enabled; int64_t refresh_duration; + nsecs_t acquire_next_image_timeout; bool shared; struct Image { @@ -1079,6 +1083,14 @@ VkResult CreateSwapchainKHR(VkDevice device, ALOGW_IF(err != 0, "native_window_api_connect failed: %s (%d)", strerror(-err), err); + err = surface.window.get()->perform(surface.window.get(), + NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, -1); + if (err != android::OK) { + ALOGE("window->perform(SET_DEQUEUE_TIMEOUT) failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + err = native_window_set_buffer_count(surface.window.get(), 0); if (err != 0) { ALOGE("native_window_set_buffer_count(0) failed: %s (%d)", @@ -1432,10 +1444,6 @@ VkResult AcquireNextImageKHR(VkDevice device, if (swapchain.surface.swapchain_handle != swapchain_handle) return VK_ERROR_OUT_OF_DATE_KHR; - ALOGW_IF( - timeout != UINT64_MAX, - "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented"); - if (swapchain.shared) { // In shared mode, we keep the buffer dequeued all the time, so we don't // want to dequeue a buffer here. Instead, just ask the driver to ensure @@ -1446,10 +1454,27 @@ VkResult AcquireNextImageKHR(VkDevice device, return result; } + const nsecs_t acquire_next_image_timeout = + timeout > (uint64_t)std::numeric_limits::max() ? -1 : timeout; + if (acquire_next_image_timeout != swapchain.acquire_next_image_timeout) { + // Cache the timeout to avoid the duplicate binder cost. + err = window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, + acquire_next_image_timeout); + if (err != android::OK) { + ALOGE("window->perform(SET_DEQUEUE_TIMEOUT) failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + swapchain.acquire_next_image_timeout = acquire_next_image_timeout; + } + ANativeWindowBuffer* buffer; int fence_fd; err = window->dequeueBuffer(window, &buffer, &fence_fd); - if (err != 0) { + if (err == android::TIMED_OUT) { + ALOGW("dequeueBuffer timed out: %s (%d)", strerror(-err), err); + return timeout ? VK_TIMEOUT : VK_NOT_READY; + } else if (err != android::OK) { ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } -- GitLab From f5030b416cdafd67e7a7635bd9e2e586f70199be Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Thu, 19 Dec 2019 00:10:04 -0800 Subject: [PATCH 0567/1255] Refactor the native window api return codes and simplify the window use Test: build, flash and boot Change-Id: Ie1a5c0ed884bd30d0df07962c8abc916ba15bc6e --- vulkan/libvulkan/swapchain.cpp | 130 +++++++++++++++------------------ 1 file changed, 60 insertions(+), 70 deletions(-) diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 2dd88782b4..5463dadd43 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -367,7 +367,7 @@ uint32_t get_num_ready_timings(Swapchain& swapchain) { int64_t composition_latch_time = 0; int64_t actual_present_time = 0; // Obtain timestamps: - int ret = native_window_get_frame_timestamps( + int err = native_window_get_frame_timestamps( swapchain.surface.window.get(), ti.native_frame_id_, &desired_present_time, &render_complete_time, &composition_latch_time, @@ -378,7 +378,7 @@ uint32_t get_num_ready_timings(Swapchain& swapchain) { nullptr, //&dequeue_ready_time, nullptr /*&reads_done_time*/); - if (ret != android::NO_ERROR) { + if (err != android::OK) { continue; } @@ -534,7 +534,7 @@ VkResult CreateAndroidSurfaceKHR( surface->swapchain_handle = VK_NULL_HANDLE; int err = native_window_get_consumer_usage(surface->window.get(), &surface->consumer_usage); - if (err != android::NO_ERROR) { + if (err != android::OK) { ALOGE("native_window_get_consumer_usage() failed: %s (%d)", strerror(-err), err); surface->~Surface(); @@ -544,7 +544,7 @@ VkResult CreateAndroidSurfaceKHR( err = native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL); - if (err != 0) { + if (err != android::OK) { ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err), err); surface->~Surface(); @@ -592,7 +592,7 @@ VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/, int query_value; int err = window->query(window, NATIVE_WINDOW_FORMAT, &query_value); - if (err != 0 || query_value < 0) { + if (err != android::OK || query_value < 0) { ALOGE("NATIVE_WINDOW_FORMAT query failed: %s (%d) value=%d", strerror(-err), err, query_value); return VK_ERROR_SURFACE_LOST_KHR; @@ -633,13 +633,13 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( int width, height; err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); - if (err != 0) { + if (err != android::OK) { ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); - if (err != 0) { + if (err != android::OK) { ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -647,7 +647,7 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( int transform_hint; err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint); - if (err != 0) { + if (err != android::OK) { ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -655,7 +655,7 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( int max_buffer_count; err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &max_buffer_count); - if (err != 0) { + if (err != android::OK) { ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -845,7 +845,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value); - if (err != 0 || query_value < 0) { + if (err != android::OK || query_value < 0) { ALOGE("NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) value=%d", strerror(-err), err, query_value); return VK_ERROR_SURFACE_LOST_KHR; @@ -853,7 +853,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, uint32_t min_undequeued_buffers = static_cast(query_value); err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value); - if (err != 0 || query_value < 0) { + if (err != android::OK || query_value < 0) { ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d) value=%d", strerror(-err), err, query_value); return VK_ERROR_SURFACE_LOST_KHR; @@ -945,12 +945,12 @@ VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice, int width = 0, height = 0; err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); - if (err != 0) { + if (err != android::OK) { ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", strerror(-err), err); } err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); - if (err != 0) { + if (err != android::OK) { ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", strerror(-err), err); } @@ -1074,25 +1074,23 @@ VkResult CreateSwapchainKHR(VkDevice device, // dequeue all buffers. // // TODO(http://b/134186185) recycle swapchain images more efficiently - err = native_window_api_disconnect(surface.window.get(), - NATIVE_WINDOW_API_EGL); - ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", + ANativeWindow* window = surface.window.get(); + err = native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); + ALOGW_IF(err != android::OK, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err); - err = - native_window_api_connect(surface.window.get(), NATIVE_WINDOW_API_EGL); - ALOGW_IF(err != 0, "native_window_api_connect failed: %s (%d)", + err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); + ALOGW_IF(err != android::OK, "native_window_api_connect failed: %s (%d)", strerror(-err), err); - err = surface.window.get()->perform(surface.window.get(), - NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, -1); + err = window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, -1); if (err != android::OK) { ALOGE("window->perform(SET_DEQUEUE_TIMEOUT) failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } - err = native_window_set_buffer_count(surface.window.get(), 0); - if (err != 0) { + err = native_window_set_buffer_count(window, 0); + if (err != android::OK) { ALOGE("native_window_set_buffer_count(0) failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1100,22 +1098,22 @@ VkResult CreateSwapchainKHR(VkDevice device, int swap_interval = create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1; - err = surface.window->setSwapInterval(surface.window.get(), swap_interval); - if (err != 0) { + err = window->setSwapInterval(window, swap_interval); + if (err != android::OK) { ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } - err = native_window_set_shared_buffer_mode(surface.window.get(), false); - if (err != 0) { + err = native_window_set_shared_buffer_mode(window, false); + if (err != android::OK) { ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } - err = native_window_set_auto_refresh(surface.window.get(), false); - if (err != 0) { + err = native_window_set_auto_refresh(window, false); + if (err != android::OK) { ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1125,25 +1123,23 @@ VkResult CreateSwapchainKHR(VkDevice device, const auto& dispatch = GetData(device).driver; - err = native_window_set_buffers_format(surface.window.get(), - native_pixel_format); - if (err != 0) { + err = native_window_set_buffers_format(window, native_pixel_format); + if (err != android::OK) { ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)", native_pixel_format, strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } - err = native_window_set_buffers_data_space(surface.window.get(), - native_dataspace); - if (err != 0) { + err = native_window_set_buffers_data_space(window, native_dataspace); + if (err != android::OK) { ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)", native_dataspace, strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } err = native_window_set_buffers_dimensions( - surface.window.get(), static_cast(create_info->imageExtent.width), + window, static_cast(create_info->imageExtent.width), static_cast(create_info->imageExtent.height)); - if (err != 0) { + if (err != android::OK) { ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)", create_info->imageExtent.width, create_info->imageExtent.height, strerror(-err), err); @@ -1159,9 +1155,8 @@ VkResult CreateSwapchainKHR(VkDevice device, // it's job the two transforms cancel each other out and the compositor ends // up applying an identity transform to the app's buffer. err = native_window_set_buffers_transform( - surface.window.get(), - InvertTransformToNative(create_info->preTransform)); - if (err != 0) { + window, InvertTransformToNative(create_info->preTransform)); + if (err != android::OK) { ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", InvertTransformToNative(create_info->preTransform), strerror(-err), err); @@ -1169,8 +1164,8 @@ VkResult CreateSwapchainKHR(VkDevice device, } err = native_window_set_scaling_mode( - surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - if (err != 0) { + window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + if (err != android::OK) { ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1180,26 +1175,25 @@ VkResult CreateSwapchainKHR(VkDevice device, if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID; - err = native_window_set_shared_buffer_mode(surface.window.get(), true); - if (err != 0) { + err = native_window_set_shared_buffer_mode(window, true); + if (err != android::OK) { ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } } if (create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { - err = native_window_set_auto_refresh(surface.window.get(), true); - if (err != 0) { + err = native_window_set_auto_refresh(window, true); + if (err != android::OK) { ALOGE("native_window_set_auto_refresh failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } } int query_value; - err = surface.window->query(surface.window.get(), - NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - &query_value); - if (err != 0 || query_value < 0) { + err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &query_value); + if (err != android::OK || query_value < 0) { ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value); return VK_ERROR_SURFACE_LOST_KHR; @@ -1215,8 +1209,8 @@ VkResult CreateSwapchainKHR(VkDevice device, // in place for that to work yet. Note we only lie to the lower layer-- we // don't want to give the app back a swapchain with extra images (which they // can't actually use!). - err = native_window_set_buffer_count(surface.window.get(), std::max(2u, num_images)); - if (err != 0) { + err = native_window_set_buffer_count(window, std::max(2u, num_images)); + if (err != android::OK) { ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images, strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1254,16 +1248,15 @@ VkResult CreateSwapchainKHR(VkDevice device, createProtectedSwapchain = true; native_usage |= BufferUsage::PROTECTED; } - err = native_window_set_usage(surface.window.get(), native_usage); - if (err != 0) { + err = native_window_set_usage(window, native_usage); + if (err != android::OK) { ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } int transform_hint; - err = surface.window->query(surface.window.get(), - NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint); - if (err != 0) { + err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint); + if (err != android::OK) { ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1319,9 +1312,8 @@ VkResult CreateSwapchainKHR(VkDevice device, Swapchain::Image& img = swapchain->images[i]; ANativeWindowBuffer* buffer; - err = surface.window->dequeueBuffer(surface.window.get(), &buffer, - &img.dequeue_fence); - if (err != 0) { + err = window->dequeueBuffer(window, &buffer, &img.dequeue_fence); + if (err != android::OK) { ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); switch (-err) { case ENOMEM: @@ -1365,8 +1357,8 @@ VkResult CreateSwapchainKHR(VkDevice device, Swapchain::Image& img = swapchain->images[i]; if (img.dequeued) { if (!swapchain->shared) { - surface.window->cancelBuffer(surface.window.get(), img.buffer.get(), - img.dequeue_fence); + window->cancelBuffer(window, img.buffer.get(), + img.dequeue_fence); img.dequeue_fence = -1; img.dequeued = false; } @@ -1681,7 +1673,7 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { uint64_t nativeFrameId = 0; err = native_window_get_next_frame_id( window, &nativeFrameId); - if (err != android::NO_ERROR) { + if (err != android::OK) { ALOGE("Failed to get next native frame ID."); } @@ -1705,7 +1697,7 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { err = window->queueBuffer(window, img.buffer.get(), fence); // queueBuffer always closes fence, even on error - if (err != 0) { + if (err != android::OK) { ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err); swapchain_result = WorstPresentResult( swapchain_result, VK_ERROR_OUT_OF_DATE_KHR); @@ -1725,17 +1717,15 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { ANativeWindowBuffer* buffer; int fence_fd; err = window->dequeueBuffer(window, &buffer, &fence_fd); - if (err != 0) { + if (err != android::OK) { ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err); swapchain_result = WorstPresentResult(swapchain_result, VK_ERROR_SURFACE_LOST_KHR); - } - else if (img.buffer != buffer) { + } else if (img.buffer != buffer) { ALOGE("got wrong image back for shared swapchain"); swapchain_result = WorstPresentResult(swapchain_result, VK_ERROR_SURFACE_LOST_KHR); - } - else { + } else { img.dequeue_fence = fence_fd; img.dequeued = true; } @@ -1747,7 +1737,7 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { int window_transform_hint; err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &window_transform_hint); - if (err != 0) { + if (err != android::OK) { ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", strerror(-err), err); swapchain_result = WorstPresentResult( -- GitLab From d174e386ee55f629244fba35dcb62c44b29266f0 Mon Sep 17 00:00:00 2001 From: Iris Chang Date: Wed, 4 Dec 2019 15:34:18 +0800 Subject: [PATCH 0568/1255] libui: print more fence information when fence is timeout The original log is not enough when fence is timeout. It only print the log name and fd. It is useless to help us to check which sync point is abnormal. Then it cause this fence can not be signaled. Therefore we print more detail when fence is timeout. Bug: 146024475 Test: call sleep function in SurfaceFlinger. Then check the fence log Change-Id: I2e711bfe8f00d7723c2d8e4184e0da5e69c8fc4d --- libs/ui/Fence.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp index 4ce891e148..33ab7c470e 100644 --- a/libs/ui/Fence.cpp +++ b/libs/ui/Fence.cpp @@ -62,8 +62,26 @@ status_t Fence::waitForever(const char* logname) { int warningTimeout = 3000; int err = sync_wait(mFenceFd, warningTimeout); if (err < 0 && errno == ETIME) { - ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd.get(), - warningTimeout); + ALOGE("waitForever: %s: fence %d didn't signal in %u ms", logname, mFenceFd.get(), + warningTimeout); + + struct sync_file_info* finfo = sync_file_info(mFenceFd); + if (finfo) { + // status: active(0) signaled(1) error(<0) + ALOGI("waitForever: fence(%s) status(%d)", finfo->name, finfo->status); + + struct sync_fence_info* pinfo = sync_get_fence_info(finfo); + for (uint32_t i = 0; i < finfo->num_fences; i++) { + uint64_t ts_sec = pinfo[i].timestamp_ns / 1000000000LL; + uint64_t ts_usec = (pinfo[i].timestamp_ns % 1000000000LL) / 1000LL; + + ALOGI("waitForever: sync point: timeline(%s) drv(%s) status(%d) timestamp(%" PRIu64 + ".%06" PRIu64 ")", + pinfo[i].obj_name, pinfo[i].driver_name, pinfo[i].status, ts_sec, ts_usec); + } + sync_file_info_free(finfo); + } + err = sync_wait(mFenceFd, TIMEOUT_NEVER); } return err < 0 ? -errno : status_t(NO_ERROR); -- GitLab From 6643cd81ed63d04662bfded60df1eeb11dcf248c Mon Sep 17 00:00:00 2001 From: Rashed Abdel-Tawab Date: Tue, 29 Oct 2019 10:01:56 -0700 Subject: [PATCH 0569/1255] CompositionEngine: fix HWC transform calculation Use the correct display transform in calculateOutputRelativeBufferTransform(). When SF_PRIMARY_DISPLAY_ORIENTATION is set, DisplayDevice only updates the logical to physical transform; OutputCompositionState.orientation doesn't change. Test: - OutputLayerTest.displayInstallOrientationBufferTransformSetTo90 - Run "dumpsys SurfaceFlinger" on a device with SF_PRIMARY_DISPLAY_ORIENTATION set to 90 and verify that the HWC transform is 0 (identity) - screencap Change-Id: I079b5ea22de8d47a7fb7233d01decfbd4b578be8 --- .../CompositionEngine/src/OutputLayer.cpp | 2 +- .../CompositionEngine/tests/OutputLayerTest.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index ce0222cee5..82d24222f1 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -231,7 +231,7 @@ uint32_t OutputLayer::calculateOutputRelativeBufferTransform() const { * (NOTE: the matrices are multiplied in reverse order) */ const ui::Transform& layerTransform = layerState.geomLayerTransform; - const ui::Transform displayTransform{outputState.orientation}; + const ui::Transform displayTransform{outputState.transform}; const ui::Transform bufferTransform{layerState.geomBufferTransform}; ui::Transform transform(displayTransform * layerTransform * bufferTransform); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 2e030a1823..0e579fa7e1 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -364,6 +364,7 @@ TEST_F(OutputLayerTest, calculateOutputRelativeBufferTransformTestsNeeded) { mLayerFEState.geomLayerTransform.set(entry.layer, 1920, 1080); mLayerFEState.geomBufferTransform = entry.buffer; mOutputState.orientation = entry.display; + mOutputState.transform = ui::Transform{entry.display}; auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(); EXPECT_EQ(entry.expected, actual) << "entry " << i; @@ -422,6 +423,7 @@ TEST_F(OutputLayerTest, mLayerFEState.geomLayerTransform = ui::Transform{entry.layer}; mLayerFEState.geomBufferTransform = entry.buffer; mOutputState.orientation = entry.display; + mOutputState.transform = ui::Transform{entry.display}; auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(); EXPECT_EQ(entry.expected, actual) << "entry " << i; @@ -764,6 +766,21 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) { mOutputLayer.writeStateToHWC(true); } +TEST_F(OutputLayerTest, displayInstallOrientationBufferTransformSetTo90) { + mLayerFEState.geomBufferUsesDisplayInverseTransform = false; + mLayerFEState.geomLayerTransform = ui::Transform{TR_IDENT}; + // This test simulates a scenario where displayInstallOrientation is set to + // ROT_90. This only has an effect on the transform; orientation stays 0 (see + // DisplayDevice::setProjection). + mOutputState.orientation = TR_IDENT; + mOutputState.transform = ui::Transform{TR_ROT_90}; + // Buffers are pre-rotated based on the transform hint (ROT_90); their + // geomBufferTransform is set to the inverse transform. + mLayerFEState.geomBufferTransform = TR_ROT_270; + + EXPECT_EQ(TR_IDENT, mOutputLayer.calculateOutputRelativeBufferTransform()); +} + TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) { mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; -- GitLab From 90e95d740b116a26679a5563c9f52bbf19766228 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Thu, 19 Dec 2019 16:10:44 -0800 Subject: [PATCH 0570/1255] Add Reboot Escrow feature flag This indicates that the device supports the RebootEscrow HAL for OTA systems to reboot a device while unattended to apply an update. Bug: 63928581 Test: make Change-Id: Ida7f4ee11848a9dfd7deca8501c1fb7d880f6199 --- data/etc/android.hardware.reboot_escrow.xml | 24 +++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 data/etc/android.hardware.reboot_escrow.xml diff --git a/data/etc/android.hardware.reboot_escrow.xml b/data/etc/android.hardware.reboot_escrow.xml new file mode 100644 index 0000000000..5db9f4c3ce --- /dev/null +++ b/data/etc/android.hardware.reboot_escrow.xml @@ -0,0 +1,24 @@ + + + + + + + + -- GitLab From 9e16a485b39a9e39191666d56d7d847ee801830f Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 3 Dec 2019 17:19:41 -0800 Subject: [PATCH 0571/1255] SurfaceFlinger: introduce PhaseOffsetsAsDurations Currently we define phase offset for each refresh rate. This works for <= 2 refresh rates, but doesn't scale well. This change is introducing a new way to calculate phase offsets, which is based on duration. Then, based on the duration and refresh rate, a phase offset is calculated. The calculation is captured here: https://docs.google.com/spreadsheets/d/1a_5cVNY3LUAkeg-yL56rYQNwved6Hy-dvEcKSxp6f8k/edit#gid=0 Bug: 145561086 Bug: 141329414 Test: jank tests Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Change-Id: I16aaf7437d30c4b12f955bdaac36582dd100519f --- .../Scheduler/DispSyncSource.cpp | 10 +- .../surfaceflinger/Scheduler/DispSyncSource.h | 4 +- .../Scheduler/InjectVSyncSource.h | 1 - .../surfaceflinger/Scheduler/PhaseOffsets.cpp | 276 +++++++++++++++--- .../surfaceflinger/Scheduler/PhaseOffsets.h | 80 ++++- .../surfaceflinger/Scheduler/Scheduler.cpp | 12 +- services/surfaceflinger/Scheduler/Scheduler.h | 4 +- .../surfaceflinger/Scheduler/VSyncModulator.h | 10 +- services/surfaceflinger/SurfaceFlinger.cpp | 54 ++-- services/surfaceflinger/SurfaceFlinger.h | 2 +- .../SurfaceFlingerDefaultFactory.cpp | 10 +- .../SurfaceFlingerDefaultFactory.h | 3 +- .../surfaceflinger/SurfaceFlingerFactory.h | 5 +- .../surfaceflinger/tests/unittests/Android.bp | 1 + .../tests/unittests/DispSyncSourceTest.cpp | 4 +- .../tests/unittests/FakePhaseOffsets.h | 5 +- .../tests/unittests/PhaseOffsetsTest.cpp | 126 ++++++++ .../tests/unittests/TestableSurfaceFlinger.h | 7 +- 18 files changed, 492 insertions(+), 122 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 571c9ca362..bd4b0ec0d1 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -27,16 +27,14 @@ namespace android { -DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, - nsecs_t offsetThresholdForNextVsync, bool traceVsync, +DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name) : mName(name), mValue(base::StringPrintf("VSYNC-%s", name), 0), mTraceVsync(traceVsync), mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)), mDispSync(dispSync), - mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset), - mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {} + mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset) {} void DispSyncSource::setVSyncEnabled(bool enable) { std::lock_guard lock(mVsyncMutex); @@ -67,10 +65,6 @@ void DispSyncSource::setCallback(VSyncSource::Callback* callback) { void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) { std::lock_guard lock(mVsyncMutex); const nsecs_t period = mDispSync->getPeriod(); - // Check if offset should be handled as negative - if (phaseOffset >= mOffsetThresholdForNextVsync) { - phaseOffset -= period; - } // Normalize phaseOffset to [-period, period) const int numPeriods = phaseOffset / period; diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h index 536464e8fb..328b8c176f 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.h +++ b/services/surfaceflinger/Scheduler/DispSyncSource.h @@ -26,8 +26,7 @@ namespace android { class DispSyncSource final : public VSyncSource, private DispSync::Callback { public: - DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, nsecs_t offsetThresholdForNextVsync, - bool traceVsync, const char* name); + DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name); ~DispSyncSource() override = default; @@ -55,7 +54,6 @@ private: std::mutex mVsyncMutex; TracedOrdinal mPhaseOffset GUARDED_BY(mVsyncMutex); - const nsecs_t mOffsetThresholdForNextVsync; bool mEnabled GUARDED_BY(mVsyncMutex) = false; }; diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h index 6c502e6d98..fa46e6f589 100644 --- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h +++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h @@ -45,7 +45,6 @@ public: const char* getName() const override { return "inject"; } void setVSyncEnabled(bool) override {} void setPhaseOffset(nsecs_t) override {} - void pauseVsyncCallback(bool) {} private: std::mutex mCallbackMutex; diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 12832a690a..4330742bf1 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -35,45 +35,48 @@ std::optional getProperty(const char* name) { namespace android::scheduler { -PhaseOffsets::~PhaseOffsets() = default; +PhaseConfiguration::~PhaseConfiguration() = default; namespace impl { -PhaseOffsets::PhaseOffsets() { - // Below defines the threshold when an offset is considered to be negative, i.e. targeting - // for the N+2 vsync instead of N+1. This means that: - // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync. - // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync. - const nsecs_t thresholdForNextVsync = - getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns") - .value_or(std::numeric_limits::max()); - - mDefaultOffsets = getDefaultOffsets(thresholdForNextVsync); - mHighFpsOffsets = getHighFpsOffsets(thresholdForNextVsync); -} - -PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(float fps) const { - // TODO(145561086): Once offsets are common for all refresh rates we can remove the magic - // number for refresh rate - if (fps > 65.0f) { - return mHighFpsOffsets; - } else { - return mDefaultOffsets; - } -} +PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs) + : // Below defines the threshold when an offset is considered to be negative, i.e. targeting + // for the N+2 vsync instead of N+1. This means that: + // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync. + // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync. + mThresholdForNextVsync(getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns") + .value_or(std::numeric_limits::max())), + mOffsets(initializeOffsets(refreshRateConfigs)), + mRefreshRateFps(refreshRateConfigs.getCurrentRefreshRate().fps) {} void PhaseOffsets::dump(std::string& result) const { - const auto [early, earlyGl, late, threshold] = getCurrentOffsets(); + const auto [early, earlyGl, late] = getCurrentOffsets(); using base::StringAppendF; StringAppendF(&result, " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n" " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n" " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n" "next VSYNC threshold: %9" PRId64 " ns\n", - late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf, threshold); + late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf, + mThresholdForNextVsync); +} + +std::unordered_map PhaseOffsets::initializeOffsets( + const scheduler::RefreshRateConfigs& refreshRateConfigs) const { + std::unordered_map offsets; + + for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) { + const nsecs_t vsyncDuration = static_cast(1e9f / refreshRate.fps); + if (refreshRate.fps > 65.0f) { + offsets.emplace(refreshRate.fps, getHighFpsOffsets(vsyncDuration)); + } else { + offsets.emplace(refreshRate.fps, getDefaultOffsets(vsyncDuration)); + } + } + return offsets; } -PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t thresholdForNextVsync) { +PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const { const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000); const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000); @@ -82,19 +85,32 @@ PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t thresholdForNextVs const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns"); const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns"); - return {{earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs), - earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs)}, + return { + { + earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync + ? earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) + : earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration, - {earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs), - earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs)}, + earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs), + }, + { + earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync + ? earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) + : earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration, - {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}, + earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs), + }, + { + sfVsyncPhaseOffsetNs < mThresholdForNextVsync + ? sfVsyncPhaseOffsetNs + : sfVsyncPhaseOffsetNs - vsyncDuration, - thresholdForNextVsync}; + vsyncPhaseOffsetNs, + }, + }; } -PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t thresholdForNextVsync) { - // TODO(b/122905996): Define these in device.mk. +PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const { const int highFpsLateAppOffsetNs = getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000); const int highFpsLateSfOffsetNs = @@ -106,15 +122,195 @@ PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t thresholdForNextVs const auto highFpsEarlyGlAppOffsetNs = getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"); - return {{highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs), - highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs)}, + return { + { + highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) < mThresholdForNextVsync + ? highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) + : highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) - + vsyncDuration, + + highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs), + }, + { + highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) < + mThresholdForNextVsync + ? highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) + : highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) - + vsyncDuration, + + highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs), + }, + { + highFpsLateSfOffsetNs < mThresholdForNextVsync + ? highFpsLateSfOffsetNs + : highFpsLateSfOffsetNs - vsyncDuration, + + highFpsLateAppOffsetNs, + }, + }; +} + +static void validateSysprops() { + const auto validatePropertyBool = [](const char* prop) { + LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop); + }; + + validatePropertyBool("debug.sf.use_phase_offsets_as_durations"); + + LOG_ALWAYS_FATAL_IF(sysprop::vsync_event_phase_offset_ns(-1) != -1, + "ro.surface_flinger.vsync_event_phase_offset_ns is set but expecting " + "duration"); + + LOG_ALWAYS_FATAL_IF(sysprop::vsync_sf_event_phase_offset_ns(-1) != -1, + "ro.surface_flinger.vsync_sf_event_phase_offset_ns is set but expecting " + "duration"); + + const auto validateProperty = [](const char* prop) { + LOG_ALWAYS_FATAL_IF(getProperty(prop).has_value(), + "%s is set to %" PRId64 " but expecting duration", prop, + getProperty(prop).value_or(-1)); + }; + + validateProperty("debug.sf.early_phase_offset_ns"); + validateProperty("debug.sf.early_gl_phase_offset_ns"); + validateProperty("debug.sf.early_app_phase_offset_ns"); + validateProperty("debug.sf.early_gl_app_phase_offset_ns"); + validateProperty("debug.sf.high_fps_late_app_phase_offset_ns"); + validateProperty("debug.sf.high_fps_late_sf_phase_offset_ns"); + validateProperty("debug.sf.high_fps_early_phase_offset_ns"); + validateProperty("debug.sf.high_fps_early_gl_phase_offset_ns"); + validateProperty("debug.sf.high_fps_early_app_phase_offset_ns"); + validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"); +} + +static nsecs_t sfDurationToOffset(nsecs_t sfDuration, nsecs_t vsyncDuration) { + return sfDuration == -1 ? 1'000'000 : vsyncDuration - sfDuration % vsyncDuration; +} + +static nsecs_t appDurationToOffset(nsecs_t appDuration, nsecs_t sfDuration, nsecs_t vsyncDuration) { + return sfDuration == -1 ? 1'000'000 + : vsyncDuration - (appDuration + sfDuration) % vsyncDuration; +} + +static std::vector getRefreshRatesFromConfigs( + const android::scheduler::RefreshRateConfigs& refreshRateConfigs) { + const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates(); + std::vector refreshRates; + refreshRates.reserve(allRefreshRates.size()); + + for (const auto& [ignored, refreshRate] : allRefreshRates) { + refreshRates.emplace_back(refreshRate.fps); + } + + return refreshRates; +} + +std::unordered_map PhaseDurations::initializeOffsets( + const std::vector& refreshRates) const { + std::unordered_map offsets; + + for (const auto fps : refreshRates) { + const nsecs_t vsyncDuration = static_cast(1e9f / fps); + offsets.emplace(fps, + Offsets{ + { + mSfEarlyDuration < vsyncDuration + ? sfDurationToOffset(mSfEarlyDuration, + vsyncDuration) + : sfDurationToOffset(mSfEarlyDuration, + vsyncDuration) - + vsyncDuration, + + appDurationToOffset(mAppEarlyDuration, mSfEarlyDuration, + vsyncDuration), + }, + { + mSfEarlyGlDuration < vsyncDuration + ? sfDurationToOffset(mSfEarlyGlDuration, + vsyncDuration) + : sfDurationToOffset(mSfEarlyGlDuration, + vsyncDuration) - + vsyncDuration, + + appDurationToOffset(mAppEarlyGlDuration, mSfEarlyGlDuration, + vsyncDuration), + }, + { + mSfDuration < vsyncDuration + ? sfDurationToOffset(mSfDuration, vsyncDuration) + : sfDurationToOffset(mSfDuration, vsyncDuration) - + vsyncDuration, + + appDurationToOffset(mAppDuration, mSfDuration, + vsyncDuration), + }, + }); + } + return offsets; +} + +PhaseDurations::PhaseDurations(const scheduler::RefreshRateConfigs& refreshRateConfigs) + : PhaseDurations(getRefreshRatesFromConfigs(refreshRateConfigs), + refreshRateConfigs.getCurrentRefreshRate().fps, + getProperty("debug.sf.late.sf.duration").value_or(-1), + getProperty("debug.sf.late.app.duration").value_or(-1), + getProperty("debug.sf.early.sf.duration").value_or(mSfDuration), + getProperty("debug.sf.early.app.duration").value_or(mAppDuration), + getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration), + getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) { + validateSysprops(); +} + +PhaseDurations::PhaseDurations(const std::vector& refreshRates, float currentFps, + nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration, + nsecs_t appEarlyDuration, nsecs_t sfEarlyGlDuration, + nsecs_t appEarlyGlDuration) + : mSfDuration(sfDuration), + mAppDuration(appDuration), + mSfEarlyDuration(sfEarlyDuration), + mAppEarlyDuration(appEarlyDuration), + mSfEarlyGlDuration(sfEarlyGlDuration), + mAppEarlyGlDuration(appEarlyGlDuration), + mOffsets(initializeOffsets(refreshRates)), + mRefreshRateFps(currentFps) {} + +PhaseOffsets::Offsets PhaseDurations::getOffsetsForRefreshRate(float fps) const { + const auto iter = mOffsets.find(fps); + LOG_ALWAYS_FATAL_IF(iter == mOffsets.end()); + return iter->second; +} + +void PhaseDurations::dump(std::string& result) const { + const auto [early, earlyGl, late] = getCurrentOffsets(); + using base::StringAppendF; + StringAppendF(&result, + " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 + " ns\n" + " app duration: %9" PRId64 " ns\t SF duration: %9" PRId64 + " ns\n" + " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 + " ns\n" + " early app duration: %9" PRId64 " ns\t early SF duration: %9" PRId64 + " ns\n" + " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 + " ns\n" + " GL early app duration: %9" PRId64 " ns\tGL early SF duration: %9" PRId64 + " ns\n", + late.app, + + late.sf, + + mAppDuration, mSfDuration, + + early.app, early.sf, + + mAppEarlyDuration, mSfEarlyDuration, - {highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs), - highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs)}, + earlyGl.app, - {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}, + earlyGl.sf, - thresholdForNextVsync}; + mAppEarlyGlDuration, mSfEarlyGlDuration); } } // namespace impl diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h index 7747f0cfcc..c10efdee21 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.h +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h @@ -29,17 +29,11 @@ namespace android::scheduler { * different offsets will help us with latency. This class keeps track of * which mode the device is on, and returns approprate offsets when needed. */ -class PhaseOffsets { +class PhaseConfiguration { public: using Offsets = VSyncModulator::OffsetsConfig; - virtual ~PhaseOffsets(); - - nsecs_t getCurrentAppOffset() const { return getCurrentOffsets().late.app; } - nsecs_t getCurrentSfOffset() const { return getCurrentOffsets().late.sf; } - nsecs_t getOffsetThresholdForNextVsync() const { - return getCurrentOffsets().thresholdForNextVsync; - } + virtual ~PhaseConfiguration(); virtual Offsets getCurrentOffsets() const = 0; virtual Offsets getOffsetsForRefreshRate(float fps) const = 0; @@ -51,9 +45,51 @@ public: namespace impl { -class PhaseOffsets : public scheduler::PhaseOffsets { +/* + * This is the old implementation of phase offsets and considered as deprecated. + * PhaseDurations is the new implementation. + */ +class PhaseOffsets : public scheduler::PhaseConfiguration { +public: + PhaseOffsets(const scheduler::RefreshRateConfigs&); + + // Returns early, early GL, and late offsets for Apps and SF for a given refresh rate. + Offsets getOffsetsForRefreshRate(float fps) const override { + const auto iter = mOffsets.find(fps); + LOG_ALWAYS_FATAL_IF(iter == mOffsets.end()); + return iter->second; + } + + // Returns early, early GL, and late offsets for Apps and SF. + Offsets getCurrentOffsets() const override { return getOffsetsForRefreshRate(mRefreshRateFps); } + + // This function should be called when the device is switching between different + // refresh rates, to properly update the offsets. + void setRefreshRateFps(float fps) override { mRefreshRateFps = fps; } + + // Returns current offsets in human friendly format. + void dump(std::string& result) const override; + +private: + std::unordered_map initializeOffsets( + const scheduler::RefreshRateConfigs&) const; + Offsets getDefaultOffsets(nsecs_t vsyncDuration) const; + Offsets getHighFpsOffsets(nsecs_t vsyncDuration) const; + + const nsecs_t mThresholdForNextVsync; + const std::unordered_map mOffsets; + + std::atomic mRefreshRateFps; +}; + +/* + * Class that encapsulates the phase offsets for SurfaceFlinger and App. + * The offsets are calculated from durations for each one of the (late, early, earlyGL) + * offset types. + */ +class PhaseDurations : public scheduler::PhaseConfiguration { public: - PhaseOffsets(); + PhaseDurations(const scheduler::RefreshRateConfigs&); // Returns early, early GL, and late offsets for Apps and SF for a given refresh rate. Offsets getOffsetsForRefreshRate(float fps) const override; @@ -68,14 +104,28 @@ public: // Returns current offsets in human friendly format. void dump(std::string& result) const override; +protected: + // Used for unit tests + PhaseDurations(const std::vector& refreshRates, float currentFps, nsecs_t sfDuration, + nsecs_t appDuration, nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration, + nsecs_t sfEarlyGlDuration, nsecs_t appEarlyGlDuration); + private: - static Offsets getDefaultOffsets(nsecs_t thresholdForNextVsync); - static Offsets getHighFpsOffsets(nsecs_t thresholdForNextVsync); + std::unordered_map initializeOffsets( + const std::vector&) const; + + const nsecs_t mSfDuration; + const nsecs_t mAppDuration; + + const nsecs_t mSfEarlyDuration; + const nsecs_t mAppEarlyDuration; + + const nsecs_t mSfEarlyGlDuration; + const nsecs_t mAppEarlyGlDuration; - std::atomic mRefreshRateFps = 0; + const std::unordered_map mOffsets; - Offsets mDefaultOffsets; - Offsets mHighFpsOffsets; + std::atomic mRefreshRateFps; }; } // namespace impl diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 71a6a2f066..71ebfc39e0 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -125,18 +125,16 @@ DispSync& Scheduler::getPrimaryDispSync() { return *mPrimaryDispSync; } -std::unique_ptr Scheduler::makePrimaryDispSyncSource( - const char* name, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync) { +std::unique_ptr Scheduler::makePrimaryDispSyncSource(const char* name, + nsecs_t phaseOffsetNs) { return std::make_unique(mPrimaryDispSync.get(), phaseOffsetNs, - offsetThresholdForNextVsync, true /* traceVsync */, - name); + true /* traceVsync */, name); } Scheduler::ConnectionHandle Scheduler::createConnection( - const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync, + const char* connectionName, nsecs_t phaseOffsetNs, impl::EventThread::InterceptVSyncsCallback interceptCallback) { - auto vsyncSource = - makePrimaryDispSyncSource(connectionName, phaseOffsetNs, offsetThresholdForNextVsync); + auto vsyncSource = makePrimaryDispSyncSource(connectionName, phaseOffsetNs); auto eventThread = std::make_unique(std::move(vsyncSource), std::move(interceptCallback)); return createConnection(std::move(eventThread)); diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 15277ceb56..2fa8b3f548 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -66,7 +66,6 @@ public: using ConnectionHandle = scheduler::ConnectionHandle; ConnectionHandle createConnection(const char* connectionName, nsecs_t phaseOffsetNs, - nsecs_t offsetThresholdForNextVsync, impl::EventThread::InterceptVSyncsCallback); sp createDisplayEventConnection(ConnectionHandle, @@ -149,8 +148,7 @@ private: Scheduler(std::unique_ptr, std::unique_ptr, const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback); - std::unique_ptr makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs, - nsecs_t offsetThresholdForNextVsync); + std::unique_ptr makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs); // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr); diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 63c0feb9cc..704a5d5626 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -43,6 +43,10 @@ public: struct Offsets { nsecs_t sf; nsecs_t app; + + bool operator==(const Offsets& other) const { return sf == other.sf && app == other.app; } + + bool operator!=(const Offsets& other) const { return !(*this == other); } }; struct OffsetsConfig { @@ -50,7 +54,11 @@ public: Offsets earlyGl; // As above but while compositing with GL. Offsets late; // Default. - nsecs_t thresholdForNextVsync; + bool operator==(const OffsetsConfig& other) const { + return early == other.early && earlyGl == other.earlyGl && late == other.late; + } + + bool operator!=(const OffsetsConfig& other) const { return !(*this == other); } }; VSyncModulator(Scheduler&, ConnectionHandle appConnectionHandle, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3403b280f0..dddd552585 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -260,7 +260,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) mFrameTracer(std::make_unique()), mEventQueue(mFactory.createMessageQueue()), mCompositionEngine(mFactory.createCompositionEngine()), - mPhaseOffsets(mFactory.createPhaseOffsets()), mPendingSyncInputWindows(false) {} SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) { @@ -582,8 +581,6 @@ void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { void SurfaceFlinger::init() { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); - ALOGI("Phase offset: %" PRId64 " ns", mPhaseOffsets->getCurrentAppOffset()); - Mutex::Autolock _l(mStateLock); // Get a RenderEngine for the given display / config (can't fail) @@ -816,7 +813,7 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, info.ydpi = ydpi; info.fps = 1e9 / hwConfig->getVsyncPeriod(); - const auto offset = mPhaseOffsets->getOffsetsForRefreshRate(info.fps); + const auto offset = mPhaseConfiguration->getOffsetsForRefreshRate(info.fps); info.appVsyncOffset = offset.late.app; // This is how far in advance a buffer must be queued for @@ -896,8 +893,8 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { // DispSync model is locked. mVSyncModulator->onRefreshRateChangeInitiated(); - mPhaseOffsets->setRefreshRateFps(refreshRate.fps); - mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets()); + mPhaseConfiguration->setRefreshRateFps(refreshRate.fps); + mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets()); } mDesiredActiveConfigChanged = true; @@ -930,8 +927,8 @@ void SurfaceFlinger::setActiveConfigInternal() { auto refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId); - mPhaseOffsets->setRefreshRateFps(refreshRate.fps); - mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets()); + mPhaseConfiguration->setRefreshRateFps(refreshRate.fps); + mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets()); ATRACE_INT("ActiveConfigFPS", refreshRate.fps); if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) { @@ -948,8 +945,8 @@ void SurfaceFlinger::desiredActiveConfigChangeDone() { mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); auto refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(mDesiredActiveConfig.configId); - mPhaseOffsets->setRefreshRateFps(refreshRate.fps); - mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets()); + mPhaseConfiguration->setRefreshRateFps(refreshRate.fps); + mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets()); } bool SurfaceFlinger::performSetActiveConfig() { @@ -1597,10 +1594,8 @@ bool SurfaceFlinger::previousFrameMissed(int graceTimeMs) NO_THREAD_SAFETY_ANALY // We are storing the last 2 present fences. If sf's phase offset is to be // woken up before the actual vsync but targeting the next vsync, we need to check // fence N-2 - const sp& fence = - mVSyncModulator->getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync() - ? mPreviousPresentFences[0] - : mPreviousPresentFences[1]; + const sp& fence = mVSyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0] + : mPreviousPresentFences[1]; if (fence == Fence::NO_FENCE) { return false; @@ -1618,10 +1613,8 @@ void SurfaceFlinger::populateExpectedPresentTime() { mScheduler->getDisplayStatInfo(&stats); const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(); // Inflate the expected present time if we're targetting the next vsync. - mExpectedPresentTime.store(mVSyncModulator->getOffsets().sf < - mPhaseOffsets->getOffsetThresholdForNextVsync() - ? presentTime - : presentTime + stats.vsyncPeriod); + mExpectedPresentTime.store( + mVSyncModulator->getOffsets().sf > 0 ? presentTime : presentTime + stats.vsyncPeriod); } void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { @@ -1865,11 +1858,12 @@ void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats, nsecs_t compositeToPresentLatency) { // Integer division and modulo round toward 0 not -inf, so we need to // treat negative and positive offsets differently. - nsecs_t idealLatency = (mPhaseOffsets->getCurrentSfOffset() > 0) - ? (stats.vsyncPeriod - (mPhaseOffsets->getCurrentSfOffset() % stats.vsyncPeriod)) - : ((-mPhaseOffsets->getCurrentSfOffset()) % stats.vsyncPeriod); + nsecs_t idealLatency = (mPhaseConfiguration->getCurrentOffsets().late.sf > 0) + ? (stats.vsyncPeriod - + (mPhaseConfiguration->getCurrentOffsets().late.sf % stats.vsyncPeriod)) + : ((-mPhaseConfiguration->getCurrentOffsets().late.sf) % stats.vsyncPeriod); - // Just in case mPhaseOffsets->getCurrentSfOffset() == -vsyncInterval. + // Just in case mPhaseConfiguration->getCurrentOffsets().late.sf == -vsyncInterval. if (idealLatency <= 0) { idealLatency = stats.vsyncPeriod; } @@ -1878,8 +1872,8 @@ void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats, // composition and present times, which often have >1ms of jitter. // Reducing jitter is important if an app attempts to extrapolate // something (such as user input) to an accurate diasplay time. - // Snapping also allows an app to precisely calculate mPhaseOffsets->getCurrentSfOffset() - // with (presentLatency % interval). + // Snapping also allows an app to precisely calculate + // mPhaseConfiguration->getCurrentOffsets().late.sf with (presentLatency % interval). nsecs_t bias = stats.vsyncPeriod / 2; int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod; nsecs_t snappedCompositeToPresentLatency = @@ -2570,24 +2564,24 @@ void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { currentConfig, HWC_POWER_MODE_OFF); mRefreshRateStats->setConfigMode(currentConfig); + mPhaseConfiguration = getFactory().createPhaseConfiguration(*mRefreshRateConfigs); + // start the EventThread mScheduler = getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); }, *mRefreshRateConfigs, *this); mAppConnectionHandle = - mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(), - mPhaseOffsets->getOffsetThresholdForNextVsync(), + mScheduler->createConnection("app", mPhaseConfiguration->getCurrentOffsets().late.app, impl::EventThread::InterceptVSyncsCallback()); mSfConnectionHandle = - mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(), - mPhaseOffsets->getOffsetThresholdForNextVsync(), + mScheduler->createConnection("sf", mPhaseConfiguration->getCurrentOffsets().late.sf, [this](nsecs_t timestamp) { mInterceptor->saveVSyncEvent(timestamp); }); mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle)); mVSyncModulator.emplace(*mScheduler, mAppConnectionHandle, mSfConnectionHandle, - mPhaseOffsets->getCurrentOffsets()); + mPhaseConfiguration->getCurrentOffsets()); mRegionSamplingThread = new RegionSamplingThread(*this, *mScheduler, @@ -3985,7 +3979,7 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { mRefreshRateStats->dump(result); result.append("\n"); - mPhaseOffsets->dump(result); + mPhaseConfiguration->dump(result); StringAppendF(&result, " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n", dispSyncPresentTimeOffset, getVsyncPeriod()); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b5bc5c5d0b..a470924e7b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1106,7 +1106,7 @@ private: scheduler::ConnectionHandle mSfConnectionHandle; // Stores phase offsets configured per refresh rate. - const std::unique_ptr mPhaseOffsets; + std::unique_ptr mPhaseConfiguration; // Optional to defer construction until scheduler connections are created. std::optional mVSyncModulator; diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index bd4cdbad45..375730b26f 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include "BufferLayerConsumer.h" @@ -59,8 +60,13 @@ std::unique_ptr DefaultFactory::createMessageQueue() { return std::make_unique(); } -std::unique_ptr DefaultFactory::createPhaseOffsets() { - return std::make_unique(); +std::unique_ptr DefaultFactory::createPhaseConfiguration( + const scheduler::RefreshRateConfigs& refreshRateConfigs) { + if (property_get_bool("debug.sf.use_phase_offsets_as_durations", false)) { + return std::make_unique(refreshRateConfigs); + } else { + return std::make_unique(refreshRateConfigs); + } } std::unique_ptr DefaultFactory::createScheduler( diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h index 1a244486fa..36fae217ce 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h @@ -30,7 +30,8 @@ public: std::unique_ptr createEventControlThread(SetVSyncEnabled) override; std::unique_ptr createHWComposer(const std::string& serviceName) override; std::unique_ptr createMessageQueue() override; - std::unique_ptr createPhaseOffsets() override; + std::unique_ptr createPhaseConfiguration( + const scheduler::RefreshRateConfigs&) override; std::unique_ptr createScheduler(SetVSyncEnabled, const scheduler::RefreshRateConfigs&, ISchedulerCallback&) override; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index 0db941d419..951bd09293 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -56,7 +56,7 @@ class CompositionEngine; } // namespace compositionengine namespace scheduler { -class PhaseOffsets; +class PhaseConfiguration; class RefreshRateConfigs; } // namespace scheduler @@ -74,7 +74,8 @@ public: virtual std::unique_ptr createEventControlThread(SetVSyncEnabled) = 0; virtual std::unique_ptr createHWComposer(const std::string& serviceName) = 0; virtual std::unique_ptr createMessageQueue() = 0; - virtual std::unique_ptr createPhaseOffsets() = 0; + virtual std::unique_ptr createPhaseConfiguration( + const scheduler::RefreshRateConfigs&) = 0; virtual std::unique_ptr createScheduler(SetVSyncEnabled, const scheduler::RefreshRateConfigs&, ISchedulerCallback&) = 0; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 0c4a752689..a950c76228 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -45,6 +45,7 @@ cc_test { "OneShotTimerTest.cpp", "LayerHistoryTest.cpp", "LayerMetadataTest.cpp", + "PhaseOffsetsTest.cpp", "SchedulerTest.cpp", "SchedulerUtilsTest.cpp", "RefreshRateConfigsTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp index 0aa8cf565d..2e705dad6d 100644 --- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp +++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp @@ -51,7 +51,6 @@ protected: AsyncCallRecorder mVSyncEventCallRecorder; static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms; - static constexpr std::chrono::nanoseconds mOffsetThresholdForNextVsync = 16ms; static constexpr int mIterations = 100; }; @@ -79,8 +78,7 @@ void DispSyncSourceTest::createDispSync() { void DispSyncSourceTest::createDispSyncSource() { createDispSync(); - mDispSyncSource = std::make_unique(mDispSync.get(), mPhaseOffset.count(), - mOffsetThresholdForNextVsync.count(), true, + mDispSyncSource = std::make_unique(mDispSync.get(), mPhaseOffset.count(), true, "DispSyncSourceTest"); mDispSyncSource->setCallback(this); } diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h index da4eea0221..b50ddf5b9a 100644 --- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h +++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h @@ -22,7 +22,7 @@ namespace android::scheduler { -struct FakePhaseOffsets : PhaseOffsets { +struct FakePhaseOffsets : PhaseConfiguration { static constexpr nsecs_t FAKE_PHASE_OFFSET_NS = 0; Offsets getOffsetsForRefreshRate(float) const override { return getCurrentOffsets(); } @@ -30,8 +30,7 @@ struct FakePhaseOffsets : PhaseOffsets { Offsets getCurrentOffsets() const override { return {{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - FAKE_PHASE_OFFSET_NS}; + {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}}; } void setRefreshRateFps(float) override {} diff --git a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp new file mode 100644 index 0000000000..6360ec14cd --- /dev/null +++ b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp @@ -0,0 +1,126 @@ +/* + * 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. + */ + +#undef LOG_TAG +#define LOG_TAG "SchedulerUnittests" + +#include +#include +#include + +#include "Scheduler/PhaseOffsets.h" + +using namespace testing; + +namespace android { +namespace scheduler { + +class TestablePhaseOffsetsAsDurations : public impl::PhaseDurations { +public: + TestablePhaseOffsetsAsDurations(float currentFps, nsecs_t sfDuration, nsecs_t appDuration, + nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration, + nsecs_t sfEarlyGlDuration, nsecs_t appEarlyGlDuration) + : impl::PhaseDurations({60.0f, 90.0f}, currentFps, sfDuration, appDuration, + sfEarlyDuration, appEarlyDuration, sfEarlyGlDuration, + appEarlyGlDuration) {} +}; + +class PhaseOffsetsTest : public testing::Test { +protected: + PhaseOffsetsTest() + : mPhaseOffsets(60.0f, 10'500'000, 20'500'000, 16'000'000, 33'500'000, 13'500'000, + 38'000'000) {} + + ~PhaseOffsetsTest() = default; + + TestablePhaseOffsetsAsDurations mPhaseOffsets; +}; + +namespace { +/* ------------------------------------------------------------------------ + * Test cases + */ +TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_60Hz) { + mPhaseOffsets.setRefreshRateFps(60.0f); + auto currentOffsets = mPhaseOffsets.getCurrentOffsets(); + auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(60.0f); + + EXPECT_EQ(currentOffsets, offsets); + EXPECT_EQ(offsets.late.sf, 6'166'667); + + EXPECT_EQ(offsets.late.app, 2'333'334); + + EXPECT_EQ(offsets.early.sf, 666'667); + + EXPECT_EQ(offsets.early.app, 500'001); + + EXPECT_EQ(offsets.earlyGl.sf, 3'166'667); + + EXPECT_EQ(offsets.earlyGl.app, 15'166'668); +} + +TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_90Hz) { + mPhaseOffsets.setRefreshRateFps(90.0f); + auto currentOffsets = mPhaseOffsets.getCurrentOffsets(); + auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(90.0f); + + EXPECT_EQ(currentOffsets, offsets); + EXPECT_EQ(offsets.late.sf, 611'111); + + EXPECT_EQ(offsets.late.app, 2'333'333); + + EXPECT_EQ(offsets.early.sf, -4'888'889); + + EXPECT_EQ(offsets.early.app, 6'055'555); + + EXPECT_EQ(offsets.earlyGl.sf, -2'388'889); + + EXPECT_EQ(offsets.earlyGl.app, 4'055'555); +} + +TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_DefaultOffsets) { + TestablePhaseOffsetsAsDurations phaseOffsetsWithDefaultValues(60.0f, -1, -1, -1, -1, -1, -1); + + auto validateOffsets = [](auto& offsets) { + EXPECT_EQ(offsets.late.sf, 1'000'000); + + EXPECT_EQ(offsets.late.app, 1'000'000); + + EXPECT_EQ(offsets.early.sf, 1'000'000); + + EXPECT_EQ(offsets.early.app, 1'000'000); + + EXPECT_EQ(offsets.earlyGl.sf, 1'000'000); + + EXPECT_EQ(offsets.earlyGl.app, 1'000'000); + }; + + phaseOffsetsWithDefaultValues.setRefreshRateFps(90.0f); + auto currentOffsets = phaseOffsetsWithDefaultValues.getCurrentOffsets(); + auto offsets = phaseOffsetsWithDefaultValues.getOffsetsForRefreshRate(90.0f); + EXPECT_EQ(currentOffsets, offsets); + validateOffsets(offsets); + + phaseOffsetsWithDefaultValues.setRefreshRateFps(60.0f); + currentOffsets = phaseOffsetsWithDefaultValues.getCurrentOffsets(); + offsets = phaseOffsetsWithDefaultValues.getOffsetsForRefreshRate(90.0f); + EXPECT_EQ(currentOffsets, offsets); + validateOffsets(offsets); +} + +} // namespace +} // namespace scheduler +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 8a7c13291b..c6c3147540 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -79,7 +79,8 @@ public: return std::make_unique(); } - std::unique_ptr createPhaseOffsets() override { + std::unique_ptr createPhaseConfiguration( + const scheduler::RefreshRateConfigs& /*refreshRateConfigs*/) override { return std::make_unique(); } @@ -203,6 +204,8 @@ public: scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, *mFlinger->mTimeStats, /*currentConfig=*/HwcConfigIndexType(0), /*powerMode=*/HWC_POWER_MODE_OFF); + mFlinger->mPhaseConfiguration = + mFactory.createPhaseConfiguration(*mFlinger->mRefreshRateConfigs); mScheduler = new TestableScheduler(std::move(primaryDispSync), std::move(eventControlThread), @@ -214,7 +217,7 @@ public: mFlinger->mVSyncModulator.emplace(*mScheduler, mFlinger->mAppConnectionHandle, mFlinger->mSfConnectionHandle, - mFlinger->mPhaseOffsets->getCurrentOffsets()); + mFlinger->mPhaseConfiguration->getCurrentOffsets()); } void resetScheduler(Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); } -- GitLab From d078476b466d15691f508593a54611103e42c26e Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 1 Nov 2019 15:33:48 -0700 Subject: [PATCH 0572/1255] Add benchmarks for InputDispatcher No logs are generated when these benchmarks are ran. Bug: none Test: atest inputflinger_benchmarks Change-Id: Ifce2518657b2f266f8e8ccfaabac1331ecdf7935 --- services/inputflinger/benchmarks/Android.bp | 22 ++ .../benchmarks/InputDispatcher_benchmarks.cpp | 314 ++++++++++++++++++ .../tests/InputDispatcher_test.cpp | 4 +- 3 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 services/inputflinger/benchmarks/Android.bp create mode 100644 services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp new file mode 100644 index 0000000000..385b9816bd --- /dev/null +++ b/services/inputflinger/benchmarks/Android.bp @@ -0,0 +1,22 @@ +cc_benchmark { + name: "inputflinger_benchmarks", + srcs: [ + "InputDispatcher_benchmarks.cpp", + ], + defaults: ["inputflinger_defaults"], + shared_libs: [ + "libbase", + "libbinder", + "libcutils", + "libinput", + "libinputflinger_base", + "libinputreporter", + "liblog", + "libstatslog", + "libui", + "libutils", + ], + static_libs: [ + "libinputdispatcher", + ], +} diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp new file mode 100644 index 0000000000..9686ceaf2f --- /dev/null +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -0,0 +1,314 @@ +/* + * Copyright (C) 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 + +#include +#include "../dispatcher/InputDispatcher.h" + +namespace android::inputdispatcher { + +// An arbitrary device id. +static const int32_t DEVICE_ID = 1; + +// An arbitrary injector pid / uid pair that has permission to inject events. +static const int32_t INJECTOR_PID = 999; +static const int32_t INJECTOR_UID = 1001; + +static const int32_t INJECT_EVENT_TIMEOUT = 5000; +static const int32_t DISPATCHING_TIMEOUT = 100000; + +static nsecs_t now() { + return systemTime(SYSTEM_TIME_MONOTONIC); +} + +// --- FakeInputDispatcherPolicy --- + +class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { +public: + FakeInputDispatcherPolicy() {} + +protected: + virtual ~FakeInputDispatcherPolicy() {} + +private: + virtual void notifyConfigurationChanged(nsecs_t) override {} + + virtual nsecs_t notifyANR(const sp&, const sp&, + const std::string& name) override { + ALOGE("The window is not responding : %s", name.c_str()); + return 0; + } + + virtual void notifyInputChannelBroken(const sp&) override {} + + virtual void notifyFocusChanged(const sp&, const sp&) override {} + + virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override { + *outConfig = mConfig; + } + + virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override { + return true; + } + + virtual void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) override {} + + virtual void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) override {} + + virtual nsecs_t interceptKeyBeforeDispatching(const sp&, const KeyEvent*, + uint32_t) override { + return 0; + } + + virtual bool dispatchUnhandledKey(const sp&, const KeyEvent*, uint32_t, + KeyEvent*) override { + return false; + } + + virtual void notifySwitch(nsecs_t, uint32_t, uint32_t, uint32_t) override {} + + virtual void pokeUserActivity(nsecs_t, int32_t) override {} + + virtual bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override { + return false; + } + + virtual void onPointerDownOutsideFocus(const sp& newToken) override {} + + InputDispatcherConfiguration mConfig; +}; + +class FakeApplicationHandle : public InputApplicationHandle { +public: + FakeApplicationHandle() {} + virtual ~FakeApplicationHandle() {} + + virtual bool updateInfo() { + mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; + return true; + } +}; + +class FakeInputReceiver { +public: + void consumeEvent() { + uint32_t consumeSeq; + InputEvent* event; + + status_t result = WOULD_BLOCK; + while (result == WOULD_BLOCK) { + result = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, + &event); + } + if (result != OK) { + ALOGE("Received result = %d from consume()", result); + } + result = mConsumer->sendFinishedSignal(consumeSeq, true); + if (result != OK) { + ALOGE("Received result = %d from sendFinishedSignal", result); + } + } + +protected: + explicit FakeInputReceiver(const sp& dispatcher, const std::string name) + : mDispatcher(dispatcher) { + InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel); + mConsumer = std::make_unique(mClientChannel); + } + + virtual ~FakeInputReceiver() {} + + sp mDispatcher; + sp mServerChannel, mClientChannel; + std::unique_ptr mConsumer; + PreallocatedInputEventFactory mEventFactory; +}; + +class FakeWindowHandle : public InputWindowHandle, public FakeInputReceiver { +public: + static const int32_t WIDTH = 200; + static const int32_t HEIGHT = 200; + + FakeWindowHandle(const sp& inputApplicationHandle, + const sp& dispatcher, const std::string name) + : FakeInputReceiver(dispatcher, name), mFrame(Rect(0, 0, WIDTH, HEIGHT)) { + mDispatcher->registerInputChannel(mServerChannel); + + inputApplicationHandle->updateInfo(); + mInfo.applicationInfo = *inputApplicationHandle->getInfo(); + } + + virtual bool updateInfo() override { + mInfo.token = mServerChannel->getConnectionToken(); + mInfo.name = "FakeWindowHandle"; + mInfo.layoutParamsFlags = 0; + mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION; + mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; + mInfo.frameLeft = mFrame.left; + mInfo.frameTop = mFrame.top; + mInfo.frameRight = mFrame.right; + mInfo.frameBottom = mFrame.bottom; + mInfo.globalScaleFactor = 1.0; + mInfo.touchableRegion.clear(); + mInfo.addTouchableRegion(mFrame); + mInfo.visible = true; + mInfo.canReceiveKeys = true; + mInfo.hasFocus = true; + mInfo.hasWallpaper = false; + mInfo.paused = false; + mInfo.layer = 0; + mInfo.ownerPid = INJECTOR_PID; + mInfo.ownerUid = INJECTOR_UID; + mInfo.inputFeatures = 0; + mInfo.displayId = ADISPLAY_ID_DEFAULT; + + return true; + } + +protected: + Rect mFrame; +}; + +static MotionEvent generateMotionEvent() { + PointerProperties pointerProperties[1]; + PointerCoords pointerCoords[1]; + + pointerProperties[0].clear(); + pointerProperties[0].id = 0; + pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + + pointerCoords[0].clear(); + pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100); + pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 100); + + const nsecs_t currentTime = now(); + + MotionEvent event; + event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0, + /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, + /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0, + /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, currentTime, + /*pointerCount*/ 1, pointerProperties, pointerCoords); + return event; +} + +static NotifyMotionArgs generateMotionArgs() { + PointerProperties pointerProperties[1]; + PointerCoords pointerCoords[1]; + + pointerProperties[0].clear(); + pointerProperties[0].id = 0; + pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + + pointerCoords[0].clear(); + pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100); + pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 100); + + const nsecs_t currentTime = now(); + // Define a valid motion event. + NotifyMotionArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, POLICY_FLAG_PASS_TO_USER, AMOTION_EVENT_ACTION_DOWN, + /* actionButton */ 0, /* flags */ 0, AMETA_NONE, /* buttonState */ 0, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, + pointerProperties, pointerCoords, + /* xPrecision */ 0, /* yPrecision */ 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /* videoFrames */ {}); + + return args; +} + +static void benchmarkNotifyMotion(benchmark::State& state) { + // Create dispatcher + sp fakePolicy = new FakeInputDispatcherPolicy(); + sp dispatcher = new InputDispatcher(fakePolicy); + dispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); + dispatcher->start(); + + // Create a window that will receive motion events + sp application = new FakeApplicationHandle(); + sp window = new FakeWindowHandle(application, dispatcher, "Fake Window"); + + dispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + + NotifyMotionArgs motionArgs = generateMotionArgs(); + + for (auto _ : state) { + // Send ACTION_DOWN + motionArgs.action = AMOTION_EVENT_ACTION_DOWN; + motionArgs.sequenceNum = 0; + motionArgs.downTime = now(); + motionArgs.eventTime = motionArgs.downTime; + dispatcher->notifyMotion(&motionArgs); + + // Send ACTION_UP + motionArgs.action = AMOTION_EVENT_ACTION_UP; + motionArgs.sequenceNum = 1; + motionArgs.eventTime = now(); + dispatcher->notifyMotion(&motionArgs); + + window->consumeEvent(); + window->consumeEvent(); + } + + dispatcher->stop(); +} + +static void benchmarkInjectMotion(benchmark::State& state) { + // Create dispatcher + sp fakePolicy = new FakeInputDispatcherPolicy(); + sp dispatcher = new InputDispatcher(fakePolicy); + dispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); + dispatcher->start(); + + // Create a window that will receive motion events + sp application = new FakeApplicationHandle(); + sp window = new FakeWindowHandle(application, dispatcher, "Fake Window"); + + dispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + + MotionEvent event = generateMotionEvent(); + + for (auto _ : state) { + // Send ACTION_DOWN + event.setAction(AMOTION_EVENT_ACTION_DOWN); + event.setDownTime(now()); + dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, INJECT_EVENT_TIMEOUT, + POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); + + // Send ACTION_UP + event.setAction(AMOTION_EVENT_ACTION_UP); + dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, INJECT_EVENT_TIMEOUT, + POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); + + window->consumeEvent(); + window->consumeEvent(); + } + + dispatcher->stop(); +} + +BENCHMARK(benchmarkNotifyMotion); +BENCHMARK(benchmarkInjectMotion); + +} // namespace android::inputdispatcher + +BENCHMARK_MAIN(); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 994010ba0e..b7f7ac56e5 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -505,7 +505,7 @@ protected: const std::string name, int32_t displayId) : mDispatcher(dispatcher), mName(name), mDisplayId(displayId) { InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel); - mConsumer = new InputConsumer(mClientChannel); + mConsumer = std::make_unique(mClientChannel); } virtual ~FakeInputReceiver() { @@ -518,7 +518,7 @@ protected: sp mDispatcher; sp mServerChannel, mClientChannel; - InputConsumer *mConsumer; + std::unique_ptr mConsumer; PreallocatedInputEventFactory mEventFactory; std::string mName; -- GitLab From 85d423a79e6a8c5f8f6214339d837c05d860f1c0 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Sun, 15 Dec 2019 13:42:02 -0800 Subject: [PATCH 0573/1255] gralloc: test libgralloctypes without running VTS Bug: 141632767 Test: GrallocTypes_test Change-Id: I81ac8c589c2841e002291360d24b551c69af9f11 --- libs/gralloc/types/Android.bp | 1 + libs/gralloc/types/Gralloc4.cpp | 11 +- .../types/include/gralloctypes/Gralloc4.h | 180 +++++++ libs/gralloc/types/tests/Android.bp | 25 + libs/gralloc/types/tests/Gralloc4_test.cpp | 465 ++++++++++++++++++ 5 files changed, 678 insertions(+), 4 deletions(-) create mode 100644 libs/gralloc/types/tests/Android.bp create mode 100644 libs/gralloc/types/tests/Gralloc4_test.cpp diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp index cb5305f58c..e1693cf672 100644 --- a/libs/gralloc/types/Android.bp +++ b/libs/gralloc/types/Android.bp @@ -41,6 +41,7 @@ cc_library { export_shared_lib_headers: [ "android.hardware.graphics.mapper@4.0", + "libhidlbase", "vintf-graphics-common-ndk_platform", ], diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp index d02e839b78..20050dc81f 100644 --- a/libs/gralloc/types/Gralloc4.cpp +++ b/libs/gralloc/types/Gralloc4.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "libgralloctypes" + #include #include #include @@ -797,10 +799,6 @@ status_t decodeCta861_3Helper(InputHidlVec* inputHidlVec, Cta861_3* outCta861_3) /** * Public API functions */ -PlaneLayoutComponentType getStandardPlaneLayoutComponentTypeValue( - const ExtendableType& planeLayoutComponentType) { - return static_cast(planeLayoutComponentType.value); -} status_t encodeBufferId(uint64_t bufferId, hidl_vec* outBufferId) { return encode(MetadataType_BufferId, bufferId, outBufferId, encodeInteger); @@ -1028,6 +1026,11 @@ ChromaSiting getStandardChromaSitingValue(const ExtendableType& chromaSiting) { return static_cast(chromaSiting.value); } +PlaneLayoutComponentType getStandardPlaneLayoutComponentTypeValue( + const ExtendableType& planeLayoutComponentType) { + return static_cast(planeLayoutComponentType.value); +} + std::string getCompressionName(const ExtendableType& compression) { if (!isStandardCompression(compression)) { std::ostringstream stream; diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h index 94de8f115f..61c9f1c227 100644 --- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h +++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h @@ -30,6 +30,186 @@ #include #include +/** + * Define equality operators for Stable AIDL types. + */ +inline bool operator==(const aidl::android::hardware::graphics::common::ExtendableType& lhs, + const aidl::android::hardware::graphics::common::ExtendableType& rhs) { + return !std::strcmp(lhs.name.c_str(), rhs.name.c_str()) && lhs.value == rhs.value; +} + +inline bool operator!=(const aidl::android::hardware::graphics::common::ExtendableType& lhs, + const aidl::android::hardware::graphics::common::ExtendableType& rhs) { + return !(lhs == rhs); +} + +inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayoutComponent& lhs, + const aidl::android::hardware::graphics::common::PlaneLayoutComponent& rhs) { + if (lhs.type.name != rhs.type.name) { + return false; + } + if (lhs.type.value != rhs.type.value) { + return false; + } + if (lhs.sizeInBits != rhs.sizeInBits) { + return false; + } + if (lhs.offsetInBits != rhs.offsetInBits) { + return false; + } + return true; +} + +inline bool operator!=(const aidl::android::hardware::graphics::common::PlaneLayoutComponent& lhs, + const aidl::android::hardware::graphics::common::PlaneLayoutComponent& rhs) { + return !(lhs == rhs); +} + +inline bool operator==(const aidl::android::hardware::graphics::common::Rect& lhs, + const aidl::android::hardware::graphics::common::Rect& rhs) { + if (lhs.left != rhs.left) { + return false; + } + if (lhs.top != rhs.top) { + return false; + } + if (lhs.right != rhs.right) { + return false; + } + if (lhs.bottom != rhs.bottom) { + return false; + } + return true; +} + +inline bool operator!=(const aidl::android::hardware::graphics::common::Rect& lhs, + const aidl::android::hardware::graphics::common::Rect& rhs) { + return !(lhs == rhs); +} + +inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayout& lhs, + const aidl::android::hardware::graphics::common::PlaneLayout& rhs) { + if (lhs.offsetInBytes != rhs.offsetInBytes) { + return false; + } + if (lhs.sampleIncrementInBits != rhs.sampleIncrementInBits) { + return false; + } + if (lhs.strideInBytes != rhs.strideInBytes) { + return false; + } + if (lhs.widthInSamples != rhs.widthInSamples) { + return false; + } + if (lhs.heightInSamples != rhs.heightInSamples) { + return false; + } + if (lhs.totalSizeInBytes != rhs.totalSizeInBytes) { + return false; + } + if (lhs.horizontalSubsampling != rhs.horizontalSubsampling) { + return false; + } + if (lhs.verticalSubsampling != rhs.verticalSubsampling) { + return false; + } + if (lhs.crop != rhs.crop) { + return false; + } + if (lhs.components.size() != rhs.components.size()) { + return false; + } + for (size_t i = 0; i < lhs.components.size(); i++) { + if (lhs.components[i] != rhs.components[i]) { + return false; + } + } + return true; +} + +inline bool operator!=(const aidl::android::hardware::graphics::common::PlaneLayout& lhs, + const aidl::android::hardware::graphics::common::PlaneLayout& rhs) { + return !(lhs == rhs); +} + +inline bool operator==(const std::vector& lhs, + const std::vector& rhs) { + if (lhs.size() != rhs.size()) { + return false; + } + for (size_t i = 0; i < lhs.size(); i++) { + if (lhs[i] != rhs[i]) { + return false; + } + } + return true; +} + +inline bool operator!=(const std::vector& lhs, + const std::vector& rhs) { + return !(lhs == rhs); +} + +inline bool operator==(const aidl::android::hardware::graphics::common::XyColor& lhs, + const aidl::android::hardware::graphics::common::XyColor& rhs) { + if (lhs.x != rhs.x) { + return false; + } + if (lhs.y != rhs.y) { + return false; + } + return true; +} + +inline bool operator!=(const aidl::android::hardware::graphics::common::XyColor& lhs, + const aidl::android::hardware::graphics::common::XyColor& rhs) { + return !(lhs == rhs); +} + +inline bool operator==(const aidl::android::hardware::graphics::common::Smpte2086& lhs, + const aidl::android::hardware::graphics::common::Smpte2086& rhs) { + if (lhs.primaryRed != rhs.primaryRed) { + return false; + } + if (lhs.primaryGreen != rhs.primaryGreen) { + return false; + } + if (lhs.primaryBlue != rhs.primaryBlue) { + return false; + } + if (lhs.whitePoint != rhs.whitePoint) { + return false; + } + if (lhs.maxLuminance != rhs.maxLuminance) { + return false; + } + if (lhs.minLuminance != rhs.minLuminance) { + return false; + } + return true; +} + +inline bool operator!=(const aidl::android::hardware::graphics::common::Smpte2086& lhs, + const aidl::android::hardware::graphics::common::Smpte2086& rhs) { + return !(lhs == rhs); +} + +inline bool operator==(const aidl::android::hardware::graphics::common::Cta861_3& lhs, + const aidl::android::hardware::graphics::common::Cta861_3& rhs) { + if (lhs.maxContentLightLevel != rhs.maxContentLightLevel) { + return false; + } + if (lhs.maxFrameAverageLightLevel != rhs.maxFrameAverageLightLevel) { + return false; + } + return true; +} + +inline bool operator!=(const aidl::android::hardware::graphics::common::Cta861_3& lhs, + const aidl::android::hardware::graphics::common::Cta861_3& rhs) { + return !(lhs == rhs); +} + namespace android { namespace gralloc4 { diff --git a/libs/gralloc/types/tests/Android.bp b/libs/gralloc/types/tests/Android.bp new file mode 100644 index 0000000000..b939c1db59 --- /dev/null +++ b/libs/gralloc/types/tests/Android.bp @@ -0,0 +1,25 @@ +// +// 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. +// + +cc_test { + name: "GrallocTypes_test", + shared_libs: [ + "libgralloctypes", + "libhidlbase", + ], + srcs: ["Gralloc4_test.cpp"], + cflags: ["-Wall", "-Werror"], +} diff --git a/libs/gralloc/types/tests/Gralloc4_test.cpp b/libs/gralloc/types/tests/Gralloc4_test.cpp new file mode 100644 index 0000000000..d036da1e52 --- /dev/null +++ b/libs/gralloc/types/tests/Gralloc4_test.cpp @@ -0,0 +1,465 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Gralloc4Test" + +#include + +#include + +#include + +using android::hardware::hidl_vec; + +using android::hardware::graphics::common::V1_2::PixelFormat; + +using aidl::android::hardware::graphics::common::BlendMode; +using aidl::android::hardware::graphics::common::ChromaSiting; +using aidl::android::hardware::graphics::common::Compression; +using aidl::android::hardware::graphics::common::Cta861_3; +using aidl::android::hardware::graphics::common::Dataspace; +using aidl::android::hardware::graphics::common::ExtendableType; +using aidl::android::hardware::graphics::common::Interlaced; +using aidl::android::hardware::graphics::common::PlaneLayout; +using aidl::android::hardware::graphics::common::PlaneLayoutComponent; +using aidl::android::hardware::graphics::common::PlaneLayoutComponentType; +using aidl::android::hardware::graphics::common::Rect; +using aidl::android::hardware::graphics::common::Smpte2086; +using aidl::android::hardware::graphics::common::StandardMetadataType; +using aidl::android::hardware::graphics::common::XyColor; + +namespace android { + +template +using EncodeFunction = status_t(*)(T, hidl_vec*); + +template +using EncodeConstFunction = status_t(*)(const T&, hidl_vec*); + +template +using EncodeOptionalFunction = status_t(*)(const std::optional&, hidl_vec*); + +template +using DecodeFunction = status_t(*)(const hidl_vec&, T*); + +template +using DecodeOptionalFunction = status_t(*)(const hidl_vec&, std::optional*); + +template +void testHelper(const T& input, EncodeFunction encode, DecodeFunction decode) { + hidl_vec vec; + T output; + ASSERT_EQ(NO_ERROR, encode(input, &vec)); + ASSERT_EQ(NO_ERROR, decode(vec, &output)); + ASSERT_EQ(input, output); +} + +template +void testHelperConst(const T& input, EncodeConstFunction encode, DecodeFunction decode) { + hidl_vec vec; + T output; + ASSERT_EQ(NO_ERROR, encode(input, &vec)); + ASSERT_EQ(NO_ERROR, decode(vec, &output)); + ASSERT_EQ(input, output); +} + +template +void testHelperStableAidlType(const T& input, EncodeConstFunction encode, DecodeFunction decode) { + hidl_vec vec; + T output; + ASSERT_EQ(NO_ERROR, encode(input, &vec)); + ASSERT_EQ(NO_ERROR, decode(vec, &output)); + ASSERT_TRUE(input == output); +} + +template +void testHelperStableAidlTypeOptional(const std::optional& input, EncodeOptionalFunction encode, + DecodeOptionalFunction decode) { + hidl_vec vec; + std::optional tmp = input; + std::optional output; + ASSERT_EQ(NO_ERROR, encode(tmp, &vec)); + ASSERT_EQ(NO_ERROR, decode(vec, &output)); + ASSERT_EQ(tmp.has_value(), output.has_value()); + if (!tmp.has_value()) { + return; + } + ASSERT_TRUE(*tmp == *output); +} + +class Gralloc4TestUint64 : public testing::TestWithParam { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestUint64Params, Gralloc4TestUint64, + ::testing::Values(0, -1, 1, 5, 100, 0xFF, std::numeric_limits::min(), + std::numeric_limits::max())); + +TEST_P(Gralloc4TestUint64, BufferId) { + ASSERT_NO_FATAL_FAILURE(testHelper(GetParam(), gralloc4::encodeBufferId, gralloc4::decodeBufferId)); +} + +TEST_P(Gralloc4TestUint64, Width) { + ASSERT_NO_FATAL_FAILURE(testHelper(GetParam(), gralloc4::encodeWidth, gralloc4::decodeWidth)); +} + +TEST_P(Gralloc4TestUint64, Height) { + ASSERT_NO_FATAL_FAILURE(testHelper(GetParam(), gralloc4::encodeHeight, gralloc4::decodeHeight)); +} + +TEST_P(Gralloc4TestUint64, LayerCount) { + ASSERT_NO_FATAL_FAILURE(testHelper(GetParam(), gralloc4::encodeLayerCount, gralloc4::decodeLayerCount)); +} + +TEST_P(Gralloc4TestUint64, PixelFormatModifier) { + ASSERT_NO_FATAL_FAILURE(testHelper(GetParam(), gralloc4::encodePixelFormatModifier, gralloc4::decodePixelFormatModifier)); +} + +TEST_P(Gralloc4TestUint64, Usage) { + ASSERT_NO_FATAL_FAILURE(testHelper(GetParam(), gralloc4::encodeUsage, gralloc4::decodeUsage)); +} + +TEST_P(Gralloc4TestUint64, AllocationSize) { + ASSERT_NO_FATAL_FAILURE(testHelper(GetParam(), gralloc4::encodeAllocationSize, gralloc4::decodeAllocationSize)); +} + +TEST_P(Gralloc4TestUint64, ProtectedContent) { + ASSERT_NO_FATAL_FAILURE(testHelper(GetParam(), gralloc4::encodeProtectedContent, gralloc4::decodeProtectedContent)); +} + +class Gralloc4TestString : public testing::TestWithParam { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestStringParams, Gralloc4TestString, + ::testing::Values("name", "aaaaa", "", "abcdefghijklmnopqrstuvwxyz", "0xFF")); + +TEST_P(Gralloc4TestString, Name) { + ASSERT_NO_FATAL_FAILURE(testHelperConst(GetParam(), gralloc4::encodeName, gralloc4::decodeName)); +} + +class Gralloc4TestUint32 : public testing::TestWithParam { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestUint32Params, Gralloc4TestUint32, + ::testing::Values(0, 1, 5, 100, 0xFF, std::numeric_limits::min(), + std::numeric_limits::max())); + +TEST_P(Gralloc4TestUint32, PixelFormatFourCC) { + ASSERT_NO_FATAL_FAILURE(testHelper(GetParam(), gralloc4::encodePixelFormatFourCC, gralloc4::decodePixelFormatFourCC)); +} + +class Gralloc4TestPixelFormat : public testing::TestWithParam { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestPixelFormatParams, Gralloc4TestPixelFormat, + ::testing::Values(PixelFormat::RGBA_8888, PixelFormat::BLOB, + PixelFormat::IMPLEMENTATION_DEFINED, PixelFormat::YCBCR_420_888, + PixelFormat::YV12)); + +TEST_P(Gralloc4TestPixelFormat, PixelFormatRequested) { + ASSERT_NO_FATAL_FAILURE(testHelperConst(GetParam(), gralloc4::encodePixelFormatRequested, gralloc4::decodePixelFormatRequested)); +} + +class Gralloc4TestCompression : public testing::TestWithParam { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestCompressionParams, Gralloc4TestCompression, + ::testing::Values(gralloc4::Compression_None, gralloc4::Compression_DisplayStreamCompression, + ExtendableType{"", 0}, + ExtendableType{"vendor.mycompanyname.graphics.common.Compression", 0xFF}, + ExtendableType{"vendor.mycompanyname.graphics.common.Compression", std::numeric_limits::max()})); + +TEST_P(Gralloc4TestCompression, Compression) { + ASSERT_NO_FATAL_FAILURE(testHelperStableAidlType(GetParam(), gralloc4::encodeCompression, gralloc4::decodeCompression)); +} + +class Gralloc4TestInterlaced : public testing::TestWithParam { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestInterlacedParams, Gralloc4TestInterlaced, + ::testing::Values(gralloc4::Interlaced_None, gralloc4::Interlaced_TopBottom, + gralloc4::Interlaced_RightLeft, + ExtendableType{"", 0}, + ExtendableType{"vendor.mycompanyname.graphics.common.Interlaced", 0xFF}, + ExtendableType{"vendor.mycompanyname.graphics.common.Interlaced", std::numeric_limits::max()})); + +TEST_P(Gralloc4TestInterlaced, Interlaced) { + ASSERT_NO_FATAL_FAILURE(testHelperStableAidlType(GetParam(), gralloc4::encodeInterlaced, gralloc4::decodeInterlaced)); +} + +class Gralloc4TestChromaSiting : public testing::TestWithParam { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestChromaSitingParams, Gralloc4TestChromaSiting, + ::testing::Values(gralloc4::ChromaSiting_None, gralloc4::ChromaSiting_Unknown, + gralloc4::ChromaSiting_SitedInterstitial, gralloc4::ChromaSiting_CositedHorizontal, + ExtendableType{"", 0}, + ExtendableType{"vendor.mycompanyname.graphics.common.ChromaSiting", 0xFF}, + ExtendableType{"vendor.mycompanyname.graphics.common.ChromaSiting", std::numeric_limits::max()})); + +TEST_P(Gralloc4TestChromaSiting, ChromaSiting) { + ASSERT_NO_FATAL_FAILURE(testHelperStableAidlType(GetParam(), gralloc4::encodeChromaSiting, gralloc4::decodeChromaSiting)); +} + +class Gralloc4TestPlaneLayouts : public testing::Test { }; + +TEST_F(Gralloc4TestPlaneLayouts, PlaneLayouts) { + uint32_t width = 64; + uint32_t height = 64; + + std::vector planeLayouts; + PlaneLayout planeLayoutA; + PlaneLayout planeLayoutRGB; + PlaneLayoutComponent component; + + planeLayoutA.offsetInBytes = 0; + planeLayoutA.sampleIncrementInBits = 8; + planeLayoutA.strideInBytes = width + 20; + planeLayoutA.widthInSamples = width; + planeLayoutA.heightInSamples = height; + planeLayoutA.totalSizeInBytes = planeLayoutA.strideInBytes * height; + planeLayoutA.horizontalSubsampling = 1; + planeLayoutA.verticalSubsampling = 1; + planeLayoutA.crop.left = 0; + planeLayoutA.crop.top = 0; + planeLayoutA.crop.right = width; + planeLayoutA.crop.bottom = height; + + component.type = gralloc4::PlaneLayoutComponentType_A; + component.offsetInBits = 0; + component.sizeInBits = 8; + planeLayoutA.components.push_back(component); + + planeLayouts.push_back(planeLayoutA); + + planeLayoutRGB.offsetInBytes = 0; + planeLayoutRGB.sampleIncrementInBits = 32; + planeLayoutRGB.strideInBytes = width + 20; + planeLayoutRGB.widthInSamples = width; + planeLayoutRGB.heightInSamples = height; + planeLayoutRGB.totalSizeInBytes = planeLayoutRGB.strideInBytes * height; + planeLayoutRGB.horizontalSubsampling = 1; + planeLayoutRGB.verticalSubsampling = 1; + planeLayoutRGB.crop.left = 0; + planeLayoutRGB.crop.top = 0; + planeLayoutRGB.crop.right = width; + planeLayoutRGB.crop.bottom = height; + + component.type = gralloc4::PlaneLayoutComponentType_R; + planeLayoutRGB.components.push_back(component); + component.type = gralloc4::PlaneLayoutComponentType_G; + planeLayoutRGB.components.push_back(component); + component.type = gralloc4::PlaneLayoutComponentType_B; + planeLayoutRGB.components.push_back(component); + + planeLayouts.push_back(planeLayoutRGB); + + ASSERT_NO_FATAL_FAILURE(testHelperStableAidlType(planeLayouts, gralloc4::encodePlaneLayouts, gralloc4::decodePlaneLayouts)); +} + +class Gralloc4TestDataspace : public testing::TestWithParam { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestDataspaceParams, Gralloc4TestDataspace, + ::testing::Values(Dataspace::UNKNOWN, Dataspace::ARBITRARY, Dataspace::DISPLAY_P3, + Dataspace::ADOBE_RGB)); + +TEST_P(Gralloc4TestDataspace, DataspaceRequested) { + ASSERT_NO_FATAL_FAILURE(testHelperConst(GetParam(), gralloc4::encodeDataspace, gralloc4::decodeDataspace)); +} + +class Gralloc4TestBlendMode : public testing::TestWithParam { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestBlendModeParams, Gralloc4TestBlendMode, + ::testing::Values(BlendMode::INVALID, BlendMode::NONE, BlendMode::PREMULTIPLIED, + BlendMode::COVERAGE)); + +TEST_P(Gralloc4TestBlendMode, BlendMode) { + ASSERT_NO_FATAL_FAILURE(testHelperConst(GetParam(), gralloc4::encodeBlendMode, gralloc4::decodeBlendMode)); +} + +class Gralloc4TestSmpte2086 : public testing::TestWithParam> { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestSmpte2086Params, Gralloc4TestSmpte2086, + ::testing::Values(std::optional(Smpte2086{XyColor{0.680, 0.320}, + XyColor{0.265, 0.690}, + XyColor{0.150, 0.060}, + XyColor{0.3127, 0.3290}, + 100.0, 0.1}), + std::optional(Smpte2086{XyColor{-1.0, 100.0}, + XyColor{0xFF, -0xFF}, + XyColor{999.9, 0.0}, + XyColor{0.0, -1.0}, + -0.1, -100.0}), + std::nullopt)); + +TEST_P(Gralloc4TestSmpte2086, Smpte2086) { + ASSERT_NO_FATAL_FAILURE(testHelperStableAidlTypeOptional(GetParam(), gralloc4::encodeSmpte2086, gralloc4::decodeSmpte2086)); +} + +class Gralloc4TestCta861_3 : public testing::TestWithParam> { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestCta861_3Params, Gralloc4TestCta861_3, + ::testing::Values(std::optional(Cta861_3{78.0, 62.0}), + std::optional(Cta861_3{10.0, 10.0}), + std::optional(Cta861_3{0.0, 0.0}), + std::optional(Cta861_3{std::numeric_limits::min(), std::numeric_limits::min()}), + std::optional(Cta861_3{std::numeric_limits::max(), std::numeric_limits::max()}), + std::nullopt)); + +TEST_P(Gralloc4TestCta861_3, Cta861_3) { + ASSERT_NO_FATAL_FAILURE(testHelperStableAidlTypeOptional(GetParam(), gralloc4::encodeCta861_3, gralloc4::decodeCta861_3)); +} + +class Gralloc4TestSmpte2094_40 : public testing::TestWithParam>> { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestSmpte2094_40Params, Gralloc4TestSmpte2094_40, + ::testing::Values(std::optional>({}), + std::optional>({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), + std::optional>({std::numeric_limits::min(), + std::numeric_limits::min() + 1, + std::numeric_limits::min() + 2, + std::numeric_limits::min() + 3, + std::numeric_limits::min() + 4}), + std::optional>({std::numeric_limits::max(), + std::numeric_limits::max() - 1, + std::numeric_limits::max() - 2, + std::numeric_limits::max() - 3, + std::numeric_limits::max() - 4}), + std::nullopt)); + +TEST_P(Gralloc4TestSmpte2094_40, Smpte2094_40) { + ASSERT_NO_FATAL_FAILURE(testHelperStableAidlTypeOptional(GetParam(), gralloc4::encodeSmpte2094_40, gralloc4::decodeSmpte2094_40)); +} + +class Gralloc4TestErrors : public testing::Test { }; + +TEST_F(Gralloc4TestErrors, Gralloc4TestEncodeNull) { + ASSERT_NE(NO_ERROR, gralloc4::encodeBufferId(0, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeName("", nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeWidth(0, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeHeight(0, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeLayerCount(0, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodePixelFormatRequested(PixelFormat::RGBA_8888, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodePixelFormatFourCC(0, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodePixelFormatModifier(0, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeUsage(0, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeAllocationSize(0, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeProtectedContent(0, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeCompression(gralloc4::Compression_None, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeInterlaced(gralloc4::Interlaced_None, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeChromaSiting(gralloc4::ChromaSiting_None, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodePlaneLayouts({}, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeDataspace(Dataspace::UNKNOWN, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeBlendMode(BlendMode::NONE, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeSmpte2086({{}}, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeCta861_3({{}}, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::encodeSmpte2094_40({{}}, nullptr)); +} + +TEST_F(Gralloc4TestErrors, Gralloc4TestDecodeNull) { + hidl_vec vec; + + ASSERT_NE(NO_ERROR, gralloc4::decodeBufferId(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeName(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeWidth(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeHeight(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeLayerCount(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodePixelFormatRequested(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodePixelFormatModifier(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeUsage(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeAllocationSize(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeProtectedContent(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeCompression(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeInterlaced(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeChromaSiting(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodePlaneLayouts(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeDataspace(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeBlendMode(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeSmpte2086(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeCta861_3(vec, nullptr)); + ASSERT_NE(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, nullptr)); +} + +TEST_F(Gralloc4TestErrors, Gralloc4TestDecodeBadVec) { + hidl_vec vec = { 0 }; + + uint64_t bufferId, width, height, layerCount, pixelFormatModifier, usage, allocationSize, + protectedContent; + std::string name; + PixelFormat pixelFormatRequested; + uint32_t pixelFormatFourCC; + ExtendableType compression, interlaced, chromaSiting; + std::vector planeLayouts; + Dataspace dataspace; + BlendMode blendMode; + std::optional smpte2086; + std::optional cta861_3; + std::optional> smpte2094_40; + + ASSERT_NE(NO_ERROR, gralloc4::decodeBufferId(vec, &bufferId)); + ASSERT_NE(NO_ERROR, gralloc4::decodeName(vec, &name)); + ASSERT_NE(NO_ERROR, gralloc4::decodeWidth(vec, &width)); + ASSERT_NE(NO_ERROR, gralloc4::decodeHeight(vec, &height)); + ASSERT_NE(NO_ERROR, gralloc4::decodeLayerCount(vec, &layerCount)); + ASSERT_NE(NO_ERROR, gralloc4::decodePixelFormatRequested(vec, &pixelFormatRequested)); + ASSERT_NE(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &pixelFormatFourCC)); + ASSERT_NE(NO_ERROR, gralloc4::decodePixelFormatModifier(vec, &pixelFormatModifier)); + ASSERT_NE(NO_ERROR, gralloc4::decodeUsage(vec, &usage)); + ASSERT_NE(NO_ERROR, gralloc4::decodeAllocationSize(vec, &allocationSize)); + ASSERT_NE(NO_ERROR, gralloc4::decodeProtectedContent(vec, &protectedContent)); + ASSERT_NE(NO_ERROR, gralloc4::decodeCompression(vec, &compression)); + ASSERT_NE(NO_ERROR, gralloc4::decodeInterlaced(vec, &interlaced)); + ASSERT_NE(NO_ERROR, gralloc4::decodeChromaSiting(vec, &chromaSiting)); + ASSERT_NE(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts)); + ASSERT_NE(NO_ERROR, gralloc4::decodeDataspace(vec, &dataspace)); + ASSERT_NE(NO_ERROR, gralloc4::decodeBlendMode(vec, &blendMode)); + ASSERT_NE(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086)); + ASSERT_NE(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3)); + ASSERT_NE(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40)); +} + +class Gralloc4TestHelpers : public testing::Test { }; + +TEST_F(Gralloc4TestHelpers, Gralloc4TestIsStandard) { + ASSERT_TRUE(gralloc4::isStandardMetadataType(gralloc4::MetadataType_BufferId)); + ASSERT_TRUE(gralloc4::isStandardCompression(gralloc4::Compression_None)); + ASSERT_TRUE(gralloc4::isStandardInterlaced(gralloc4::Interlaced_None)); + ASSERT_TRUE(gralloc4::isStandardChromaSiting(gralloc4::ChromaSiting_None)); + ASSERT_TRUE(gralloc4::isStandardPlaneLayoutComponentType(gralloc4::PlaneLayoutComponentType_Y)); +} + +TEST_F(Gralloc4TestHelpers, Gralloc4TestIsNotStandard) { + ASSERT_FALSE(gralloc4::isStandardMetadataType({"vendor.mycompanyname.graphics.common.MetadataType", 0})); + ASSERT_FALSE(gralloc4::isStandardCompression({"vendor.mycompanyname.graphics.common.Compression", 0})); + ASSERT_FALSE(gralloc4::isStandardInterlaced({"vendor.mycompanyname.graphics.common.Interlaced", 0})); + ASSERT_FALSE(gralloc4::isStandardChromaSiting({"vendor.mycompanyname.graphics.common.ChromaSiting", 0})); + ASSERT_FALSE(gralloc4::isStandardPlaneLayoutComponentType({"vendor.mycompanyname.graphics.common.PlaneLayoutComponentType", 0})); +} + +TEST_F(Gralloc4TestHelpers, Gralloc4TestGetStandardValue) { + ASSERT_EQ(StandardMetadataType::BUFFER_ID, gralloc4::getStandardMetadataTypeValue(gralloc4::MetadataType_BufferId)); + ASSERT_EQ(Compression::NONE, gralloc4::getStandardCompressionValue(gralloc4::Compression_None)); + ASSERT_EQ(Interlaced::NONE, gralloc4::getStandardInterlacedValue(gralloc4::Interlaced_None)); + ASSERT_EQ(ChromaSiting::NONE, gralloc4::getStandardChromaSitingValue(gralloc4::ChromaSiting_None)); + ASSERT_EQ(PlaneLayoutComponentType::Y, gralloc4::getStandardPlaneLayoutComponentTypeValue(gralloc4::PlaneLayoutComponentType_Y)); +} + +} // namespace android -- GitLab From b95c1efcaa86f54a6cc67c49f1ac39c92a2c2e9d Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Wed, 18 Dec 2019 14:57:31 -0800 Subject: [PATCH 0574/1255] gralloc: add vendor encode/decode helpers Add helper functions so vendors can encode and decode basic C++ types without writing their own encode/decode functions. Test: Gralloc4_test and libgralloctypes_fuzzer Bug: 145624669 Change-Id: I91f7a69c76a8ff633fe88f0deb6be6996b789ba0 --- libs/gralloc/types/Gralloc4.cpp | 70 +++++++++++ libs/gralloc/types/fuzzer/gralloctypes.cpp | 22 +++- libs/gralloc/types/fuzzer/gralloctypes.h | 4 +- libs/gralloc/types/fuzzer/main.cpp | 97 ++++++++++++---- .../types/include/gralloctypes/Gralloc4.h | 52 +++++++++ libs/gralloc/types/tests/Gralloc4_test.cpp | 109 ++++++++++++++++-- 6 files changed, 316 insertions(+), 38 deletions(-) diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp index 20050dc81f..4851b44c36 100644 --- a/libs/gralloc/types/Gralloc4.cpp +++ b/libs/gralloc/types/Gralloc4.cpp @@ -985,6 +985,76 @@ status_t decodeSmpte2094_40(const hidl_vec& smpte2094_40, decodeByteVector); } +status_t encodeUint32(const MetadataType& metadataType, uint32_t input, + hidl_vec* output) { + return encode(metadataType, input, output, encodeInteger); +} + +status_t decodeUint32(const MetadataType& metadataType, const hidl_vec& input, + uint32_t* output) { + return decode(metadataType, input, output, decodeInteger); +} + +status_t encodeInt32(const MetadataType& metadataType, int32_t input, + hidl_vec* output) { + return encode(metadataType, input, output, encodeInteger); +} + +status_t decodeInt32(const MetadataType& metadataType, const hidl_vec& input, + int32_t* output) { + return decode(metadataType, input, output, decodeInteger); +} + +status_t encodeUint64(const MetadataType& metadataType, uint64_t input, + hidl_vec* output) { + return encode(metadataType, input, output, encodeInteger); +} + +status_t decodeUint64(const MetadataType& metadataType, const hidl_vec& input, + uint64_t* output) { + return decode(metadataType, input, output, decodeInteger); +} + +status_t encodeInt64(const MetadataType& metadataType, int64_t input, + hidl_vec* output) { + return encode(metadataType, input, output, encodeInteger); +} + +status_t decodeInt64(const MetadataType& metadataType, const hidl_vec& input, + int64_t* output) { + return decode(metadataType, input, output, decodeInteger); +} + +status_t encodeFloat(const MetadataType& metadataType, float input, + hidl_vec* output) { + return encode(metadataType, input, output, encodeInteger); +} + +status_t decodeFloat(const MetadataType& metadataType, const hidl_vec& input, + float* output) { + return decode(metadataType, input, output, decodeInteger); +} + +status_t encodeDouble(const MetadataType& metadataType, double input, + hidl_vec* output) { + return encode(metadataType, input, output, encodeInteger); +} + +status_t decodeDouble(const MetadataType& metadataType, const hidl_vec& input, + double* output) { + return decode(metadataType, input, output, decodeInteger); +} + +status_t encodeString(const MetadataType& metadataType, const std::string& input, + hidl_vec* output) { + return encode(metadataType, input, output, encodeString); +} + +status_t decodeString(const MetadataType& metadataType, const hidl_vec& input, + std::string* output) { + return decode(metadataType, input, output, decodeString); +} + bool isStandardMetadataType(const MetadataType& metadataType) { return !std::strncmp(metadataType.name.c_str(), GRALLOC4_STANDARD_METADATA_TYPE, metadataType.name.size()); diff --git a/libs/gralloc/types/fuzzer/gralloctypes.cpp b/libs/gralloc/types/fuzzer/gralloctypes.cpp index da8cf97d4c..b18f407fe8 100644 --- a/libs/gralloc/types/fuzzer/gralloctypes.cpp +++ b/libs/gralloc/types/fuzzer/gralloctypes.cpp @@ -30,9 +30,10 @@ #include "util.h" using ::android::status_t; +using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType; #define GRALLOCTYPES_DECODE(T, FUNC) \ - [] (const ::android::hardware::hidl_vec& vec, uint8_t /*data*/) {\ + [] (const ::android::hardware::hidl_vec& vec) {\ FUZZ_LOG() << "about to read " #T " using " #FUNC;\ T t;\ status_t err = FUNC(vec, &t);\ @@ -40,6 +41,15 @@ using ::android::status_t; FUZZ_LOG() << #T " done " /* << "err: " << err*/;\ } +#define GRALLOCTYPES_DECODE_VENDOR_HELPER(T, FUNC) \ + [] (const MetadataType& metadataType, const ::android::hardware::hidl_vec& vec) {\ + FUZZ_LOG() << "about to read " #T " using " #FUNC;\ + T t;\ + status_t err = FUNC(metadataType, vec, &t);\ + (void) err;\ + FUZZ_LOG() << #T " done " /* << "err: " << err*/;\ + } + // clang-format off std::vector GRALLOCTYPES_DECODE_FUNCTIONS { @@ -64,4 +74,14 @@ std::vector GRALLOCTYPES_DECODE_FUNCTIONS { GRALLOCTYPES_DECODE(std::optional, ::android::gralloc4::decodeCta861_3), GRALLOCTYPES_DECODE(std::optional>, ::android::gralloc4::decodeSmpte2094_40), }; + +std::vector GRALLOCTYPES_DECODE_VENDOR_HELPER_FUNCTIONS { + GRALLOCTYPES_DECODE_VENDOR_HELPER(uint32_t, ::android::gralloc4::decodeUint32), + GRALLOCTYPES_DECODE_VENDOR_HELPER(int32_t, ::android::gralloc4::decodeInt32), + GRALLOCTYPES_DECODE_VENDOR_HELPER(uint64_t, ::android::gralloc4::decodeUint64), + GRALLOCTYPES_DECODE_VENDOR_HELPER(int64_t, ::android::gralloc4::decodeInt64), + GRALLOCTYPES_DECODE_VENDOR_HELPER(float, ::android::gralloc4::decodeFloat), + GRALLOCTYPES_DECODE_VENDOR_HELPER(double, ::android::gralloc4::decodeDouble), + GRALLOCTYPES_DECODE_VENDOR_HELPER(std::string, ::android::gralloc4::decodeString), +}; // clang-format on diff --git a/libs/gralloc/types/fuzzer/gralloctypes.h b/libs/gralloc/types/fuzzer/gralloctypes.h index b995fcebe4..a3fe2d9db7 100644 --- a/libs/gralloc/types/fuzzer/gralloctypes.h +++ b/libs/gralloc/types/fuzzer/gralloctypes.h @@ -20,6 +20,8 @@ #include -using GrallocTypesDecode = std::function& vec, uint8_t data)>; +using GrallocTypesDecode = std::function& vec)>; +using GrallocTypesVendorHelperDecode = std::function& vec)>; extern std::vector GRALLOCTYPES_DECODE_FUNCTIONS; +extern std::vector GRALLOCTYPES_DECODE_VENDOR_HELPER_FUNCTIONS; diff --git a/libs/gralloc/types/fuzzer/main.cpp b/libs/gralloc/types/fuzzer/main.cpp index 2807878d74..8779fa232c 100644 --- a/libs/gralloc/types/fuzzer/main.cpp +++ b/libs/gralloc/types/fuzzer/main.cpp @@ -24,52 +24,99 @@ #include #include +using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType; + void doFuzz( - const std::vector& decodes, - const std::vector& input, - const std::vector& instructions) { + const std::vector& decodes, uint8_t instruction, + const std::vector& input) { ::android::hardware::hidl_vec vec; vec.setToExternal(const_cast(input.data()), input.size(), false /*shouldOwn*/); // since we are only using a byte to index CHECK(decodes.size() <= 255) << decodes.size(); + uint8_t decodeIdx = instruction % decodes.size(); + + FUZZ_LOG() << "Instruction: " << instruction << " idx: " << static_cast(decodeIdx) + << " size: " << vec.size(); + + decodes[decodeIdx](vec); +} + +size_t fillInMetadataType(const std::vector& input, MetadataType* outMetadataType) { + if (input.size() < sizeof(outMetadataType->value) + 1) { + return 0; + } + size_t size = 0; + + outMetadataType->value = *(reinterpret_cast(input.data())); + size += sizeof(outMetadataType->value); + + uint8_t nameLen = *(input.data() + size); + size += 1; - for (size_t i = 0; i < instructions.size() - 1; i += 2) { - uint8_t a = instructions[i]; - uint8_t decodeIdx = a % decodes.size(); + if (input.size() < size + nameLen) { + return 0; + } + std::string name(reinterpret_cast(input.data()) + size, nameLen); + outMetadataType->name = name; + return size + nameLen; +} - uint8_t b = instructions[i + 1]; +void doFuzzVendorHelper( + const std::vector& decodes, uint8_t instruction, + const std::vector& input) { - FUZZ_LOG() << "Instruction: " << (i / 2) + 1 << "/" << instructions.size() / 2 - << " cmd: " << static_cast(a) << " (" << static_cast(decodeIdx) - << ") arg: " << static_cast(b) << " size: " << vec.size(); + MetadataType metadataType; + size_t sizeUsed = fillInMetadataType(input, &metadataType); + if (sizeUsed <= 0) { + return; + } + + ::android::hardware::hidl_vec vec; + vec.setToExternal(const_cast(input.data() + sizeUsed), input.size() - sizeUsed, + false /*shouldOwn*/); + + // since we are only using a byte to index + CHECK(decodes.size() <= 255) << decodes.size(); + uint8_t decodeIdx = instruction % decodes.size(); + + FUZZ_LOG() << "Vendor Helper instruction: " << instruction << " idx: " + << static_cast(decodeIdx) << " size: " << vec.size(); + + decodes[decodeIdx](metadataType, vec); +} - decodes[decodeIdx](vec, b); +void fuzz(uint8_t options, uint8_t instruction, const std::vector& input) { + uint8_t option = options & 0x1; + + switch (option) { + case 0x0: + doFuzz(GRALLOCTYPES_DECODE_FUNCTIONS, instruction, input); + break; + case 0x1: + doFuzzVendorHelper(GRALLOCTYPES_DECODE_VENDOR_HELPER_FUNCTIONS, instruction, input); + break; + default: + LOG_ALWAYS_FATAL("unknown gralloc types %d", static_cast(option)); } } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (size <= 1) return 0; // no use - // data to fill out parcel - size_t inputLen = size / 2; - std::vector input(data, data + inputLen); - data += inputLen; - size -= inputLen; + uint8_t options = *data; + data++; + size--; - // data to use to determine what to do - size_t instructionLen = size; - std::vector instructions(data, data + instructionLen); - data += instructionLen; - size -= instructionLen; + uint8_t instruction = *data; + data++; + size--; - CHECK(size == 0) << "size: " << size; + std::vector input(data, data + size); - FUZZ_LOG() << "inputLen: " << inputLen << " instructionLen: " << instructionLen; FUZZ_LOG() << "input: " << hexString(input); - FUZZ_LOG() << "instructions: " << hexString(instructions); - doFuzz(GRALLOCTYPES_DECODE_FUNCTIONS, input, instructions); + fuzz(options, instruction, input); return 0; } diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h index 61c9f1c227..ca0d4b5ccf 100644 --- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h +++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h @@ -488,6 +488,58 @@ status_t encodeSmpte2094_40(const std::optional>& smpte2094 status_t decodeSmpte2094_40(const android::hardware::hidl_vec& smpte2094_40, std::optional>* outSmpte2094_40); +/** + * The functions below can be used to encode and decode vendor metadata types. + */ +status_t encodeUint32( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + uint32_t input, android::hardware::hidl_vec* output); +status_t decodeUint32( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + const android::hardware::hidl_vec& input, uint32_t* output); + +status_t encodeInt32( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + int32_t input, android::hardware::hidl_vec* output); +status_t decodeInt32( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + const android::hardware::hidl_vec& input, int32_t* output); + +status_t encodeUint64( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + uint64_t input, android::hardware::hidl_vec* output); +status_t decodeUint64( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + const android::hardware::hidl_vec& input, uint64_t* output); + +status_t encodeInt64( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + int64_t input, android::hardware::hidl_vec* output); +status_t decodeInt64( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + const android::hardware::hidl_vec& input, int64_t* output); + +status_t encodeFloat( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + float input, android::hardware::hidl_vec* output); +status_t decodeFloat( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + const android::hardware::hidl_vec& input, float* output); + +status_t encodeDouble( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + double input, android::hardware::hidl_vec* output); +status_t decodeDouble( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + const android::hardware::hidl_vec& input, double* output); + +status_t encodeString( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + const std::string& input, android::hardware::hidl_vec* output); +status_t decodeString( + const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType& metadataType, + const android::hardware::hidl_vec& input, std::string* output); + /** * The functions below can be used to parse extendable types. */ diff --git a/libs/gralloc/types/tests/Gralloc4_test.cpp b/libs/gralloc/types/tests/Gralloc4_test.cpp index d036da1e52..3542ed9550 100644 --- a/libs/gralloc/types/tests/Gralloc4_test.cpp +++ b/libs/gralloc/types/tests/Gralloc4_test.cpp @@ -41,6 +41,8 @@ using aidl::android::hardware::graphics::common::Smpte2086; using aidl::android::hardware::graphics::common::StandardMetadataType; using aidl::android::hardware::graphics::common::XyColor; +using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType; + namespace android { template @@ -49,12 +51,21 @@ using EncodeFunction = status_t(*)(T, hidl_vec*); template using EncodeConstFunction = status_t(*)(const T&, hidl_vec*); +template +using EncodeMetadataTypeFunction = status_t(*)(const MetadataType&, T, hidl_vec*); + +template +using EncodeMetadataTypeConstFunction = status_t(*)(const MetadataType&, const T&, hidl_vec*); + template using EncodeOptionalFunction = status_t(*)(const std::optional&, hidl_vec*); template using DecodeFunction = status_t(*)(const hidl_vec&, T*); +template +using DecodeMetadataTypeFunction = status_t(*)(const MetadataType&, const hidl_vec&, T*); + template using DecodeOptionalFunction = status_t(*)(const hidl_vec&, std::optional*); @@ -76,6 +87,26 @@ void testHelperConst(const T& input, EncodeConstFunction encode, DecodeFuncti ASSERT_EQ(input, output); } +template +void testHelperMetadataType(const T& input, EncodeMetadataTypeFunction encode, DecodeMetadataTypeFunction decode) { + hidl_vec vec; + MetadataType metadataType{"vendor.mycompanyname.graphics.common.MetadataType", 0}; + T output; + ASSERT_EQ(NO_ERROR, encode(metadataType, input, &vec)); + ASSERT_EQ(NO_ERROR, decode(metadataType, vec, &output)); + ASSERT_EQ(input, output); +} + +template +void testHelperMetadataTypeConst(const T& input, EncodeMetadataTypeConstFunction encode, DecodeMetadataTypeFunction decode) { + hidl_vec vec; + MetadataType metadataType{"vendor.mycompanyname.graphics.common.MetadataType", 0}; + T output; + ASSERT_EQ(NO_ERROR, encode(metadataType, input, &vec)); + ASSERT_EQ(NO_ERROR, decode(metadataType, vec, &output)); + ASSERT_EQ(input, output); +} + template void testHelperStableAidlType(const T& input, EncodeConstFunction encode, DecodeFunction decode) { hidl_vec vec; @@ -100,6 +131,32 @@ void testHelperStableAidlTypeOptional(const std::optional& input, EncodeOptio ASSERT_TRUE(*tmp == *output); } +class Gralloc4TestUint32 : public testing::TestWithParam { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestUint32Params, Gralloc4TestUint32, + ::testing::Values(0, -1, 1, 5, 100, 0xFF, std::numeric_limits::min(), + std::numeric_limits::max())); + +TEST_P(Gralloc4TestUint32, Uint32) { + ASSERT_NO_FATAL_FAILURE(testHelperMetadataType(GetParam(), gralloc4::encodeUint32, gralloc4::decodeUint32)); +} + +TEST_P(Gralloc4TestUint32, PixelFormatFourCC) { + ASSERT_NO_FATAL_FAILURE(testHelper(GetParam(), gralloc4::encodePixelFormatFourCC, gralloc4::decodePixelFormatFourCC)); +} + +class Gralloc4TestInt32 : public testing::TestWithParam { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestInt32Params, Gralloc4TestInt32, + ::testing::Values(0, 1, 5, 100, 0xFF, std::numeric_limits::min(), + std::numeric_limits::max())); + +TEST_P(Gralloc4TestInt32, Int32) { + ASSERT_NO_FATAL_FAILURE(testHelperMetadataType(GetParam(), gralloc4::encodeInt32, gralloc4::decodeInt32)); +} + class Gralloc4TestUint64 : public testing::TestWithParam { }; INSTANTIATE_TEST_CASE_P( @@ -107,6 +164,10 @@ INSTANTIATE_TEST_CASE_P( ::testing::Values(0, -1, 1, 5, 100, 0xFF, std::numeric_limits::min(), std::numeric_limits::max())); +TEST_P(Gralloc4TestUint64, Uint64) { + ASSERT_NO_FATAL_FAILURE(testHelperMetadataType(GetParam(), gralloc4::encodeUint64, gralloc4::decodeUint64)); +} + TEST_P(Gralloc4TestUint64, BufferId) { ASSERT_NO_FATAL_FAILURE(testHelper(GetParam(), gralloc4::encodeBufferId, gralloc4::decodeBufferId)); } @@ -139,25 +200,51 @@ TEST_P(Gralloc4TestUint64, ProtectedContent) { ASSERT_NO_FATAL_FAILURE(testHelper(GetParam(), gralloc4::encodeProtectedContent, gralloc4::decodeProtectedContent)); } -class Gralloc4TestString : public testing::TestWithParam { }; +class Gralloc4TestInt64 : public testing::TestWithParam { }; INSTANTIATE_TEST_CASE_P( - Gralloc4TestStringParams, Gralloc4TestString, - ::testing::Values("name", "aaaaa", "", "abcdefghijklmnopqrstuvwxyz", "0xFF")); + Gralloc4TestInt64Params, Gralloc4TestInt64, + ::testing::Values(0, 1, 5, 100, 0xFF, std::numeric_limits::min(), + std::numeric_limits::max())); -TEST_P(Gralloc4TestString, Name) { - ASSERT_NO_FATAL_FAILURE(testHelperConst(GetParam(), gralloc4::encodeName, gralloc4::decodeName)); +TEST_P(Gralloc4TestInt64, Int64) { + ASSERT_NO_FATAL_FAILURE(testHelperMetadataType(GetParam(), gralloc4::encodeInt64, gralloc4::decodeInt64)); } -class Gralloc4TestUint32 : public testing::TestWithParam { }; +class Gralloc4TestFloat : public testing::TestWithParam { }; INSTANTIATE_TEST_CASE_P( - Gralloc4TestUint32Params, Gralloc4TestUint32, - ::testing::Values(0, 1, 5, 100, 0xFF, std::numeric_limits::min(), - std::numeric_limits::max())); + Gralloc4TestFloatParams, Gralloc4TestFloat, + ::testing::Values(0.0, 1.999999, 5.5, 100.1, 1234.5678, std::numeric_limits::min(), + std::numeric_limits::max())); -TEST_P(Gralloc4TestUint32, PixelFormatFourCC) { - ASSERT_NO_FATAL_FAILURE(testHelper(GetParam(), gralloc4::encodePixelFormatFourCC, gralloc4::decodePixelFormatFourCC)); +TEST_P(Gralloc4TestFloat, Float) { + ASSERT_NO_FATAL_FAILURE(testHelperMetadataType(GetParam(), gralloc4::encodeFloat, gralloc4::decodeFloat)); +} + +class Gralloc4TestDouble : public testing::TestWithParam { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestDoubleParams, Gralloc4TestDouble, + ::testing::Values(0.0, 1.999999, 5.5, 100.1, 1234.5678, std::numeric_limits::min(), + std::numeric_limits::max())); + +TEST_P(Gralloc4TestDouble, Double) { + ASSERT_NO_FATAL_FAILURE(testHelperMetadataType(GetParam(), gralloc4::encodeDouble, gralloc4::decodeDouble)); +} + +class Gralloc4TestString : public testing::TestWithParam { }; + +INSTANTIATE_TEST_CASE_P( + Gralloc4TestStringParams, Gralloc4TestString, + ::testing::Values("name", "aaaaa", "", "abcdefghijklmnopqrstuvwxyz", "0xFF")); + +TEST_P(Gralloc4TestString, String) { + ASSERT_NO_FATAL_FAILURE(testHelperMetadataTypeConst(GetParam(), gralloc4::encodeString, gralloc4::decodeString)); +} + +TEST_P(Gralloc4TestString, Name) { + ASSERT_NO_FATAL_FAILURE(testHelperConst(GetParam(), gralloc4::encodeName, gralloc4::decodeName)); } class Gralloc4TestPixelFormat : public testing::TestWithParam { }; -- GitLab From 430193f390a86d2319decfb3689ca6e8802debf1 Mon Sep 17 00:00:00 2001 From: Iris Chang Date: Wed, 4 Dec 2019 16:25:46 +0800 Subject: [PATCH 0575/1255] libgui: add more information when print BQ log and dump Logs are only debug pupose, BQ_LOG prefix define: When any BQ log appears with same consumer name, it needs more information about BqId, pid to determine whether BQ destoryed and recreate. Dump log: Add more information in dump log to check if the behavior of BQ fulfill the requirement Bug: 145881374 Test: Manual tesing with 'launch and leave arbitrary activiy' and enbale print Verbose log. Test: Manual tesing with 'dumpsys SurfaceFlinger' Change-Id: I9352336df009fb3f26e2549f14feb8f21bad8a52 --- libs/gui/BufferQueueConsumer.cpp | 22 +++++++++++++ libs/gui/BufferQueueCore.cpp | 44 ++++++++++++++++++++++++++ libs/gui/BufferQueueProducer.cpp | 22 +++++++++++++ libs/gui/include/gui/BufferQueueCore.h | 6 ---- 4 files changed, 88 insertions(+), 6 deletions(-) diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 3a7cb44450..6418e8c9a9 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -44,6 +44,28 @@ namespace android { +// Macros for include BufferQueueCore information in log messages +#define BQ_LOGV(x, ...) \ + ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGD(x, ...) \ + ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGI(x, ...) \ + ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGW(x, ...) \ + ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGE(x, ...) \ + ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) + BufferQueueConsumer::BufferQueueConsumer(const sp& core) : mCore(core), mSlots(core->mSlots), diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index d6009d6cd5..3b0120b853 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -42,6 +42,23 @@ namespace android { +// Macros for include BufferQueueCore information in log messages +#define BQ_LOGV(x, ...) \ + ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ + mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) +#define BQ_LOGD(x, ...) \ + ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ + mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) +#define BQ_LOGI(x, ...) \ + ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ + mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) +#define BQ_LOGW(x, ...) \ + ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ + mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) +#define BQ_LOGE(x, ...) \ + ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ + mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) + static String8 getUniqueName() { static volatile int32_t counter = 0; return String8::format("unnamed-%d-%d", getpid(), @@ -54,6 +71,19 @@ static uint64_t getUniqueId() { return id | counter++; } +static status_t getProcessName(int pid, String8& name) { + FILE* fp = fopen(String8::format("/proc/%d/cmdline", pid), "r"); + if (NULL != fp) { + const size_t size = 64; + char proc_name[size]; + fgets(proc_name, size, fp); + fclose(fp); + name = proc_name; + return NO_ERROR; + } + return INVALID_OPERATION; +} + BufferQueueCore::BufferQueueCore() : mMutex(), mIsAbandoned(false), @@ -132,6 +162,20 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const mTransformHintInUse, mAutoPrerotation); outResult->appendFormat("%sFIFO(%zu):\n", prefix.string(), mQueue.size()); + + outResult->appendFormat("%s(mConsumerName=%s, ", prefix.string(), mConsumerName.string()); + + outResult->appendFormat("mConnectedApi=%d, mConsumerUsageBits=%" PRIu64 ", ", mConnectedApi, + mConsumerUsageBits); + + String8 producerProcName = String8("\?\?\?"); + String8 consumerProcName = String8("\?\?\?"); + int32_t pid = getpid(); + getProcessName(mConnectedPid, producerProcName); + getProcessName(pid, consumerProcName); + outResult->appendFormat("mId=%" PRIx64 ", producer=[%d:%s], consumer=[%d:%s])\n", mUniqueId, + mConnectedPid, producerProcName.string(), pid, + consumerProcName.string()); Fifo::const_iterator current(mQueue.begin()); while (current != mQueue.end()) { double timestamp = current->mTimestamp / 1e9; diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index a307d04a16..d3ce06f5fe 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -44,6 +44,28 @@ namespace android { +// Macros for include BufferQueueCore information in log messages +#define BQ_LOGV(x, ...) \ + ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGD(x, ...) \ + ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGI(x, ...) \ + ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGW(x, ...) \ + ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) +#define BQ_LOGE(x, ...) \ + ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ + ##__VA_ARGS__) + static constexpr uint32_t BQ_LAYER_COUNT = 1; BufferQueueProducer::BufferQueueProducer(const sp& core, diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 3c960894da..557c28b1b7 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -34,12 +34,6 @@ #include #include -#define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGI(x, ...) ALOGI("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) - #define ATRACE_BUFFER_INDEX(index) \ do { \ if (ATRACE_ENABLED()) { \ -- GitLab From 011538f1ed7d102dc1e96911466805cdea63eecd Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Fri, 20 Dec 2019 14:37:21 -0800 Subject: [PATCH 0576/1255] GpuStats: track whether the app creates ES1 context Bug: 146661131 Test: adb shell dumpsys gpu Change-Id: I54e6953368ea8e2ced7477ee64796580dc14c39e --- libs/graphicsenv/GpuStatsInfo.cpp | 3 +++ libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h | 2 ++ opengl/libs/EGL/egl_platform_entries.cpp | 2 ++ services/gpuservice/gpustats/GpuStats.cpp | 3 +++ 4 files changed, 10 insertions(+) diff --git a/libs/graphicsenv/GpuStatsInfo.cpp b/libs/graphicsenv/GpuStatsInfo.cpp index 85137f5ca9..f2d0943e86 100644 --- a/libs/graphicsenv/GpuStatsInfo.cpp +++ b/libs/graphicsenv/GpuStatsInfo.cpp @@ -87,6 +87,7 @@ status_t GpuStatsAppInfo::writeToParcel(Parcel* parcel) const { if ((status = parcel->writeInt64Vector(angleDriverLoadingTime)) != OK) return status; if ((status = parcel->writeBool(cpuVulkanInUse)) != OK) return status; if ((status = parcel->writeBool(falsePrerotation)) != OK) return status; + if ((status = parcel->writeBool(gles1InUse)) != OK) return status; return OK; } @@ -99,6 +100,7 @@ status_t GpuStatsAppInfo::readFromParcel(const Parcel* parcel) { if ((status = parcel->readInt64Vector(&angleDriverLoadingTime)) != OK) return status; if ((status = parcel->readBool(&cpuVulkanInUse)) != OK) return status; if ((status = parcel->readBool(&falsePrerotation)) != OK) return status; + if ((status = parcel->readBool(&gles1InUse)) != OK) return status; return OK; } @@ -108,6 +110,7 @@ std::string GpuStatsAppInfo::toString() const { StringAppendF(&result, "driverVersionCode = %" PRIu64 "\n", driverVersionCode); StringAppendF(&result, "cpuVulkanInUse = %d\n", cpuVulkanInUse); StringAppendF(&result, "falsePrerotation = %d\n", falsePrerotation); + StringAppendF(&result, "gles1InUse = %d\n", gles1InUse); result.append("glDriverLoadingTime:"); for (int32_t loadingTime : glDriverLoadingTime) { StringAppendF(&result, " %d", loadingTime); diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h index 7959652189..9aba69fd07 100644 --- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h +++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h @@ -71,6 +71,7 @@ public: std::vector angleDriverLoadingTime = {}; bool cpuVulkanInUse = false; bool falsePrerotation = false; + bool gles1InUse = false; }; /* @@ -95,6 +96,7 @@ public: enum Stats { CPU_VULKAN_IN_USE = 0, FALSE_PREROTATION = 1, + GLES_1_IN_USE = 2, }; GpuStatsInfo() = default; diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index 1fc7927e12..5162ba4abf 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -984,6 +984,8 @@ EGLContext eglCreateContextImpl(EGLDisplay dpy, EGLConfig config, if (attr == EGL_CONTEXT_CLIENT_VERSION) { if (value == 1) { version = egl_connection_t::GLESv1_INDEX; + android::GraphicsEnv::getInstance().setTargetStats( + android::GpuStatsInfo::Stats::GLES_1_IN_USE); } else if (value == 2 || value == 3) { version = egl_connection_t::GLESv2_INDEX; } diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp index 67babd496f..7fff6edc38 100644 --- a/services/gpuservice/gpustats/GpuStats.cpp +++ b/services/gpuservice/gpustats/GpuStats.cpp @@ -145,6 +145,9 @@ void GpuStats::insertTargetStats(const std::string& appPackageName, case GpuStatsInfo::Stats::FALSE_PREROTATION: mAppStats[appStatsKey].falsePrerotation = true; break; + case GpuStatsInfo::Stats::GLES_1_IN_USE: + mAppStats[appStatsKey].gles1InUse = true; + break; default: break; } -- GitLab From a483b4aae955319e48fc3837eae58f2049c63f4b Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 12 Dec 2019 15:07:52 -0800 Subject: [PATCH 0577/1255] Draw shadows when the casting layer is occluded or transparent Ignore transparent region when generating the composition layer for shadows. Client may provide transparent region hints but the shadow should be drawn over the entire layer. Solves an issue with YouTube in PiP which sets a transparent region where the SurfaceView is shown causing a shadow of incorrect size to be drawn. Draw shadows even if the layer is completely occluded by another layer. The layer will not be composed in this case causing the shadow to not be drawn either. So extend its visible region by the shadow length so we can check if the shadows will be occluded as well. Bug: 136561771 Test: atest libcompositionengine_test Test: manual tests with pip overriding shadows to be drawn by sf Change-Id: I4c6cae1716caebe46119ebd1643d8b5e3eda56c3 --- .../LayerFECompositionState.h | 3 + .../impl/OutputLayerCompositionState.h | 3 + .../src/LayerFECompositionState.cpp | 3 + .../CompositionEngine/src/Output.cpp | 42 ++++- .../src/OutputLayerCompositionState.cpp | 3 + .../CompositionEngine/tests/OutputTest.cpp | 143 ++++++++++++++++++ services/surfaceflinger/Layer.cpp | 2 + 7 files changed, 191 insertions(+), 8 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 2ba781d924..a64fdbf88a 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -79,6 +79,9 @@ struct LayerFECompositionState { // The bounds of the layer in layer local coordinates FloatRect geomLayerBounds; + // length of the shadow in screen space + float shadowRadius; + /* * Geometry state */ diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index 11cfccc504..00baa8963d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -52,6 +52,9 @@ struct OutputLayerCompositionState { // The visibleRegion transformed to output space Region outputSpaceVisibleRegion; + // Region cast by the layer's shadow + Region shadowRegion; + // If true, client composition will be used on this output bool forceClientComposition{false}; diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp index 1ca03dca5f..e74052994a 100644 --- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp @@ -51,6 +51,9 @@ void LayerFECompositionState::dump(std::string& out) const { out.append(" "); dumpVal(out, "geomLayerBounds", geomLayerBounds); + out.append(" "); + dumpVal(out, "shadowRadius", shadowRadius); + out.append("\n "); dumpVal(out, "blend", toString(blendMode), blendMode); dumpVal(out, "alpha", alpha); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 7e5a720875..28d26536a8 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -408,6 +408,11 @@ void Output::ensureOutputLayerIfVisible(std::shared_ptr

Two bits are used to encode alpha. Use {@link ANDROID_BITMAP_FLAGS_ALPHA_MASK} + * and {@link ANDROID_BITMAP_FLAGS_ALPHA_SHIFT} to retrieve them.

+ * + *

One bit is used to encode whether the Bitmap uses the HARDWARE Config. Use + * {@link ANDROID_BITMAP_FLAGS_IS_HARDWARE} to know.

+ * + *

These flags were introduced in API level 30.

+ */ uint32_t flags; } AndroidBitmapInfo; /** - * Given a java bitmap object, fill out the AndroidBitmapInfo struct for it. + * Given a java bitmap object, fill out the {@link AndroidBitmapInfo} struct for it. * If the call fails, the info parameter will be ignored. */ int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, -- GitLab From 453932d54dbc5ac5c78e92d5fbcbcd3b3a340c2e Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Mon, 3 Feb 2020 20:42:25 -0800 Subject: [PATCH 0764/1255] Kawase blur filter For better performance and more stable large radius. Also removing LensFilter given that performance was not good enough for real time effects. Test: visual (on Kawase and Gaussian) Bug: 148614710 Change-Id: I81fd2cce030dafb8d87a7c65606632ac1ecfa113 --- libs/renderengine/Android.bp | 2 +- libs/renderengine/gl/GLESRenderEngine.cpp | 9 +- libs/renderengine/gl/GLESRenderEngine.h | 2 +- libs/renderengine/gl/filters/BlurFilter.cpp | 16 +- libs/renderengine/gl/filters/BlurFilter.h | 2 +- .../gl/filters/KawaseBlurFilter.cpp | 139 +++++++++++ .../{LensBlurFilter.h => KawaseBlurFilter.h} | 39 ++- .../gl/filters/LensBlurFilter.cpp | 225 ------------------ 8 files changed, 175 insertions(+), 259 deletions(-) create mode 100644 libs/renderengine/gl/filters/KawaseBlurFilter.cpp rename libs/renderengine/gl/filters/{LensBlurFilter.h => KawaseBlurFilter.h} (54%) delete mode 100644 libs/renderengine/gl/filters/LensBlurFilter.cpp diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 4c7b629197..3d77059b9d 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -59,7 +59,7 @@ filegroup { "gl/Program.cpp", "gl/ProgramCache.cpp", "gl/filters/BlurFilter.cpp", - "gl/filters/LensBlurFilter.cpp", + "gl/filters/KawaseBlurFilter.cpp", "gl/filters/GaussianBlurFilter.cpp", "gl/filters/GenericProgram.cpp", ], diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 69003fb86f..e523836c59 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -51,7 +51,7 @@ #include "ProgramCache.h" #include "filters/BlurFilter.h" #include "filters/GaussianBlurFilter.h" -#include "filters/LensBlurFilter.h" +#include "filters/KawaseBlurFilter.h" extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); @@ -285,6 +285,9 @@ std::unique_ptr GLESRenderEngine::create(const RenderEngineCre // now figure out what version of GL did we actually get GlesVersion version = parseGlesVersion(extensions.getVersion()); + LOG_ALWAYS_FATAL_IF(args.supportsBackgroundBlur && version < GLES_VERSION_3_0, + "Blurs require OpenGL ES 3.0. Please unset ro.surface_flinger.supports_background_blur"); + // initialize the renderer while GL is current std::unique_ptr engine; switch (version) { @@ -428,11 +431,11 @@ GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisp if (args.supportsBackgroundBlur) { char isGaussian[PROPERTY_VALUE_MAX]; - property_get("debug.sf.gaussianBlur", isGaussian, "1"); + property_get("debug.sf.gaussianBlur", isGaussian, "0"); if (atoi(isGaussian)) { mBlurFilter = new GaussianBlurFilter(*this); } else { - mBlurFilter = new LensBlurFilter(*this); + mBlurFilter = new KawaseBlurFilter(*this); } checkErrors("BlurFilter creation"); } diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 4fc457f904..ebf78fe6c8 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -262,7 +262,7 @@ private: friend class GLFramebuffer; friend class BlurFilter; friend class GaussianBlurFilter; - friend class LensBlurFilter; + friend class KawaseBlurFilter; friend class GenericProgram; std::unique_ptr mFlushTracer; std::unique_ptr mImageManager = std::make_unique(this); diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index 48c256065c..f8b0a7a891 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -71,8 +71,18 @@ status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t ra } void BlurFilter::drawMesh(GLuint uv, GLuint position) { - GLfloat positions[] = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f}; - GLfloat texCoords[] = {0.0, 0.0, 0.0, 1.0f, 1.0f, 1.0f, 1.0f, 0}; + static constexpr auto size = 2.0f; + static constexpr auto translation = 1.0f; + GLfloat positions[] = { + translation-size, -translation-size, + translation-size, -translation+size, + translation+size, -translation+size + }; + GLfloat texCoords[] = { + 0.0f, 0.0f-translation, + 0.0f, size-translation, + size, size-translation + }; // set attributes glEnableVertexAttribArray(uv); @@ -82,7 +92,7 @@ void BlurFilter::drawMesh(GLuint uv, GLuint position) { positions); // draw mesh - glDrawArrays(GL_TRIANGLE_FAN, 0 /* first */, 4 /* count */); + glDrawArrays(GL_TRIANGLES, 0 /* first */, 3 /* count */); mEngine.checkErrors("Drawing blur mesh"); } diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h index 6889939518..67b3895262 100644 --- a/libs/renderengine/gl/filters/BlurFilter.h +++ b/libs/renderengine/gl/filters/BlurFilter.h @@ -33,7 +33,7 @@ public: static constexpr float kFboScale = 0.25f; // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited // image, up to this radius. - static constexpr float kMaxCrossFadeRadius = 15.0f; + static constexpr float kMaxCrossFadeRadius = 30.0f; explicit BlurFilter(GLESRenderEngine& engine); virtual ~BlurFilter(){}; diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp new file mode 100644 index 0000000000..fc26bccc52 --- /dev/null +++ b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp @@ -0,0 +1,139 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "KawaseBlurFilter.h" +#include +#include +#include +#include +#include + +#include + +namespace android { +namespace renderengine { +namespace gl { + +KawaseBlurFilter::KawaseBlurFilter(GLESRenderEngine& engine) + : BlurFilter(engine), mFbo(engine), mProgram(engine) { + mProgram.compile(getVertexShader(), getFragmentShader()); + mPosLoc = mProgram.getAttributeLocation("aPosition"); + mUvLoc = mProgram.getAttributeLocation("aUV"); + mTextureLoc = mProgram.getUniformLocation("uTexture"); + mOffsetLoc = mProgram.getUniformLocation("uOffset"); +} + +void KawaseBlurFilter::allocateTextures() { + mFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight()); +} + +status_t KawaseBlurFilter::prepare() { + ATRACE_NAME("KawaseBlurFilter::prepare"); + + if (mFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { + ALOGE("Invalid FBO"); + return mFbo.getStatus(); + } + if (!mProgram.isValid()) { + ALOGE("Invalid shader"); + return GL_INVALID_OPERATION; + } + + blit(mCompositionFbo, mBlurredFbo); + + // Kawase is an approximation of Gaussian, but it behaves differently from it. + // A radius transformation is required for approximating them, and also to introduce + // non-integer steps, necessary to smoothly interpolate large radii. + auto radius = mRadius / 6.0f; + + // Calculate how many passes we'll do, based on the radius. + // Too many passes will make the operation expensive. + auto passes = min(kMaxPasses, (uint32_t)ceil(radius)); + + // We'll ping pong between our textures, to accumulate the result of various offsets. + mProgram.useProgram(); + GLFramebuffer* draw = &mFbo; + GLFramebuffer* read = &mBlurredFbo; + float stepX = radius / (float)mCompositionFbo.getBufferWidth() / (float)passes; + float stepY = radius / (float)mCompositionFbo.getBufferHeight() / (float)passes; + glActiveTexture(GL_TEXTURE0); + glUniform1i(mTextureLoc, 0); + for (auto i = 0; i < passes; i++) { + ATRACE_NAME("KawaseBlurFilter::renderPass"); + draw->bind(); + + glViewport(0, 0, draw->getBufferWidth(), draw->getBufferHeight()); + glBindTexture(GL_TEXTURE_2D, read->getTextureName()); + glUniform2f(mOffsetLoc, stepX * i, stepY * i); + mEngine.checkErrors("Setting uniforms"); + + drawMesh(mUvLoc, mPosLoc); + + // Swap buffers for next iteration + auto tmp = draw; + draw = read; + read = tmp; + } + + // Copy texture, given that we're expected to end on mBlurredFbo. + if (draw == &mBlurredFbo) { + blit(mFbo, mBlurredFbo); + } + + // Cleanup + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + return NO_ERROR; +} + +string KawaseBlurFilter::getFragmentShader() const { + return R"SHADER(#version 310 es + precision mediump float; + + uniform sampler2D uTexture; + highp uniform vec2 uOffset; + + highp in vec2 vUV; + out vec4 fragColor; + + vec4 kawaseBlur() { + return (texture(uTexture, vec2(-1.0, 1.0) * uOffset + vUV, 0.0) + + texture(uTexture, uOffset + vUV, 0.0) + + texture(uTexture, vec2(1.0, -1.0) * uOffset + vUV, 0.0) + + texture(uTexture, vec2(-1.0) * uOffset + vUV, 0.0)) + * 0.25; + } + + void main() { + fragColor = kawaseBlur(); + } + )SHADER"; +} + +void KawaseBlurFilter::blit(GLFramebuffer& read, GLFramebuffer& draw) const { + read.bindAsReadBuffer(); + draw.bindAsDrawBuffer(); + glBlitFramebuffer(0, 0, read.getBufferWidth(), read.getBufferHeight(), 0, 0, + draw.getBufferWidth(), draw.getBufferHeight(), GL_COLOR_BUFFER_BIT, + GL_LINEAR); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +} // namespace gl +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/gl/filters/LensBlurFilter.h b/libs/renderengine/gl/filters/KawaseBlurFilter.h similarity index 54% rename from libs/renderengine/gl/filters/LensBlurFilter.h rename to libs/renderengine/gl/filters/KawaseBlurFilter.h index 1620c5a556..ec81f81229 100644 --- a/libs/renderengine/gl/filters/LensBlurFilter.h +++ b/libs/renderengine/gl/filters/KawaseBlurFilter.h @@ -1,5 +1,5 @@ /* - * Copyright 2019 The Android Open Source Project + * 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. @@ -28,38 +28,27 @@ namespace android { namespace renderengine { namespace gl { -class LensBlurFilter : public BlurFilter { +class KawaseBlurFilter : public BlurFilter { public: - explicit LensBlurFilter(GLESRenderEngine& engine); + static constexpr uint32_t kMaxPasses = 8; + + explicit KawaseBlurFilter(GLESRenderEngine& engine); status_t prepare() override; void allocateTextures() override; private: - string getFragmentShader(bool forComposition) const; - - // Intermediate render pass - GLFramebuffer mVerticalDiagonalPassFbo; + string getFragmentShader() const; + void blit(GLFramebuffer& read, GLFramebuffer& draw) const; - // Vertical/diagonal pass and its uniforms - GenericProgram mVerticalDiagonalProgram; - GLuint mVDPosLoc; - GLuint mVDUvLoc; - GLuint mVDTexture0Loc; - GLuint mVDSizeLoc; - GLuint mVDRadiusLoc; - GLuint mVDNumSamplesLoc; + GLFramebuffer mFbo; - // Blur composition pass and its uniforms - GenericProgram mCombinedProgram; - GLuint mCPosLoc; - GLuint mCUvLoc; - GLuint mCTexture0Loc; - GLuint mCTexture1Loc; - GLuint mCSizeLoc; - GLuint mCRadiusLoc; - GLuint mCNumSamplesLoc; + GenericProgram mProgram; + GLuint mPosLoc; + GLuint mUvLoc; + GLuint mTextureLoc; + GLuint mOffsetLoc; }; } // namespace gl } // namespace renderengine -} // namespace android \ No newline at end of file +} // namespace android diff --git a/libs/renderengine/gl/filters/LensBlurFilter.cpp b/libs/renderengine/gl/filters/LensBlurFilter.cpp deleted file mode 100644 index fb29fbb48b..0000000000 --- a/libs/renderengine/gl/filters/LensBlurFilter.cpp +++ /dev/null @@ -1,225 +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. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "LensBlurFilter.h" -#include -#include -#include -#include -#include -#include - -#include - -namespace android { -namespace renderengine { -namespace gl { - -// Number of blur samples in shader (for loop) -static constexpr auto kNumSamples = 12; - -LensBlurFilter::LensBlurFilter(GLESRenderEngine& engine) - : BlurFilter(engine), - mVerticalDiagonalPassFbo(engine, true /* multiTarget */), - mVerticalDiagonalProgram(engine), - mCombinedProgram(engine) { - mVerticalDiagonalProgram.compile(getVertexShader(), getFragmentShader(false)); - mCombinedProgram.compile(getVertexShader(), getFragmentShader(true)); - - mVDPosLoc = mVerticalDiagonalProgram.getAttributeLocation("aPosition"); - mVDUvLoc = mVerticalDiagonalProgram.getAttributeLocation("aUV"); - mVDTexture0Loc = mVerticalDiagonalProgram.getUniformLocation("uTexture0"); - mVDSizeLoc = mVerticalDiagonalProgram.getUniformLocation("uSize"); - mVDRadiusLoc = mVerticalDiagonalProgram.getUniformLocation("uRadius"); - mVDNumSamplesLoc = mVerticalDiagonalProgram.getUniformLocation("uNumSamples"); - - mCPosLoc = mCombinedProgram.getAttributeLocation("aPosition"); - mCUvLoc = mCombinedProgram.getAttributeLocation("aUV"); - mCTexture0Loc = mCombinedProgram.getUniformLocation("uTexture0"); - mCTexture1Loc = mCombinedProgram.getUniformLocation("uTexture1"); - mCSizeLoc = mCombinedProgram.getUniformLocation("uSize"); - mCRadiusLoc = mCombinedProgram.getUniformLocation("uRadius"); - mCNumSamplesLoc = mCombinedProgram.getUniformLocation("uNumSamples"); -} - -void LensBlurFilter::allocateTextures() { - mVerticalDiagonalPassFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), - mBlurredFbo.getBufferHeight()); -} - -status_t LensBlurFilter::prepare() { - ATRACE_NAME("LensBlurFilter::prepare"); - - if (mVerticalDiagonalPassFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid vertical-diagonal FBO"); - return mVerticalDiagonalPassFbo.getStatus(); - } - if (!mVerticalDiagonalProgram.isValid()) { - ALOGE("Invalid vertical-diagonal shader"); - return GL_INVALID_OPERATION; - } - if (!mCombinedProgram.isValid()) { - ALOGE("Invalid blur shader"); - return GL_INVALID_OPERATION; - } - - // First, we'll apply the vertical/diagonal pass, that receives the flattened background layers, - // and writes the output to two textures (vertical and diagonal.) - mVerticalDiagonalPassFbo.bind(); - mVerticalDiagonalProgram.useProgram(); - - // set uniforms - auto width = mVerticalDiagonalPassFbo.getBufferWidth(); - auto height = mVerticalDiagonalPassFbo.getBufferHeight(); - auto radiusF = fmax(1.0f, mRadius * kFboScale); - glViewport(0, 0, width, height); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName()); - glUniform1i(mVDTexture0Loc, 0); - glUniform2f(mVDSizeLoc, mDisplayWidth, mDisplayHeight); - glUniform1f(mVDRadiusLoc, radiusF); - glUniform1i(mVDNumSamplesLoc, kNumSamples); - mEngine.checkErrors("Setting vertical-diagonal pass uniforms"); - - drawMesh(mVDUvLoc, mVDPosLoc); - - // Now we'll combine the multi render pass into a blurred image - mBlurredFbo.bind(); - mCombinedProgram.useProgram(); - - // set uniforms - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mVerticalDiagonalPassFbo.getTextureName()); - glUniform1i(mCTexture0Loc, 0); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, mVerticalDiagonalPassFbo.getSecondaryTextureName()); - glUniform1i(mCTexture1Loc, 1); - glUniform2f(mCSizeLoc, mDisplayWidth, mDisplayHeight); - glUniform1f(mCRadiusLoc, radiusF); - glUniform1i(mCNumSamplesLoc, kNumSamples); - mEngine.checkErrors("Setting vertical pass uniforms"); - - drawMesh(mCUvLoc, mCPosLoc); - - // reset active texture - mBlurredFbo.unbind(); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, 0); - - // unbind program - glUseProgram(0); - - return NO_ERROR; -} - -string LensBlurFilter::getFragmentShader(bool forComposition) const { - string shader = "#version 310 es\n#define DIRECTION "; - shader += (forComposition ? "1" : "0"); - shader += R"SHADER( - precision mediump float; - #define PI 3.14159265359 - - uniform sampler2D uTexture0; - uniform vec2 uSize; - uniform float uRadius; - uniform int uNumSamples; - - highp in vec2 vUV; - - #if DIRECTION == 0 - layout(location = 0) out vec4 fragColor0; - layout(location = 1) out vec4 fragColor1; - #else - uniform sampler2D uTexture1; - out vec4 fragColor; - #endif - - const vec2 verticalMult = vec2(cos(PI / 2.0), sin(PI / 2.0)); - const vec2 diagonalMult = vec2(cos(-PI / 6.0), sin(-PI / 6.0)); - const vec2 diagonal2Mult = vec2(cos(-5.0 * PI / 6.0), sin(-5.0 * PI / 6.0)); - - vec3 blur(const sampler2D tex, vec2 uv, const vec2 direction, float radius, - int samples, float intensity) { - vec3 finalColor = vec3(0.0); - uv += direction * 0.5; - - for (int i = 0; i < samples; i++){ - float delta = radius * float(i) / float(samples); - vec3 color = texture(tex, uv + direction * delta).rgb; - color.rgb *= intensity; - finalColor += color; - } - - return finalColor / float(samples); - } - - vec3 blur(const sampler2D tex, vec2 uv, const vec2 direction, float radius, - int samples) { - return blur(tex, uv, direction, radius, samples, 1.0); - } - - vec4[2] verticalDiagonalLensBlur (vec2 uv, sampler2D texture, vec2 resolution, - float radius, int samples) { - // Vertical Blur - vec2 blurDirV = 1.0 / resolution.xy * verticalMult; - vec3 colorV = blur(texture, uv, blurDirV, radius, samples); - - // Diagonal Blur - vec2 blurDirD = 1.0 / resolution.xy * diagonalMult; - vec3 colorD = blur(texture, uv, blurDirD, radius, samples); - - vec4 composed[2]; - composed[0] = vec4(colorV, 1.0); - // added * 0.5, to remap - composed[1] = vec4((colorD + colorV) * 0.5, 1.0); - - return composed; - } - - vec4 rhombiLensBlur (vec2 uv, sampler2D texture0, sampler2D texture1, vec2 resolution, - float radius, int samples) { - vec2 blurDirection1 = 1.0 / resolution.xy * diagonalMult; - vec3 color1 = blur(texture0, uv, blurDirection1, radius, samples); - - vec2 blurDirection2 = 1.0 / resolution.xy * diagonal2Mult; - vec3 color2 = blur(texture1, uv, blurDirection2, radius, samples, 2.0); - - return vec4((color1 + color2) * 0.33, 1.0); - } - - void main() { - #if DIRECTION == 0 - // First pass: outputs two textures - vec4 colorOut[] = verticalDiagonalLensBlur(vUV, uTexture0, uSize, uRadius, uNumSamples); - fragColor0 = colorOut[0]; - fragColor1 = colorOut[1]; - #else - // Second pass: combines both textures into a blurred one. - fragColor = rhombiLensBlur(vUV, uTexture0, uTexture1, uSize, uRadius, uNumSamples); - #endif - } - - )SHADER"; - return shader; -} - -} // namespace gl -} // namespace renderengine -} // namespace android -- GitLab From 48da0709f8a45ab7a1912535bffd97e6f675f048 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 4 Feb 2020 15:59:25 -0800 Subject: [PATCH 0765/1255] SurfaceFlinger: rename use_smart_90_for_video flag Rename use_smart_90_for_video -> use_content_detection_for_refresh_rate to better describe what it controls. Test: Play video and observe the refresh rate Change-Id: I5ae03073bd670d0b3bc7f2861cbf3ec0d28efbe7 --- services/surfaceflinger/Scheduler/Scheduler.cpp | 3 ++- .../surfaceflinger/SurfaceFlingerProperties.cpp | 14 ++++++++++++-- services/surfaceflinger/SurfaceFlingerProperties.h | 2 +- .../sysprop/SurfaceFlingerProperties.sysprop | 12 ++++++++++++ .../api/SurfaceFlingerProperties-current.txt | 5 +++++ 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index bc4f805d5e..19f3f9840b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -108,7 +108,8 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, mUseContentDetectionV2(useContentDetectionV2) { using namespace sysprop; - if (property_get_bool("debug.sf.use_smart_90_for_video", 0) || use_smart_90_for_video(false)) { + if (property_get_bool("debug.sf.use_content_detection_for_refresh_rate", 0) || + use_content_detection_for_refresh_rate(false)) { if (mUseContentDetectionV2) { mLayerHistory = std::make_unique(); } else { diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index b4716eb61e..688606f0da 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -258,8 +259,17 @@ int32_t set_display_power_timer_ms(int32_t defaultValue) { return defaultValue; } -bool use_smart_90_for_video(bool defaultValue) { - auto temp = SurfaceFlingerProperties::use_smart_90_for_video(); +bool use_content_detection_for_refresh_rate(bool defaultValue) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + auto smart_90_deprecated = SurfaceFlingerProperties::use_smart_90_for_video(); +#pragma clang diagnostic pop + if (smart_90_deprecated.has_value()) { + ALOGW("Using deprecated use_smart_90_for_video sysprop. Value: %d", *smart_90_deprecated); + return *smart_90_deprecated; + } + + auto temp = SurfaceFlingerProperties::use_content_detection_for_refresh_rate(); if (temp.has_value()) { return *temp; } diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index e394ccab7b..440df49d94 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -81,7 +81,7 @@ int32_t set_touch_timer_ms(int32_t defaultValue); int32_t set_display_power_timer_ms(int32_t defaultValue); -bool use_smart_90_for_video(bool defaultValue); +bool use_content_detection_for_refresh_rate(bool defaultValue); bool enable_protected_contents(bool defaultValue); diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index ed2b220e86..c839985365 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -344,14 +344,26 @@ prop { prop_name: "ro.surface_flinger.set_display_power_timer_ms" } +# useContentDetectionForRefreshRate indicates whether Scheduler should detect content FPS, and try +# to adjust the screen refresh rate based on that. +prop { + api_name: "use_content_detection_for_refresh_rate" + type: Boolean + scope: Public + access: Readonly + prop_name: "ro.surface_flinger.use_content_detection_for_refresh_rate" +} + # useSmart90ForVideo indicates whether Scheduler should detect content FPS, and try to adjust the # screen refresh rate based on that. +# Replaced by useContentDetectionForRefreshRate prop { api_name: "use_smart_90_for_video" type: Boolean scope: Public access: Readonly prop_name: "ro.surface_flinger.use_smart_90_for_video" + deprecated: true } prop { diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt index d24ad18eaf..edbdd9050c 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -111,6 +111,10 @@ props { api_name: "use_color_management" prop_name: "ro.surface_flinger.use_color_management" } + prop { + api_name: "use_content_detection_for_refresh_rate" + prop_name: "ro.surface_flinger.use_content_detection_for_refresh_rate" + } prop { api_name: "use_context_priority" prop_name: "ro.surface_flinger.use_context_priority" @@ -118,6 +122,7 @@ props { prop { api_name: "use_smart_90_for_video" prop_name: "ro.surface_flinger.use_smart_90_for_video" + deprecated: true } prop { api_name: "use_vr_flinger" -- GitLab From 3f6a2062120308f02f6feae5591b3c33a21f329f Mon Sep 17 00:00:00 2001 From: Ana Krulec Date: Thu, 23 Jan 2020 15:48:01 -0800 Subject: [PATCH 0766/1255] SF: Remove refresh_rate_switching flag. With a fix. ag/9294789 introduce a flag to only allow refresh rate switching on the devices that have that flag set to true, because it broke devices that didn't support multiple refresh rates, and Android TV. LocalDisplayAdapter sets the refresh rate to default when booting the phone, so no need for that in SF anymore. Test: Turn off Smooth display (see b/148821456), device doesn't crash. Test: Install on devices that doesn't have multiple refresh rates. Test: Run SF unittests. Test: Turn on all the flags, and run through set of examples: Video playback stays at 60. Camera stays at 60. Maps play at 60. Low brightness stays at 90. Swappy successfully switches between 60 & 90. Test: Turn off all the flags, and rerun the examples from previous. If applications requested the change, the change is honored, otherwise we stay at default (set by DM). Test: Ask Android TV team to test the patch. Bug: 148427603 Bug: 148821456 Change-Id: I5bb964572d93e5cb78d7b75054b900917be563b0 --- .../Scheduler/RefreshRateConfigs.cpp | 20 +--- .../Scheduler/RefreshRateConfigs.h | 10 +- .../surfaceflinger/Scheduler/Scheduler.cpp | 51 ++++++---- services/surfaceflinger/SurfaceFlinger.cpp | 40 +++----- .../SurfaceFlingerProperties.cpp | 5 + .../sysprop/SurfaceFlingerProperties.sysprop | 1 + .../api/SurfaceFlingerProperties-current.txt | 1 + .../tests/unittests/LayerHistoryTest.cpp | 3 +- .../tests/unittests/LayerHistoryTestV2.cpp | 3 +- .../unittests/RefreshRateConfigsTest.cpp | 93 ++++--------------- .../tests/unittests/RefreshRateStatsTest.cpp | 4 +- .../tests/unittests/SchedulerTest.cpp | 3 +- .../tests/unittests/TestableSurfaceFlinger.h | 3 +- 13 files changed, 82 insertions(+), 155 deletions(-) diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 0f55615d50..c73e825d51 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -216,20 +216,12 @@ const AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const { const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const { std::lock_guard lock(mLock); - if (!mRefreshRateSwitching) { - return *mCurrentRefreshRate; - } else { - return *mAvailableRefreshRates.front(); - } + 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 { @@ -242,18 +234,14 @@ void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) { mCurrentRefreshRate = &mRefreshRates.at(configId); } -RefreshRateConfigs::RefreshRateConfigs(bool refreshRateSwitching, - const std::vector& configs, - HwcConfigIndexType currentHwcConfig) - : mRefreshRateSwitching(refreshRateSwitching) { +RefreshRateConfigs::RefreshRateConfigs(const std::vector& configs, + HwcConfigIndexType currentHwcConfig) { init(configs, currentHwcConfig); } RefreshRateConfigs::RefreshRateConfigs( - bool refreshRateSwitching, const std::vector>& configs, - HwcConfigIndexType currentConfigId) - : mRefreshRateSwitching(refreshRateSwitching) { + HwcConfigIndexType currentConfigId) { std::vector 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 c4dea0d298..fc959597a3 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -94,9 +94,6 @@ public: // 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 @@ -167,10 +164,9 @@ public: nsecs_t vsyncPeriod = 0; }; - RefreshRateConfigs(bool refreshRateSwitching, const std::vector& configs, + RefreshRateConfigs(const std::vector& configs, HwcConfigIndexType currentHwcConfig); - RefreshRateConfigs(bool refreshRateSwitching, - const std::vector>& configs, + RefreshRateConfigs(const std::vector>& configs, HwcConfigIndexType currentConfigId); private: @@ -208,8 +204,6 @@ private: 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 bc4f805d5e..49a269fe5f 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -530,8 +530,6 @@ void Scheduler::dump(std::string& result) const { 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", @@ -575,35 +573,44 @@ bool Scheduler::layerHistoryHasClientSpecifiedFrameRate() { } HwcConfigIndexType Scheduler::calculateRefreshRateType() { - if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) { - return mRefreshRateConfigs.getCurrentRefreshRate().configId; + // 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 the layer history doesn't have the frame rate specified, use the old path. NOTE: // if we remove the kernel idle timer, and use our internal idle timer, this code will have to // be refactored. - if (!layerHistoryHasClientSpecifiedFrameRate()) { - // If Display Power is not in normal operation we want to be in performance mode. - // When coming back to normal mode, a grace period is given with DisplayPowerTimer - if (!mFeatures.isDisplayPowerStateNormal || - mFeatures.displayPowerTimer == TimerState::Reset) { - return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId; - } + // 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; + } - // As long as touch is active we want to be in performance mode - if (mFeatures.touch == TouchState::Active) { - 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; + } - // 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 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 (!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; } @@ -623,6 +630,10 @@ HwcConfigIndexType Scheduler::calculateRefreshRateType() { std::optional Scheduler::getPreferredConfigId() { std::lock_guard lock(mFeatureStateLock); + // Make sure that the default config ID is first updated, before returned. + if (mFeatures.configId.has_value()) { + mFeatures.configId = calculateRefreshRateType(); + } return mFeatures.configId; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 33d85cb420..e0c3372633 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -556,12 +556,6 @@ void SurfaceFlinger::bootFinished() 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(*this); mRefreshRateOverlay->changeRefreshRate(mRefreshRateConfigs->getCurrentRefreshRate()); @@ -2720,8 +2714,7 @@ void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { auto currentConfig = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(primaryDisplayId)); mRefreshRateConfigs = - std::make_unique(refresh_rate_switching(false), - getHwComposer().getConfigs( + std::make_unique(getHwComposer().getConfigs( primaryDisplayId), currentConfig); mRefreshRateStats = @@ -5706,26 +5699,19 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const sponConfigChanged(mAppConnectionHandle, display->getId()->value, display->getActiveConfig(), vsyncPeriod); - 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}); - } + 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}); } else { - ALOGV("switching to config %d", defaultConfig.value()); - setDesiredActiveConfig({defaultConfig, Scheduler::ConfigEvent::Changed}); + LOG_ALWAYS_FATAL("Desired config not allowed: %d", preferredRefreshRate.configId.value()); } return NO_ERROR; diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index b4716eb61e..e199b53dce 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -227,8 +228,12 @@ int64_t color_space_agnostic_dataspace(Dataspace defaultValue) { } bool refresh_rate_switching(bool defaultValue) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" auto temp = SurfaceFlingerProperties::refresh_rate_switching(); +#pragma clang diagnostic pop if (temp.has_value()) { + ALOGW("Using deprecated refresh_rate_switching sysprop. Value: %d", *temp); return *temp; } return defaultValue; diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index ed2b220e86..764181abbf 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -311,6 +311,7 @@ prop { scope: System access: Readonly prop_name: "ro.surface_flinger.refresh_rate_switching" + deprecated: true } prop { diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt index d24ad18eaf..bee99f40e3 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -75,6 +75,7 @@ props { prop { api_name: "refresh_rate_switching" prop_name: "ro.surface_flinger.refresh_rate_switching" + deprecated: true } prop { api_name: "running_without_sync_framework" diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index d9481be1a1..18e9941385 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -63,8 +63,7 @@ protected: auto createLayer() { return sp(new mock::MockLayer(mFlinger.flinger())); } - RefreshRateConfigs mConfigs{true, - { + RefreshRateConfigs mConfigs{{ RefreshRateConfigs::InputConfig{HwcConfigIndexType(0), HwcConfigGroupType(0), LO_FPS_PERIOD}, diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp index bb3bbad6c2..959c256262 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp @@ -71,8 +71,7 @@ protected: auto createLayer() { return sp(new mock::MockLayer(mFlinger.flinger())); } - RefreshRateConfigs mConfigs{true, - { + RefreshRateConfigs mConfigs{{ RefreshRateConfigs::InputConfig{HwcConfigIndexType(0), HwcConfigGroupType(0), LO_FPS_PERIOD}, diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 7c1ecea81f..841c624a3f 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -74,26 +74,14 @@ TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingSupported) { std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}}; auto refreshRateConfigs = - std::make_unique(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); -} - -TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingNotSupported) { - std::vector configs{ - {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}}; - auto refreshRateConfigs = - std::make_unique(/*refreshRateSwitching=*/false, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); } TEST_F(RefreshRateConfigsTest, invalidPolicy) { std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}}; auto refreshRateConfigs = - std::make_unique(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); + std::make_unique(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); } @@ -103,10 +91,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) { {{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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); const auto minRate = refreshRateConfigs->getMinRefreshRate(); const auto performanceRate = refreshRateConfigs->getMaxRefreshRate(); @@ -128,10 +113,8 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differe {{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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); + std::make_unique(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(); @@ -145,7 +128,6 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differe 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(); @@ -161,9 +143,8 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_policyChange) { {{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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); + auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy(); auto performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy(); @@ -174,7 +155,6 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_policyChange) { 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(); @@ -187,8 +167,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getCurrentRefreshRate) { {{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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); { auto current = refreshRateConfigs->getCurrentRefreshRate(); EXPECT_EQ(current.configId, HWC_CONFIG_ID_60); @@ -212,10 +191,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { {{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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); 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}; @@ -276,10 +252,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_60_90 {{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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); 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}; @@ -387,10 +360,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_60_72 {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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); 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}; @@ -430,10 +400,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60 {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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(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}; @@ -474,8 +441,7 @@ TEST_F(RefreshRateConfigsTest, {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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); + std::make_unique(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}; @@ -542,10 +508,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60 {{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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); 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}; @@ -583,10 +546,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60 {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72}, {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; auto refreshRateConfigs = - std::make_unique(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(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}; @@ -625,10 +585,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Prior {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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(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}; @@ -681,10 +638,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_24Fps {{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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(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}; @@ -707,10 +661,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent_Explici {{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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); 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}; @@ -738,10 +689,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Expli {{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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); 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}; @@ -779,10 +727,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_75HzC {{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(/*refreshRateSwitching=*/true, configs, - /*currentConfigId=*/HWC_CONFIG_ID_60); - - ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + std::make_unique(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}; diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index 8e07c79656..18d6bd21e6 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -47,8 +47,8 @@ protected: ~RefreshRateStatsTest(); void init(const std::vector& configs) { - mRefreshRateConfigs = std::make_unique( - /*refreshRateSwitching=*/true, configs, /*currentConfig=*/CONFIG_ID_0); + mRefreshRateConfigs = + std::make_unique(configs, /*currentConfig=*/CONFIG_ID_0); mRefreshRateStats = std::make_unique(*mRefreshRateConfigs, mTimeStats, /*currentConfigId=*/CONFIG_ID_0, diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 82a00ee734..89002a8f3e 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -73,8 +73,7 @@ SchedulerTest::SchedulerTest() { std::vector configs{ {{HwcConfigIndexType(0), HwcConfigGroupType(0), 16666667}}}; mRefreshRateConfigs = std::make_unique< - scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs, - /*currentConfig=*/HwcConfigIndexType(0)); + scheduler::RefreshRateConfigs>(configs, /*currentConfig=*/HwcConfigIndexType(0)); mScheduler = std::make_unique(*mRefreshRateConfigs, false); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 64838cab7d..798ba766fc 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -202,8 +202,7 @@ public: std::vector configs{ {{HwcConfigIndexType(0), HwcConfigGroupType(0), 16666667}}}; mFlinger->mRefreshRateConfigs = std::make_unique< - scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs, - /*currentConfig=*/HwcConfigIndexType(0)); + scheduler::RefreshRateConfigs>(configs, /*currentConfig=*/HwcConfigIndexType(0)); mFlinger->mRefreshRateStats = std::make_unique< scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, *mFlinger->mTimeStats, /*currentConfig=*/HwcConfigIndexType(0), -- GitLab From bb5ffd2074fe150725eee7eb1f97d5814a2df249 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Thu, 6 Feb 2020 11:45:16 -0500 Subject: [PATCH 0767/1255] AImageDecoder: respond to API review Bug: 148954890 Test: Generate docs List the formats supported. List the possible error codes that can be returned from each method and what it means. Change-Id: I192888c1d438db0308cc715ab7f4997543509e73 --- include/android/imagedecoder.h | 169 +++++++++++++++++++++++++-------- 1 file changed, 128 insertions(+), 41 deletions(-) diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h index 7437ab1093..3a87da0fee 100644 --- a/include/android/imagedecoder.h +++ b/include/android/imagedecoder.h @@ -20,9 +20,18 @@ * 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 + * to decode images in the following formats: + * - JPEG + * - PNG + * - GIF + * - WebP + * - BMP + * - ICO + * - WBMP + * - HEIF + * - Digital negatives (via the DNG SDK) + *

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 * Image decoder @@ -62,7 +71,7 @@ enum { */ ANDROID_IMAGE_DECODER_SUCCESS = 0, /** - * The input was incomplete. + * The input is incomplete. */ ANDROID_IMAGE_DECODER_INCOMPLETE = -1, /** @@ -80,7 +89,7 @@ enum { */ ANDROID_IMAGE_DECODER_INVALID_SCALE = -4, /** - * Some other parameter was bad. + * Some other parameter is invalid. */ ANDROID_IMAGE_DECODER_BAD_PARAMETER = -5, /** @@ -133,6 +142,19 @@ typedef struct AImageDecoder AImageDecoder; * responsible for calling {@link AImageDecoder_delete} on it. * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value * indicating the reason for the failure. + * + * Errors: + * - {@link ANDROID_IMAGE_DECODER_INCOMPLETE}: The asset was truncated before + * reading the image header. + * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: One of the parameters is + * null. + * - {@link ANDROID_IMAGE_DECODER_INVALID_INPUT}: There is an error in the + * header. + * - {@link ANDROID_IMAGE_DECODER_SEEK_ERROR}: The asset failed to seek. + * - {@link ANDROID_IMAGE_DECODER_INTERNAL_ERROR}: Some other error, like a + * failure to allocate memory. + * - {@link ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT}: The format is not + * supported. */ int AImageDecoder_createFromAAsset(struct AAsset* asset, AImageDecoder** outDecoder) __INTRODUCED_IN(30); @@ -149,6 +171,19 @@ int AImageDecoder_createFromAAsset(struct AAsset* asset, AImageDecoder** outDeco * responsible for calling {@link AImageDecoder_delete} on it. * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value * indicating the reason for the failure. + * + * Errors: + * - {@link ANDROID_IMAGE_DECODER_INCOMPLETE}: The file was truncated before + * reading the image header. + * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The {@link AImageDecoder} is + * null, or |fd| does not represent a valid, seekable file descriptor. + * - {@link ANDROID_IMAGE_DECODER_INVALID_INPUT}: There is an error in the + * header. + * - {@link ANDROID_IMAGE_DECODER_SEEK_ERROR}: The descriptor failed to seek. + * - {@link ANDROID_IMAGE_DECODER_INTERNAL_ERROR}: Some other error, like a + * failure to allocate memory. + * - {@link ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT}: The format is not + * supported. */ int AImageDecoder_createFromFd(int fd, AImageDecoder** outDecoder) __INTRODUCED_IN(30); @@ -163,7 +198,19 @@ int AImageDecoder_createFromFd(int fd, AImageDecoder** outDecoder) __INTRODUCED_ * 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. + * + * Errors: + * - {@link ANDROID_IMAGE_DECODER_INCOMPLETE}: The encoded image was truncated before + * reading the image header. + * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: One of the parameters is + * invalid. + * - {@link ANDROID_IMAGE_DECODER_INVALID_INPUT}: There is an error in the + * header. + * - {@link ANDROID_IMAGE_DECODER_INTERNAL_ERROR}: Some other error, like a + * failure to allocate memory. + * - {@link ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT}: The format is not + * supported. */ int AImageDecoder_createFromBuffer(const void* buffer, size_t length, AImageDecoder** outDecoder) __INTRODUCED_IN(30); @@ -177,11 +224,18 @@ void AImageDecoder_delete(AImageDecoder* decoder) __INTRODUCED_IN(30); * Choose the desired output format. * * @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 {@link AImageDecoder} uses the - * format it was already planning to use (either its default - * or a previously successful setting from this function). + * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value + * indicating the reason for the failure. On failure, the + * {@link AImageDecoder} uses the format it was already planning + * to use (either its default or a previously successful setting + * from this function). + * + * Errors: + * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The + * {@link AImageDecoder} is null or |format| does not correspond to an + * {@link AndroidBitmapFormat}. + * - {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION}: The + * {@link AndroidBitmapFormat} is incompatible with the image. */ int AImageDecoder_setAndroidBitmapFormat(AImageDecoder*, int32_t format) __INTRODUCED_IN(30); @@ -194,11 +248,15 @@ int AImageDecoder_setAndroidBitmapFormat(AImageDecoder*, * opaque image. * * @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 + * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value + * indicating the reason for the failure. + * + * Errors: + * - {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION}: Unpremultiplied is not + * possible due to an existing scale set by + * {@link AImageDecoder_setTargetSize}. + * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The + * {@link AImageDecoder} is null. */ int AImageDecoder_setUnpremultipliedRequired(AImageDecoder*, bool unpremultipliedRequired) __INTRODUCED_IN(30); @@ -215,10 +273,13 @@ int AImageDecoder_setUnpremultipliedRequired(AImageDecoder*, * {@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 or - * {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} for a null - * {@link AImageDecoder} or an integer that does not correspond to an - * {@link ADataSpace} value. + * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value + * indicating the reason for the failure. + * + * Errors: + * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The + * {@link AImageDecoder} is null or |dataspace| does not correspond to an + * {@link ADataSpace} value. */ int AImageDecoder_setDataSpace(AImageDecoder*, int32_t dataspace) __INTRODUCED_IN(30); @@ -236,11 +297,16 @@ int AImageDecoder_setDataSpace(AImageDecoder*, int32_t dataspace) __INTRODUCED_I * {@link AImageDecoder_getMinimumStride}, which will now return * a value based on this width. * @param height Height of the output (prior to cropping). - * @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. + * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value + * indicating the reason for the failure. + * + * Errors: + * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The + * {@link AImageDecoder} is null. + * - {@link ANDROID_IMAGE_DECODER_INVALID_SCALE}: |width| or |height| is <= 0, + * the size is too big, any existing crop is not contained by the new image dimensions, + * or the scale is incompatible with a previous call to + * {@link AImageDecoder_setUnpremultipliedRequired}(true). */ int AImageDecoder_setTargetSize(AImageDecoder*, int32_t width, int32_t height) __INTRODUCED_IN(30); @@ -262,8 +328,12 @@ int AImageDecoder_setTargetSize(AImageDecoder*, int32_t width, int32_t height) _ * in the direction that the decoder can do most efficiently. * @param height Out parameter for the height sampled by sampleSize, and rounded * 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. + * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value + * indicating the reason for the failure. + * + * Errors: + * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The + * {@link AImageDecoder}, |width| or |height| is null or |sampleSize| is < 1. */ int AImageDecoder_computeSampledSize(const AImageDecoder*, int sampleSize, int32_t* width, int32_t* height) __INTRODUCED_IN(30); @@ -282,18 +352,21 @@ int AImageDecoder_computeSampledSize(const AImageDecoder*, int sampleSize, * specifically { 0, 0, 0, 0 } - may be used to remove the cropping * behavior. Any other empty or unsorted ARects will result in * 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. + * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value + * indicating the reason for the failure. + * + * Errors: + * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The + * {@link AImageDecoder} is null or the crop is not contained by the + * (possibly scaled) image dimensions. */ int AImageDecoder_setCrop(AImageDecoder*, ARect crop) __INTRODUCED_IN(30); struct AImageDecoderHeaderInfo; /** - * Opaque handle for representing information about the encoded image. It can - * be passed to methods like {@link AImageDecoderHeaderInfo_getWidth} and + * Opaque handle for representing information about the encoded image. Retrieved + * using {@link AImageDecoder_getHeaderInfo} and passed to methods like + * {@link AImageDecoderHeaderInfo_getWidth} and * {@link AImageDecoderHeaderInfo_getHeight}. */ typedef struct AImageDecoderHeaderInfo AImageDecoderHeaderInfo; @@ -310,14 +383,16 @@ const AImageDecoderHeaderInfo* AImageDecoder_getHeaderInfo( /** * 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. + * used to choose a different size or {@link AImageDecoder_setCrop} is used to + * set a crop rect. */ int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30); /** * 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. + * used to choose a different size or {@link AImageDecoder_setCrop} is used to + * set a crop rect. */ int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30); @@ -392,11 +467,23 @@ size_t AImageDecoder_getMinimumStride(AImageDecoder*) __INTRODUCED_IN(30); * @param size Size of the pixel buffer in bytes. Must be at least * stride * (height - 1) + * {@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. + * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value + * indicating the reason for the failure. + * + * Errors: + * - {@link ANDROID_IMAGE_DECODER_INCOMPLETE}: The image was truncated. A + * partial image was decoded, and undecoded lines have been initialized to all + * zeroes. + * - {@link ANDROID_IMAGE_DECODER_ERROR}: The image contained an error. A + * partial image was decoded, and undecoded lines have been initialized to all + * zeroes. + * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The {@link AImageDecoder} or + * |pixels| is null, the stride is not large enough or not pixel aligned, or + * |size| is not large enough. + * - {@link ANDROID_IMAGE_DECODER_SEEK_ERROR}: The asset or file descriptor + * failed to seek. + * - {@link ANDROID_IMAGE_DECODER_INTERNAL_ERROR}: Some other error, like a + * failure to allocate memory. */ int AImageDecoder_decodeImage(AImageDecoder* decoder, void* pixels, size_t stride, -- GitLab From bf29e040323d8ee6265fd8e86dfe26705cca85b8 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Thu, 6 Feb 2020 11:40:38 -0800 Subject: [PATCH 0768/1255] Disable Desired Present time test for BLAST adapter Flaky, will require more work to properly check fence signal and present timing. Bug: 149005974 Test: build, boot, libgui_test Change-Id: I5f112ee46f22f0c21a606af0f248470459fa265b --- libs/gui/tests/BLASTBufferQueue_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index b40eb14093..e184c7f33b 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -239,7 +239,7 @@ TEST_F(BLASTBufferQueueTest, SetNextTransaction) { ASSERT_EQ(&next, adapter.getNextTransaction()); } -TEST_F(BLASTBufferQueueTest, onFrameAvailable_ApplyDesiredPresentTime) { +TEST_F(BLASTBufferQueueTest, DISABLED_onFrameAvailable_ApplyDesiredPresentTime) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); sp igbProducer; setUpProducer(adapter, igbProducer); -- GitLab From 55c85404f7155da7cea22b5394bad960493d4e10 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 21 Jan 2020 16:25:47 -0800 Subject: [PATCH 0769/1255] SF: Populate DisplayConnectionType in DisplayInfo Without HWC support, fall back to categorizing the primary display as internal, and secondary displays as external. Also, validate displays in HWComposer for other 2.4 APIs. Bug: 134771872 Test: dumpsys SurfaceFlinger --displays Test: dumpsys display Test: libsurfaceflinger_unittest Change-Id: I139eeab9cc34e21a1b8584a2fcb9c9fd5dc43ac3 --- libs/ui/include/ui/DisplayInfo.h | 3 + .../CompositionEngine/tests/MockHWComposer.h | 1 + services/surfaceflinger/DisplayDevice.cpp | 22 ++++--- services/surfaceflinger/DisplayDevice.h | 29 ++++++--- .../surfaceflinger/DisplayHardware/HWC2.cpp | 51 ++++++++++------ .../surfaceflinger/DisplayHardware/HWC2.h | 13 ++-- .../DisplayHardware/HWComposer.cpp | 24 ++++++-- .../DisplayHardware/HWComposer.h | 2 + services/surfaceflinger/SurfaceFlinger.cpp | 43 +++++++++----- .../surfaceflinger/SurfaceInterceptor.cpp | 4 +- .../tests/unittests/CompositionTest.cpp | 15 ++--- .../unittests/DisplayTransactionTest.cpp | 59 ++++++++++++++----- .../tests/unittests/TestableSurfaceFlinger.h | 17 ++++-- 13 files changed, 197 insertions(+), 86 deletions(-) diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h index 7773319b84..69f86d39bb 100644 --- a/libs/ui/include/ui/DisplayInfo.h +++ b/libs/ui/include/ui/DisplayInfo.h @@ -20,8 +20,11 @@ namespace android { +enum class DisplayConnectionType { Internal, External }; + // Immutable information about physical display. struct DisplayInfo { + DisplayConnectionType connectionType = DisplayConnectionType::Internal; float density = 0.f; bool secure = false; }; diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index 502a33fe28..358177e750 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -88,6 +88,7 @@ public: MOCK_CONST_METHOD1(getColorModes, std::vector(DisplayId)); MOCK_METHOD3(setActiveColorMode, status_t(DisplayId, ui::ColorMode, ui::RenderIntent)); MOCK_CONST_METHOD0(isUsingVrComposer, bool()); + MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(DisplayId)); MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(DisplayId)); MOCK_CONST_METHOD1(getDisplayVsyncPeriod, nsecs_t(DisplayId)); MOCK_METHOD4(setActiveConfigWithConstraints, diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 6ff39b485e..cd6bbd1716 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -49,16 +49,16 @@ ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::T DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp& flinger, const wp& displayToken, - const std::optional& displayId) + std::optional displayId) : flinger(flinger), displayToken(displayToken), displayId(displayId) {} DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args) : mFlinger(args.flinger), mDisplayToken(args.displayToken), mSequenceId(args.sequenceId), - mIsVirtual(args.isVirtual), + mConnectionType(args.connectionType), mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay( - compositionengine::DisplayCreationArgs{args.isVirtual, args.displayId, + compositionengine::DisplayCreationArgs{args.isVirtual(), args.displayId, args.powerAdvisor})}, mPhysicalOrientation(args.physicalOrientation), mIsPrimary(args.isPrimary) { @@ -248,10 +248,18 @@ ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() { } std::string DisplayDevice::getDebugName() const { - const auto id = getId() ? to_string(*getId()) + ", " : std::string(); - return base::StringPrintf("DisplayDevice{%s%s%s\"%s\"}", id.c_str(), - isPrimary() ? "primary, " : "", isVirtual() ? "virtual, " : "", - mDisplayName.c_str()); + std::string displayId; + if (const auto id = getId()) { + displayId = to_string(*id) + ", "; + } + + const char* type = "virtual"; + if (mConnectionType) { + type = *mConnectionType == DisplayConnectionType::Internal ? "internal" : "external"; + } + + return base::StringPrintf("DisplayDevice{%s%s%s, \"%s\"}", displayId.c_str(), type, + isPrimary() ? ", primary" : "", mDisplayName.c_str()); } void DisplayDevice::dump(std::string& result) const { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index f45feaee63..d970b821e8 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -52,7 +53,6 @@ class SurfaceFlinger; struct CompositionInfo; struct DisplayDeviceCreationArgs; -struct DisplayInfo; namespace compositionengine { class Display; @@ -71,7 +71,9 @@ public: return mCompositionDisplay; } - bool isVirtual() const { return mIsVirtual; } + std::optional getConnectionType() const { return mConnectionType; } + + bool isVirtual() const { return !mConnectionType; } bool isPrimary() const { return mIsPrimary; } // isSecure indicates whether this display can be trusted to display @@ -159,7 +161,7 @@ private: const sp mFlinger; const wp mDisplayToken; const int32_t mSequenceId; - const bool mIsVirtual; + const std::optional mConnectionType; const std::shared_ptr mCompositionDisplay; @@ -178,10 +180,19 @@ private: }; struct DisplayDeviceState { - bool isVirtual() const { return !displayId.has_value(); } + struct Physical { + DisplayId id; + DisplayConnectionType type; + + bool operator==(const Physical& other) const { + return id == other.id && type == other.type; + } + }; + + bool isVirtual() const { return !physical; } int32_t sequenceId = sNextSequenceId++; - std::optional displayId; + std::optional physical; sp surface; ui::LayerStack layerStack = ui::NO_LAYER_STACK; Rect viewport; @@ -199,15 +210,17 @@ private: struct DisplayDeviceCreationArgs { // We use a constructor to ensure some of the values are set, without // assuming a default value. - DisplayDeviceCreationArgs(const sp& flinger, const wp& displayToken, - const std::optional& displayId); + DisplayDeviceCreationArgs(const sp&, const wp& displayToken, + std::optional); + + bool isVirtual() const { return !connectionType; } const sp flinger; const wp displayToken; const std::optional displayId; int32_t sequenceId{0}; - bool isVirtual{false}; + std::optional connectionType; bool isSecure{false}; sp nativeWindow; sp displaySurface; diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 41e787980a..dd3dba1caf 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -95,13 +95,13 @@ float Display::Config::Builder::getDefaultDensity() { } namespace impl { + Display::Display(android::Hwc2::Composer& composer, const std::unordered_set& capabilities, hwc2_display_t id, DisplayType type) : mComposer(composer), mCapabilities(capabilities), mId(id), - mIsConnected(false), mType(type) { ALOGV("Created display %" PRIu64, id); } @@ -109,20 +109,27 @@ Display::Display(android::Hwc2::Composer& composer, Display::~Display() { mLayers.clear(); - if (mType == DisplayType::Virtual) { - ALOGV("Destroying virtual display"); - auto intError = mComposer.destroyVirtualDisplay(mId); - auto error = static_cast(intError); - ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 - ") failed: %s (%d)", mId, to_string(error).c_str(), intError); - } else if (mType == DisplayType::Physical) { - auto error = setVsyncEnabled(HWC2::Vsync::Disable); - if (error != Error::None) { - ALOGE("~Display: Failed to disable vsync for display %" PRIu64 - ": %s (%d)", mId, to_string(error).c_str(), - static_cast(error)); - } + Error error = Error::None; + const char* msg; + switch (mType) { + case DisplayType::Physical: + error = setVsyncEnabled(HWC2::Vsync::Disable); + msg = "disable VSYNC for"; + break; + + case DisplayType::Virtual: + error = static_cast(mComposer.destroyVirtualDisplay(mId)); + msg = "destroy virtual"; + break; + + case DisplayType::Invalid: // Used in unit tests. + break; } + + ALOGE_IF(error != Error::None, "%s: Failed to %s display %" PRIu64 ": %s (%d)", __FUNCTION__, + msg, mId, to_string(error).c_str(), static_cast(error)); + + ALOGV("Destroyed display %" PRIu64, mId); } // Required by HWC2 display @@ -372,9 +379,19 @@ Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests, return Error::None; } -Error Display::getType(DisplayType* outType) const -{ - *outType = mType; +Error Display::getConnectionType(android::DisplayConnectionType* outType) const { + if (mType != DisplayType::Physical) return Error::BadDisplay; + + using ConnectionType = Hwc2::IComposerClient::DisplayConnectionType; + ConnectionType connectionType; + const auto error = static_cast(mComposer.getDisplayConnectionType(mId, &connectionType)); + if (error != Error::None) { + return error; + } + + *outType = connectionType == ConnectionType::INTERNAL + ? android::DisplayConnectionType::Internal + : android::DisplayConnectionType::External; return Error::None; } diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index e7cf5ffc2d..5524bd7908 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -191,7 +192,8 @@ public: [[clang::warn_unused_result]] virtual Error getRequests( DisplayRequest* outDisplayRequests, std::unordered_map* outLayerRequests) = 0; - [[clang::warn_unused_result]] virtual Error getType(DisplayType* outType) const = 0; + [[clang::warn_unused_result]] virtual Error getConnectionType( + android::DisplayConnectionType*) const = 0; [[clang::warn_unused_result]] virtual Error supportsDoze(bool* outSupport) const = 0; [[clang::warn_unused_result]] virtual Error getHdrCapabilities( android::HdrCapabilities* outCapabilities) const = 0; @@ -268,7 +270,7 @@ public: Error getName(std::string* outName) const override; Error getRequests(DisplayRequest* outDisplayRequests, std::unordered_map* outLayerRequests) override; - Error getType(DisplayType* outType) const override; + Error getConnectionType(android::DisplayConnectionType*) const override; Error supportsDoze(bool* outSupport) const override; Error getHdrCapabilities(android::HdrCapabilities* outCapabilities) const override; Error getDisplayedContentSamplingAttributes(android::ui::PixelFormat* outFormat, @@ -332,16 +334,17 @@ private: android::Hwc2::Composer& mComposer; const std::unordered_set& mCapabilities; - hwc2_display_t mId; - bool mIsConnected; + const hwc2_display_t mId; DisplayType mType; - std::unordered_map> mLayers; + bool mIsConnected = false; + std::unordered_map> mLayers; std::unordered_map> mConfigs; std::once_flag mDisplayCapabilityQueryFlag; std::unordered_set mDisplayCapabilities; }; + } // namespace impl class Layer { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 153cfe7f9d..80fd7cdfb7 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -406,18 +406,32 @@ std::shared_ptr HWComposer::getActiveConfig( // Composer 2.4 +DisplayConnectionType HWComposer::getDisplayConnectionType(DisplayId displayId) const { + RETURN_IF_INVALID_DISPLAY(displayId, DisplayConnectionType::Internal); + const auto& hwcDisplay = mDisplayData.at(displayId).hwcDisplay; + + DisplayConnectionType type; + const auto error = hwcDisplay->getConnectionType(&type); + + const auto FALLBACK_TYPE = hwcDisplay->getId() == mInternalHwcDisplayId + ? DisplayConnectionType::Internal + : DisplayConnectionType::External; + + RETURN_IF_HWC_ERROR(error, displayId, FALLBACK_TYPE); + return type; +} + bool HWComposer::isVsyncPeriodSwitchSupported(DisplayId displayId) const { + RETURN_IF_INVALID_DISPLAY(displayId, false); return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported(); } nsecs_t HWComposer::getDisplayVsyncPeriod(DisplayId displayId) const { + RETURN_IF_INVALID_DISPLAY(displayId, 0); + nsecs_t vsyncPeriodNanos; auto error = mDisplayData.at(displayId).hwcDisplay->getDisplayVsyncPeriod(&vsyncPeriodNanos); - if (error != HWC2::Error::None) { - LOG_DISPLAY_ERROR(displayId, "Failed to get Vsync Period"); - return 0; - } - + RETURN_IF_HWC_ERROR(error, displayId, 0); return vsyncPeriodNanos; } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index effe43b548..75b52ef356 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -184,6 +184,7 @@ public: virtual bool isUsingVrComposer() const = 0; // Composer 2.4 + virtual DisplayConnectionType getDisplayConnectionType(DisplayId) const = 0; virtual bool isVsyncPeriodSwitchSupported(DisplayId displayId) const = 0; virtual nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const = 0; virtual status_t setActiveConfigWithConstraints( @@ -319,6 +320,7 @@ public: bool isUsingVrComposer() const override; // Composer 2.4 + DisplayConnectionType getDisplayConnectionType(DisplayId) const override; bool isVsyncPeriodSwitchSupported(DisplayId displayId) const override; nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const override; status_t setActiveConfigWithConstraints(DisplayId displayId, size_t configId, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 33d85cb420..1f7310a9b6 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -785,14 +785,18 @@ status_t SurfaceFlinger::getDisplayInfo(const sp& displayToken, Display return NAME_NOT_FOUND; } - if (display->isVirtual()) { + if (const auto connectionType = display->getConnectionType()) + info->connectionType = *connectionType; + else { return INVALID_OPERATION; } if (mEmulatedDisplayDensity) { info->density = mEmulatedDisplayDensity; } else { - info->density = display->isPrimary() ? mInternalDisplayDensity : FALLBACK_DENSITY; + info->density = info->connectionType == DisplayConnectionType::Internal + ? mInternalDisplayDensity + : FALLBACK_DENSITY; } info->secure = display->isSecure(); @@ -2243,30 +2247,38 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { continue; } + const DisplayId displayId = info->id; + const auto it = mPhysicalDisplayTokens.find(displayId); + if (event.connection == HWC2::Connection::Connected) { - if (!mPhysicalDisplayTokens.count(info->id)) { - ALOGV("Creating display %s", to_string(info->id).c_str()); + if (it == mPhysicalDisplayTokens.end()) { + ALOGV("Creating display %s", to_string(displayId).c_str()); + if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) { - initScheduler(info->id); + initScheduler(displayId); } - mPhysicalDisplayTokens[info->id] = new BBinder(); + DisplayDeviceState state; - state.displayId = info->id; + state.physical = {displayId, getHwComposer().getDisplayConnectionType(displayId)}; state.isSecure = true; // All physical displays are currently considered secure. state.displayName = info->name; - mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state); + + sp token = new BBinder(); + mCurrentState.displays.add(token, state); + mPhysicalDisplayTokens.emplace(displayId, std::move(token)); + mInterceptor->saveDisplayCreation(state); } } else { - ALOGV("Removing display %s", to_string(info->id).c_str()); + ALOGV("Removing display %s", to_string(displayId).c_str()); - ssize_t index = mCurrentState.displays.indexOfKey(mPhysicalDisplayTokens[info->id]); + const ssize_t index = mCurrentState.displays.indexOfKey(it->second); if (index >= 0) { const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); mInterceptor->saveDisplayDeletion(state.sequenceId); mCurrentState.displays.removeItemsAt(index); } - mPhysicalDisplayTokens.erase(info->id); + mPhysicalDisplayTokens.erase(it); } processDisplayChangesLocked(); @@ -2286,13 +2298,16 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( const sp& producer) { DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId); creationArgs.sequenceId = state.sequenceId; - creationArgs.isVirtual = state.isVirtual(); creationArgs.isSecure = state.isSecure; creationArgs.displaySurface = dispSurface; creationArgs.hasWideColorGamut = false; creationArgs.supportedPerFrameMetadata = 0; creationArgs.powerAdvisor = displayId ? &mPowerAdvisor : nullptr; + if (const auto& physical = state.physical) { + creationArgs.connectionType = physical->type; + } + const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked(); creationArgs.isPrimary = isInternalDisplay; @@ -2483,8 +2498,8 @@ void SurfaceFlinger::processDisplayChangesLocked() { "surface is provided (%p), ignoring it", state.surface.get()); - displayId = state.displayId; - LOG_ALWAYS_FATAL_IF(!displayId); + LOG_FATAL_IF(!state.physical); + displayId = state.physical->id; dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer); producer = bqProducer; } diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index 6884b4c42e..1f9d46c330 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -595,8 +595,8 @@ void SurfaceInterceptor::addDisplayCreationLocked(Increment* increment, creation->set_id(info.sequenceId); creation->set_name(info.displayName); creation->set_is_secure(info.isSecure); - if (info.displayId) { - creation->set_display_id(info.displayId->value); + if (info.physical) { + creation->set_display_id(info.physical->id.value); } } diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 888e009282..27e2e8dba3 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -286,13 +286,14 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1); EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1); EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1); - test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID, - false /* isVirtual */, true /* isPrimary */) - .setDisplaySurface(test->mDisplaySurface) - .setNativeWindow(test->mNativeWindow) - .setSecure(Derived::IS_SECURE) - .setPowerMode(Derived::INIT_POWER_MODE) - .inject(); + test->mDisplay = + FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID, + DisplayConnectionType::Internal, true /* isPrimary */) + .setDisplaySurface(test->mDisplaySurface) + .setNativeWindow(test->mNativeWindow) + .setSecure(Derived::IS_SECURE) + .setPowerMode(Derived::INIT_POWER_MODE) + .inject(); Mock::VerifyAndClear(test->mNativeWindow); test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK); } diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index dddad92f79..fd2ccc48d4 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -312,6 +312,16 @@ struct DisplayIdGetter { static std::optional get() { return {}; } }; +template +struct DisplayConnectionTypeGetter { + static constexpr std::optional value; +}; + +template +struct DisplayConnectionTypeGetter> { + static constexpr std::optional value = PhysicalDisplay::CONNECTION_TYPE; +}; + // DisplayIdType can be: // 1) PhysicalDisplayId<...> for generated ID of physical display backed by HWC. // 2) VirtualDisplayId<...> for hard-coded ID of virtual display backed by HWC. @@ -320,6 +330,7 @@ template struct DisplayVariant { using DISPLAY_ID = DisplayIdGetter; + using CONNECTION_TYPE = DisplayConnectionTypeGetter; // The display width and height static constexpr int WIDTH = width; @@ -345,8 +356,8 @@ struct DisplayVariant { static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) { auto injector = - FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(), - static_cast(VIRTUAL), static_cast(PRIMARY)); + FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(), CONNECTION_TYPE::value, + static_cast(PRIMARY)); injector.setSecure(static_cast(SECURE)); injector.setNativeWindow(test->mNativeWindow); @@ -450,6 +461,15 @@ struct HwcDisplayVariant { } static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) { + constexpr auto CONNECTION_TYPE = + PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal + ? IComposerClient::DisplayConnectionType::INTERNAL + : IComposerClient::DisplayConnectionType::EXTERNAL; + + EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _)) + .WillOnce( + DoAll(SetArgPointee<1>(CONNECTION_TYPE), Return(Hwc2::V2_4::Error::NONE))); + EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE)); EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _)) .WillOnce(DoAll(SetArgPointee<1>(std::vector{HWC_ACTIVE_CONFIG_ID}), @@ -514,6 +534,7 @@ struct PhysicalDisplayVariant template struct PrimaryDisplay { + static constexpr auto CONNECTION_TYPE = DisplayConnectionType::Internal; static constexpr Primary PRIMARY = Primary::TRUE; static constexpr uint8_t PORT = 255; static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData; @@ -522,6 +543,7 @@ struct PrimaryDisplay { template struct ExternalDisplay { + static constexpr auto CONNECTION_TYPE = DisplayConnectionType::External; static constexpr Primary PRIMARY = Primary::FALSE; static constexpr uint8_t PORT = 254; static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData; @@ -1183,7 +1205,8 @@ public: GetBestColorModeTest() : DisplayTransactionTest(), - mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, false /* isVirtual */, + mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, + DisplayConnectionType::Internal, true /* isPrimary */)) {} void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; } @@ -1285,8 +1308,6 @@ TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDISPLAY_BT2020) { class DisplayDeviceSetProjectionTest : public DisplayTransactionTest { public: static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777}; - static constexpr bool DEFAULT_DISPLAY_IS_VIRTUAL = false; - static constexpr bool DEFAULT_DISPLAY_IS_PRIMARY = true; static constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1080; // arbitrary static constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1920; // arbitrary @@ -1316,8 +1337,8 @@ public: EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)); EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)); - return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, DEFAULT_DISPLAY_IS_VIRTUAL, - DEFAULT_DISPLAY_IS_PRIMARY) + return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, + DisplayConnectionType::Internal, true /* isPrimary */) .setNativeWindow(mNativeWindow) .setPhysicalOrientation(mPhysicalOrientation) .inject(); @@ -1647,8 +1668,12 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { // Invocation DisplayDeviceState state; - state.displayId = static_cast(Case::Display::VIRTUAL) ? std::nullopt - : Case::Display::DISPLAY_ID::get(); + if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) { + const auto displayId = Case::Display::DISPLAY_ID::get(); + ASSERT_TRUE(displayId); + state.physical = {*displayId, *connectionType}; + } + state.isSecure = static_cast(Case::Display::SECURE); auto device = @@ -1660,6 +1685,7 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { ASSERT_TRUE(device != nullptr); EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId()); + EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, device->getConnectionType()); EXPECT_EQ(static_cast(Case::Display::VIRTUAL), device->isVirtual()); EXPECT_EQ(static_cast(Case::Display::SECURE), device->isSecure()); EXPECT_EQ(static_cast(Case::Display::PRIMARY), device->isPrimary()); @@ -1823,21 +1849,24 @@ void HandleTransactionLockedTest::verifyDisplayIsConnected(const sp& di EXPECT_EQ(static_cast(Case::Display::SECURE), device->isSecure()); EXPECT_EQ(static_cast(Case::Display::PRIMARY), device->isPrimary()); + std::optional expectedPhysical; + if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) { + const auto displayId = Case::Display::DISPLAY_ID::get(); + ASSERT_TRUE(displayId); + expectedPhysical = {*displayId, *connectionType}; + } + // The display should have been set up in the current display state ASSERT_TRUE(hasCurrentDisplayState(displayToken)); const auto& current = getCurrentDisplayState(displayToken); EXPECT_EQ(static_cast(Case::Display::VIRTUAL), current.isVirtual()); - EXPECT_EQ(static_cast(Case::Display::VIRTUAL) ? std::nullopt - : Case::Display::DISPLAY_ID::get(), - current.displayId); + EXPECT_EQ(expectedPhysical, current.physical); // The display should have been set up in the drawing display state ASSERT_TRUE(hasDrawingDisplayState(displayToken)); const auto& draw = getDrawingDisplayState(displayToken); EXPECT_EQ(static_cast(Case::Display::VIRTUAL), draw.isVirtual()); - EXPECT_EQ(static_cast(Case::Display::VIRTUAL) ? std::nullopt - : Case::Display::DISPLAY_ID::get(), - draw.displayId); + EXPECT_EQ(expectedPhysical, draw.physical); } template diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 64838cab7d..6886d3b15c 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -546,10 +546,11 @@ public: class FakeDisplayDeviceInjector { public: FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, - const std::optional& displayId, bool isVirtual, + std::optional displayId, + std::optional connectionType, bool isPrimary) : mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), mDisplayToken, displayId) { - mCreationArgs.isVirtual = isVirtual; + mCreationArgs.connectionType = connectionType; mCreationArgs.isPrimary = isPrimary; } @@ -612,7 +613,12 @@ public: sp inject() { DisplayDeviceState state; - state.displayId = mCreationArgs.isVirtual ? std::nullopt : mCreationArgs.displayId; + if (const auto type = mCreationArgs.connectionType) { + const auto id = mCreationArgs.displayId; + LOG_ALWAYS_FATAL_IF(!id); + state.physical = {*id, *type}; + } + state.isSecure = mCreationArgs.isSecure; sp device = new DisplayDevice(std::move(mCreationArgs)); @@ -620,9 +626,8 @@ public: mFlinger.mutableCurrentState().displays.add(mDisplayToken, state); mFlinger.mutableDrawingState().displays.add(mDisplayToken, state); - if (!mCreationArgs.isVirtual) { - LOG_ALWAYS_FATAL_IF(!state.displayId); - mFlinger.mutablePhysicalDisplayTokens()[*state.displayId] = mDisplayToken; + if (const auto& physical = state.physical) { + mFlinger.mutablePhysicalDisplayTokens()[physical->id] = mDisplayToken; } return device; -- GitLab From 4883c52b940bbfa4f396c8432a25bed5e5e6d51b Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Thu, 30 Jan 2020 15:10:11 -0500 Subject: [PATCH 0770/1255] Fix docs for bitmap.h Bug: 135133301 Test: Generate docs - Fix errors in bitmap documentation. - Add links where relevant. - Move comment in sensor.h so it will apply to the module, and not AHardwareBuffer. Change-Id: Iec00725522e74eccab9346665562081211a870eb --- include/android/bitmap.h | 26 +++++++++++++------------- include/android/sensor.h | 9 +++------ 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/include/android/bitmap.h b/include/android/bitmap.h index 412fc6b53f..727a4af2f9 100644 --- a/include/android/bitmap.h +++ b/include/android/bitmap.h @@ -81,8 +81,8 @@ enum { enum { /** If this bit is set in AndroidBitmapInfo.flags, the Bitmap uses the - * HARDWARE Config, and its AHardwareBuffer can be retrieved via - * AndroidBitmap_getHardwareBuffer. + * HARDWARE Config, and its {@link AHardwareBuffer} can be retrieved via + * {@link AndroidBitmap_getHardwareBuffer}. */ ANDROID_BITMAP_FLAGS_IS_HARDWARE = 1 << 31, }; @@ -120,10 +120,10 @@ int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, #if __ANDROID_API__ >= 30 /** - * Given a java bitmap object, return its ADataSpace. + * Given a java bitmap object, return its {@link ADataSpace}. * - * Note that ADataSpace only exposes a few values. This may return - * ADATASPACE_UNKNOWN, even for Named ColorSpaces, if they have no + * Note that {@link ADataSpace} only exposes a few values. This may return + * {@link ADATASPACE_UNKNOWN}, even for Named ColorSpaces, if they have no * corresponding ADataSpace. */ int32_t AndroidBitmap_getDataSpace(JNIEnv* env, jobject jbitmap) __INTRODUCED_IN(30); @@ -206,17 +206,17 @@ typedef bool (*AndroidBitmap_CompressWriteFunc)(void* userContext, * @param dataspace {@link ADataSpace} describing the color space of the * pixels. * @param pixels Pointer to pixels to compress. - * @param format (@link AndroidBitmapCompressFormat} to compress to. + * @param format {@link AndroidBitmapCompressFormat} to compress to. * @param quality Hint to the compressor, 0-100. The value is interpreted * differently depending on the * {@link AndroidBitmapCompressFormat}. * @param userContext User-defined data which will be passed to the supplied * {@link AndroidBitmap_CompressWriteFunc} each time it is * called. May be null. - * @parm fn Function that writes the compressed data. Will be called each time - * the compressor has compressed more data that is ready to be - * written. May be called more than once for each call to this method. - * May not be null. + * @param fn Function that writes the compressed data. Will be called each time + * the compressor has compressed more data that is ready to be + * written. May be called more than once for each call to this method. + * May not be null. * @return AndroidBitmap functions result code. */ int AndroidBitmap_compress(const AndroidBitmapInfo* info, @@ -235,11 +235,11 @@ struct AHardwareBuffer; * * @param bitmap Handle to an android.graphics.Bitmap. * @param outBuffer On success, is set to a pointer to the - * AHardwareBuffer associated with bitmap. This acquires + * {@link AHardwareBuffer} associated with bitmap. This acquires * a reference on the buffer, and the client must call - * AHardwareBuffer_release when finished with it. + * {@link AHardwareBuffer_release} when finished with it. * @return AndroidBitmap functions result code. - * ANDROID_BITMAP_RESULT_BAD_PARAMETER if bitmap is not a + * {@link ANDROID_BITMAP_RESULT_BAD_PARAMETER} if bitmap is not a * HARDWARE Bitmap. */ int AndroidBitmap_getHardwareBuffer(JNIEnv* env, jobject bitmap, diff --git a/include/android/sensor.h b/include/android/sensor.h index 12c00ad8a2..e63ac4b407 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -15,6 +15,9 @@ */ /** + * Structures and functions to receive and process sensor events in + * native code. + * * @addtogroup Sensor * @{ */ @@ -42,12 +45,6 @@ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES */ -/** - * Structures and functions to receive and process sensor events in - * native code. - * - */ - #include #include -- GitLab From 6a3e6717cee02a93d8f8f108d38d546bd20b87b1 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Fri, 7 Feb 2020 09:45:47 -0800 Subject: [PATCH 0771/1255] SF: fix SurfaceFlinger freeze When BufferQueueLayer errors in onFrameAvailable and onFrameReplaced, it infinitely loops. This patch adds a break when we get into the bad state. Bug: 147476322 Test: verified by vendor that this fixes their bug and SurfaceFlinger_test Change-Id: Ida063470edc7e688d106ec9fbac3c81bc5e00189 --- services/surfaceflinger/BufferQueueLayer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index e85281d8a9..dff529cc15 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -433,6 +433,7 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500)); if (result != NO_ERROR) { ALOGE("[%s] Timed out waiting on callback", getDebugName()); + break; } } @@ -461,6 +462,7 @@ void BufferQueueLayer::onFrameReplaced(const BufferItem& item) { status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500)); if (result != NO_ERROR) { ALOGE("[%s] Timed out waiting on callback", getDebugName()); + break; } } -- GitLab From 52c2cab46d033b6218b2fd031c33acd0755967b4 Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Tue, 10 Dec 2019 17:23:52 -0800 Subject: [PATCH 0772/1255] libui: rewrite Region with FatVector Region is heavily used by SurfaceFlinger and the Android animation framework, but it uses the libutils Vector internally. libutils Vector allocates four elements via malloc() regardless of the contents of the Vector. However, Region is overwhelmingly a single-element Vector (occasionally two), which can be allocated on the stack easily enough. FatVector is an existing wrapper around std::vector that allows for a stack-allocated vector when the contents are small enough. Using FatVector in Region instead of libutils Vector avoids all of the malloc/free overhead, which improves SurfaceFlinger per-frame runtime by ~4%. This CL moves FatVector from libhwui to make it usable by Region. Test: boots, works, passes tests Bug: 149096186 Change-Id: I265c6c831bc82f31afe0d100aec2f98344f2390b --- include/ui/FatVector.h | 1 + libs/ui/Region.cpp | 94 +++++++++++++++-------------- libs/ui/include/ui/FatVector.h | 93 ++++++++++++++++++++++++++++ libs/ui/include/ui/Region.h | 7 +-- libs/ui/include_vndk/ui/FatVector.h | 1 + 5 files changed, 146 insertions(+), 50 deletions(-) create mode 120000 include/ui/FatVector.h create mode 100644 libs/ui/include/ui/FatVector.h create mode 120000 libs/ui/include_vndk/ui/FatVector.h diff --git a/include/ui/FatVector.h b/include/ui/FatVector.h new file mode 120000 index 0000000000..c2047c07e1 --- /dev/null +++ b/include/ui/FatVector.h @@ -0,0 +1 @@ +../../libs/ui/include/ui/FatVector.h \ No newline at end of file diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index bf487c4aec..cd2a448c3e 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -67,19 +67,20 @@ const Region Region::INVALID_REGION(Rect::INVALID_RECT); // ---------------------------------------------------------------------------- Region::Region() { - mStorage.add(Rect(0,0)); + mStorage.push_back(Rect(0, 0)); } Region::Region(const Region& rhs) - : mStorage(rhs.mStorage) { + mStorage.clear(); + mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end()); #if defined(VALIDATE_REGIONS) validate(rhs, "rhs copy-ctor"); #endif } Region::Region(const Rect& rhs) { - mStorage.add(rhs); + mStorage.push_back(rhs); } Region::~Region() @@ -100,8 +101,8 @@ Region::~Region() * final, correctly ordered region buffer. Each rectangle will be compared with the span directly * above it, and subdivided to resolve any remaining T-junctions. */ -static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, - Vector& dst, int spanDirection) { +static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, FatVector& dst, + int spanDirection) { dst.clear(); const Rect* current = end - 1; @@ -109,7 +110,7 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, // add first span immediately do { - dst.add(*current); + dst.push_back(*current); current--; } while (current->top == lastTop && current >= begin); @@ -147,12 +148,12 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, if (prev.right <= left) break; if (prev.right > left && prev.right < right) { - dst.add(Rect(prev.right, top, right, bottom)); + dst.push_back(Rect(prev.right, top, right, bottom)); right = prev.right; } if (prev.left > left && prev.left < right) { - dst.add(Rect(prev.left, top, right, bottom)); + dst.push_back(Rect(prev.left, top, right, bottom)); right = prev.left; } @@ -166,12 +167,12 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, if (prev.left >= right) break; if (prev.left > left && prev.left < right) { - dst.add(Rect(left, top, prev.left, bottom)); + dst.push_back(Rect(left, top, prev.left, bottom)); left = prev.left; } if (prev.right > left && prev.right < right) { - dst.add(Rect(left, top, prev.right, bottom)); + dst.push_back(Rect(left, top, prev.right, bottom)); left = prev.right; } // if an entry in the previous span is too far left, nothing further right in the @@ -183,7 +184,7 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, } if (left < right) { - dst.add(Rect(left, top, right, bottom)); + dst.push_back(Rect(left, top, right, bottom)); } current--; @@ -201,13 +202,14 @@ Region Region::createTJunctionFreeRegion(const Region& r) { if (r.isEmpty()) return r; if (r.isRect()) return r; - Vector reversed; + FatVector reversed; reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL); Region outputRegion; - reverseRectsResolvingJunctions(reversed.begin(), reversed.end(), - outputRegion.mStorage, direction_LTR); - outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds + reverseRectsResolvingJunctions(reversed.data(), reversed.data() + reversed.size(), + outputRegion.mStorage, direction_LTR); + outputRegion.mStorage.push_back( + r.getBounds()); // to make region valid, mStorage must end with bounds #if defined(VALIDATE_REGIONS) validate(outputRegion, "T-Junction free region"); @@ -222,7 +224,8 @@ Region& Region::operator = (const Region& rhs) validate(*this, "this->operator="); validate(rhs, "rhs.operator="); #endif - mStorage = rhs.mStorage; + mStorage.clear(); + mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end()); return *this; } @@ -231,7 +234,7 @@ Region& Region::makeBoundsSelf() if (mStorage.size() >= 2) { const Rect bounds(getBounds()); mStorage.clear(); - mStorage.add(bounds); + mStorage.push_back(bounds); } return *this; } @@ -255,25 +258,25 @@ bool Region::contains(int x, int y) const { void Region::clear() { mStorage.clear(); - mStorage.add(Rect(0,0)); + mStorage.push_back(Rect(0, 0)); } void Region::set(const Rect& r) { mStorage.clear(); - mStorage.add(r); + mStorage.push_back(r); } void Region::set(int32_t w, int32_t h) { mStorage.clear(); - mStorage.add(Rect(w, h)); + mStorage.push_back(Rect(w, h)); } void Region::set(uint32_t w, uint32_t h) { mStorage.clear(); - mStorage.add(Rect(w, h)); + mStorage.push_back(Rect(w, h)); } bool Region::isTriviallyEqual(const Region& region) const { @@ -299,8 +302,7 @@ bool Region::hasSameRects(const Region& other) const { void Region::addRectUnchecked(int l, int t, int r, int b) { Rect rect(l,t,r,b); - size_t where = mStorage.size() - 1; - mStorage.insertAt(rect, where, 1); + mStorage.insert(mStorage.end() - 1, rect); } // ---------------------------------------------------------------------------- @@ -350,7 +352,7 @@ Region& Region::translateSelf(int x, int y) { Region& Region::scaleSelf(float sx, float sy) { size_t count = mStorage.size(); - Rect* rects = mStorage.editArray(); + Rect* rects = mStorage.data(); while (count) { rects->left = static_cast(static_cast(rects->left) * sx + 0.5f); rects->right = static_cast(static_cast(rects->right) * sx + 0.5f); @@ -455,10 +457,10 @@ const Region Region::operation(const Region& rhs, int dx, int dy, uint32_t op) c class Region::rasterizer : public region_operator::region_rasterizer { Rect bounds; - Vector& storage; + FatVector& storage; Rect* head; Rect* tail; - Vector span; + FatVector span; Rect* cur; public: explicit rasterizer(Region& reg) @@ -485,8 +487,8 @@ Region::rasterizer::~rasterizer() flushSpan(); } if (storage.size()) { - bounds.top = storage.itemAt(0).top; - bounds.bottom = storage.top().bottom; + bounds.top = storage.front().top; + bounds.bottom = storage.back().bottom; if (storage.size() == 1) { storage.clear(); } @@ -494,7 +496,7 @@ Region::rasterizer::~rasterizer() bounds.left = 0; bounds.right = 0; } - storage.add(bounds); + storage.push_back(bounds); } void Region::rasterizer::operator()(const Rect& rect) @@ -509,15 +511,15 @@ void Region::rasterizer::operator()(const Rect& rect) return; } } - span.add(rect); - cur = span.editArray() + (span.size() - 1); + span.push_back(rect); + cur = span.data() + (span.size() - 1); } void Region::rasterizer::flushSpan() { bool merge = false; if (tail-head == ssize_t(span.size())) { - Rect const* p = span.editArray(); + Rect const* p = span.data(); Rect const* q = head; if (p->top == q->bottom) { merge = true; @@ -532,17 +534,17 @@ void Region::rasterizer::flushSpan() } } if (merge) { - const int bottom = span[0].bottom; + const int bottom = span.front().bottom; Rect* r = head; while (r != tail) { r->bottom = bottom; r++; } } else { - bounds.left = min(span.itemAt(0).left, bounds.left); - bounds.right = max(span.top().right, bounds.right); - storage.appendVector(span); - tail = storage.editArray() + storage.size(); + bounds.left = min(span.front().left, bounds.left); + bounds.right = max(span.back().right, bounds.right); + storage.insert(storage.end(), span.begin(), span.end()); + tail = storage.data() + storage.size(); head = tail - span.size(); } span.clear(); @@ -550,7 +552,7 @@ void Region::rasterizer::flushSpan() bool Region::validate(const Region& reg, const char* name, bool silent) { - if (reg.mStorage.isEmpty()) { + if (reg.mStorage.empty()) { ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name); // return immediately as the code below assumes mStorage is non-empty return false; @@ -689,9 +691,8 @@ void Region::boolean_operation(uint32_t op, Region& dst, } sk_dst.op(sk_lhs, sk_rhs, sk_op); - if (sk_dst.isEmpty() && dst.isEmpty()) - return; - + if (sk_dst.empty() && dst.empty()) return; + bool same = true; Region::const_iterator head = dst.begin(); Region::const_iterator const tail = dst.end(); @@ -786,7 +787,7 @@ void Region::translate(Region& reg, int dx, int dy) validate(reg, "translate (before)"); #endif size_t count = reg.mStorage.size(); - Rect* rects = reg.mStorage.editArray(); + Rect* rects = reg.mStorage.data(); while (count) { rects->offsetBy(dx, dy); rects++; @@ -866,24 +867,25 @@ status_t Region::unflatten(void const* buffer, size_t size) { ALOGE("Region::unflatten() failed, invalid region"); return BAD_VALUE; } - mStorage = result.mStorage; + mStorage.clear(); + mStorage.insert(mStorage.begin(), result.mStorage.begin(), result.mStorage.end()); return NO_ERROR; } // ---------------------------------------------------------------------------- Region::const_iterator Region::begin() const { - return mStorage.array(); + return mStorage.data(); } Region::const_iterator Region::end() const { // Workaround for b/77643177 // mStorage should never be empty, but somehow it is and it's causing // an abort in ubsan - if (mStorage.isEmpty()) return mStorage.array(); + if (mStorage.empty()) return mStorage.data(); size_t numRects = isRect() ? 1 : mStorage.size() - 1; - return mStorage.array() + numRects; + return mStorage.data() + numRects; } Rect const* Region::getArray(size_t* count) const { diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h new file mode 100644 index 0000000000..25fe3a0a2a --- /dev/null +++ b/libs/ui/include/ui/FatVector.h @@ -0,0 +1,93 @@ +/* + * 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. + */ + +#ifndef ANDROID_REGION_FAT_VECTOR_H +#define ANDROID_REGION_FAT_VECTOR_H + +#include +#include +#include +#include + +#include + +namespace android { + +template +class InlineStdAllocator { +public: + struct Allocation { + private: + Allocation(const Allocation&) = delete; + void operator=(const Allocation&) = delete; + + public: + Allocation() {} + // char array instead of T array, so memory is uninitialized, with no destructors run + char array[sizeof(T) * SIZE]; + bool inUse = false; + }; + + typedef T value_type; // needed to implement std::allocator + typedef T* pointer; // needed to implement std::allocator + + explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {} + InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {} + ~InlineStdAllocator() {} + + T* allocate(size_t num, const void* = 0) { + if (!mAllocation.inUse && num <= SIZE) { + mAllocation.inUse = true; + return static_cast(static_cast(mAllocation.array)); + } else { + return static_cast(static_cast(malloc(num * sizeof(T)))); + } + } + + void deallocate(pointer p, size_t) { + if (p == static_cast(static_cast(mAllocation.array))) { + mAllocation.inUse = false; + } else { + // 'free' instead of delete here - destruction handled separately + free(p); + } + } + Allocation& mAllocation; +}; + +/** + * std::vector with SIZE elements preallocated into an internal buffer. + * + * Useful for avoiding the cost of malloc in cases where only SIZE or + * fewer elements are needed in the common case. + */ +template +class FatVector : public std::vector> { +public: + FatVector() + : std::vector>(InlineStdAllocator(mAllocation)) { + this->reserve(SIZE); + } + + explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); } + +private: + typename InlineStdAllocator::Allocation mAllocation; +}; + +} // namespace android + +#endif // ANDROID_REGION_FAT_VECTOR_H diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h index 2db3b10f13..6bb7b8d21c 100644 --- a/libs/ui/include/ui/Region.h +++ b/libs/ui/include/ui/Region.h @@ -21,13 +21,13 @@ #include #include -#include - #include #include #include +#include "FatVector.h" + #include namespace android { @@ -180,7 +180,7 @@ private: // with an extra Rect as the last element which is set to the // bounds of the region. However, if the region is // a simple Rect then mStorage contains only that rect. - Vector mStorage; + FatVector mStorage; }; @@ -235,4 +235,3 @@ static inline void PrintTo(const Region& region, ::std::ostream* os) { }; // namespace android #endif // ANDROID_UI_REGION_H - diff --git a/libs/ui/include_vndk/ui/FatVector.h b/libs/ui/include_vndk/ui/FatVector.h new file mode 120000 index 0000000000..bf30166784 --- /dev/null +++ b/libs/ui/include_vndk/ui/FatVector.h @@ -0,0 +1 @@ +../../include/ui/FatVector.h \ No newline at end of file -- GitLab From 285aac19abe088ca9461219495fda5c038b94a11 Mon Sep 17 00:00:00 2001 From: Mike Ma Date: Fri, 7 Feb 2020 12:29:46 -0800 Subject: [PATCH 0773/1255] Skip dump proto when initCheck fails Sometimes sensorservice is not initialized when calling dumpProto. Add this check to prevent NPE, which aligns with what text dump does. Fixes: 149019631 Test: Manual Change-Id: Id8c2dcd242b04e2bf3ef948690d88760f3bd08c8 --- services/sensorservice/SensorService.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index e803c9ad7e..914a4cb54d 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -520,6 +520,10 @@ status_t SensorService::dump(int fd, const Vector& args) { status_t SensorService::dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock) const { using namespace service::SensorServiceProto; util::ProtoOutputStream proto; + proto.write(INIT_STATUS, int(SensorDevice::getInstance().initCheck())); + if (!mSensors.hasAnySensor()) { + return proto.flush(fd) ? OK : UNKNOWN_ERROR; + } const bool privileged = IPCThreadState::self()->getCallingUid() == 0; timespec curTime; -- GitLab From 5d47791e231cdddb2ae933e8b1923c43533c7663 Mon Sep 17 00:00:00 2001 From: Ana Krulec Date: Fri, 7 Feb 2020 12:02:38 -0800 Subject: [PATCH 0774/1255] SF Crash Bug fix There is a state when Scheduler returns a config which is not allowed by the policy. This can happen when policy has changed, and scheduler decided that the next config should be the current config. We fix it by returning the current config, if allowed, otherwise the default. Change-Id: Id49674dc5cf6cc36eb6a48dfec7d007063c1f382 Bug: 149077559 Test: Turn off all policies. Toggle smoooth display. Doesn't fail. Test: Turn off all polcies. Open Waze. Doesn't fail. Test: Turn off all policies. Open TouchLatency app. Switch between 60/90. Test: Turn off all policies. Play youtube video. Test: Turn off all policies. Open Chrome. Play video. --- services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp | 9 +++++++++ services/surfaceflinger/Scheduler/RefreshRateConfigs.h | 4 ++++ services/surfaceflinger/Scheduler/Scheduler.cpp | 4 ++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index c73e825d51..8202515bec 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -229,6 +229,15 @@ const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const { return *mCurrentRefreshRate; } +const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicy() const { + std::lock_guard lock(mLock); + if (std::find(mAvailableRefreshRates.begin(), mAvailableRefreshRates.end(), + mCurrentRefreshRate) != mAvailableRefreshRates.end()) { + return *mCurrentRefreshRate; + } + return mRefreshRates.at(mDefaultConfig); +} + void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) { std::lock_guard lock(mLock); mCurrentRefreshRate = &mRefreshRates.at(configId); diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index fc959597a3..e5bb55710d 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -149,6 +149,10 @@ public: // Returns the current refresh rate const RefreshRate& getCurrentRefreshRate() const EXCLUDES(mLock); + // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by + // the policy. + const RefreshRate& getCurrentRefreshRateByPolicy() const; + // Returns the refresh rate that corresponds to a HwcConfigIndexType. This won't change at // runtime. const RefreshRate& getRefreshRateFromConfigId(HwcConfigIndexType configId) const { diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 49a269fe5f..adecb8d0fb 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -624,8 +624,8 @@ HwcConfigIndexType Scheduler::calculateRefreshRateType() { .configId; } - // There are no signals for refresh rate, just leave it as is - return mRefreshRateConfigs.getCurrentRefreshRate().configId; + // There are no signals for refresh rate, just leave it as is. + return mRefreshRateConfigs.getCurrentRefreshRateByPolicy().configId; } std::optional Scheduler::getPreferredConfigId() { -- GitLab From a6f8e13c76383fc9d858e01cff184d4097906836 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Thu, 6 Feb 2020 18:37:10 -0800 Subject: [PATCH 0775/1255] Multi-layer blur support Test: open power menu on top of notification shade Test: LayerTypeAndRenderTypeTransaction_test Change-Id: I967a5385199a3ff76928a073471d052f7d6c87dd --- libs/renderengine/gl/GLESRenderEngine.cpp | 38 +++++++++++------ libs/renderengine/gl/filters/BlurFilter.cpp | 8 +++- libs/renderengine/gl/filters/BlurFilter.h | 2 +- ...LayerTypeAndRenderTypeTransaction_test.cpp | 42 +++++++++++++++++++ 4 files changed, 74 insertions(+), 16 deletions(-) diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index e523836c59..e11b59ff24 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -984,18 +984,19 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, } std::unique_ptr fbo; - // Let's find the topmost layer requesting background blur (if any.) - // Blurs in multiple layers are not supported, given the cost of the shader. - const LayerSettings* blurLayer = nullptr; + // Gathering layers that requested blur, we'll need them to decide when to render to an + // offscreen buffer, and when to render to the native buffer. + std::deque blurLayers; if (CC_LIKELY(mBlurFilter != nullptr)) { - for (auto const layer : layers) { + for (auto layer : layers) { if (layer->backgroundBlurRadius > 0) { - blurLayer = layer; + blurLayers.push_back(layer); } } } + const auto blurLayersSize = blurLayers.size(); - if (blurLayer == nullptr) { + if (blurLayersSize == 0) { fbo = std::make_unique(*this, buffer, useFramebufferCache); if (fbo->getStatus() != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", @@ -1006,7 +1007,8 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, setViewportAndProjection(display.physicalDisplay, display.clip); } else { setViewportAndProjection(display.physicalDisplay, display.clip); - auto status = mBlurFilter->setAsDrawTarget(display, blurLayer->backgroundBlurRadius); + auto status = + mBlurFilter->setAsDrawTarget(display, blurLayers.front()->backgroundBlurRadius); if (status != NO_ERROR) { ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).", buffer->handle); @@ -1039,7 +1041,9 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, .setCropCoords(2 /* size */) .build(); for (auto const layer : layers) { - if (blurLayer == layer) { + if (blurLayers.size() > 0 && blurLayers.front() == layer) { + blurLayers.pop_front(); + auto status = mBlurFilter->prepare(); if (status != NO_ERROR) { ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", @@ -1048,18 +1052,26 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, return status; } - fbo = std::make_unique(*this, buffer, - useFramebufferCache); - status = fbo->getStatus(); + if (blurLayers.size() == 0) { + // Done blurring, time to bind the native FBO and render our blur onto it. + fbo = std::make_unique(*this, buffer, + useFramebufferCache); + status = fbo->getStatus(); + setViewportAndProjection(display.physicalDisplay, display.clip); + } else { + // There's still something else to blur, so let's keep rendering to our FBO + // instead of to the display. + status = mBlurFilter->setAsDrawTarget(display, + blurLayers.front()->backgroundBlurRadius); + } if (status != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", buffer->handle); checkErrors("Can't bind native framebuffer"); return status; } - setViewportAndProjection(display.physicalDisplay, display.clip); - status = mBlurFilter->render(); + status = mBlurFilter->render(blurLayersSize > 1); if (status != NO_ERROR) { ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", buffer->handle); diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index f8b0a7a891..b1a84bd0c2 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -96,13 +96,17 @@ void BlurFilter::drawMesh(GLuint uv, GLuint position) { mEngine.checkErrors("Drawing blur mesh"); } -status_t BlurFilter::render() { +status_t BlurFilter::render(bool multiPass) { ATRACE_NAME("BlurFilter::render"); // Now let's scale our blur up. It will be interpolated with the larger composited // texture for the first frames, to hide downscaling artifacts. GLfloat mix = fmin(1.0, mRadius / kMaxCrossFadeRadius); - if (mix >= 1) { + + // When doing multiple passes, we cannot try to read mCompositionFbo, given that we'll + // be writing onto it. Let's disable the crossfade, otherwise we'd need 1 extra frame buffer, + // as large as the screen size. + if (mix >= 1 || multiPass) { mBlurredFbo.bindAsReadBuffer(); glBlitFramebuffer(0, 0, mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight(), 0, 0, mDisplayWidth, mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h index 67b3895262..52dc8aab3c 100644 --- a/libs/renderengine/gl/filters/BlurFilter.h +++ b/libs/renderengine/gl/filters/BlurFilter.h @@ -45,7 +45,7 @@ public: // Execute blur passes, rendering to offscreen texture. virtual status_t prepare() = 0; // Render blur to the bound framebuffer (screen). - status_t render(); + status_t render(bool multiPass); protected: uint32_t mRadius; diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index 3bbd12a242..9e619ca8ff 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -279,6 +279,48 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadius) { 50 /* tolerance */); } +TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusOnMultipleLayers) { + char value[PROPERTY_VALUE_MAX]; + property_get("ro.surface_flinger.supports_background_blur", value, "0"); + if (!atoi(value)) { + // This device doesn't support blurs, no-op. + return; + } + + auto size = 256; + auto center = size / 2; + auto blurRadius = 50; + + sp backgroundLayer; + ASSERT_NO_FATAL_FAILURE(backgroundLayer = createLayer("background", size, size)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(backgroundLayer, Color::GREEN, size, size)); + + sp leftLayer; + ASSERT_NO_FATAL_FAILURE(leftLayer = createLayer("left", size / 2, size)); + ASSERT_NO_FATAL_FAILURE(fillLayerColor(leftLayer, Color::RED, size / 2, size)); + + sp blurLayer1; + auto centralSquareSize = size / 2; + ASSERT_NO_FATAL_FAILURE(blurLayer1 = + createLayer("blur1", centralSquareSize, centralSquareSize)); + ASSERT_NO_FATAL_FAILURE( + fillLayerColor(blurLayer1, Color::BLUE, centralSquareSize, centralSquareSize)); + + sp blurLayer2; + ASSERT_NO_FATAL_FAILURE(blurLayer2 = createLayer("blur2", size, size)); + ASSERT_NO_FATAL_FAILURE( + fillLayerColor(blurLayer2, Color::TRANSPARENT, centralSquareSize, centralSquareSize)); + + Transaction() + .setBackgroundBlurRadius(blurLayer1, blurRadius) + .setBackgroundBlurRadius(blurLayer2, blurRadius) + .apply(); + + auto shot = getScreenCapture(); + shot->expectColor(Rect(center - 5, center - 5, center, center), Color{100, 100, 100, 255}, + 40 /* tolerance */); +} + TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) { sp bufferLayer; ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32)); -- GitLab From 62493096843ffd4fd2a134588181599727f1c10d Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 15 Jan 2020 16:04:47 -0800 Subject: [PATCH 0776/1255] Remove libbinder usage from media.swcodec apex libgui_bufferqueue_static is used by com.android.media.swcodec apex which doesn't do any IPC through binder. Remove binder dependency to eliminate any possibility of IPC via any unstable interfaces. b/147759770 b/139201422 test: atest CtsMediaTestCases -- --module-arg CtsMediaTestCases:size:small Change-Id: I98dbe751527bf4725c7764ba21f46b6af60968b4 --- libs/gui/Android.bp | 27 +-- libs/gui/BufferQueueConsumer.cpp | 12 +- libs/gui/BufferQueueProducer.cpp | 8 +- libs/gui/BufferQueueThreadState.cpp | 10 ++ libs/gui/IConsumerListener.cpp | 1 - libs/gui/IGraphicBufferProducer.cpp | 128 -------------- libs/gui/IProducerListener.cpp | 2 - libs/gui/QueueBufferInputOutput.cpp | 159 ++++++++++++++++++ libs/gui/bufferqueue/1.0/Conversion.cpp | 65 ------- .../bufferqueue/1.0/H2BProducerListener.cpp | 4 + .../gui/bufferqueue/1.0/WProducerListener.cpp | 2 + .../2.0/B2HGraphicBufferProducer.cpp | 26 +++ .../bufferqueue/2.0/H2BProducerListener.cpp | 7 + libs/gui/include/gui/BufferQueueProducer.h | 5 + libs/gui/include/gui/IConsumerListener.h | 8 + libs/gui/include/gui/IGraphicBufferConsumer.h | 11 +- libs/gui/include/gui/IGraphicBufferProducer.h | 32 ++-- libs/gui/include/gui/IProducerListener.h | 7 + .../include/gui/bufferqueue/1.0/Conversion.h | 11 -- .../gui/bufferqueue/1.0/H2BProducerListener.h | 5 + .../bufferqueue/1.0/WGraphicBufferProducer.h | 1 - .../gui/bufferqueue/1.0/WProducerListener.h | 2 +- .../2.0/B2HGraphicBufferProducer.h | 2 + .../gui/bufferqueue/2.0/H2BProducerListener.h | 8 + 24 files changed, 307 insertions(+), 236 deletions(-) create mode 100644 libs/gui/QueueBufferInputOutput.cpp diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 40c044df0a..99d385624b 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -55,7 +55,11 @@ cc_library_shared { "DisplayEventReceiver.cpp", "GLConsumer.cpp", "GuiConfig.cpp", + "IConsumerListener.cpp", "IDisplayEventConnection.cpp", + "IGraphicBufferConsumer.cpp", + "IGraphicBufferProducer.cpp", + "IProducerListener.cpp", "IRegionSamplingListener.cpp", "ISurfaceComposer.cpp", "ISurfaceComposerClient.cpp", @@ -63,22 +67,32 @@ cc_library_shared { "LayerDebugInfo.cpp", "LayerMetadata.cpp", "LayerState.cpp", + "OccupancyTracker.cpp", "StreamSplitter.cpp", "Surface.cpp", "SurfaceControl.cpp", "SurfaceComposerClient.cpp", "SyncFeatures.cpp", "view/Surface.cpp", + "bufferqueue/1.0/B2HProducerListener.cpp", + "bufferqueue/1.0/H2BGraphicBufferProducer.cpp", + "bufferqueue/2.0/B2HProducerListener.cpp", + "bufferqueue/2.0/H2BGraphicBufferProducer.cpp", ], shared_libs: [ "android.frameworks.bufferhub@1.0", + "libbinder", "libbufferhub", "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui. "libinput", "libpdx_default_transport", ], + export_shared_lib_headers: [ + "libbinder", + ], + // bufferhub is not used when building libgui for vendors target: { vendor: { @@ -118,6 +132,7 @@ cc_library_static { cflags: [ "-DNO_BUFFERHUB", + "-DNO_BINDER", ], defaults: ["libgui_bufferqueue-defaults"], @@ -140,19 +155,11 @@ filegroup { "FrameTimestamps.cpp", "GLConsumerUtils.cpp", "HdrMetadata.cpp", - "IConsumerListener.cpp", - "IGraphicBufferConsumer.cpp", - "IGraphicBufferProducer.cpp", - "IProducerListener.cpp", - "OccupancyTracker.cpp", - "bufferqueue/1.0/B2HProducerListener.cpp", + "QueueBufferInputOutput.cpp", "bufferqueue/1.0/Conversion.cpp", - "bufferqueue/1.0/H2BGraphicBufferProducer.cpp", "bufferqueue/1.0/H2BProducerListener.cpp", "bufferqueue/1.0/WProducerListener.cpp", "bufferqueue/2.0/B2HGraphicBufferProducer.cpp", - "bufferqueue/2.0/B2HProducerListener.cpp", - "bufferqueue/2.0/H2BGraphicBufferProducer.cpp", "bufferqueue/2.0/H2BProducerListener.cpp", "bufferqueue/2.0/types.cpp", ], @@ -189,7 +196,6 @@ cc_defaults { "android.hardware.graphics.common@1.2", "android.hidl.token@1.0-utils", "libbase", - "libbinder", "libcutils", "libEGL", "libGLESv2", @@ -212,7 +218,6 @@ cc_defaults { ], export_shared_lib_headers: [ - "libbinder", "libEGL", "libnativewindow", "libui", diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 9b74fef752..4435265bb2 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -66,6 +66,8 @@ namespace android { mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) +ConsumerListener::~ConsumerListener() = default; + BufferQueueConsumer::BufferQueueConsumer(const sp& core) : mCore(core), mSlots(core->mSlots), @@ -291,8 +293,9 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, ATRACE_INT(mCore->mConsumerName.string(), static_cast(mCore->mQueue.size())); +#ifndef NO_BINDER mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size()); - +#endif VALIDATE_CONSISTENCY(); } @@ -765,7 +768,12 @@ status_t BufferQueueConsumer::getSidebandStream(sp* outStream) con status_t BufferQueueConsumer::getOccupancyHistory(bool forceFlush, std::vector* outHistory) { std::lock_guard lock(mCore->mMutex); +#ifndef NO_BINDER *outHistory = mCore->mOccupancyTracker.getSegmentHistory(forceFlush); +#else + (void)forceFlush; + outHistory->clear(); +#endif return NO_ERROR; } @@ -798,7 +806,7 @@ status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResul bool denied = false; const uid_t uid = BufferQueueThreadState::getCallingUid(); -#ifndef __ANDROID_VNDK__ +#if !defined(__ANDROID_VNDK__) && !defined(NO_BINDER) // permission check can't be done for vendors as vendors have no access to // the PermissionController. We need to do a runtime check as well, since // the system variant of libgui can be loaded in a vendor process. For eg: diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 6b11a54e2b..9e86838592 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -67,6 +67,7 @@ namespace android { ##__VA_ARGS__) static constexpr uint32_t BQ_LAYER_COUNT = 1; +ProducerListener::~ProducerListener() = default; BufferQueueProducer::BufferQueueProducer(const sp& core, bool consumerIsSurfaceFlinger) : @@ -1005,8 +1006,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, ATRACE_INT(mCore->mConsumerName.string(), static_cast(mCore->mQueue.size())); +#ifndef NO_BINDER mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size()); - +#endif // Take a ticket for the callback functions callbackTicket = mNextCallbackTicket++; @@ -1252,6 +1254,7 @@ status_t BufferQueueProducer::connect(const sp& listener, if (listener != nullptr) { // Set up a death notification so that we can disconnect // automatically if the remote producer dies +#ifndef NO_BINDER if (IInterface::asBinder(listener)->remoteBinder() != nullptr) { status = IInterface::asBinder(listener)->linkToDeath( static_cast(this)); @@ -1261,6 +1264,7 @@ status_t BufferQueueProducer::connect(const sp& listener, } mCore->mLinkedToDeath = listener; } +#endif mCore->mConnectedProducerListener = listener; mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify(); } @@ -1329,6 +1333,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { if (mCore->mConnectedApi == api) { mCore->freeAllBuffersLocked(); +#ifndef NO_BINDER // Remove our death notification callback if we have one if (mCore->mLinkedToDeath != nullptr) { sp token = @@ -1338,6 +1343,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { token->unlinkToDeath( static_cast(this)); } +#endif mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; mCore->mLinkedToDeath = nullptr; diff --git a/libs/gui/BufferQueueThreadState.cpp b/libs/gui/BufferQueueThreadState.cpp index c13030b1ed..976c9b9d50 100644 --- a/libs/gui/BufferQueueThreadState.cpp +++ b/libs/gui/BufferQueueThreadState.cpp @@ -14,8 +14,10 @@ * limitations under the License. */ +#ifndef NO_BINDER #include #include +#endif // NO_BINDER #include #include #include @@ -23,17 +25,25 @@ namespace android { uid_t BufferQueueThreadState::getCallingUid() { +#ifndef NO_BINDER if (getCurrentServingCall() == BinderCallType::HWBINDER) { return hardware::IPCThreadState::self()->getCallingUid(); } return IPCThreadState::self()->getCallingUid(); +#else // NO_BINDER + return hardware::IPCThreadState::self()->getCallingUid(); +#endif // NO_BINDER } pid_t BufferQueueThreadState::getCallingPid() { +#ifndef NO_BINDER if (getCurrentServingCall() == BinderCallType::HWBINDER) { return hardware::IPCThreadState::self()->getCallingPid(); } return IPCThreadState::self()->getCallingPid(); +#else // NO_BINDER + return hardware::IPCThreadState::self()->getCallingPid(); +#endif // NO_BINDER } } // namespace android diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp index 48cb4b9db8..f3bd90cffb 100644 --- a/libs/gui/IConsumerListener.cpp +++ b/libs/gui/IConsumerListener.cpp @@ -90,7 +90,6 @@ public: // Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see // clang warning -Wweak-vtables) BpConsumerListener::~BpConsumerListener() = default; -ConsumerListener::~ConsumerListener() = default; IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener"); diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 75876f26f3..7b5596e43c 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -1113,133 +1113,5 @@ IGraphicBufferProducer::QueueBufferInput::QueueBufferInput(const Parcel& parcel) parcel.read(*this); } -constexpr size_t IGraphicBufferProducer::QueueBufferInput::minFlattenedSize() { - return sizeof(timestamp) + - sizeof(isAutoTimestamp) + - sizeof(dataSpace) + - sizeof(crop) + - sizeof(scalingMode) + - sizeof(transform) + - sizeof(stickyTransform) + - sizeof(getFrameTimestamps); -} - -size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { - return minFlattenedSize() + - fence->getFlattenedSize() + - surfaceDamage.getFlattenedSize() + - hdrMetadata.getFlattenedSize(); -} - -size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { - return fence->getFdCount(); -} - -status_t IGraphicBufferProducer::QueueBufferInput::flatten( - void*& buffer, size_t& size, int*& fds, size_t& count) const -{ - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - - FlattenableUtils::write(buffer, size, timestamp); - FlattenableUtils::write(buffer, size, isAutoTimestamp); - FlattenableUtils::write(buffer, size, dataSpace); - FlattenableUtils::write(buffer, size, crop); - FlattenableUtils::write(buffer, size, scalingMode); - FlattenableUtils::write(buffer, size, transform); - FlattenableUtils::write(buffer, size, stickyTransform); - FlattenableUtils::write(buffer, size, getFrameTimestamps); - - status_t result = fence->flatten(buffer, size, fds, count); - if (result != NO_ERROR) { - return result; - } - result = surfaceDamage.flatten(buffer, size); - if (result != NO_ERROR) { - return result; - } - FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); - return hdrMetadata.flatten(buffer, size); -} - -status_t IGraphicBufferProducer::QueueBufferInput::unflatten( - void const*& buffer, size_t& size, int const*& fds, size_t& count) -{ - if (size < minFlattenedSize()) { - return NO_MEMORY; - } - - FlattenableUtils::read(buffer, size, timestamp); - FlattenableUtils::read(buffer, size, isAutoTimestamp); - FlattenableUtils::read(buffer, size, dataSpace); - FlattenableUtils::read(buffer, size, crop); - FlattenableUtils::read(buffer, size, scalingMode); - FlattenableUtils::read(buffer, size, transform); - FlattenableUtils::read(buffer, size, stickyTransform); - FlattenableUtils::read(buffer, size, getFrameTimestamps); - - fence = new Fence(); - status_t result = fence->unflatten(buffer, size, fds, count); - if (result != NO_ERROR) { - return result; - } - result = surfaceDamage.unflatten(buffer, size); - if (result != NO_ERROR) { - return result; - } - FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); - return hdrMetadata.unflatten(buffer, size); -} - -// ---------------------------------------------------------------------------- -constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() { - return sizeof(width) + sizeof(height) + sizeof(transformHint) + sizeof(numPendingBuffers) + - sizeof(nextFrameNumber) + sizeof(bufferReplaced) + sizeof(maxBufferCount); -} - -size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const { - return minFlattenedSize() + frameTimestamps.getFlattenedSize(); -} - -size_t IGraphicBufferProducer::QueueBufferOutput::getFdCount() const { - return frameTimestamps.getFdCount(); -} - -status_t IGraphicBufferProducer::QueueBufferOutput::flatten( - void*& buffer, size_t& size, int*& fds, size_t& count) const -{ - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - - FlattenableUtils::write(buffer, size, width); - FlattenableUtils::write(buffer, size, height); - FlattenableUtils::write(buffer, size, transformHint); - FlattenableUtils::write(buffer, size, numPendingBuffers); - FlattenableUtils::write(buffer, size, nextFrameNumber); - FlattenableUtils::write(buffer, size, bufferReplaced); - FlattenableUtils::write(buffer, size, maxBufferCount); - - return frameTimestamps.flatten(buffer, size, fds, count); -} - -status_t IGraphicBufferProducer::QueueBufferOutput::unflatten( - void const*& buffer, size_t& size, int const*& fds, size_t& count) -{ - if (size < minFlattenedSize()) { - return NO_MEMORY; - } - - FlattenableUtils::read(buffer, size, width); - FlattenableUtils::read(buffer, size, height); - FlattenableUtils::read(buffer, size, transformHint); - FlattenableUtils::read(buffer, size, numPendingBuffers); - FlattenableUtils::read(buffer, size, nextFrameNumber); - FlattenableUtils::read(buffer, size, bufferReplaced); - FlattenableUtils::read(buffer, size, maxBufferCount); - - return frameTimestamps.unflatten(buffer, size, fds, count); -} }; // namespace android diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp index 808e3369f1..5c81b9d7db 100644 --- a/libs/gui/IProducerListener.cpp +++ b/libs/gui/IProducerListener.cpp @@ -119,8 +119,6 @@ status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data, return BBinder::onTransact(code, data, reply, flags); } -ProducerListener::~ProducerListener() = default; - DummyProducerListener::~DummyProducerListener() = default; bool BnProducerListener::needsReleaseNotify() { diff --git a/libs/gui/QueueBufferInputOutput.cpp b/libs/gui/QueueBufferInputOutput.cpp new file mode 100644 index 0000000000..30f0ef6785 --- /dev/null +++ b/libs/gui/QueueBufferInputOutput.cpp @@ -0,0 +1,159 @@ +/* + * Copyright 2010 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 + +#define LOG_TAG "QueueBufferInputOutput" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define LOG_NDEBUG 0 + +#include + +namespace android { + +constexpr size_t IGraphicBufferProducer::QueueBufferInput::minFlattenedSize() { + return sizeof(timestamp) + + sizeof(isAutoTimestamp) + + sizeof(dataSpace) + + sizeof(crop) + + sizeof(scalingMode) + + sizeof(transform) + + sizeof(stickyTransform) + + sizeof(getFrameTimestamps); +} + +IGraphicBufferProducer::QueueBufferInput::QueueBufferInput(const Parcel& parcel) { + parcel.read(*this); +} + +size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { + return minFlattenedSize() + + fence->getFlattenedSize() + + surfaceDamage.getFlattenedSize() + + hdrMetadata.getFlattenedSize(); +} + +size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { + return fence->getFdCount(); +} + +status_t IGraphicBufferProducer::QueueBufferInput::flatten( + void*& buffer, size_t& size, int*& fds, size_t& count) const +{ + if (size < getFlattenedSize()) { + return NO_MEMORY; + } + + FlattenableUtils::write(buffer, size, timestamp); + FlattenableUtils::write(buffer, size, isAutoTimestamp); + FlattenableUtils::write(buffer, size, dataSpace); + FlattenableUtils::write(buffer, size, crop); + FlattenableUtils::write(buffer, size, scalingMode); + FlattenableUtils::write(buffer, size, transform); + FlattenableUtils::write(buffer, size, stickyTransform); + FlattenableUtils::write(buffer, size, getFrameTimestamps); + + status_t result = fence->flatten(buffer, size, fds, count); + if (result != NO_ERROR) { + return result; + } + result = surfaceDamage.flatten(buffer, size); + if (result != NO_ERROR) { + return result; + } + FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); + return hdrMetadata.flatten(buffer, size); +} + +status_t IGraphicBufferProducer::QueueBufferInput::unflatten( + void const*& buffer, size_t& size, int const*& fds, size_t& count) +{ + if (size < minFlattenedSize()) { + return NO_MEMORY; + } + + FlattenableUtils::read(buffer, size, timestamp); + FlattenableUtils::read(buffer, size, isAutoTimestamp); + FlattenableUtils::read(buffer, size, dataSpace); + FlattenableUtils::read(buffer, size, crop); + FlattenableUtils::read(buffer, size, scalingMode); + FlattenableUtils::read(buffer, size, transform); + FlattenableUtils::read(buffer, size, stickyTransform); + FlattenableUtils::read(buffer, size, getFrameTimestamps); + + fence = new Fence(); + status_t result = fence->unflatten(buffer, size, fds, count); + if (result != NO_ERROR) { + return result; + } + result = surfaceDamage.unflatten(buffer, size); + if (result != NO_ERROR) { + return result; + } + FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); + return hdrMetadata.unflatten(buffer, size); +} + +//////////////////////////////////////////////////////////////////////// +constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() { + return sizeof(width) + sizeof(height) + sizeof(transformHint) + sizeof(numPendingBuffers) + + sizeof(nextFrameNumber) + sizeof(bufferReplaced) + sizeof(maxBufferCount); +} +size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const { + return minFlattenedSize() + frameTimestamps.getFlattenedSize(); +} + +size_t IGraphicBufferProducer::QueueBufferOutput::getFdCount() const { + return frameTimestamps.getFdCount(); +} + +status_t IGraphicBufferProducer::QueueBufferOutput::flatten( + void*& buffer, size_t& size, int*& fds, size_t& count) const +{ + if (size < getFlattenedSize()) { + return NO_MEMORY; + } + + FlattenableUtils::write(buffer, size, width); + FlattenableUtils::write(buffer, size, height); + FlattenableUtils::write(buffer, size, transformHint); + FlattenableUtils::write(buffer, size, numPendingBuffers); + FlattenableUtils::write(buffer, size, nextFrameNumber); + FlattenableUtils::write(buffer, size, bufferReplaced); + FlattenableUtils::write(buffer, size, maxBufferCount); + + return frameTimestamps.flatten(buffer, size, fds, count); +} + +status_t IGraphicBufferProducer::QueueBufferOutput::unflatten( + void const*& buffer, size_t& size, int const*& fds, size_t& count) +{ + if (size < minFlattenedSize()) { + return NO_MEMORY; + } + + FlattenableUtils::read(buffer, size, width); + FlattenableUtils::read(buffer, size, height); + FlattenableUtils::read(buffer, size, transformHint); + FlattenableUtils::read(buffer, size, numPendingBuffers); + FlattenableUtils::read(buffer, size, nextFrameNumber); + FlattenableUtils::read(buffer, size, bufferReplaced); + FlattenableUtils::read(buffer, size, maxBufferCount); + + return frameTimestamps.unflatten(buffer, size, fds, count); +} + +} // namespace android diff --git a/libs/gui/bufferqueue/1.0/Conversion.cpp b/libs/gui/bufferqueue/1.0/Conversion.cpp index 5cb35933e9..3e20a37d54 100644 --- a/libs/gui/bufferqueue/1.0/Conversion.cpp +++ b/libs/gui/bufferqueue/1.0/Conversion.cpp @@ -108,20 +108,6 @@ status_t toStatusT(Return const& t) { return t.isOk() ? OK : (t.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR); } -/** - * \brief Convert `Return` to `binder::Status`. - * - * \param[in] t The source `Return`. - * \return The corresponding `binder::Status`. - */ -// convert: Return -> ::android::binder::Status -::android::binder::Status toBinderStatus( - Return const& t) { - return ::android::binder::Status::fromExceptionCode( - toStatusT(t), - t.description().c_str()); -} - /** * \brief Wrap `native_handle_t*` in `hidl_handle`. * @@ -1337,57 +1323,6 @@ status_t unflatten( return unflatten(&(t->surfaceDamage), buffer, size); } -/** - * \brief Wrap `BGraphicBufferProducer::QueueBufferInput` in - * `HGraphicBufferProducer::QueueBufferInput`. - * - * \param[out] t The wrapper of type - * `HGraphicBufferProducer::QueueBufferInput`. - * \param[out] nh The underlying native handle for `t->fence`. - * \param[in] l The source `BGraphicBufferProducer::QueueBufferInput`. - * - * If the return value is `true` and `t->fence` contains a valid file - * descriptor, \p nh will be a newly created native handle holding that file - * descriptor. \p nh needs to be deleted with `native_handle_delete()` - * afterwards. - */ -bool wrapAs( - HGraphicBufferProducer::QueueBufferInput* t, - native_handle_t** nh, - BGraphicBufferProducer::QueueBufferInput const& l) { - - size_t const baseSize = l.getFlattenedSize(); - std::unique_ptr baseBuffer( - new (std::nothrow) uint8_t[baseSize]); - if (!baseBuffer) { - return false; - } - - size_t const baseNumFds = l.getFdCount(); - std::unique_ptr baseFds( - new (std::nothrow) int[baseNumFds]); - if (!baseFds) { - return false; - } - - void* buffer = static_cast(baseBuffer.get()); - size_t size = baseSize; - int* fds = baseFds.get(); - size_t numFds = baseNumFds; - if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) { - return false; - } - - void const* constBuffer = static_cast(baseBuffer.get()); - size = baseSize; - int const* constFds = static_cast(baseFds.get()); - numFds = baseNumFds; - if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) { - return false; - } - - return true; -} /** * \brief Convert `HGraphicBufferProducer::QueueBufferInput` to diff --git a/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp index 2712f42c89..598c8dea9b 100644 --- a/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp +++ b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp @@ -32,7 +32,11 @@ namespace utils { using ::android::hardware::Return; H2BProducerListener::H2BProducerListener(sp const& base) +#ifndef NO_BINDER : CBase{base} { +#else + : mBase(base) { +#endif } void H2BProducerListener::onBufferReleased() { diff --git a/libs/gui/bufferqueue/1.0/WProducerListener.cpp b/libs/gui/bufferqueue/1.0/WProducerListener.cpp index 78dc4e8b18..56b64b9ddd 100644 --- a/libs/gui/bufferqueue/1.0/WProducerListener.cpp +++ b/libs/gui/bufferqueue/1.0/WProducerListener.cpp @@ -46,5 +46,7 @@ void LWProducerListener::onBufferReleased() { bool LWProducerListener::needsReleaseNotify() { return static_cast(mBase->needsReleaseNotify()); } +void LWProducerListener::onBuffersDiscarded(const std::vector& /*slots*/) { +} } // namespace android diff --git a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp index e891ec581e..0f3ae2e28c 100644 --- a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp +++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp @@ -249,6 +249,24 @@ Return B2HGraphicBufferProducer::query(int32_t what, query_cb _hidl_cb) { return {}; } +struct Obituary : public hardware::hidl_death_recipient { + wp producer; + sp listener; + HConnectionType apiType; + Obituary(const wp& p, + const sp& l, + HConnectionType t) + : producer(p), listener(l), apiType(t) {} + + void serviceDied(uint64_t /* cookie */, + const wp<::android::hidl::base::V1_0::IBase>& /* who */) override { + sp dr = producer.promote(); + if (dr != nullptr) { + (void)dr->disconnect(apiType); + } + } +}; + Return B2HGraphicBufferProducer::connect( sp const& hListener, HConnectionType hConnectionType, @@ -270,6 +288,10 @@ Return B2HGraphicBufferProducer::connect( &bOutput), &hStatus) && b2h(bOutput, &hOutput); + if (converted) { + mObituary = new Obituary(this, hListener, hConnectionType); + hListener->linkToDeath(mObituary, 0); + } _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, hOutput); return {}; } @@ -282,6 +304,10 @@ Return B2HGraphicBufferProducer::disconnect( } HStatus hStatus{}; bool converted = b2h(mBase->disconnect(bConnectionType), &hStatus); + if (mObituary != nullptr) { + mObituary->listener->unlinkToDeath(mObituary); + mObituary.clear(); + } return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; } diff --git a/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp index b81a357d63..b2bd1172d6 100644 --- a/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp +++ b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp @@ -32,7 +32,11 @@ namespace utils { using ::android::hardware::Return; H2BProducerListener::H2BProducerListener(sp const& base) +#ifndef NO_BINDER : CBase{base} { +#else + : mBase(base) { +#endif } void H2BProducerListener::onBufferReleased() { @@ -48,6 +52,9 @@ bool H2BProducerListener::needsReleaseNotify() { return static_cast(mBase); } +void H2BProducerListener::onBuffersDiscarded(const std::vector& /*slots*/) { +} + } // namespace utils } // namespace V2_0 } // namespace bufferqueue diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index 2dec663183..cbace5bb8b 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -22,10 +22,15 @@ namespace android { +class IBinder; struct BufferSlot; +#ifndef NO_BINDER class BufferQueueProducer : public BnGraphicBufferProducer, private IBinder::DeathRecipient { +#else +class BufferQueueProducer : public BnGraphicBufferProducer { +#endif public: friend class BufferQueue; // Needed to access binderDied diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h index 046f6e10d0..0ab2399eb2 100644 --- a/libs/gui/include/gui/IConsumerListener.h +++ b/libs/gui/include/gui/IConsumerListener.h @@ -92,6 +92,7 @@ public: FrameEventHistoryDelta* /*outDelta*/) {} }; +#ifndef NO_BINDER class IConsumerListener : public ConsumerListener, public IInterface { public: DECLARE_META_INTERFACE(ConsumerListener) @@ -105,4 +106,11 @@ public: uint32_t flags = 0) override; }; +#else +class IConsumerListener : public ConsumerListener { +}; +class BnConsumerListener : public IConsumerListener { +}; +#endif + } // namespace android diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h index 54f77b424a..56fe949c9c 100644 --- a/libs/gui/include/gui/IGraphicBufferConsumer.h +++ b/libs/gui/include/gui/IGraphicBufferConsumer.h @@ -35,10 +35,14 @@ class Fence; class GraphicBuffer; class IConsumerListener; class NativeHandle; - +#ifndef NO_BINDER class IGraphicBufferConsumer : public IInterface { public: DECLARE_META_INTERFACE(GraphicBufferConsumer) +#else +class IGraphicBufferConsumer : public RefBase { +public: +#endif enum { // Returned by releaseBuffer, after which the consumer must free any references to the @@ -292,6 +296,7 @@ public: } }; +#ifndef NO_BINDER class BnGraphicBufferConsumer : public SafeBnInterface { public: BnGraphicBufferConsumer() @@ -300,5 +305,9 @@ public: status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override; }; +#else +class BnGraphicBufferConsumer : public IGraphicBufferConsumer { +}; +#endif } // namespace android diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 680d64ed75..87989da19b 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -45,6 +45,13 @@ class IProducerListener; class NativeHandle; class Surface; +using HGraphicBufferProducerV1_0 = + ::android::hardware::graphics::bufferqueue::V1_0:: + IGraphicBufferProducer; +using HGraphicBufferProducerV2_0 = + ::android::hardware::graphics::bufferqueue::V2_0:: + IGraphicBufferProducer; + /* * This class defines the Binder IPC interface for the producer side of * a queue of graphics buffers. It's used to send graphics data from one @@ -59,20 +66,15 @@ class Surface; * * This class was previously called ISurfaceTexture. */ -class IGraphicBufferProducer : public IInterface -{ -public: - using HGraphicBufferProducerV1_0 = - ::android::hardware::graphics::bufferqueue::V1_0:: - IGraphicBufferProducer; - using HGraphicBufferProducerV2_0 = - ::android::hardware::graphics::bufferqueue::V2_0:: - IGraphicBufferProducer; - +#ifndef NO_BINDER +class IGraphicBufferProducer : public IInterface { DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducerV1_0, HGraphicBufferProducerV2_0) - +#else +class IGraphicBufferProducer : public RefBase { +#endif +public: enum { // A flag returned by dequeueBuffer when the client needs to call // requestBuffer immediately thereafter. @@ -640,6 +642,7 @@ public: // Sets the apps intended frame rate. virtual status_t setFrameRate(float frameRate); +#ifndef NO_BINDER // Static method exports any IGraphicBufferProducer object to a parcel. It // handles null producer as well. static status_t exportToParcel(const sp& producer, @@ -657,10 +660,11 @@ protected: // it writes a strong binder object; for BufferHub, it writes a // ProducerQueueParcelable object. virtual status_t exportToParcel(Parcel* parcel); +#endif }; // ---------------------------------------------------------------------------- - +#ifndef NO_BINDER class BnGraphicBufferProducer : public BnInterface { public: @@ -669,6 +673,10 @@ public: Parcel* reply, uint32_t flags = 0); }; +#else +class BnGraphicBufferProducer : public IGraphicBufferProducer { +}; +#endif // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h index 32a3690ff2..0b1f4b5838 100644 --- a/libs/gui/include/gui/IProducerListener.h +++ b/libs/gui/include/gui/IProducerListener.h @@ -51,6 +51,7 @@ public: virtual void onBuffersDiscarded(const std::vector& slots) = 0; // Asynchronous }; +#ifndef NO_BINDER class IProducerListener : public ProducerListener, public IInterface { public: @@ -73,6 +74,12 @@ public: virtual void onBuffersDiscarded(const std::vector& slots); }; +#else +class IProducerListener : public ProducerListener { +}; +class BnProducerListener : public IProducerListener { +}; +#endif class DummyProducerListener : public BnProducerListener { public: diff --git a/libs/gui/include/gui/bufferqueue/1.0/Conversion.h b/libs/gui/include/gui/bufferqueue/1.0/Conversion.h index 627845c0ea..811dcbeb02 100644 --- a/libs/gui/include/gui/bufferqueue/1.0/Conversion.h +++ b/libs/gui/include/gui/bufferqueue/1.0/Conversion.h @@ -25,8 +25,6 @@ #include #include -#include -#include #include #include #include @@ -126,15 +124,6 @@ int native_handle_read_fd(native_handle_t const* nh, int index = 0); * `convertTo()` do. */ -/** - * \brief Convert `Return` to `binder::Status`. - * - * \param[in] t The source `Return`. - * \return The corresponding `binder::Status`. - */ -// convert: Return -> ::android::binder::Status -::android::binder::Status toBinderStatus(Return const& t); - /** * \brief Convert `Return` to `status_t`. This is for legacy binder calls. * diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h index 211fdd5351..cda5103334 100644 --- a/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h +++ b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h @@ -34,7 +34,12 @@ using HProducerListener = ::android::hardware::graphics::bufferqueue::V1_0:: using BProducerListener = ::android::IProducerListener; class H2BProducerListener +#ifndef NO_BINDER : public H2BConverter { +#else + : public BProducerListener { + sp mBase; +#endif public: H2BProducerListener(sp const& base); virtual void onBufferReleased() override; diff --git a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h index 029dcc047f..99ab0857d3 100644 --- a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h +++ b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h @@ -49,7 +49,6 @@ typedef ::android::hardware::graphics::bufferqueue::V1_0:: typedef ::android::IGraphicBufferProducer BGraphicBufferProducer; typedef ::android::IProducerListener BProducerListener; -using ::android::BnGraphicBufferProducer; #ifndef LOG struct LOG_dummy { diff --git a/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h index 51dff5b8be..197db26444 100644 --- a/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h +++ b/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h @@ -20,7 +20,6 @@ #include #include -#include #include #include @@ -55,6 +54,7 @@ public: LWProducerListener(sp const& base); void onBufferReleased() override; bool needsReleaseNotify() override; + void onBuffersDiscarded(const std::vector& slots) override; }; } // namespace android diff --git a/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h index 1c58167752..16d054ba9e 100644 --- a/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h +++ b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h @@ -45,6 +45,7 @@ using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::graphics::common::V1_2::HardwareBuffer; +struct Obituary; class B2HGraphicBufferProducer : public HGraphicBufferProducer { public: @@ -108,6 +109,7 @@ public: protected: sp mBase; + sp mObituary; }; diff --git a/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h index 898920bf8a..92650b701b 100644 --- a/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h +++ b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h @@ -33,12 +33,20 @@ using HProducerListener = ::android::hardware::graphics::bufferqueue::V2_0:: using BProducerListener = ::android::IProducerListener; +#ifndef NO_BINDER class H2BProducerListener : public H2BConverter { +#else +class H2BProducerListener + : public BProducerListener { + sp mBase; + +#endif public: H2BProducerListener(sp const& base); virtual void onBufferReleased() override; virtual bool needsReleaseNotify() override; + virtual void onBuffersDiscarded(const std::vector& slots) override; }; } // namespace utils -- GitLab From 3803b8d76a0d66ae42b6dd727658c292b42e63e2 Mon Sep 17 00:00:00 2001 From: Ana Krulec Date: Mon, 3 Feb 2020 16:35:46 -0800 Subject: [PATCH 0777/1255] SF: Flag guard setFrameRate() API - LayerHistory is now always created - Do not use LayerHistory when content detection flag is turned off. Bug: 148428554 Test: atest CtsGraphicsTestCases:SetFrameRateTest Test: Play YouTube video. When content detection flag is off, display runs at 90, otherwise at 60. Test: adb shell /data/.../libsurfaceflinger_unittest Change-Id: Iab8b79e16a5257c770d9ddd204cfe26d22de83b6 --- services/surfaceflinger/Layer.cpp | 4 +- .../surfaceflinger/Scheduler/LayerHistory.cpp | 19 --------- .../Scheduler/LayerHistoryV2.cpp | 6 ++- .../surfaceflinger/Scheduler/Scheduler.cpp | 41 ++++++++----------- services/surfaceflinger/Scheduler/Scheduler.h | 5 ++- services/surfaceflinger/SurfaceFlinger.cpp | 3 ++ services/surfaceflinger/SurfaceFlinger.h | 5 +++ .../SurfaceFlingerProperties.cpp | 8 ++++ .../surfaceflinger/SurfaceFlingerProperties.h | 2 + .../sysprop/SurfaceFlingerProperties.sysprop | 10 +++++ .../api/SurfaceFlingerProperties-current.txt | 4 ++ 11 files changed, 61 insertions(+), 46 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index effbed67b8..6ff23c5f51 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -80,7 +80,6 @@ Layer::Layer(const LayerCreationArgs& args) mName(args.name), mClientRef(args.client), mWindowType(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0)) { - uint32_t layerFlags = 0; if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden; if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque; @@ -1264,6 +1263,9 @@ bool Layer::setShadowRadius(float shadowRadius) { } bool Layer::setFrameRate(FrameRate frameRate) { + if (!mFlinger->useFrameRateApi) { + return false; + } if (mCurrentState.frameRate == frameRate) { return false; } diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 9aada11473..b313777253 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -66,7 +66,6 @@ void trace(const wp& weak, int fps) { ATRACE_INT(tag.c_str(), fps); ALOGD("%s: %s @ %d Hz", __FUNCTION__, name.c_str(), fps); } - } // namespace LayerHistory::LayerHistory() @@ -102,23 +101,6 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { partitionLayers(now); - // Find the maximum refresh rate among recently active layers. - for (const auto& [activeLayer, info] : activeLayers()) { - const bool recent = info->isRecentlyActive(now); - - if (recent || CC_UNLIKELY(mTraceEnabled)) { - const float refreshRate = info->getRefreshRate(now); - if (recent && refreshRate > 0.0f) { - if (const auto layer = activeLayer.promote(); layer) { - const int32_t priority = layer->getFrameRateSelectionPriority(); - // TODO(b/142507166): This is where the scoring algorithm should live. - // Layers should be organized by priority - ALOGD("Layer has priority: %d", priority); - } - } - } - } - LayerHistory::Summary summary; for (const auto& [weakLayer, info] : activeLayers()) { const bool recent = info->isRecentlyActive(now); @@ -196,6 +178,5 @@ void LayerHistory::clear() { mActiveLayersEnd = 0; } - } // namespace android::scheduler::impl diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp index ce085f4a1d..6ef6ce414b 100644 --- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp @@ -79,7 +79,6 @@ void trace(const wp& weak, LayerHistory::LayerVoteType type, int fps) { ALOGD("%s: %s @ %d Hz", __FUNCTION__, name.c_str(), fps); } - } // namespace LayerHistoryV2::LayerHistoryV2() @@ -124,6 +123,10 @@ LayerHistoryV2::Summary LayerHistoryV2::summarize(nsecs_t now) { continue; } + // TODO(b/144307188): This needs to be plugged into layer summary as + // an additional parameter. + ALOGV("Layer has priority: %d", strong->getFrameRateSelectionPriority()); + const bool recent = info->isRecentlyActive(now); if (recent) { const auto [type, refreshRate] = info->getRefreshRate(now); @@ -212,5 +215,4 @@ void LayerHistoryV2::clear() { mActiveLayersEnd = 0; } - } // namespace android::scheduler::impl diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 94791ebf28..2b70d65588 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -108,13 +108,10 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, mUseContentDetectionV2(useContentDetectionV2) { using namespace sysprop; - if (property_get_bool("debug.sf.use_content_detection_for_refresh_rate", 0) || - use_content_detection_for_refresh_rate(false)) { - if (mUseContentDetectionV2) { - mLayerHistory = std::make_unique(); - } else { - mLayerHistory = std::make_unique(); - } + if (mUseContentDetectionV2) { + mLayerHistory = std::make_unique(); + } else { + mLayerHistory = std::make_unique(); } const int setIdleTimerMs = property_get_int32("debug.sf.set_idle_timer_ms", 0); @@ -438,7 +435,7 @@ void Scheduler::chooseRefreshRateForContent() { mFeatures.contentDetection = !summary.empty() ? ContentDetectionState::On : ContentDetectionState::Off; - newConfigId = calculateRefreshRateType(); + newConfigId = calculateRefreshRateConfigIndexType(); if (mFeatures.configId == newConfigId) { return; } @@ -531,8 +528,6 @@ void Scheduler::dump(std::string& result) const { using base::StringAppendF; const char* const states[] = {"off", "on"}; - StringAppendF(&result, "+ Content detection: %s\n", states[mLayerHistory != nullptr]); - StringAppendF(&result, "+ Idle timer: %s\n", mIdleTimer ? mIdleTimer->dump().c_str() : states[0]); StringAppendF(&result, "+ Touch timer: %s\n\n", @@ -549,7 +544,7 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO return; } *currentState = newState; - newConfigId = calculateRefreshRateType(); + newConfigId = calculateRefreshRateConfigIndexType(); if (mFeatures.configId == newConfigId) { return; } @@ -563,6 +558,7 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO } bool Scheduler::layerHistoryHasClientSpecifiedFrameRate() { + // Traverse all the layers to see if any of them requested frame rate. for (const auto& layer : mFeatures.contentRequirements) { if (layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitDefault || layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitExactOrMultiple) { @@ -573,10 +569,9 @@ bool Scheduler::layerHistoryHasClientSpecifiedFrameRate() { return false; } -HwcConfigIndexType Scheduler::calculateRefreshRateType() { +HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() { // 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. + // their request should be honored depending on other active layers. if (layerHistoryHasClientSpecifiedFrameRate()) { if (!mUseContentDetectionV2) { return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements) @@ -587,23 +582,23 @@ HwcConfigIndexType Scheduler::calculateRefreshRateType() { } } - // 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 the layer history doesn't have the frame rate specified, check for other features and + // honor them. 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; } - // As long as touch is active we want to be in performance mode + // As long as touch is active we want to be in performance mode. if (mTouchTimer && mFeatures.touch == TouchState::Active) { return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId; } - // If timer has expired as it means there is no new content on the screen + // 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; } @@ -611,7 +606,7 @@ HwcConfigIndexType Scheduler::calculateRefreshRateType() { if (!mUseContentDetectionV2) { // 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. + // NOTE: V1 always calls this, but this is not a default behavior for V2. return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId; } @@ -633,7 +628,7 @@ std::optional Scheduler::getPreferredConfigId() { std::lock_guard lock(mFeatureStateLock); // Make sure that the default config ID is first updated, before returned. if (mFeatures.configId.has_value()) { - mFeatures.configId = calculateRefreshRateType(); + mFeatures.configId = calculateRefreshRateConfigIndexType(); } return mFeatures.configId; } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 01062f85b9..c2345ccc14 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -177,7 +177,10 @@ private: void setVsyncPeriod(nsecs_t period); - HwcConfigIndexType calculateRefreshRateType() REQUIRES(mFeatureStateLock); + // This function checks whether individual features that are affecting the refresh rate + // selection were initialized, prioritizes them, and calculates the HwcConfigIndexType + // for the suggested refresh rate. + HwcConfigIndexType calculateRefreshRateConfigIndexType() REQUIRES(mFeatureStateLock); bool layerHistoryHasClientSpecifiedFrameRate() REQUIRES(mFeatureStateLock); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e8c7a55bc6..1a4d316c5d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -228,6 +228,7 @@ Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB; ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888; Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB; ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; +bool SurfaceFlinger::useFrameRateApi; std::string getHwcServiceName() { char value[PROPERTY_VALUE_MAX] = {}; @@ -387,6 +388,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI // for production purposes later on. setenv("TREBLE_TESTING_OVERRIDE", "true", true); } + + useFrameRateApi = use_frame_rate_api(true); } void SurfaceFlinger::onFirstRef() diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index ccf57946ab..8cabcf0ef6 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -248,6 +248,11 @@ public: static ui::Dataspace wideColorGamutCompositionDataspace; static ui::PixelFormat wideColorGamutCompositionPixelFormat; + // Whether to use frame rate API when deciding about the refresh rate of the display. This + // variable is caches in SF, so that we can check it with each layer creation, and a void the + // overhead that is caused by reading from sysprop. + static bool useFrameRateApi; + static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; } diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 269cf94b4d..1a611f5d7e 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -297,6 +297,14 @@ bool support_kernel_idle_timer(bool defaultValue) { return defaultValue; } +bool use_frame_rate_api(bool defaultValue) { + auto temp = SurfaceFlingerProperties::use_frame_rate_api(); + if (temp.has_value()) { + return *temp; + } + return defaultValue; +} + #define DISPLAY_PRIMARY_SIZE 3 constexpr float kSrgbRedX = 0.4123f; diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index 440df49d94..4c6e191e70 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -87,6 +87,8 @@ bool enable_protected_contents(bool defaultValue); bool support_kernel_idle_timer(bool defaultValue); +bool use_frame_rate_api(bool defaultValue); + android::ui::DisplayPrimaries getDisplayNativePrimaries(); } // namespace sysprop } // namespace android diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index 71f8d6a7d9..b19eae62e5 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -393,3 +393,13 @@ prop { access: Readonly prop_name: "ro.surface_flinger.supports_background_blur" } + +# Indicates whether Scheduler should use frame rate API when adjusting the +# display refresh rate. +prop { + api_name: "use_frame_rate_api" + type: Boolean + scope: Public + access: Readonly + prop_name: "ro.surface_flinger.use_frame_rate_api" +} diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt index cdfd0f53aa..c66523a517 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -120,6 +120,10 @@ props { api_name: "use_context_priority" prop_name: "ro.surface_flinger.use_context_priority" } + prop { + api_name: "use_frame_rate_api" + prop_name: "ro.surface_flinger.use_frame_rate_api" + } prop { api_name: "use_smart_90_for_video" prop_name: "ro.surface_flinger.use_smart_90_for_video" -- GitLab From 5dee2f130ef20dd21e413bc97556e2284610cd7a Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 5 Feb 2020 17:49:47 -0800 Subject: [PATCH 0778/1255] SurfaceFlinger: use vsyncPeriod from HWC Composer 2.4 onVsync callback provides a vsyncPeriod. Use that period in VsyncReactor to know when a vsync transition is done. Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Bug: 140201379 Change-Id: Ia255e3b1d722fd1a3e571ec2aeceb1e8569d44d4 --- .../DisplayHardware/HWComposer.cpp | 1 - .../surfaceflinger/Scheduler/DispSync.cpp | 3 +- services/surfaceflinger/Scheduler/DispSync.h | 6 +- .../surfaceflinger/Scheduler/Scheduler.cpp | 6 +- services/surfaceflinger/Scheduler/Scheduler.h | 3 +- .../surfaceflinger/Scheduler/VSyncReactor.cpp | 19 ++++-- .../surfaceflinger/Scheduler/VSyncReactor.h | 6 +- services/surfaceflinger/SurfaceFlinger.cpp | 6 +- .../tests/unittests/VSyncReactorTest.cpp | 66 ++++++++++++------- .../tests/unittests/mock/MockDispSync.h | 2 +- 10 files changed, 75 insertions(+), 43 deletions(-) diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 153cfe7f9d..6d80173180 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -109,7 +109,6 @@ public: android::Hwc2::Display display, int64_t timestamp, android::Hwc2::VsyncPeriodNanos vsyncPeriodNanos) override { if (mVsyncSwitchingSupported) { - // TODO(b/140201379): use vsyncPeriodNanos in the new DispSync mCallback->onVsyncReceived(mSequenceId, display, timestamp, std::make_optional(vsyncPeriodNanos)); } else { diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index ca41608c1c..809a0e52fa 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -542,7 +542,8 @@ void DispSync::beginResync() { resetLocked(); } -bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodFlushed) { +bool DispSync::addResyncSample(nsecs_t timestamp, std::optional /*hwcVsyncPeriod*/, + bool* periodFlushed) { Mutex::Autolock lock(mMutex); ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp)); diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h index c6aadbb928..2d9afc9544 100644 --- a/services/surfaceflinger/Scheduler/DispSync.h +++ b/services/surfaceflinger/Scheduler/DispSync.h @@ -49,7 +49,8 @@ public: virtual void reset() = 0; virtual bool addPresentFence(const std::shared_ptr&) = 0; virtual void beginResync() = 0; - virtual bool addResyncSample(nsecs_t timestamp, bool* periodFlushed) = 0; + virtual bool addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, + bool* periodFlushed) = 0; virtual void endResync() = 0; virtual void setPeriod(nsecs_t period) = 0; virtual nsecs_t getPeriod() = 0; @@ -125,7 +126,8 @@ public: // down the DispSync model, and false otherwise. // periodFlushed will be set to true if mPendingPeriod is flushed to // mIntendedPeriod, and false otherwise. - bool addResyncSample(nsecs_t timestamp, bool* periodFlushed) override; + bool addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, + bool* periodFlushed) override; void endResync() override; // The setPeriod method sets the vsync event model's period to a specific diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index bc4f805d5e..614b74ea0b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -340,13 +340,15 @@ void Scheduler::setVsyncPeriod(nsecs_t period) { } } -void Scheduler::addResyncSample(nsecs_t timestamp, bool* periodFlushed) { +void Scheduler::addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, + bool* periodFlushed) { bool needsHwVsync = false; *periodFlushed = false; { // Scope for the lock std::lock_guard lock(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { - needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodFlushed); + needsHwVsync = + mPrimaryDispSync->addResyncSample(timestamp, hwcVsyncPeriod, periodFlushed); } } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 01062f85b9..0208ba240d 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -109,7 +109,8 @@ public: // Passes a vsync sample to DispSync. periodFlushed will be true if // DispSync detected that the vsync period changed, and false otherwise. - void addResyncSample(nsecs_t timestamp, bool* periodFlushed); + void addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, + bool* periodFlushed); void addPresentFence(const std::shared_ptr&); void setIgnorePresentFences(bool ignore); nsecs_t getDispSyncExpectedPresentTime(); diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index 70e4760676..da73e4e194 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -229,24 +229,33 @@ void VSyncReactor::beginResync() { void VSyncReactor::endResync() {} -bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp) { - if (!mLastHwVsync || !mPeriodConfirmationInProgress) { +bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp, std::optional HwcVsyncPeriod) { + if (!mPeriodConfirmationInProgress) { + return false; + } + + if (!mLastHwVsync && !HwcVsyncPeriod) { return false; } - auto const period = mPeriodTransitioningTo ? *mPeriodTransitioningTo : getPeriod(); + auto const period = mPeriodTransitioningTo ? *mPeriodTransitioningTo : getPeriod(); static constexpr int allowancePercent = 10; static constexpr std::ratio allowancePercentRatio; auto const allowance = period * allowancePercentRatio.num / allowancePercentRatio.den; + if (HwcVsyncPeriod) { + return std::abs(*HwcVsyncPeriod - period) < allowance; + } + auto const distance = vsync_timestamp - *mLastHwVsync; return std::abs(distance - period) < allowance; } -bool VSyncReactor::addResyncSample(nsecs_t timestamp, bool* periodFlushed) { +bool VSyncReactor::addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, + bool* periodFlushed) { assert(periodFlushed); std::lock_guard lk(mMutex); - if (periodConfirmed(timestamp)) { + if (periodConfirmed(timestamp, hwcVsyncPeriod)) { if (mPeriodTransitioningTo) { mTracker->setPeriod(*mPeriodTransitioningTo); for (auto& entry : mCallbacks) { diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index 5b79f35c23..aa8a38d871 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -49,7 +49,8 @@ public: // TODO: (b/145626181) remove begin,endResync functions from DispSync i/f when possible. void beginResync() final; - bool addResyncSample(nsecs_t timestamp, bool* periodFlushed) final; + bool addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, + bool* periodFlushed) final; void endResync() final; status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback, @@ -65,7 +66,8 @@ private: void updateIgnorePresentFencesInternal() REQUIRES(mMutex); void startPeriodTransition(nsecs_t newPeriod) REQUIRES(mMutex); void endPeriodTransition() REQUIRES(mMutex); - bool periodConfirmed(nsecs_t vsync_timestamp) REQUIRES(mMutex); + bool periodConfirmed(nsecs_t vsync_timestamp, std::optional hwcVsyncPeriod) + REQUIRES(mMutex); std::unique_ptr const mClock; std::unique_ptr const mTracker; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 33d85cb420..0fa9058f44 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1505,11 +1505,9 @@ nsecs_t SurfaceFlinger::getVsyncPeriod() const { void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId, int64_t timestamp, - std::optional /*vsyncPeriod*/) { + std::optional vsyncPeriod) { ATRACE_NAME("SF onVsync"); - // TODO(b/140201379): use vsyncPeriod in the new DispSync - Mutex::Autolock lock(mStateLock); // Ignore any vsyncs from a previous hardware composer. if (sequenceId != getBE().mComposerSequenceId) { @@ -1526,7 +1524,7 @@ void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDispl } bool periodFlushed = false; - mScheduler->addResyncSample(timestamp, &periodFlushed); + mScheduler->addResyncSample(timestamp, vsyncPeriod, &periodFlushed); if (periodFlushed) { mVSyncModulator->onRefreshRateChangeCompleted(); } diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index 1de72b9599..2f36bb2941 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -250,9 +250,9 @@ TEST_F(VSyncReactorTest, ignoresProperlyAfterAPeriodConfirmation) { nsecs_t const newPeriod = 5000; mReactor.setPeriod(newPeriod); - EXPECT_TRUE(mReactor.addResyncSample(0, &periodFlushed)); + EXPECT_TRUE(mReactor.addResyncSample(0, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_FALSE(mReactor.addResyncSample(newPeriod, &periodFlushed)); + EXPECT_FALSE(mReactor.addResyncSample(newPeriod, std::nullopt, &periodFlushed)); EXPECT_TRUE(periodFlushed); EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); @@ -302,16 +302,16 @@ TEST_F(VSyncReactorTest, setPeriodCalledOnceConfirmedChange) { mReactor.setPeriod(newPeriod); bool periodFlushed = true; - EXPECT_TRUE(mReactor.addResyncSample(10000, &periodFlushed)); + EXPECT_TRUE(mReactor.addResyncSample(10000, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_TRUE(mReactor.addResyncSample(20000, &periodFlushed)); + EXPECT_TRUE(mReactor.addResyncSample(20000, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); Mock::VerifyAndClearExpectations(mMockTracker.get()); EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1); - EXPECT_FALSE(mReactor.addResyncSample(25000, &periodFlushed)); + EXPECT_FALSE(mReactor.addResyncSample(25000, std::nullopt, &periodFlushed)); EXPECT_TRUE(periodFlushed); } @@ -320,14 +320,14 @@ TEST_F(VSyncReactorTest, changingPeriodBackAbortsConfirmationProcess) { nsecs_t const newPeriod = 5000; mReactor.setPeriod(newPeriod); bool periodFlushed = true; - EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed)); + EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed)); + EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); mReactor.setPeriod(period); - EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, &periodFlushed)); + EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); } @@ -338,14 +338,14 @@ TEST_F(VSyncReactorTest, changingToAThirdPeriodWillWaitForLastPeriod) { mReactor.setPeriod(secondPeriod); bool periodFlushed = true; - EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed)); + EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed)); + EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); mReactor.setPeriod(thirdPeriod); - EXPECT_TRUE(mReactor.addResyncSample(sampleTime += secondPeriod, &periodFlushed)); + EXPECT_TRUE(mReactor.addResyncSample(sampleTime += secondPeriod, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_FALSE(mReactor.addResyncSample(sampleTime += thirdPeriod, &periodFlushed)); + EXPECT_FALSE(mReactor.addResyncSample(sampleTime += thirdPeriod, std::nullopt, &periodFlushed)); EXPECT_TRUE(periodFlushed); } @@ -360,9 +360,9 @@ TEST_F(VSyncReactorTest, reportedBadTimestampFromPredictorWillReactivateHwVSync) nsecs_t skewyPeriod = period >> 1; bool periodFlushed = false; nsecs_t sampleTime = 0; - EXPECT_TRUE(mReactor.addResyncSample(sampleTime += skewyPeriod, &periodFlushed)); + EXPECT_TRUE(mReactor.addResyncSample(sampleTime += skewyPeriod, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, &periodFlushed)); + EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); } @@ -390,12 +390,12 @@ TEST_F(VSyncReactorTest, setPeriodCalledFirstTwoEventsNewPeriod) { mReactor.setPeriod(newPeriod); bool periodFlushed = true; - EXPECT_TRUE(mReactor.addResyncSample(5000, &periodFlushed)); + EXPECT_TRUE(mReactor.addResyncSample(5000, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); Mock::VerifyAndClearExpectations(mMockTracker.get()); EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1); - EXPECT_FALSE(mReactor.addResyncSample(10000, &periodFlushed)); + EXPECT_FALSE(mReactor.addResyncSample(10000, std::nullopt, &periodFlushed)); EXPECT_TRUE(periodFlushed); } @@ -404,7 +404,7 @@ TEST_F(VSyncReactorTest, addResyncSampleTypical) { bool periodFlushed = false; EXPECT_CALL(*mMockTracker, addVsyncTimestamp(fakeTimestamp)); - EXPECT_FALSE(mReactor.addResyncSample(fakeTimestamp, &periodFlushed)); + EXPECT_FALSE(mReactor.addResyncSample(fakeTimestamp, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); } @@ -418,17 +418,17 @@ TEST_F(VSyncReactorTest, addResyncSamplePeriodChanges) { auto constexpr numTimestampSubmissions = 10; for (auto i = 0; i < numTimestampSubmissions; i++) { time += period; - EXPECT_TRUE(mReactor.addResyncSample(time, &periodFlushed)); + EXPECT_TRUE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); } time += newPeriod; - EXPECT_FALSE(mReactor.addResyncSample(time, &periodFlushed)); + EXPECT_FALSE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed)); EXPECT_TRUE(periodFlushed); for (auto i = 0; i < numTimestampSubmissions; i++) { time += newPeriod; - EXPECT_FALSE(mReactor.addResyncSample(time, &periodFlushed)); + EXPECT_FALSE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); } } @@ -440,11 +440,11 @@ TEST_F(VSyncReactorTest, addPresentFenceWhileAwaitingPeriodConfirmationRequestsH mReactor.setPeriod(newPeriod); time += period; - mReactor.addResyncSample(time, &periodFlushed); + mReactor.addResyncSample(time, std::nullopt, &periodFlushed); EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); time += newPeriod; - mReactor.addResyncSample(time, &periodFlushed); + mReactor.addResyncSample(time, std::nullopt, &periodFlushed); EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); } @@ -568,8 +568,8 @@ TEST_F(VSyncReactorTest, changingPeriodChangesOffsetsOnNextCb) { bool periodFlushed = false; mReactor.setPeriod(anotherPeriod); - EXPECT_TRUE(mReactor.addResyncSample(anotherPeriod, &periodFlushed)); - EXPECT_FALSE(mReactor.addResyncSample(anotherPeriod * 2, &periodFlushed)); + EXPECT_TRUE(mReactor.addResyncSample(anotherPeriod, std::nullopt, &periodFlushed)); + EXPECT_FALSE(mReactor.addResyncSample(anotherPeriod * 2, std::nullopt, &periodFlushed)); mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); } @@ -614,6 +614,24 @@ TEST_F(VSyncReactorTest, beginResyncResetsModel) { mReactor.beginResync(); } +TEST_F(VSyncReactorTest, periodChangeWithGivenVsyncPeriod) { + bool periodFlushed = true; + EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(3); + mReactor.setIgnorePresentFences(true); + + nsecs_t const newPeriod = 5000; + mReactor.setPeriod(newPeriod); + + EXPECT_TRUE(mReactor.addResyncSample(0, 0, &periodFlushed)); + EXPECT_FALSE(periodFlushed); + EXPECT_TRUE(mReactor.addResyncSample(newPeriod, 0, &periodFlushed)); + EXPECT_FALSE(periodFlushed); + EXPECT_FALSE(mReactor.addResyncSample(newPeriod, newPeriod, &periodFlushed)); + EXPECT_TRUE(periodFlushed); + + EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); +} + using VSyncReactorDeathTest = VSyncReactorTest; TEST_F(VSyncReactorDeathTest, invalidRemoval) { mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h index 9ca116d735..a2ae6c9b8d 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h +++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h @@ -31,7 +31,7 @@ public: MOCK_METHOD0(reset, void()); MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr&)); MOCK_METHOD0(beginResync, void()); - MOCK_METHOD2(addResyncSample, bool(nsecs_t, bool*)); + MOCK_METHOD3(addResyncSample, bool(nsecs_t, std::optional, bool*)); MOCK_METHOD0(endResync, void()); MOCK_METHOD1(setPeriod, void(nsecs_t)); MOCK_METHOD0(getPeriod, nsecs_t()); -- GitLab From 92bf548f59dbfa95e357d16d39dd8549fdfc2739 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Mon, 10 Feb 2020 09:49:08 -0800 Subject: [PATCH 0779/1255] Add rounded corners to BLAST layers BLAST layers have no concept of crop, which is used to calculate rounded corners. Instead, use display frame to calculate rounded corners for BLAST layers Bug: 147109621 Test: build, boot, SurfaceFlinger_test Change-Id: Iea453313625f9352e5f0131bb7bfa9bd11151045 --- services/surfaceflinger/BufferStateLayer.cpp | 27 ++++++++++++++ services/surfaceflinger/BufferStateLayer.h | 1 + services/surfaceflinger/Layer.h | 2 +- ...LayerTypeAndRenderTypeTransaction_test.cpp | 36 +++++++++++++------ 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 923a81c093..371b80227b 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -742,6 +742,33 @@ sp BufferStateLayer::createClone() { layer->setInitialValuesForClone(this); return layer; } + +Layer::RoundedCornerState BufferStateLayer::getRoundedCornerState() const { + const auto& p = mDrawingParent.promote(); + if (p != nullptr) { + RoundedCornerState parentState = p->getRoundedCornerState(); + if (parentState.radius > 0) { + ui::Transform t = getActiveTransform(getDrawingState()); + t = t.inverse(); + parentState.cropRect = t.transform(parentState.cropRect); + // The rounded corners shader only accepts 1 corner radius for performance reasons, + // but a transform matrix can define horizontal and vertical scales. + // Let's take the average between both of them and pass into the shader, practically we + // never do this type of transformation on windows anyway. + parentState.radius *= (t[0][0] + t[1][1]) / 2.0f; + return parentState; + } + } + const float radius = getDrawingState().cornerRadius; + const State& s(getDrawingState()); + if (radius <= 0 || (getActiveWidth(s) == UINT32_MAX && getActiveHeight(s) == UINT32_MAX)) + return RoundedCornerState(); + return RoundedCornerState(FloatRect(static_cast(s.active.transform.tx()), + static_cast(s.active.transform.ty()), + static_cast(s.active.transform.tx() + s.active.w), + static_cast(s.active.transform.ty() + s.active.h)), + radius); +} } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 6ee58024f0..539442aa4e 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -103,6 +103,7 @@ public: Rect getBufferSize(const State& s) const override; FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; + Layer::RoundedCornerState getRoundedCornerState() const override; // ----------------------------------------------------------------------- diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index de4a08070c..c110462d61 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -710,7 +710,7 @@ public: // corner definition and converting it into current layer's coordinates. // As of now, only 1 corner radius per display list is supported. Subsequent ones will be // ignored. - RoundedCornerState getRoundedCornerState() const; + virtual RoundedCornerState getRoundedCornerState() const; renderengine::ShadowSettings getShadowSettings(const Rect& viewport) const; diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index 3bbd12a242..3ec462789b 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -199,10 +199,17 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) { ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size)); - Transaction() - .setCornerRadius(layer, cornerRadius) - .setCrop_legacy(layer, Rect(0, 0, size, size)) - .apply(); + if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { + Transaction() + .setCornerRadius(layer, cornerRadius) + .setCrop_legacy(layer, Rect(0, 0, size, size)) + .apply(); + } else { + Transaction() + .setCornerRadius(layer, cornerRadius) + .setFrame(layer, Rect(0, 0, size, size)) + .apply(); + } { const uint8_t bottom = size - 1; const uint8_t right = size - 1; @@ -226,12 +233,21 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) { ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2)); - Transaction() - .setCornerRadius(parent, cornerRadius) - .setCrop_legacy(parent, Rect(0, 0, size, size)) - .reparent(child, parent->getHandle()) - .setPosition(child, 0, size / 2) - .apply(); + if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) { + Transaction() + .setCornerRadius(parent, cornerRadius) + .setCrop_legacy(parent, Rect(0, 0, size, size)) + .reparent(child, parent->getHandle()) + .setPosition(child, 0, size / 2) + .apply(); + } else { + Transaction() + .setCornerRadius(parent, cornerRadius) + .setFrame(parent, Rect(0, 0, size, size)) + .reparent(child, parent->getHandle()) + .setFrame(child, Rect(0, size / 2, size, size)) + .apply(); + } { const uint8_t bottom = size - 1; const uint8_t right = size - 1; -- GitLab From 019a7ee1420485973408e42b0299e20b045b6966 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Mon, 10 Feb 2020 11:43:19 -0800 Subject: [PATCH 0780/1255] gralloc4: support crop as a seperate metadata type Move crop out of PlaneLayout so it can be set and get independently from PlaneLayout. Bug: 141632767 Test: Gralloc4_test and libgralloctypes_fuzzer Change-Id: Icdf81a7183b8bd8c782ddb38164f373f437b7466 --- libs/gralloc/types/Gralloc4.cpp | 65 +++++++++++++++---- libs/gralloc/types/fuzzer/gralloctypes.cpp | 1 + .../types/include/gralloctypes/Gralloc4.h | 28 +++++++- libs/gralloc/types/tests/Gralloc4_test.cpp | 36 +++++++--- 4 files changed, 106 insertions(+), 24 deletions(-) diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp index 4e8569f2de..603e7e559f 100644 --- a/libs/gralloc/types/Gralloc4.cpp +++ b/libs/gralloc/types/Gralloc4.cpp @@ -734,12 +734,7 @@ status_t encodePlaneLayout(const PlaneLayout& input, OutputHidlVec* output) { if (err) { return err; } - err = encodeInteger(static_cast(input.verticalSubsampling), output); - if (err) { - return err; - } - - return encodeRect(input.crop, output); + return encodeInteger(static_cast(input.verticalSubsampling), output); } status_t decodePlaneLayout(InputHidlVec* input, PlaneLayout* output) { @@ -780,12 +775,7 @@ status_t decodePlaneLayout(InputHidlVec* input, PlaneLayout* output) { if (err) { return err; } - err = decodeInteger(input, &output->verticalSubsampling); - if (err) { - return err; - } - - return decodeRect(input, &output->crop); + return decodeInteger(input, &output->verticalSubsampling); } status_t encodePlaneLayoutsHelper(const std::vector& planeLayouts, OutputHidlVec* outOutputHidlVec) { @@ -831,6 +821,49 @@ void clearPlaneLayouts(std::vector* output) { output->clear(); } +status_t encodeCropHelper(const std::vector& crops, OutputHidlVec* outOutputHidlVec) { + status_t err = encodeInteger(static_cast(crops.size()), outOutputHidlVec); + if (err) { + return err; + } + + for (const auto& crop : crops) { + err = encodeRect(crop, outOutputHidlVec); + if (err) { + return err; + } + } + + return NO_ERROR; +} + +status_t decodeCropHelper(InputHidlVec* inputHidlVec, std::vector* outCrops) { + int64_t size = 0; + status_t err = decodeInteger(inputHidlVec, &size); + if (err) { + return err; + } + if (size < 0) { + return BAD_VALUE; + } + + for (size_t i = 0; i < size; i++) { + outCrops->emplace_back(); + err = decodeRect(inputHidlVec, &outCrops->back()); + if (err) { + return err; + } + } + return NO_ERROR; +} + +void clearCrop(std::vector* output) { + if (!output) { + return; + } + output->clear(); +} + status_t encodeSmpte2086Helper(const Smpte2086& smpte2086, OutputHidlVec* outOutputHidlVec) { status_t err = encodeXyColor(smpte2086.primaryRed, outOutputHidlVec); if (err) { @@ -1043,6 +1076,14 @@ status_t decodePlaneLayouts(const hidl_vec& planeLayouts, std::vector

& crop, hidl_vec* outCrop) { + return encodeMetadata(MetadataType_Crop, crop, outCrop, encodeCropHelper); +} + +status_t decodeCrop(const hidl_vec& crop, std::vector* outCrop) { + return decodeMetadata(MetadataType_Crop, crop, outCrop, decodeCropHelper, clearCrop); +} + status_t encodeDataspace(const Dataspace& dataspace, hidl_vec* outDataspace) { return encodeMetadata(MetadataType_Dataspace, static_cast(dataspace), outDataspace, encodeInteger); diff --git a/libs/gralloc/types/fuzzer/gralloctypes.cpp b/libs/gralloc/types/fuzzer/gralloctypes.cpp index b5644beafb..dc22385883 100644 --- a/libs/gralloc/types/fuzzer/gralloctypes.cpp +++ b/libs/gralloc/types/fuzzer/gralloctypes.cpp @@ -70,6 +70,7 @@ std::vector GRALLOCTYPES_DECODE_FUNCTIONS { GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::ExtendableType, ::android::gralloc4::decodeInterlaced), GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::ExtendableType, ::android::gralloc4::decodeChromaSiting), GRALLOCTYPES_DECODE(std::vector, ::android::gralloc4::decodePlaneLayouts), + GRALLOCTYPES_DECODE(std::vector, ::android::gralloc4::decodeCrop), GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::Dataspace, ::android::gralloc4::decodeDataspace), GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::BlendMode, ::android::gralloc4::decodeBlendMode), GRALLOCTYPES_DECODE(std::optional, ::android::gralloc4::decodeSmpte2086), diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h index d8554398c3..5ec4d0df3c 100644 --- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h +++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h @@ -89,6 +89,24 @@ inline bool operator!=(const aidl::android::hardware::graphics::common::Rect& lh return !(lhs == rhs); } +inline bool operator==(const std::vector& lhs, + const std::vector& rhs) { + if (lhs.size() != rhs.size()) { + return false; + } + for (size_t i = 0; i < lhs.size(); i++) { + if (lhs[i] != rhs[i]) { + return false; + } + } + return true; +} + +inline bool operator!=(const std::vector& lhs, + const std::vector& rhs) { + return !(lhs == rhs); +} + inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayout& lhs, const aidl::android::hardware::graphics::common::PlaneLayout& rhs) { if (lhs.offsetInBytes != rhs.offsetInBytes) { @@ -115,9 +133,6 @@ inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLay if (lhs.verticalSubsampling != rhs.verticalSubsampling) { return false; } - if (lhs.crop != rhs.crop) { - return false; - } if (lhs.components.size() != rhs.components.size()) { return false; } @@ -286,6 +301,10 @@ static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType Me GRALLOC4_STANDARD_METADATA_TYPE, static_cast(aidl::android::hardware::graphics::common::StandardMetadataType::PLANE_LAYOUTS) }; +static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType MetadataType_Crop = { + GRALLOC4_STANDARD_METADATA_TYPE, static_cast(aidl::android::hardware::graphics::common::StandardMetadataType::CROP) +}; + static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType MetadataType_Dataspace = { GRALLOC4_STANDARD_METADATA_TYPE, static_cast(aidl::android::hardware::graphics::common::StandardMetadataType::DATASPACE) }; @@ -469,6 +488,9 @@ status_t decodeChromaSiting(const android::hardware::hidl_vec& chromaSi status_t encodePlaneLayouts(const std::vector& planeLayouts, android::hardware::hidl_vec* outPlaneLayouts); status_t decodePlaneLayouts(const android::hardware::hidl_vec& planeLayouts, std::vector* outPlaneLayouts); +status_t encodeCrop(const std::vector& crop, android::hardware::hidl_vec* outCrop); +status_t decodeCrop(const android::hardware::hidl_vec& crop, std::vector* outCrop); + status_t encodeDataspace(const aidl::android::hardware::graphics::common::Dataspace& dataspace, android::hardware::hidl_vec* outDataspace); status_t decodeDataspace(const android::hardware::hidl_vec& dataspace, aidl::android::hardware::graphics::common::Dataspace* outDataspace); diff --git a/libs/gralloc/types/tests/Gralloc4_test.cpp b/libs/gralloc/types/tests/Gralloc4_test.cpp index dbe41f16cc..89cbf4ac4a 100644 --- a/libs/gralloc/types/tests/Gralloc4_test.cpp +++ b/libs/gralloc/types/tests/Gralloc4_test.cpp @@ -321,10 +321,6 @@ TEST_F(Gralloc4TestPlaneLayouts, PlaneLayouts) { planeLayoutA.totalSizeInBytes = planeLayoutA.strideInBytes * height; planeLayoutA.horizontalSubsampling = 1; planeLayoutA.verticalSubsampling = 1; - planeLayoutA.crop.left = 0; - planeLayoutA.crop.top = 0; - planeLayoutA.crop.right = width; - planeLayoutA.crop.bottom = height; component.type = gralloc4::PlaneLayoutComponentType_A; component.offsetInBits = 0; @@ -341,11 +337,6 @@ TEST_F(Gralloc4TestPlaneLayouts, PlaneLayouts) { planeLayoutRGB.totalSizeInBytes = planeLayoutRGB.strideInBytes * height; planeLayoutRGB.horizontalSubsampling = 1; planeLayoutRGB.verticalSubsampling = 1; - planeLayoutRGB.crop.left = 0; - planeLayoutRGB.crop.top = 0; - planeLayoutRGB.crop.right = width; - planeLayoutRGB.crop.bottom = height; - component.type = gralloc4::PlaneLayoutComponentType_R; planeLayoutRGB.components.push_back(component); component.type = gralloc4::PlaneLayoutComponentType_G; @@ -358,6 +349,33 @@ TEST_F(Gralloc4TestPlaneLayouts, PlaneLayouts) { ASSERT_NO_FATAL_FAILURE(testHelperStableAidlType(planeLayouts, gralloc4::encodePlaneLayouts, gralloc4::decodePlaneLayouts)); } +class Gralloc4TestCrop : public testing::Test { }; + +TEST_F(Gralloc4TestCrop, Crop) { + std::vector crops; + Rect crop1, crop2, crop3; + + crop1.left = 0; + crop1.top = 0; + crop1.right = 64; + crop1.bottom = 64; + crops.push_back(crop1); + + crop2.left = std::numeric_limits::min(); + crop2.top = 0xFF; + crop2.right = std::numeric_limits::max(); + crop2.bottom = 0xFFFF; + crops.push_back(crop2); + + crop3.left = 0; + crop3.top = 0; + crop3.right = -1; + crop3.bottom = -1; + crops.push_back(crop3); + + ASSERT_NO_FATAL_FAILURE(testHelperStableAidlType(crops, gralloc4::encodeCrop, gralloc4::decodeCrop)); +} + class Gralloc4TestDataspace : public testing::TestWithParam { }; INSTANTIATE_TEST_CASE_P( -- GitLab From 7bfc75b74c2e1b7da0d195843013089b7f3d9fce Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 10 Feb 2020 11:20:34 -0800 Subject: [PATCH 0781/1255] SFStats: track lateAcquired and badDesiredPresent frames from the field Bug: 135478131 Test: statsd_testdrive 10063 Test: atest libsurfaceflinger_unittest:TimeStatsTest Change-Id: Ic1ffdc2aaf90ca0266b21d74491be60563943a98 --- services/surfaceflinger/TimeStats/TimeStats.cpp | 3 +++ .../tests/unittests/TimeStatsTest.cpp | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 493a7093a0..b2cce7c932 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -148,6 +148,9 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventLis } } + mStatsDelegate->statsEventWriteInt64(event, layer->lateAcquireFrames); + mStatsDelegate->statsEventWriteInt64(event, layer->badDesiredPresentFrames); + mStatsDelegate->statsEventBuild(event); } clearLayersLocked(); diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index 91a40d012c..fb2e3bddc4 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -892,12 +892,20 @@ MATCHER_P2(BytesEq, bytes, size, "") { return expected == actual; } -TEST_F(TimeStatsTest, layerStatsCallback_pullsAllHistogramsAndClears) { +TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { + constexpr size_t LATE_ACQUIRE_FRAMES = 2; + constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3; EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); mTimeStats->onBootFinished(); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); + for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) { + mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire); + } + for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) { + mTimeStats->incrementBadDesiredPresent(LAYER_ID_0); + } insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000); EXPECT_THAT(mDelegate->mAtomTags, @@ -955,6 +963,9 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllHistogramsAndClears) { BytesEq((const uint8_t*)expectedPostToAcquire.c_str(), expectedPostToAcquire.size()), expectedPostToAcquire.size())); + EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, LATE_ACQUIRE_FRAMES)); + EXPECT_CALL(*mDelegate, + statsEventWriteInt64(mDelegate->mEvent, BAD_DESIRED_PRESENT_FRAMES)); EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent)); } EXPECT_EQ(AStatsManager_PULL_SUCCESS, -- GitLab From 786eda95575878f8bf6d79772cbc69211e45facb Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 10 Feb 2020 12:27:07 -0800 Subject: [PATCH 0782/1255] rm libbinderthreadstate Empty, since the functionality was moved to libbinder/libhwbinder to remove extra lib dependency. Bug: 148692216 Test: N/A Change-Id: Ic314bbe5e05b009960038f4ef970306ba970f81a --- libs/binder/fuzzer/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/binder/fuzzer/Android.bp b/libs/binder/fuzzer/Android.bp index 521d36fced..d2b4d52acc 100644 --- a/libs/binder/fuzzer/Android.bp +++ b/libs/binder/fuzzer/Android.bp @@ -16,7 +16,6 @@ cc_fuzz { ], static_libs: [ "libbase", - "libbinderthreadstate", "libcgrouprc", "libcgrouprc_format", "libcutils", -- GitLab From 1d9a05718312123255bfb3fe9b11a09e996aa298 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Mon, 10 Feb 2020 14:00:30 -0800 Subject: [PATCH 0783/1255] Add Rounded Corner BLAST test back to presubmit Bug: 147109621 Test: build Change-Id: I3e3cf20dc64d4ab4f4c00709d77bd8d27eab90f3 --- services/surfaceflinger/tests/SurfaceFlinger_test.filter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter index 2bedd7d602..cf7d570165 100644 --- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter +++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter @@ -1,5 +1,5 @@ { "presubmit": { - "filter": "*:-LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/3:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/3" + "filter": "" } } -- GitLab From fa3f3d3b091d4170422cb07ef75700102c47a802 Mon Sep 17 00:00:00 2001 From: shubang Date: Mon, 10 Feb 2020 14:40:38 -0800 Subject: [PATCH 0784/1255] Add android.hardware.tv.tuner feature see https://developer.android.com/guide/topics/manifest/uses-feature-element Test: make; Change-Id: Ib2bc4c0fdd98cb3aaad3be2e3ba53ae7cc933a3a --- data/etc/android.hardware.tv.tuner.xml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 data/etc/android.hardware.tv.tuner.xml diff --git a/data/etc/android.hardware.tv.tuner.xml b/data/etc/android.hardware.tv.tuner.xml new file mode 100644 index 0000000000..bbf084fabf --- /dev/null +++ b/data/etc/android.hardware.tv.tuner.xml @@ -0,0 +1,21 @@ + + + + + + + -- GitLab From 17f3d25884ed43f57c49c8066d771213a4527f87 Mon Sep 17 00:00:00 2001 From: Raymond Chiu Date: Mon, 10 Feb 2020 18:02:27 -0800 Subject: [PATCH 0785/1255] Run setenforce 1 on test teardown Cleanup after test to avoid changing test environment Fixes: 148917835 Test: SurfaceFlingerTest sffakehwc_test Change-Id: I5a61401d523302d77c6974befe8ff9844f853c8e --- services/surfaceflinger/tests/SurfaceInterceptor_test.cpp | 1 + services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 0e7eba8d76..8d97f275ba 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -145,6 +145,7 @@ protected: mBGSurfaceControl.clear(); mFGSurfaceControl.clear(); mComposerClient.clear(); + system("setenforce 1"); } sp mComposerClient; diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp index 2f89696e8e..96a7541919 100644 --- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp @@ -183,6 +183,7 @@ void FakeHwcEnvironment::TearDown() { // Wait for mock call signaling teardown? property_set("debug.sf.nobootanimation", "0"); property_set("debug.sf.hwc_service_name", "default"); + system("setenforce 1"); ALOGI("Test env tear down - done"); } -- GitLab From 63daa668128d04797edfed504322f8915457ac60 Mon Sep 17 00:00:00 2001 From: Pierre Fite-Georgel Date: Tue, 17 Dec 2019 16:52:29 -0800 Subject: [PATCH 0786/1255] Changing logic that generates virtual SENSOR_TYPE_LINEAR_ACCELERATION. New logic only requires accel/gyro to be available rather than accel/gyro/mag which is not necessary. Bug: 145707966 Fix: 145707966 Test: Flashed a Hawk device (AAE development platform) that does not have Linear Acceleration Sensor currently. After flashing : Linear Acceleration Sensor | AOSP | ver: 3 | type: android.sensor.linear_acceleration(10) | perm: n/a | flags: 0x00000000 continuous | maxDelay=0us | maxRate=500.00Hz | no batching | non-wakeUp | Change-Id: Idfe7c1ab357e363cb2c8daf6e4175adbbcf9d8c4 --- services/sensorservice/SensorService.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 914a4cb54d..22a15c6df8 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -210,12 +210,6 @@ void SensorService::onFirstRef() { registerSensor(new RotationVectorSensor(), !needRotationVector, true); registerSensor(new OrientationSensor(), !needRotationVector, true); - bool needLinearAcceleration = - (virtualSensorsNeeds & (1< Date: Mon, 10 Feb 2020 14:12:05 -0800 Subject: [PATCH 0787/1255] SurfaceFlinger: handle properly layers with Max refresh rate Fix a bug where layers that voted LayerVoteType::Max are ignored if there are other layers with a numerical vote. Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Bug: 147516364 Change-Id: I177ebbd9fa31544997216d951fe697f06670e0a4 --- .../Scheduler/RefreshRateConfigs.cpp | 19 ++++++++-- .../Scheduler/RefreshRateConfigs.h | 6 +++ .../unittests/RefreshRateConfigsTest.cpp | 38 +++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 8202515bec..d1de737a89 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -194,9 +194,22 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( } } - float max = 0; + // Now that we scored all the refresh rates we need to pick the one that got the highest score. + // In case of a tie we will pick the higher refresh rate if any of the layers wanted Max, + // or the lower otherwise. + const RefreshRate* bestRefreshRate = maxVoteLayers > 0 + ? getBestRefreshRate(scores.rbegin(), scores.rend()) + : getBestRefreshRate(scores.begin(), scores.end()); + + return bestRefreshRate == nullptr ? *mCurrentRefreshRate : *bestRefreshRate; +} + +template +const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const { const RefreshRate* bestRefreshRate = nullptr; - for (const auto [refreshRate, score] : scores) { + float max = 0; + for (auto i = begin; i != end; ++i) { + const auto [refreshRate, score] = *i; ALOGV("%s scores %.2f", refreshRate->name.c_str(), score); ATRACE_INT(refreshRate->name.c_str(), round(score * 100)); @@ -207,7 +220,7 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( } } - return bestRefreshRate == nullptr ? *mCurrentRefreshRate : *bestRefreshRate; + return bestRefreshRate; } const AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const { diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index e5bb55710d..1132a8c58c 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -182,6 +182,12 @@ private: const std::function& shouldAddRefreshRate, std::vector* outRefreshRates); + // Returns the refresh rate with the highest score in the collection specified from begin + // to end. If there are more than one with the same highest refresh rate, the first one is + // returned. + template + const RefreshRate* getBestRefreshRate(Iter begin, Iter end) const; + // The list of refresh rates, indexed by display config ID. This must not change after this // object is initialized. AllRefreshRatesMapType mRefreshRates; diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 841c624a3f..99c5f3d4cd 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -745,6 +745,44 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_75HzC } } +TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Multiples) { + std::vector configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); + + RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; + RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90}; + + auto layers = std::vector{LayerRequirement{.weight = 1.0f}, + LayerRequirement{.weight = 1.0f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60.0f; + lr2.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 90.0f; + EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60.0f; + lr2.vote = LayerVoteType::Max; + EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 30.0f; + lr2.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 90.0f; + EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 30.0f; + lr2.vote = LayerVoteType::Max; + EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); +} + } // namespace } // namespace scheduler } // namespace android -- GitLab From 717bcb6ec858b16132aa8854120f05536f5a9f91 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 10 Feb 2020 17:07:19 -0800 Subject: [PATCH 0788/1255] [SfStats] Record vsync event connection count Bug: 135480141 Test: ./statsd_testdrive 10062 Change-Id: I220f0c96935c96afea194ed8ca69922785cf296e --- .../surfaceflinger/Scheduler/EventThread.cpp | 5 ++++ .../surfaceflinger/Scheduler/EventThread.h | 17 ++++++----- .../surfaceflinger/Scheduler/Scheduler.cpp | 5 ++++ services/surfaceflinger/Scheduler/Scheduler.h | 2 ++ services/surfaceflinger/SurfaceFlinger.cpp | 4 +++ .../surfaceflinger/SurfaceFlingerFactory.h | 6 ++-- .../surfaceflinger/TimeStats/TimeStats.cpp | 12 ++++++++ services/surfaceflinger/TimeStats/TimeStats.h | 8 +++++ .../include/timestatsproto/TimeStatsHelper.h | 1 + .../tests/unittests/EventThreadTest.cpp | 30 +++++++++++++++++-- .../tests/unittests/SchedulerTest.cpp | 5 ++++ .../tests/unittests/TimeStatsTest.cpp | 5 ++++ .../tests/unittests/mock/MockEventThread.h | 1 + .../tests/unittests/mock/MockTimeStats.h | 1 + 14 files changed, 90 insertions(+), 12 deletions(-) diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 14e3ec6ead..acab5a6249 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -335,6 +335,11 @@ void EventThread::onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexTyp mCondition.notify_all(); } +size_t EventThread::getEventThreadConnectionCount() { + std::lock_guard lock(mMutex); + return mDisplayEventConnections.size(); +} + void EventThread::threadMain(std::unique_lock& lock) { DisplayEventConsumers consumers; diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 641b2a5782..466234d3d7 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -16,7 +16,12 @@ #pragma once +#include +#include +#include +#include #include +#include #include #include @@ -26,13 +31,6 @@ #include #include -#include - -#include -#include -#include - -#include #include "HwcStrongTypes.h" // --------------------------------------------------------------------------- @@ -134,6 +132,9 @@ public: // Usage of this method assumes that only the primary internal display // supports multiple display configurations. virtual void requestLatestConfig() = 0; + + // Retrieves the number of event connections tracked by this EventThread. + virtual size_t getEventThreadConnectionCount() = 0; }; namespace impl { @@ -168,6 +169,8 @@ public: void setPhaseOffset(nsecs_t phaseOffset) override; + size_t getEventThreadConnectionCount() override; + private: friend EventThreadTest; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index dd5d2ac7bf..68a34c6f90 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -233,6 +233,11 @@ void Scheduler::onConfigChanged(ConnectionHandle handle, PhysicalDisplayId displ mConnections[handle].thread->onConfigChanged(displayId, configId, vsyncPeriod); } +size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) { + RETURN_IF_INVALID_HANDLE(handle, 0); + return mConnections[handle].thread->getEventThreadConnectionCount(); +} + void Scheduler::dump(ConnectionHandle handle, std::string& result) const { RETURN_IF_INVALID_HANDLE(handle); mConnections.at(handle).thread->dump(result); diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 01062f85b9..ccf61ed4ef 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -144,6 +144,8 @@ public: // Notifies the scheduler when the display size has changed. Called from SF's main thread void onPrimaryDisplayAreaChanged(uint32_t displayArea); + size_t getEventThreadConnectionCount(ConnectionHandle handle); + private: friend class TestableScheduler; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e8c7a55bc6..cca2a709e7 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2118,6 +2118,10 @@ void SurfaceFlinger::postComposition() mTimeStats->setPresentFenceGlobal(presentFenceTime); + const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle); + const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle); + mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections); + if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) && !displayDevice->isPoweredOn()) { return; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index 951bd09293..c7da730c64 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -16,14 +16,14 @@ #pragma once +#include +#include + #include #include #include #include -#include -#include - namespace android { typedef int32_t PixelFormat; diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 493a7093a0..8fbce56c37 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -70,6 +70,7 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventLi mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames); mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime); mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime()); + mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount); mStatsDelegate->statsEventBuild(event); clearGlobalLocked(); @@ -269,6 +270,16 @@ void TimeStats::incrementClientCompositionReusedFrames() { mTimeStats.clientCompositionReusedFrames++; } +void TimeStats::recordDisplayEventConnectionCount(int32_t count) { + if (!mEnabled.load()) return; + + ATRACE_CALL(); + + std::lock_guard lock(mMutex); + mTimeStats.displayEventConnectionsCount = + std::max(mTimeStats.displayEventConnectionsCount, count); +} + static int32_t msBetween(nsecs_t start, nsecs_t end) { int64_t delta = std::chrono::duration_cast( std::chrono::nanoseconds(end - start)) @@ -812,6 +823,7 @@ void TimeStats::clearGlobalLocked() { mTimeStats.missedFrames = 0; mTimeStats.clientCompositionFrames = 0; mTimeStats.clientCompositionReusedFrames = 0; + mTimeStats.displayEventConnectionsCount = 0; mTimeStats.displayOnTime = 0; mTimeStats.presentToPresent.hist.clear(); mTimeStats.frameDuration.hist.clear(); diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index a428ef416c..ddebeb184b 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -52,6 +52,9 @@ public: virtual void incrementMissedFrames() = 0; virtual void incrementClientCompositionFrames() = 0; virtual void incrementClientCompositionReusedFrames() = 0; + // Records the most up-to-date count of display event connections. + // The stored count will be the maximum ever recoded. + virtual void recordDisplayEventConnectionCount(int32_t count) = 0; // Records the start and end times for a frame. // The start time is the same as the beginning of a SurfaceFlinger @@ -177,6 +180,10 @@ public: return AStatsEvent_setAtomId(event, atom_id); } + virtual void statsEventWriteInt32(AStatsEvent* event, int32_t field) { + return AStatsEvent_writeInt32(event, field); + } + virtual void statsEventWriteInt64(AStatsEvent* event, int64_t field) { return AStatsEvent_writeInt64(event, field); } @@ -208,6 +215,7 @@ public: void incrementMissedFrames() override; void incrementClientCompositionFrames() override; void incrementClientCompositionReusedFrames() override; + void recordDisplayEventConnectionCount(int32_t count) override; void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override; void recordRenderEngineDuration(nsecs_t startTime, nsecs_t endTime) override; diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h index e374b73c38..5e7c449122 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h +++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h @@ -62,6 +62,7 @@ public: int32_t missedFrames = 0; int32_t clientCompositionFrames = 0; int32_t clientCompositionReusedFrames = 0; + int32_t displayEventConnectionsCount = 0; int64_t displayOnTime = 0; Histogram presentToPresent; Histogram frameDuration; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 61d4f47c21..65b3e35d32 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -19,9 +19,7 @@ #include #include - #include - #include #include "AsyncCallRecorder.h" @@ -401,6 +399,34 @@ TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) { expectVSyncSetEnabledCallReceived(false); } +TEST_F(EventThreadTest, tracksEventConnections) { + EXPECT_EQ(1, mThread->getEventThreadConnectionCount()); + ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY}; + sp errorConnection = + createConnection(errorConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); + mThread->setVsyncRate(1, errorConnection); + EXPECT_EQ(2, mThread->getEventThreadConnectionCount()); + ConnectionEventRecorder secondConnectionEventRecorder{0}; + sp secondConnection = + createConnection(secondConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); + mThread->setVsyncRate(1, secondConnection); + EXPECT_EQ(3, mThread->getEventThreadConnectionCount()); + + // EventThread should enable vsync callbacks. + expectVSyncSetEnabledCallReceived(true); + + // The first event will be seen by the interceptor, and by the connection, + // which then returns an error. + mCallback->onVSyncEvent(123); + expectInterceptCallReceived(123); + expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u); + expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123, + 1u); + EXPECT_EQ(2, mThread->getEventThreadConnectionCount()); +} + TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) { ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK}; sp errorConnection = diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 89002a8f3e..5db11ec5c1 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -159,6 +159,11 @@ TEST_F(SchedulerTest, validConnectionHandle) { EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1); ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10)); + + static constexpr size_t kEventConnections = 5; + ON_CALL(*mEventThread, getEventThreadConnectionCount()) + .WillByDefault(Return(kEventConnections)); + EXPECT_EQ(kEventConnections, mScheduler->getEventThreadConnectionCount(mConnectionHandle)); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index 91a40d012c..b1d5b165d7 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -166,6 +166,7 @@ public: MOCK_METHOD1(unregisterStatsPullAtomCallback, void(int32_t)); MOCK_METHOD2(statsEventSetAtomId, void(AStatsEvent*, uint32_t)); + MOCK_METHOD2(statsEventWriteInt32, void(AStatsEvent*, int32_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)); @@ -800,6 +801,7 @@ TEST_F(TimeStatsTest, globalStatsCallback) { constexpr size_t TOTAL_FRAMES = 5; constexpr size_t MISSED_FRAMES = 4; constexpr size_t CLIENT_COMPOSITION_FRAMES = 3; + constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14; mTimeStats->onBootFinished(); EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); @@ -814,6 +816,8 @@ TEST_F(TimeStatsTest, globalStatsCallback) { mTimeStats->incrementClientCompositionFrames(); } + mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS); + mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL); mTimeStats->setPresentFenceGlobal(std::make_shared(3000000)); mTimeStats->setPresentFenceGlobal(std::make_shared(5000000)); @@ -834,6 +838,7 @@ TEST_F(TimeStatsTest, globalStatsCallback) { EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES)); EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _)); EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2)); + EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, DISPLAY_EVENT_CONNECTIONS)); EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent)); } EXPECT_EQ(AStatsManager_PULL_SUCCESS, diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 9bda095a48..50eb390471 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -42,6 +42,7 @@ public: MOCK_METHOD1(requestNextVsync, void(const sp &)); MOCK_METHOD0(requestLatestConfig, void()); MOCK_METHOD1(pauseVsyncCallback, void(bool)); + MOCK_METHOD0(getEventThreadConnectionCount, size_t()); }; } // namespace mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h index 2720537432..c45d5843e3 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h @@ -36,6 +36,7 @@ public: MOCK_METHOD0(incrementMissedFrames, void()); MOCK_METHOD0(incrementClientCompositionFrames, void()); MOCK_METHOD0(incrementClientCompositionReusedFrames, void()); + MOCK_METHOD1(recordDisplayEventConnectionCount, void(int32_t)); MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t)); MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t)); MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr&)); -- GitLab From fa247b1870da660a722551d6eb944dab1c8f0b53 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 11 Feb 2020 08:58:26 -0800 Subject: [PATCH 0789/1255] Rename ColorLayer to EffectLayer to handle both shadows and color fill We want the ability for a layer to render shadows without any content. This new layer type will be able to combine effects as needed. Test: presubmit tests (no functional changes) Test: go/wm-smoke Change-Id: I8663d126a23263a3d7dc799d39a9cf44b3b6e4a0 --- libs/gui/include/gui/ISurfaceComposerClient.h | 2 +- libs/gui/tests/BLASTBufferQueue_test.cpp | 2 +- libs/gui/tests/EndToEndNativeInputTest.cpp | 3 +- libs/gui/tests/RegionSampling_test.cpp | 2 +- libs/gui/tests/SamplingDemo.cpp | 6 ++-- services/surfaceflinger/Android.bp | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 2 +- .../{ColorLayer.cpp => EffectLayer.cpp} | 32 ++++++++--------- .../{ColorLayer.h => EffectLayer.h} | 12 ++++--- services/surfaceflinger/Layer.cpp | 8 ++--- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 16 ++++----- services/surfaceflinger/SurfaceFlinger.h | 6 ++-- .../SurfaceFlingerDefaultFactory.cpp | 6 ++-- .../SurfaceFlingerDefaultFactory.h | 2 +- .../surfaceflinger/SurfaceFlingerFactory.h | 4 +-- .../tests/LayerRenderTypeTransaction_test.cpp | 20 +++++------ .../tests/LayerTransactionTest.h | 4 +-- .../tests/LayerTypeTransaction_test.cpp | 10 +++--- .../surfaceflinger/tests/LayerUpdate_test.cpp | 12 +++---- .../tests/MultiDisplayLayerBounds_test.cpp | 2 +- .../tests/fakehwc/SFFakeHwc_test.cpp | 9 ++--- .../tests/unittests/CompositionTest.cpp | 34 +++++++++---------- .../unittests/RefreshRateSelectionTest.cpp | 16 ++++----- .../tests/unittests/TestableSurfaceFlinger.h | 6 ++-- 25 files changed, 112 insertions(+), 108 deletions(-) rename services/surfaceflinger/{ColorLayer.cpp => EffectLayer.cpp} (78%) rename services/surfaceflinger/{ColorLayer.h => EffectLayer.h} (79%) diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h index 2b65d2f42d..6366529a10 100644 --- a/libs/gui/include/gui/ISurfaceComposerClient.h +++ b/libs/gui/include/gui/ISurfaceComposerClient.h @@ -44,7 +44,7 @@ public: eCursorWindow = 0x00002000, eFXSurfaceBufferQueue = 0x00000000, - eFXSurfaceColor = 0x00020000, + eFXSurfaceEffect = 0x00020000, eFXSurfaceBufferState = 0x00040000, eFXSurfaceContainer = 0x00080000, eFXSurfaceMask = 0x000F0000, diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index e184c7f33b..a87ccd664e 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -403,7 +403,7 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { int32_t finalCropSideLength = bufferSideLength / 2; auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); ASSERT_NE(nullptr, bg.get()); Transaction t; t.setLayerStack(bg, 0) diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 1a623e21dc..c59afba87c 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -82,7 +82,8 @@ public: int width, int height) { sp surfaceControl = scc->createSurface(String8("Test Surface"), 0 /* bufHeight */, 0 /* bufWidth */, - PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor); + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect); return std::make_unique(surfaceControl, width, height); } diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index c9de37d957..dbd4ef9d7e 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -183,7 +183,7 @@ protected: mBackgroundLayer = mSurfaceComposerClient->createSurface(String8("Background RegionSamplingTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); uint32_t layerPositionBottom = 0x7E000000; SurfaceComposerClient::Transaction{} .setLayer(mBackgroundLayer, layerPositionBottom) diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp index 9891587fe2..5c1bebb960 100644 --- a/libs/gui/tests/SamplingDemo.cpp +++ b/libs/gui/tests/SamplingDemo.cpp @@ -39,7 +39,7 @@ public: sp client = new SurfaceComposerClient; mButton = client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); const int32_t width = samplingArea.getWidth(); const int32_t height = samplingArea.getHeight(); @@ -55,7 +55,7 @@ public: .apply(); mButtonBlend = client->createSurface(String8(name) + "Blend", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); SurfaceComposerClient::Transaction{} .setLayer(mButtonBlend, 0x7ffffffe) @@ -73,7 +73,7 @@ public: if (HIGHLIGHT_SAMPLING_AREA) { mSamplingArea = client->createSurface(String8("SamplingArea"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); SurfaceComposerClient::Transaction{} .setLayer(mSamplingArea, 0x7ffffffd) diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 1b1e8890ab..4ffdf9761e 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -136,7 +136,7 @@ filegroup { "BufferStateLayer.cpp", "ClientCache.cpp", "Client.cpp", - "ColorLayer.cpp", + "EffectLayer.cpp", "ContainerLayer.cpp", "DisplayDevice.cpp", "DisplayHardware/ComposerHal.cpp", diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 923a81c093..6e0d13a732 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -32,7 +32,7 @@ #include #include -#include "ColorLayer.h" +#include "EffectLayer.h" #include "FrameTracer/FrameTracer.h" #include "TimeStats/TimeStats.h" diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/EffectLayer.cpp similarity index 78% rename from services/surfaceflinger/ColorLayer.cpp rename to services/surfaceflinger/EffectLayer.cpp index 83050c4774..e928c57929 100644 --- a/services/surfaceflinger/ColorLayer.cpp +++ b/services/surfaceflinger/EffectLayer.cpp @@ -20,9 +20,9 @@ // #define LOG_NDEBUG 0 #undef LOG_TAG -#define LOG_TAG "ColorLayer" +#define LOG_TAG "EffectLayer" -#include "ColorLayer.h" +#include "EffectLayer.h" #include #include @@ -41,13 +41,13 @@ namespace android { // --------------------------------------------------------------------------- -ColorLayer::ColorLayer(const LayerCreationArgs& args) +EffectLayer::EffectLayer(const LayerCreationArgs& args) : Layer(args), mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {} -ColorLayer::~ColorLayer() = default; +EffectLayer::~EffectLayer() = default; -std::optional ColorLayer::prepareClientComposition( +std::optional EffectLayer::prepareClientComposition( compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { auto result = Layer::prepareClientComposition(targetSettings); if (!result) { @@ -57,11 +57,11 @@ std::optional ColorLayer::prepareClie return result; } -bool ColorLayer::isVisible() const { +bool EffectLayer::isVisible() const { return !isHiddenByPolicy() && getAlpha() > 0.0_hf; } -bool ColorLayer::setColor(const half3& color) { +bool EffectLayer::setColor(const half3& color) { if (mCurrentState.color.r == color.r && mCurrentState.color.g == color.g && mCurrentState.color.b == color.b) { return false; @@ -76,7 +76,7 @@ bool ColorLayer::setColor(const half3& color) { return true; } -bool ColorLayer::setDataspace(ui::Dataspace dataspace) { +bool EffectLayer::setDataspace(ui::Dataspace dataspace) { if (mCurrentState.dataspace == dataspace) { return false; } @@ -88,7 +88,7 @@ bool ColorLayer::setDataspace(ui::Dataspace dataspace) { return true; } -void ColorLayer::preparePerFrameCompositionState() { +void EffectLayer::preparePerFrameCompositionState() { Layer::preparePerFrameCompositionState(); auto* compositionState = editCompositionState(); @@ -96,30 +96,30 @@ void ColorLayer::preparePerFrameCompositionState() { compositionState->compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; } -sp ColorLayer::getCompositionEngineLayerFE() const { +sp EffectLayer::getCompositionEngineLayerFE() const { return asLayerFE(); } -compositionengine::LayerFECompositionState* ColorLayer::editCompositionState() { +compositionengine::LayerFECompositionState* EffectLayer::editCompositionState() { return mCompositionState.get(); } -const compositionengine::LayerFECompositionState* ColorLayer::getCompositionState() const { +const compositionengine::LayerFECompositionState* EffectLayer::getCompositionState() const { return mCompositionState.get(); } -bool ColorLayer::isOpaque(const Layer::State& s) const { +bool EffectLayer::isOpaque(const Layer::State& s) const { // Consider the layer to be opaque if its opaque flag is set or its effective // alpha (considering the alpha of its parents as well) is 1.0; return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf; } -ui::Dataspace ColorLayer::getDataSpace() const { +ui::Dataspace EffectLayer::getDataSpace() const { return mDrawingState.dataspace; } -sp ColorLayer::createClone() { - sp layer = mFlinger->getFactory().createColorLayer( +sp EffectLayer::createClone() { + sp layer = mFlinger->getFactory().createEffectLayer( LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, LayerMetadata())); layer->setInitialValuesForClone(this); diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/EffectLayer.h similarity index 79% rename from services/surfaceflinger/ColorLayer.h rename to services/surfaceflinger/EffectLayer.h index 4deb162191..8694283760 100644 --- a/services/surfaceflinger/ColorLayer.h +++ b/services/surfaceflinger/EffectLayer.h @@ -23,15 +23,19 @@ namespace android { -class ColorLayer : public Layer { +// A layer that can render a combination of the following effects. +// * fill the bounds of the layer with a color +// * render a shadow cast by the bounds of the layer +// If no effects are enabled, the layer is considered to be invisible. +class EffectLayer : public Layer { public: - explicit ColorLayer(const LayerCreationArgs&); - ~ColorLayer() override; + explicit EffectLayer(const LayerCreationArgs&); + ~EffectLayer() override; sp getCompositionEngineLayerFE() const override; compositionengine::LayerFECompositionState* editCompositionState() override; - const char* getType() const override { return "ColorLayer"; } + const char* getType() const override { return "EffectLayer"; } bool isVisible() const override; bool setColor(const half3& color) override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index effbed67b8..8eb5c22fa8 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -56,10 +56,10 @@ #include #include "BufferLayer.h" -#include "ColorLayer.h" #include "Colorizer.h" #include "DisplayDevice.h" #include "DisplayHardware/HWComposer.h" +#include "EffectLayer.h" #include "FrameTracer/FrameTracer.h" #include "LayerProtoHelper.h" #include "LayerRejecter.h" @@ -165,7 +165,7 @@ LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, const sp c /* * onLayerDisplayed is only meaningful for BufferLayer, but, is called through * Layer. So, the implementation is done in BufferLayer. When called on a - * ColorLayer object, it's essentially a NOP. + * EffectLayer object, it's essentially a NOP. */ void Layer::onLayerDisplayed(const sp& /*releaseFence*/) {} @@ -1092,9 +1092,9 @@ bool Layer::setBackgroundColor(const half3& color, float alpha, ui::Dataspace da if (!mCurrentState.bgColorLayer && alpha != 0) { // create background color layer if one does not yet exist - uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor; + uint32_t flags = ISurfaceComposerClient::eFXSurfaceEffect; std::string name = mName + "BackgroundColorLayer"; - mCurrentState.bgColorLayer = mFlinger->getFactory().createColorLayer( + mCurrentState.bgColorLayer = mFlinger->getFactory().createEffectLayer( LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), 0, 0, flags, LayerMetadata())); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index de4a08070c..a249726739 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -212,7 +212,7 @@ public: InputWindowInfo inputInfo; wp touchableRegionCrop; - // dataspace is only used by BufferStateLayer and ColorLayer + // dataspace is only used by BufferStateLayer and EffectLayer ui::Dataspace dataspace; // The fields below this point are only used by BufferStateLayer diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e8c7a55bc6..55166c0ab3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -83,10 +83,10 @@ #include "BufferQueueLayer.h" #include "BufferStateLayer.h" #include "Client.h" -#include "ColorLayer.h" #include "Colorizer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" +#include "EffectLayer.h" #include "Layer.h" #include "LayerVector.h" #include "MonitoredProducer.h" @@ -3694,7 +3694,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags, std::move(metadata), handle, outTransformHint, &layer); break; - case ISurfaceComposerClient::eFXSurfaceColor: + case ISurfaceComposerClient::eFXSurfaceEffect: // check if buffer size is set for color layer. if (w > 0 || h > 0) { ALOGE("createLayer() failed, w or h cannot be set for color layer (w=%d, h=%d)", @@ -3702,8 +3702,8 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie return BAD_VALUE; } - result = createColorLayer(client, std::move(uniqueName), w, h, flags, - std::move(metadata), handle, &layer); + result = createEffectLayer(client, std::move(uniqueName), w, h, flags, + std::move(metadata), handle, &layer); break; case ISurfaceComposerClient::eFXSurfaceContainer: // check if buffer size is set for container layer. @@ -3821,10 +3821,10 @@ status_t SurfaceFlinger::createBufferStateLayer(const sp& client, std::s return NO_ERROR; } -status_t SurfaceFlinger::createColorLayer(const sp& client, std::string name, uint32_t w, - uint32_t h, uint32_t flags, LayerMetadata metadata, - sp* handle, sp* outLayer) { - *outLayer = getFactory().createColorLayer( +status_t SurfaceFlinger::createEffectLayer(const sp& client, std::string name, uint32_t w, + uint32_t h, uint32_t flags, LayerMetadata metadata, + sp* handle, sp* outLayer) { + *outLayer = getFactory().createEffectLayer( {this, client, std::move(name), w, h, flags, std::move(metadata)}); *handle = (*outLayer)->getHandle(); return NO_ERROR; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index ccf57946ab..3a48bdadff 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -648,9 +648,9 @@ private: sp* outHandle, uint32_t* outTransformHint, sp* outLayer); - status_t createColorLayer(const sp& client, std::string name, uint32_t w, uint32_t h, - uint32_t flags, LayerMetadata metadata, sp* outHandle, - sp* outLayer); + status_t createEffectLayer(const sp& client, std::string name, uint32_t w, uint32_t h, + uint32_t flags, LayerMetadata metadata, sp* outHandle, + sp* outLayer); status_t createContainerLayer(const sp& client, std::string name, uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata, diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index f9658a78d6..d49133d1fc 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -25,9 +25,9 @@ #include "BufferLayerConsumer.h" #include "BufferQueueLayer.h" #include "BufferStateLayer.h" -#include "ColorLayer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" +#include "EffectLayer.h" #include "Layer.h" #include "MonitoredProducer.h" #include "NativeWindowSurface.h" @@ -139,8 +139,8 @@ sp DefaultFactory::createBufferStateLayer(const LayerCreationA return new BufferStateLayer(args); } -sp DefaultFactory::createColorLayer(const LayerCreationArgs& args) { - return new ColorLayer(args); +sp DefaultFactory::createEffectLayer(const LayerCreationArgs& args) { + return new EffectLayer(args); } } // namespace android::surfaceflinger diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h index 36fae217ce..89194c7ad1 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h @@ -55,7 +55,7 @@ public: std::unique_ptr createCompositionEngine() override; sp createBufferQueueLayer(const LayerCreationArgs& args) override; sp createBufferStateLayer(const LayerCreationArgs& args) override; - sp createColorLayer(const LayerCreationArgs& args) override; + sp createEffectLayer(const LayerCreationArgs& args) override; sp createContainerLayer(const LayerCreationArgs& args) override; }; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index 951bd09293..1eab3b1302 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -31,7 +31,7 @@ typedef int32_t PixelFormat; class BufferQueueLayer; class BufferStateLayer; class BufferLayerConsumer; -class ColorLayer; +class EffectLayer; class ContainerLayer; class DisplayDevice; class DispSync; @@ -104,7 +104,7 @@ public: virtual sp createBufferQueueLayer(const LayerCreationArgs& args) = 0; virtual sp createBufferStateLayer(const LayerCreationArgs& args) = 0; - virtual sp createColorLayer(const LayerCreationArgs& args) = 0; + virtual sp createEffectLayer(const LayerCreationArgs& args) = 0; virtual sp createContainerLayer(const LayerCreationArgs& args) = 0; protected: diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index 24874b010b..6c8eb27bd0 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -531,7 +531,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorBasic) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction() .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) @@ -570,7 +570,7 @@ void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType Color priorBgColor = Color::BLUE; Color expectedColor = Color::BLACK; switch (layerType) { - case ISurfaceComposerClient::eFXSurfaceColor: + case ISurfaceComposerClient::eFXSurfaceEffect: ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType)); Transaction() .setCrop_legacy(layer, Rect(0, 0, width, height)) @@ -599,7 +599,7 @@ void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType return; } - if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceColor) { + if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceEffect) { Transaction() .setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN) .apply(); @@ -628,7 +628,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) { bool bufferFill = false; float alpha = 1.0f; Color finalColor = Color::RED; - ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceColor, + ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceEffect, priorColor, bufferFill, alpha, finalColor)); } @@ -744,7 +744,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) { sp colorLayer; ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction() .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f)) @@ -760,7 +760,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply(); const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f); @@ -787,7 +787,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorWithParentAlpha_Bug74220420) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply(); const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f); const float alpha = 0.25f; @@ -1663,7 +1663,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) { sp colorLayer; ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction() .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) .setLayer(colorLayer, mLayerZBase + 1) @@ -1719,7 +1719,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnParent) { ISurfaceComposerClient::eFXSurfaceContainer)); ASSERT_NO_FATAL_FAILURE( colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get())); + ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get())); Transaction() .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100)) @@ -1780,7 +1780,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnChildAndParent) { ISurfaceComposerClient::eFXSurfaceContainer)); ASSERT_NO_FATAL_FAILURE( colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get())); + ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get())); Transaction() .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100)) diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 5eb1739219..932c7c86fa 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -89,7 +89,7 @@ protected: SurfaceControl* parent = nullptr) { auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, parent); + ISurfaceComposerClient::eFXSurfaceEffect, parent); asTransaction([&](Transaction& t) { t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f}); t.setAlpha(colorLayer, color.a / 255.0f); @@ -268,7 +268,7 @@ private: mBlackBgSurface = createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */, - PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor); + PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect); // set layer stack (b/68888219) Transaction t; diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp index 7e9202bb82..84780ba73b 100644 --- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp @@ -69,13 +69,13 @@ TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) { TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) { sp parent = LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); sp childLayer; ASSERT_NO_FATAL_FAILURE( childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor, + ISurfaceComposerClient::eFXSurfaceEffect, parent.get())); Transaction() .setColor(childLayer, half3{1.0f, 0.0f, 0.0f}) @@ -116,17 +116,17 @@ TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) { TEST_P(LayerTypeTransactionTest, HideRelativeParentHidesLayer) { sp parent = LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); sp relativeParent = LayerTransactionTest::createLayer("RelativeParent", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); sp childLayer; ASSERT_NO_FATAL_FAILURE( childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor, + ISurfaceComposerClient::eFXSurfaceEffect, parent.get())); Transaction() .setColor(childLayer, half3{1.0f, 0.0f, 0.0f}) diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index a1c412801d..cf3f8e8865 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -1114,7 +1114,7 @@ TEST_F(BoundlessLayerTest, BufferLayerIgnoresSize) { TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) { sp colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get()); + ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { t.setColor(colorLayer, half3{0, 0, 0}); @@ -1139,7 +1139,7 @@ TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) { ASSERT_TRUE(cropLayer->isValid()); sp colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get()); + ISurfaceComposerClient::eFXSurfaceEffect, cropLayer.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10)); @@ -1164,7 +1164,7 @@ TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) { TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) { sp colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get()); + ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { t.setPosition(colorLayer, 320, 320); @@ -1195,7 +1195,7 @@ TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) { ASSERT_TRUE(boundlessLayerDownShift->isValid()); sp colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, boundlessLayerDownShift.get()); + ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayerDownShift.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { t.setPosition(boundlessLayerRightShift, 32, 0); @@ -1229,7 +1229,7 @@ TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) { ASSERT_TRUE(boundlessLayer->isValid()); sp colorLayer = mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, boundlessLayer.get()); + ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayer.get()); ASSERT_TRUE(colorLayer != nullptr); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { @@ -1261,7 +1261,7 @@ TEST_F(BoundlessLayerTest, RootBoundlessLayerCanSetTransform) { ASSERT_TRUE(rootBoundlessLayer->isValid()); sp colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, rootBoundlessLayer.get()); + ISurfaceComposerClient::eFXSurfaceEffect, rootBoundlessLayer.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp index c9fdc3b799..f8a5b4094d 100644 --- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp +++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp @@ -66,7 +66,7 @@ protected: void createColorLayer(uint32_t layerStack) { mColorLayer = createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */, - PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor); + PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect); ASSERT_TRUE(mColorLayer != nullptr); ASSERT_TRUE(mColorLayer->isValid()); asTransaction([&](Transaction& t) { diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index e75149653c..32c58ad390 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -1827,10 +1827,11 @@ class ChildColorLayerTest : public ChildLayerTest { protected: void SetUp() override { Base::SetUp(); - Base::mChild = Base::mComposerClient->createSurface(String8("Child surface"), 0, 0, - PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, - Base::mFGSurfaceControl.get()); + Base::mChild = + Base::mComposerClient->createSurface(String8("Child surface"), 0, 0, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect, + Base::mFGSurfaceControl.get()); { TransactionScope ts(*Base::sFakeComposer); ts.setColor(Base::mChild, diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 888e009282..6e83166a80 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -35,7 +35,7 @@ #include #include "BufferQueueLayer.h" -#include "ColorLayer.h" +#include "EffectLayer.h" #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" @@ -713,7 +713,7 @@ struct BaseLayerProperties { struct DefaultLayerProperties : public BaseLayerProperties {}; -struct ColorLayerProperties : public BaseLayerProperties { +struct EffectLayerProperties : public BaseLayerProperties { static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE; }; @@ -866,16 +866,16 @@ struct BaseLayerVariant { }; template -struct ColorLayerVariant : public BaseLayerVariant { +struct EffectLayerVariant : public BaseLayerVariant { using Base = BaseLayerVariant; - using FlingerLayerType = sp; + using FlingerLayerType = sp; static FlingerLayerType createLayer(CompositionTest* test) { - FlingerLayerType layer = Base::template createLayerWithFactory(test, [test]() { - return new ColorLayer(LayerCreationArgs(test->mFlinger.mFlinger.get(), sp(), - "test-layer", LayerProperties::WIDTH, - LayerProperties::HEIGHT, - LayerProperties::LAYER_FLAGS, LayerMetadata())); + FlingerLayerType layer = Base::template createLayerWithFactory(test, [test]() { + return new EffectLayer( + LayerCreationArgs(test->mFlinger.mFlinger.get(), sp(), "test-layer", + LayerProperties::WIDTH, LayerProperties::HEIGHT, + LayerProperties::LAYER_FLAGS, LayerMetadata())); }); auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer); @@ -1228,31 +1228,31 @@ TEST_F(CompositionTest, captureScreenNormalBufferLayer) { * Single-color layers */ -TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyGeometry) { +TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyGeometry) { displayRefreshCompositionDirtyGeometry< - CompositionCase, + CompositionCase, KeepCompositionTypeVariant, HwcCompositionResultVariant>>(); } -TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyFrame) { +TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyFrame) { displayRefreshCompositionDirtyFrame< - CompositionCase, + CompositionCase, KeepCompositionTypeVariant, HwcCompositionResultVariant>>(); } -TEST_F(CompositionTest, REComposedColorLayer) { +TEST_F(CompositionTest, REComposedEffectLayer) { displayRefreshCompositionDirtyFrame< - CompositionCase, + CompositionCase, ChangeCompositionTypeVariant, RECompositionResultVariant>>(); } -TEST_F(CompositionTest, captureScreenColorLayer) { +TEST_F(CompositionTest, captureScreenEffectLayer) { captureScreenComposition< - CompositionCase, + CompositionCase, NoCompositionTypeVariant, REScreenshotResultVariant>>(); } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp index cffdc14df7..edd9de46ab 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp @@ -27,7 +27,7 @@ #include "BufferQueueLayer.h" #include "BufferStateLayer.h" -#include "ColorLayer.h" +#include "EffectLayer.h" #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" @@ -68,7 +68,7 @@ protected: void setupComposer(int virtualDisplayCount); sp createBufferQueueLayer(); sp createBufferStateLayer(); - sp createColorLayer(); + sp createEffectLayer(); void setParent(Layer* child, Layer* parent); void commitTransaction(Layer* layer); @@ -111,11 +111,11 @@ sp RefreshRateSelectionTest::createBufferStateLayer() { return new BufferStateLayer(args); } -sp RefreshRateSelectionTest::createColorLayer() { +sp RefreshRateSelectionTest::createEffectLayer() { sp client; LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS, LayerMetadata()); - return new ColorLayer(args); + return new EffectLayer(args); } void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) { @@ -244,11 +244,11 @@ TEST_F(RefreshRateSelectionTest, testPriorityOnBufferStateLayers) { ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority()); } -TEST_F(RefreshRateSelectionTest, testPriorityOnColorLayers) { - mParent = createColorLayer(); - mChild = createColorLayer(); +TEST_F(RefreshRateSelectionTest, testPriorityOnEffectLayers) { + mParent = createEffectLayer(); + mChild = createEffectLayer(); setParent(mChild.get(), mParent.get()); - mGrandChild = createColorLayer(); + mGrandChild = createEffectLayer(); setParent(mGrandChild.get(), mChild.get()); ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority()); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 798ba766fc..685cfaf450 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -25,9 +25,9 @@ #include "BufferQueueLayer.h" #include "BufferStateLayer.h" -#include "ColorLayer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" +#include "EffectLayer.h" #include "FakePhaseOffsets.h" #include "Layer.h" #include "NativeWindowSurface.h" @@ -147,9 +147,7 @@ public: return nullptr; } - sp createColorLayer(const LayerCreationArgs&) override { - return nullptr; - } + sp createEffectLayer(const LayerCreationArgs&) override { return nullptr; } sp createContainerLayer(const LayerCreationArgs&) override { return nullptr; -- GitLab From 92fa2f4b7e0d67f0b28e9f775ce4cd094c721da1 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 11 Feb 2020 15:33:56 -0800 Subject: [PATCH 0790/1255] SurfaceFlinger: make sure VsyncPredictor always maintains a valid slope - Add a safety check around the predicated vsync period in case the timestamps we got from present fences are incorrect. We suspect this happens when the device is in AOD. - Ignore present fences when device is in AOD. Change-Id: Ib02287cb0b8e693b1f5f384d754c2c3d978024dc Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Bug: 149299560 --- .../Scheduler/VSyncPredictor.cpp | 56 +++++++++++-------- .../surfaceflinger/Scheduler/VSyncPredictor.h | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 3 +- .../tests/unittests/VSyncPredictorTest.cpp | 22 +++++++- 4 files changed, 57 insertions(+), 28 deletions(-) diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index b467f24207..399da19c75 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -53,15 +53,15 @@ inline void VSyncPredictor::traceInt64If(const char* name, int64_t value) const } inline size_t VSyncPredictor::next(int i) const { - return (i + 1) % timestamps.size(); + return (i + 1) % mTimestamps.size(); } bool VSyncPredictor::validate(nsecs_t timestamp) const { - if (lastTimestampIndex < 0 || timestamps.empty()) { + if (mLastTimestampIndex < 0 || mTimestamps.empty()) { return true; } - auto const aValidTimestamp = timestamps[lastTimestampIndex]; + auto const aValidTimestamp = mTimestamps[mLastTimestampIndex]; auto const percent = (timestamp - aValidTimestamp) % mIdealPeriod * kMaxPercent / mIdealPeriod; return percent < kOutlierTolerancePercent || percent > (kMaxPercent - kOutlierTolerancePercent); } @@ -79,15 +79,15 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { return false; } - if (timestamps.size() != kHistorySize) { - timestamps.push_back(timestamp); - lastTimestampIndex = next(lastTimestampIndex); + if (mTimestamps.size() != kHistorySize) { + mTimestamps.push_back(timestamp); + mLastTimestampIndex = next(mLastTimestampIndex); } else { - lastTimestampIndex = next(lastTimestampIndex); - timestamps[lastTimestampIndex] = timestamp; + mLastTimestampIndex = next(mLastTimestampIndex); + mTimestamps[mLastTimestampIndex] = timestamp; } - if (timestamps.size() < kMinimumSamplesForPrediction) { + if (mTimestamps.size() < kMinimumSamplesForPrediction) { mRateMap[mIdealPeriod] = {mIdealPeriod, 0}; return true; } @@ -107,11 +107,11 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { // // intercept = mean(Y) - slope * mean(X) // - std::vector vsyncTS(timestamps.size()); - std::vector ordinals(timestamps.size()); + std::vector vsyncTS(mTimestamps.size()); + std::vector ordinals(mTimestamps.size()); // normalizing to the oldest timestamp cuts down on error in calculating the intercept. - auto const oldest_ts = *std::min_element(timestamps.begin(), timestamps.end()); + auto const oldest_ts = *std::min_element(mTimestamps.begin(), mTimestamps.end()); auto it = mRateMap.find(mIdealPeriod); auto const currentPeriod = std::get<0>(it->second); // TODO (b/144707443): its important that there's some precision in the mean of the ordinals @@ -120,10 +120,10 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { // scheduler::utils::calculate_mean to have a fixed point fractional part. static constexpr int kScalingFactor = 10; - for (auto i = 0u; i < timestamps.size(); i++) { - traceInt64If("VSP-ts", timestamps[i]); + for (auto i = 0u; i < mTimestamps.size(); i++) { + traceInt64If("VSP-ts", mTimestamps[i]); - vsyncTS[i] = timestamps[i] - oldest_ts; + vsyncTS[i] = mTimestamps[i] - oldest_ts; ordinals[i] = ((vsyncTS[i] + (currentPeriod / 2)) / currentPeriod) * kScalingFactor; } @@ -143,12 +143,20 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { if (CC_UNLIKELY(bottom == 0)) { it->second = {mIdealPeriod, 0}; + clearTimestamps(); return false; } nsecs_t const anticipatedPeriod = top / bottom * kScalingFactor; nsecs_t const intercept = meanTS - (anticipatedPeriod * meanOrdinal / kScalingFactor); + auto const percent = std::abs(anticipatedPeriod - mIdealPeriod) * kMaxPercent / mIdealPeriod; + if (percent >= kOutlierTolerancePercent) { + it->second = {mIdealPeriod, 0}; + clearTimestamps(); + return false; + } + traceInt64If("VSP-period", anticipatedPeriod); traceInt64If("VSP-intercept", intercept); @@ -164,14 +172,14 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { auto const [slope, intercept] = getVSyncPredictionModel(lk); - if (timestamps.empty()) { + if (mTimestamps.empty()) { traceInt64If("VSP-mode", 1); auto const knownTimestamp = mKnownTimestamp ? *mKnownTimestamp : timePoint; auto const numPeriodsOut = ((timePoint - knownTimestamp) / mIdealPeriod) + 1; return knownTimestamp + numPeriodsOut * mIdealPeriod; } - auto const oldest = *std::min_element(timestamps.begin(), timestamps.end()); + auto const oldest = *std::min_element(mTimestamps.begin(), mTimestamps.end()); // See b/145667109, the ordinal calculation must take into account the intercept. auto const zeroPoint = oldest + intercept; @@ -225,10 +233,10 @@ void VSyncPredictor::setPeriod(nsecs_t period) { } void VSyncPredictor::clearTimestamps() { - if (!timestamps.empty()) { - mKnownTimestamp = *std::max_element(timestamps.begin(), timestamps.end()); - timestamps.clear(); - lastTimestampIndex = 0; + if (!mTimestamps.empty()) { + mKnownTimestamp = *std::max_element(mTimestamps.begin(), mTimestamps.end()); + mTimestamps.clear(); + mLastTimestampIndex = 0; } } @@ -236,11 +244,11 @@ bool VSyncPredictor::needsMoreSamples(nsecs_t now) const { using namespace std::literals::chrono_literals; std::lock_guard lk(mMutex); bool needsMoreSamples = true; - if (timestamps.size() >= kMinimumSamplesForPrediction) { + if (mTimestamps.size() >= kMinimumSamplesForPrediction) { nsecs_t constexpr aLongTime = std::chrono::duration_cast(500ms).count(); - if (!(lastTimestampIndex < 0 || timestamps.empty())) { - auto const lastTimestamp = timestamps[lastTimestampIndex]; + if (!(mLastTimestampIndex < 0 || mTimestamps.empty())) { + auto const lastTimestamp = mTimestamps[mLastTimestampIndex]; needsMoreSamples = !((lastTimestamp + aLongTime) > now); } } diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h index 532fe9e928..ef1d88ac27 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.h +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h @@ -83,8 +83,8 @@ private: std::unordered_map> mutable mRateMap GUARDED_BY(mMutex); - int lastTimestampIndex GUARDED_BY(mMutex) = 0; - std::vector timestamps GUARDED_BY(mMutex); + int mLastTimestampIndex GUARDED_BY(mMutex) = 0; + std::vector mTimestamps GUARDED_BY(mMutex); }; } // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f81179a3e2..edf9b42769 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2081,7 +2081,8 @@ void SurfaceFlinger::postComposition() } }); - if (presentFenceTime->isValid()) { + if (displayDevice && displayDevice->isPrimary() && + displayDevice->getPowerMode() == HWC_POWER_MODE_NORMAL && presentFenceTime->isValid()) { mScheduler->addPresentFence(presentFenceTime); } diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp index 6ec3844f25..f834af895c 100644 --- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp @@ -36,7 +36,7 @@ using namespace std::literals; namespace android::scheduler { MATCHER_P2(IsCloseTo, value, tolerance, "is within tolerance") { - return arg <= value + tolerance && value >= value - tolerance; + return arg <= value + tolerance && arg >= value - tolerance; } std::vector generateVsyncTimestamps(size_t count, nsecs_t period, nsecs_t bias) { @@ -370,6 +370,26 @@ TEST_F(VSyncPredictorTest, resetsWhenInstructed) { IsCloseTo(idealPeriod, mMaxRoundingError)); } +TEST_F(VSyncPredictorTest, slopeAlwaysValid) { + constexpr auto kNumVsyncs = 100; + auto invalidPeriod = mPeriod; + auto now = 0; + for (int i = 0; i < kNumVsyncs; i++) { + tracker.addVsyncTimestamp(now); + now += invalidPeriod; + invalidPeriod *= 0.9f; + + auto [slope, intercept] = tracker.getVSyncPredictionModel(); + EXPECT_THAT(slope, IsCloseTo(mPeriod, mPeriod * kOutlierTolerancePercent / 100.f)); + + // When VsyncPredictor returns the period it means that it doesn't know how to predict and + // it needs to get more samples + if (slope == mPeriod && intercept == 0) { + EXPECT_TRUE(tracker.needsMoreSamples(now)); + } + } +} + } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues -- GitLab From 0ede0213baf29864101a82d1db53ebadcf8a16f8 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Tue, 11 Feb 2020 11:21:09 -0800 Subject: [PATCH 0791/1255] Kawase blur feedback Test: transaction tests Test: visual Fixes: 149309004 Change-Id: I0e17eaa60b61065107f3c93a85fcc460ed61b83d --- .../gl/filters/KawaseBlurFilter.cpp | 18 ++++++++---------- .../renderengine/gl/filters/KawaseBlurFilter.h | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp index fc26bccc52..7524c6dfe2 100644 --- a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp +++ b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp @@ -106,21 +106,19 @@ string KawaseBlurFilter::getFragmentShader() const { precision mediump float; uniform sampler2D uTexture; - highp uniform vec2 uOffset; + uniform vec2 uOffset; highp in vec2 vUV; out vec4 fragColor; - vec4 kawaseBlur() { - return (texture(uTexture, vec2(-1.0, 1.0) * uOffset + vUV, 0.0) - + texture(uTexture, uOffset + vUV, 0.0) - + texture(uTexture, vec2(1.0, -1.0) * uOffset + vUV, 0.0) - + texture(uTexture, vec2(-1.0) * uOffset + vUV, 0.0)) - * 0.25; - } - void main() { - fragColor = kawaseBlur(); + fragColor = texture(uTexture, vUV, 0.0); + fragColor += texture(uTexture, vUV + vec2( uOffset.x, uOffset.y), 0.0); + fragColor += texture(uTexture, vUV + vec2( uOffset.x, -uOffset.y), 0.0); + fragColor += texture(uTexture, vUV + vec2(-uOffset.x, uOffset.y), 0.0); + fragColor += texture(uTexture, vUV + vec2(-uOffset.x, -uOffset.y), 0.0); + + fragColor = vec4(fragColor.rgb * 0.2, 1.0); } )SHADER"; } diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.h b/libs/renderengine/gl/filters/KawaseBlurFilter.h index ec81f81229..20009cf9bb 100644 --- a/libs/renderengine/gl/filters/KawaseBlurFilter.h +++ b/libs/renderengine/gl/filters/KawaseBlurFilter.h @@ -30,7 +30,7 @@ namespace gl { class KawaseBlurFilter : public BlurFilter { public: - static constexpr uint32_t kMaxPasses = 8; + static constexpr uint32_t kMaxPasses = 6; explicit KawaseBlurFilter(GLESRenderEngine& engine); status_t prepare() override; -- GitLab From 3248ea00de2c2c593d557ad6760bcfe9e5c2a96d Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 11 Feb 2020 17:27:38 -0800 Subject: [PATCH 0792/1255] Define out the hwbinder death notifier code for libgui This code is only needed for the NO_BINDER version of libgui (libgui_bufferqueue_static). For libgui, the notifier is linked inside the connect/disconnect call of BufferQueue itself. bug: 149345887 test: Android Auto team helped test it on Auto devices to fix the bug. Change-Id: I29ab83b9119729e3b878ace439086e87d9c585f6 --- libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp index 0f3ae2e28c..c76d771262 100644 --- a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp +++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp @@ -288,10 +288,12 @@ Return B2HGraphicBufferProducer::connect( &bOutput), &hStatus) && b2h(bOutput, &hOutput); - if (converted) { +#ifdef NO_BINDER + if (converted && hListener != nullptr) { mObituary = new Obituary(this, hListener, hConnectionType); hListener->linkToDeath(mObituary, 0); } +#endif // NO_BINDER _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, hOutput); return {}; } @@ -304,10 +306,12 @@ Return B2HGraphicBufferProducer::disconnect( } HStatus hStatus{}; bool converted = b2h(mBase->disconnect(bConnectionType), &hStatus); +#ifdef NO_BINDER if (mObituary != nullptr) { mObituary->listener->unlinkToDeath(mObituary); mObituary.clear(); } +#endif // NO_BINDER return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; } -- GitLab From 54d3e189009e4138ec5074b0ac79f56ce322daed Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 15 Jan 2020 17:38:38 -0800 Subject: [PATCH 0793/1255] Add verifyInputEvent api to InputDispatcher Now InputDispatcher will be able to check whether a certain InputEvent is legitimate. Use the 'verifyInputEvent' api to determine if a given 'InputEvent' actually came from InputDispatcher. Bug: 134977432 Test: atest VerifiedKeyEventTest VerifiedMotionEventTest libinput_tests inputflinger_tests Change-Id: I8e7fa9bfa3c14b0b0d949fb5e28b43ff7583398f --- include/input/Input.h | 62 ++++++++++ libs/input/Input.cpp | 24 ++++ libs/input/tests/Android.bp | 2 +- libs/input/tests/InputEvent_test.cpp | 1 - .../tests/InputPublisherAndConsumer_test.cpp | 1 + libs/input/tests/StructLayout_test.cpp | 30 +++++ libs/input/tests/VerifiedInputEvent_test.cpp | 116 ++++++++++++++++++ .../dispatcher/InputDispatcher.cpp | 4 + .../inputflinger/dispatcher/InputDispatcher.h | 2 + .../include/InputDispatcherInterface.h | 7 ++ 10 files changed, 247 insertions(+), 2 deletions(-) create mode 100644 libs/input/tests/VerifiedInputEvent_test.cpp diff --git a/include/input/Input.h b/include/input/Input.h index cf0814cf2f..14a7288d19 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -73,6 +73,19 @@ enum { AMOTION_EVENT_FLAG_TAINTED = 0x80000000, }; +/** + * Allowed VerifiedKeyEvent flags. All other flags from KeyEvent do not get verified. + * These values must be kept in sync with VerifiedKeyEvent.java + */ +constexpr int32_t VERIFIED_KEY_EVENT_FLAGS = AKEY_EVENT_FLAG_CANCELED; + +/** + * Allowed VerifiedMotionEventFlags. All other flags from MotionEvent do not get verified. + * These values must be kept in sync with VerifiedMotionEvent.java + */ +constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + enum { /* Used when a motion event is not associated with any display. * Typically used for non-pointer events. */ @@ -718,6 +731,55 @@ protected: bool mInTouchMode; }; +/** + * Base class for verified events. + * Do not create a VerifiedInputEvent explicitly. + * Use helper functions to create them from InputEvents. + */ +struct __attribute__((__packed__)) VerifiedInputEvent { + enum class Type : int32_t { + KEY = AINPUT_EVENT_TYPE_KEY, + MOTION = AINPUT_EVENT_TYPE_MOTION, + }; + + Type type; + int32_t deviceId; + nsecs_t eventTimeNanos; + uint32_t source; + int32_t displayId; +}; + +/** + * Same as KeyEvent, but only contains the data that can be verified. + * If you update this class, you must also update VerifiedKeyEvent.java + */ +struct __attribute__((__packed__)) VerifiedKeyEvent : public VerifiedInputEvent { + int32_t action; + nsecs_t downTimeNanos; + int32_t flags; + int32_t keyCode; + int32_t scanCode; + int32_t metaState; + int32_t repeatCount; +}; + +/** + * Same as MotionEvent, but only contains the data that can be verified. + * If you update this class, you must also update VerifiedMotionEvent.java + */ +struct __attribute__((__packed__)) VerifiedMotionEvent : public VerifiedInputEvent { + float rawX; + float rawY; + int32_t actionMasked; + nsecs_t downTimeNanos; + int32_t flags; + int32_t metaState; + int32_t buttonState; +}; + +VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event); +VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event); + /* * Input event factory. */ diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 85b0fd0ec7..2a73dc0149 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -57,6 +57,30 @@ const char* inputEventTypeToString(int32_t type) { return "UNKNOWN"; } +VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) { + return {{VerifiedInputEvent::Type::KEY, event.getDeviceId(), event.getEventTime(), + event.getSource(), event.getDisplayId()}, + event.getAction(), + event.getDownTime(), + event.getFlags() & VERIFIED_KEY_EVENT_FLAGS, + event.getKeyCode(), + event.getScanCode(), + event.getMetaState(), + event.getRepeatCount()}; +} + +VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event) { + return {{VerifiedInputEvent::Type::MOTION, event.getDeviceId(), event.getEventTime(), + event.getSource(), event.getDisplayId()}, + event.getRawX(0), + event.getRawY(0), + event.getActionMasked(), + event.getDownTime(), + event.getFlags() & VERIFIED_MOTION_EVENT_FLAGS, + event.getMetaState(), + event.getButtonState()}; +} + void InputEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId, std::array hmac) { mDeviceId = deviceId; diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index c1c35e1b89..fb21d5e3b1 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -10,12 +10,12 @@ cc_test { "LatencyStatistics_test.cpp", "TouchVideoFrame_test.cpp", "VelocityTracker_test.cpp", + "VerifiedInputEvent_test.cpp", ], cflags: [ "-Wall", "-Wextra", "-Werror", - "-Wno-unused-variable", ], shared_libs: [ "libinput", diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index dce1f29124..d0f761887a 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -46,7 +46,6 @@ TEST_F(PointerCoordsTest, ClearSetsBitsToZero) { } TEST_F(PointerCoordsTest, AxisValues) { - float* valuePtr; PointerCoords coords; coords.clear(); diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index d4bbf6c6ac..885196f3f3 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -38,6 +38,7 @@ protected: virtual void SetUp() { status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); + ASSERT_EQ(OK, result); mPublisher = new InputPublisher(serverChannel); mConsumer = new InputConsumer(clientChannel); diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index aa8a2d488f..dd127fcabd 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -98,4 +98,34 @@ void TestBodySize() { static_assert(sizeof(InputMessage::Body::Focus) == 8); } +// --- VerifiedInputEvent --- +// Ensure that VerifiedInputEvent, VerifiedKeyEvent, VerifiedMotionEvent are packed. +// We will treat them as byte collections when signing them. There should not be any uninitialized +// data in-between fields. Otherwise, the padded data will affect the hmac value and verifications +// will fail. + +void TestVerifiedEventSize() { + // VerifiedInputEvent + constexpr size_t VERIFIED_INPUT_EVENT_SIZE = sizeof(VerifiedInputEvent::type) + + sizeof(VerifiedInputEvent::deviceId) + sizeof(VerifiedInputEvent::eventTimeNanos) + + sizeof(VerifiedInputEvent::source) + sizeof(VerifiedInputEvent::displayId); + static_assert(sizeof(VerifiedInputEvent) == VERIFIED_INPUT_EVENT_SIZE); + + // VerifiedKeyEvent + constexpr size_t VERIFIED_KEY_EVENT_SIZE = VERIFIED_INPUT_EVENT_SIZE + + sizeof(VerifiedKeyEvent::action) + sizeof(VerifiedKeyEvent::downTimeNanos) + + sizeof(VerifiedKeyEvent::flags) + sizeof(VerifiedKeyEvent::keyCode) + + sizeof(VerifiedKeyEvent::scanCode) + sizeof(VerifiedKeyEvent::metaState) + + sizeof(VerifiedKeyEvent::repeatCount); + static_assert(sizeof(VerifiedKeyEvent) == VERIFIED_KEY_EVENT_SIZE); + + // VerifiedMotionEvent + constexpr size_t VERIFIED_MOTION_EVENT_SIZE = VERIFIED_INPUT_EVENT_SIZE + + sizeof(VerifiedMotionEvent::rawX) + sizeof(VerifiedMotionEvent::rawY) + + sizeof(VerifiedMotionEvent::actionMasked) + sizeof(VerifiedMotionEvent::downTimeNanos) + + sizeof(VerifiedMotionEvent::flags) + sizeof(VerifiedMotionEvent::metaState) + + sizeof(VerifiedMotionEvent::buttonState); + static_assert(sizeof(VerifiedMotionEvent) == VERIFIED_MOTION_EVENT_SIZE); +} + } // namespace android diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp new file mode 100644 index 0000000000..a59dbe5987 --- /dev/null +++ b/libs/input/tests/VerifiedInputEvent_test.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace android { + +static KeyEvent getKeyEventWithFlags(int32_t flags) { + KeyEvent event; + event.initialize(2 /*deviceId*/, AINPUT_SOURCE_GAMEPAD, ADISPLAY_ID_DEFAULT, INVALID_HMAC, + AKEY_EVENT_ACTION_DOWN, flags, AKEYCODE_BUTTON_X, 121 /*scanCode*/, + AMETA_ALT_ON, 1 /*repeatCount*/, 1000 /*downTime*/, 2000 /*eventTime*/); + return event; +} + +static MotionEvent getMotionEventWithFlags(int32_t flags) { + MotionEvent event; + constexpr size_t pointerCount = 1; + PointerProperties pointerProperties[pointerCount]; + PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerProperties[i].id = i; + pointerCoords[i].clear(); + } + + event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, INVALID_HMAC, + AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags, + AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, + MotionClassification::NONE, 2 /*xScale*/, 3 /*yScale*/, 4 /*xOffset*/, + 5 /*yOffset*/, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/, 280 /*xCursorPosition*/, + 540 /*yCursorPosition*/, 100 /*downTime*/, 200 /*eventTime*/, pointerCount, + pointerProperties, pointerCoords); + return event; +} + +TEST(VerifiedKeyEventTest, ConvertKeyEventToVerifiedKeyEvent) { + KeyEvent event = getKeyEventWithFlags(0); + VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event); + + ASSERT_EQ(VerifiedInputEvent::Type::KEY, verified.type); + + ASSERT_EQ(event.getDeviceId(), verified.deviceId); + ASSERT_EQ(event.getEventTime(), verified.eventTimeNanos); + ASSERT_EQ(event.getSource(), verified.source); + ASSERT_EQ(event.getDisplayId(), verified.displayId); + + ASSERT_EQ(event.getAction(), verified.action); + ASSERT_EQ(event.getDownTime(), verified.downTimeNanos); + ASSERT_EQ(event.getFlags() & VERIFIED_KEY_EVENT_FLAGS, verified.flags); + ASSERT_EQ(event.getKeyCode(), verified.keyCode); + ASSERT_EQ(event.getScanCode(), verified.scanCode); + ASSERT_EQ(event.getMetaState(), verified.metaState); + ASSERT_EQ(event.getRepeatCount(), verified.repeatCount); +} + +TEST(VerifiedKeyEventTest, VerifiedKeyEventContainsOnlyVerifiedFlags) { + KeyEvent event = getKeyEventWithFlags(AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_FALLBACK); + VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event); + ASSERT_EQ(AKEY_EVENT_FLAG_CANCELED, verified.flags); +} + +TEST(VerifiedKeyEventTest, VerifiedKeyEventDoesNotContainUnverifiedFlags) { + KeyEvent event = getKeyEventWithFlags(AKEY_EVENT_FLAG_EDITOR_ACTION); + VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event); + ASSERT_EQ(0, verified.flags); +} + +TEST(VerifiedMotionEventTest, ConvertMotionEventToVerifiedMotionEvent) { + MotionEvent event = getMotionEventWithFlags(0); + VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event); + + ASSERT_EQ(VerifiedInputEvent::Type::MOTION, verified.type); + + ASSERT_EQ(event.getDeviceId(), verified.deviceId); + ASSERT_EQ(event.getEventTime(), verified.eventTimeNanos); + ASSERT_EQ(event.getSource(), verified.source); + ASSERT_EQ(event.getDisplayId(), verified.displayId); + + ASSERT_EQ(event.getRawX(0), verified.rawX); + ASSERT_EQ(event.getRawY(0), verified.rawY); + ASSERT_EQ(event.getAction(), verified.actionMasked); + ASSERT_EQ(event.getDownTime(), verified.downTimeNanos); + ASSERT_EQ(event.getFlags() & VERIFIED_MOTION_EVENT_FLAGS, verified.flags); + ASSERT_EQ(event.getMetaState(), verified.metaState); + ASSERT_EQ(event.getButtonState(), verified.buttonState); +} + +TEST(VerifiedMotionEventTest, VerifiedMotionEventContainsOnlyVerifiedFlags) { + MotionEvent event = getMotionEventWithFlags(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | + AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE); + VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event); + ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, verified.flags); +} + +TEST(VerifiedMotionEventTest, VerifiedMotionEventDoesNotContainUnverifiedFlags) { + MotionEvent event = getMotionEventWithFlags(AMOTION_EVENT_FLAG_TAINTED); + VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event); + ASSERT_EQ(0, verified.flags); +} + +} // namespace android diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index f2b95e7f7a..a8158ba3cf 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3340,6 +3340,10 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec return injectionResult; } +std::unique_ptr InputDispatcher::verifyInputEvent(const InputEvent& event) { + return nullptr; +} + bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { return injectorUid == 0 || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index d2aea80069..72511e9bf2 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -96,6 +96,8 @@ public: int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags) override; + virtual std::unique_ptr verifyInputEvent(const InputEvent& event) override; + virtual void setInputWindows( const std::vector>& inputWindowHandles, int32_t displayId, const sp& setInputWindowsListener = nullptr) override; diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index 3424f4ce84..6e986768fc 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -92,6 +92,13 @@ public: int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags) = 0; + /* + * Check whether InputEvent actually happened by checking the signature of the event. + * + * Return nullptr if the event cannot be verified. + */ + virtual std::unique_ptr verifyInputEvent(const InputEvent& event) = 0; + /* Sets the list of input windows. * * This method may be called on any thread (usually by the input manager). -- GitLab From 342c9270b18499de563d6997bd3b08275b60982e Mon Sep 17 00:00:00 2001 From: Gang Wang Date: Mon, 13 Jan 2020 13:15:04 -0500 Subject: [PATCH 0794/1255] Add HmacKeyManager to InputDispatcher This class will be used to sign pieces of MotionEvent and MotionEntry. Bug: 134977432 Test: atest libinput_tests inputflinger_tests Change-Id: Ica006edc5b049e1d5d894de255866eedb9cbb0e2 --- services/inputflinger/Android.bp | 1 + services/inputflinger/dispatcher/Android.bp | 1 + .../dispatcher/InputDispatcher.cpp | 51 +++++++++++++ .../inputflinger/dispatcher/InputDispatcher.h | 10 +++ .../tests/InputDispatcher_test.cpp | 75 +++++++++++++++++++ 5 files changed, 138 insertions(+) diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 308e93aa48..5c80d551b8 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -40,6 +40,7 @@ cc_library_shared { "libinputreporter", "libinputreader", "libbinder", + "libcrypto", "libcutils", "libhidlbase", "libinput", diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp index a556aad553..3f956a88fb 100644 --- a/services/inputflinger/dispatcher/Android.bp +++ b/services/inputflinger/dispatcher/Android.bp @@ -28,6 +28,7 @@ cc_library_static { ], shared_libs: [ "libbase", + "libcrypto", "libcutils", "libinput", "libinputreporter", diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index a8158ba3cf..306ed40abb 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -61,6 +61,8 @@ static constexpr bool DEBUG_FOCUS = false; #include #include #include +#include +#include #include #include @@ -325,6 +327,55 @@ static std::unique_ptr createDispatchEntry(const InputTarget& inp return dispatchEntry; } +static std::array getRandomKey() { + std::array key; + if (RAND_bytes(key.data(), key.size()) != 1) { + LOG_ALWAYS_FATAL("Can't generate HMAC key"); + } + return key; +} + +// --- HmacKeyManager --- + +HmacKeyManager::HmacKeyManager() : mHmacKey(getRandomKey()) {} + +std::array HmacKeyManager::sign(const VerifiedInputEvent& event) const { + size_t size; + switch (event.type) { + case VerifiedInputEvent::Type::KEY: { + size = sizeof(VerifiedKeyEvent); + break; + } + case VerifiedInputEvent::Type::MOTION: { + size = sizeof(VerifiedMotionEvent); + break; + } + } + std::vector data; + const uint8_t* start = reinterpret_cast(&event); + data.assign(start, start + size); + return sign(data); +} + +std::array HmacKeyManager::sign(const std::vector& data) const { + // SHA256 always generates 32-bytes result + std::array hash; + unsigned int hashLen = 0; + uint8_t* result = HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data.data(), data.size(), + hash.data(), &hashLen); + if (result == nullptr) { + ALOGE("Could not sign the data using HMAC"); + return INVALID_HMAC; + } + + if (hashLen != hash.size()) { + ALOGE("HMAC-SHA256 has unexpected length"); + return INVALID_HMAC; + } + + return hash; +} + // --- InputDispatcher --- InputDispatcher::InputDispatcher(const sp& policy) diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 72511e9bf2..ded59a595c 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -56,6 +56,16 @@ namespace android::inputdispatcher { class Connection; +class HmacKeyManager { +public: + HmacKeyManager(); + std::array sign(const VerifiedInputEvent& event) const; + +private: + std::array sign(const std::vector& data) const; + const std::array mHmacKey; +}; + /* Dispatches events to input targets. Some functions of the input dispatcher, such as * identifying input targets, are controlled by a separate policy object. * diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 27db8f5534..c4092cd696 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -43,6 +43,18 @@ struct PointF { float y; }; +/** + * Return a DOWN key event with KEYCODE_A. + */ +static KeyEvent getTestKeyEvent() { + KeyEvent event; + + event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC, + AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, + ARBITRARY_TIME); + return event; +} + // --- FakeInputDispatcherPolicy --- class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { @@ -197,6 +209,69 @@ private: } }; +// --- HmacKeyManagerTest --- + +class HmacKeyManagerTest : public testing::Test { +protected: + HmacKeyManager mHmacKeyManager; +}; + +/** + * Ensure that separate calls to sign the same data are generating the same key. + * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance + * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky + * tests. + */ +TEST_F(HmacKeyManagerTest, GeneratedHmac_IsConsistent) { + KeyEvent event = getTestKeyEvent(); + VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event); + + std::array hmac1 = mHmacKeyManager.sign(verifiedEvent); + std::array hmac2 = mHmacKeyManager.sign(verifiedEvent); + ASSERT_EQ(hmac1, hmac2); +} + +/** + * Ensure that changes in VerifiedKeyEvent produce a different hmac. + */ +TEST_F(HmacKeyManagerTest, GeneratedHmac_ChangesWhenFieldsChange) { + KeyEvent event = getTestKeyEvent(); + VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event); + std::array initialHmac = mHmacKeyManager.sign(verifiedEvent); + + verifiedEvent.deviceId += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.source += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.eventTimeNanos += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.displayId += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.action += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.downTimeNanos += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.flags += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.keyCode += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.scanCode += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.metaState += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); + + verifiedEvent.repeatCount += 1; + ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent)); +} // --- InputDispatcherTest --- -- GitLab From 0d8ed6e8ade20652cea20f579f40b1d698ce8fc0 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 17 Jan 2020 15:48:59 -0800 Subject: [PATCH 0795/1255] Use VIRTUAL_KEYBOARD_ID for injected events The events injected via injectInputEvent will no longer be allowed to specify an arbitrary device id. All injected events will now come from VIRTUAL_KEYBOARD_ID. Bug: 134977432 Test: atest libinput_tests inputflinger_tests Change-Id: I9a61a99cf5f8ca1a27e4526dd6feedf2c1beec0f --- .../dispatcher/InputDispatcher.cpp | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 306ed40abb..75bc0aa7c8 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -60,6 +60,7 @@ static constexpr bool DEBUG_FOCUS = false; #include #include #include +#include #include #include #include @@ -3204,22 +3205,22 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec std::queue injectedEntries; switch (event->getType()) { case AINPUT_EVENT_TYPE_KEY: { - KeyEvent keyEvent; - keyEvent.initialize(*static_cast(event)); - int32_t action = keyEvent.getAction(); + const KeyEvent& incomingKey = static_cast(*event); + int32_t action = incomingKey.getAction(); if (!validateKeyEvent(action)) { return INPUT_EVENT_INJECTION_FAILED; } - int32_t flags = keyEvent.getFlags(); - int32_t keyCode = keyEvent.getKeyCode(); - int32_t metaState = keyEvent.getMetaState(); - accelerateMetaShortcuts(keyEvent.getDeviceId(), action, + int32_t flags = incomingKey.getFlags(); + int32_t keyCode = incomingKey.getKeyCode(); + int32_t metaState = incomingKey.getMetaState(); + accelerateMetaShortcuts(VIRTUAL_KEYBOARD_ID, action, /*byref*/ keyCode, /*byref*/ metaState); - keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), - keyEvent.getDisplayId(), INVALID_HMAC, action, flags, keyCode, - keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(), - keyEvent.getDownTime(), keyEvent.getEventTime()); + KeyEvent keyEvent; + keyEvent.initialize(VIRTUAL_KEYBOARD_ID, incomingKey.getSource(), + incomingKey.getDisplayId(), INVALID_HMAC, action, flags, keyCode, + incomingKey.getScanCode(), metaState, incomingKey.getRepeatCount(), + incomingKey.getDownTime(), incomingKey.getEventTime()); if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { policyFlags |= POLICY_FLAG_VIRTUAL; @@ -3237,11 +3238,10 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec mLock.lock(); KeyEntry* injectedEntry = new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(), - keyEvent.getDeviceId(), keyEvent.getSource(), - keyEvent.getDisplayId(), policyFlags, action, flags, - keyEvent.getKeyCode(), keyEvent.getScanCode(), - keyEvent.getMetaState(), keyEvent.getRepeatCount(), - keyEvent.getDownTime()); + VIRTUAL_KEYBOARD_ID, keyEvent.getSource(), keyEvent.getDisplayId(), + policyFlags, action, flags, keyEvent.getKeyCode(), + keyEvent.getScanCode(), keyEvent.getMetaState(), + keyEvent.getRepeatCount(), keyEvent.getDownTime()); injectedEntries.push(injectedEntry); break; } @@ -3272,7 +3272,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); MotionEntry* injectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), + VIRTUAL_KEYBOARD_ID, motionEvent->getSource(), motionEvent->getDisplayId(), policyFlags, action, actionButton, motionEvent->getFlags(), motionEvent->getMetaState(), motionEvent->getButtonState(), motionEvent->getClassification(), @@ -3289,7 +3289,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec samplePointerCoords += pointerCount; MotionEntry* nextInjectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), + VIRTUAL_KEYBOARD_ID, motionEvent->getSource(), motionEvent->getDisplayId(), policyFlags, action, actionButton, motionEvent->getFlags(), motionEvent->getMetaState(), motionEvent->getButtonState(), -- GitLab From fe1209c190cd86651584b9dc8a7355b7131dc159 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Tue, 11 Feb 2020 12:25:35 -0800 Subject: [PATCH 0796/1255] BufferStateLayer: Use mCurrentState for HeadFrameNumber This is the frameNumber used for deferred transaction signalling. We need to use this because of cases where we defer a transaction for a surface to itself. In the BLAST world this may not make a huge amount of sense (Why not just merge the Buffer transaction with the deferred transaction?) but this is an important legacy use case, for example moving a window at the same time it draws makes use of this kind of technique. So anyway imagine we have something like this: Transaction { // containing Buffer -> frameNumber = 2 DeferTransactionUntil -> frameNumber = 2 Random other stuff } Now imagine getHeadFrameNumber returned mDrawingState.mFrameNumber (or mCurrentFrameNumber). Prior to doTransaction SurfaceFlinger will call notifyAvailableFrames, but because we haven't swapped mCurrentState to mDrawingState yet we will think the sync point is not ready. So we will return false from applyPendingState and not swap current state to drawing state. But because we don't swap current state to drawing state the number will never update and we will be stuck. This way we can see we need to return the frame number for the buffer we are about to apply. Bug: 146598493 Bug: 149251083 Bug: 149315421 Test: Flip the flag. Play. Change-Id: Ibac46da8ed48bef868328dfe38b106115f09b91f --- services/surfaceflinger/BufferLayer.h | 4 +-- services/surfaceflinger/BufferStateLayer.cpp | 26 ++++++++++++++++++++ services/surfaceflinger/BufferStateLayer.h | 1 + 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 4085b52449..208a82c4f1 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -202,12 +202,12 @@ protected: void updateCloneBufferInfo() override; uint64_t mPreviousFrameNumber = 0; + virtual uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const; + private: // Returns true if this layer requires filtering bool needsFiltering(const sp& displayDevice) const override; - uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const; - // BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame // and its parent layer is not bounded Rect getBufferSize(const State& s) const override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 371b80227b..556b60ca80 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -468,6 +468,32 @@ uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const return mDrawingState.frameNumber; } +/** + * This is the frameNumber used for deferred transaction signalling. We need to use this because + * of cases where we defer a transaction for a surface to itself. In the BLAST world this + * may not make a huge amount of sense (Why not just merge the Buffer transaction with the + * deferred transaction?) but this is an important legacy use case, for example moving + * a window at the same time it draws makes use of this kind of technique. So anyway + * imagine we have something like this: + * + * Transaction { // containing + * Buffer -> frameNumber = 2 + * DeferTransactionUntil -> frameNumber = 2 + * Random other stuff + * } + * Now imagine getHeadFrameNumber returned mDrawingState.mFrameNumber (or mCurrentFrameNumber). + * Prior to doTransaction SurfaceFlinger will call notifyAvailableFrames, but because we + * haven't swapped mCurrentState to mDrawingState yet we will think the sync point + * is not ready. So we will return false from applyPendingState and not swap + * current state to drawing state. But because we don't swap current state + * to drawing state the number will never update and we will be stuck. This way + * we can see we need to return the frame number for the buffer we are about + * to apply. + */ +uint64_t BufferStateLayer::getHeadFrameNumber(nsecs_t /* expectedPresentTime */) const { + return mCurrentState.frameNumber; +} + bool BufferStateLayer::getAutoRefresh() const { // TODO(marissaw): support shared buffer mode return false; diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 539442aa4e..753a74250b 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -116,6 +116,7 @@ public: protected: void gatherBufferInfo() override; + uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const; private: bool updateFrameEventHistory(const sp& acquireFence, nsecs_t postedTime, -- GitLab From f4916efbbe6272362c6cabe339a81e394697587f Mon Sep 17 00:00:00 2001 From: "Nathaniel R. Lewis" Date: Tue, 14 Jan 2020 11:57:18 -0800 Subject: [PATCH 0797/1255] Refactor InputMapper creation and collection type Move the creation of InputMappers from InputReader into InputDevice and change the collection type from a vector of raw pointers to a vector of unique_ptrs. Add helper functions for iterating over the mappers data structure. InputDevice::addMapper(...) is preserved for test cases, except rather than taking a bare pointer to a mapper, it creates the mapper, adds it's mapper vector, and returns a reference to this mapper. The unit tests have been updated for this change. Test: atest inputflinger_tests libinput_tests Change-Id: I1e1b69e8bd13dcfa835b2f846fd5cf0d6a4e1719 --- services/inputflinger/reader/InputDevice.cpp | 178 +++-- services/inputflinger/reader/InputReader.cpp | 92 +-- .../inputflinger/reader/include/InputDevice.h | 32 +- .../inputflinger/tests/InputReader_test.cpp | 626 ++++++++---------- 4 files changed, 422 insertions(+), 506 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 7fed61f09d..1c08ab1ed2 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -18,7 +18,16 @@ #include "InputDevice.h" -#include "InputMapper.h" +#include "CursorInputMapper.h" +#include "ExternalStylusInputMapper.h" +#include "InputReaderContext.h" +#include "JoystickInputMapper.h" +#include "KeyboardInputMapper.h" +#include "MultiTouchInputMapper.h" +#include "RotaryEncoderInputMapper.h" +#include "SingleTouchInputMapper.h" +#include "SwitchInputMapper.h" +#include "VibratorInputMapper.h" namespace android { @@ -36,13 +45,7 @@ InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t genera mHasMic(false), mDropUntilNextSync(false) {} -InputDevice::~InputDevice() { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - delete mMappers[i]; - } - mMappers.clear(); -} +InputDevice::~InputDevice() {} bool InputDevice::isEnabled() { return getEventHub()->isDeviceEnabled(mId); @@ -110,15 +113,80 @@ void InputDevice::dump(std::string& dump) { } } - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->dump(dump); - } + for_each_mapper([&dump](InputMapper& mapper) { mapper.dump(dump); }); } -void InputDevice::addMapper(InputMapper* mapper) { - mMappers.push_back(mapper); +void InputDevice::populateMappers() { + uint32_t classes = mClasses; + std::vector>& mappers = mMappers; + + // External devices. + if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { + setExternal(true); + } + + // Devices with mics. + if (classes & INPUT_DEVICE_CLASS_MIC) { + setMic(true); + } + + // Switch-like devices. + if (classes & INPUT_DEVICE_CLASS_SWITCH) { + mappers.push_back(std::make_unique(this)); + } + + // Scroll wheel-like devices. + if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) { + mappers.push_back(std::make_unique(this)); + } + + // Vibrator-like devices. + if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { + mappers.push_back(std::make_unique(this)); + } + + // Keyboard-like devices. + uint32_t keyboardSource = 0; + int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; + if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { + keyboardSource |= AINPUT_SOURCE_KEYBOARD; + } + if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { + keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; + } + if (classes & INPUT_DEVICE_CLASS_DPAD) { + keyboardSource |= AINPUT_SOURCE_DPAD; + } + if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { + keyboardSource |= AINPUT_SOURCE_GAMEPAD; + } + + if (keyboardSource != 0) { + mappers.push_back( + std::make_unique(this, keyboardSource, keyboardType)); + } + + // Cursor-like devices. + if (classes & INPUT_DEVICE_CLASS_CURSOR) { + mappers.push_back(std::make_unique(this)); + } + + // Touchscreens and touchpad devices. + if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { + mappers.push_back(std::make_unique(this)); + } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { + mappers.push_back(std::make_unique(this)); + } + + // Joystick-like devices. + if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { + mappers.push_back(std::make_unique(this)); + } + + // External stylus-like devices. + if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + mappers.push_back(std::make_unique(this)); + } } void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, @@ -193,10 +261,10 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config } } - for (InputMapper* mapper : mMappers) { - mapper->configure(when, config, changes); - mSources |= mapper->getSources(); - } + for_each_mapper([this, when, config, changes](InputMapper& mapper) { + mapper.configure(when, config, changes); + mSources |= mapper.getSources(); + }); // If a device is just plugged but it might be disabled, we need to update some info like // axis range of touch from each InputMapper first, then disable it. @@ -207,9 +275,7 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config } void InputDevice::reset(nsecs_t when) { - for (InputMapper* mapper : mMappers) { - mapper->reset(when); - } + for_each_mapper([when](InputMapper& mapper) { mapper.reset(when); }); mContext->updateGlobalMetaState(); @@ -244,32 +310,25 @@ void InputDevice::process(const RawEvent* rawEvents, size_t count) { mDropUntilNextSync = true; reset(rawEvent->when); } else { - for (InputMapper* mapper : mMappers) { - mapper->process(rawEvent); - } + for_each_mapper([rawEvent](InputMapper& mapper) { mapper.process(rawEvent); }); } --count; } } void InputDevice::timeoutExpired(nsecs_t when) { - for (InputMapper* mapper : mMappers) { - mapper->timeoutExpired(when); - } + for_each_mapper([when](InputMapper& mapper) { mapper.timeoutExpired(when); }); } void InputDevice::updateExternalStylusState(const StylusState& state) { - for (InputMapper* mapper : mMappers) { - mapper->updateExternalStylusState(state); - } + for_each_mapper([state](InputMapper& mapper) { mapper.updateExternalStylusState(state); }); } void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, mIsExternal, mHasMic); - for (InputMapper* mapper : mMappers) { - mapper->populateDeviceInfo(outDeviceInfo); - } + for_each_mapper( + [outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(outDeviceInfo); }); } int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { @@ -286,11 +345,12 @@ int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) { int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { int32_t result = AKEY_STATE_UNKNOWN; - for (InputMapper* mapper : mMappers) { - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { + for (auto& mapperPtr : mMappers) { + InputMapper& mapper = *mapperPtr; + if (sourcesMatchMask(mapper.getSources(), sourceMask)) { // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it. - int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code); + int32_t currentResult = (mapper.*getStateFunc)(sourceMask, code); if (currentResult >= AKEY_STATE_DOWN) { return currentResult; } else if (currentResult == AKEY_STATE_UP) { @@ -304,51 +364,41 @@ int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc ge bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { bool result = false; - for (InputMapper* mapper : mMappers) { - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { - result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); + for_each_mapper([&result, sourceMask, numCodes, keyCodes, outFlags](InputMapper& mapper) { + if (sourcesMatchMask(mapper.getSources(), sourceMask)) { + result |= mapper.markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); } - } + }); return result; } void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token) { - for (InputMapper* mapper : mMappers) { - mapper->vibrate(pattern, patternSize, repeat, token); - } + for_each_mapper([pattern, patternSize, repeat, token](InputMapper& mapper) { + mapper.vibrate(pattern, patternSize, repeat, token); + }); } void InputDevice::cancelVibrate(int32_t token) { - for (InputMapper* mapper : mMappers) { - mapper->cancelVibrate(token); - } + for_each_mapper([token](InputMapper& mapper) { mapper.cancelVibrate(token); }); } void InputDevice::cancelTouch(nsecs_t when) { - for (InputMapper* mapper : mMappers) { - mapper->cancelTouch(when); - } + for_each_mapper([when](InputMapper& mapper) { mapper.cancelTouch(when); }); } int32_t InputDevice::getMetaState() { int32_t result = 0; - for (InputMapper* mapper : mMappers) { - result |= mapper->getMetaState(); - } + for_each_mapper([&result](InputMapper& mapper) { result |= mapper.getMetaState(); }); return result; } void InputDevice::updateMetaState(int32_t keyCode) { - for (InputMapper* mapper : mMappers) { - mapper->updateMetaState(keyCode); - } + for_each_mapper([keyCode](InputMapper& mapper) { mapper.updateMetaState(keyCode); }); } void InputDevice::fadePointer() { - for (InputMapper* mapper : mMappers) { - mapper->fadePointer(); - } + for_each_mapper([](InputMapper& mapper) { mapper.fadePointer(); }); } void InputDevice::bumpGeneration() { @@ -367,14 +417,8 @@ std::optional InputDevice::getAssociatedDisplayId() { } // No associated display port, check if some InputMapper is associated. - for (InputMapper* mapper : mMappers) { - std::optional associatedDisplayId = mapper->getAssociatedDisplayId(); - if (associatedDisplayId) { - return associatedDisplayId; - } - } - - return std::nullopt; + return first_in_mappers( + [](InputMapper& mapper) { return mapper.getAssociatedDisplayId(); }); } } // namespace android diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 2023c6e8da..010729a6d3 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -18,33 +18,22 @@ #include "InputReader.h" -#include "CursorInputMapper.h" -#include "ExternalStylusInputMapper.h" -#include "InputReaderContext.h" -#include "JoystickInputMapper.h" -#include "KeyboardInputMapper.h" -#include "MultiTouchInputMapper.h" -#include "RotaryEncoderInputMapper.h" -#include "SingleTouchInputMapper.h" -#include "SwitchInputMapper.h" -#include "VibratorInputMapper.h" - +#include #include +#include +#include #include #include +#include #include #include #include #include - -#include #include - -#include -#include -#include #include +#include "InputDevice.h" + using android::base::StringPrintf; namespace android { @@ -261,74 +250,7 @@ InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controlle uint32_t classes) { InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), controllerNumber, identifier, classes); - - // External devices. - if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { - device->setExternal(true); - } - - // Devices with mics. - if (classes & INPUT_DEVICE_CLASS_MIC) { - device->setMic(true); - } - - // Switch-like devices. - if (classes & INPUT_DEVICE_CLASS_SWITCH) { - device->addMapper(new SwitchInputMapper(device)); - } - - // Scroll wheel-like devices. - if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) { - device->addMapper(new RotaryEncoderInputMapper(device)); - } - - // Vibrator-like devices. - if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { - device->addMapper(new VibratorInputMapper(device)); - } - - // Keyboard-like devices. - uint32_t keyboardSource = 0; - int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; - if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { - keyboardSource |= AINPUT_SOURCE_KEYBOARD; - } - if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { - keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; - } - if (classes & INPUT_DEVICE_CLASS_DPAD) { - keyboardSource |= AINPUT_SOURCE_DPAD; - } - if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { - keyboardSource |= AINPUT_SOURCE_GAMEPAD; - } - - if (keyboardSource != 0) { - device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); - } - - // Cursor-like devices. - if (classes & INPUT_DEVICE_CLASS_CURSOR) { - device->addMapper(new CursorInputMapper(device)); - } - - // Touchscreens and touchpad devices. - if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { - device->addMapper(new MultiTouchInputMapper(device)); - } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { - device->addMapper(new SingleTouchInputMapper(device)); - } - - // Joystick-like devices. - if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { - device->addMapper(new JoystickInputMapper(device)); - } - - // External stylus-like devices. - if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { - device->addMapper(new ExternalStylusInputMapper(device)); - } - + device->populateMappers(); return device; } diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 882407dd20..d06cc20719 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -67,7 +67,7 @@ public: void setEnabled(bool enabled, nsecs_t when); void dump(std::string& dump); - void addMapper(InputMapper* mapper); + void populateMappers(); void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); void reset(nsecs_t when); void process(const RawEvent* rawEvents, size_t count); @@ -116,6 +116,14 @@ public: std::optional getAssociatedDisplayId(); + // construct and add a mapper to the input device + template + T& addMapper(Args... args) { + T* mapper = new T(this, args...); + mMappers.emplace_back(mapper); + return *mapper; + } + private: InputReaderContext* mContext; int32_t mId; @@ -125,7 +133,7 @@ private: std::string mAlias; uint32_t mClasses; - std::vector mMappers; + std::vector> mMappers; uint32_t mSources; bool mIsExternal; @@ -138,6 +146,26 @@ private: int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); PropertyMap mConfiguration; + + // run a function against every mapper + inline void for_each_mapper(std::function f) { + for (auto& mapperPtr : mMappers) { + f(*mapperPtr); + } + } + + // return the first value returned by a function over every mapper. + // if all mappers return nullopt, return nullopt. + template + inline std::optional first_in_mappers(std::function(InputMapper&)> f) { + for (auto& mapperPtr : mMappers) { + std::optional ret = f(*mapperPtr); + if (ret) { + return ret; + } + } + return std::nullopt; + } }; } // namespace android diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 8ca7e4a893..7cd8793d5a 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1354,22 +1354,22 @@ protected: ASSERT_NO_FATAL_FAILURE(mFakeEventHub->assertQueueIsEmpty()); } - void disableDevice(int32_t deviceId, InputDevice* device) { + void disableDevice(int32_t deviceId) { mFakePolicy->addDisabledDevice(deviceId); mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_ENABLED_STATE); } - void enableDevice(int32_t deviceId, InputDevice* device) { + void enableDevice(int32_t deviceId) { mFakePolicy->removeDisabledDevice(deviceId); mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_ENABLED_STATE); } - FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber, - const std::string& name, uint32_t classes, uint32_t sources, - const PropertyMap* configuration) { + FakeInputMapper& addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber, + const std::string& name, uint32_t classes, + uint32_t sources, + const PropertyMap* configuration) { InputDevice* device = mReader->newDevice(deviceId, controllerNumber, name, classes); - FakeInputMapper* mapper = new FakeInputMapper(device, sources); - device->addMapper(mapper); + FakeInputMapper& mapper = device->addMapper(sources); mReader->setNextDevice(device); addDevice(deviceId, name, classes, configuration); return mapper; @@ -1406,8 +1406,7 @@ TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) { constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass); // Must add at least one mapper or the device will be ignored! - FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD); - device->addMapper(mapper); + device->addMapper(AINPUT_SOURCE_KEYBOARD); mReader->setNextDevice(device); ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr)); @@ -1418,20 +1417,20 @@ TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) { ASSERT_EQ(deviceId, resetArgs.deviceId); ASSERT_EQ(device->isEnabled(), true); - disableDevice(deviceId, device); + disableDevice(deviceId); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); ASSERT_EQ(deviceId, resetArgs.deviceId); ASSERT_EQ(device->isEnabled(), false); - disableDevice(deviceId, device); + disableDevice(deviceId); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasNotCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasNotCalled()); ASSERT_EQ(device->isEnabled(), false); - enableDevice(deviceId, device); + enableDevice(deviceId); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); ASSERT_EQ(deviceId, resetArgs.deviceId); @@ -1439,10 +1438,10 @@ TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) { } TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { - FakeInputMapper* mapper = nullptr; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake", - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr)); - mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); + FakeInputMapper& mapper = + addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD, + AINPUT_SOURCE_KEYBOARD, nullptr); + mapper.setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(0, AINPUT_SOURCE_ANY, AKEYCODE_A)) @@ -1466,10 +1465,10 @@ TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { } TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { - FakeInputMapper* mapper = nullptr; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake", - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr)); - mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN); + FakeInputMapper& mapper = + addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD, + AINPUT_SOURCE_KEYBOARD, nullptr); + mapper.setScanCodeState(KEY_A, AKEY_STATE_DOWN); ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(0, AINPUT_SOURCE_ANY, KEY_A)) @@ -1493,10 +1492,10 @@ TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { } TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { - FakeInputMapper* mapper = nullptr; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake", - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr)); - mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN); + FakeInputMapper& mapper = + addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD, + AINPUT_SOURCE_KEYBOARD, nullptr); + mapper.setSwitchState(SW_LID, AKEY_STATE_DOWN); ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(0, AINPUT_SOURCE_ANY, SW_LID)) @@ -1520,12 +1519,12 @@ TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { } TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { - FakeInputMapper* mapper = nullptr; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake", - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr)); + FakeInputMapper& mapper = + addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD, + AINPUT_SOURCE_KEYBOARD, nullptr); - mapper->addSupportedKeyCode(AKEYCODE_A); - mapper->addSupportedKeyCode(AKEYCODE_B); + mapper.addSupportedKeyCode(AKEYCODE_A); + mapper.addSupportedKeyCode(AKEYCODE_B); const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; uint8_t flags[4] = { 0, 0, 0, 1 }; @@ -1565,16 +1564,16 @@ TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChange } TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { - FakeInputMapper* mapper = nullptr; - ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, "fake", - INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr)); + FakeInputMapper& mapper = + addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD, + AINPUT_SOURCE_KEYBOARD, nullptr); mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, 1); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeEventHub->assertQueueIsEmpty()); RawEvent event; - ASSERT_NO_FATAL_FAILURE(mapper->assertProcessWasCalled(&event)); + ASSERT_NO_FATAL_FAILURE(mapper.assertProcessWasCalled(&event)); ASSERT_EQ(0, event.when); ASSERT_EQ(1, event.deviceId); ASSERT_EQ(EV_KEY, event.type); @@ -1587,8 +1586,7 @@ TEST_F(InputReaderTest, DeviceReset_IncrementsSequenceNumber) { constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass); // Must add at least one mapper or the device will be ignored! - FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD); - device->addMapper(mapper); + device->addMapper(AINPUT_SOURCE_KEYBOARD); mReader->setNextDevice(device); ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr)); @@ -1596,19 +1594,19 @@ TEST_F(InputReaderTest, DeviceReset_IncrementsSequenceNumber) { ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); uint32_t prevSequenceNum = resetArgs.sequenceNum; - disableDevice(deviceId, device); + disableDevice(deviceId); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum); prevSequenceNum = resetArgs.sequenceNum; - enableDevice(deviceId, device); + enableDevice(deviceId); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum); prevSequenceNum = resetArgs.sequenceNum; - disableDevice(deviceId, device); + disableDevice(deviceId); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum); @@ -1621,8 +1619,7 @@ TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { const char* DEVICE_LOCATION = "USB1"; InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass, DEVICE_LOCATION); - FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_TOUCHSCREEN); - device->addMapper(mapper); + FakeInputMapper& mapper = device->addMapper(AINPUT_SOURCE_TOUCHSCREEN); mReader->setNextDevice(device); const uint8_t hdmi1 = 1; @@ -1645,7 +1642,7 @@ TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled()); - ASSERT_NO_FATAL_FAILURE(mapper->assertConfigureWasCalled()); + ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled()); // Device should only dispatch to the specified display. ASSERT_EQ(deviceId, device->getId()); @@ -1653,14 +1650,13 @@ TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { ASSERT_TRUE(mReader->canDispatchToDisplay(deviceId, SECONDARY_DISPLAY_ID)); // Can't dispatch event from a disabled device. - disableDevice(deviceId, device); + disableDevice(deviceId); mReader->loopOnce(); ASSERT_FALSE(mReader->canDispatchToDisplay(deviceId, SECONDARY_DISPLAY_ID)); } // --- InputDeviceTest --- - class InputDeviceTest : public testing::Test { protected: static const char* DEVICE_NAME; @@ -1764,21 +1760,19 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe // Configuration. mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8("key"), String8("value")); - FakeInputMapper* mapper1 = new FakeInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD); - mapper1->setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC); - mapper1->setMetaState(AMETA_ALT_ON); - mapper1->addSupportedKeyCode(AKEYCODE_A); - mapper1->addSupportedKeyCode(AKEYCODE_B); - mapper1->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); - mapper1->setKeyCodeState(AKEYCODE_B, AKEY_STATE_UP); - mapper1->setScanCodeState(2, AKEY_STATE_DOWN); - mapper1->setScanCodeState(3, AKEY_STATE_UP); - mapper1->setSwitchState(4, AKEY_STATE_DOWN); - mDevice->addMapper(mapper1); - - FakeInputMapper* mapper2 = new FakeInputMapper(mDevice, AINPUT_SOURCE_TOUCHSCREEN); - mapper2->setMetaState(AMETA_SHIFT_ON); - mDevice->addMapper(mapper2); + FakeInputMapper& mapper1 = mDevice->addMapper(AINPUT_SOURCE_KEYBOARD); + mapper1.setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC); + mapper1.setMetaState(AMETA_ALT_ON); + mapper1.addSupportedKeyCode(AKEYCODE_A); + mapper1.addSupportedKeyCode(AKEYCODE_B); + mapper1.setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); + mapper1.setKeyCodeState(AKEYCODE_B, AKEY_STATE_UP); + mapper1.setScanCodeState(2, AKEY_STATE_DOWN); + mapper1.setScanCodeState(3, AKEY_STATE_UP); + mapper1.setSwitchState(4, AKEY_STATE_DOWN); + + FakeInputMapper& mapper2 = mDevice->addMapper(AINPUT_SOURCE_TOUCHSCREEN); + mapper2.setMetaState(AMETA_SHIFT_ON); InputReaderConfiguration config; mDevice->configure(ARBITRARY_TIME, &config, 0); @@ -1788,13 +1782,13 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe << "Device should have read configuration during configuration phase."; ASSERT_STREQ("value", propertyValue.string()); - ASSERT_NO_FATAL_FAILURE(mapper1->assertConfigureWasCalled()); - ASSERT_NO_FATAL_FAILURE(mapper2->assertConfigureWasCalled()); + ASSERT_NO_FATAL_FAILURE(mapper1.assertConfigureWasCalled()); + ASSERT_NO_FATAL_FAILURE(mapper2.assertConfigureWasCalled()); // Reset mDevice->reset(ARBITRARY_TIME); - ASSERT_NO_FATAL_FAILURE(mapper1->assertResetWasCalled()); - ASSERT_NO_FATAL_FAILURE(mapper2->assertResetWasCalled()); + ASSERT_NO_FATAL_FAILURE(mapper1.assertResetWasCalled()); + ASSERT_NO_FATAL_FAILURE(mapper2.assertResetWasCalled()); NotifyDeviceResetArgs resetArgs; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); @@ -1850,16 +1844,15 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe RawEvent event; mDevice->process(&event, 1); - ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled()); - ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled()); + ASSERT_NO_FATAL_FAILURE(mapper1.assertProcessWasCalled()); + ASSERT_NO_FATAL_FAILURE(mapper2.assertProcessWasCalled()); } // A single input device is associated with a specific display. Check that: // 1. Device is disabled if the viewport corresponding to the associated display is not found // 2. Device is disabled when setEnabled API is called TEST_F(InputDeviceTest, Configure_AssignsDisplayPort) { - FakeInputMapper* mapper = new FakeInputMapper(mDevice, AINPUT_SOURCE_TOUCHSCREEN); - mDevice->addMapper(mapper); + mDevice->addMapper(AINPUT_SOURCE_TOUCHSCREEN); // First Configuration. mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0); @@ -1944,10 +1937,12 @@ protected: mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes); } - void addMapperAndConfigure(InputMapper* mapper) { - mDevice->addMapper(mapper); + template + T& addMapperAndConfigure(Args... args) { + T& mapper = mDevice->addMapper(args...); configureDevice(0); mDevice->reset(ARBITRARY_TIME); + return mapper; } void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height, @@ -1962,15 +1957,15 @@ protected: mFakePolicy->clearViewports(); } - static void process(InputMapper* mapper, nsecs_t when, int32_t type, - int32_t code, int32_t value) { + static void process(InputMapper& mapper, nsecs_t when, int32_t type, int32_t code, + int32_t value) { RawEvent event; event.when = when; - event.deviceId = mapper->getDeviceId(); + event.deviceId = mapper.getDeviceId(); event.type = type; event.code = code; event.value = value; - mapper->process(&event); + mapper.process(&event); } static void assertMotionRange(const InputDeviceInfo& info, @@ -2024,26 +2019,23 @@ protected: }; TEST_F(SwitchInputMapperTest, GetSources) { - SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); - addMapperAndConfigure(mapper); + SwitchInputMapper& mapper = addMapperAndConfigure(); - ASSERT_EQ(uint32_t(AINPUT_SOURCE_SWITCH), mapper->getSources()); + ASSERT_EQ(uint32_t(AINPUT_SOURCE_SWITCH), mapper.getSources()); } TEST_F(SwitchInputMapperTest, GetSwitchState) { - SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); - addMapperAndConfigure(mapper); + SwitchInputMapper& mapper = addMapperAndConfigure(); mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 1); - ASSERT_EQ(1, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); + ASSERT_EQ(1, mapper.getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 0); - ASSERT_EQ(0, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); + ASSERT_EQ(0, mapper.getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); } TEST_F(SwitchInputMapperTest, Process) { - SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); - addMapperAndConfigure(mapper); + SwitchInputMapper& mapper = addMapperAndConfigure(); process(mapper, ARBITRARY_TIME, EV_SW, SW_LID, 1); process(mapper, ARBITRARY_TIME, EV_SW, SW_JACK_PHYSICAL_INSERT, 1); @@ -2068,7 +2060,7 @@ protected: void prepareDisplay(int32_t orientation); - void testDPadKeyRotation(KeyboardInputMapper* mapper, int32_t originalScanCode, + void testDPadKeyRotation(KeyboardInputMapper& mapper, int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode, int32_t displayId = ADISPLAY_ID_NONE); }; @@ -2081,7 +2073,7 @@ void KeyboardInputMapperTest::prepareDisplay(int32_t orientation) { orientation, UNIQUE_ID, NO_PORT, ViewportType::VIEWPORT_INTERNAL); } -void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper, +void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper& mapper, int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode, int32_t displayId) { NotifyKeyArgs args; @@ -2102,11 +2094,11 @@ void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper, } TEST_F(KeyboardInputMapperTest, GetSources) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper->getSources()); + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper.getSources()); } TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { @@ -2115,9 +2107,9 @@ TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); mFakeEventHub->addKey(DEVICE_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE); - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); // Key down by scan code. process(mapper, ARBITRARY_TIME, EV_KEY, KEY_HOME, 1); @@ -2213,38 +2205,38 @@ TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) { mFakeEventHub->addKey(DEVICE_ID, KEY_LEFTSHIFT, 0, AKEYCODE_SHIFT_LEFT, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0); - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); // Initial metastate. - ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); + ASSERT_EQ(AMETA_NONE, mapper.getMetaState()); // Metakey down. process(mapper, ARBITRARY_TIME, EV_KEY, KEY_LEFTSHIFT, 1); NotifyKeyArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper.getMetaState()); ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled()); // Key down. process(mapper, ARBITRARY_TIME + 1, EV_KEY, KEY_A, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper.getMetaState()); // Key up. process(mapper, ARBITRARY_TIME + 2, EV_KEY, KEY_A, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); + ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper.getMetaState()); // Metakey up. process(mapper, ARBITRARY_TIME + 3, EV_KEY, KEY_LEFTSHIFT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AMETA_NONE, args.metaState); - ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); + ASSERT_EQ(AMETA_NONE, mapper.getMetaState()); ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled()); } @@ -2254,9 +2246,9 @@ TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateD mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); prepareDisplay(DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, @@ -2275,10 +2267,10 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addConfigurationProperty("keyboard.orientationAware", "1"); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); prepareDisplay(DISPLAY_ORIENTATION_0); ASSERT_NO_FATAL_FAILURE( @@ -2348,9 +2340,9 @@ TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_NotOrientationAware // key events should not be associated with a specific display id mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); NotifyKeyArgs args; // Display id should be ADISPLAY_ID_NONE without any display configuration. @@ -2373,10 +2365,10 @@ TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_OrientationAware) { // key events should be associated with the internal viewport mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addConfigurationProperty("keyboard.orientationAware", "1"); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); NotifyKeyArgs args; // Display id should be ADISPLAY_ID_NONE without any display configuration. @@ -2402,39 +2394,39 @@ TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_OrientationAware) { } TEST_F(KeyboardInputMapperTest, GetKeyCodeState) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 1); - ASSERT_EQ(1, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); + ASSERT_EQ(1, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 0); - ASSERT_EQ(0, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); + ASSERT_EQ(0, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); } TEST_F(KeyboardInputMapperTest, GetScanCodeState) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 1); - ASSERT_EQ(1, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); + ASSERT_EQ(1, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 0); - ASSERT_EQ(0, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); + ASSERT_EQ(0, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); } TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0); const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; uint8_t flags[2] = { 0, 0 }; - ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 1, keyCodes, flags)); + ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, 1, keyCodes, flags)); ASSERT_TRUE(flags[0]); ASSERT_FALSE(flags[1]); } @@ -2447,9 +2439,9 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) mFakeEventHub->addKey(DEVICE_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0); - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); // Initialization should have turned all of the lights off. ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); @@ -2462,7 +2454,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper->getMetaState()); + ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState()); // Toggle num lock on. process(mapper, ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 1); @@ -2470,7 +2462,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper->getMetaState()); + ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper.getMetaState()); // Toggle caps lock off. process(mapper, ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 1); @@ -2478,7 +2470,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper->getMetaState()); + ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState()); // Toggle scroll lock on. process(mapper, ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 1); @@ -2486,7 +2478,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper->getMetaState()); + ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper.getMetaState()); // Toggle num lock off. process(mapper, ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 1); @@ -2494,7 +2486,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper->getMetaState()); + ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper.getMetaState()); // Toggle scroll lock off. process(mapper, ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 1); @@ -2502,7 +2494,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); - ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); + ASSERT_EQ(AMETA_NONE, mapper.getMetaState()); } TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) { @@ -2527,13 +2519,13 @@ TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) { mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, - AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); - KeyboardInputMapper* mapper2 = new KeyboardInputMapper(device2.get(), AINPUT_SOURCE_KEYBOARD, - AINPUT_KEYBOARD_TYPE_ALPHABETIC); - device2->addMapper(mapper2); + KeyboardInputMapper& mapper2 = + device2->addMapper(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/); device2->reset(ARBITRARY_TIME); @@ -2593,9 +2585,9 @@ TEST_F(KeyboardInputMapperTest, ExternalDevice_WakeBehavior) { mFakeEventHub->addKey(DEVICE_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE, POLICY_FLAG_WAKE); - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, - AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); process(mapper, ARBITRARY_TIME, EV_KEY, KEY_HOME, 1); NotifyKeyArgs args; @@ -2631,10 +2623,10 @@ TEST_F(KeyboardInputMapperTest, ExternalDevice_DoNotWakeByDefaultBehavior) { mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, POLICY_FLAG_WAKE); - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, - AINPUT_KEYBOARD_TYPE_ALPHABETIC); addConfigurationProperty("keyboard.doNotWakeByDefault", "1"); - addMapperAndConfigure(mapper); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); process(mapper, ARBITRARY_TIME, EV_KEY, KEY_HOME, 1); NotifyKeyArgs args; @@ -2677,8 +2669,8 @@ protected: mFakePolicy->setPointerController(mDevice->getId(), mFakePointerController); } - void testMotionRotation(CursorInputMapper* mapper, - int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY); + void testMotionRotation(CursorInputMapper& mapper, int32_t originalX, int32_t originalY, + int32_t rotatedX, int32_t rotatedY); void prepareDisplay(int32_t orientation) { const std::string uniqueId = "local:0"; @@ -2690,8 +2682,9 @@ protected: const int32_t CursorInputMapperTest::TRACKBALL_MOVEMENT_THRESHOLD = 6; -void CursorInputMapperTest::testMotionRotation(CursorInputMapper* mapper, - int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY) { +void CursorInputMapperTest::testMotionRotation(CursorInputMapper& mapper, int32_t originalX, + int32_t originalY, int32_t rotatedX, + int32_t rotatedY) { NotifyMotionArgs args; process(mapper, ARBITRARY_TIME, EV_REL, REL_X, originalX); @@ -2706,28 +2699,25 @@ void CursorInputMapperTest::testMotionRotation(CursorInputMapper* mapper, } TEST_F(CursorInputMapperTest, WhenModeIsPointer_GetSources_ReturnsMouse) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "pointer"); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); - ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources()); + ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources()); } TEST_F(CursorInputMapperTest, WhenModeIsNavigation_GetSources_ReturnsTrackball) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); - ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper->getSources()); + ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper.getSources()); } TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeFromPointerController) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "pointer"); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); InputDeviceInfo info; - mapper->populateDeviceInfo(&info); + mapper.populateDeviceInfo(&info); // Initially there may not be a valid motion range. ASSERT_EQ(nullptr, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE)); @@ -2739,7 +2729,7 @@ TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeF mFakePointerController->setBounds(1, 2, 800 - 1, 480 - 1); InputDeviceInfo info2; - mapper->populateDeviceInfo(&info2); + mapper.populateDeviceInfo(&info2); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE, @@ -2753,12 +2743,11 @@ TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeF } TEST_F(CursorInputMapperTest, WhenModeIsNavigation_PopulateDeviceInfo_ReturnsScaledRange) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); InputDeviceInfo info; - mapper->populateDeviceInfo(&info); + mapper.populateDeviceInfo(&info); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_TRACKBALL, @@ -2772,9 +2761,8 @@ TEST_F(CursorInputMapperTest, WhenModeIsNavigation_PopulateDeviceInfo_ReturnsSca } TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -2865,9 +2853,8 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat } TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs args; @@ -2889,9 +2876,8 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { } TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs args; @@ -2923,9 +2909,8 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { } TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs args; @@ -2971,9 +2956,8 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { } TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); prepareDisplay(DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); @@ -2987,10 +2971,9 @@ TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMot } TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addConfigurationProperty("cursor.orientationAware", "1"); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); prepareDisplay(DISPLAY_ORIENTATION_0); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); @@ -3034,9 +3017,8 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) } TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "pointer"); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1); mFakePointerController->setPosition(100, 200); @@ -3322,9 +3304,8 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { } TEST_F(CursorInputMapperTest, Process_WhenModeIsPointer_ShouldMoveThePointerAround) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "pointer"); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1); mFakePointerController->setPosition(100, 200); @@ -3344,10 +3325,9 @@ TEST_F(CursorInputMapperTest, Process_WhenModeIsPointer_ShouldMoveThePointerArou } TEST_F(CursorInputMapperTest, Process_PointerCapture) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "pointer"); mFakePolicy->setPointerCapture(true); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); NotifyDeviceResetArgs resetArgs; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); @@ -3433,8 +3413,7 @@ TEST_F(CursorInputMapperTest, Process_PointerCapture) { } TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addMapperAndConfigure(mapper); + CursorInputMapper& mapper = addMapperAndConfigure(); // Setup for second display. constexpr int32_t SECOND_DISPLAY_ID = 1; @@ -3462,7 +3441,6 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) { ASSERT_EQ(SECOND_DISPLAY_ID, args.displayId); } - // --- TouchInputMapperTest --- class TouchInputMapperTest : public InputMapperTest { @@ -3637,15 +3615,15 @@ protected: void prepareButtons(); void prepareAxes(int axes); - void processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y); - void processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y); - void processUp(SingleTouchInputMapper* mappery); - void processPressure(SingleTouchInputMapper* mapper, int32_t pressure); - void processToolMajor(SingleTouchInputMapper* mapper, int32_t toolMajor); - void processDistance(SingleTouchInputMapper* mapper, int32_t distance); - void processTilt(SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY); - void processKey(SingleTouchInputMapper* mapper, int32_t code, int32_t value); - void processSync(SingleTouchInputMapper* mapper); + void processDown(SingleTouchInputMapper& mapper, int32_t x, int32_t y); + void processMove(SingleTouchInputMapper& mapper, int32_t x, int32_t y); + void processUp(SingleTouchInputMapper& mappery); + void processPressure(SingleTouchInputMapper& mapper, int32_t pressure); + void processToolMajor(SingleTouchInputMapper& mapper, int32_t toolMajor); + void processDistance(SingleTouchInputMapper& mapper, int32_t distance); + void processTilt(SingleTouchInputMapper& mapper, int32_t tiltX, int32_t tiltY); + void processKey(SingleTouchInputMapper& mapper, int32_t code, int32_t value); + void processSync(SingleTouchInputMapper& mapper); }; void SingleTouchInputMapperTest::prepareButtons() { @@ -3679,103 +3657,95 @@ void SingleTouchInputMapperTest::prepareAxes(int axes) { } } -void SingleTouchInputMapperTest::processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y) { +void SingleTouchInputMapperTest::processDown(SingleTouchInputMapper& mapper, int32_t x, int32_t y) { process(mapper, ARBITRARY_TIME, EV_KEY, BTN_TOUCH, 1); process(mapper, ARBITRARY_TIME, EV_ABS, ABS_X, x); process(mapper, ARBITRARY_TIME, EV_ABS, ABS_Y, y); } -void SingleTouchInputMapperTest::processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y) { +void SingleTouchInputMapperTest::processMove(SingleTouchInputMapper& mapper, int32_t x, int32_t y) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_X, x); process(mapper, ARBITRARY_TIME, EV_ABS, ABS_Y, y); } -void SingleTouchInputMapperTest::processUp(SingleTouchInputMapper* mapper) { +void SingleTouchInputMapperTest::processUp(SingleTouchInputMapper& mapper) { process(mapper, ARBITRARY_TIME, EV_KEY, BTN_TOUCH, 0); } -void SingleTouchInputMapperTest::processPressure( - SingleTouchInputMapper* mapper, int32_t pressure) { +void SingleTouchInputMapperTest::processPressure(SingleTouchInputMapper& mapper, int32_t pressure) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_PRESSURE, pressure); } -void SingleTouchInputMapperTest::processToolMajor( - SingleTouchInputMapper* mapper, int32_t toolMajor) { +void SingleTouchInputMapperTest::processToolMajor(SingleTouchInputMapper& mapper, + int32_t toolMajor) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_TOOL_WIDTH, toolMajor); } -void SingleTouchInputMapperTest::processDistance( - SingleTouchInputMapper* mapper, int32_t distance) { +void SingleTouchInputMapperTest::processDistance(SingleTouchInputMapper& mapper, int32_t distance) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_DISTANCE, distance); } -void SingleTouchInputMapperTest::processTilt( - SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY) { +void SingleTouchInputMapperTest::processTilt(SingleTouchInputMapper& mapper, int32_t tiltX, + int32_t tiltY) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_TILT_X, tiltX); process(mapper, ARBITRARY_TIME, EV_ABS, ABS_TILT_Y, tiltY); } -void SingleTouchInputMapperTest::processKey( - SingleTouchInputMapper* mapper, int32_t code, int32_t value) { +void SingleTouchInputMapperTest::processKey(SingleTouchInputMapper& mapper, int32_t code, + int32_t value) { process(mapper, ARBITRARY_TIME, EV_KEY, code, value); } -void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) { +void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper& mapper) { process(mapper, ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); } - TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareButtons(); prepareAxes(POSITION); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); - ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources()); + ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources()); } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_X); mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_Y); prepareButtons(); prepareAxes(POSITION); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); - ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); + ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources()); } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTouchPad) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareButtons(); prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchPad"); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); - ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); + ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources()); } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_ReturnsTouchScreen) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareButtons(); prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources()); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources()); } TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); // Unknown key. - ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); + ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); // Virtual key is down. int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); @@ -3784,27 +3754,26 @@ TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); + ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); // Virtual key is up. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - ASSERT_EQ(AKEY_STATE_UP, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); + ASSERT_EQ(AKEY_STATE_UP, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); } TEST_F(SingleTouchInputMapperTest, GetScanCodeState) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); // Unknown key. - ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); + ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); // Virtual key is down. int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); @@ -3813,40 +3782,38 @@ TEST_F(SingleTouchInputMapperTest, GetScanCodeState) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); + ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); // Virtual key is up. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - ASSERT_EQ(AKEY_STATE_UP, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); + ASSERT_EQ(AKEY_STATE_UP, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); } TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); const int32_t keys[2] = { AKEYCODE_HOME, AKEYCODE_A }; uint8_t flags[2] = { 0, 0 }; - ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 2, keys, flags)); + ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, 2, keys, flags)); ASSERT_TRUE(flags[0]); ASSERT_FALSE(flags[1]); } TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -3891,13 +3858,12 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNor } TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -4013,13 +3979,12 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfB } TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -4087,7 +4052,6 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMoves } TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture_VirtualDisplay) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); addConfigurationProperty("touch.displayId", VIRTUAL_DISPLAY_UNIQUE_ID); @@ -4095,7 +4059,7 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture_VirtualDispl prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -4186,13 +4150,12 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture_VirtualDispl } TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -4277,12 +4240,11 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { } TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareButtons(); prepareAxes(POSITION); addConfigurationProperty("touch.orientationAware", "0"); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs args; @@ -4301,11 +4263,10 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotate } TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareButtons(); prepareAxes(POSITION); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs args; @@ -4367,12 +4328,11 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) } TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE | TOOL | DISTANCE | TILT); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; @@ -4412,13 +4372,12 @@ TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { } TEST_F(SingleTouchInputMapperTest, Process_XYAxes_AffineCalibration) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareLocationCalibration(); prepareButtons(); prepareAxes(POSITION); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); int32_t rawX = 100; int32_t rawY = 200; @@ -4436,12 +4395,11 @@ TEST_F(SingleTouchInputMapperTest, Process_XYAxes_AffineCalibration) { } TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllButtons) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs motionArgs; NotifyKeyArgs keyArgs; @@ -4680,12 +4638,11 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllButtons) { } TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs motionArgs; @@ -4816,13 +4773,12 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { } TEST_F(SingleTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); mFakeEventHub->addKey(DEVICE_ID, BTN_TOOL_FINGER, 0, AKEYCODE_UNKNOWN, 0); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs motionArgs; @@ -4889,12 +4845,11 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueI } TEST_F(SingleTouchInputMapperTest, Process_WhenAbsPressureIsPresent_HoversIfItsValueIsZero) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE); - addMapperAndConfigure(mapper); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs motionArgs; @@ -4960,27 +4915,26 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenAbsPressureIsPresent_HoversIfItsV toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } - // --- MultiTouchInputMapperTest --- class MultiTouchInputMapperTest : public TouchInputMapperTest { protected: void prepareAxes(int axes); - void processPosition(MultiTouchInputMapper* mapper, int32_t x, int32_t y); - void processTouchMajor(MultiTouchInputMapper* mapper, int32_t touchMajor); - void processTouchMinor(MultiTouchInputMapper* mapper, int32_t touchMinor); - void processToolMajor(MultiTouchInputMapper* mapper, int32_t toolMajor); - void processToolMinor(MultiTouchInputMapper* mapper, int32_t toolMinor); - void processOrientation(MultiTouchInputMapper* mapper, int32_t orientation); - void processPressure(MultiTouchInputMapper* mapper, int32_t pressure); - void processDistance(MultiTouchInputMapper* mapper, int32_t distance); - void processId(MultiTouchInputMapper* mapper, int32_t id); - void processSlot(MultiTouchInputMapper* mapper, int32_t slot); - void processToolType(MultiTouchInputMapper* mapper, int32_t toolType); - void processKey(MultiTouchInputMapper* mapper, int32_t code, int32_t value); - void processMTSync(MultiTouchInputMapper* mapper); - void processSync(MultiTouchInputMapper* mapper); + void processPosition(MultiTouchInputMapper& mapper, int32_t x, int32_t y); + void processTouchMajor(MultiTouchInputMapper& mapper, int32_t touchMajor); + void processTouchMinor(MultiTouchInputMapper& mapper, int32_t touchMinor); + void processToolMajor(MultiTouchInputMapper& mapper, int32_t toolMajor); + void processToolMinor(MultiTouchInputMapper& mapper, int32_t toolMinor); + void processOrientation(MultiTouchInputMapper& mapper, int32_t orientation); + void processPressure(MultiTouchInputMapper& mapper, int32_t pressure); + void processDistance(MultiTouchInputMapper& mapper, int32_t distance); + void processId(MultiTouchInputMapper& mapper, int32_t id); + void processSlot(MultiTouchInputMapper& mapper, int32_t slot); + void processToolType(MultiTouchInputMapper& mapper, int32_t toolType); + void processKey(MultiTouchInputMapper& mapper, int32_t code, int32_t value); + void processMTSync(MultiTouchInputMapper& mapper); + void processSync(MultiTouchInputMapper& mapper); }; void MultiTouchInputMapperTest::prepareAxes(int axes) { @@ -5033,83 +4987,74 @@ void MultiTouchInputMapperTest::prepareAxes(int axes) { } } -void MultiTouchInputMapperTest::processPosition( - MultiTouchInputMapper* mapper, int32_t x, int32_t y) { +void MultiTouchInputMapperTest::processPosition(MultiTouchInputMapper& mapper, int32_t x, + int32_t y) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_X, x); process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_Y, y); } -void MultiTouchInputMapperTest::processTouchMajor( - MultiTouchInputMapper* mapper, int32_t touchMajor) { +void MultiTouchInputMapperTest::processTouchMajor(MultiTouchInputMapper& mapper, + int32_t touchMajor) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_TOUCH_MAJOR, touchMajor); } -void MultiTouchInputMapperTest::processTouchMinor( - MultiTouchInputMapper* mapper, int32_t touchMinor) { +void MultiTouchInputMapperTest::processTouchMinor(MultiTouchInputMapper& mapper, + int32_t touchMinor) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_TOUCH_MINOR, touchMinor); } -void MultiTouchInputMapperTest::processToolMajor( - MultiTouchInputMapper* mapper, int32_t toolMajor) { +void MultiTouchInputMapperTest::processToolMajor(MultiTouchInputMapper& mapper, int32_t toolMajor) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_WIDTH_MAJOR, toolMajor); } -void MultiTouchInputMapperTest::processToolMinor( - MultiTouchInputMapper* mapper, int32_t toolMinor) { +void MultiTouchInputMapperTest::processToolMinor(MultiTouchInputMapper& mapper, int32_t toolMinor) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_WIDTH_MINOR, toolMinor); } -void MultiTouchInputMapperTest::processOrientation( - MultiTouchInputMapper* mapper, int32_t orientation) { +void MultiTouchInputMapperTest::processOrientation(MultiTouchInputMapper& mapper, + int32_t orientation) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_ORIENTATION, orientation); } -void MultiTouchInputMapperTest::processPressure( - MultiTouchInputMapper* mapper, int32_t pressure) { +void MultiTouchInputMapperTest::processPressure(MultiTouchInputMapper& mapper, int32_t pressure) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_PRESSURE, pressure); } -void MultiTouchInputMapperTest::processDistance( - MultiTouchInputMapper* mapper, int32_t distance) { +void MultiTouchInputMapperTest::processDistance(MultiTouchInputMapper& mapper, int32_t distance) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_DISTANCE, distance); } -void MultiTouchInputMapperTest::processId( - MultiTouchInputMapper* mapper, int32_t id) { +void MultiTouchInputMapperTest::processId(MultiTouchInputMapper& mapper, int32_t id) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_TRACKING_ID, id); } -void MultiTouchInputMapperTest::processSlot( - MultiTouchInputMapper* mapper, int32_t slot) { +void MultiTouchInputMapperTest::processSlot(MultiTouchInputMapper& mapper, int32_t slot) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_SLOT, slot); } -void MultiTouchInputMapperTest::processToolType( - MultiTouchInputMapper* mapper, int32_t toolType) { +void MultiTouchInputMapperTest::processToolType(MultiTouchInputMapper& mapper, int32_t toolType) { process(mapper, ARBITRARY_TIME, EV_ABS, ABS_MT_TOOL_TYPE, toolType); } -void MultiTouchInputMapperTest::processKey( - MultiTouchInputMapper* mapper, int32_t code, int32_t value) { +void MultiTouchInputMapperTest::processKey(MultiTouchInputMapper& mapper, int32_t code, + int32_t value) { process(mapper, ARBITRARY_TIME, EV_KEY, code, value); } -void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper* mapper) { +void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper& mapper) { process(mapper, ARBITRARY_TIME, EV_SYN, SYN_MT_REPORT, 0); } -void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper* mapper) { +void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper& mapper) { process(mapper, ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); } - TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -5381,12 +5326,11 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin } TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID); prepareVirtualKeys(); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -5557,12 +5501,11 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId } TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT); prepareVirtualKeys(); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -5728,11 +5671,10 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { } TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR | DISTANCE); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; @@ -5778,12 +5720,11 @@ TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) { } TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | TOUCH | TOOL | MINOR); addConfigurationProperty("touch.size.calibration", "geometric"); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; @@ -5816,7 +5757,6 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) } TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_SummedLinearCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | TOUCH | TOOL); @@ -5824,7 +5764,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_SummedLinearCalibrati addConfigurationProperty("touch.size.scale", "10"); addConfigurationProperty("touch.size.bias", "160"); addConfigurationProperty("touch.size.isSummed", "1"); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); // These calculations are based on the input device calibration documentation. // Note: We only provide a single common touch/tool value because the device is assumed @@ -5869,14 +5809,13 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_SummedLinearCalibrati } TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_AreaCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | TOUCH | TOOL); addConfigurationProperty("touch.size.calibration", "area"); addConfigurationProperty("touch.size.scale", "43"); addConfigurationProperty("touch.size.bias", "3"); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; @@ -5903,16 +5842,15 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_AreaCalibration) { } TEST_F(MultiTouchInputMapperTest, Process_PressureAxis_AmplitudeCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | PRESSURE); addConfigurationProperty("touch.pressure.calibration", "amplitude"); addConfigurationProperty("touch.pressure.scale", "0.01"); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); InputDeviceInfo info; - mapper->populateDeviceInfo(&info); + mapper.populateDeviceInfo(&info); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_TOUCHSCREEN, 0.0f, RAW_PRESSURE_MAX * 0.01, 0.0f, 0.0f)); @@ -5938,11 +5876,10 @@ TEST_F(MultiTouchInputMapperTest, Process_PressureAxis_AmplitudeCalibration) { } TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllButtons) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs motionArgs; NotifyKeyArgs keyArgs; @@ -6182,11 +6119,10 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllButtons) { } TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs motionArgs; @@ -6333,12 +6269,11 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { } TEST_F(MultiTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT); mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs motionArgs; @@ -6405,11 +6340,10 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIs } TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTPressureIsPresent_HoversIfItsValueIsZero) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs motionArgs; @@ -6482,7 +6416,6 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTPressureIsPresent_HoversIfIts * This can be checked by looking at the displayId of the resulting NotifyMotionArgs. */ TEST_F(MultiTouchInputMapperTest, Configure_AssignsDisplayPort) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); const std::string usb2 = "USB2"; const uint8_t hdmi1 = 0; const uint8_t hdmi2 = 1; @@ -6491,7 +6424,7 @@ TEST_F(MultiTouchInputMapperTest, Configure_AssignsDisplayPort) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareAxes(POSITION); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi1); mFakePolicy->addInputPortAssociation(usb2, hdmi2); @@ -6522,14 +6455,13 @@ TEST_F(MultiTouchInputMapperTest, Configure_AssignsDisplayPort) { * Expect fallback to internal viewport if device is external and external viewport is not present. */ TEST_F(MultiTouchInputMapperTest, Viewports_Fallback) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); mDevice->setExternal(true); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources()); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources()); NotifyMotionArgs motionArgs; @@ -6559,13 +6491,12 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) { mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID); prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL); - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); // Check source is mouse that would obtain the PointerController. - ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources()); + ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources()); NotifyMotionArgs motionArgs; processPosition(mapper, 100, 100); @@ -6578,10 +6509,9 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) { TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) { // Setup the first touch screen device. - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); prepareAxes(POSITION | ID | SLOT); addConfigurationProperty("touch.deviceType", "touchScreen"); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); // Create the second touch screen device, and enable multi fingers. const std::string USB2 = "USB2"; @@ -6606,8 +6536,7 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) { String8("touchScreen")); // Setup the second touch screen device. - MultiTouchInputMapper* mapper2 = new MultiTouchInputMapper(device2.get()); - device2->addMapper(mapper2); + MultiTouchInputMapper& mapper2 = device2->addMapper(); device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/); device2->reset(ARBITRARY_TIME); @@ -6659,11 +6588,10 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) { } TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs motionArgs; // Unrotated video frame @@ -6685,10 +6613,9 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) { } TEST_F(MultiTouchInputMapperTest, VideoFrames_AreRotated) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); // Unrotated video frame TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2}); NotifyMotionArgs motionArgs; @@ -6710,10 +6637,9 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_AreRotated) { } TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreRotated) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); // Unrotated video frames. There's no rule that they must all have the same dimensions, // so mix these. TouchVideoFrame frame1(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2}); @@ -6737,7 +6663,6 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreRotated) { * expected to be disabled, and it should be enabled after the viewport has found. */ TEST_F(MultiTouchInputMapperTest, Configure_EnabledForAssociatedDisplay) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); constexpr uint8_t hdmi2 = 1; const std::string secondaryUniqueId = "uniqueId2"; constexpr ViewportType type = ViewportType::VIEWPORT_EXTERNAL; @@ -6746,7 +6671,7 @@ TEST_F(MultiTouchInputMapperTest, Configure_EnabledForAssociatedDisplay) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareAxes(POSITION); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); ASSERT_EQ(mDevice->isEnabled(), false); @@ -6767,11 +6692,10 @@ TEST_F(MultiTouchInputMapperTest, Configure_EnabledForAssociatedDisplay) { * Test touch should not work if outside of surface. */ TEST_F(MultiTouchInputMapperTest, Viewports_SurfaceRange) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); // Touch on left-top area should work. int32_t rawX = DISPLAY_WIDTH / 2 - 1; @@ -6783,7 +6707,7 @@ TEST_F(MultiTouchInputMapperTest, Viewports_SurfaceRange) { ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); // Reset. - mapper->reset(ARBITRARY_TIME); + mapper.reset(ARBITRARY_TIME); // Let logical display be different to physical display and rotate 90-degrees. std::optional internalViewport = @@ -6811,11 +6735,10 @@ TEST_F(MultiTouchInputMapperTest, Viewports_SurfaceRange) { } TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs motionArgs; @@ -6857,11 +6780,10 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) { * UP events should be ignored. */ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); - addMapperAndConfigure(mapper); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs motionArgs; -- GitLab From 26ec22263d16538483cdc963e828f2bcf21a877e Mon Sep 17 00:00:00 2001 From: "Nathaniel R. Lewis" Date: Fri, 10 Jan 2020 16:30:54 -0800 Subject: [PATCH 0798/1255] Refactor use of services in InputMappers. Create InputDeviceContext class to hide direct EventHub and InputDevice accesses from InputMappers. Test: atest inputflinger_tests libinput_tests Change-Id: I05f9c808fc1a6f4c9207bd29fde50b76ec5655bb --- services/inputflinger/reader/InputDevice.cpp | 41 ++++-- services/inputflinger/reader/InputReader.cpp | 14 +- .../inputflinger/reader/include/InputDevice.h | 131 +++++++++++++++--- .../inputflinger/reader/include/InputReader.h | 6 +- .../reader/include/InputReaderContext.h | 3 +- .../reader/mapper/CursorInputMapper.cpp | 46 +++--- .../reader/mapper/CursorInputMapper.h | 4 +- .../mapper/ExternalStylusInputMapper.cpp | 12 +- .../reader/mapper/ExternalStylusInputMapper.h | 2 +- .../reader/mapper/InputMapper.cpp | 6 +- .../inputflinger/reader/mapper/InputMapper.h | 18 ++- .../reader/mapper/JoystickInputMapper.cpp | 12 +- .../reader/mapper/JoystickInputMapper.h | 2 +- .../reader/mapper/KeyboardInputMapper.cpp | 38 ++--- .../reader/mapper/KeyboardInputMapper.h | 2 +- .../reader/mapper/MultiTouchInputMapper.cpp | 19 +-- .../reader/mapper/MultiTouchInputMapper.h | 6 +- .../mapper/RotaryEncoderInputMapper.cpp | 24 ++-- .../reader/mapper/RotaryEncoderInputMapper.h | 2 +- .../reader/mapper/SingleTouchInputMapper.cpp | 5 +- .../reader/mapper/SingleTouchInputMapper.h | 2 +- .../reader/mapper/SwitchInputMapper.cpp | 8 +- .../reader/mapper/SwitchInputMapper.h | 2 +- .../reader/mapper/TouchInputMapper.cpp | 104 +++++++------- .../reader/mapper/TouchInputMapper.h | 2 +- .../reader/mapper/VibratorInputMapper.cpp | 10 +- .../reader/mapper/VibratorInputMapper.h | 2 +- .../accumulator/CursorButtonAccumulator.cpp | 18 +-- .../accumulator/CursorButtonAccumulator.h | 4 +- .../accumulator/CursorScrollAccumulator.cpp | 8 +- .../accumulator/CursorScrollAccumulator.h | 6 +- .../SingleTouchMotionAccumulator.cpp | 16 +-- .../SingleTouchMotionAccumulator.h | 4 +- .../accumulator/TouchButtonAccumulator.cpp | 42 +++--- .../accumulator/TouchButtonAccumulator.h | 6 +- .../inputflinger/tests/InputReader_test.cpp | 18 +-- 36 files changed, 377 insertions(+), 268 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 1c08ab1ed2..ae82cd4aa4 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -43,12 +43,14 @@ InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t genera mSources(0), mIsExternal(false), mHasMic(false), - mDropUntilNextSync(false) {} + mDropUntilNextSync(false) { + mDeviceContext = std::make_unique(*this); +} InputDevice::~InputDevice() {} bool InputDevice::isEnabled() { - return getEventHub()->isDeviceEnabled(mId); + return mDeviceContext->isDeviceEnabled(); } void InputDevice::setEnabled(bool enabled, nsecs_t when) { @@ -64,11 +66,11 @@ void InputDevice::setEnabled(bool enabled, nsecs_t when) { } if (enabled) { - getEventHub()->enableDevice(mId); + mDeviceContext->enableDevice(); reset(when); } else { reset(when); - getEventHub()->disableDevice(mId); + mDeviceContext->disableDevice(); } // Must change generation to flag this device as changed bumpGeneration(); @@ -119,6 +121,7 @@ void InputDevice::dump(std::string& dump) { void InputDevice::populateMappers() { uint32_t classes = mClasses; std::vector>& mappers = mMappers; + std::unique_ptr& contextPtr = mDeviceContext; // External devices. if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { @@ -132,17 +135,17 @@ void InputDevice::populateMappers() { // Switch-like devices. if (classes & INPUT_DEVICE_CLASS_SWITCH) { - mappers.push_back(std::make_unique(this)); + mappers.push_back(std::make_unique(*contextPtr)); } // Scroll wheel-like devices. if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) { - mappers.push_back(std::make_unique(this)); + mappers.push_back(std::make_unique(*contextPtr)); } // Vibrator-like devices. if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { - mappers.push_back(std::make_unique(this)); + mappers.push_back(std::make_unique(*contextPtr)); } // Keyboard-like devices. @@ -163,29 +166,29 @@ void InputDevice::populateMappers() { if (keyboardSource != 0) { mappers.push_back( - std::make_unique(this, keyboardSource, keyboardType)); + std::make_unique(*contextPtr, keyboardSource, keyboardType)); } // Cursor-like devices. if (classes & INPUT_DEVICE_CLASS_CURSOR) { - mappers.push_back(std::make_unique(this)); + mappers.push_back(std::make_unique(*contextPtr)); } // Touchscreens and touchpad devices. if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { - mappers.push_back(std::make_unique(this)); + mappers.push_back(std::make_unique(*contextPtr)); } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { - mappers.push_back(std::make_unique(this)); + mappers.push_back(std::make_unique(*contextPtr)); } // Joystick-like devices. if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { - mappers.push_back(std::make_unique(this)); + mappers.push_back(std::make_unique(*contextPtr)); } // External stylus-like devices. if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { - mappers.push_back(std::make_unique(this)); + mappers.push_back(std::make_unique(*contextPtr)); } } @@ -195,14 +198,14 @@ void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config if (!isIgnored()) { if (!changes) { // first time only - mContext->getEventHub()->getConfiguration(mId, &mConfiguration); + mDeviceContext->getConfiguration(&mConfiguration); } if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { sp keyboardLayout = mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier); - if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { + if (mDeviceContext->setKeyboardLayoutOverlay(keyboardLayout)) { bumpGeneration(); } } @@ -421,4 +424,12 @@ std::optional InputDevice::getAssociatedDisplayId() { [](InputMapper& mapper) { return mapper.getAssociatedDisplayId(); }); } +InputDeviceContext::InputDeviceContext(InputDevice& device) + : mDevice(device), + mContext(device.getContext()), + mEventHub(device.getContext()->getEventHub()), + mId(device.getId()) {} + +InputDeviceContext::~InputDeviceContext() {} + } // namespace android diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 010729a6d3..3e23fa6c84 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -348,13 +348,11 @@ void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { mDisableVirtualKeysTimeout = time; } -bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, InputDevice* device, int32_t keyCode, - int32_t scanCode) { +bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, int32_t keyCode, int32_t scanCode) { if (now < mDisableVirtualKeysTimeout) { - ALOGI("Dropping virtual key from device %s because virtual keys are " + ALOGI("Dropping virtual key from device because virtual keys are " "temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d", - device->getName().c_str(), (mDisableVirtualKeysTimeout - now) * 0.000001, keyCode, - scanCode); + (mDisableVirtualKeysTimeout - now) * 0.000001, keyCode, scanCode); return true; } else { return false; @@ -662,10 +660,10 @@ void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) { mReader->disableVirtualKeysUntilLocked(time); } -bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now, InputDevice* device, - int32_t keyCode, int32_t scanCode) { +bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now, int32_t keyCode, + int32_t scanCode) { // lock is already held by the input loop - return mReader->shouldDropVirtualKeyLocked(now, device, keyCode, scanCode); + return mReader->shouldDropVirtualKeyLocked(now, keyCode, scanCode); } void InputReader::ContextImpl::fadePointer() { diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index d06cc20719..0814d1f16e 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -31,6 +31,7 @@ namespace android { +class InputDeviceContext; class InputMapper; /* Represents the state of a single input device. */ @@ -96,30 +97,12 @@ public: inline const PropertyMap& getConfiguration() { return mConfiguration; } inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } - bool hasKey(int32_t code) { return getEventHub()->hasScanCode(mId, code); } - - bool hasAbsoluteAxis(int32_t code) { - RawAbsoluteAxisInfo info; - getEventHub()->getAbsoluteAxisInfo(mId, code, &info); - return info.valid; - } - - bool isKeyPressed(int32_t code) { - return getEventHub()->getScanCodeState(mId, code) == AKEY_STATE_DOWN; - } - - int32_t getAbsoluteAxisValue(int32_t code) { - int32_t value; - getEventHub()->getAbsoluteAxisValue(mId, code, &value); - return value; - } - std::optional getAssociatedDisplayId(); // construct and add a mapper to the input device template T& addMapper(Args... args) { - T* mapper = new T(this, args...); + T* mapper = new T(*mDeviceContext, args...); mMappers.emplace_back(mapper); return *mapper; } @@ -133,6 +116,7 @@ private: std::string mAlias; uint32_t mClasses; + std::unique_ptr mDeviceContext; std::vector> mMappers; uint32_t mSources; @@ -168,6 +152,115 @@ private: } }; +/* Provides access to EventHub methods, but limits access to the current InputDevice. + * Essentially an implementation of EventHubInterface, but for a specific device id. + * Helps hide implementation details of InputDevice and EventHub. Used by mappers to + * check the status of the associated hardware device + */ +class InputDeviceContext { +public: + InputDeviceContext(InputDevice& device); + ~InputDeviceContext(); + + inline InputReaderContext* getContext() { return mContext; } + inline int32_t getId() { return mId; } + + inline uint32_t getDeviceClasses() const { return mEventHub->getDeviceClasses(mId); } + inline InputDeviceIdentifier getDeviceIdentifier() const { + return mEventHub->getDeviceIdentifier(mId); + } + inline int32_t getDeviceControllerNumber() const { + return mEventHub->getDeviceControllerNumber(mId); + } + inline void getConfiguration(PropertyMap* outConfiguration) const { + return mEventHub->getConfiguration(mId, outConfiguration); + } + inline status_t getAbsoluteAxisInfo(int32_t code, RawAbsoluteAxisInfo* axisInfo) const { + return mEventHub->getAbsoluteAxisInfo(mId, code, axisInfo); + } + inline bool hasRelativeAxis(int32_t code) const { + return mEventHub->hasRelativeAxis(mId, code); + } + inline bool hasInputProperty(int property) const { + return mEventHub->hasInputProperty(mId, property); + } + inline status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t metaState, + int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const { + return mEventHub->mapKey(mId, scanCode, usageCode, metaState, outKeycode, outMetaState, + outFlags); + } + inline status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const { + return mEventHub->mapAxis(mId, scanCode, outAxisInfo); + } + inline std::vector getVideoFrames() { return mEventHub->getVideoFrames(mId); } + inline int32_t getScanCodeState(int32_t scanCode) const { + return mEventHub->getScanCodeState(mId, scanCode); + } + inline int32_t getKeyCodeState(int32_t keyCode) const { + return mEventHub->getKeyCodeState(mId, keyCode); + } + inline int32_t getSwitchState(int32_t sw) const { return mEventHub->getSwitchState(mId, sw); } + inline status_t getAbsoluteAxisValue(int32_t code, int32_t* outValue) const { + return mEventHub->getAbsoluteAxisValue(mId, code, outValue); + } + inline bool markSupportedKeyCodes(size_t numCodes, const int32_t* keyCodes, + uint8_t* outFlags) const { + return mEventHub->markSupportedKeyCodes(mId, numCodes, keyCodes, outFlags); + } + inline bool hasScanCode(int32_t scanCode) const { + return mEventHub->hasScanCode(mId, scanCode); + } + inline bool hasLed(int32_t led) const { return mEventHub->hasLed(mId, led); } + inline void setLedState(int32_t led, bool on) { return mEventHub->setLedState(mId, led, on); } + inline void getVirtualKeyDefinitions(std::vector& outVirtualKeys) const { + return mEventHub->getVirtualKeyDefinitions(mId, outVirtualKeys); + } + inline sp getKeyCharacterMap() const { + return mEventHub->getKeyCharacterMap(mId); + } + inline bool setKeyboardLayoutOverlay(const sp& map) { + return mEventHub->setKeyboardLayoutOverlay(mId, map); + } + inline void vibrate(nsecs_t duration) { return mEventHub->vibrate(mId, duration); } + inline void cancelVibrate() { return mEventHub->cancelVibrate(mId); } + + inline bool hasAbsoluteAxis(int32_t code) const { + RawAbsoluteAxisInfo info; + mEventHub->getAbsoluteAxisInfo(mId, code, &info); + return info.valid; + } + inline bool isKeyPressed(int32_t code) const { + return mEventHub->getScanCodeState(mId, code) == AKEY_STATE_DOWN; + } + inline int32_t getAbsoluteAxisValue(int32_t code) const { + int32_t value; + mEventHub->getAbsoluteAxisValue(mId, code, &value); + return value; + } + inline bool isDeviceEnabled() { return mEventHub->isDeviceEnabled(mId); } + inline status_t enableDevice() { return mEventHub->enableDevice(mId); } + inline status_t disableDevice() { return mEventHub->disableDevice(mId); } + + inline const std::string getName() { return mDevice.getName(); } + inline const std::string getDescriptor() { return mDevice.getDescriptor(); } + inline bool isExternal() { return mDevice.isExternal(); } + inline std::optional getAssociatedDisplayPort() const { + return mDevice.getAssociatedDisplayPort(); + } + inline std::optional getAssociatedViewport() const { + return mDevice.getAssociatedViewport(); + } + inline void cancelTouch(nsecs_t when) { mDevice.cancelTouch(when); } + inline void bumpGeneration() { mDevice.bumpGeneration(); } + inline const PropertyMap& getConfiguration() { return mDevice.getConfiguration(); } + +private: + InputDevice& mDevice; + InputReaderContext* mContext; + EventHubInterface* mEventHub; + int32_t mId; +}; + } // namespace android #endif //_UI_INPUTREADER_INPUT_DEVICE_H diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index 02957cd6ee..cf1af04417 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -101,8 +101,7 @@ protected: virtual void updateGlobalMetaState() override; virtual int32_t getGlobalMetaState() override; virtual void disableVirtualKeysUntil(nsecs_t time) override; - virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, - int32_t scanCode) override; + virtual bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) override; virtual void fadePointer() override; virtual void requestTimeoutAtTime(nsecs_t when) override; virtual int32_t bumpGeneration() override; @@ -168,8 +167,7 @@ private: nsecs_t mDisableVirtualKeysTimeout; void disableVirtualKeysUntilLocked(nsecs_t time); - bool shouldDropVirtualKeyLocked(nsecs_t now, InputDevice* device, int32_t keyCode, - int32_t scanCode); + bool shouldDropVirtualKeyLocked(nsecs_t now, int32_t keyCode, int32_t scanCode); nsecs_t mNextTimeout; void requestTimeoutAtTimeLocked(nsecs_t when); diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h index 3472346d44..e14fbbec3d 100644 --- a/services/inputflinger/reader/include/InputReaderContext.h +++ b/services/inputflinger/reader/include/InputReaderContext.h @@ -42,8 +42,7 @@ public: virtual int32_t getGlobalMetaState() = 0; virtual void disableVirtualKeysUntil(nsecs_t time) = 0; - virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, - int32_t scanCode) = 0; + virtual bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) = 0; virtual void fadePointer() = 0; diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 69a75bae2f..78f33823d0 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -30,7 +30,7 @@ CursorMotionAccumulator::CursorMotionAccumulator() { clearRelativeAxes(); } -void CursorMotionAccumulator::reset(InputDevice* device) { +void CursorMotionAccumulator::reset(InputDeviceContext& deviceContext) { clearRelativeAxes(); } @@ -58,7 +58,8 @@ void CursorMotionAccumulator::finishSync() { // --- CursorInputMapper --- -CursorInputMapper::CursorInputMapper(InputDevice* device) : InputMapper(device) {} +CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext) + : InputMapper(deviceContext) {} CursorInputMapper::~CursorInputMapper() {} @@ -113,7 +114,7 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* InputMapper::configure(when, config, changes); if (!changes) { // first time only - mCursorScrollAccumulator.configure(getDevice()); + mCursorScrollAccumulator.configure(getDeviceContext()); // Configure basic parameters. configureParameters(); @@ -167,7 +168,8 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* } bumpGeneration(); if (changes) { - getDevice()->notifyReset(when); + NotifyDeviceResetArgs args(getContext()->getNextSequenceNum(), when, getDeviceId()); + getListener()->notifyDeviceReset(&args); } } @@ -218,7 +220,8 @@ void CursorInputMapper::updatePointerControllerDisplayViewport( void CursorInputMapper::configureParameters() { mParameters.mode = Parameters::MODE_POINTER; String8 cursorModeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) { + if (getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.mode"), + cursorModeString)) { if (cursorModeString == "navigation") { mParameters.mode = Parameters::MODE_NAVIGATION; } else if (cursorModeString != "pointer" && cursorModeString != "default") { @@ -227,8 +230,8 @@ void CursorInputMapper::configureParameters() { } mParameters.orientationAware = false; - getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"), - mParameters.orientationAware); + getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.orientationAware"), + mParameters.orientationAware); mParameters.hasAssociatedDisplay = false; if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) { @@ -266,9 +269,9 @@ void CursorInputMapper::reset(nsecs_t when) { mWheelXVelocityControl.reset(); mWheelYVelocityControl.reset(); - mCursorButtonAccumulator.reset(getDevice()); - mCursorMotionAccumulator.reset(getDevice()); - mCursorScrollAccumulator.reset(getDevice()); + mCursorButtonAccumulator.reset(getDeviceContext()); + mCursorMotionAccumulator.reset(getDeviceContext()); + mCursorScrollAccumulator.reset(getDeviceContext()); InputMapper::reset(when); } @@ -369,7 +372,7 @@ void CursorInputMapper::sync(nsecs_t when) { // the device in your pocket. // TODO: Use the input device configuration to control this behavior more finely. uint32_t policyFlags = 0; - if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) { + if ((buttonsPressed || moved || scrolled) && getDeviceContext().isExternal()) { policyFlags |= POLICY_FLAG_WAKE; } @@ -379,7 +382,7 @@ void CursorInputMapper::sync(nsecs_t when) { // Send motion event. if (downChanged || moved || scrolled || buttonsChanged) { - int32_t metaState = mContext->getGlobalMetaState(); + int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = lastButtonState; int32_t motionEventAction; if (downChanged) { @@ -395,8 +398,8 @@ void CursorInputMapper::sync(nsecs_t when) { while (!released.isEmpty()) { int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); buttonState &= ~actionButton; - NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, + NotifyMotionArgs releaseArgs(getContext()->getNextSequenceNum(), when, + getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, @@ -407,7 +410,7 @@ void CursorInputMapper::sync(nsecs_t when) { } } - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, @@ -420,7 +423,7 @@ void CursorInputMapper::sync(nsecs_t when) { while (!pressed.isEmpty()) { int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit()); buttonState |= actionButton; - NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(), + NotifyMotionArgs pressArgs(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, metaState, buttonState, MotionClassification::NONE, @@ -436,9 +439,10 @@ void CursorInputMapper::sync(nsecs_t when) { // Send hover move after UP to tell the application that the mouse is hovering now. if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) { - NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, - 0, metaState, currentButtonState, MotionClassification::NONE, + NotifyMotionArgs hoverArgs(getContext()->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, + currentButtonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, /* videoFrames */ {}); @@ -450,7 +454,7 @@ void CursorInputMapper::sync(nsecs_t when) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), + NotifyMotionArgs scrollArgs(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState, MotionClassification::NONE, @@ -471,7 +475,7 @@ void CursorInputMapper::sync(nsecs_t when) { int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); + return getDeviceContext().getScanCodeState(scanCode); } else { return AKEY_STATE_UNKNOWN; } diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index d56f9be045..94ab30674d 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -36,7 +36,7 @@ class CursorScrollAccumulator; class CursorMotionAccumulator { public: CursorMotionAccumulator(); - void reset(InputDevice* device); + void reset(InputDeviceContext& deviceContext); void process(const RawEvent* rawEvent); void finishSync(); @@ -53,7 +53,7 @@ private: class CursorInputMapper : public InputMapper { public: - explicit CursorInputMapper(InputDevice* device); + explicit CursorInputMapper(InputDeviceContext& deviceContext); virtual ~CursorInputMapper(); virtual uint32_t getSources() override; diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp index 9aa0770245..37e4047890 100644 --- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp +++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp @@ -23,7 +23,8 @@ namespace android { -ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) : InputMapper(device) {} +ExternalStylusInputMapper::ExternalStylusInputMapper(InputDeviceContext& deviceContext) + : InputMapper(deviceContext) {} uint32_t ExternalStylusInputMapper::getSources() { return AINPUT_SOURCE_STYLUS; @@ -46,13 +47,12 @@ void ExternalStylusInputMapper::dump(std::string& dump) { void ExternalStylusInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis); - mTouchButtonAccumulator.configure(getDevice()); + mTouchButtonAccumulator.configure(getDeviceContext()); } void ExternalStylusInputMapper::reset(nsecs_t when) { - InputDevice* device = getDevice(); - mSingleTouchMotionAccumulator.reset(device); - mTouchButtonAccumulator.reset(device); + mSingleTouchMotionAccumulator.reset(getDeviceContext()); + mTouchButtonAccumulator.reset(getDeviceContext()); InputMapper::reset(when); } @@ -86,7 +86,7 @@ void ExternalStylusInputMapper::sync(nsecs_t when) { mStylusState.buttons = mTouchButtonAccumulator.getButtonState(); - mContext->dispatchExternalStylusState(mStylusState); + getContext()->dispatchExternalStylusState(mStylusState); } } // namespace android diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h index 34f339a3cd..1d42b30fe2 100644 --- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h +++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h @@ -27,7 +27,7 @@ namespace android { class ExternalStylusInputMapper : public InputMapper { public: - explicit ExternalStylusInputMapper(InputDevice* device); + explicit ExternalStylusInputMapper(InputDeviceContext& deviceContext); virtual ~ExternalStylusInputMapper() = default; virtual uint32_t getSources() override; diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp index d941528d14..92af6123cc 100644 --- a/services/inputflinger/reader/mapper/InputMapper.cpp +++ b/services/inputflinger/reader/mapper/InputMapper.cpp @@ -22,7 +22,7 @@ namespace android { -InputMapper::InputMapper(InputDevice* device) : mDevice(device), mContext(device->getContext()) {} +InputMapper::InputMapper(InputDeviceContext& deviceContext) : mDeviceContext(deviceContext) {} InputMapper::~InputMapper() {} @@ -74,11 +74,11 @@ void InputMapper::updateExternalStylusState(const StylusState& state) {} void InputMapper::fadePointer() {} status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) { - return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo); + return getDeviceContext().getAbsoluteAxisInfo(axis, axisInfo); } void InputMapper::bumpGeneration() { - mDevice->bumpGeneration(); + getDeviceContext().bumpGeneration(); } void InputMapper::dumpRawAbsoluteAxisInfo(std::string& dump, const RawAbsoluteAxisInfo& axis, diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h index a559ef882f..09888bfe20 100644 --- a/services/inputflinger/reader/mapper/InputMapper.h +++ b/services/inputflinger/reader/mapper/InputMapper.h @@ -39,16 +39,15 @@ namespace android { */ class InputMapper { public: - explicit InputMapper(InputDevice* device); + explicit InputMapper(InputDeviceContext& deviceContext); virtual ~InputMapper(); - inline InputDevice* getDevice() { return mDevice; } - inline int32_t getDeviceId() { return mDevice->getId(); } - inline const std::string getDeviceName() { return mDevice->getName(); } - inline InputReaderContext* getContext() { return mContext; } - inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); } - inline InputListenerInterface* getListener() { return mContext->getListener(); } - inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } + inline int32_t getDeviceId() { return mDeviceContext.getId(); } + inline InputDeviceContext& getDeviceContext() { return mDeviceContext; } + inline const std::string getDeviceName() { return mDeviceContext.getName(); } + inline InputReaderContext* getContext() { return mDeviceContext.getContext(); } + inline InputReaderPolicyInterface* getPolicy() { return getContext()->getPolicy(); } + inline InputListenerInterface* getListener() { return getContext()->getListener(); } virtual uint32_t getSources() = 0; virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); @@ -76,8 +75,7 @@ public: virtual std::optional getAssociatedDisplayId() { return std::nullopt; } protected: - InputDevice* mDevice; - InputReaderContext* mContext; + InputDeviceContext& mDeviceContext; status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo); void bumpGeneration(); diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp index 50adf73c76..57c85b6280 100644 --- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp +++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp @@ -20,7 +20,8 @@ namespace android { -JoystickInputMapper::JoystickInputMapper(InputDevice* device) : InputMapper(device) {} +JoystickInputMapper::JoystickInputMapper(InputDeviceContext& deviceContext) + : InputMapper(deviceContext) {} JoystickInputMapper::~JoystickInputMapper() {} @@ -112,7 +113,8 @@ void JoystickInputMapper::configure(nsecs_t when, const InputReaderConfiguration if (!changes) { // first time only // Collect all axes. for (int32_t abs = 0; abs <= ABS_MAX; abs++) { - if (!(getAbsAxisUsage(abs, getDevice()->getClasses()) & INPUT_DEVICE_CLASS_JOYSTICK)) { + if (!(getAbsAxisUsage(abs, getDeviceContext().getDeviceClasses()) & + INPUT_DEVICE_CLASS_JOYSTICK)) { continue; // axis must be claimed by a different device } @@ -121,7 +123,7 @@ void JoystickInputMapper::configure(nsecs_t when, const InputReaderConfiguration if (rawAxisInfo.valid) { // Map axis. AxisInfo axisInfo; - bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo); + bool explicitlyMapped = !getDeviceContext().mapAxis(abs, &axisInfo); if (!explicitlyMapped) { // Axis is not explicitly mapped, will choose a generic axis later. axisInfo.mode = AxisInfo::MODE_NORMAL; @@ -304,7 +306,7 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { return; } - int32_t metaState = mContext->getGlobalMetaState(); + int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = 0; PointerProperties pointerProperties; @@ -331,7 +333,7 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { // TODO: Use the input device configuration to control this behavior more finely. uint32_t policyFlags = 0; - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), + NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.h b/services/inputflinger/reader/mapper/JoystickInputMapper.h index b46d27d2d1..823a096d68 100644 --- a/services/inputflinger/reader/mapper/JoystickInputMapper.h +++ b/services/inputflinger/reader/mapper/JoystickInputMapper.h @@ -23,7 +23,7 @@ namespace android { class JoystickInputMapper : public InputMapper { public: - explicit JoystickInputMapper(InputDevice* device); + explicit JoystickInputMapper(InputDeviceContext& deviceContext); virtual ~JoystickInputMapper(); virtual uint32_t getSources() override; diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp index 348a7ada0e..9ab707fb60 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp @@ -87,8 +87,9 @@ static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { // --- KeyboardInputMapper --- -KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType) - : InputMapper(device), mSource(source), mKeyboardType(keyboardType) {} +KeyboardInputMapper::KeyboardInputMapper(InputDeviceContext& deviceContext, uint32_t source, + int32_t keyboardType) + : InputMapper(deviceContext), mSource(source), mKeyboardType(keyboardType) {} KeyboardInputMapper::~KeyboardInputMapper() {} @@ -114,7 +115,7 @@ void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); info->setKeyboardType(mKeyboardType); - info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId())); + info->setKeyCharacterMap(getDeviceContext().getKeyCharacterMap()); } void KeyboardInputMapper::dump(std::string& dump) { @@ -129,10 +130,10 @@ void KeyboardInputMapper::dump(std::string& dump) { std::optional KeyboardInputMapper::findViewport( nsecs_t when, const InputReaderConfiguration* config) { - const std::optional displayPort = mDevice->getAssociatedDisplayPort(); + const std::optional displayPort = getDeviceContext().getAssociatedDisplayPort(); if (displayPort) { // Find the viewport that contains the same port - return mDevice->getAssociatedViewport(); + return getDeviceContext().getAssociatedViewport(); } // No associated display defined, try to find default display if orientationAware. @@ -171,7 +172,7 @@ static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const* p void KeyboardInputMapper::configureParameters() { mParameters.orientationAware = false; - const PropertyMap& config = getDevice()->getConfiguration(); + const PropertyMap& config = getDeviceContext().getConfiguration(); config.tryGetProperty(String8("keyboard.orientationAware"), mParameters.orientationAware); if (mParameters.orientationAware) { @@ -271,8 +272,8 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t keyMetaState; uint32_t policyFlags; - if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState, &keyCode, - &keyMetaState, &policyFlags)) { + if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState, + &policyFlags)) { keyCode = AKEYCODE_UNKNOWN; keyMetaState = mMetaState; policyFlags = 0; @@ -292,11 +293,11 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, } else { // key down if ((policyFlags & POLICY_FLAG_VIRTUAL) && - mContext->shouldDropVirtualKey(when, getDevice(), keyCode, scanCode)) { + getContext()->shouldDropVirtualKey(when, keyCode, scanCode)) { return; } if (policyFlags & POLICY_FLAG_GESTURE) { - mDevice->cancelTouch(when); + getDeviceContext().cancelTouch(when); } KeyDown keyDown; @@ -338,7 +339,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, // prevented (e.g. TV remotes), the key layout file should specify the policy flags for each // wake key individually. // TODO: Use the input device configuration to control this behavior more finely. - if (down && getDevice()->isExternal() && !mParameters.doNotWakeByDefault && + if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault && !isMediaKey(keyCode)) { policyFlags |= POLICY_FLAG_WAKE; } @@ -347,8 +348,9 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT; } - NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, getDisplayId(), - policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, + NotifyKeyArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, + getDisplayId(), policyFlags, + down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime); getListener()->notifyKey(&args); } @@ -364,16 +366,16 @@ ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) { } int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return getEventHub()->getKeyCodeState(getDeviceId(), keyCode); + return getDeviceContext().getKeyCodeState(keyCode); } int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); + return getDeviceContext().getScanCodeState(scanCode); } bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { - return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags); + return getDeviceContext().markSupportedKeyCodes(numCodes, keyCodes, outFlags); } int32_t KeyboardInputMapper::getMetaState() { @@ -407,7 +409,7 @@ void KeyboardInputMapper::resetLedState() { } void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) { - ledState.avail = getEventHub()->hasLed(getDeviceId(), led); + ledState.avail = getDeviceContext().hasLed(led); ledState.on = false; } @@ -422,7 +424,7 @@ void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, int32_t if (ledState.avail) { bool desiredState = (mMetaState & modifier) != 0; if (reset || ledState.on != desiredState) { - getEventHub()->setLedState(getDeviceId(), led, desiredState); + getDeviceContext().setLedState(led, desiredState); ledState.on = desiredState; } } diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h index badbcb26cf..0bdeded285 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h @@ -23,7 +23,7 @@ namespace android { class KeyboardInputMapper : public InputMapper { public: - KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType); + KeyboardInputMapper(InputDeviceContext& deviceContext, uint32_t source, int32_t keyboardType); virtual ~KeyboardInputMapper(); virtual uint32_t getSources() override; diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp index f42ddcf461..d195a07eff 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp @@ -38,17 +38,17 @@ MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { delete[] mSlots; } -void MultiTouchMotionAccumulator::configure(InputDevice* device, size_t slotCount, +void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol) { mSlotCount = slotCount; mUsingSlotsProtocol = usingSlotsProtocol; - mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE); + mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE); delete[] mSlots; mSlots = new Slot[slotCount]; } -void MultiTouchMotionAccumulator::reset(InputDevice* device) { +void MultiTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) { // Unfortunately there is no way to read the initial contents of the slots. // So when we reset the accumulator, we must assume they are all zeroes. if (mUsingSlotsProtocol) { @@ -62,8 +62,7 @@ void MultiTouchMotionAccumulator::reset(InputDevice* device) { // This can cause the touch point to "jump", but at least there will be // no stuck touches. int32_t initialSlot; - status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(), ABS_MT_SLOT, - &initialSlot); + status_t status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot); if (status) { ALOGD("Could not retrieve current multitouch slot index. status=%d", status); initialSlot = -1; @@ -218,12 +217,13 @@ int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { // --- MultiTouchInputMapper --- -MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : TouchInputMapper(device) {} +MultiTouchInputMapper::MultiTouchInputMapper(InputDeviceContext& deviceContext) + : TouchInputMapper(deviceContext) {} MultiTouchInputMapper::~MultiTouchInputMapper() {} void MultiTouchInputMapper::reset(nsecs_t when) { - mMultiTouchMotionAccumulator.reset(getDevice()); + mMultiTouchMotionAccumulator.reset(getDeviceContext()); mPointerIdBits.clear(); @@ -353,9 +353,10 @@ void MultiTouchInputMapper::configureRawPointerAxes() { getDeviceName().c_str(), slotCount, MAX_SLOTS); slotCount = MAX_SLOTS; } - mMultiTouchMotionAccumulator.configure(getDevice(), slotCount, true /*usingSlotsProtocol*/); + mMultiTouchMotionAccumulator.configure(getDeviceContext(), slotCount, + true /*usingSlotsProtocol*/); } else { - mMultiTouchMotionAccumulator.configure(getDevice(), MAX_POINTERS, + mMultiTouchMotionAccumulator.configure(getDeviceContext(), MAX_POINTERS, false /*usingSlotsProtocol*/); } } diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h index a45c3cb12b..89ef41d177 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h @@ -70,8 +70,8 @@ public: MultiTouchMotionAccumulator(); ~MultiTouchMotionAccumulator(); - void configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol); - void reset(InputDevice* device); + void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol); + void reset(InputDeviceContext& deviceContext); void process(const RawEvent* rawEvent); void finishSync(); bool hasStylus() const; @@ -91,7 +91,7 @@ private: class MultiTouchInputMapper : public TouchInputMapper { public: - explicit MultiTouchInputMapper(InputDevice* device); + explicit MultiTouchInputMapper(InputDeviceContext& deviceContext); virtual ~MultiTouchInputMapper(); virtual void reset(nsecs_t when) override; diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp index e113ccad84..a1cce5695b 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp @@ -22,8 +22,8 @@ namespace android { -RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) - : InputMapper(device), mOrientation(DISPLAY_ORIENTATION_0) { +RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDeviceContext& deviceContext) + : InputMapper(deviceContext), mOrientation(DISPLAY_ORIENTATION_0) { mSource = AINPUT_SOURCE_ROTARY_ENCODER; } @@ -38,11 +38,11 @@ void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo* info) { if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) { float res = 0.0f; - if (!mDevice->getConfiguration().tryGetProperty(String8("device.res"), res)) { + if (!getDeviceContext().getConfiguration().tryGetProperty(String8("device.res"), res)) { ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n"); } - if (!mDevice->getConfiguration().tryGetProperty(String8("device.scalingFactor"), - mScalingFactor)) { + if (!getDeviceContext().getConfiguration().tryGetProperty(String8("device.scalingFactor"), + mScalingFactor)) { ALOGW("Rotary Encoder device configuration file didn't specify scaling factor," "default to 1.0!\n"); mScalingFactor = 1.0f; @@ -62,7 +62,7 @@ void RotaryEncoderInputMapper::configure(nsecs_t when, const InputReaderConfigur uint32_t changes) { InputMapper::configure(when, config, changes); if (!changes) { - mRotaryEncoderScrollAccumulator.configure(getDevice()); + mRotaryEncoderScrollAccumulator.configure(getDeviceContext()); } if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { std::optional internalViewport = @@ -76,7 +76,7 @@ void RotaryEncoderInputMapper::configure(nsecs_t when, const InputReaderConfigur } void RotaryEncoderInputMapper::reset(nsecs_t when) { - mRotaryEncoderScrollAccumulator.reset(getDevice()); + mRotaryEncoderScrollAccumulator.reset(getDeviceContext()); InputMapper::reset(when); } @@ -106,7 +106,7 @@ void RotaryEncoderInputMapper::sync(nsecs_t when) { // Moving the rotary encoder should wake the device (if specified). uint32_t policyFlags = 0; - if (scrolled && getDevice()->isExternal()) { + if (scrolled && getDeviceContext().isExternal()) { policyFlags |= POLICY_FLAG_WAKE; } @@ -116,12 +116,12 @@ void RotaryEncoderInputMapper::sync(nsecs_t when) { // Send motion event. if (scrolled) { - int32_t metaState = mContext->getGlobalMetaState(); + int32_t metaState = getContext()->getGlobalMetaState(); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor); - NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, - metaState, /* buttonState */ 0, MotionClassification::NONE, + NotifyMotionArgs scrollArgs(getContext()->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, + 0, metaState, /* buttonState */ 0, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}); diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h index 38c7258f7e..7a77b1286c 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h @@ -24,7 +24,7 @@ namespace android { class RotaryEncoderInputMapper : public InputMapper { public: - explicit RotaryEncoderInputMapper(InputDevice* device); + explicit RotaryEncoderInputMapper(InputDeviceContext& deviceContext); virtual ~RotaryEncoderInputMapper(); virtual uint32_t getSources() override; diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp b/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp index 440d282686..4fff9bebb5 100644 --- a/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp @@ -18,12 +18,13 @@ namespace android { -SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : TouchInputMapper(device) {} +SingleTouchInputMapper::SingleTouchInputMapper(InputDeviceContext& deviceContext) + : TouchInputMapper(deviceContext) {} SingleTouchInputMapper::~SingleTouchInputMapper() {} void SingleTouchInputMapper::reset(nsecs_t when) { - mSingleTouchMotionAccumulator.reset(getDevice()); + mSingleTouchMotionAccumulator.reset(getDeviceContext()); TouchInputMapper::reset(when); } diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h index 8438eee80b..f5befb37de 100644 --- a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h +++ b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h @@ -24,7 +24,7 @@ namespace android { class SingleTouchInputMapper : public TouchInputMapper { public: - explicit SingleTouchInputMapper(InputDevice* device); + explicit SingleTouchInputMapper(InputDeviceContext& deviceContext); virtual ~SingleTouchInputMapper(); virtual void reset(nsecs_t when) override; diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp index 16095b9eb1..52b24498ac 100644 --- a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp @@ -20,8 +20,8 @@ namespace android { -SwitchInputMapper::SwitchInputMapper(InputDevice* device) - : InputMapper(device), mSwitchValues(0), mUpdatedSwitchMask(0) {} +SwitchInputMapper::SwitchInputMapper(InputDeviceContext& deviceContext) + : InputMapper(deviceContext), mSwitchValues(0), mUpdatedSwitchMask(0) {} SwitchInputMapper::~SwitchInputMapper() {} @@ -56,7 +56,7 @@ void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) { void SwitchInputMapper::sync(nsecs_t when) { if (mUpdatedSwitchMask) { uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask; - NotifySwitchArgs args(mContext->getNextSequenceNum(), when, 0 /*policyFlags*/, + NotifySwitchArgs args(getContext()->getNextSequenceNum(), when, 0 /*policyFlags*/, updatedSwitchValues, mUpdatedSwitchMask); getListener()->notifySwitch(&args); @@ -65,7 +65,7 @@ void SwitchInputMapper::sync(nsecs_t when) { } int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return getEventHub()->getSwitchState(getDeviceId(), switchCode); + return getDeviceContext().getSwitchState(switchCode); } void SwitchInputMapper::dump(std::string& dump) { diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.h b/services/inputflinger/reader/mapper/SwitchInputMapper.h index e65d4e2bd5..4d74163069 100644 --- a/services/inputflinger/reader/mapper/SwitchInputMapper.h +++ b/services/inputflinger/reader/mapper/SwitchInputMapper.h @@ -23,7 +23,7 @@ namespace android { class SwitchInputMapper : public InputMapper { public: - explicit SwitchInputMapper(InputDevice* device); + explicit SwitchInputMapper(InputDeviceContext& deviceContext); virtual ~SwitchInputMapper(); virtual uint32_t getSources() override; diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 3b20173fa4..e832804e16 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -156,8 +156,8 @@ void CookedPointerData::copyFrom(const CookedPointerData& other) { // --- TouchInputMapper --- -TouchInputMapper::TouchInputMapper(InputDevice* device) - : InputMapper(device), +TouchInputMapper::TouchInputMapper(InputDeviceContext& deviceContext) + : InputMapper(deviceContext), mSource(0), mDeviceMode(DEVICE_MODE_DISABLED), mSurfaceWidth(-1), @@ -348,8 +348,8 @@ void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* c configureParameters(); // Configure common accumulators. - mCursorScrollAccumulator.configure(getDevice()); - mTouchButtonAccumulator.configure(getDevice()); + mCursorScrollAccumulator.configure(getDeviceContext()); + mTouchButtonAccumulator.configure(getDeviceContext()); // Configure absolute axis information. configureRawPointerAxes(); @@ -386,13 +386,14 @@ void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* c if (changes && resetNeeded) { // Send reset, unless this is the first time the device has been configured, // in which case the reader will call reset itself after all mappers are ready. - getDevice()->notifyReset(when); + NotifyDeviceResetArgs args(getContext()->getNextSequenceNum(), when, getDeviceId()); + getListener()->notifyDeviceReset(&args); } } void TouchInputMapper::resolveExternalStylusPresence() { std::vector devices; - mContext->getExternalStylusDevices(devices); + getContext()->getExternalStylusDevices(devices); mExternalStylusConnected = !devices.empty(); if (!mExternalStylusConnected) { @@ -404,13 +405,13 @@ void TouchInputMapper::configureParameters() { // Use the pointer presentation mode for devices that do not support distinct // multitouch. The spot-based presentation relies on being able to accurately // locate two or more fingers on the touch pad. - mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT) + mParameters.gestureMode = getDeviceContext().hasInputProperty(INPUT_PROP_SEMI_MT) ? Parameters::GESTURE_MODE_SINGLE_TOUCH : Parameters::GESTURE_MODE_MULTI_TOUCH; String8 gestureModeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"), - gestureModeString)) { + if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.gestureMode"), + gestureModeString)) { if (gestureModeString == "single-touch") { mParameters.gestureMode = Parameters::GESTURE_MODE_SINGLE_TOUCH; } else if (gestureModeString == "multi-touch") { @@ -420,14 +421,14 @@ void TouchInputMapper::configureParameters() { } } - if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) { + if (getDeviceContext().hasInputProperty(INPUT_PROP_DIRECT)) { // The device is a touch screen. mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; - } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) { + } else if (getDeviceContext().hasInputProperty(INPUT_PROP_POINTER)) { // The device is a pointing device like a track pad. mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) || - getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) { + } else if (getDeviceContext().hasRelativeAxis(REL_X) || + getDeviceContext().hasRelativeAxis(REL_Y)) { // The device is a cursor device with a touch pad attached. // By default don't use the touch pad to move the pointer. mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; @@ -436,12 +437,11 @@ void TouchInputMapper::configureParameters() { mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; } - mParameters.hasButtonUnderPad = - getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_BUTTONPAD); + mParameters.hasButtonUnderPad = getDeviceContext().hasInputProperty(INPUT_PROP_BUTTONPAD); String8 deviceTypeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), - deviceTypeString)) { + if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.deviceType"), + deviceTypeString)) { if (deviceTypeString == "touchScreen") { mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; } else if (deviceTypeString == "touchPad") { @@ -456,8 +456,8 @@ void TouchInputMapper::configureParameters() { } mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; - getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), - mParameters.orientationAware); + getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientationAware"), + mParameters.orientationAware); mParameters.hasAssociatedDisplay = false; mParameters.associatedDisplayIsExternal = false; @@ -466,22 +466,22 @@ void TouchInputMapper::configureParameters() { mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { mParameters.hasAssociatedDisplay = true; if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) { - mParameters.associatedDisplayIsExternal = getDevice()->isExternal(); + mParameters.associatedDisplayIsExternal = getDeviceContext().isExternal(); String8 uniqueDisplayId; - getDevice()->getConfiguration().tryGetProperty(String8("touch.displayId"), - uniqueDisplayId); + getDeviceContext().getConfiguration().tryGetProperty(String8("touch.displayId"), + uniqueDisplayId); mParameters.uniqueDisplayId = uniqueDisplayId.c_str(); } } - if (getDevice()->getAssociatedDisplayPort()) { + if (getDeviceContext().getAssociatedDisplayPort()) { mParameters.hasAssociatedDisplay = true; } // Initial downs on external touch devices should wake the device. // Normally we don't do this for internal touch screens to prevent them from waking // up in your pocket but you can enable it using the input device configuration. - mParameters.wake = getDevice()->isExternal(); - getDevice()->getConfiguration().tryGetProperty(String8("touch.wake"), mParameters.wake); + mParameters.wake = getDeviceContext().isExternal(); + getDeviceContext().getConfiguration().tryGetProperty(String8("touch.wake"), mParameters.wake); } void TouchInputMapper::dumpParameters(std::string& dump) { @@ -559,10 +559,10 @@ bool TouchInputMapper::hasExternalStylus() const { */ std::optional TouchInputMapper::findViewport() { if (mParameters.hasAssociatedDisplay) { - const std::optional displayPort = mDevice->getAssociatedDisplayPort(); + const std::optional displayPort = getDeviceContext().getAssociatedDisplayPort(); if (displayPort) { // Find the viewport that contains the same port - return mDevice->getAssociatedViewport(); + return getDeviceContext().getAssociatedViewport(); } if (mDeviceMode == DEVICE_MODE_POINTER) { @@ -1045,7 +1045,7 @@ void TouchInputMapper::dumpSurface(std::string& dump) { void TouchInputMapper::configureVirtualKeys() { std::vector virtualKeyDefinitions; - getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); + getDeviceContext().getVirtualKeyDefinitions(virtualKeyDefinitions); mVirtualKeys.clear(); @@ -1065,8 +1065,8 @@ void TouchInputMapper::configureVirtualKeys() { int32_t keyCode; int32_t dummyKeyMetaState; uint32_t flags; - if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, 0, &keyCode, - &dummyKeyMetaState, &flags)) { + if (getDeviceContext().mapKey(virtualKey.scanCode, 0, 0, &keyCode, &dummyKeyMetaState, + &flags)) { ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode); continue; // drop the key } @@ -1109,7 +1109,7 @@ void TouchInputMapper::dumpVirtualKeys(std::string& dump) { } void TouchInputMapper::parseCalibration() { - const PropertyMap& in = getDevice()->getConfiguration(); + const PropertyMap& in = getDeviceContext().getConfiguration(); Calibration& out = mCalibration; // Size @@ -1353,14 +1353,14 @@ void TouchInputMapper::dumpAffineTransformation(std::string& dump) { } void TouchInputMapper::updateAffineTransformation() { - mAffineTransform = getPolicy()->getTouchAffineTransformation(mDevice->getDescriptor(), + mAffineTransform = getPolicy()->getTouchAffineTransformation(getDeviceContext().getDescriptor(), mSurfaceOrientation); } void TouchInputMapper::reset(nsecs_t when) { - mCursorButtonAccumulator.reset(getDevice()); - mCursorScrollAccumulator.reset(getDevice()); - mTouchButtonAccumulator.reset(getDevice()); + mCursorButtonAccumulator.reset(getDeviceContext()); + mCursorScrollAccumulator.reset(getDeviceContext()); + mTouchButtonAccumulator.reset(getDeviceContext()); mPointerVelocityControl.reset(); mWheelXVelocityControl.reset(); @@ -1782,8 +1782,8 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { mCurrentVirtualKey.keyCode = virtualKey->keyCode; mCurrentVirtualKey.scanCode = virtualKey->scanCode; mCurrentVirtualKey.ignored = - mContext->shouldDropVirtualKey(when, getDevice(), virtualKey->keyCode, - virtualKey->scanCode); + getContext()->shouldDropVirtualKey(when, virtualKey->keyCode, + virtualKey->scanCode); if (!mCurrentVirtualKey.ignored) { #if DEBUG_VIRTUAL_KEYS @@ -1816,7 +1816,7 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { // is displayed. if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { - mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); + getContext()->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); } return false; } @@ -1826,12 +1826,12 @@ void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t keyCode = mCurrentVirtualKey.keyCode; int32_t scanCode = mCurrentVirtualKey.scanCode; nsecs_t downTime = mCurrentVirtualKey.downTime; - int32_t metaState = mContext->getGlobalMetaState(); + int32_t metaState = getContext()->getGlobalMetaState(); policyFlags |= POLICY_FLAG_VIRTUAL; - NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, - mViewport.displayId, policyFlags, keyEventAction, keyEventFlags, keyCode, - scanCode, metaState, downTime); + NotifyKeyArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), + AINPUT_SOURCE_KEYBOARD, mViewport.displayId, policyFlags, keyEventAction, + keyEventFlags, keyCode, scanCode, metaState, downTime); getListener()->notifyKey(&args); } @@ -2503,7 +2503,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); const int32_t displayId = mPointerController->getDisplayId(); - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, @@ -3423,7 +3423,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.down = false; // Send up. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties, @@ -3437,7 +3437,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.hovering = false; // Send hover exit. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties, @@ -3453,7 +3453,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.downTime = when; // Send down. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, @@ -3464,7 +3464,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, } // Send move. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties, @@ -3479,7 +3479,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.hovering = true; // Send hover enter. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState, mCurrentRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, @@ -3490,7 +3490,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, } // Send hover move. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties, @@ -3512,7 +3512,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties, @@ -3583,10 +3583,10 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32 } const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE); const int32_t deviceId = getDeviceId(); - std::vector frames = mDevice->getEventHub()->getVideoFrames(deviceId); + std::vector frames = getDeviceContext().getVideoFrames(); std::for_each(frames.begin(), frames.end(), [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); }); - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId, source, displayId, + NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, deviceId, source, displayId, policyFlags, action, actionButton, flags, metaState, buttonState, MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition, diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 4b1c0cbeaf..3a61206481 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -132,7 +132,7 @@ struct CookedPointerData { class TouchInputMapper : public InputMapper { public: - explicit TouchInputMapper(InputDevice* device); + explicit TouchInputMapper(InputDeviceContext& deviceContext); virtual ~TouchInputMapper(); virtual uint32_t getSources() override; diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp index a27fab4581..1b584ea7b9 100644 --- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp @@ -20,8 +20,8 @@ namespace android { -VibratorInputMapper::VibratorInputMapper(InputDevice* device) - : InputMapper(device), mVibrating(false) {} +VibratorInputMapper::VibratorInputMapper(InputDeviceContext& deviceContext) + : InputMapper(deviceContext), mVibrating(false) {} VibratorInputMapper::~VibratorInputMapper() {} @@ -100,12 +100,12 @@ void VibratorInputMapper::nextStep() { #if DEBUG_VIBRATOR ALOGD("nextStep: sending vibrate deviceId=%d, duration=%" PRId64, getDeviceId(), duration); #endif - getEventHub()->vibrate(getDeviceId(), duration); + getDeviceContext().vibrate(duration); } else { #if DEBUG_VIBRATOR ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId()); #endif - getEventHub()->cancelVibrate(getDeviceId()); + getDeviceContext().cancelVibrate(); } nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); mNextStepTime = now + duration; @@ -120,7 +120,7 @@ void VibratorInputMapper::stopVibrating() { #if DEBUG_VIBRATOR ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId()); #endif - getEventHub()->cancelVibrate(getDeviceId()); + getDeviceContext().cancelVibrate(); } void VibratorInputMapper::dump(std::string& dump) { diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.h b/services/inputflinger/reader/mapper/VibratorInputMapper.h index dc67890a31..f69fdde22e 100644 --- a/services/inputflinger/reader/mapper/VibratorInputMapper.h +++ b/services/inputflinger/reader/mapper/VibratorInputMapper.h @@ -23,7 +23,7 @@ namespace android { class VibratorInputMapper : public InputMapper { public: - explicit VibratorInputMapper(InputDevice* device); + explicit VibratorInputMapper(InputDeviceContext& deviceContext); virtual ~VibratorInputMapper(); virtual uint32_t getSources() override; diff --git a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.cpp index 0337d51126..2d7d73b4a3 100644 --- a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.cpp +++ b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.cpp @@ -25,15 +25,15 @@ CursorButtonAccumulator::CursorButtonAccumulator() { clearButtons(); } -void CursorButtonAccumulator::reset(InputDevice* device) { - mBtnLeft = device->isKeyPressed(BTN_LEFT); - mBtnRight = device->isKeyPressed(BTN_RIGHT); - mBtnMiddle = device->isKeyPressed(BTN_MIDDLE); - mBtnBack = device->isKeyPressed(BTN_BACK); - mBtnSide = device->isKeyPressed(BTN_SIDE); - mBtnForward = device->isKeyPressed(BTN_FORWARD); - mBtnExtra = device->isKeyPressed(BTN_EXTRA); - mBtnTask = device->isKeyPressed(BTN_TASK); +void CursorButtonAccumulator::reset(InputDeviceContext& deviceContext) { + mBtnLeft = deviceContext.isKeyPressed(BTN_LEFT); + mBtnRight = deviceContext.isKeyPressed(BTN_RIGHT); + mBtnMiddle = deviceContext.isKeyPressed(BTN_MIDDLE); + mBtnBack = deviceContext.isKeyPressed(BTN_BACK); + mBtnSide = deviceContext.isKeyPressed(BTN_SIDE); + mBtnForward = deviceContext.isKeyPressed(BTN_FORWARD); + mBtnExtra = deviceContext.isKeyPressed(BTN_EXTRA); + mBtnTask = deviceContext.isKeyPressed(BTN_TASK); } void CursorButtonAccumulator::clearButtons() { diff --git a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h index d9123109a3..9e159064fa 100644 --- a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h +++ b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h @@ -21,14 +21,14 @@ namespace android { -class InputDevice; +class InputDeviceContext; struct RawEvent; /* Keeps track of the state of mouse or touch pad buttons. */ class CursorButtonAccumulator { public: CursorButtonAccumulator(); - void reset(InputDevice* device); + void reset(InputDeviceContext& deviceContext); void process(const RawEvent* rawEvent); diff --git a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp index d744096d94..07146941fd 100644 --- a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp +++ b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp @@ -25,12 +25,12 @@ CursorScrollAccumulator::CursorScrollAccumulator() : mHaveRelWheel(false), mHave clearRelativeAxes(); } -void CursorScrollAccumulator::configure(InputDevice* device) { - mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL); - mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL); +void CursorScrollAccumulator::configure(InputDeviceContext& deviceContext) { + mHaveRelWheel = deviceContext.hasRelativeAxis(REL_WHEEL); + mHaveRelHWheel = deviceContext.hasRelativeAxis(REL_HWHEEL); } -void CursorScrollAccumulator::reset(InputDevice* device) { +void CursorScrollAccumulator::reset(InputDeviceContext& deviceContext) { clearRelativeAxes(); } diff --git a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h index 85f331fd8a..16495599d7 100644 --- a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h +++ b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h @@ -21,7 +21,7 @@ namespace android { -class InputDevice; +class InputDeviceContext; struct RawEvent; /* Keeps track of cursor scrolling motions. */ @@ -29,8 +29,8 @@ struct RawEvent; class CursorScrollAccumulator { public: CursorScrollAccumulator(); - void configure(InputDevice* device); - void reset(InputDevice* device); + void configure(InputDeviceContext& deviceContext); + void reset(InputDeviceContext& deviceContext); void process(const RawEvent* rawEvent); void finishSync(); diff --git a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp index e9ba727a0d..27b8e40fc6 100644 --- a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp +++ b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp @@ -25,14 +25,14 @@ SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() { clearAbsoluteAxes(); } -void SingleTouchMotionAccumulator::reset(InputDevice* device) { - mAbsX = device->getAbsoluteAxisValue(ABS_X); - mAbsY = device->getAbsoluteAxisValue(ABS_Y); - mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE); - mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH); - mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE); - mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X); - mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y); +void SingleTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) { + mAbsX = deviceContext.getAbsoluteAxisValue(ABS_X); + mAbsY = deviceContext.getAbsoluteAxisValue(ABS_Y); + mAbsPressure = deviceContext.getAbsoluteAxisValue(ABS_PRESSURE); + mAbsToolWidth = deviceContext.getAbsoluteAxisValue(ABS_TOOL_WIDTH); + mAbsDistance = deviceContext.getAbsoluteAxisValue(ABS_DISTANCE); + mAbsTiltX = deviceContext.getAbsoluteAxisValue(ABS_TILT_X); + mAbsTiltY = deviceContext.getAbsoluteAxisValue(ABS_TILT_Y); } void SingleTouchMotionAccumulator::clearAbsoluteAxes() { diff --git a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h index 75f8a961b3..4c011f16a7 100644 --- a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h +++ b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h @@ -21,7 +21,7 @@ namespace android { -class InputDevice; +class InputDeviceContext; struct RawEvent; /* Keeps track of the state of single-touch protocol. */ @@ -30,7 +30,7 @@ public: SingleTouchMotionAccumulator(); void process(const RawEvent* rawEvent); - void reset(InputDevice* device); + void reset(InputDeviceContext& deviceContext); inline int32_t getAbsoluteX() const { return mAbsX; } inline int32_t getAbsoluteY() const { return mAbsY; } diff --git a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp index d2f06c86fd..86153d3f5e 100644 --- a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp +++ b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp @@ -25,29 +25,31 @@ TouchButtonAccumulator::TouchButtonAccumulator() : mHaveBtnTouch(false), mHaveSt clearButtons(); } -void TouchButtonAccumulator::configure(InputDevice* device) { - mHaveBtnTouch = device->hasKey(BTN_TOUCH); - mHaveStylus = device->hasKey(BTN_TOOL_PEN) || device->hasKey(BTN_TOOL_RUBBER) || - device->hasKey(BTN_TOOL_BRUSH) || device->hasKey(BTN_TOOL_PENCIL) || - device->hasKey(BTN_TOOL_AIRBRUSH); +void TouchButtonAccumulator::configure(InputDeviceContext& deviceContext) { + mHaveBtnTouch = deviceContext.hasScanCode(BTN_TOUCH); + mHaveStylus = deviceContext.hasScanCode(BTN_TOOL_PEN) || + deviceContext.hasScanCode(BTN_TOOL_RUBBER) || + deviceContext.hasScanCode(BTN_TOOL_BRUSH) || + deviceContext.hasScanCode(BTN_TOOL_PENCIL) || + deviceContext.hasScanCode(BTN_TOOL_AIRBRUSH); } -void TouchButtonAccumulator::reset(InputDevice* device) { - mBtnTouch = device->isKeyPressed(BTN_TOUCH); - mBtnStylus = device->isKeyPressed(BTN_STYLUS); +void TouchButtonAccumulator::reset(InputDeviceContext& deviceContext) { + mBtnTouch = deviceContext.isKeyPressed(BTN_TOUCH); + mBtnStylus = deviceContext.isKeyPressed(BTN_STYLUS); // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch - mBtnStylus2 = device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0); - mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); - mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); - mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); - mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH); - mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL); - mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH); - mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE); - mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS); - mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP); - mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP); - mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP); + mBtnStylus2 = deviceContext.isKeyPressed(BTN_STYLUS2) || deviceContext.isKeyPressed(BTN_0); + mBtnToolFinger = deviceContext.isKeyPressed(BTN_TOOL_FINGER); + mBtnToolPen = deviceContext.isKeyPressed(BTN_TOOL_PEN); + mBtnToolRubber = deviceContext.isKeyPressed(BTN_TOOL_RUBBER); + mBtnToolBrush = deviceContext.isKeyPressed(BTN_TOOL_BRUSH); + mBtnToolPencil = deviceContext.isKeyPressed(BTN_TOOL_PENCIL); + mBtnToolAirbrush = deviceContext.isKeyPressed(BTN_TOOL_AIRBRUSH); + mBtnToolMouse = deviceContext.isKeyPressed(BTN_TOOL_MOUSE); + mBtnToolLens = deviceContext.isKeyPressed(BTN_TOOL_LENS); + mBtnToolDoubleTap = deviceContext.isKeyPressed(BTN_TOOL_DOUBLETAP); + mBtnToolTripleTap = deviceContext.isKeyPressed(BTN_TOOL_TRIPLETAP); + mBtnToolQuadTap = deviceContext.isKeyPressed(BTN_TOOL_QUADTAP); } void TouchButtonAccumulator::clearButtons() { diff --git a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h index 65b6bdcc12..22ebb720d5 100644 --- a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h +++ b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h @@ -21,15 +21,15 @@ namespace android { -class InputDevice; +class InputDeviceContext; struct RawEvent; /* Keeps track of the state of touch, stylus and tool buttons. */ class TouchButtonAccumulator { public: TouchButtonAccumulator(); - void configure(InputDevice* device); - void reset(InputDevice* device); + void configure(InputDeviceContext& deviceContext); + void reset(InputDeviceContext& deviceContext); void process(const RawEvent* rawEvent); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 7cd8793d5a..01bd9db76f 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -881,9 +881,7 @@ private: virtual void disableVirtualKeysUntil(nsecs_t) { } - virtual bool shouldDropVirtualKey(nsecs_t, InputDevice*, int32_t, int32_t) { - return false; - } + virtual bool shouldDropVirtualKey(nsecs_t, int32_t, int32_t) { return false; } virtual void fadePointer() { } @@ -929,12 +927,14 @@ class FakeInputMapper : public InputMapper { std::optional mViewport; public: - FakeInputMapper(InputDevice* device, uint32_t sources) : - InputMapper(device), - mSources(sources), mKeyboardType(AINPUT_KEYBOARD_TYPE_NONE), + FakeInputMapper(InputDeviceContext& deviceContext, uint32_t sources) + : InputMapper(deviceContext), + mSources(sources), + mKeyboardType(AINPUT_KEYBOARD_TYPE_NONE), mMetaState(0), - mConfigureWasCalled(false), mResetWasCalled(false), mProcessWasCalled(false) { - } + mConfigureWasCalled(false), + mResetWasCalled(false), + mProcessWasCalled(false) {} virtual ~FakeInputMapper() { } @@ -1022,7 +1022,7 @@ private: mConfigureWasCalled = true; // Find the associated viewport if exist. - const std::optional displayPort = mDevice->getAssociatedDisplayPort(); + const std::optional displayPort = getDeviceContext().getAssociatedDisplayPort(); if (displayPort && (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { mViewport = config->getDisplayViewportByPort(*displayPort); } -- GitLab From dfad90016b5d024701338c4ba022536a2e996641 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 12 Feb 2020 17:49:09 -0800 Subject: [PATCH 0799/1255] [SfStats] Add frame duration and renderengine timing to statsd Bug: 144037240 Test: statsd_testdrive 10062 Change-Id: I240f1bfda5e1e02212c7a6f93c4530729f454c1c --- .../surfaceflinger/TimeStats/TimeStats.cpp | 53 +++++---- .../tests/unittests/TimeStatsTest.cpp | 105 ++++++++++-------- 2 files changed, 92 insertions(+), 66 deletions(-) diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 7c8c28e87b..8038eba2e1 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -55,28 +55,6 @@ AStatsManager_PullAtomCallbackReturn TimeStats::pullAtomCallback(int32_t atom_ta return result; } -AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) { - std::lock_guard lock(mMutex); - - if (mTimeStats.statsStart == 0) { - return AStatsManager_PULL_SKIP; - } - flushPowerTimeLocked(); - - AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data); - mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime()); - mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount); - mStatsDelegate->statsEventBuild(event); - clearGlobalLocked(); - - return AStatsManager_PULL_SUCCESS; -} - namespace { // Histograms align with the order of fields in SurfaceflingerStatsLayerInfo. const std::array kHistogramNames = { @@ -112,6 +90,37 @@ std::string histogramToProtoByteString(const std::unordered_map lock(mMutex); + + if (mTimeStats.statsStart == 0) { + return AStatsManager_PULL_SKIP; + } + flushPowerTimeLocked(); + + AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data); + mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime()); + mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount); + std::string frameDurationBytes = + histogramToProtoByteString(mTimeStats.frameDuration.hist, mMaxPulledHistogramBuckets); + mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(), + frameDurationBytes.size()); + std::string renderEngineTimingBytes = + histogramToProtoByteString(mTimeStats.renderEngineTiming.hist, + mMaxPulledHistogramBuckets); + mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)renderEngineTimingBytes.c_str(), + renderEngineTimingBytes.size()); + mStatsDelegate->statsEventBuild(event); + clearGlobalLocked(); + + return AStatsManager_PULL_SUCCESS; +} + AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventList* data) { std::lock_guard lock(mMutex); diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index 685dfba9ea..a7a4d4837e 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -797,6 +797,49 @@ TEST_F(TimeStatsTest, canDumpWithInvalidMaxLayers) { ASSERT_EQ(0, globalProto.stats_size()); } +namespace { +std::string buildExpectedHistogramBytestring(const std::vector& times, + const std::vector& frameCounts) { + util::ProtoOutputStream proto; + for (int i = 0; i < times.size(); i++) { + ALOGE("Writing time: %d", times[i]); + proto.write(util::FIELD_TYPE_INT32 | util::FIELD_COUNT_REPEATED | 1 /* field id */, + (int32_t)times[i]); + ALOGE("Writing count: %d", frameCounts[i]); + proto.write(util::FIELD_TYPE_INT64 | util::FIELD_COUNT_REPEATED | 2 /* field id */, + (int64_t)frameCounts[i]); + } + std::string byteString; + proto.serializeToString(&byteString); + return byteString; +} + +std::string dumpByteStringHex(const std::string& str) { + std::stringstream ss; + ss << std::hex; + for (const char& c : str) { + ss << (int)c << " "; + } + + return ss.str(); +} + +} // namespace + +MATCHER_P2(BytesEq, bytes, size, "") { + std::string expected; + expected.append((const char*)bytes, size); + std::string actual; + actual.append((const char*)arg, size); + + *result_listener << "Bytes are not equal! \n"; + *result_listener << "size: " << size << "\n"; + *result_listener << "expected: " << dumpByteStringHex(expected).c_str() << "\n"; + *result_listener << "actual: " << dumpByteStringHex(actual).c_str() << "\n"; + + return expected == actual; +} + TEST_F(TimeStatsTest, globalStatsCallback) { constexpr size_t TOTAL_FRAMES = 5; constexpr size_t MISSED_FRAMES = 4; @@ -817,8 +860,11 @@ TEST_F(TimeStatsTest, globalStatsCallback) { } mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS); - mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL); + mTimeStats->recordFrameDuration(1000000, 3000000); + mTimeStats->recordRenderEngineDuration(2000000, 4000000); + mTimeStats->recordRenderEngineDuration(2000000, std::make_shared(3000000)); + mTimeStats->setPresentFenceGlobal(std::make_shared(3000000)); mTimeStats->setPresentFenceGlobal(std::make_shared(5000000)); @@ -828,6 +874,9 @@ TEST_F(TimeStatsTest, globalStatsCallback) { EXPECT_NE(nullptr, mDelegate->mCallback); EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie); + std::string expectedFrameDuration = buildExpectedHistogramBytestring({2}, {1}); + std::string expectedRenderEngineTiming = buildExpectedHistogramBytestring({1, 2}, {1, 1}); + { InSequence seq; EXPECT_CALL(*mDelegate, @@ -839,6 +888,17 @@ TEST_F(TimeStatsTest, globalStatsCallback) { EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _)); EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2)); EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, DISPLAY_EVENT_CONNECTIONS)); + EXPECT_CALL(*mDelegate, + statsEventWriteByteArray(mDelegate->mEvent, + BytesEq((const uint8_t*)expectedFrameDuration.c_str(), + expectedFrameDuration.size()), + expectedFrameDuration.size())); + EXPECT_CALL(*mDelegate, + statsEventWriteByteArray(mDelegate->mEvent, + BytesEq((const uint8_t*) + expectedRenderEngineTiming.c_str(), + expectedRenderEngineTiming.size()), + expectedRenderEngineTiming.size())); EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent)); } EXPECT_EQ(AStatsManager_PULL_SUCCESS, @@ -854,49 +914,6 @@ TEST_F(TimeStatsTest, globalStatsCallback) { EXPECT_EQ(0, globalProto.present_to_present_size()); } -namespace { -std::string buildExpectedHistogramBytestring(const std::vector& times, - const std::vector& frameCounts) { - util::ProtoOutputStream proto; - for (int i = 0; i < times.size(); i++) { - ALOGE("Writing time: %d", times[i]); - proto.write(util::FIELD_TYPE_INT32 | util::FIELD_COUNT_REPEATED | 1 /* field id */, - (int32_t)times[i]); - ALOGE("Writing count: %d", frameCounts[i]); - proto.write(util::FIELD_TYPE_INT64 | util::FIELD_COUNT_REPEATED | 2 /* field id */, - (int64_t)frameCounts[i]); - } - std::string byteString; - proto.serializeToString(&byteString); - return byteString; -} - -std::string dumpByteStringHex(const std::string& str) { - std::stringstream ss; - ss << std::hex; - for (const char& c : str) { - ss << (int)c << " "; - } - - return ss.str(); -} - -} // namespace - -MATCHER_P2(BytesEq, bytes, size, "") { - std::string expected; - expected.append((const char*)bytes, size); - std::string actual; - actual.append((const char*)arg, size); - - *result_listener << "Bytes are not equal! \n"; - *result_listener << "size: " << size << "\n"; - *result_listener << "expected: " << dumpByteStringHex(expected).c_str() << "\n"; - *result_listener << "actual: " << dumpByteStringHex(actual).c_str() << "\n"; - - return expected == actual; -} - TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { constexpr size_t LATE_ACQUIRE_FRAMES = 2; constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3; -- GitLab From 2a4983f49f508b472f7b06aeb411381b04e21c62 Mon Sep 17 00:00:00 2001 From: Ricky Wai Date: Fri, 7 Feb 2020 14:25:45 +0000 Subject: [PATCH 0800/1255] Fix private volume DE data path for mounting data mirror Also, fix the correct CE DE dir permission Bug: 149027213 Bug: 133435829 Test: Due to bug b/148856669, after reverting ag/10156695 and aosp/1218838, can see virtual disk is mounted correctly in adb shell mount, and test app works and mounted correctly after pm move-package. Change-Id: I18437187db14ae9b383fa3b8b4577273a3afb7a8 --- cmds/installd/InstalldNativeService.cpp | 44 +++++++++++++++---- cmds/installd/InstalldNativeService.h | 2 +- .../installd/binder/android/os/IInstalld.aidl | 2 +- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 08d4657a48..42887359d1 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -2684,7 +2684,7 @@ binder::Status InstalldNativeService::invalidateMounts() { } // Mount volume's CE and DE storage to mirror -binder::Status InstalldNativeService::onPrivateVolumeMounted( +binder::Status InstalldNativeService::tryMountDataMirror( const std::unique_ptr& uuid) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); @@ -2696,24 +2696,50 @@ binder::Status InstalldNativeService::onPrivateVolumeMounted( } const char* uuid_ = uuid->c_str(); - // Mount CE mirror + std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_)); std::lock_guard lock(mLock); - if (fs_prepare_dir(mirrorVolCePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) { + if (fs_prepare_dir(mirrorVolCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) { return error("Failed to create CE mirror"); } - auto cePath = StringPrintf("%s/user_ce", create_data_path(uuid_).c_str()); + + std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_)); + if (fs_prepare_dir(mirrorVolDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) { + return error("Failed to create DE mirror"); + } + + auto cePath = StringPrintf("%s/user", create_data_path(uuid_).c_str()); + auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str()); + + if (access(cePath.c_str(), F_OK) != 0) { + return error("Cannot access CE path: " + cePath); + } + if (access(dePath.c_str(), F_OK) != 0) { + return error("Cannot access DE path: " + dePath); + } + + struct stat ceStat, mirrorCeStat; + if (stat(cePath.c_str(), &ceStat) != 0) { + return error("Failed to stat " + cePath); + } + if (stat(mirrorVolCePath.c_str(), &mirrorCeStat) != 0) { + return error("Failed to stat " + mirrorVolCePath); + } + + if (mirrorCeStat.st_ino == ceStat.st_ino) { + // As it's being called by prepareUserStorage, it can be called multiple times. + // Hence, we if we mount it already, we should skip it. + LOG(WARNING) << "CE dir is mounted already: " + cePath; + return ok(); + } + + // Mount CE mirror if (TEMP_FAILURE_RETRY(mount(cePath.c_str(), mirrorVolCePath.c_str(), NULL, MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) { return error("Failed to mount " + mirrorVolCePath); } // Mount DE mirror - std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_)); - if (fs_prepare_dir(mirrorVolDePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) { - return error("Failed to create DE mirror"); - } - auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str()); if (TEMP_FAILURE_RETRY(mount(dePath.c_str(), mirrorVolDePath.c_str(), NULL, MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) { return error("Failed to mount " + mirrorVolDePath); diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index eb35fd3126..27c59b054f 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -155,7 +155,7 @@ public: binder::Status invalidateMounts(); binder::Status isQuotaSupported(const std::unique_ptr& volumeUuid, bool* _aidl_return); - binder::Status onPrivateVolumeMounted(const std::unique_ptr& volumeUuid); + binder::Status tryMountDataMirror(const std::unique_ptr& volumeUuid); binder::Status onPrivateVolumeRemoved(const std::unique_ptr& volumeUuid); binder::Status prepareAppProfile(const std::string& packageName, diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 80d97038b4..f2e86baabb 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -116,7 +116,7 @@ interface IInstalld { int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags); void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName, int userId, long ceSnapshotInode, int snapshotId, int storageFlags); - void onPrivateVolumeMounted(@nullable @utf8InCpp String volumeUuid); + void tryMountDataMirror(@nullable @utf8InCpp String volumeUuid); void onPrivateVolumeRemoved(@nullable @utf8InCpp String volumeUuid); void migrateLegacyObbData(); -- GitLab From 0188adf4c1f9d0285cb270cf6cc93afca0c586a8 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Thu, 13 Feb 2020 08:29:20 -0800 Subject: [PATCH 0801/1255] Only process passback transactions during onFrameAvailable A callback will be fired from the rendering thread when drawFrame returns after queueBuffer. Since the client expects the transaction, if sent, to be populated with the desired frame at this time, we need to make that call to queueBuffer wait until the frame has actually been processed and not put on the shadow queue Step 1 in resolving screen freeze Bug: 149315421 Test: build, boot, turn BLAST ON & reboot & phone boots fine Change-Id: Ibef45fe6c7e0b57fdc4a1be61e2ac93fb2d33525 --- libs/gui/BLASTBufferQueue.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index e2f5d31d00..f6493bf9c7 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -174,7 +174,9 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS) { + mCallbackCV.wait(_lock); + } + } // add to shadow queue mNumFrameAvailable++; processNextBufferLocked(); -- GitLab From 8540faff16bf57e99e31d059be0379075c81615e Mon Sep 17 00:00:00 2001 From: Hunter Knepshield Date: Tue, 4 Feb 2020 19:47:20 -0800 Subject: [PATCH 0802/1255] Hook IDumpstateDevice 1.1 up to dumpstate binary. Bug reports will now prefer v1.1 of the HAL since it supports well-scoped modes that mirror BugreportManager. For new devices launching with R, v1.1 must be supported if this (optional) HAL is implemented. It's also fairly trivial to update existing devices to 1.1 if an OEM chooses. As for what this means, bug reports will: - Be smaller in many cases, and as a result, faster to collect - Contain less unnecessary PII (e.g. camera logs should now be excluded for MODE_TELEPHONY) There's still some minor cleanup to be done, but for now leaving TODOs. Bug: 143183758 Bug: 143184495 Test: atest dumpstate_test Test: take bug report on Cuttlefish and Blueline, check for v1.1 usage Change-Id: I1660ff3983931fdeed51c85f2342700c89a012aa --- cmds/dumpstate/Android.bp | 1 + cmds/dumpstate/dumpstate.cpp | 83 ++++++++++++++++++------- cmds/dumpstate/dumpstate.h | 6 ++ cmds/dumpstate/tests/dumpstate_test.cpp | 20 +++++- 4 files changed, 85 insertions(+), 25 deletions(-) diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp index be7e3e1a73..acca11acf7 100644 --- a/cmds/dumpstate/Android.bp +++ b/cmds/dumpstate/Android.bp @@ -76,6 +76,7 @@ cc_defaults { defaults: ["dumpstate_cflag_defaults"], shared_libs: [ "android.hardware.dumpstate@1.0", + "android.hardware.dumpstate@1.1", "libziparchive", "libbase", "libbinder", diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 8e0f8a35d6..3a79357a54 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -64,6 +64,8 @@ #include #include #include +#include +#include #include #include #include @@ -85,7 +87,11 @@ #include "DumpstateService.h" #include "dumpstate.h" -using ::android::hardware::dumpstate::V1_0::IDumpstateDevice; +using IDumpstateDevice_1_0 = ::android::hardware::dumpstate::V1_0::IDumpstateDevice; +using IDumpstateDevice_1_1 = ::android::hardware::dumpstate::V1_1::IDumpstateDevice; +using ::android::hardware::dumpstate::V1_1::DumpstateMode; +using ::android::hardware::dumpstate::V1_1::DumpstateStatus; +using ::android::hardware::dumpstate::V1_1::toString; using ::std::literals::chrono_literals::operator""ms; using ::std::literals::chrono_literals::operator""s; @@ -1892,8 +1898,8 @@ void Dumpstate::DumpstateBoard() { std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i]))); } - sp dumpstate_device(IDumpstateDevice::getService()); - if (dumpstate_device == nullptr) { + sp dumpstate_device_1_0(IDumpstateDevice_1_0::getService()); + if (dumpstate_device_1_0 == nullptr) { MYLOGE("No IDumpstateDevice implementation\n"); return; } @@ -1924,29 +1930,54 @@ void Dumpstate::DumpstateBoard() { handle.get()->data[i] = fd.release(); } - // Given that bugreport is required to diagnose failures, it's better to - // set an arbitrary amount of timeout for IDumpstateDevice than to block the - // rest of bugreport. In the timeout case, we will kill dumpstate board HAL - // and grab whatever dumped - std::packaged_task - dumpstate_task([paths, dumpstate_device, &handle]() -> bool { - android::hardware::Return status = dumpstate_device->dumpstateBoard(handle.get()); + // Given that bugreport is required to diagnose failures, it's better to set an arbitrary amount + // of timeout for IDumpstateDevice than to block the rest of bugreport. In the timeout case, we + // will kill the HAL and grab whatever it dumped in time. + constexpr size_t timeout_sec = 30; + // Prefer version 1.1 if available. New devices launching with R are no longer allowed to + // implement just 1.0. + const char* descriptor_to_kill; + using DumpstateBoardTask = std::packaged_task; + DumpstateBoardTask dumpstate_board_task; + sp dumpstate_device_1_1( + IDumpstateDevice_1_1::castFrom(dumpstate_device_1_0)); + if (dumpstate_device_1_1 != nullptr) { + MYLOGI("Using IDumpstateDevice v1.1"); + descriptor_to_kill = IDumpstateDevice_1_1::descriptor; + dumpstate_board_task = DumpstateBoardTask([this, dumpstate_device_1_1, &handle]() -> bool { + ::android::hardware::Return status = + dumpstate_device_1_1->dumpstateBoard_1_1(handle.get(), options_->dumpstate_hal_mode, + SEC_TO_MSEC(timeout_sec)); if (!status.isOk()) { MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str()); return false; + } else if (status != DumpstateStatus::OK) { + MYLOGE("dumpstateBoard failed with DumpstateStatus::%s\n", toString(status).c_str()); + return false; } return true; }); + } else { + MYLOGI("Using IDumpstateDevice v1.0"); + descriptor_to_kill = IDumpstateDevice_1_0::descriptor; + dumpstate_board_task = DumpstateBoardTask([dumpstate_device_1_0, &handle]() -> bool { + ::android::hardware::Return status = + dumpstate_device_1_0->dumpstateBoard(handle.get()); + if (!status.isOk()) { + MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str()); + return false; + } + return true; + }); + } + auto result = dumpstate_board_task.get_future(); + std::thread(std::move(dumpstate_board_task)).detach(); - auto result = dumpstate_task.get_future(); - std::thread(std::move(dumpstate_task)).detach(); - - constexpr size_t timeout_sec = 30; if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) { MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec); - if (!android::base::SetProperty("ctl.interface_restart", - android::base::StringPrintf("%s/default", - IDumpstateDevice::descriptor))) { + if (!android::base::SetProperty( + "ctl.interface_restart", + android::base::StringPrintf("%s/default", descriptor_to_kill))) { MYLOGE("Couldn't restart dumpstate HAL\n"); } } @@ -1978,15 +2009,14 @@ void Dumpstate::DumpstateBoard() { continue; } AddZipEntry(kDumpstateBoardFiles[i], paths[i]); + printf("*** See %s entry ***\n", kDumpstateBoardFiles[i].c_str()); } - - printf("*** See dumpstate-board.txt entry ***\n"); } static void ShowUsage() { fprintf(stderr, "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] " - "[-z]] [-s] [-S] [-q] [-P] [-R] [-V version]\n" + "[-z] [-s] [-S] [-q] [-P] [-R] [-V version]\n" " -h: display this help message\n" " -b: play sound file instead of vibrate, at beginning of job\n" " -e: play sound file instead of vibrate, at end of job\n" @@ -2196,33 +2226,40 @@ static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOpt switch (mode) { case Dumpstate::BugreportMode::BUGREPORT_FULL: options->do_fb = true; + options->dumpstate_hal_mode = DumpstateMode::FULL; break; case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE: // Currently, the dumpstate binder is only used by Shell to update progress. options->do_start_service = true; options->do_progress_updates = true; options->do_fb = false; + options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE; break; case Dumpstate::BugreportMode::BUGREPORT_REMOTE: options->do_vibrate = false; options->is_remote_mode = true; options->do_fb = false; + options->dumpstate_hal_mode = DumpstateMode::REMOTE; break; case Dumpstate::BugreportMode::BUGREPORT_WEAR: options->do_start_service = true; options->do_progress_updates = true; options->do_zip_file = true; options->do_fb = true; + options->dumpstate_hal_mode = DumpstateMode::WEAR; break; + // TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY. case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY: options->telephony_only = true; options->do_progress_updates = true; options->do_fb = false; + options->dumpstate_hal_mode = DumpstateMode::CONNECTIVITY; break; case Dumpstate::BugreportMode::BUGREPORT_WIFI: options->wifi_only = true; options->do_zip_file = true; options->do_fb = false; + options->dumpstate_hal_mode = DumpstateMode::WIFI; break; case Dumpstate::BugreportMode::BUGREPORT_DEFAULT: break; @@ -2233,11 +2270,13 @@ static void LogDumpOptions(const Dumpstate::DumpOptions& options) { MYLOGI( "do_zip_file: %d do_vibrate: %d use_socket: %d use_control_socket: %d do_fb: %d " "is_remote_mode: %d show_header_only: %d do_start_service: %d telephony_only: %d " - "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s args: %s\n", + "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s dumpstate_hal_mode: %s " + "args: %s\n", options.do_zip_file, options.do_vibrate, options.use_socket, options.use_control_socket, options.do_fb, options.is_remote_mode, options.show_header_only, options.do_start_service, options.telephony_only, options.wifi_only, options.do_progress_updates, - options.bugreport_fd.get(), options.bugreport_mode.c_str(), options.args.c_str()); + options.bugreport_fd.get(), options.bugreport_mode.c_str(), + toString(options.dumpstate_hal_mode).c_str(), options.args.c_str()); } void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode, diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 7d9b113f1e..111c098992 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -366,6 +367,11 @@ class Dumpstate { bool wifi_only = false; // Whether progress updates should be published. bool do_progress_updates = false; + // The mode we'll use when calling IDumpstateDevice::dumpstateBoard. + // TODO(b/148168577) get rid of the AIDL values, replace them with the HAL values instead. + // The HAL is actually an API surface that can be validated, while the AIDL is not (@hide). + ::android::hardware::dumpstate::V1_1::DumpstateMode dumpstate_hal_mode = + ::android::hardware::dumpstate::V1_1::DumpstateMode::DEFAULT; // File descriptor to output zip file. android::base::unique_fd bugreport_fd; // File descriptor to screenshot file. diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 718f4592a3..76b996081d 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -36,20 +36,22 @@ #include #include #include -#include #include +#include +#include namespace android { namespace os { namespace dumpstate { +using ::android::hardware::dumpstate::V1_1::DumpstateMode; using ::testing::EndsWith; using ::testing::HasSubstr; -using ::testing::IsNull; using ::testing::IsEmpty; +using ::testing::IsNull; using ::testing::NotNull; -using ::testing::StrEq; using ::testing::StartsWith; +using ::testing::StrEq; using ::testing::Test; using ::testing::internal::CaptureStderr; using ::testing::internal::CaptureStdout; @@ -174,6 +176,7 @@ TEST_F(DumpOptionsTest, InitializeNone) { EXPECT_FALSE(options_.do_fb); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); } TEST_F(DumpOptionsTest, InitializeAdbBugreport) { @@ -200,6 +203,7 @@ TEST_F(DumpOptionsTest, InitializeAdbBugreport) { EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); EXPECT_FALSE(options_.use_socket); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); } TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) { @@ -224,6 +228,7 @@ TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) { EXPECT_FALSE(options_.do_fb); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); } TEST_F(DumpOptionsTest, InitializeFullBugReport) { @@ -231,6 +236,7 @@ TEST_F(DumpOptionsTest, InitializeFullBugReport) { EXPECT_TRUE(options_.do_add_date); EXPECT_TRUE(options_.do_fb); EXPECT_TRUE(options_.do_zip_file); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::FULL); // Other options retain default values EXPECT_TRUE(options_.do_vibrate); @@ -249,6 +255,7 @@ TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) { EXPECT_TRUE(options_.do_progress_updates); EXPECT_TRUE(options_.do_start_service); EXPECT_FALSE(options_.do_fb); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::INTERACTIVE); // Other options retain default values EXPECT_TRUE(options_.do_vibrate); @@ -265,6 +272,7 @@ TEST_F(DumpOptionsTest, InitializeRemoteBugReport) { EXPECT_TRUE(options_.is_remote_mode); EXPECT_FALSE(options_.do_vibrate); EXPECT_FALSE(options_.do_fb); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::REMOTE); // Other options retain default values EXPECT_FALSE(options_.use_control_socket); @@ -280,6 +288,7 @@ TEST_F(DumpOptionsTest, InitializeWearBugReport) { EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.do_progress_updates); EXPECT_TRUE(options_.do_start_service); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WEAR); // Other options retain default values EXPECT_TRUE(options_.do_vibrate); @@ -296,6 +305,7 @@ TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) { EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.telephony_only); EXPECT_TRUE(options_.do_progress_updates); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::CONNECTIVITY); // Other options retain default values EXPECT_TRUE(options_.do_vibrate); @@ -311,6 +321,7 @@ TEST_F(DumpOptionsTest, InitializeWifiBugReport) { EXPECT_FALSE(options_.do_fb); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.wifi_only); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WIFI); // Other options retain default values EXPECT_TRUE(options_.do_vibrate); @@ -337,6 +348,7 @@ TEST_F(DumpOptionsTest, InitializeDefaultBugReport) { EXPECT_TRUE(options_.do_add_date); EXPECT_TRUE(options_.do_fb); EXPECT_TRUE(options_.do_zip_file); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); // Other options retain default values EXPECT_TRUE(options_.do_vibrate); @@ -375,6 +387,7 @@ TEST_F(DumpOptionsTest, InitializePartial1) { EXPECT_FALSE(options_.do_fb); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); } TEST_F(DumpOptionsTest, InitializePartial2) { @@ -403,6 +416,7 @@ TEST_F(DumpOptionsTest, InitializePartial2) { EXPECT_FALSE(options_.do_zip_file); EXPECT_FALSE(options_.use_socket); EXPECT_FALSE(options_.use_control_socket); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); } TEST_F(DumpOptionsTest, InitializeHelp) { -- GitLab From bf7632e88a595baa8636ee1f6649ab86dc78cc11 Mon Sep 17 00:00:00 2001 From: Kevin DuBois Date: Thu, 13 Feb 2020 10:11:53 -0800 Subject: [PATCH 0803/1255] SF: correct runaway RegionSamplingThread timer In some cases, the VSyncReactor timer would keep firing even after the registration was stopped. This was because the onDispSyncEvent callback would cancel its timer from within its callback, and then VSR would not check if the callback had stopped itself before rescheduling the callback again. Fixes: 149221293 Test: 1 new unit test Test: ensure timerDispatch thread is quiet when display off Test: [todo] verify using powerStats procedure in bug. Change-Id: I5314c8d01de7d125c31488e48c7f2c550d201701 --- .../surfaceflinger/Scheduler/VSyncReactor.cpp | 3 +++ .../tests/unittests/VSyncReactorTest.cpp | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index da73e4e194..949ba4ca52 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -98,6 +98,9 @@ private: { std::lock_guard lk(mMutex); + if (mStopped) { + return; + } auto const schedule_result = mRegistration.schedule(calculateWorkload(), vsynctime); LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled), "Error rescheduling callback: rc %X", schedule_result); diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index 2f36bb2941..ac959388c2 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -534,6 +534,30 @@ TEST_F(VSyncReactorTest, eventListenersRemovedOnDestruction) { mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); } +// b/149221293 +TEST_F(VSyncReactorTest, selfRemovingEventListenerStopsCallbacks) { + class SelfRemovingCallback : public DispSync::Callback { + public: + SelfRemovingCallback(VSyncReactor& vsr) : mVsr(vsr) {} + void onDispSyncEvent(nsecs_t when) final { mVsr.removeEventListener(this, &when); } + + private: + VSyncReactor& mVsr; + } selfRemover(mReactor); + + Sequence seq; + EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) + .InSequence(seq) + .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken))); + EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) + .InSequence(seq); + EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq); + EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq); + + mReactor.addEventListener(mName, mPhase, &selfRemover, lastCallbackTime); + innerCb(0, 0); +} + TEST_F(VSyncReactorTest, addEventListenerChangePeriod) { Sequence seq; EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) -- GitLab From b87d94f61ddf784947cb6fd2d0569d8e568c1822 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 13 Feb 2020 09:17:36 -0800 Subject: [PATCH 0804/1255] Retrieve a list of composition settings from front end layer Replace prepareClientComposition and prepareShadowClientComposition calls with one that provides a list of composition settings in z-order to handle layers that renders shadows wihtout any content. If the EffectLayer is called with an invalid color, skip the color fill. Test: atest libcompositionengine_test Test: LayerTransactionTest.SetFlagsSecureEUidSystem Test: go/wm-smoke Change-Id: Iad16931341fc2e58247f4439a322c0ad1e8750f8 --- services/surfaceflinger/BufferLayer.cpp | 156 +++++----- services/surfaceflinger/BufferLayer.h | 5 +- .../include/compositionengine/LayerFE.h | 40 ++- .../include/compositionengine/mock/LayerFE.h | 6 +- .../CompositionEngine/src/Output.cpp | 47 ++- .../CompositionEngine/tests/OutputTest.cpp | 274 ++++++++++++------ services/surfaceflinger/EffectLayer.cpp | 36 ++- services/surfaceflinger/EffectLayer.h | 9 +- services/surfaceflinger/Layer.cpp | 46 ++- services/surfaceflinger/Layer.h | 14 +- services/surfaceflinger/SurfaceFlinger.cpp | 21 +- .../tests/LayerRenderTypeTransaction_test.cpp | 16 +- 12 files changed, 430 insertions(+), 240 deletions(-) diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index f4f45be49f..5a955f777b 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -180,95 +180,91 @@ std::optional BufferLayer::prepareCli } bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || (isSecure() && !targetSettings.isSecure); - const State& s(getDrawingState()); compositionengine::LayerFE::LayerSettings& layer = *result; - if (!blackOutLayer) { - layer.source.buffer.buffer = mBufferInfo.mBuffer; - layer.source.buffer.isOpaque = isOpaque(s); - layer.source.buffer.fence = mBufferInfo.mFence; - layer.source.buffer.textureName = mTextureName; - layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha(); - layer.source.buffer.isY410BT2020 = isHdrY410(); - bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086; - bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3; - layer.source.buffer.maxMasteringLuminance = hasSmpte2086 - ? mBufferInfo.mHdrMetadata.smpte2086.maxLuminance - : defaultMaxMasteringLuminance; - layer.source.buffer.maxContentLuminance = hasCta861_3 - ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel - : defaultMaxContentLuminance; - layer.frameNumber = mCurrentFrameNumber; - layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0; - - // TODO: we could be more subtle with isFixedSize() - const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize(); - - // Query the texture matrix given our current filtering mode. - float textureMatrix[16]; - getDrawingTransformMatrix(useFiltering, textureMatrix); - - if (getTransformToDisplayInverse()) { - /* - * the code below applies the primary display's inverse transform to - * the texture transform - */ - uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags(); - mat4 tr = inverseOrientation(transform); - - /** - * TODO(b/36727915): This is basically a hack. - * - * Ensure that regardless of the parent transformation, - * this buffer is always transformed from native display - * orientation to display orientation. For example, in the case - * of a camera where the buffer remains in native orientation, - * we want the pixels to always be upright. - */ - sp p = mDrawingParent.promote(); - if (p != nullptr) { - const auto parentTransform = p->getTransform(); - tr = tr * inverseOrientation(parentTransform.getOrientation()); - } - - // and finally apply it to the original texture matrix - const mat4 texTransform(mat4(static_cast(textureMatrix)) * tr); - memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix)); - } + if (blackOutLayer) { + prepareClearClientComposition(layer, true /* blackout */); + return layer; + } - const Rect win{getBounds()}; - float bufferWidth = getBufferSize(s).getWidth(); - float bufferHeight = getBufferSize(s).getHeight(); + const State& s(getDrawingState()); + layer.source.buffer.buffer = mBufferInfo.mBuffer; + layer.source.buffer.isOpaque = isOpaque(s); + layer.source.buffer.fence = mBufferInfo.mFence; + layer.source.buffer.textureName = mTextureName; + layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha(); + layer.source.buffer.isY410BT2020 = isHdrY410(); + bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086; + bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3; + layer.source.buffer.maxMasteringLuminance = hasSmpte2086 + ? mBufferInfo.mHdrMetadata.smpte2086.maxLuminance + : defaultMaxMasteringLuminance; + layer.source.buffer.maxContentLuminance = hasCta861_3 + ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel + : defaultMaxContentLuminance; + layer.frameNumber = mCurrentFrameNumber; + layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0; + + // TODO: we could be more subtle with isFixedSize() + const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize(); + + // Query the texture matrix given our current filtering mode. + float textureMatrix[16]; + getDrawingTransformMatrix(useFiltering, textureMatrix); - // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has - // been set and there is no parent layer bounds. In that case, the scale is meaningless so - // ignore them. - if (!getBufferSize(s).isValid()) { - bufferWidth = float(win.right) - float(win.left); - bufferHeight = float(win.bottom) - float(win.top); + if (getTransformToDisplayInverse()) { + /* + * the code below applies the primary display's inverse transform to + * the texture transform + */ + uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags(); + mat4 tr = inverseOrientation(transform); + + /** + * TODO(b/36727915): This is basically a hack. + * + * Ensure that regardless of the parent transformation, + * this buffer is always transformed from native display + * orientation to display orientation. For example, in the case + * of a camera where the buffer remains in native orientation, + * we want the pixels to always be upright. + */ + sp p = mDrawingParent.promote(); + if (p != nullptr) { + const auto parentTransform = p->getTransform(); + tr = tr * inverseOrientation(parentTransform.getOrientation()); } - const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight; - const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth; - const float translateY = float(win.top) / bufferHeight; - const float translateX = float(win.left) / bufferWidth; + // and finally apply it to the original texture matrix + const mat4 texTransform(mat4(static_cast(textureMatrix)) * tr); + memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix)); + } - // Flip y-coordinates because GLConsumer expects OpenGL convention. - mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) * - mat4::translate(vec4(-.5, -.5, 0, 1)) * - mat4::translate(vec4(translateX, translateY, 0, 1)) * - mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0)); + const Rect win{getBounds()}; + float bufferWidth = getBufferSize(s).getWidth(); + float bufferHeight = getBufferSize(s).getHeight(); - layer.source.buffer.useTextureFiltering = useFiltering; - layer.source.buffer.textureTransform = mat4(static_cast(textureMatrix)) * tr; - } else { - // If layer is blacked out, force alpha to 1 so that we draw a black color - // layer. - layer.source.buffer.buffer = nullptr; - layer.alpha = 1.0; - layer.frameNumber = 0; - layer.bufferId = 0; + // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has + // been set and there is no parent layer bounds. In that case, the scale is meaningless so + // ignore them. + if (!getBufferSize(s).isValid()) { + bufferWidth = float(win.right) - float(win.left); + bufferHeight = float(win.bottom) - float(win.top); } + const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight; + const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth; + const float translateY = float(win.top) / bufferHeight; + const float translateX = float(win.left) / bufferWidth; + + // Flip y-coordinates because GLConsumer expects OpenGL convention. + mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) * + mat4::translate(vec4(-.5, -.5, 0, 1)) * + mat4::translate(vec4(translateX, translateY, 0, 1)) * + mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0)); + + layer.source.buffer.useTextureFiltering = useFiltering; + layer.source.buffer.textureTransform = mat4(static_cast(textureMatrix)) * tr; + return layer; } diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 4085b52449..0487e380ec 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -173,14 +173,15 @@ protected: BufferInfo mBufferInfo; virtual void gatherBufferInfo() = 0; + std::optional prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings&) override; + /* * compositionengine::LayerFE overrides */ const compositionengine::LayerFECompositionState* getCompositionState() const override; bool onPreComposition(nsecs_t) override; void preparePerFrameCompositionState() override; - std::optional prepareClientComposition( - compositionengine::LayerFE::ClientCompositionTargetSettings&) override; // Loads the corresponding system property once per process static bool latchUnsignaledBuffers(); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 912dffd029..6cc90cb3ee 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -97,6 +97,21 @@ public: // Modified by each call to prepareClientComposition to indicate the // region of the target buffer that should be cleared. Region& clearRegion; + + // Viewport of the target being rendered to. This is used to determine + // the shadow light position. + const Rect& viewport; + + // Dataspace of the output so we can optimize how to render the shadow + // by avoiding unnecessary color space conversions. + const ui::Dataspace dataspace; + + // True if the region excluding the shadow is visible. + const bool realContentIsVisible; + + // If set to true, change the layer settings to render a clear output. + // This may be requested by the HWC + const bool clearContent; }; // A superset of LayerSettings required by RenderEngine to compose a layer @@ -109,18 +124,12 @@ public: uint64_t frameNumber = 0; }; - // Returns the LayerSettings to pass to RenderEngine::drawLayers, or - // nullopt_t if the layer does not render - virtual std::optional prepareClientComposition( + // Returns the z-ordered list of LayerSettings to pass to RenderEngine::drawLayers. The list + // may contain shadows casted by the layer or the content of the layer itself. If the layer + // does not render then an empty list will be returned. + virtual std::vector prepareClientCompositionList( ClientCompositionTargetSettings&) = 0; - // Returns the LayerSettings used to draw shadows around a layer. It is passed - // to RenderEngine::drawLayers. Returns nullopt_t if the layer does not render - // shadows. - virtual std::optional prepareShadowClientComposition( - const LayerSettings& layerSettings, const Rect& displayViewport, - ui::Dataspace outputDataspace) = 0; - // Called after the layer is displayed to update the presentation fence virtual void onLayerDisplayed(const sp&) = 0; @@ -142,7 +151,10 @@ static inline bool operator==(const LayerFE::ClientCompositionTargetSettings& lh lhs.useIdentityTransform == rhs.useIdentityTransform && lhs.needsFiltering == rhs.needsFiltering && lhs.isSecure == rhs.isSecure && lhs.supportsProtectedContent == rhs.supportsProtectedContent && - lhs.clearRegion.hasSameRects(rhs.clearRegion); + lhs.clearRegion.hasSameRects(rhs.clearRegion) && lhs.viewport == rhs.viewport && + lhs.dataspace == rhs.dataspace && + lhs.realContentIsVisible == rhs.realContentIsVisible && + lhs.clearContent == rhs.clearContent; } static inline bool operator==(const LayerFE::LayerSettings& lhs, @@ -164,6 +176,12 @@ static inline void PrintTo(const LayerFE::ClientCompositionTargetSettings& setti *os << "\n .supportsProtectedContent = " << settings.supportsProtectedContent; *os << "\n .clearRegion = "; PrintTo(settings.clearRegion, os); + *os << "\n .viewport = "; + PrintTo(settings.viewport, os); + *os << "\n .dataspace = "; + PrintTo(settings.dataspace, os); + *os << "\n .realContentIsVisible = " << settings.realContentIsVisible; + *os << "\n .clearContent = " << settings.clearContent; *os << "\n}"; } diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index 5c2ad15268..45891a7ff6 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -35,11 +35,9 @@ public: MOCK_METHOD1(onPreComposition, bool(nsecs_t)); MOCK_METHOD1(prepareCompositionState, void(compositionengine::LayerFE::StateSubset)); - MOCK_METHOD1(prepareClientComposition, - std::optional( + MOCK_METHOD1(prepareClientCompositionList, + std::vector( compositionengine::LayerFE::ClientCompositionTargetSettings&)); - MOCK_METHOD3(prepareShadowClientComposition, - std::optional(const LayerSettings&, const Rect&, ui::Dataspace)); MOCK_METHOD1(onLayerDisplayed, void(const sp&)); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index a389bf3805..e792f45bb7 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -963,11 +963,16 @@ std::vector Output::generateClientCompositionRequests( // rectangle, as by definition the layer must blend with whatever is // underneath. We also skip the first layer as the buffer target is // guaranteed to start out cleared. - bool clearClientComposition = + const bool clearClientComposition = layerState.clearClientTarget && layerFEState->isOpaque && !firstLayer; ALOGV(" Composition type: client %d clear %d", clientComposition, clearClientComposition); + // If the layer casts a shadow but the content casting the shadow is occluded, skip + // composing the non-shadow content and only draw the shadows. + const bool realContentIsVisible = clientComposition && + !layerState.visibleRegion.subtract(layerState.shadowRegion).isEmpty(); + if (clientComposition || clearClientComposition) { compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ clip, @@ -976,35 +981,21 @@ std::vector Output::generateClientCompositionRequests( outputState.isSecure, supportsProtectedContent, clientComposition ? clearRegion : dummyRegion, + outputState.viewport, + outputDataspace, + realContentIsVisible, + !clientComposition, /* clearContent */ }; - if (std::optional result = - layerFE.prepareClientComposition(targetSettings)) { - if (!clientComposition) { - LayerFE::LayerSettings& layerSettings = *result; - layerSettings.source.buffer.buffer = nullptr; - layerSettings.source.solidColor = half3(0.0, 0.0, 0.0); - layerSettings.alpha = half(0.0); - layerSettings.disableBlending = true; - layerSettings.frameNumber = 0; - } else { - std::optional shadowLayer = - layerFE.prepareShadowClientComposition(*result, outputState.viewport, - outputDataspace); - if (shadowLayer) { - clientCompositionLayers.push_back(*shadowLayer); - } - } - - // If the layer casts a shadow but the content casting the shadow is occluded, skip - // composing the non-shadow content and only draw the shadows. - const bool skipNonShadowContentComposition = clientComposition && - layerState.visibleRegion.subtract(layerState.shadowRegion).isEmpty(); - - if (!skipNonShadowContentComposition) { - layer->editState().clientCompositionTimestamp = systemTime(); - clientCompositionLayers.push_back(*result); - } + std::vector results = + layerFE.prepareClientCompositionList(targetSettings); + if (realContentIsVisible && !results.empty()) { + layer->editState().clientCompositionTimestamp = systemTime(); } + + clientCompositionLayers.insert(clientCompositionLayers.end(), + std::make_move_iterator(results.begin()), + std::make_move_iterator(results.end())); + results.clear(); } firstLayer = false; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 2b450467ed..be0e9e4bc8 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -3425,19 +3425,13 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, gathersClientCompositi LayerFE::LayerSettings mShadowSettings; mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f}; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(_)).WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[1].mLayerSettings)); - EXPECT_CALL(mLayers[1].mLayerFE, - prepareShadowClientComposition(mLayers[1].mLayerSettings, kDisplayViewport, - kDisplayDataspace)) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[2].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, - prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport, - kDisplayDataspace)) - .WillOnce(Return(mShadowSettings)); + EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(_)) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(_)) + .WillOnce(Return(std::vector({mLayers[1].mLayerSettings}))); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_)) + .WillOnce(Return(std::vector( + {mShadowSettings, mLayers[2].mLayerSettings}))); Region accumClearRegion(Rect(10, 11, 12, 13)); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3469,10 +3463,8 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, mLayers[1].mLayerFEState.isOpaque = true; mLayers[2].mLayerFEState.isOpaque = true; - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[2].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _)) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_)) + .WillOnce(Return(std::vector({mLayers[2].mLayerSettings}))); Region accumClearRegion(Rect(10, 11, 12, 13)); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3497,10 +3489,8 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, mLayers[1].mLayerFEState.isOpaque = false; mLayers[2].mLayerFEState.isOpaque = false; - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[2].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _)) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_)) + .WillOnce(Return(std::vector({mLayers[2].mLayerSettings}))); Region accumClearRegion(Rect(10, 11, 12, 13)); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3529,25 +3519,51 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqu mLayers[0].mLayerFEState.isOpaque = true; mLayers[1].mLayerFEState.isOpaque = true; mLayers[2].mLayerFEState.isOpaque = true; + Region accumClearRegion(Rect(10, 11, 12, 13)); + Region dummyRegion; + + compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ + Region(kDisplayFrame), + false, /* identity transform */ + false, /* needs filtering */ + false, /* secure */ + false, /* supports protected content */ + dummyRegion, /* clear region */ + kDisplayViewport, + kDisplayDataspace, + false /* realContentIsVisible */, + true /* clearContent */, + }; + compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ + Region(kDisplayFrame), + false, /* identity transform */ + false, /* needs filtering */ + false, /* secure */ + false, /* supports protected content */ + accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, + }; - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[1].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[2].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _)) - .WillOnce(Return(std::nullopt)); + LayerFE::LayerSettings mBlackoutSettings = mLayers[1].mLayerSettings; + mBlackoutSettings.source.buffer.buffer = nullptr; + mBlackoutSettings.source.solidColor = {0.1f, 0.1f, 0.1f}; + mBlackoutSettings.alpha = 0.f; + mBlackoutSettings.disableBlending = true; + + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::vector({mBlackoutSettings}))); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::vector({mLayers[2].mLayerSettings}))); - Region accumClearRegion(Rect(10, 11, 12, 13)); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, accumClearRegion, kDisplayDataspace); ASSERT_EQ(2u, requests.size()); // The second layer is expected to be rendered as alpha=0 black with no blending - EXPECT_EQ(mLayers[1].mLayerSettings.geometry.boundaries, requests[0].geometry.boundaries); - EXPECT_FALSE(requests[0].source.buffer.buffer); - EXPECT_EQ((half3{0.f, 0.f, 0.f}), requests[0].source.solidColor); - EXPECT_EQ(0.f, static_cast(requests[0].alpha)); - EXPECT_EQ(true, requests[0].disableBlending); + EXPECT_EQ(mBlackoutSettings, requests[0]); EXPECT_EQ(mLayers[2].mLayerSettings, requests[1]); @@ -3569,6 +3585,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(Rect(0, 0, 30, 30)), @@ -3577,6 +3597,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(Rect(0, 0, 40, 201)), @@ -3585,14 +3609,18 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::vector())); static_cast( mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3613,6 +3641,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), @@ -3621,6 +3653,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), @@ -3629,14 +3665,18 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::vector())); static_cast( mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3657,6 +3697,11 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, + }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), @@ -3665,6 +3710,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), @@ -3673,14 +3722,18 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::vector())); static_cast( mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3700,6 +3753,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), @@ -3708,6 +3765,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), @@ -3716,14 +3777,18 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true, /* secure */ false, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::vector())); static_cast( mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, @@ -3741,6 +3806,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ true, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), @@ -3749,6 +3818,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ true, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), @@ -3757,14 +3830,18 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* secure */ true, /* supports protected content */ accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; - EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings)))) - .WillOnce(Return(std::nullopt)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings)))) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings)))) + .WillOnce(Return(std::vector())); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings)))) + .WillOnce(Return(std::vector())); static_cast(mOutput.generateClientCompositionRequests(true /* supportsProtectedContent */, accumClearRegion, @@ -3847,16 +3924,16 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq true, /* secure */ true, /* supports protected content */ accumClearRegion, + kPortraitViewport, + kOutputDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; EXPECT_CALL(leftLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true)); EXPECT_CALL(leftLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false)); - EXPECT_CALL(leftLayer.mLayerFE, prepareClientComposition(Eq(ByRef(leftLayerSettings)))) - .WillOnce(Return(leftLayer.mLayerSettings)); - EXPECT_CALL(leftLayer.mLayerFE, - prepareShadowClientComposition(leftLayer.mLayerSettings, kPortraitViewport, - kOutputDataspace)) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(leftLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(leftLayerSettings)))) + .WillOnce(Return(std::vector({leftLayer.mLayerSettings}))); compositionengine::LayerFE::ClientCompositionTargetSettings rightLayerSettings{ Region(Rect(1000, 0, 2000, 1000)), @@ -3865,16 +3942,16 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq true, /* secure */ true, /* supports protected content */ accumClearRegion, + kPortraitViewport, + kOutputDataspace, + true /* realContentIsVisible */, + false /* clearContent */, }; EXPECT_CALL(rightLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true)); EXPECT_CALL(rightLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false)); - EXPECT_CALL(rightLayer.mLayerFE, prepareClientComposition(Eq(ByRef(rightLayerSettings)))) - .WillOnce(Return(rightLayer.mLayerSettings)); - EXPECT_CALL(rightLayer.mLayerFE, - prepareShadowClientComposition(rightLayer.mLayerSettings, kPortraitViewport, - kOutputDataspace)) - .WillOnce(Return(std::nullopt)); + EXPECT_CALL(rightLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(rightLayerSettings)))) + .WillOnce(Return(std::vector({rightLayer.mLayerSettings}))); constexpr bool supportsProtectedContent = true; auto requests = mOutput.generateClientCompositionRequests(supportsProtectedContent, @@ -3891,6 +3968,20 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, const Region kShadowRegion = Region(kContentWithShadow).subtract(kContent); const Region kPartialShadowRegion = Region(kContentWithShadow).subtract(Rect(40, 40, 60, 80)); + Region accumClearRegion(Rect(10, 11, 12, 13)); + compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{ + Region(Rect(60, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */ + false, /* identity transform */ + false, /* needs filtering */ + false, /* secure */ + false, /* supports protected content */ + accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + false /* realContentIsVisible */, + false /* clearContent */, + }; + LayerFE::LayerSettings mShadowSettings; mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f}; @@ -3899,14 +3990,9 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[2].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, - prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport, - kDisplayDataspace)) - .WillOnce(Return(mShadowSettings)); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings)))) + .WillOnce(Return(std::vector({mShadowSettings}))); - Region accumClearRegion(Rect(10, 11, 12, 13)); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, accumClearRegion, kDisplayDataspace); ASSERT_EQ(1u, requests.size()); @@ -3928,16 +4014,26 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, mLayers[2].mOutputLayerState.visibleRegion = kPartialContentWithPartialShadowRegion; mLayers[2].mOutputLayerState.shadowRegion = kShadowRegion; + Region accumClearRegion(Rect(10, 11, 12, 13)); + compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{ + Region(Rect(50, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */ + false, /* identity transform */ + false, /* needs filtering */ + false, /* secure */ + false, /* supports protected content */ + accumClearRegion, + kDisplayViewport, + kDisplayDataspace, + true /* realContentIsVisible */, + false /* clearContent */, + }; + EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); - EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_)) - .WillOnce(Return(mLayers[2].mLayerSettings)); - EXPECT_CALL(mLayers[2].mLayerFE, - prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport, - kDisplayDataspace)) - .WillOnce(Return(mShadowSettings)); + EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings)))) + .WillOnce(Return(std::vector( + {mShadowSettings, mLayers[2].mLayerSettings}))); - Region accumClearRegion(Rect(10, 11, 12, 13)); auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, accumClearRegion, kDisplayDataspace); ASSERT_EQ(2u, requests.size()); diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp index e928c57929..9d45e333d8 100644 --- a/services/surfaceflinger/EffectLayer.cpp +++ b/services/surfaceflinger/EffectLayer.cpp @@ -47,18 +47,35 @@ EffectLayer::EffectLayer(const LayerCreationArgs& args) EffectLayer::~EffectLayer() = default; -std::optional EffectLayer::prepareClientComposition( +std::vector EffectLayer::prepareClientCompositionList( compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { - auto result = Layer::prepareClientComposition(targetSettings); - if (!result) { - return result; + std::vector results; + std::optional layerSettings = + prepareClientComposition(targetSettings); + // Nothing to render. + if (!layerSettings) { + return {}; } - result->source.solidColor = getColor().rgb; - return result; + + std::optional shadowSettings = + prepareShadowClientComposition(*layerSettings, targetSettings.viewport, + targetSettings.dataspace); + if (shadowSettings) { + results.push_back(*shadowSettings); + } + + // If fill bounds are occluded or the fill color is invalid skip the fill settings. + if (targetSettings.realContentIsVisible && fillsColor()) { + // Set color for color fill settings. + layerSettings->source.solidColor = getColor().rgb; + results.push_back(*layerSettings); + } + + return results; } bool EffectLayer::isVisible() const { - return !isHiddenByPolicy() && getAlpha() > 0.0_hf; + return !isHiddenByPolicy() && getAlpha() > 0.0_hf && hasSomethingToDraw(); } bool EffectLayer::setColor(const half3& color) { @@ -126,6 +143,11 @@ sp EffectLayer::createClone() { return layer; } +bool EffectLayer::fillsColor() const { + return mDrawingState.color.r >= 0.0_hf && mDrawingState.color.g >= 0.0_hf && + mDrawingState.color.b >= 0.0_hf; +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/EffectLayer.h b/services/surfaceflinger/EffectLayer.h index 8694283760..33758b6378 100644 --- a/services/surfaceflinger/EffectLayer.h +++ b/services/surfaceflinger/EffectLayer.h @@ -52,12 +52,17 @@ protected: */ const compositionengine::LayerFECompositionState* getCompositionState() const override; void preparePerFrameCompositionState() override; - std::optional prepareClientComposition( - compositionengine::LayerFE::ClientCompositionTargetSettings&) override; + std::vector prepareClientCompositionList( + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) override; std::unique_ptr mCompositionState; sp createClone() override; + +private: + // Returns true if there is a valid color to fill. + bool fillsColor() const; + bool hasSomethingToDraw() const { return fillsColor() || drawShadows(); } }; } // namespace android diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 8eb5c22fa8..5073a9231b 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -492,13 +492,12 @@ void Layer::preparePerFrameCompositionState() { compositionState->hasProtectedContent = isProtected(); const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f; - const bool drawsShadows = mEffectiveShadowRadius != 0.f; 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) { + if (isHdrY410() || usesRoundedCorners || drawShadows()) { compositionState->forceClientComposition = true; } } @@ -653,6 +652,49 @@ std::optional Layer::prepareShadowCli return shadowLayer; } +void Layer::prepareClearClientComposition(LayerFE::LayerSettings& layerSettings, + bool blackout) const { + layerSettings.source.buffer.buffer = nullptr; + layerSettings.source.solidColor = half3(0.0, 0.0, 0.0); + layerSettings.disableBlending = true; + layerSettings.frameNumber = 0; + + // If layer is blacked out, force alpha to 1 so that we draw a black color layer. + layerSettings.alpha = blackout ? 1.0f : 0.0f; +} + +std::vector Layer::prepareClientCompositionList( + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { + std::optional layerSettings = + prepareClientComposition(targetSettings); + // Nothing to render. + if (!layerSettings) { + return {}; + } + + // HWC requests to clear this layer. + if (targetSettings.clearContent) { + prepareClearClientComposition(*layerSettings, false /* blackout */); + return {*layerSettings}; + } + + std::optional shadowSettings = + prepareShadowClientComposition(*layerSettings, targetSettings.viewport, + targetSettings.dataspace); + // There are no shadows to render. + if (!shadowSettings) { + return {*layerSettings}; + } + + // If the layer casts a shadow but the content casting the shadow is occluded, skip + // composing the non-shadow content and only draw the shadows. + if (targetSettings.realContentIsVisible) { + return {*shadowSettings, *layerSettings}; + } + + return {*shadowSettings}; +} + Hwc2::IComposerClient::Composition Layer::getCompositionType( const sp& display) const { const auto outputLayer = findOutputLayerForDisplay(display); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index a249726739..1689881c8d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -552,6 +552,14 @@ protected: void updateClonedRelatives(const std::map, sp>& clonedLayersMap); void addChildToDrawing(const sp& layer); void updateClonedInputInfo(const std::map, sp>& clonedLayersMap); + virtual std::optional prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings&); + virtual std::optional prepareShadowClientComposition( + const LayerFE::LayerSettings& layerSettings, const Rect& displayViewport, + ui::Dataspace outputDataspace); + // Modifies the passed in layer settings to clear the contents. If the blackout flag is set, + // the settings clears the content with a solid black fill. + void prepareClearClientComposition(LayerFE::LayerSettings& layerSettings, bool blackout) const; public: /* @@ -560,11 +568,8 @@ public: const compositionengine::LayerFECompositionState* getCompositionState() const override; bool onPreComposition(nsecs_t) override; void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override; - std::optional prepareClientComposition( + std::vector prepareClientCompositionList( compositionengine::LayerFE::ClientCompositionTargetSettings&) override; - std::optional prepareShadowClientComposition( - const LayerFE::LayerSettings& layerSettings, const Rect& displayViewport, - ui::Dataspace outputDataspace) override; void onLayerDisplayed(const sp& releaseFence) override; const char* getDebugName() const override; @@ -704,6 +709,7 @@ public: half getAlpha() const; half4 getColor() const; int32_t getBackgroundBlurRadius() const; + bool drawShadows() const { return mEffectiveShadowRadius > 0.f; }; // Returns how rounded corners should be drawn for this layer. // This will traverse the hierarchy until it reaches its root, finding topmost rounded diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 55166c0ab3..ff4a6529fa 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5545,17 +5545,18 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, renderArea.isSecure(), supportProtectedContent, clearRegion, + displayViewport, + clientCompositionDisplay.outputDataspace, + true, /* realContentIsVisible */ + false, /* clearContent */ }; - auto result = layer->prepareClientComposition(targetSettings); - if (result) { - std::optional shadowLayer = - layer->prepareShadowClientComposition(*result, displayViewport, - clientCompositionDisplay.outputDataspace); - if (shadowLayer) { - clientCompositionLayers.push_back(*shadowLayer); - } - clientCompositionLayers.push_back(*result); - } + std::vector results = + layer->prepareClientCompositionList(targetSettings); + clientCompositionLayers.insert(clientCompositionLayers.end(), + std::make_move_iterator(results.begin()), + std::make_move_iterator(results.end())); + results.clear(); + }); std::vector clientCompositionLayerPointers; diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index 6c8eb27bd0..83e5060830 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -747,12 +747,26 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) { ISurfaceComposerClient::eFXSurfaceEffect)); Transaction() .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) - .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f)) + .setColor(colorLayer, half3(2.0f, 0.0f, 0.0f)) .apply(); getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); } +// An invalid color will not render a color and the layer will not be visible. +TEST_P(LayerRenderTypeTransactionTest, SetInvalidColor) { + sp colorLayer; + ASSERT_NO_FATAL_FAILURE(colorLayer = + createLayer("test", 0 /* buffer width */, 0 /* buffer height */, + ISurfaceComposerClient::eFXSurfaceEffect)); + Transaction() + .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) + .setColor(colorLayer, half3(1.0f, -1.0f, 0.5f)) + .apply(); + + getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); +} + TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) { sp bufferLayer; sp colorLayer; -- GitLab From e908789636ec55c04d9e00c406520b5cab19007a Mon Sep 17 00:00:00 2001 From: Gang Wang Date: Tue, 7 Jan 2020 12:17:14 -0500 Subject: [PATCH 0805/1255] Use hmac to sign events in InputDispatcher InputDispatcher will now be able to sign events. Add two static methods to InputDispatcher class, for signing events, and for checking the event signature. The new methods can verify whether a MotionEntry object was actually created by the Input system and whether the MotionEntry object was modified afterwards. Bug: 134977432 Test: none Change-Id: Ica11bccd0c3fb065b02634bd236ae5a46f6b19ee --- services/inputflinger/benchmarks/Android.bp | 1 + services/inputflinger/dispatcher/Entry.cpp | 26 +++++++++++ services/inputflinger/dispatcher/Entry.h | 3 ++ .../dispatcher/InputDispatcher.cpp | 45 +++++++++++++++++-- .../inputflinger/dispatcher/InputDispatcher.h | 2 + .../tests/InputDispatcher_test.cpp | 38 ++++++++++++++++ 6 files changed, 112 insertions(+), 3 deletions(-) diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp index 385b9816bd..066a816069 100644 --- a/services/inputflinger/benchmarks/Android.bp +++ b/services/inputflinger/benchmarks/Android.bp @@ -7,6 +7,7 @@ cc_benchmark { shared_libs: [ "libbase", "libbinder", + "libcrypto", "libcutils", "libinput", "libinputflinger_base", diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index b7236547de..c4b3789090 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -57,6 +57,32 @@ static std::string keyActionToString(int32_t action) { } return StringPrintf("%" PRId32, action); } +VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry) { + return {{VerifiedInputEvent::Type::KEY, entry.deviceId, entry.eventTime, entry.source, + entry.displayId}, + entry.action, + entry.downTime, + entry.flags & VERIFIED_KEY_EVENT_FLAGS, + entry.keyCode, + entry.scanCode, + entry.metaState, + entry.repeatCount}; +} + +VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry) { + const float rawX = entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X); + const float rawY = entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y); + const int actionMasked = entry.action & AMOTION_EVENT_ACTION_MASK; + return {{VerifiedInputEvent::Type::MOTION, entry.deviceId, entry.eventTime, entry.source, + entry.displayId}, + rawX, + rawY, + actionMasked, + entry.downTime, + entry.flags & VERIFIED_MOTION_EVENT_FLAGS, + entry.metaState, + entry.buttonState}; +} // --- EventEntry --- diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index e8c37f0e6e..b5b61ccb98 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -220,6 +220,9 @@ private: static uint32_t nextSeq(); }; +VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry); +VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry); + class InputDispatcher; // A command entry captures state and behavior for an action to be performed in the // dispatch loop after the initial processing has taken place. It is essentially diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 75bc0aa7c8..f9a86dd6bb 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2433,12 +2433,16 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, switch (eventEntry->type) { case EventEntry::Type::KEY: { KeyEntry* keyEntry = static_cast(eventEntry); + VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEntry(*keyEntry); + verifiedEvent.flags = dispatchEntry->resolvedFlags & VERIFIED_KEY_EVENT_FLAGS; + verifiedEvent.action = dispatchEntry->resolvedAction; + std::array hmac = mHmacKeyManager.sign(verifiedEvent); // Publish the key event. status = connection->inputPublisher .publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId, keyEntry->source, keyEntry->displayId, - INVALID_HMAC, dispatchEntry->resolvedAction, + std::move(hmac), dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, keyEntry->keyCode, keyEntry->scanCode, keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, @@ -2482,12 +2486,18 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, usingCoords = scaledCoords; } } + VerifiedMotionEvent verifiedEvent = + verifiedMotionEventFromMotionEntry(*motionEntry); + verifiedEvent.actionMasked = + dispatchEntry->resolvedAction & AMOTION_EVENT_ACTION_MASK; + verifiedEvent.flags = dispatchEntry->resolvedFlags & VERIFIED_MOTION_EVENT_FLAGS; + std::array hmac = mHmacKeyManager.sign(verifiedEvent); // Publish the motion event. status = connection->inputPublisher .publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, motionEntry->source, motionEntry->displayId, - INVALID_HMAC, dispatchEntry->resolvedAction, + std::move(hmac), dispatchEntry->resolvedAction, motionEntry->actionButton, dispatchEntry->resolvedFlags, motionEntry->edgeFlags, motionEntry->metaState, @@ -3392,7 +3402,36 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec } std::unique_ptr InputDispatcher::verifyInputEvent(const InputEvent& event) { - return nullptr; + std::array calculatedHmac; + std::unique_ptr result; + switch (event.getType()) { + case AINPUT_EVENT_TYPE_KEY: { + const KeyEvent& keyEvent = static_cast(event); + VerifiedKeyEvent verifiedKeyEvent = verifiedKeyEventFromKeyEvent(keyEvent); + result = std::make_unique(verifiedKeyEvent); + calculatedHmac = mHmacKeyManager.sign(verifiedKeyEvent); + break; + } + case AINPUT_EVENT_TYPE_MOTION: { + const MotionEvent& motionEvent = static_cast(event); + VerifiedMotionEvent verifiedMotionEvent = + verifiedMotionEventFromMotionEvent(motionEvent); + result = std::make_unique(verifiedMotionEvent); + calculatedHmac = mHmacKeyManager.sign(verifiedMotionEvent); + break; + } + default: { + ALOGE("Cannot verify events of type %" PRId32, event.getType()); + return nullptr; + } + } + if (calculatedHmac == INVALID_HMAC) { + return nullptr; + } + if (calculatedHmac != event.getHmac()) { + return nullptr; + } + return result; } bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index ded59a595c..482133ee90 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -217,6 +217,8 @@ private: // the pointer stream in order to claim it for a system gesture. std::unordered_map> mGestureMonitorsByDisplay GUARDED_BY(mLock); + HmacKeyManager mHmacKeyManager; + // Event injection and synchronization. std::condition_variable mInjectionResultAvailable; bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index c4092cd696..2fb1b65d93 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1398,6 +1398,44 @@ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) { window->assertNoEvents(); } +TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { + sp application = new FakeApplicationHandle(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + window->setFocus(true); + + mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/); + + NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN); + mDispatcher->notifyKey(&keyArgs); + + InputEvent* event = window->consume(); + ASSERT_NE(event, nullptr); + + std::unique_ptr verified = mDispatcher->verifyInputEvent(*event); + ASSERT_NE(verified, nullptr); + ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY); + + ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos); + ASSERT_EQ(keyArgs.deviceId, verified->deviceId); + ASSERT_EQ(keyArgs.source, verified->source); + ASSERT_EQ(keyArgs.displayId, verified->displayId); + + const VerifiedKeyEvent& verifiedKey = static_cast(*verified); + + ASSERT_EQ(keyArgs.action, verifiedKey.action); + ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos); + ASSERT_EQ(keyArgs.eventTime, verifiedKey.eventTimeNanos); + ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags); + ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode); + ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode); + ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState); + ASSERT_EQ(0, verifiedKey.repeatCount); +} + /* Test InputDispatcher for MultiDisplay */ class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest { public: -- GitLab From ef0b153009c04608ac2316d247ab70009c338e9c Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 17 Dec 2019 09:39:07 -0800 Subject: [PATCH 0806/1255] [ANativeWindow] Add getLastQueuedBuffer api Bug: 137012798 Bug: 148962594 Test: builds Change-Id: I3dcf6741c8d5dc62b7ae13d5cf5dc56173f95660 --- libs/gui/Surface.cpp | 27 ++++++++++++++++++++ libs/gui/include/gui/Surface.h | 1 + libs/nativewindow/include/system/window.h | 31 +++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 23532e7e38..278cc593b7 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1180,6 +1180,9 @@ int Surface::perform(int operation, va_list args) allocateBuffers(); res = NO_ERROR; break; + case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER: + res = dispatchGetLastQueuedBuffer(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1452,6 +1455,30 @@ int Surface::dispatchAddQueueInterceptor(va_list args) { return NO_ERROR; } +int Surface::dispatchGetLastQueuedBuffer(va_list args) { + AHardwareBuffer** buffer = va_arg(args, AHardwareBuffer**); + int* fence = va_arg(args, int*); + float* matrix = va_arg(args, float*); + sp graphicBuffer; + sp spFence; + + int result = mGraphicBufferProducer->getLastQueuedBuffer(&graphicBuffer, &spFence, matrix); + + if (graphicBuffer != nullptr) { + *buffer = reinterpret_cast(graphicBuffer.get()); + AHardwareBuffer_acquire(*buffer); + } else { + *buffer = nullptr; + } + + if (spFence != nullptr) { + *fence = spFence->dup(); + } else { + *fence = -1; + } + return result; +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 0139507101..4a353fc659 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -262,6 +262,7 @@ private: int dispatchAddDequeueInterceptor(va_list args); int dispatchAddPerformInterceptor(va_list args); int dispatchAddQueueInterceptor(va_list args); + int dispatchGetLastQueuedBuffer(va_list args); bool transformToDisplayInverse(); protected: diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 121374b1d5..f686147a5f 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -253,6 +253,7 @@ enum { NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR = 43, /* private */ NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR = 44, /* private */ NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */ + NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */ // clang-format on }; @@ -1018,4 +1019,34 @@ static inline int native_window_set_frame_rate(struct ANativeWindow* window, flo return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate); } +// ------------------------------------------------------------------------------------------------ +// Candidates for APEX visibility +// These functions are planned to be made stable for APEX modules, but have not +// yet been stabilized to a specific api version. +// ------------------------------------------------------------------------------------------------ + +/** + * Retrieves the last queued buffer for this window, along with the fence that + * fires when the buffer is ready to be read, and the 4x4 coordinate + * transform matrix that should be applied to the buffer's content. The + * transform matrix is represented in column-major order. + * + * If there was no buffer previously queued, then outBuffer will be NULL and + * the value of outFence will be -1. + * + * Note that if outBuffer is not NULL, then the caller will hold a reference + * onto the buffer. Accordingly, the caller must call AHardwareBuffer_release + * when the buffer is no longer needed so that the system may reclaim the + * buffer. + * + * \return NO_ERROR on success. + * \return NO_MEMORY if there was insufficient memory. + */ +static inline int ANativeWindow_getLastQueuedBuffer(ANativeWindow* window, + AHardwareBuffer** outBuffer, int* outFence, + float outTransformMatrix[16]) { + return window->perform(window, NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER, outBuffer, outFence, + outTransformMatrix); +} + __END_DECLS -- GitLab From 65b8e8729104d4f7a379d72cdff06036b569dd9b Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Thu, 13 Feb 2020 09:45:14 -0800 Subject: [PATCH 0807/1255] Move maxAcquired back to 1 and set maxDequeued BufferQueue internally already limits number of acquired buffers to be 1 more than the maxAcquired set. We want to be able to acquire 2, so setting back to 1. Enable triple buffering through maxDequeuedCount. Bug: 146345307 Test: build, boot, turn BLAST ON, run manually, libgui_test Change-Id: I1deff382da3b37a2bde840802fdc4c10a8b868ed --- libs/gui/BLASTBufferQueue.cpp | 10 ++++++++-- libs/gui/include/gui/BLASTBufferQueue.h | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index e2f5d31d00..4bbc855642 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -19,6 +19,8 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include + #include #include #include @@ -99,7 +101,11 @@ BLASTBufferQueue::BLASTBufferQueue(const sp& surface, int width, mHeight(height), mNextTransaction(nullptr) { BufferQueue::createBufferQueue(&mProducer, &mConsumer); - mConsumer->setMaxAcquiredBufferCount(MAX_ACQUIRED_BUFFERS); + + int8_t disableTripleBuffer = property_get_bool("ro.sf.disable_triple_buffer", 0); + if (!disableTripleBuffer) { + mProducer->setMaxDequeuedBufferCount(2); + } mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true); static int32_t id = 0; @@ -181,7 +187,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp Date: Tue, 11 Feb 2020 12:06:56 -0800 Subject: [PATCH 0808/1255] [sf] Add support for generic layer metadata to HWComposer and HWC2 HWComposer construction is slightly modified to make it easier to test. Data is retrieved about the device on the call SurfaceFlinger makes right after creaton (was registerCallbacks, now called setConfiguration). This now includes obtaining the supported layer metadata information from the HAL implementation. Since getting capabilities is now no longer done by just construction, the existing tests were adjusted to not expect the call, especially as none of them were testing any variance in capabilities. A HWC2::Layer::setLayerGenericMetadata function is also added to set the metadata. Tests are explicitly added for both retrieving the supported metadata and for setting layer generic metadata. Bug: 139747351 Test: atest libsurfaceflinger_unittest Change-Id: I3e95be932d94d4e9f200b870acea965744c68d2c --- .../CompositionEngine/tests/MockHWC2.h | 2 + .../CompositionEngine/tests/MockHWComposer.h | 4 +- .../surfaceflinger/DisplayHardware/HWC2.cpp | 18 +- .../surfaceflinger/DisplayHardware/HWC2.h | 11 +- .../DisplayHardware/HWComposer.cpp | 28 ++- .../DisplayHardware/HWComposer.h | 15 +- services/surfaceflinger/SurfaceFlinger.cpp | 5 +- .../surfaceflinger/tests/unittests/Android.bp | 1 + .../tests/unittests/CompositionTest.cpp | 2 - .../unittests/DisplayTransactionTest.cpp | 2 - .../tests/unittests/HWComposerTest.cpp | 176 ++++++++++++++++++ .../unittests/RefreshRateSelectionTest.cpp | 2 - 12 files changed, 243 insertions(+), 23 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/HWComposerTest.cpp diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h index a51cc67b1d..be89c1adb4 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h @@ -65,6 +65,8 @@ public: MOCK_METHOD2(setInfo, Error(uint32_t, uint32_t)); MOCK_METHOD1(setColorTransform, Error(const android::mat4&)); + MOCK_METHOD3(setLayerGenericMetadata, + Error(const std::string&, bool, const std::vector&)); }; } // namespace mock diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index 502a33fe28..9995ce1895 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -36,7 +36,7 @@ public: HWComposer(); ~HWComposer() override; - MOCK_METHOD2(registerCallback, void(HWC2::ComposerCallback*, int32_t)); + MOCK_METHOD2(setConfiguration, void(HWC2::ComposerCallback*, int32_t)); MOCK_CONST_METHOD3(getDisplayIdentificationData, bool(hwc2_display_t, uint8_t*, DisplayIdentificationData*)); MOCK_CONST_METHOD1(hasCapability, bool(HWC2::Capability)); @@ -96,6 +96,8 @@ public: MOCK_METHOD2(setAutoLowLatencyMode, status_t(DisplayId, bool)); MOCK_METHOD2(getSupportedContentTypes, status_t(DisplayId, std::vector*)); MOCK_METHOD2(setContentType, status_t(DisplayId, HWC2::ContentType)); + MOCK_CONST_METHOD0(getSupportedLayerGenericMetadata, + const std::unordered_map&()); MOCK_CONST_METHOD1(dump, void(std::string&)); MOCK_CONST_METHOD0(getComposer, android::Hwc2::Composer*()); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 41e787980a..e8bf2d8294 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -734,12 +734,11 @@ namespace impl { Layer::Layer(android::Hwc2::Composer& composer, const std::unordered_set& capabilities, hwc2_display_t displayId, hwc2_layer_t layerId) - : mComposer(composer), - mCapabilities(capabilities), - mDisplayId(displayId), - mId(layerId), - mColorMatrix(android::mat4()) -{ + : mComposer(composer), + mCapabilities(capabilities), + mDisplayId(displayId), + mId(layerId), + mColorMatrix(android::mat4()) { ALOGV("Created layer %" PRIu64 " on display %" PRIu64, layerId, displayId); } @@ -979,6 +978,13 @@ Error Layer::setColorTransform(const android::mat4& matrix) { return error; } +// Composer HAL 2.4 +Error Layer::setLayerGenericMetadata(const std::string& name, bool mandatory, + const std::vector& value) { + auto intError = mComposer.setLayerGenericMetadata(mDisplayId, mId, name, mandatory, value); + return static_cast(intError); +} + } // namespace impl } // namespace HWC2 diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index e7cf5ffc2d..5804903e1f 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -374,6 +374,10 @@ public: // Composer HAL 2.3 [[clang::warn_unused_result]] virtual Error setColorTransform(const android::mat4& matrix) = 0; + + // Composer HAL 2.4 + [[clang::warn_unused_result]] virtual Error setLayerGenericMetadata( + const std::string& name, bool mandatory, const std::vector& value) = 0; }; namespace impl { @@ -382,8 +386,7 @@ namespace impl { class Layer : public HWC2::Layer { public: - Layer(android::Hwc2::Composer& composer, - const std::unordered_set& capabilities, + Layer(android::Hwc2::Composer& composer, const std::unordered_set& capabilities, hwc2_display_t displayId, hwc2_layer_t layerId); ~Layer() override; @@ -412,6 +415,10 @@ public: // Composer HAL 2.3 Error setColorTransform(const android::mat4& matrix) override; + // Composer HAL 2.4 + Error setLayerGenericMetadata(const std::string& name, bool mandatory, + const std::vector& value) override; + private: // These are references to data owned by HWC2::Device, which will outlive // this HWC2::Layer, so these references are guaranteed to be valid for diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index f8d45c0e57..bb6f696f20 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -148,20 +148,20 @@ HWComposer::~HWComposer() = default; namespace impl { HWComposer::HWComposer(std::unique_ptr composer) : mComposer(std::move(composer)) { - loadCapabilities(); } HWComposer::HWComposer(const std::string& composerServiceName) : mComposer(std::make_unique(composerServiceName)) { - loadCapabilities(); } HWComposer::~HWComposer() { mDisplayData.clear(); } -void HWComposer::registerCallback(HWC2::ComposerCallback* callback, - int32_t sequenceId) { +void HWComposer::setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) { + loadCapabilities(); + loadLayerMetadataSupport(); + if (mRegisteredCallback) { ALOGW("Callback already registered. Ignored extra registration attempt."); return; @@ -871,6 +871,10 @@ status_t HWComposer::setContentType(DisplayId displayId, HWC2::ContentType conte return NO_ERROR; } +const std::unordered_map& HWComposer::getSupportedLayerGenericMetadata() const { + return mSupportedLayerGenericMetadata; +} + void HWComposer::dump(std::string& result) const { result.append(mComposer->dumpDebugInfo()); } @@ -946,6 +950,22 @@ void HWComposer::loadCapabilities() { } } +void HWComposer::loadLayerMetadataSupport() { + mSupportedLayerGenericMetadata.clear(); + + std::vector supportedMetadataKeyInfo; + const auto error = mComposer->getLayerGenericMetadataKeys(&supportedMetadataKeyInfo); + if (error != hardware::graphics::composer::V2_4::Error::NONE) { + ALOGE("%s: %s failed: %s (%d)", __FUNCTION__, "getLayerGenericMetadataKeys", + toString(error).c_str(), static_cast(error)); + return; + } + + for (const auto& [name, mandatory] : supportedMetadataKeyInfo) { + mSupportedLayerGenericMetadata.emplace(name, mandatory); + } +} + uint32_t HWComposer::getMaxVirtualDisplayCount() const { return mComposer->getMaxVirtualDisplayCount(); } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index effe43b548..76e831be54 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -55,11 +55,16 @@ namespace compositionengine { class Output; } // namespace compositionengine +struct KnownHWCGenericLayerMetadata { + const char* name; + const uint32_t id; +}; + class HWComposer { public: virtual ~HWComposer(); - virtual void registerCallback(HWC2::ComposerCallback* callback, int32_t sequenceId) = 0; + virtual void setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) = 0; virtual bool getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort, DisplayIdentificationData* outData) const = 0; @@ -194,6 +199,8 @@ public: virtual status_t getSupportedContentTypes( DisplayId displayId, std::vector* outSupportedContentTypes) = 0; virtual status_t setContentType(DisplayId displayId, HWC2::ContentType contentType) = 0; + virtual const std::unordered_map& getSupportedLayerGenericMetadata() + const = 0; // for debugging ---------------------------------------------------------- virtual void dump(std::string& out) const = 0; @@ -217,7 +224,7 @@ public: ~HWComposer() override; - void registerCallback(HWC2::ComposerCallback* callback, int32_t sequenceId) override; + void setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) override; bool getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort, DisplayIdentificationData* outData) const override; @@ -329,6 +336,8 @@ public: std::vector*) override; status_t setContentType(DisplayId displayId, HWC2::ContentType) override; + const std::unordered_map& getSupportedLayerGenericMetadata() const override; + // for debugging ---------------------------------------------------------- void dump(std::string& out) const override; @@ -351,6 +360,7 @@ private: std::optional onHotplugConnect(hwc2_display_t hwcDisplayId); void loadCapabilities(); + void loadLayerMetadataSupport(); uint32_t getMaxVirtualDisplayCount() const; struct DisplayData { @@ -379,6 +389,7 @@ private: std::unique_ptr mComposer; std::unordered_set mCapabilities; + std::unordered_map mSupportedLayerGenericMetadata; bool mRegisteredCallback = false; std::unordered_map mPhysicalDisplayIdMap; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f81179a3e2..7ed6342dd9 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -622,7 +623,7 @@ void SurfaceFlinger::init() { LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay, "Starting with vr flinger active is not currently supported."); mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName)); - mCompositionEngine->getHwComposer().registerCallback(this, getBE().mComposerSequenceId); + mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId); // Process any initial hotplug and resulting display changes. processDisplayHotplugEventsLocked(); const auto display = getDefaultDisplayDeviceLocked(); @@ -1682,7 +1683,7 @@ void SurfaceFlinger::updateVrFlinger() { mCompositionEngine->setHwComposer(std::unique_ptr()); mCompositionEngine->setHwComposer(getFactory().createHWComposer( vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName)); - getHwComposer().registerCallback(this, ++getBE().mComposerSequenceId); + mCompositionEngine->getHwComposer().setConfiguration(this, ++getBE().mComposerSequenceId); LOG_ALWAYS_FATAL_IF(!getHwComposer().getComposer()->isRemote(), "Switched to non-remote hardware composer"); diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index d046f765e8..1cd8731fa9 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -42,6 +42,7 @@ cc_test { "DisplayTransactionTest.cpp", "EventControlThreadTest.cpp", "EventThreadTest.cpp", + "HWComposerTest.cpp", "OneShotTimerTest.cpp", "LayerHistoryTest.cpp", "LayerHistoryTestV2.cpp", diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 888e009282..b41131b39f 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -116,8 +116,6 @@ public: void setupComposer(int virtualDisplayCount) { mComposer = new Hwc2::mock::Composer(); - EXPECT_CALL(*mComposer, getCapabilities()) - .WillOnce(Return(std::vector())); EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); mFlinger.setupComposer(std::unique_ptr(mComposer)); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index dddad92f79..232255f548 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -201,8 +201,6 @@ void DisplayTransactionTest::injectMockScheduler() { void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) { mComposer = new Hwc2::mock::Composer(); - EXPECT_CALL(*mComposer, getCapabilities()) - .WillOnce(Return(std::vector())); EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); mFlinger.setupComposer(std::unique_ptr(mComposer)); diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp new file mode 100644 index 0000000000..c6fe205006 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -0,0 +1,176 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include + +#include +#include +#include + +#include "DisplayHardware/HWComposer.h" +#include "mock/DisplayHardware/MockComposer.h" + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" + +namespace android { +namespace { + +using ::testing::_; +using ::testing::DoAll; +using ::testing::ElementsAreArray; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::StrictMock; + +struct MockHWC2ComposerCallback : public HWC2::ComposerCallback { + ~MockHWC2ComposerCallback() = default; + + MOCK_METHOD3(onHotplugReceived, + void(int32_t sequenceId, hwc2_display_t display, HWC2::Connection connection)); + MOCK_METHOD2(onRefreshReceived, void(int32_t sequenceId, hwc2_display_t display)); + MOCK_METHOD4(onVsyncReceived, + void(int32_t sequenceId, hwc2_display_t display, int64_t timestamp, + std::optional vsyncPeriod)); + MOCK_METHOD3(onVsyncPeriodTimingChangedReceived, + void(int32_t sequenceId, hwc2_display_t display, + const hwc_vsync_period_change_timeline_t& updatedTimeline)); + MOCK_METHOD2(onSeamlessPossible, void(int32_t sequenceId, hwc2_display_t display)); +}; + +struct HWComposerTest : public testing::Test { + Hwc2::mock::Composer* mHal = new StrictMock(); +}; + +struct HWComposerSetConfigurationTest : public HWComposerTest { + StrictMock mCallback; +}; + +TEST_F(HWComposerSetConfigurationTest, loadsLayerMetadataSupport) { + const std::string kMetadata1Name = "com.example.metadata.1"; + constexpr bool kMetadata1Mandatory = false; + const std::string kMetadata2Name = "com.example.metadata.2"; + constexpr bool kMetadata2Mandatory = true; + + EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0)); + EXPECT_CALL(*mHal, getCapabilities()) + .WillOnce(Return(std::vector{})); + EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_)) + .WillOnce(DoAll(SetArgPointee<0>( + std::vector{ + {kMetadata1Name, kMetadata1Mandatory}, + {kMetadata2Name, kMetadata2Mandatory}, + }), + Return(hardware::graphics::composer::V2_4::Error::NONE))); + EXPECT_CALL(*mHal, registerCallback(_)); + EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false)); + + impl::HWComposer hwc{std::unique_ptr(mHal)}; + hwc.setConfiguration(&mCallback, 123); + + const auto& supported = hwc.getSupportedLayerGenericMetadata(); + EXPECT_EQ(2u, supported.size()); + EXPECT_EQ(1u, supported.count(kMetadata1Name)); + EXPECT_EQ(kMetadata1Mandatory, supported.find(kMetadata1Name)->second); + EXPECT_EQ(1u, supported.count(kMetadata2Name)); + EXPECT_EQ(kMetadata2Mandatory, supported.find(kMetadata2Name)->second); +} + +TEST_F(HWComposerSetConfigurationTest, handlesUnsupportedCallToGetLayerGenericMetadataKeys) { + EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0)); + EXPECT_CALL(*mHal, getCapabilities()) + .WillOnce(Return(std::vector{})); + EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_)) + .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED)); + EXPECT_CALL(*mHal, registerCallback(_)); + EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false)); + + impl::HWComposer hwc{std::unique_ptr(mHal)}; + hwc.setConfiguration(&mCallback, 123); + + const auto& supported = hwc.getSupportedLayerGenericMetadata(); + EXPECT_EQ(0u, supported.size()); +} + +struct HWComposerLayerTest : public testing::Test { + static constexpr hwc2_display_t kDisplayId = static_cast(1001); + static constexpr hwc2_layer_t kLayerId = static_cast(1002); + + HWComposerLayerTest(const std::unordered_set& capabilities) + : mCapabilies(capabilities) {} + + ~HWComposerLayerTest() override { EXPECT_CALL(*mHal, destroyLayer(kDisplayId, kLayerId)); } + + std::unique_ptr mHal{new StrictMock()}; + const std::unordered_set mCapabilies; + HWC2::impl::Layer mLayer{*mHal, mCapabilies, kDisplayId, kLayerId}; +}; + +struct HWComposerLayerGenericMetadataTest : public HWComposerLayerTest { + static const std::string kLayerGenericMetadata1Name; + static constexpr bool kLayerGenericMetadata1Mandatory = false; + static const std::vector kLayerGenericMetadata1Value; + static const std::string kLayerGenericMetadata2Name; + static constexpr bool kLayerGenericMetadata2Mandatory = true; + static const std::vector kLayerGenericMetadata2Value; + + HWComposerLayerGenericMetadataTest() : HWComposerLayerTest({}) {} +}; + +const std::string HWComposerLayerGenericMetadataTest::kLayerGenericMetadata1Name = + "com.example.metadata.1"; + +const std::vector HWComposerLayerGenericMetadataTest::kLayerGenericMetadata1Value = {1u, + 2u, + 3u}; + +const std::string HWComposerLayerGenericMetadataTest::kLayerGenericMetadata2Name = + "com.example.metadata.2"; + +const std::vector HWComposerLayerGenericMetadataTest::kLayerGenericMetadata2Value = {45u, + 67u}; + +TEST_F(HWComposerLayerGenericMetadataTest, forwardsSupportedMetadata) { + EXPECT_CALL(*mHal, + setLayerGenericMetadata(kDisplayId, kLayerId, kLayerGenericMetadata1Name, + kLayerGenericMetadata1Mandatory, + kLayerGenericMetadata1Value)) + .WillOnce(Return(hardware::graphics::composer::V2_4::Error::NONE)); + auto result = mLayer.setLayerGenericMetadata(kLayerGenericMetadata1Name, + kLayerGenericMetadata1Mandatory, + kLayerGenericMetadata1Value); + EXPECT_EQ(HWC2::Error::None, result); + + EXPECT_CALL(*mHal, + setLayerGenericMetadata(kDisplayId, kLayerId, kLayerGenericMetadata2Name, + kLayerGenericMetadata2Mandatory, + kLayerGenericMetadata2Value)) + .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED)); + result = mLayer.setLayerGenericMetadata(kLayerGenericMetadata2Name, + kLayerGenericMetadata2Mandatory, + kLayerGenericMetadata2Value); + EXPECT_EQ(HWC2::Error::Unsupported, result); +} + +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp index cffdc14df7..d8e8724f5f 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp @@ -153,8 +153,6 @@ void RefreshRateSelectionTest::setupScheduler() { void RefreshRateSelectionTest::setupComposer(int virtualDisplayCount) { mComposer = new Hwc2::mock::Composer(); - EXPECT_CALL(*mComposer, getCapabilities()) - .WillOnce(Return(std::vector())); EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); mFlinger.setupComposer(std::unique_ptr(mComposer)); -- GitLab From 8d9f836d54548199c397b63e5ab12e7e46d72b19 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Tue, 11 Feb 2020 19:13:09 -0800 Subject: [PATCH 0809/1255] [sf] Pass metadata to layer during composition Adds the simple bits of code to grab a snapshot of the front-end Layer generic metadata, storing a copy in LayerFECompositionState, and then sending int to the HWC2::Layer along with other "geometry update" settings. As the metadata stored in the layers uses integer keys, they need to be translated to name strings. For hard-coded mapping is defined, with a TODO left to remove the hard-coded mapping. A test is added to ensure that the metadata is written by OutputLayer when present, and that it is not set as part of a "per-frame" update. Bug: 139747351 Test: atest libcompositionengine_test Change-Id: I63f2a34e1fb70e1aefc5aa7e97ce56b7c2579a29 --- .../LayerFECompositionState.h | 25 +++++++++ .../src/LayerFECompositionState.cpp | 25 +++++++++ .../CompositionEngine/src/OutputLayer.cpp | 9 ++- .../tests/OutputLayerTest.cpp | 56 +++++++++++++++++++ services/surfaceflinger/Layer.cpp | 20 +++++++ services/surfaceflinger/SurfaceFlinger.cpp | 15 +++++ services/surfaceflinger/SurfaceFlinger.h | 9 +++ 7 files changed, 158 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 40cd3e0c20..d8ce629153 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -40,6 +40,29 @@ namespace android::compositionengine { +// More complex metadata for this layer +struct GenericLayerMetadataEntry { + // True if the metadata may affect the composed result. + // See setLayerGenericMetadata in IComposerClient.hal + bool mandatory; + + // Byte blob or parcel + std::vector value; + + std::string dumpAsString() const; +}; + +inline bool operator==(const GenericLayerMetadataEntry& lhs, const GenericLayerMetadataEntry& rhs) { + return lhs.mandatory == rhs.mandatory && lhs.value == rhs.value; +} + +// Defining PrintTo helps with Google Tests. +inline void PrintTo(const GenericLayerMetadataEntry& v, ::std::ostream* os) { + *os << v.dumpAsString(); +} + +using GenericLayerMetadataMap = std::unordered_map; + /* * Used by LayerFE::getCompositionState */ @@ -115,6 +138,8 @@ struct LayerFECompositionState { // The appId for this layer int appId{0}; + GenericLayerMetadataMap metadata; + /* * Per-frame content */ diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp index 3e0f8038d7..02e3a45acd 100644 --- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp @@ -32,6 +32,20 @@ void dumpVal(std::string& out, const char* name, half4 value) { } // namespace +std::string GenericLayerMetadataEntry::dumpAsString() const { + using android::base::StringAppendF; + std::string out; + + out.append("GenericLayerMetadataEntry{mandatory: "); + StringAppendF(&out, "%d", mandatory); + out.append(" value: "); + for (uint8_t byte : value) { + StringAppendF(&out, "0x08%" PRIx8 " ", byte); + } + out.append("]}"); + return out; +} + LayerFECompositionState::~LayerFECompositionState() = default; void LayerFECompositionState::dump(std::string& out) const { @@ -65,6 +79,17 @@ void LayerFECompositionState::dump(std::string& out) const { dumpVal(out, "type", type); dumpVal(out, "appId", appId); + if (!metadata.empty()) { + out.append("\n metadata {"); + for (const auto& [key, entry] : metadata) { + out.append("\n "); + out.append(key); + out.append("="); + out.append(entry.dumpAsString()); + } + out.append("\n }\n "); + } + dumpVal(out, "composition type", toString(compositionType), compositionType); out.append("\n buffer: "); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index b538d7520f..3aa79562cc 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -406,6 +406,14 @@ void OutputLayer::writeOutputIndependentGeometryStateToHWC( ALOGE("[%s] Failed to set info %s (%d)", getLayerFE().getDebugName(), to_string(error).c_str(), static_cast(error)); } + + for (const auto& [name, entry] : outputIndependentState.metadata) { + if (auto error = hwcLayer->setLayerGenericMetadata(name, entry.mandatory, entry.value); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set generic metadata %s %s (%d)", getLayerFE().getDebugName(), + name.c_str(), to_string(error).c_str(), static_cast(error)); + } + } } void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) { @@ -661,4 +669,3 @@ void OutputLayer::dump(std::string& out) const { } // namespace impl } // namespace android::compositionengine - diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 963062fdbf..1b5617c7eb 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -625,6 +625,8 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static constexpr ui::Dataspace kDataspace = static_cast(71); static constexpr int kSupportedPerFrameMetadata = 101; static constexpr int kExpectedHwcSlot = 0; + static constexpr bool kLayerGenericMetadata1Mandatory = true; + static constexpr bool kLayerGenericMetadata2Mandatory = true; static const half4 kColor; static const Rect kDisplayFrame; @@ -635,6 +637,10 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static native_handle_t* kSidebandStreamHandle; static const sp kBuffer; static const sp kFence; + static const std::string kLayerGenericMetadata1Key; + static const std::vector kLayerGenericMetadata1Value; + static const std::string kLayerGenericMetadata2Key; + static const std::vector kLayerGenericMetadata2Value; OutputLayerWriteStateToHWCTest() { auto& outputLayerState = mOutputLayer.editState(); @@ -669,6 +675,13 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { // Some tests may need to simulate unsupported HWC calls enum class SimulateUnsupported { None, ColorTransform }; + void includeGenericLayerMetadataInState() { + mLayerFEState.metadata[kLayerGenericMetadata1Key] = {kLayerGenericMetadata1Mandatory, + kLayerGenericMetadata1Value}; + mLayerFEState.metadata[kLayerGenericMetadata2Key] = {kLayerGenericMetadata2Mandatory, + kLayerGenericMetadata2Value}; + } + void expectGeometryCommonCalls() { EXPECT_CALL(*mHwcLayer, setDisplayFrame(kDisplayFrame)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setSourceCrop(kSourceCrop)).WillOnce(Return(kError)); @@ -720,6 +733,18 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, kBuffer, kFence)); } + void expectGenericLayerMetadataCalls() { + // Note: Can be in any order. + EXPECT_CALL(*mHwcLayer, + setLayerGenericMetadata(kLayerGenericMetadata1Key, + kLayerGenericMetadata1Mandatory, + kLayerGenericMetadata1Value)); + EXPECT_CALL(*mHwcLayer, + setLayerGenericMetadata(kLayerGenericMetadata2Key, + kLayerGenericMetadata2Mandatory, + kLayerGenericMetadata2Value)); + } + std::shared_ptr mHwcLayer{std::make_shared>()}; StrictMock mDisplayColorProfile; }; @@ -739,6 +764,13 @@ native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle = reinterpret_cast(1031); const sp OutputLayerWriteStateToHWCTest::kBuffer; const sp OutputLayerWriteStateToHWCTest::kFence; +const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key = + "com.example.metadata.1"; +const std::vector OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Value{{1, 2, 3}}; +const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata2Key = + "com.example.metadata.2"; +const std::vector OutputLayerWriteStateToHWCTest::kLayerGenericMetadata2Value{ + {4, 5, 6, 7}}; TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoFECompositionState) { EXPECT_CALL(*mLayerFE, getCompositionState()).WillOnce(Return(nullptr)); @@ -862,6 +894,30 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompo mOutputLayer.writeStateToHWC(false); } +TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) { + mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + includeGenericLayerMetadataInState(); + + expectGeometryCommonCalls(); + expectPerFrameCommonCalls(); + expectSetHdrMetadataAndBufferCalls(); + expectGenericLayerMetadataCalls(); + expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + + mOutputLayer.writeStateToHWC(true); +} + +TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPresent) { + mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + includeGenericLayerMetadataInState(); + + expectPerFrameCommonCalls(); + expectSetHdrMetadataAndBufferCalls(); + expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + + mOutputLayer.writeStateToHWC(false); +} + /* * OutputLayer::writeCursorPositionToHWC() */ diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 6ff23c5f51..e04e0ab996 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -475,6 +475,26 @@ void Layer::prepareGeometryCompositionState() { compositionState->type = type; compositionState->appId = appId; + + compositionState->metadata.clear(); + const auto& supportedMetadata = mFlinger->getHwComposer().getSupportedLayerGenericMetadata(); + for (const auto& [key, mandatory] : supportedMetadata) { + const auto& genericLayerMetadataCompatibilityMap = + mFlinger->getGenericLayerMetadataKeyMap(); + auto compatIter = genericLayerMetadataCompatibilityMap.find(key); + if (compatIter == std::end(genericLayerMetadataCompatibilityMap)) { + continue; + } + const uint32_t id = compatIter->second; + + auto it = drawingState.metadata.mMap.find(id); + if (it == std::end(drawingState.metadata.mMap)) { + continue; + } + + compositionState->metadata + .emplace(key, compositionengine::GenericLayerMetadataEntry{mandatory, it->second}); + } } void Layer::preparePerFrameCompositionState() { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7ed6342dd9..084251c93e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5851,6 +5851,21 @@ status_t SurfaceFlinger::setGlobalShadowSettings(const half4& ambientColor, cons return NO_ERROR; } +const std::unordered_map& SurfaceFlinger::getGenericLayerMetadataKeyMap() + const { + // TODO(b/149500060): Remove this fixed/static mapping. Please prefer taking + // on the work to remove the table in that bug rather than adding more to + // it. + static const std::unordered_map genericLayerMetadataKeyMap{ + // Note: METADATA_OWNER_UID and METADATA_WINDOW_TYPE are officially + // supported, and exposed via the + // IVrComposerClient::VrCommand::SET_LAYER_INFO command. + {"org.chromium.arc.V1_0.TaskId", METADATA_TASK_ID}, + {"org.chromium.arc.V1_0.CursorInfo", METADATA_MOUSE_CURSOR}, + }; + return genericLayerMetadataKeyMap; +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8cabcf0ef6..763df2353d 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1153,6 +1153,15 @@ private: std::atomic mExpectedPresentTime = 0; + /* ------------------------------------------------------------------------ + * Generic Layer Metadata + */ + const std::unordered_map& getGenericLayerMetadataKeyMap() const; + + /* ------------------------------------------------------------------------ + * Misc + */ + std::mutex mActiveConfigLock; // This bit is set once we start setting the config. We read from this bit during the // process. If at the end, this bit is different than mDesiredActiveConfig, we restart -- GitLab From d9d8572a850fa179f8ba81d6dd673d90d83e7742 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 13 Feb 2020 13:57:19 -0800 Subject: [PATCH 0810/1255] [ANativeWindow] allocateBuffers changes * rename allocateBuffers to tryAllocateBuffers to reflect that its a best-effort API * promote to public NDK Bug: 148962594 Test: builds Change-Id: Iff73c2eb7bb07d28ef26b95202257950e9da4627 --- libs/nativewindow/ANativeWindow.cpp | 12 ++++++++---- libs/nativewindow/include/android/native_window.h | 11 +++++++++++ libs/nativewindow/libnativewindow.map.txt | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index a1c9eb806b..98b76fd667 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -165,6 +165,14 @@ int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) { return native_window_set_frame_rate(window, frameRate); } +void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { + if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { + return; + } + window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS); +} + + /************************************************************************************************** * vndk-stable **************************************************************************************************/ @@ -328,10 +336,6 @@ int ANativeWindow_setQueueBufferInterceptor(ANativeWindow* window, return window->perform(window, NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR, interceptor, data); } -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/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 262aee3501..4b426c518a 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -261,6 +261,17 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN */ int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) __INTRODUCED_IN(30); +/** + * Provides a hint to the window that buffers should be preallocated ahead of + * time. Note that the window implementation is not guaranteed to preallocate + * any buffers, for instance if an implementation disallows allocation of new + * buffers, or if there is insufficient memory in the system to preallocate + * additional buffers + * + * Available since API level 30. + */ +void ANativeWindow_tryAllocateBuffers(ANativeWindow* window); + #endif // __ANDROID_API__ >= 30 #ifdef __cplusplus diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index e0e20c3ae2..154eb8eb52 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -17,7 +17,6 @@ LIBNATIVEWINDOW { ANativeWindow_OemStorageGet; # llndk ANativeWindow_OemStorageSet; # llndk ANativeWindow_acquire; - ANativeWindow_allocateBuffers; # apex # introduced=30 ANativeWindow_cancelBuffer; # llndk ANativeWindow_dequeueBuffer; # llndk ANativeWindow_getBuffersDataSpace; # introduced=28 @@ -51,6 +50,7 @@ LIBNATIVEWINDOW { ANativeWindow_setSwapInterval; # llndk ANativeWindow_setFrameRate; # introduced=30 ANativeWindow_setUsage; # llndk + ANativeWindow_tryAllocateBuffers; # introduced=30 ANativeWindow_unlockAndPost; local: *; -- GitLab From 110a0d1b954a129c7b8efddc07d3e85b2b3057a9 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Tue, 11 Feb 2020 10:34:28 -0800 Subject: [PATCH 0811/1255] Gaussian blur optimizations Test: transaction tests Test: visual Bug: 149309004 Change-Id: I5ddcd674e7068fa05482b3f6f2eb1efb1c4a4b73 --- libs/renderengine/gl/filters/BlurFilter.cpp | 6 +- .../gl/filters/GaussianBlurFilter.cpp | 126 ++++++++++++------ .../gl/filters/GaussianBlurFilter.h | 9 +- 3 files changed, 95 insertions(+), 46 deletions(-) diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index b1a84bd0c2..eb66c8f2a7 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -132,8 +132,7 @@ status_t BlurFilter::render(bool multiPass) { } string BlurFilter::getVertexShader() const { - return R"SHADER( - #version 310 es + return R"SHADER(#version 310 es in vec2 aPosition; in highp vec2 aUV; @@ -147,8 +146,7 @@ string BlurFilter::getVertexShader() const { } string BlurFilter::getMixFragShader() const { - string shader = R"SHADER( - #version 310 es + string shader = R"SHADER(#version 310 es precision mediump float; in highp vec2 vUV; diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp index 4d7bf44540..a0d7af8218 100644 --- a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp +++ b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp @@ -43,7 +43,7 @@ GaussianBlurFilter::GaussianBlurFilter(GLESRenderEngine& engine) mVPosLoc = mVerticalProgram.getAttributeLocation("aPosition"); mVUvLoc = mVerticalProgram.getAttributeLocation("aUV"); mVTextureLoc = mVerticalProgram.getUniformLocation("uTexture"); - mVIncrementLoc = mVerticalProgram.getUniformLocation("uIncrement"); + mVGaussianOffsetLoc = mVerticalProgram.getUniformLocation("uGaussianOffsets"); mVNumSamplesLoc = mVerticalProgram.getUniformLocation("uSamples"); mVGaussianWeightLoc = mVerticalProgram.getUniformLocation("uGaussianWeights"); @@ -51,7 +51,7 @@ GaussianBlurFilter::GaussianBlurFilter(GLESRenderEngine& engine) mHPosLoc = mHorizontalProgram.getAttributeLocation("aPosition"); mHUvLoc = mHorizontalProgram.getAttributeLocation("aUV"); mHTextureLoc = mHorizontalProgram.getUniformLocation("uTexture"); - mHIncrementLoc = mHorizontalProgram.getUniformLocation("uIncrement"); + mHGaussianOffsetLoc = mHorizontalProgram.getUniformLocation("uGaussianOffsets"); mHNumSamplesLoc = mHorizontalProgram.getUniformLocation("uSamples"); mHGaussianWeightLoc = mHorizontalProgram.getUniformLocation("uGaussianWeights"); } @@ -60,6 +60,36 @@ void GaussianBlurFilter::allocateTextures() { mVerticalPassFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight()); } +static void calculateLinearGaussian(uint32_t samples, double dimension, + GLfloat* gaussianLinearOffsets, GLfloat* gaussianWeights, + GLfloat* gaussianLinearWeights) { + // The central point in the symmetric bell curve is not offset. + // This decision allows one less sampling in the GPU. + gaussianLinearWeights[0] = gaussianWeights[0]; + gaussianLinearOffsets[0] = 0.0; + + // Calculate the linear weights. + // This is a vector reduction where an element of the packed reduced array + // contains the sum of two adjacent members of the original packed array. + // We start preserving the element 1 of the array and then perform sum for + // every other (i+=2) element of the gaussianWeights array. + gaussianLinearWeights[1] = gaussianWeights[1]; + const auto start = 1 + ((samples - 1) & 0x1); + for (size_t i = start; i < samples; i += 2) { + gaussianLinearWeights[start + i / 2] = gaussianWeights[i] + gaussianWeights[i + 1]; + } + + // Calculate the texture coordinates offsets as an average of the initial offsets, + // weighted by the Gaussian weights as described in the original article. + gaussianLinearOffsets[1] = 1.0 / dimension; + for (size_t i = start; i < samples; i += 2) { + GLfloat offset_1 = float(i) / dimension; + GLfloat offset_2 = float(i + 1) / dimension; + gaussianLinearOffsets[start + i / 2] = + (offset_1 * gaussianWeights[i] + offset_2 * gaussianWeights[i + 1]) / + gaussianLinearWeights[start + i / 2]; + } +} status_t GaussianBlurFilter::prepare() { ATRACE_NAME("GaussianBlurFilter::prepare"); @@ -88,27 +118,47 @@ status_t GaussianBlurFilter::prepare() { mVerticalPassFbo.bind(); mVerticalProgram.useProgram(); - // Precompute gaussian bell curve, and send it to the shader to avoid - // unnecessary computations. - auto samples = min(mRadius, kNumSamples); + // Precompute gaussian bell curve, and send it to the shader to avoid unnecessary computations. + double radiusD = fmax(1.0, mRadius * kFboScale); + auto samples = int(fmin(radiusD, kNumSamples)); GLfloat gaussianWeights[kNumSamples] = {}; - for (size_t i = 0; i < samples; i++) { - float normalized = float(i) / samples; + + gaussianWeights[0] = 1.0f; + auto totalWeight = gaussianWeights[0]; + + // Gaussian weights calculation. + for (size_t i = 1; i < samples; i++) { + const double normalized = i / radiusD; gaussianWeights[i] = (float)exp(-K * normalized * normalized); + totalWeight += 2.0 * gaussianWeights[i]; + } + + // Gaussian weights normalization to avoid work in the GPU. + for (size_t i = 0; i < samples; i++) { + gaussianWeights[i] /= totalWeight; } - // set uniforms auto width = mVerticalPassFbo.getBufferWidth(); auto height = mVerticalPassFbo.getBufferHeight(); - auto radiusF = fmax(1.0f, mRadius * kFboScale); glViewport(0, 0, width, height); + + // Allocate space for the corrected Gaussian weights and offsets. + // We could use less space, but let's keep the code simple. + GLfloat gaussianLinearWeights[kNumSamples] = {}; + GLfloat gaussianLinearOffsets[kNumSamples] = {}; + + // Calculate the weights and offsets for the vertical pass. + // This only need to be called every time mRadius or height changes, so it could be optimized. + calculateLinearGaussian(samples, double(height), gaussianLinearOffsets, gaussianWeights, + gaussianLinearWeights); + // set uniforms glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName()); glUniform1i(mVTextureLoc, 0); - glUniform2f(mVIncrementLoc, radiusF / (width * 2.0f), radiusF / (height * 2.0f)); - glUniform1i(mVNumSamplesLoc, samples); - glUniform1fv(mVGaussianWeightLoc, kNumSamples, gaussianWeights); - mEngine.checkErrors("Setting vertical-diagonal pass uniforms"); + glUniform1i(mVNumSamplesLoc, 1 + (samples + 1) / 2); + glUniform1fv(mVGaussianWeightLoc, kNumSamples, gaussianLinearWeights); + glUniform1fv(mVGaussianOffsetLoc, kNumSamples, gaussianLinearOffsets); + mEngine.checkErrors("Setting vertical pass uniforms"); drawMesh(mVUvLoc, mVPosLoc); @@ -116,14 +166,18 @@ status_t GaussianBlurFilter::prepare() { mBlurredFbo.bind(); mHorizontalProgram.useProgram(); + // Calculate the weights and offsets for the horizontal pass. + // This only needs to be called every time mRadius or width change, so it could be optimized. + calculateLinearGaussian(samples, double(width), gaussianLinearOffsets, gaussianWeights, + gaussianLinearWeights); // set uniforms glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mVerticalPassFbo.getTextureName()); glUniform1i(mHTextureLoc, 0); - glUniform2f(mHIncrementLoc, radiusF / (width * 2.0f), radiusF / (height * 2.0f)); - glUniform1i(mHNumSamplesLoc, samples); - glUniform1fv(mHGaussianWeightLoc, kNumSamples, gaussianWeights); - mEngine.checkErrors("Setting vertical pass uniforms"); + glUniform1i(mHNumSamplesLoc, 1 + (samples + 1) / 2); + glUniform1fv(mHGaussianWeightLoc, kNumSamples, gaussianLinearWeights); + glUniform1fv(mHGaussianOffsetLoc, kNumSamples, gaussianLinearOffsets); + mEngine.checkErrors("Setting horizontal pass uniforms"); drawMesh(mHUvLoc, mHPosLoc); @@ -142,43 +196,37 @@ string GaussianBlurFilter::getFragmentShader(bool horizontal) const { stringstream shader; shader << "#version 310 es\n" << "#define DIRECTION " << (horizontal ? "1" : "0") << "\n" - << "#define NUM_SAMPLES " << kNumSamples << + << "#define NUM_SAMPLES " << 1 + (kNumSamples + 1) / 2 << R"SHADER( precision mediump float; uniform sampler2D uTexture; - uniform vec2 uIncrement; uniform float[NUM_SAMPLES] uGaussianWeights; + uniform float[NUM_SAMPLES] uGaussianOffsets; uniform int uSamples; highp in vec2 vUV; out vec4 fragColor; - vec3 gaussianBlur(sampler2D texture, highp vec2 uv, float inc, vec2 direction) { - float totalWeight = 0.0; - vec3 blurred = vec3(0.0); - float fSamples = 1.0 / float(uSamples); - - for (int i = -uSamples; i <= uSamples; i++) { - float weight = uGaussianWeights[abs(i)]; - float normalized = float(i) * fSamples; - float radInc = inc * normalized; - blurred += weight * (texture(texture, radInc * direction + uv, 0.0)).rgb; - totalWeight += weight; - } - - return blurred / totalWeight; - } - void main() { #if DIRECTION == 1 - vec3 color = gaussianBlur(uTexture, vUV, uIncrement.x, vec2(1.0, 0.0)); + const vec2 direction = vec2(1.0, 0.0); #else - vec3 color = gaussianBlur(uTexture, vUV, uIncrement.y, vec2(0.0, 1.0)); + const vec2 direction = vec2(0.0, 1.0); #endif - fragColor = vec4(color, 1.0); - } + // Iteration zero outside loop to avoid sampling the central point twice. + vec4 blurred = uGaussianWeights[0] * (texture(uTexture, vUV, 0.0)); + + // Iterate one side of the bell to halve the loop iterations. + for (int i = 1; i <= uSamples; i++) { + vec2 offset = uGaussianOffsets[i] * direction; + blurred += uGaussianWeights[i] * (texture(uTexture, vUV + offset, 0.0)); + blurred += uGaussianWeights[i] * (texture(uTexture, vUV - offset, 0.0)); + } + + fragColor = vec4(blurred.rgb, 1.0); + } )SHADER"; return shader.str(); } diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.h b/libs/renderengine/gl/filters/GaussianBlurFilter.h index 8580522f40..44f5fde9f7 100644 --- a/libs/renderengine/gl/filters/GaussianBlurFilter.h +++ b/libs/renderengine/gl/filters/GaussianBlurFilter.h @@ -28,9 +28,12 @@ namespace android { namespace renderengine { namespace gl { +// Class that implements a Gaussian Filter that uses Linear Sampling +// to halve the number of samples and reduce runtime by 40% as described in: +// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling class GaussianBlurFilter : public BlurFilter { public: - static constexpr uint32_t kNumSamples = 12; + static constexpr uint32_t kNumSamples = 22; explicit GaussianBlurFilter(GLESRenderEngine& engine); status_t prepare() override; @@ -47,7 +50,7 @@ private: GLuint mVPosLoc; GLuint mVUvLoc; GLuint mVTextureLoc; - GLuint mVIncrementLoc; + GLuint mVGaussianOffsetLoc; GLuint mVNumSamplesLoc; GLuint mVGaussianWeightLoc; @@ -56,7 +59,7 @@ private: GLuint mHPosLoc; GLuint mHUvLoc; GLuint mHTextureLoc; - GLuint mHIncrementLoc; + GLuint mHGaussianOffsetLoc; GLuint mHNumSamplesLoc; GLuint mHGaussianWeightLoc; }; -- GitLab From 93d5a5e4b7e82e594e539c2e5fee49e5631ce0b7 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Thu, 13 Feb 2020 14:50:01 -0800 Subject: [PATCH 0812/1255] Actually finalize frame event history before sending callbacks Bug: 141939081 Test: build, boot, libgui_test Change-Id: I33f14405ae7bebe28daf87c7fa37e9f27d5b04cd --- services/surfaceflinger/BufferLayer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index f4f45be49f..7bf2e6a941 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -329,6 +329,7 @@ bool BufferLayer::onPostComposition(sp displayDevice, Mutex::Autolock lock(mFrameEventHistoryMutex); mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence, compositorTiming); + finalizeFrameEventHistory(glDoneFence, compositorTiming); } // Update mFrameTracker. -- GitLab From d983cc793c7a55c8dc048842d8c4d3a8d5a39383 Mon Sep 17 00:00:00 2001 From: Alan Stokes Date: Fri, 14 Feb 2020 14:36:58 +0000 Subject: [PATCH 0813/1255] Don't destroy ART profiles after package move. They don't get moved, so instead of deleting a redundant copy we are deleting the only copy. Bug: 149200535 Test: Manual. After repro steps in bug app is moved, profiles are not deleted. Change-Id: I3589588cafde77828113547953d5916ba3beb557 --- cmds/installd/InstalldNativeService.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 42887359d1..ea8b181ab6 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -701,11 +701,13 @@ binder::Status InstalldNativeService::destroyAppData(const std::unique_ptr lock(mMountsLock); -- GitLab From 75c8aa9197b2015afdb027073fd9f3b0f690d0bb Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Mon, 30 Dec 2019 11:12:53 -0800 Subject: [PATCH 0814/1255] Add multi-display support This change modifies and implements below methods to support multi-display device implementations. - getIGraphicBufferProducer() takes a target display identifier. If a given identifier is not valid, this will return a null pointer. - AutomotiveDisplayProxyService stores display tokens of each display. - showWindow() is modified to set a layer stack properly for a target display. - getDisplayIdList() is newly implemented and returns stable IDs of all available displays. - getDisplayInfo() returns the description of a target display that is identified by a given stable ID. Bug: 141886260 Bug: 146567078 Test: VtsHalEvsV1_1TargetTest Change-Id: Ia195a6c19416eb75bfe77da61d7a32030ec85967 Signed-off-by: Changyeon Jo --- services/automotive/display/Android.bp | 4 + .../display/AutomotiveDisplayProxyService.cpp | 170 ++++++++++++------ .../include/AutomotiveDisplayProxyService.h | 40 ++--- .../display/main_automotivedisplayproxy.cpp | 9 +- 4 files changed, 146 insertions(+), 77 deletions(-) diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp index d94fb273b0..8ff0711f55 100644 --- a/services/automotive/display/Android.bp +++ b/services/automotive/display/Android.bp @@ -36,4 +36,8 @@ cc_binary { local_include_dirs: [ "include", ], + + cflags: [ + "-DLOG_TAG=\"AutomotiveDisplayService\"" + ], } diff --git a/services/automotive/display/AutomotiveDisplayProxyService.cpp b/services/automotive/display/AutomotiveDisplayProxyService.cpp index 3cd8e390b2..8f57dcdb18 100644 --- a/services/automotive/display/AutomotiveDisplayProxyService.cpp +++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp @@ -27,97 +27,163 @@ namespace display { namespace V1_0 { namespace implementation { -Return> -AutomotiveDisplayProxyService::getIGraphicBufferProducer() { - if (mSurface == nullptr) { - status_t err; - mSurfaceComposerClient = new SurfaceComposerClient(); - - err = mSurfaceComposerClient->initCheck(); - if (err != NO_ERROR) { - ALOGE("SurfaceComposerClient::initCheck error: %#x", err); - mSurfaceComposerClient = nullptr; - return nullptr; - } - const auto displayToken = SurfaceComposerClient::getInternalDisplayToken(); +Return> +AutomotiveDisplayProxyService::getIGraphicBufferProducer(uint64_t id) { + auto it = mDisplays.find(id); + sp displayToken = nullptr; + sp surfaceControl = nullptr; + if (it == mDisplays.end()) { + displayToken = SurfaceComposerClient::getPhysicalDisplayToken(id); if (displayToken == nullptr) { - ALOGE("Failed to get internal display "); + ALOGE("Given display id, 0x%lX, is invalid.", id); return nullptr; } - err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &mDpyConfig); + // Get the resolution from stored display state. + DisplayConfig displayConfig = {}; + auto err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig); if (err != NO_ERROR) { - ALOGE("Failed to get active display config"); + ALOGE("Failed to get display configuration of %lX. " + "This display will be ignored.", id); return nullptr; } - err = SurfaceComposerClient::getDisplayState(displayToken, &mDpyState); + ui::DisplayState displayState = {}; + err = SurfaceComposerClient::getDisplayState(displayToken, &displayState); if (err != NO_ERROR) { - ALOGE("Failed to get display state"); + ALOGE("Failed to get current display status of %lX. " + "This display will be ignored.", id); return nullptr; } - const ui::Size& resolution = mDpyConfig.resolution; - auto width = resolution.getWidth(); - auto height = resolution.getHeight(); + auto displayWidth = displayConfig.resolution.getWidth(); + auto displayHeight = displayConfig.resolution.getHeight(); + if ((displayState.orientation != ui::ROTATION_0) && + (displayState.orientation != ui::ROTATION_180)) { + std::swap(displayWidth, displayHeight); + } - if (mDpyState.orientation == ui::ROTATION_90 || - mDpyState.orientation == ui::ROTATION_270) { - std::swap(width, height); + sp surfaceClient = new SurfaceComposerClient(); + err = surfaceClient->initCheck(); + if (err != NO_ERROR) { + ALOGE("SurfaceComposerClient::initCheck error: %#x", err); + return nullptr; } - mSurfaceControl = mSurfaceComposerClient->createSurface( - String8("Automotive Display"), width, height, + // Create a SurfaceControl instance + surfaceControl = surfaceClient->createSurface( + String8::format("AutomotiveDisplay::%lX", id), + displayWidth, displayHeight, PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque); - if (mSurfaceControl == nullptr || !mSurfaceControl->isValid()) { - ALOGE("Failed to create SurfaceControl"); - mSurfaceComposerClient = nullptr; - mSurfaceControl = nullptr; + if (surfaceControl == nullptr || !surfaceControl->isValid()) { + ALOGE("Failed to create SurfaceControl."); return nullptr; } - // SurfaceControl::getSurface is guaranteed to be not null. - mSurface = mSurfaceControl->getSurface(); + // Store + DisplayDesc descriptor = {displayToken, surfaceControl}; + mDisplays.insert_or_assign(id, std::move(descriptor)); + } else { + displayToken = it->second.token; + surfaceControl = it->second.surfaceControl; } + // SurfaceControl::getSurface is guaranteed to be not null. + auto targetSurface = surfaceControl->getSurface(); return new ::android::hardware::graphics::bufferqueue::V2_0::utils:: - B2HGraphicBufferProducer( - mSurface->getIGraphicBufferProducer()); + B2HGraphicBufferProducer(targetSurface->getIGraphicBufferProducer()); } -Return AutomotiveDisplayProxyService::showWindow() { - status_t status = NO_ERROR; - if (mSurfaceControl != nullptr) { - status = SurfaceComposerClient::Transaction{} - .setLayer( - mSurfaceControl, 0x7FFFFFFF) // always on top - .show(mSurfaceControl) - .apply(); - } else { - ALOGE("showWindow: Failed to get a valid SurfaceControl!"); +Return AutomotiveDisplayProxyService::showWindow(uint64_t id) { + auto it = mDisplays.find(id); + if (it == mDisplays.end()) { + ALOGE("Given display token is invalid or unknown."); + return false; + } + + ui::DisplayState displayState; + auto err = SurfaceComposerClient::getDisplayState(it->second.token, &displayState); + if (err != NO_ERROR) { + ALOGE("Failed to get current state of the display 0x%lX", id); return false; } + SurfaceComposerClient::Transaction t; + t.setDisplayLayerStack(it->second.token, displayState.layerStack); + t.setLayerStack(it->second.surfaceControl, displayState.layerStack); + + status_t status = t.setLayer(it->second.surfaceControl, 0x7FFFFFFF) + .show(it->second.surfaceControl) + .apply(); + return status == NO_ERROR; } -Return AutomotiveDisplayProxyService::hideWindow() { - status_t status = NO_ERROR; - if (mSurfaceControl != nullptr) { - status = SurfaceComposerClient::Transaction{} - .hide(mSurfaceControl) - .apply(); - } else { - ALOGE("hideWindow: Failed to get a valid SurfaceControl!"); +Return AutomotiveDisplayProxyService::hideWindow(uint64_t id) { + auto it = mDisplays.find(id); + if (it == mDisplays.end()) { + ALOGE("Given display token is invalid or unknown."); return false; } + status_t status = SurfaceComposerClient::Transaction{} + .hide(it->second.surfaceControl) + .apply(); + return status == NO_ERROR; } + +Return AutomotiveDisplayProxyService::getDisplayIdList(getDisplayIdList_cb _cb) { + hardware::hidl_vec ids; + + // Get stable IDs of all available displays and get their tokens and + // descriptors. + auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds(); + ids.resize(displayIds.size()); + for (auto i = 0; i < displayIds.size(); ++i) { + ids[i] = displayIds[i]; + } + + _cb(ids); + return hardware::Void(); +} + + +Return AutomotiveDisplayProxyService::getDisplayInfo(uint64_t id, getDisplayInfo_cb _cb) { + HwDisplayConfig activeConfig; + HwDisplayState activeState; + + auto displayToken = SurfaceComposerClient::getPhysicalDisplayToken(id); + if (displayToken == nullptr) { + ALOGE("Given display id, 0x%lX, is invalid.", id); + } else { + DisplayConfig displayConfig = {}; + auto err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig); + if (err != NO_ERROR) { + ALOGW("Failed to get display configuration of %lX. " + "This display will be ignored.", id); + } + + ui::DisplayState displayState = {}; + err = SurfaceComposerClient::getDisplayState(displayToken, &displayState); + if (err != NO_ERROR) { + ALOGW("Failed to get current display status of %lX. " + "This display will be ignored.", id); + } + + activeConfig.setToExternal((uint8_t*)&displayConfig, sizeof(DisplayConfig)); + activeState.setToExternal((uint8_t*)&displayState, sizeof(DisplayState)); + } + + _cb(activeConfig, activeState); + return hardware::Void(); +} + + } // namespace implementation } // namespace V1_0 } // namespace display diff --git a/services/automotive/display/include/AutomotiveDisplayProxyService.h b/services/automotive/display/include/AutomotiveDisplayProxyService.h index 3956602477..e2fc0d2eec 100644 --- a/services/automotive/display/include/AutomotiveDisplayProxyService.h +++ b/services/automotive/display/include/AutomotiveDisplayProxyService.h @@ -16,12 +16,14 @@ #pragma once #include -#include #include +#include #include #include #include #include +#include +#include namespace android { namespace frameworks { @@ -31,32 +33,30 @@ namespace V1_0 { namespace implementation { using ::android::hardware::Return; -using ::android::sp; using ::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer; +using ::android::sp; -class AutomotiveDisplayProxyService : public IAutomotiveDisplayProxyService { -public: - Return> getIGraphicBufferProducer() override; - Return showWindow() override; - Return hideWindow() override; - Return getDisplayInfo(getDisplayInfo_cb _info_cb) override { - HwDisplayConfig cfg; - cfg.setToExternal((uint8_t*)&mDpyConfig, sizeof(DisplayConfig)); - HwDisplayState state; - state.setToExternal((uint8_t*)&mDpyState, sizeof(DisplayState)); +typedef struct DisplayDesc { + sp token; + sp surfaceControl; +} DisplayDesc; - _info_cb(cfg, state); - return hardware::Void(); - } + +class AutomotiveDisplayProxyService : public IAutomotiveDisplayProxyService { +public: + Return> getIGraphicBufferProducer(uint64_t id) override; + Return showWindow(uint64_t id) override; + Return hideWindow(uint64_t id) override; + Return getDisplayIdList(getDisplayIdList_cb _cb) override; + Return getDisplayInfo(uint64_t, getDisplayInfo_cb _cb) override; private: - sp mSurface; - sp mSurfaceComposerClient; - sp mSurfaceControl; - DisplayConfig mDpyConfig; - ui::DisplayState mDpyState; + uint8_t getDisplayPort(const uint64_t id) { return (id & 0xF); } + + std::unordered_map mDisplays; }; + } // namespace implementation } // namespace V1_0 } // namespace display diff --git a/services/automotive/display/main_automotivedisplayproxy.cpp b/services/automotive/display/main_automotivedisplayproxy.cpp index 626c1852c9..59b584cd46 100644 --- a/services/automotive/display/main_automotivedisplayproxy.cpp +++ b/services/automotive/display/main_automotivedisplayproxy.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#define LOG_TAG "AutomotiveDisplayService" - #include #include @@ -39,9 +37,10 @@ using namespace android; const static char kServiceName[] = "default"; int main() { - ALOGI("Car Window Service is starting"); + ALOGI("Automotive Display Proxy Service is starting"); - android::sp service = new AutomotiveDisplayProxyService(); + android::sp service = + new AutomotiveDisplayProxyService(); configureRpcThreadpool(1, true /* callerWillJoin */); @@ -56,7 +55,7 @@ int main() { } // In normal operation, we don't expect the thread pool to exit - ALOGE("Car Window Service is shutting down"); + ALOGE("Automotive Window Service is shutting down"); return 1; } -- GitLab From d41a1be2d7a0a46be45c7f6338b739c49bef824e Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 14 Feb 2020 15:18:11 -0800 Subject: [PATCH 0815/1255] [ANativeWindow] Apply remaining API feedback * move ANativeWindow_getFrameId to a platform api, as native_window_get_frame_timestamps is not stable and therefore the associated api surface is not complete enough to be stable. * Adjust documentation for returned errors. In most cases errors aren't returned in practice. In the case of ANativeWindow_setDequeueTimeout the errors are enumerated explicitly. Bug: 148962594 Test: builds Change-Id: I1ff5113d91fdcfc4679b2862af72fbf811171253 --- libs/nativewindow/ANativeWindow.cpp | 4 --- libs/nativewindow/include/apex/window.h | 34 ++++++++--------------- libs/nativewindow/include/system/window.h | 11 ++++++++ libs/nativewindow/libnativewindow.map.txt | 1 - 4 files changed, 22 insertions(+), 28 deletions(-) diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 98b76fd667..d0d1114d30 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -335,7 +335,3 @@ int ANativeWindow_setQueueBufferInterceptor(ANativeWindow* window, void* data) { return window->perform(window, NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR, interceptor, data); } - -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 02b886c4f0..2d1354cdf1 100644 --- a/libs/nativewindow/include/apex/window.h +++ b/libs/nativewindow/include/apex/window.h @@ -173,25 +173,22 @@ int ANativeWindow_setQueueBufferInterceptor(ANativeWindow* window, /** * Retrieves how long it took for the last time a buffer was dequeued. * - * \return a negative value on error, otherwise returns the duration in - * nanoseconds + * \return the dequeue duration in nanoseconds */ int64_t ANativeWindow_getLastDequeueDuration(ANativeWindow* window); /** * Retrieves how long it took for the last time a buffer was queued. * - * \return a negative value on error, otherwise returns the duration in - * nanoseconds. + * \return the queue duration in nanoseconds */ int64_t ANativeWindow_getLastQueueDuration(ANativeWindow* window); /** * Retrieves the system time in nanoseconds when the last time a buffer - * was dequeued. + * started to be dequeued. * - * \return a negative value on error, otherwise returns the duration in - * nanoseconds. + * \return the start time in nanoseconds */ int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window); @@ -200,23 +197,14 @@ int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window); * made by the window will return -ETIMEDOUT after the timeout if the dequeue * takes too long. * - * \return NO_ERROR on success, -errno on error. - */ -int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout); - -/** - * Provides a hint to the window that buffers should be preallocated ahead of - * time. Note that the window implementation is not guaranteed to preallocate - * any buffers, for instance if a private API disallows allocation of new - * buffers. As such no success/error status is returned. - */ -void ANativeWindow_allocateBuffers(ANativeWindow* window); - -/** - * Retrieves an identifier for the next frame to be queued by this window. + * If the provided timeout is negative, hen this removes the previously configured + * timeout. The window then behaves as if ANativeWindow_setDequeueTimeout was + * never called. * - * \return -errno on error, otherwise returns the next frame id. + * \return NO_ERROR on success + * \return BAD_VALUE if the dequeue timeout was unabled to be updated, as + * updating the dequeue timeout may change internals of the underlying window. */ -int64_t ANativeWindow_getNextFrameId(ANativeWindow* window); +int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout); __END_DECLS diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index f686147a5f..c791b61753 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1049,4 +1049,15 @@ static inline int ANativeWindow_getLastQueuedBuffer(ANativeWindow* window, outTransformMatrix); } +/** + * Retrieves an identifier for the next frame to be queued by this window. + * + * \return the next frame id. + */ +static inline int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) { + int64_t value; + window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, &value); + return value; +} + __END_DECLS diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 154eb8eb52..35f0627e90 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -25,7 +25,6 @@ LIBNATIVEWINDOW { 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 -- GitLab From 0cc6c21b12cf724653ca9d7d4f9ef0296e53abe4 Mon Sep 17 00:00:00 2001 From: Hunter Knepshield Date: Tue, 7 Jan 2020 16:57:10 -0800 Subject: [PATCH 0816/1255] Include carrier services in user builds' connectivity bug reports. In order to achieve this, we give CarrierConfigLoader an extra argument during its dumpsys that tells it to also dump whatever services it's currently connected to. Back in dumpstate, we give this process a slightly larger timeout to account for the additional info. Bug: 146521742 Test: adb shell dumpsys carrier_config --requesting-package Test: take bug report from adb on user build, see no apps dumped with carrier_config Change-Id: I7953f90c6a67a4e032fc176e01cc3bd6dbadce76 --- cmds/dumpstate/dumpstate.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 3a79357a54..814a4edafd 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1672,7 +1672,7 @@ static void DumpstateRadioCommon(bool include_sensitive_info = true) { // information. This information MUST NOT identify user-installed packages (UIDs are OK, package // names are not), and MUST NOT contain logs of user application traffic. // TODO(b/148168577) rename this and other related fields/methods to "connectivity" instead. -static void DumpstateTelephonyOnly() { +static void DumpstateTelephonyOnly(const std::string& calling_package) { DurationReporter duration_reporter("DUMPSTATE"); const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build(); @@ -1695,11 +1695,18 @@ static void DumpstateTelephonyOnly() { RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); - // TODO(b/146521742) build out an argument to include bound services here for user builds - RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), - SEC_TO_MSEC(10)); - RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(), - SEC_TO_MSEC(10)); + if (include_sensitive_info) { + // Carrier apps' services will be dumped below in dumpsys activity service all-non-platform. + RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), + SEC_TO_MSEC(10)); + } else { + // If the caller is a carrier app and has a carrier service, dump it here since we aren't + // running dumpsys activity service all-non-platform below. Due to the increased output, we + // give a higher timeout as well. + RunDumpsys("DUMPSYS", {"carrier_config", "--requesting-package", calling_package}, + CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(30)); + } + RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); RunDumpsys("DUMPSYS", {"netpolicy"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); RunDumpsys("DUMPSYS", {"network_management"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); @@ -2587,7 +2594,7 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, if (options_->telephony_only) { MaybeCheckUserConsent(calling_uid, calling_package); - DumpstateTelephonyOnly(); + DumpstateTelephonyOnly(calling_package); DumpstateBoard(); } else if (options_->wifi_only) { MaybeCheckUserConsent(calling_uid, calling_package); -- GitLab From e4943eb672d8861d700affa2e3f3306e73a1648d Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Sat, 15 Feb 2020 18:34:59 -0800 Subject: [PATCH 0817/1255] BLASTBufferQueue: Correct deadlocks in mNextTransaction handling. There are two deadlocks in mNextTransaction handling that we adress here. The first relates to the wait-condition. Imagine we submit a buffer, now enable mNextTransaction, and queue our next buffer. In onFrameAvailable mNumAcquired will be 1 (MAX_ACQUIRED_BUFFERS), and so we will wait on the condition variable. However, we've only ever submitted one buffer, and so no callback will ever come, and we deadlock. Instead the condition should be mNumAcquired+1 meaning that we have submitted two buffers and are waiting for a callback on one of them (capturing the original intent of waiting for the callback). The second relates to the handling of mNextTransaction in transactionCallback. Imagine a scenario like this: 1. Submit a buffer, mNumAcquired = 1 2. Submit a buffer, callback for the first doesn't arrive yet, mNumAcquired = 2 3. Submit a third buffer, mNumAcquired > MAX_ACQUIRED + 1, so mAvailable = 1 and we wait for the callback. 4. Enable mNextTransaction 5. The callback arrives, but because of the !mNextTransaction condition in the callback function, we don't call processNextBuffer. We do however release one: mNumAcquired = 1, mAvailable = 1 6. At this point we queue a new buffer (The one that was just released we dequeue and queue again). But, mAvailable = 1, and so we wait on the condition variable. However the callback has already fired, and so nothing will actually process the available buffer and we wait forever. The intent of this code was to avoid using the mNextTransaction when we are processing buffers from the callback function. We capture this intent directly by using a boolean set from onFrameAvailable before calling processNextBuffer() Bug: 146598493 Bug: 149251083 Bug: 149315421 Test: Flip the flag. Play. Change-Id: I652eacf1a016f8b65fd754e47d468227bf8ecf1d --- libs/gui/BLASTBufferQueue.cpp | 12 +++++++----- libs/gui/include/gui/BLASTBufferQueue.h | 2 ++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index f6493bf9c7..7a8ee8ec4c 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -174,9 +174,9 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS) { + while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) { mCallbackCV.wait(_lock); } + mUseNextTransaction = true; } // add to shadow queue mNumFrameAvailable++; @@ -268,6 +269,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) { void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) { std::lock_guard _lock{mMutex}; + mUseNextTransaction = false; mNextTransaction = t; } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index d72eb5a632..27d8716541 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -121,6 +121,8 @@ private: sp mBufferItemConsumer; SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex); + + bool mUseNextTransaction = false; }; } // namespace android -- GitLab From b0d738af0fe2874416cecac9eb7f931d01a12a31 Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Sun, 16 Feb 2020 10:38:47 -0800 Subject: [PATCH 0818/1255] Explicit cast uint64_t as unsigned long type This fixes build errors caused by the difference in uint64_t definitions between targets. Bug: 149647375 Test: build for x86 target Change-Id: I3a0845b0527a7cf0f20c7983870c2d3dd8219444 Signed-off-by: Changyeon Jo --- .../display/AutomotiveDisplayProxyService.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/services/automotive/display/AutomotiveDisplayProxyService.cpp b/services/automotive/display/AutomotiveDisplayProxyService.cpp index 8f57dcdb18..4767406931 100644 --- a/services/automotive/display/AutomotiveDisplayProxyService.cpp +++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp @@ -36,7 +36,7 @@ AutomotiveDisplayProxyService::getIGraphicBufferProducer(uint64_t id) { if (it == mDisplays.end()) { displayToken = SurfaceComposerClient::getPhysicalDisplayToken(id); if (displayToken == nullptr) { - ALOGE("Given display id, 0x%lX, is invalid.", id); + ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id); return nullptr; } @@ -45,7 +45,7 @@ AutomotiveDisplayProxyService::getIGraphicBufferProducer(uint64_t id) { auto err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig); if (err != NO_ERROR) { ALOGE("Failed to get display configuration of %lX. " - "This display will be ignored.", id); + "This display will be ignored.", (unsigned long)id); return nullptr; } @@ -53,7 +53,7 @@ AutomotiveDisplayProxyService::getIGraphicBufferProducer(uint64_t id) { err = SurfaceComposerClient::getDisplayState(displayToken, &displayState); if (err != NO_ERROR) { ALOGE("Failed to get current display status of %lX. " - "This display will be ignored.", id); + "This display will be ignored.", (unsigned long)id); return nullptr; } @@ -73,7 +73,7 @@ AutomotiveDisplayProxyService::getIGraphicBufferProducer(uint64_t id) { // Create a SurfaceControl instance surfaceControl = surfaceClient->createSurface( - String8::format("AutomotiveDisplay::%lX", id), + String8::format("AutomotiveDisplay::%lX", (unsigned long)id), displayWidth, displayHeight, PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque); if (surfaceControl == nullptr || !surfaceControl->isValid()) { @@ -106,7 +106,7 @@ Return AutomotiveDisplayProxyService::showWindow(uint64_t id) { ui::DisplayState displayState; auto err = SurfaceComposerClient::getDisplayState(it->second.token, &displayState); if (err != NO_ERROR) { - ALOGE("Failed to get current state of the display 0x%lX", id); + ALOGE("Failed to get current state of the display 0x%lX", (unsigned long)id); return false; } @@ -159,20 +159,20 @@ Return AutomotiveDisplayProxyService::getDisplayInfo(uint64_t id, getDispl auto displayToken = SurfaceComposerClient::getPhysicalDisplayToken(id); if (displayToken == nullptr) { - ALOGE("Given display id, 0x%lX, is invalid.", id); + ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id); } else { DisplayConfig displayConfig = {}; auto err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig); if (err != NO_ERROR) { ALOGW("Failed to get display configuration of %lX. " - "This display will be ignored.", id); + "This display will be ignored.", (unsigned long)id); } ui::DisplayState displayState = {}; err = SurfaceComposerClient::getDisplayState(displayToken, &displayState); if (err != NO_ERROR) { ALOGW("Failed to get current display status of %lX. " - "This display will be ignored.", id); + "This display will be ignored.", (unsigned long)id); } activeConfig.setToExternal((uint8_t*)&displayConfig, sizeof(DisplayConfig)); -- GitLab From 4df87f6585a480b8f15eae69baa178c85114fbf1 Mon Sep 17 00:00:00 2001 From: Felka Chang Date: Tue, 11 Feb 2020 19:08:43 +0800 Subject: [PATCH 0819/1255] Disable storage crates functionalities The Storage Crates functionalities is disable by default. In order to make installd to grow smoothly, the crate function should not add into installd until it addes more tests such as benchmark and memory regression tests. Test: make -j installd && \ grep crates $OUT/system/bin/installd ; \ if [ $? -eq 0 ] ; \ then \ echo "include crate" ; \ else \ echo "not include crate " ; \ fi Test: #should skip the test adb root; \ adb shell setprop fw.storage_crates true \ atest CtsOsTestCases:android.os.storage.cts.StorageCrateTest \ CtsOsTestCases:android.os.storage.cts.StorageStatsManagerTest \ CtsOsTestCases:android.os.storage.cts.CrateInfoTest Test: #should test fail because installd disable the functionalities adb root; \ adb shell "setprop fw.storage_crates ''" \ atest CtsOsTestCases:android.os.storage.cts.StorageCrateTest \ CtsOsTestCases:android.os.storage.cts.StorageStatsManagerTest \ CtsOsTestCases:android.os.storage.cts.CrateInfoTest Bug: 148179319 Change-Id: I1fd142c9c9e5d7e133ebd994f4645966ee432916 --- cmds/installd/CrateManager.cpp | 4 ++++ cmds/installd/CrateManager.h | 7 +++++++ cmds/installd/InstalldNativeService.cpp | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/cmds/installd/CrateManager.cpp b/cmds/installd/CrateManager.cpp index 344aefbcbe..6e079ebbf3 100644 --- a/cmds/installd/CrateManager.cpp +++ b/cmds/installd/CrateManager.cpp @@ -16,6 +16,8 @@ #include "CrateManager.h" +#ifdef ENABLE_STORAGE_CRATES + #include #include #include @@ -127,3 +129,5 @@ void CrateManager::dump(std::unique_ptr& CrateMetadata) { } // namespace installd } // namespace android + +#endif // ENABLE_STORAGE_CRATES \ No newline at end of file diff --git a/cmds/installd/CrateManager.h b/cmds/installd/CrateManager.h index 1776622d6a..4332d4cbc9 100644 --- a/cmds/installd/CrateManager.h +++ b/cmds/installd/CrateManager.h @@ -17,6 +17,8 @@ #ifndef ANDROID_INSTALLD_CRATE_INFO_MANAGER_H #define ANDROID_INSTALLD_CRATE_INFO_MANAGER_H +#ifdef ENABLE_STORAGE_CRATES + #include #include #include @@ -79,4 +81,9 @@ private: } // namespace installd } // namespace android +#else // ENABLE_STORAGE_CRATES +#include +using android::os::storage::CrateMetadata; +#endif // ENABLE_STORAGE_CRATES + #endif // ANDROID_INSTALLD_CRATE_INFO_MANAGER_H diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 42887359d1..3713e8732b 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -2054,6 +2054,7 @@ binder::Status InstalldNativeService::getAppCrates( for (const auto& packageName : packageNames) { CHECK_ARGUMENT_PACKAGE_NAME(packageName); } +#ifdef ENABLE_STORAGE_CRATES std::lock_guard lock(mLock); auto retVector = std::make_unique>>(); @@ -2083,6 +2084,14 @@ binder::Status InstalldNativeService::getAppCrates( #endif *_aidl_return = std::move(retVector); +#else // ENABLE_STORAGE_CRATES + *_aidl_return = nullptr; + + /* prevent compile warning fail */ + if (userId < 0) { + return error(); + } +#endif // ENABLE_STORAGE_CRATES return ok(); } @@ -2091,6 +2100,7 @@ binder::Status InstalldNativeService::getUserCrates( std::unique_ptr>>* _aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); +#ifdef ENABLE_STORAGE_CRATES std::lock_guard lock(mLock); const char* uuid_ = uuid ? uuid->c_str() : nullptr; @@ -2118,6 +2128,14 @@ binder::Status InstalldNativeService::getUserCrates( #endif *_aidl_return = std::move(retVector); +#else // ENABLE_STORAGE_CRATES + *_aidl_return = nullptr; + + /* prevent compile warning fail */ + if (userId < 0) { + return error(); + } +#endif // ENABLE_STORAGE_CRATES return ok(); } -- GitLab From d7a703c592bb8f57964f5b56b0a8111049458f81 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Tue, 18 Feb 2020 12:02:22 -0500 Subject: [PATCH 0820/1255] Add hinge angle sensor enum docs Bug: 148954908 Test: N/A Change-Id: I1c75bdf8b0fcaad4128336dbe4515e10ff570235 --- include/android/sensor.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/android/sensor.h b/include/android/sensor.h index e63ac4b407..eb407794d1 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -244,6 +244,9 @@ enum { ASENSOR_TYPE_ACCELEROMETER_UNCALIBRATED = 35, /** * {@link ASENSOR_TYPE_HINGE_ANGLE} + * reporting-mode: on-change + * + * The hinge angle sensor value is returned in degrees. */ ASENSOR_TYPE_HINGE_ANGLE = 36, }; -- GitLab From 0e328f6a641f256c49e2f063207eca6ddd02be60 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Thu, 6 Feb 2020 17:12:08 -0800 Subject: [PATCH 0821/1255] SurfaceControl: C++ Binding Lifetime refactoring First we eliminate the "dropReferenceTransaction" semantic. This semantic reparents the surface to null if the C++ object dies before release() is called. This is a legacy semantic from before SurfaceControls were reference counted. I point that it's unused by noting that all Java code paths will lead to calling release() in the JNI code before dropping the last reference. With dropReferenceTransaction gone we can remove mOwned it has no further uses. With these gone we now remove release() all together on the native side. This means that mClient and mHandle will only be written from the constructor and destructor making access to them thread-safe as long as you hold an sp<> to the SurfaceControl. This should prevent bugs like we've had in the past about who calls release when, no one calls it! The final question is: is removing the call to release on the Java side safe? We still need an explicit Java binding release call so we can drop the native reference in a timely fashion. This then breaks down in to two scenarios: 1. We are the last reference 2. Someone else holds a reference If we are in the first scenario, then calling release or not is equivalent to just dropping the reference. If we are in the second scenario, calling release() will be unsafe. Because we could at any time overwrite mClient/mHandle after the other ref holder had verified it was null. The main path I know of for how native code could acquire a second reference to the JNI owned SurfaceControl is via Transaction::registerSurfaceControlForCallback then if we release while Transaction::writeToParcel is running, it will inevitably segfault. This change could lead to the extension of life-time for SurfaceControl.cpp objects while the Transaction containing them is alive (but previously the SurfaceControl.cpp proxy would have been released). I also argue this is safe since the sp itself was reffed in another place in the Transaction so the lifetime of the actual server side resource isn't extended at all. Only the lightweight proxy object. Bug: 149055469 Bug: 149315421 Test: Existing tests pass. Change-Id: Ibd4d1804ef18a9c389c7f9112d15872cfe44b22e --- libs/gui/SurfaceComposerClient.cpp | 19 ++----------------- libs/gui/SurfaceControl.cpp | 17 ++--------------- libs/gui/include/gui/SurfaceComposerClient.h | 6 ------ libs/gui/include/gui/SurfaceControl.h | 7 +------ ...LayerTypeAndRenderTypeTransaction_test.cpp | 3 ++- .../surfaceflinger/tests/LayerUpdate_test.cpp | 2 ++ 6 files changed, 9 insertions(+), 45 deletions(-) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 7017b7c8f3..ff8b719009 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -526,21 +526,6 @@ void SurfaceComposerClient::Transaction::clear() { mDesiredPresentTime = -1; } -void SurfaceComposerClient::doDropReferenceTransaction(const sp& handle) { - sp sf(ComposerService::getComposerService()); - Vector composerStates; - Vector displayStates; - - ComposerState s; - s.state.surface = handle; - s.state.what |= layer_state_t::eReparent; - s.state.parentHandleForChild = nullptr; - - composerStates.add(s); - sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState(composerStates, displayStates, 0, applyToken, {}, -1, {}, false, {}); -} - void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { sp sf(ComposerService::getComposerService()); @@ -1558,7 +1543,7 @@ sp SurfaceComposerClient::createWithSurfaceParent(const String8& } ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err)); if (err == NO_ERROR) { - return new SurfaceControl(this, handle, gbp, true /* owned */, transformHint); + return new SurfaceControl(this, handle, gbp, transformHint); } } return nullptr; @@ -1589,7 +1574,7 @@ status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32 } ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err)); if (err == NO_ERROR) { - *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */, transformHint); + *outSurface = new SurfaceControl(this, handle, gbp, transformHint); } } return err; diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 6292388ac3..a332a1f2a8 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -46,33 +46,21 @@ namespace android { // ============================================================================ SurfaceControl::SurfaceControl(const sp& client, const sp& handle, - const sp& gbp, bool owned, + const sp& gbp, uint32_t transform) : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp), - mOwned(owned), mTransformHint(transform) {} SurfaceControl::SurfaceControl(const sp& other) { mClient = other->mClient; mHandle = other->mHandle; mGraphicBufferProducer = other->mGraphicBufferProducer; - mOwned = false; mTransformHint = other->mTransformHint; } SurfaceControl::~SurfaceControl() -{ - // Avoid reparenting the server-side surface to null if we are not the owner of it, - // meaning that we retrieved it from another process. - if (mHandle != nullptr && mOwned) { - SurfaceComposerClient::doDropReferenceTransaction(mHandle); - } - release(); -} - -void SurfaceControl::release() { // Trigger an IPC now, to make sure things // happen without delay, since these resources are quite heavy. @@ -157,7 +145,6 @@ sp SurfaceControl::createSurface() const sp SurfaceControl::getHandle() const { - Mutex::Autolock lock(mLock); return mHandle; } @@ -206,7 +193,7 @@ sp SurfaceControl::readFromParcel(const Parcel* parcel) { return new SurfaceControl(new SurfaceComposerClient( interface_cast(client)), handle.get(), interface_cast(gbp), - false /* owned */, transformHint); + transformHint); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index d0bb6a39ec..27877bb174 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -183,12 +183,6 @@ public: */ static bool getProtectedContentSupport(); - /** - * Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it - * to null), but without needing an sp to avoid infinite ressurection. - */ - static void doDropReferenceTransaction(const sp& handle); - /** * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is * in order with other transactions that use buffers. diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index 7bc7c686c9..ac2bbccfd2 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -58,10 +58,6 @@ public: static bool isSameSurface( const sp& lhs, const sp& rhs); - // Release the handles assosciated with the SurfaceControl, without reparenting - // them off-screen. At the moment if this isn't executed before ~SurfaceControl - // is called then the destructor will reparent the layer off-screen for you. - void release(); // Reparent off-screen and release. This is invoked by the destructor. void destroy(); @@ -89,7 +85,7 @@ public: explicit SurfaceControl(const sp& other); SurfaceControl(const sp& client, const sp& handle, - const sp& gbp, bool owned, uint32_t transformHint = 0); + const sp& gbp, uint32_t transformHint = 0); private: // can't be copied @@ -109,7 +105,6 @@ private: sp mGraphicBufferProducer; mutable Mutex mLock; mutable sp mSurfaceData; - bool mOwned; uint32_t mTransformHint; }; diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index dbace11dcb..2fd257945f 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -92,7 +92,8 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetRelativeZBug64572777) { .setRelativeLayer(layerG, layerR->getHandle(), 1) .apply(); - layerG.clear(); + Transaction().reparent(layerG, nullptr).apply(); + // layerG should have been removed getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); } diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index cf3f8e8865..cdd9d92063 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -542,6 +542,7 @@ TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) { mCapture->checkPixel(64, 64, 111, 111, 111); } + Transaction().reparent(mChild, nullptr).apply(); mChild.clear(); { @@ -1702,6 +1703,7 @@ TEST_F(ScreenCaptureTest, CaptureInvalidLayer) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); auto redLayerHandle = redLayer->getHandle(); + Transaction().reparent(redLayer, nullptr).apply(); redLayer.clear(); SurfaceComposerClient::Transaction().apply(true); -- GitLab From e38a1414c4bc3643aa314f623783f9dc4f48db65 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Thu, 13 Feb 2020 21:28:37 -0500 Subject: [PATCH 0822/1255] Update sensors framework for HAL 2.1 Bug: 144139857 Test: Run sensors framework w/ default HAL 2.1 running Change-Id: I56de4da2da30dadecb48d6ef6e6e2a5d9088f96a --- services/sensorservice/Android.bp | 9 +- services/sensorservice/SensorDevice.cpp | 121 +++++++++------ services/sensorservice/SensorDevice.h | 14 +- services/sensorservice/SensorsWrapper.h | 194 ------------------------ 4 files changed, 93 insertions(+), 245 deletions(-) delete mode 100644 services/sensorservice/SensorsWrapper.h diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp index 5246c78866..532a2e5a13 100644 --- a/services/sensorservice/Android.bp +++ b/services/sensorservice/Android.bp @@ -33,6 +33,10 @@ cc_library_shared { "-fvisibility=hidden" ], + header_libs: [ + "android.hardware.sensors@2.X-shared-utils", + ], + shared_libs: [ "libcutils", "libhardware", @@ -49,9 +53,12 @@ cc_library_shared { "libfmq", "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", + "android.hardware.sensors@2.1", ], - static_libs: ["android.hardware.sensors@1.0-convert"], + static_libs: [ + "android.hardware.sensors@1.0-convert", + ], generated_headers: ["framework-cppstream-protos"], diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index 33f940fe80..3b68e0e097 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -16,8 +16,10 @@ #include "SensorDevice.h" -#include "android/hardware/sensors/2.0/ISensorsCallback.h" #include "android/hardware/sensors/2.0/types.h" +#include "android/hardware/sensors/2.1/ISensorsCallback.h" +#include "android/hardware/sensors/2.1/types.h" +#include "convertV2_1.h" #include "SensorService.h" #include @@ -35,9 +37,15 @@ using namespace android::hardware::sensors; using namespace android::hardware::sensors::V1_0; using namespace android::hardware::sensors::V1_0::implementation; -using android::hardware::sensors::V2_0::ISensorsCallback; using android::hardware::sensors::V2_0::EventQueueFlagBits; using android::hardware::sensors::V2_0::WakeLockQueueFlagBits; +using android::hardware::sensors::V2_1::ISensorsCallback; +using android::hardware::sensors::V2_1::implementation::convertToOldSensorInfo; +using android::hardware::sensors::V2_1::implementation::convertToNewSensorInfos; +using android::hardware::sensors::V2_1::implementation::convertToNewEvents; +using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV1_0; +using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_0; +using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_1; using android::hardware::hidl_vec; using android::hardware::Return; using android::SensorDeviceUtils::HidlServiceRegistrationWaiter; @@ -87,11 +95,19 @@ void SensorsHalDeathReceivier::serviceDied( struct SensorsCallback : public ISensorsCallback { using Result = ::android::hardware::sensors::V1_0::Result; - Return onDynamicSensorsConnected( + using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo; + + Return onDynamicSensorsConnected_2_1( const hidl_vec &dynamicSensorsAdded) override { return SensorDevice::getInstance().onDynamicSensorsConnected(dynamicSensorsAdded); } + Return onDynamicSensorsConnected( + const hidl_vec &dynamicSensorsAdded) override { + return SensorDevice::getInstance().onDynamicSensorsConnected( + convertToNewSensorInfos(dynamicSensorsAdded)); + } + Return onDynamicSensorsDisconnected( const hidl_vec &dynamicSensorHandlesRemoved) override { return SensorDevice::getInstance().onDynamicSensorsDisconnected( @@ -126,7 +142,7 @@ void SensorDevice::initializeSensorList() { Info model; for (size_t i=0 ; i < count; i++) { sensor_t sensor; - convertToSensor(list[i], &sensor); + convertToSensor(convertToOldSensorInfo(list[i]), &sensor); // Sanity check and clamp power if it is 0 (or close) if (sensor.power < minPowerMa) { ALOGI("Reported power %f not deemed sane, clamping to %f", @@ -160,7 +176,11 @@ SensorDevice::~SensorDevice() { } bool SensorDevice::connectHidlService() { - HalConnectionStatus status = connectHidlServiceV2_0(); + HalConnectionStatus status = connectHidlServiceV2_1(); + if (status == HalConnectionStatus::DOES_NOT_EXIST) { + status = connectHidlServiceV2_0(); + } + if (status == HalConnectionStatus::DOES_NOT_EXIST) { status = connectHidlServiceV1_0(); } @@ -180,7 +200,7 @@ SensorDevice::HalConnectionStatus SensorDevice::connectHidlServiceV1_0() { break; } - mSensors = new SensorServiceUtil::SensorsWrapperV1_0(sensors); + mSensors = new ISensorsWrapperV1_0(sensors); mRestartWaiter->reset(); // Poke ISensor service. If it has lingering connection from previous generation of // system server, it will kill itself. There is no intention to handle the poll result, @@ -208,40 +228,55 @@ SensorDevice::HalConnectionStatus SensorDevice::connectHidlServiceV2_0() { if (sensors == nullptr) { connectionStatus = HalConnectionStatus::DOES_NOT_EXIST; } else { - mSensors = new SensorServiceUtil::SensorsWrapperV2_0(sensors); + mSensors = new ISensorsWrapperV2_0(sensors); + connectionStatus = initializeHidlServiceV2_X(); + } - mEventQueue = std::make_unique( - SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT, - true /* configureEventFlagWord */); + return connectionStatus; +} - mWakeLockQueue = std::make_unique( - SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT, - true /* configureEventFlagWord */); +SensorDevice::HalConnectionStatus SensorDevice::connectHidlServiceV2_1() { + HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN; + sp sensors = V2_1::ISensors::getService(); - hardware::EventFlag::deleteEventFlag(&mEventQueueFlag); - hardware::EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag); + if (sensors == nullptr) { + connectionStatus = HalConnectionStatus::DOES_NOT_EXIST; + } else { + mSensors = new ISensorsWrapperV2_1(sensors); + connectionStatus = initializeHidlServiceV2_X(); + } - hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag); - hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), - &mWakeLockQueueFlag); + return connectionStatus; +} - CHECK(mSensors != nullptr && mEventQueue != nullptr && - mWakeLockQueue != nullptr && mEventQueueFlag != nullptr && - mWakeLockQueueFlag != nullptr); +SensorDevice::HalConnectionStatus SensorDevice::initializeHidlServiceV2_X() { + HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN; - status_t status = checkReturnAndGetStatus(mSensors->initialize( - *mEventQueue->getDesc(), - *mWakeLockQueue->getDesc(), - new SensorsCallback())); + mWakeLockQueue = std::make_unique( + SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT, + true /* configureEventFlagWord */); - if (status != NO_ERROR) { - connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT; - ALOGE("Failed to initialize Sensors HAL (%s)", strerror(-status)); - } else { - connectionStatus = HalConnectionStatus::CONNECTED; - mSensorsHalDeathReceiver = new SensorsHalDeathReceivier(); - sensors->linkToDeath(mSensorsHalDeathReceiver, 0 /* cookie */); - } + hardware::EventFlag::deleteEventFlag(&mEventQueueFlag); + hardware::EventFlag::createEventFlag(mSensors->getEventQueue()->getEventFlagWord(), &mEventQueueFlag); + + hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag); + hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), + &mWakeLockQueueFlag); + + CHECK(mSensors != nullptr && mWakeLockQueue != nullptr && + mEventQueueFlag != nullptr && mWakeLockQueueFlag != nullptr); + + status_t status = checkReturnAndGetStatus(mSensors->initialize( + *mWakeLockQueue->getDesc(), + new SensorsCallback())); + + if (status != NO_ERROR) { + connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT; + ALOGE("Failed to initialize Sensors HAL (%s)", strerror(-status)); + } else { + connectionStatus = HalConnectionStatus::CONNECTED; + mSensorsHalDeathReceiver = new SensorsHalDeathReceivier(); + mSensors->linkToDeath(mSensorsHalDeathReceiver, 0 /* cookie */); } return connectionStatus; @@ -473,7 +508,8 @@ ssize_t SensorDevice::pollHal(sensors_event_t* buffer, size_t count) { const auto &events, const auto &dynamicSensorsAdded) { if (result == Result::OK) { - convertToSensorEvents(events, dynamicSensorsAdded, buffer); + convertToSensorEvents(convertToNewEvents(events), + convertToNewSensorInfos(dynamicSensorsAdded), buffer); err = (ssize_t)events.size(); } else { err = statusFromResult(result); @@ -507,7 +543,7 @@ ssize_t SensorDevice::pollHal(sensors_event_t* buffer, size_t count) { ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead) { ssize_t eventsRead = 0; - size_t availableEvents = mEventQueue->availableToRead(); + size_t availableEvents = mSensors->getEventQueue()->availableToRead(); if (availableEvents == 0) { uint32_t eventFlagState = 0; @@ -518,7 +554,7 @@ ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead // additional latency in delivering events to applications. mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS) | asBaseType(INTERNAL_WAKE), &eventFlagState); - availableEvents = mEventQueue->availableToRead(); + availableEvents = mSensors->getEventQueue()->availableToRead(); if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mReconnecting) { ALOGD("Event FMQ internal wake, returning from poll with no events"); @@ -528,7 +564,7 @@ ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead size_t eventsToRead = std::min({availableEvents, maxNumEventsToRead, mEventBuffer.size()}); if (eventsToRead > 0) { - if (mEventQueue->read(mEventBuffer.data(), eventsToRead)) { + if (mSensors->getEventQueue()->read(mEventBuffer.data(), eventsToRead)) { // Notify the Sensors HAL that sensor events have been read. This is required to support // the use of writeBlocking by the Sensors HAL. mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::EVENTS_READ)); @@ -557,7 +593,7 @@ Return SensorDevice::onDynamicSensorsConnected( CHECK(it == mConnectedDynamicSensors.end()); sensor_t *sensor = new sensor_t(); - convertToSensor(info, sensor); + convertToSensor(convertToOldSensorInfo(info), sensor); mConnectedDynamicSensors.insert( std::make_pair(sensor->handle, sensor)); @@ -858,7 +894,7 @@ status_t SensorDevice::injectSensorData( injected_sensor_event->data[5]); Event ev; - convertFromSensorEvent(*injected_sensor_event, &ev); + V2_1::implementation::convertFromSensorEvent(*injected_sensor_event, &ev); return checkReturnAndGetStatus(mSensors->injectSensorData(ev)); } @@ -1021,10 +1057,9 @@ bool SensorDevice::isDirectReportSupported() const { void SensorDevice::convertToSensorEvent( const Event &src, sensors_event_t *dst) { - ::android::hardware::sensors::V1_0::implementation::convertToSensorEvent( - src, dst); + V2_1::implementation::convertToSensorEvent(src, dst); - if (src.sensorType == SensorType::DYNAMIC_SENSOR_META) { + if (src.sensorType == V2_1::SensorType::DYNAMIC_SENSOR_META) { const DynamicSensorInfo &dyn = src.u.dynamic; dst->dynamic_sensor_meta.connected = dyn.connected; @@ -1052,7 +1087,7 @@ void SensorDevice::convertToSensorEvents( } for (size_t i = 0; i < src.size(); ++i) { - convertToSensorEvent(src[i], &dst[i]); + V2_1::implementation::convertToSensorEvent(src[i], &dst[i]); } } diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h index 33aa7d64b0..24d03c63c2 100644 --- a/services/sensorservice/SensorDevice.h +++ b/services/sensorservice/SensorDevice.h @@ -19,7 +19,7 @@ #include "SensorDeviceUtils.h" #include "SensorServiceUtils.h" -#include "SensorsWrapper.h" +#include "ISensorsWrapper.h" #include #include @@ -112,7 +112,7 @@ public: using Result = ::android::hardware::sensors::V1_0::Result; hardware::Return onDynamicSensorsConnected( - const hardware::hidl_vec &dynamicSensorsAdded); + const hardware::hidl_vec &dynamicSensorsAdded); hardware::Return onDynamicSensorsDisconnected( const hardware::hidl_vec &dynamicSensorHandlesRemoved); @@ -128,7 +128,7 @@ public: private: friend class Singleton; - sp mSensors; + sp<::android::hardware::sensors::V2_1::implementation::ISensorsWrapperBase> mSensors; Vector mSensorList; std::unordered_map mConnectedDynamicSensors; @@ -205,6 +205,8 @@ private: }; HalConnectionStatus connectHidlServiceV1_0(); HalConnectionStatus connectHidlServiceV2_0(); + HalConnectionStatus connectHidlServiceV2_1(); + HalConnectionStatus initializeHidlServiceV2_X(); ssize_t pollHal(sensors_event_t* buffer, size_t count); ssize_t pollFmq(sensors_event_t* buffer, size_t count); @@ -226,8 +228,8 @@ private: bool isClientDisabled(void* ident); bool isClientDisabledLocked(void* ident); - using Event = hardware::sensors::V1_0::Event; - using SensorInfo = hardware::sensors::V1_0::SensorInfo; + using Event = hardware::sensors::V2_1::Event; + using SensorInfo = hardware::sensors::V2_1::SensorInfo; void convertToSensorEvent(const Event &src, sensors_event_t *dst); @@ -238,9 +240,7 @@ private: bool mIsDirectReportSupported; - typedef hardware::MessageQueue EventMessageQueue; typedef hardware::MessageQueue WakeLockQueue; - std::unique_ptr mEventQueue; std::unique_ptr mWakeLockQueue; hardware::EventFlag* mEventQueueFlag; diff --git a/services/sensorservice/SensorsWrapper.h b/services/sensorservice/SensorsWrapper.h deleted file mode 100644 index d1a72345f7..0000000000 --- a/services/sensorservice/SensorsWrapper.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_SENSORS_WRAPPER_H -#define ANDROID_SENSORS_WRAPPER_H - -#include "android/hardware/sensors/1.0/ISensors.h" -#include "android/hardware/sensors/2.0/ISensors.h" -#include "android/hardware/sensors/2.0/ISensorsCallback.h" - -#include - -namespace android { -namespace SensorServiceUtil { - -using ::android::hardware::MQDescriptorSync; -using ::android::hardware::Return; -using ::android::hardware::sensors::V1_0::Event; -using ::android::hardware::sensors::V1_0::ISensors; -using ::android::hardware::sensors::V1_0::OperationMode; -using ::android::hardware::sensors::V1_0::RateLevel; -using ::android::hardware::sensors::V1_0::Result; -using ::android::hardware::sensors::V1_0::SharedMemInfo; -using ::android::hardware::sensors::V2_0::ISensorsCallback; - -/* - * The ISensorsWrapper interface includes all function from supported Sensors HAL versions. This - * allows for the SensorDevice to use the ISensorsWrapper interface to interact with the Sensors - * HAL regardless of the current version of the Sensors HAL that is loaded. Each concrete - * instantiation of ISensorsWrapper must correspond to a specific Sensors HAL version. This design - * is beneficial because only the functions that change between Sensors HAL versions must be newly - * newly implemented, any previously implemented function that does not change may remain the same. - * - * Functions that exist across all versions of the Sensors HAL should be implemented as pure - * virtual functions which forces the concrete instantiations to implement the functions. - * - * Functions that do not exist across all versions of the Sensors HAL should include a default - * implementation that generates an error if called. The default implementation should never - * be called and must be overridden by Sensors HAL versions that support the function. - */ -class ISensorsWrapper : public VirtualLightRefBase { -public: - virtual bool supportsPolling() const = 0; - - virtual bool supportsMessageQueues() const = 0; - - virtual Return getSensorsList(ISensors::getSensorsList_cb _hidl_cb) = 0; - - virtual Return setOperationMode(OperationMode mode) = 0; - - virtual Return activate(int32_t sensorHandle, bool enabled) = 0; - - virtual Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) = 0; - - virtual Return flush(int32_t sensorHandle) = 0; - - virtual Return injectSensorData(const Event& event) = 0; - - virtual Return registerDirectChannel(const SharedMemInfo& mem, - ISensors::registerDirectChannel_cb _hidl_cb) = 0; - - virtual Return unregisterDirectChannel(int32_t channelHandle) = 0; - - virtual Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, - RateLevel rate, - ISensors::configDirectReport_cb _hidl_cb) = 0; - - virtual Return poll(int32_t maxCount, ISensors::poll_cb _hidl_cb) { - (void)maxCount; - (void)_hidl_cb; - // TODO (b/111070257): Generate an assert-level error since this should never be called - // directly - return Return(); - } - - virtual Return initialize(const MQDescriptorSync& eventQueueDesc, - const MQDescriptorSync& wakeLockDesc, - const ::android::sp& callback) { - (void)eventQueueDesc; - (void)wakeLockDesc; - (void)callback; - // TODO (b/111070257): Generate an assert-level error since this should never be called - // directly - return Result::INVALID_OPERATION; - } -}; - -template -class SensorsWrapperBase : public ISensorsWrapper { -public: - SensorsWrapperBase(sp sensors) : - mSensors(sensors) { }; - - Return getSensorsList(ISensors::getSensorsList_cb _hidl_cb) override { - return mSensors->getSensorsList(_hidl_cb); - } - - Return setOperationMode(OperationMode mode) override { - return mSensors->setOperationMode(mode); - } - - Return activate(int32_t sensorHandle, bool enabled) override { - return mSensors->activate(sensorHandle, enabled); - } - - Return batch(int32_t sensorHandle, int64_t samplingPeriodNs, - int64_t maxReportLatencyNs) override { - return mSensors->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); - } - - Return flush(int32_t sensorHandle) override { - return mSensors->flush(sensorHandle); - } - - Return injectSensorData(const Event& event) override { - return mSensors->injectSensorData(event); - } - - Return registerDirectChannel(const SharedMemInfo& mem, - ISensors::registerDirectChannel_cb _hidl_cb) override { - return mSensors->registerDirectChannel(mem, _hidl_cb); - } - - Return unregisterDirectChannel(int32_t channelHandle) override { - return mSensors->unregisterDirectChannel(channelHandle); - } - - Return configDirectReport(int32_t sensorHandle, int32_t channelHandle, - RateLevel rate, - ISensors::configDirectReport_cb _hidl_cb) override { - return mSensors->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); - } - -protected: - sp mSensors; -}; - -class SensorsWrapperV1_0 : public SensorsWrapperBase { -public: - SensorsWrapperV1_0(sp sensors) : - SensorsWrapperBase(sensors) { }; - - bool supportsPolling() const override { - return true; - } - - bool supportsMessageQueues() const override { - return false; - } - - Return poll(int32_t maxCount, - hardware::sensors::V1_0::ISensors::poll_cb _hidl_cb) override { - return mSensors->poll(maxCount, _hidl_cb); - } -}; - -class SensorsWrapperV2_0 : public SensorsWrapperBase { -public: - SensorsWrapperV2_0(sp sensors) - : SensorsWrapperBase(sensors) { }; - - bool supportsPolling() const override { - return false; - } - - bool supportsMessageQueues() const override { - return true; - } - - Return initialize(const MQDescriptorSync& eventQueueDesc, - const MQDescriptorSync& wakeLockDesc, - const ::android::sp& callback) override { - return mSensors->initialize(eventQueueDesc, wakeLockDesc, callback); - } -}; - -}; // namespace SensorServiceUtil -}; // namespace android - -#endif // ANDROID_SENSORS_WRAPPER_H -- GitLab From 4ccdcb4162194f844e1eab73d5cf5dd1650d1295 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 11 Feb 2020 17:34:34 -0800 Subject: [PATCH 0823/1255] SurfaceFlinger: allow switching when layers vote to refresh rate This CL is a refinement of the refresh rate switching algorithm to allow refresh rate switching even if some of the layers voted explicitly for a refresh rate. Test: Run ExoPlayer demo app and scroll the list while playing a video Bug: 147516364 Change-Id: Id01ff8477804bba9e859545e20b05eeb1ec0d319 --- .../surfaceflinger/Scheduler/LayerHistory.cpp | 1 + .../surfaceflinger/Scheduler/LayerInfoV2.cpp | 30 +- .../surfaceflinger/Scheduler/LayerInfoV2.h | 4 +- .../Scheduler/RefreshRateConfigs.cpp | 146 ++++--- .../Scheduler/RefreshRateConfigs.h | 19 +- .../surfaceflinger/Scheduler/Scheduler.cpp | 55 +-- services/surfaceflinger/Scheduler/Scheduler.h | 4 +- .../unittests/RefreshRateConfigsTest.cpp | 379 ++++++++++++++---- 8 files changed, 437 insertions(+), 201 deletions(-) diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index b313777253..bc0111b044 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -97,6 +97,7 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now) { } LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { + ATRACE_CALL(); std::lock_guard lock(mLock); partitionLayers(now); diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp index 345b8f93fd..b755798a92 100644 --- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp @@ -61,21 +61,35 @@ bool LayerInfoV2::isFrameTimeValid(const FrameTimeData& frameTime) const { } bool LayerInfoV2::isFrequent(nsecs_t now) const { + // Find the first valid frame time + auto it = mFrameTimes.begin(); + for (; it != mFrameTimes.end(); ++it) { + if (isFrameTimeValid(*it)) { + break; + } + } + // 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) { + if (std::distance(it, mFrameTimes.end()) < FREQUENT_LAYER_WINDOW_SIZE) { return true; } - // Layer is frequent if the earliest value in the window of most recent present times is - // within threshold. - const auto it = mFrameTimes.end() - FREQUENT_LAYER_WINDOW_SIZE; - if (!isFrameTimeValid(*it)) { - return true; + // Find the first active frame + for (; it != mFrameTimes.end(); ++it) { + if (it->queueTime >= getActiveLayerThreshold(now)) { + break; + } + } + + const auto numFrames = std::distance(it, mFrameTimes.end()) - 1; + if (numFrames <= 0) { + return false; } - const nsecs_t threshold = now - MAX_FREQUENT_LAYER_PERIOD_NS.count(); - return it->queueTime >= threshold; + // Layer is considered frequent if the average frame rate is higher than the threshold + const auto totalTime = mFrameTimes.back().queueTime - it->queueTime; + return (1e9f * numFrames) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER; } bool LayerInfoV2::hasEnoughDataForHeuristic() const { diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h index 90f6310d3b..25fb95a451 100644 --- a/services/surfaceflinger/Scheduler/LayerInfoV2.h +++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h @@ -47,7 +47,9 @@ class LayerInfoV2 { // is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in // favor of a low refresh rate. static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3; - static constexpr std::chrono::nanoseconds MAX_FREQUENT_LAYER_PERIOD_NS = 250ms; + static constexpr float MIN_FPS_FOR_FREQUENT_LAYER = 10.0f; + static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = + std::chrono::nanoseconds(static_cast(1e9f / MIN_FPS_FOR_FREQUENT_LAYER)) + 1ms; friend class LayerHistoryTestV2; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index d1de737a89..b876ccdc7e 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -23,8 +23,6 @@ #include #include -using namespace std::chrono_literals; - namespace android::scheduler { using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType; @@ -84,14 +82,31 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContent( return *bestSoFar; } +std::pair RefreshRateConfigs::getDisplayFrames(nsecs_t layerPeriod, + nsecs_t displayPeriod) const { + auto [displayFramesQuot, displayFramesRem] = std::div(layerPeriod, displayPeriod); + if (displayFramesRem <= MARGIN_FOR_PERIOD_CALCULATION || + std::abs(displayFramesRem - displayPeriod) <= MARGIN_FOR_PERIOD_CALCULATION) { + displayFramesQuot++; + displayFramesRem = 0; + } + + return {displayFramesQuot, displayFramesRem}; +} + const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( - const std::vector& layers) const { - constexpr nsecs_t MARGIN = std::chrono::nanoseconds(800us).count(); + const std::vector& layers, bool touchActive) const { ATRACE_CALL(); ALOGV("getRefreshRateForContent %zu layers", layers.size()); std::lock_guard lock(mLock); + // For now if the touch is active return the peak refresh rate + // This should be optimized to consider other layers as well. + if (touchActive) { + return *mAvailableRefreshRates.back(); + } + int noVoteLayers = 0; int minVoteLayers = 0; int maxVoteLayers = 0; @@ -115,11 +130,6 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( return *mAvailableRefreshRates.front(); } - // If we have some Max layers and no Explicit we should return Max - if (maxVoteLayers > 0 && explicitDefaultVoteLayers + explicitExactOrMultipleVoteLayers == 0) { - return *mAvailableRefreshRates.back(); - } - // Find the best refresh rate based on score std::vector> scores; scores.reserve(mAvailableRefreshRates.size()); @@ -130,67 +140,85 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( for (const auto& layer : layers) { ALOGV("Calculating score for %s (type: %d)", layer.name.c_str(), layer.vote); - if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min || - layer.vote == LayerVoteType::Max) { + if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) { 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 i = 0u; i < scores.size(); i++) { + // If the layer wants Max, give higher score to the higher refresh rate + if (layer.vote == LayerVoteType::Max) { + const auto ratio = scores[i].first->fps / scores.back().first->fps; + // use ratio^2 to get a lower score the more we get further from peak + const auto layerScore = ratio * ratio; + ALOGV("%s (Max, weight %.2f) gives %s score of %.2f", layer.name.c_str(), weight, + scores[i].first->name.c_str(), layerScore); + scores[i].second += weight * layerScore; + continue; } - } - for (auto& [refreshRate, overallScore] : scores) { - const auto displayPeriod = refreshRate->vsyncPeriod; + const auto displayPeriod = scores[i].first->vsyncPeriod; const auto layerPeriod = round(1e9f / layer.desiredRefreshRate); - - // Calculate how many display vsyncs we need to present a single frame for this layer - auto [displayFramesQuot, displayFramesRem] = std::div(layerPeriod, displayPeriod); - if (displayFramesRem <= MARGIN || - std::abs(displayFramesRem - displayPeriod) <= MARGIN) { - displayFramesQuot++; - displayFramesRem = 0; + if (layer.vote == LayerVoteType::ExplicitDefault) { + const auto layerScore = [&]() { + const auto [displayFramesQuot, displayFramesRem] = + getDisplayFrames(layerPeriod, displayPeriod); + if (displayFramesQuot == 0) { + // Layer desired refresh rate is higher the display rate. + return static_cast(layerPeriod) / static_cast(displayPeriod); + } + + return 1.0f - + (static_cast(displayFramesRem) / + static_cast(layerPeriod)); + }(); + + ALOGV("%s (ExplicitDefault, weight %.2f) %.2fHz gives %s score of %.2f", + layer.name.c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), + layerScore); + scores[i].second += weight * layerScore; + continue; } - float layerScore; - 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 = weight * 1.0f; - } else if (displayFramesQuot == 0) { - // Layer desired refresh rate is higher the display rate. - layerScore = weight * - (static_cast(layerPeriod) / static_cast(displayPeriod)) * - (1.0f / (MAX_FRAMES_TO_FIT + 1)); - } else { - // Layer desired refresh rate is lower the display rate. Check how well it fits the - // cadence - auto diff = std::abs(displayFramesRem - (displayPeriod - displayFramesRem)); - int iter = 2; - while (diff > MARGIN && iter < MAX_FRAMES_TO_FIT) { - diff = diff - (displayPeriod - diff); - iter++; - } - - layerScore = weight * (1.0f / iter); + if (layer.vote == LayerVoteType::ExplicitExactOrMultiple || + layer.vote == LayerVoteType::Heuristic) { + const auto layerScore = [&]() { + // Calculate how many display vsyncs we need to present a single frame for this + // layer + const auto [displayFramesQuot, displayFramesRem] = + getDisplayFrames(layerPeriod, displayPeriod); + 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. + return 1.0f; + } + + if (displayFramesQuot == 0) { + // Layer desired refresh rate is higher the display rate. + return (static_cast(layerPeriod) / + static_cast(displayPeriod)) * + (1.0f / (MAX_FRAMES_TO_FIT + 1)); + } + + // Layer desired refresh rate is lower the display rate. Check how well it fits + // the cadence + auto diff = std::abs(displayFramesRem - (displayPeriod - displayFramesRem)); + int iter = 2; + while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) { + diff = diff - (displayPeriod - diff); + iter++; + } + + return 1.0f / iter; + }(); + ALOGV("%s (ExplicitExactOrMultiple, weight %.2f) %.2fHz gives %s score of %.2f", + layer.name.c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), + layerScore); + scores[i].second += weight * layerScore; + continue; } - - ALOGV("%s (weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), weight, - 1e9f / layerPeriod, refreshRate->name.c_str(), layerScore); - overallScore += layerScore; } } diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 1132a8c58c..0b5c73c9b7 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -28,6 +28,7 @@ #include "Scheduler/StrongTyping.h" namespace android::scheduler { +using namespace std::chrono_literals; enum class RefreshRateConfigEvent : unsigned { None = 0b0, Changed = 0b1 }; @@ -43,6 +44,10 @@ inline RefreshRateConfigEvent operator|(RefreshRateConfigEvent lhs, RefreshRateC */ class RefreshRateConfigs { public: + // Margin used when matching refresh rates to the content desired ones. + static constexpr nsecs_t MARGIN_FOR_PERIOD_CALCULATION = + std::chrono::nanoseconds(800us).count(); + struct RefreshRate { // The tolerance within which we consider FPS approximately equals. static constexpr float FPS_EPSILON = 0.001f; @@ -123,13 +128,15 @@ public: bool operator!=(const LayerRequirement& other) const { return !(*this == other); } }; - // Returns all available refresh rates according to the current policy. + // Returns the refresh rate that fits best to the given layers. const RefreshRate& getRefreshRateForContent(const std::vector& layers) const EXCLUDES(mLock); - // Returns all available refresh rates according to the current policy. - const RefreshRate& getRefreshRateForContentV2(const std::vector& layers) const - EXCLUDES(mLock); + // Returns the refresh rate that fits best to the given layers. This function also gets a + // boolean flag that indicates whether user touched the screen recently to be factored in when + // choosing the refresh rate. + const RefreshRate& getRefreshRateForContentV2(const std::vector& layers, + bool touchActive) const EXCLUDES(mLock); // Returns all the refresh rates supported by the device. This won't change at runtime. const AllRefreshRatesMapType& getAllRefreshRates() const EXCLUDES(mLock); @@ -188,6 +195,10 @@ private: template const RefreshRate* getBestRefreshRate(Iter begin, Iter end) const; + // Returns number of display frames and remainder when dividing the layer refresh period by + // display refresh period. + std::pair getDisplayFrames(nsecs_t layerPeriod, nsecs_t displayPeriod) const; + // The list of refresh rates, indexed by display config ID. This must not change after this // object is initialized. AllRefreshRatesMapType mRefreshRates; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 71ac90e2d3..3a4433298a 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -439,7 +439,7 @@ void Scheduler::chooseRefreshRateForContent() { return; } mFeatures.contentRequirements = summary; - mFeatures.contentDetection = + mFeatures.contentDetectionV1 = !summary.empty() ? ContentDetectionState::On : ContentDetectionState::Off; newConfigId = calculateRefreshRateConfigIndexType(); @@ -466,7 +466,7 @@ void Scheduler::notifyTouchEvent() { // NOTE: Instead of checking all the layers, we should be checking the layer // that is currently on top. b/142507166 will give us this capability. std::lock_guard lock(mFeatureStateLock); - if (mLayerHistory && !layerHistoryHasClientSpecifiedFrameRate()) { + if (mLayerHistory) { mLayerHistory->clear(); mTouchTimer->reset(); @@ -556,7 +556,7 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO return; } mFeatures.configId = newConfigId; - if (eventOnContentDetection && mFeatures.contentDetection == ContentDetectionState::On) { + if (eventOnContentDetection && !mFeatures.contentRequirements.empty()) { event = ConfigEvent::Changed; } } @@ -564,33 +564,10 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO mSchedulerCallback.changeRefreshRate(newRefreshRate, event); } -bool Scheduler::layerHistoryHasClientSpecifiedFrameRate() { - // Traverse all the layers to see if any of them requested frame rate. - for (const auto& layer : mFeatures.contentRequirements) { - if (layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitDefault || - layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitExactOrMultiple) { - return true; - } - } - - return false; -} - HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() { - // This block of the code checks whether any layers used the SetFrameRate API. If they have, - // their request should be honored depending on other active layers. - if (layerHistoryHasClientSpecifiedFrameRate()) { - if (!mUseContentDetectionV2) { - return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements) - .configId; - } else { - return mRefreshRateConfigs.getRefreshRateForContentV2(mFeatures.contentRequirements) - .configId; - } - } + ATRACE_CALL(); - // If the layer history doesn't have the frame rate specified, check for other features and - // honor them. NOTE: If we remove the kernel idle timer, and use our internal idle timer, this + // 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. @@ -600,9 +577,11 @@ HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() { 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; + if (!mUseContentDetectionV2) { + // As long as touch is active we want to be in performance mode. + if (mTouchTimer && mFeatures.touch == TouchState::Active) { + return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId; + } } // If timer has expired as it means there is no new content on the screen. @@ -612,7 +591,7 @@ HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() { if (!mUseContentDetectionV2) { // If content detection is off we choose performance as we don't know the content fps. - if (mFeatures.contentDetection == ContentDetectionState::Off) { + if (mFeatures.contentDetectionV1 == ContentDetectionState::Off) { // NOTE: V1 always calls this, but this is not a default behavior for V2. return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId; } @@ -621,14 +600,10 @@ HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() { return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements).configId; } - // Content detection is on, find the appropriate refresh rate with minimal error - if (mFeatures.contentDetection == ContentDetectionState::On) { - return mRefreshRateConfigs.getRefreshRateForContentV2(mFeatures.contentRequirements) - .configId; - } - - // There are no signals for refresh rate, just leave it as is. - return mRefreshRateConfigs.getCurrentRefreshRateByPolicy().configId; + return mRefreshRateConfigs + .getRefreshRateForContentV2(mFeatures.contentRequirements, + mTouchTimer && mFeatures.touch == TouchState::Active) + .configId; } std::optional Scheduler::getPreferredConfigId() { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 81051be96f..46d1a5e7df 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -185,8 +185,6 @@ private: // for the suggested refresh rate. HwcConfigIndexType calculateRefreshRateConfigIndexType() REQUIRES(mFeatureStateLock); - bool layerHistoryHasClientSpecifiedFrameRate() REQUIRES(mFeatureStateLock); - // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection. struct Connection { sp connection; @@ -229,7 +227,7 @@ private: std::mutex mFeatureStateLock; struct { - ContentDetectionState contentDetection = ContentDetectionState::Off; + ContentDetectionState contentDetectionV1 = ContentDetectionState::Off; TimerState idleTimer = TimerState::Reset; TouchState touch = TouchState::Inactive; TimerState displayPowerTimer = TimerState::Expired; diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 99c5f3d4cd..7e625135ae 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -247,7 +247,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f))); } -TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_60_90) { +TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; @@ -261,100 +261,136 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_60_90 auto& lr = layers[0]; lr.vote = LayerVoteType::Min; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "Min"; + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.vote = LayerVoteType::Max; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "Max"; + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "90Hz Heuristic"; + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 60.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "60Hz Heuristic"; + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 45.0f; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "45Hz Heuristic"; + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 30.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "30Hz Heuristic"; + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 24.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "24Hz Heuristic"; + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + lr.name = ""; ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0); lr.vote = LayerVoteType::Min; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.vote = LayerVoteType::Max; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 60.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 45.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 30.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 24.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0); lr.vote = LayerVoteType::Min; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.vote = LayerVoteType::Max; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 60.0f; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 45.0f; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 30.0f; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 24.0f; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0); lr.vote = LayerVoteType::Min; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.vote = LayerVoteType::Max; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 60.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 45.0f; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 30.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 24.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); } -TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_60_72_90) { +TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_72_90) { std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72}, @@ -370,29 +406,36 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_60_72 auto& lr = layers[0]; lr.vote = LayerVoteType::Min; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.vote = LayerVoteType::Max; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 60.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 45.0f; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 30.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 24.0f; - EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected72Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); } -TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60_72_90_120) { +TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90_120) { std::vector configs{ {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}, {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, @@ -417,23 +460,25 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60 lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60.0f; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected120Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 48.0f; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected72Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 48.0f; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected72Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); } -TEST_F(RefreshRateConfigsTest, - twoDeviceConfigs_getRefreshRateForContentV2_30_60_90_120_DifferentTypes) { +TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_DifferentTypes) { std::vector configs{ {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}, {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, @@ -456,54 +501,87 @@ TEST_F(RefreshRateConfigsTest, lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitDefault; + lr1.name = "24Hz ExplicitDefault"; lr2.desiredRefreshRate = 60.0f; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr2.name = "60Hz Heuristic"; + EXPECT_EQ(expected120Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; lr2.desiredRefreshRate = 60.0f; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr2.name = "60Hz Heuristic"; + EXPECT_EQ(expected120Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; lr2.desiredRefreshRate = 60.0f; lr2.vote = LayerVoteType::ExplicitDefault; - EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr2.name = "60Hz ExplicitDefault"; + EXPECT_EQ(expected120Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; lr2.desiredRefreshRate = 90.0f; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + + lr1.desiredRefreshRate = 24.0f; + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; + lr2.desiredRefreshRate = 90.0f; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(expected72Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitDefault; + lr1.name = "24Hz ExplicitDefault"; lr2.desiredRefreshRate = 90.0f; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::Heuristic; + lr1.name = "24Hz Heuristic"; lr2.desiredRefreshRate = 90.0f; lr2.vote = LayerVoteType::ExplicitDefault; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr2.name = "90Hz ExplicitDefault"; + EXPECT_EQ(expected72Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.name = "24Hz ExplicitExactOrMultiple"; lr2.desiredRefreshRate = 90.0f; lr2.vote = LayerVoteType::ExplicitDefault; - EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr2.name = "90Hz ExplicitDefault"; + EXPECT_EQ(expected72Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitDefault; + lr1.name = "24Hz ExplicitDefault"; lr2.desiredRefreshRate = 90.0f; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr2.name = "90Hz ExplicitExactOrMultiple"; + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); } -TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60) { +TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60) { std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}}}; @@ -517,29 +595,36 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60 auto& lr = layers[0]; lr.vote = LayerVoteType::Min; - EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected30Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.vote = LayerVoteType::Max; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 60.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 45.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 30.0f; - EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected30Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 24.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); } -TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60_72_90) { +TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90) { std::vector configs{ {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}, {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, @@ -557,29 +642,59 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60 auto& lr = layers[0]; lr.vote = LayerVoteType::Min; - EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "Min"; + EXPECT_EQ(expected30Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.vote = LayerVoteType::Max; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "Max"; + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "90Hz Heuristic"; + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr.desiredRefreshRate = 60.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "60Hz Heuristic"; + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true)); lr.desiredRefreshRate = 45.0f; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "45Hz Heuristic"; + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true)); lr.desiredRefreshRate = 30.0f; - EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "30Hz Heuristic"; + EXPECT_EQ(expected30Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true)); lr.desiredRefreshRate = 24.0f; - EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr.name = "24Hz Heuristic"; + EXPECT_EQ(expected72Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true)); + + lr.desiredRefreshRate = 24.0f; + lr.vote = LayerVoteType::ExplicitExactOrMultiple; + lr.name = "24Hz ExplicitExactOrMultiple"; + EXPECT_EQ(expected72Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true)); } -TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_PriorityTest) { +TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_PriorityTest) { std::vector configs{ {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}, {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, @@ -598,42 +713,49 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Prior lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::Max; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 24.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 24.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.vote = LayerVoteType::Max; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60.0f; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.vote = LayerVoteType::Max; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 15.0f; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 45.0f; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 30.0f; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 45.0f; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); } -TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_24FpsVideo) { +TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_24FpsVideo) { std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; @@ -650,7 +772,8 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_24Fps lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { lr.desiredRefreshRate = fps; - const auto& refreshRate = refreshRateConfigs->getRefreshRateForContentV2(layers); + const auto& refreshRate = + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false); printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str()); EXPECT_EQ(expected60Config, refreshRate); } @@ -703,13 +826,22 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Expli lr1.desiredRefreshRate = 60.0f; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 90.0f; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + + lr1.vote = LayerVoteType::ExplicitDefault; + lr1.desiredRefreshRate = 90.0f; + lr2.vote = LayerVoteType::ExplicitExactOrMultiple; + lr2.desiredRefreshRate = 60.0f; + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 90.0f; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); } TEST_F(RefreshRateConfigsTest, testInPolicy) { @@ -722,7 +854,7 @@ TEST_F(RefreshRateConfigsTest, testInPolicy) { ASSERT_FALSE(expectedDefaultConfig.inPolicy(50.0f, 59.998f)); } -TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_75HzContent) { +TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_75HzContent) { std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; @@ -739,13 +871,14 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_75HzC lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) { lr.desiredRefreshRate = fps; - const auto& refreshRate = refreshRateConfigs->getRefreshRateForContentV2(layers); + const auto& refreshRate = + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false); printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str()); EXPECT_EQ(expected90Config, refreshRate); } } -TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Multiples) { +TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_Multiples) { std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; @@ -762,25 +895,99 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Multi lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60.0f; + lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 90.0f; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60.0f; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.desiredRefreshRate = 90.0f; + lr2.name = "90Hz ExplicitDefault"; + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60.0f; + lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr2.name = "Max"; + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 30.0f; + lr1.name = "30Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 90.0f; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 30.0f; + lr1.name = "30Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers)); + lr2.name = "Max"; + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); +} + +TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) { + std::vector configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); + + RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; + RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90}; + + auto layers = std::vector{LayerRequirement{.weight = 1.0f}, + LayerRequirement{.weight = 1.0f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60.0f; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::NoVote; + lr2.name = "NoVote"; + EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false)); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60.0f; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::NoVote; + lr2.name = "NoVote"; + EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, true)); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60.0f; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Max; + lr2.name = "Max"; + EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, true)); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60.0f; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Max; + lr2.name = "Max"; + EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false)); + + // The other layer starts to provide buffers + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60.0f; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Heuristic; + lr2.desiredRefreshRate = 90.0f; + lr2.name = "90Hz Heuristic"; + EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false)); } } // namespace -- GitLab From 62a4cf8c48647de3442808264005e093ab7704f0 Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Fri, 31 Jan 2020 12:04:03 -0800 Subject: [PATCH 0824/1255] Add compatibility param to setFrameRate() api Add a compatiblity param to the setFrameRate() api, so the system has more info to decide the device frame rate when there are multiple competing preferences. I also changed the plumbing for setFrameRate() to go directly to surface flinger, instead of through buffer queue. We're trying to avoid changes to buffer queue code, to avoid disturbing the prebuilts. Bug: 137287430 Test: Added new cts tests to verify behavior of the compatibility param. cts-tradefed run commandAndExit cts-dev --module CtsGraphicsTestCases --test android.graphics.cts.SetFrameRateTest Test: /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test --gtest_filter='SetFrameRateTest.*' Change-Id: Ibe75a778fb459d4138a1446c1b38b44798b56a99 --- include/android/surface_control.h | 9 ++- libs/gui/ISurfaceComposer.cpp | 66 +++++++++++++++++++ libs/gui/LayerState.cpp | 22 +++++++ libs/gui/Surface.cpp | 16 +++-- libs/gui/SurfaceComposerClient.cpp | 7 +- libs/gui/include/gui/ISurfaceComposer.h | 7 ++ libs/gui/include/gui/LayerState.h | 15 ++++- libs/gui/include/gui/Surface.h | 2 +- libs/gui/include/gui/SurfaceComposerClient.h | 3 +- libs/gui/tests/Surface_test.cpp | 5 ++ libs/nativewindow/ANativeWindow.cpp | 6 +- .../include/android/native_window.h | 29 +++++++- libs/nativewindow/include/system/window.h | 6 +- libs/nativewindow/libnativewindow.map.txt | 2 +- services/surfaceflinger/BufferQueueLayer.cpp | 13 ---- services/surfaceflinger/BufferQueueLayer.h | 5 -- services/surfaceflinger/Layer.cpp | 13 ++++ services/surfaceflinger/Layer.h | 6 +- .../surfaceflinger/Scheduler/LayerHistory.cpp | 1 - services/surfaceflinger/SurfaceFlinger.cpp | 35 +++++++++- services/surfaceflinger/SurfaceFlinger.h | 2 + .../tests/SetFrameRate_test.cpp | 14 ++-- 22 files changed, 236 insertions(+), 48 deletions(-) diff --git a/include/android/surface_control.h b/include/android/surface_control.h index eeb8330efd..c30dcfee09 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -425,12 +425,15 @@ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transactio * valid refresh rate for this device's display - e.g., it's fine to pass 30fps to a device that can * only run the display at 60fps. * + * |compatibility| The frame rate compatibility of this surface. The compatibility value may + * influence the system's choice of display frame rate. To specify a compatibility use the + * ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* enum. + * * Available since API level 30. */ void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, - ASurfaceControl* surface_control, - float frameRate) - __INTRODUCED_IN(30); + ASurfaceControl* surface_control, float frameRate, + int8_t compatibility) __INTRODUCED_IN(30); #endif // __ANDROID_API__ >= 30 diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 2f27fd20fd..ce41eaba1d 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1112,6 +1112,42 @@ public: } return NO_ERROR; } + + virtual status_t setFrameRate(const sp& surface, float frameRate, + int8_t compatibility) { + Parcel data, reply; + status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing interface token: %s (%d)", strerror(-err), -err); + return err; + } + + err = data.writeStrongBinder(IInterface::asBinder(surface)); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing strong binder: %s (%d)", strerror(-err), -err); + return err; + } + + err = data.writeFloat(frameRate); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing float: %s (%d)", strerror(-err), -err); + return err; + } + + err = data.writeByte(compatibility); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing byte: %s (%d)", strerror(-err), -err); + return err; + } + + err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply, + IBinder::FLAG_ONEWAY); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err); + return err; + } + return NO_ERROR; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1877,6 +1913,36 @@ status_t BnSurfaceComposer::onTransact( return setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ, lightRadius); } + case SET_FRAME_RATE: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp binder; + status_t err = data.readStrongBinder(&binder); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to read strong binder: %s (%d)", strerror(-err), -err); + return err; + } + sp surface = interface_cast(binder); + if (!surface) { + ALOGE("setFrameRate: failed to cast to IGraphicBufferProducer: %s (%d)", + strerror(-err), -err); + return err; + } + float frameRate; + err = data.readFloat(&frameRate); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to read float: %s (%d)", strerror(-err), -err); + return err; + } + int8_t compatibility; + err = data.readByte(&compatibility); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to read byte: %s (%d)", strerror(-err), -err); + return err; + } + status_t result = setFrameRate(surface, frameRate, compatibility); + reply->writeInt32(result); + return NO_ERROR; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 5547efc3ad..a9c9b7460b 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -24,6 +24,8 @@ #include #include +#include + namespace android { status_t layer_state_t::write(Parcel& output) const @@ -113,6 +115,7 @@ status_t layer_state_t::write(Parcel& output) const output.writeFloat(shadowRadius); output.writeInt32(frameRateSelectionPriority); output.writeFloat(frameRate); + output.writeByte(frameRateCompatibility); return NO_ERROR; } @@ -194,6 +197,7 @@ status_t layer_state_t::read(const Parcel& input) shadowRadius = input.readFloat(); frameRateSelectionPriority = input.readInt32(); frameRate = input.readFloat(); + frameRateCompatibility = input.readByte(); return NO_ERROR; } @@ -427,6 +431,7 @@ void layer_state_t::merge(const layer_state_t& other) { if (other.what & eFrameRateChanged) { what |= eFrameRateChanged; frameRate = other.frameRate; + frameRateCompatibility = other.frameRateCompatibility; } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " @@ -474,4 +479,21 @@ void InputWindowCommands::read(const Parcel& input) { syncInputWindows = input.readBool(); } +bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName) { + const char* functionName = inFunctionName != nullptr ? inFunctionName : "call"; + int floatClassification = std::fpclassify(frameRate); + if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) { + ALOGE("%s failed - invalid frame rate %f", functionName, frameRate); + return false; + } + + if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT && + compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE) { + ALOGE("%s failed - invalid compatibility value %d", functionName, compatibility); + return false; + } + + return true; +} + }; // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 278cc593b7..f911e70ebf 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -43,6 +43,7 @@ #include #include +#include #include namespace android { @@ -1413,7 +1414,8 @@ int Surface::dispatchGetLastQueueDuration(va_list args) { int Surface::dispatchSetFrameRate(va_list args) { float frameRate = static_cast(va_arg(args, double)); - return setFrameRate(frameRate); + int8_t compatibility = static_cast(va_arg(args, int)); + return setFrameRate(frameRate, compatibility); } int Surface::dispatchAddCancelInterceptor(va_list args) { @@ -2222,11 +2224,15 @@ void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vectoronBuffersDiscarded(discardedBufs); } -status_t Surface::setFrameRate(float frameRate) { +status_t Surface::setFrameRate(float frameRate, int8_t compatibility) { ATRACE_CALL(); - ALOGV("Surface::setTargetFrameRate"); - Mutex::Autolock lock(mMutex); - return mGraphicBufferProducer->setFrameRate(frameRate); + ALOGV("Surface::setFrameRate"); + + if (!ValidateFrameRate(frameRate, compatibility, "Surface::setFrameRate")) { + return BAD_VALUE; + } + + return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility); } }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 7017b7c8f3..7f28c6c230 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1402,14 +1402,19 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setShado } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate( - const sp& sc, float frameRate) { + const sp& sc, float frameRate, int8_t compatibility) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } + if (!ValidateFrameRate(frameRate, compatibility, "Transaction::setFrameRate")) { + mStatus = BAD_VALUE; + return *this; + } s->what |= layer_state_t::eFrameRateChanged; s->frameRate = frameRate; + s->frameRateCompatibility = compatibility; return *this; } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index e860f61c22..0659f0de06 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -500,6 +500,12 @@ public: virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) = 0; + + /* + * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info. + */ + virtual status_t setFrameRate(const sp& surface, float frameRate, + int8_t compatibility) = 0; }; // ---------------------------------------------------------------------------- @@ -557,6 +563,7 @@ public: SET_AUTO_LOW_LATENCY_MODE, GET_GAME_CONTENT_TYPE_SUPPORT, SET_GAME_CONTENT_TYPE, + SET_FRAME_RATE, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 2d53b48475..7e3d5d50d3 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -20,8 +20,7 @@ #include #include -#include - +#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include namespace android { @@ -135,7 +135,8 @@ struct layer_state_t { colorSpaceAgnostic(false), shadowRadius(0.0f), frameRateSelectionPriority(-1), - frameRate(0.0f) { + frameRate(0.0f), + frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; hdrMetadata.validTypes = 0; @@ -221,7 +222,9 @@ struct layer_state_t { // Priority of the layer assigned by Window Manager. int32_t frameRateSelectionPriority; + // Layer frame rate and compatibility. See ANativeWindow_setFrameRate(). float frameRate; + int8_t frameRateCompatibility; }; struct ComposerState { @@ -292,6 +295,12 @@ static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) return compare_type(lhs.token, rhs.token); } +// Returns true if the frameRate and compatibility are valid values, false +// othwerise. If either of the params are invalid, an error log is printed, and +// functionName is added to the log to indicate which function call failed. +// functionName can be null. +bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName); + }; // namespace android #endif // ANDROID_SF_LAYER_STATE_H diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 4a353fc659..ad7cbfe914 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -179,7 +179,7 @@ public: status_t getConsumerUsage(uint64_t* outUsage) const; // See IGraphicBufferProducer::setFrameRate - status_t setFrameRate(float frameRate); + status_t setFrameRate(float frameRate, int8_t compatibility); protected: virtual ~Surface(); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index d0bb6a39ec..fe3dec5ee5 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -525,7 +525,8 @@ public: const Rect& source, const Rect& dst, int transform); Transaction& setShadowRadius(const sp& sc, float cornerRadius); - Transaction& setFrameRate(const sp& sc, float frameRate); + Transaction& setFrameRate(const sp& sc, float frameRate, + int8_t compatibility); status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 70fd888aaf..8c0f8f8de9 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -854,6 +854,11 @@ public: return NO_ERROR; } + status_t setFrameRate(const sp& /*surface*/, float /*frameRate*/, + int8_t /*compatibility*/) override { + return NO_ERROR; + } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 98b76fd667..f09decf21a 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -158,11 +158,11 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) { return query(window, NATIVE_WINDOW_DATASPACE); } -int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) { - if (!window || !query(window, NATIVE_WINDOW_IS_VALID) || frameRate < 0) { +int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) { + if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { return -EINVAL; } - return native_window_set_frame_rate(window, frameRate); + return native_window_set_frame_rate(window, frameRate, compatibility); } void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 4b426c518a..59aa6655b8 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -33,6 +33,7 @@ #ifndef ANDROID_NATIVE_WINDOW_H #define ANDROID_NATIVE_WINDOW_H +#include #include #include @@ -232,6 +233,24 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN #if __ANDROID_API__ >= 30 +/* Parameter for ANativeWindow_setFrameRate */ +enum { + /** + * There are no inherent restrictions on the frame rate of this window. + */ + ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT = 0, + /** + * This window is being used to display content with an inherently fixed + * frame rate, e.g. a video that has a specific frame rate. When the system + * selects a frame rate other than what the app requested, the app will need + * to do pull down or use some other technique to adapt to the system's + * frame rate. The user experience is likely to be worse (e.g. more frame + * stuttering) than it would be if the system had chosen the app's requested + * frame rate. + */ + ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1 +}; + /** * Sets the intended frame rate for this window. * @@ -257,9 +276,15 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN * refresh rate for this device's display - e.g., it's fine to pass 30fps to a * device that can only run the display at 60fps. * - * \return 0 for success, -EINVAL if the window or frame rate are invalid. + * \param compatibility The frame rate compatibility of this window. The + * compatibility value may influence the system's choice of display refresh + * rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info. + * + * \return 0 for success, -EINVAL if the window, frame rate, or compatibility + * value are invalid. */ -int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) __INTRODUCED_IN(30); +int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) + __INTRODUCED_IN(30); /** * Provides a hint to the window that buffers should be preallocated ahead of diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index f686147a5f..0e28fb84ca 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1015,8 +1015,10 @@ static inline int native_window_set_auto_prerotation(struct ANativeWindow* windo return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation); } -static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate) { - return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate); +static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, + int8_t compatibility) { + return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate, + (int)compatibility); } // ------------------------------------------------------------------------------------------------ diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 154eb8eb52..e072e1145d 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -46,9 +46,9 @@ LIBNATIVEWINDOW { ANativeWindow_setBuffersTimestamp; # llndk ANativeWindow_setBuffersTransform; ANativeWindow_setDequeueTimeout; # apex # introduced=30 + ANativeWindow_setFrameRate; # introduced=30 ANativeWindow_setSharedBufferMode; # llndk ANativeWindow_setSwapInterval; # llndk - ANativeWindow_setFrameRate; # introduced=30 ANativeWindow_setUsage; # llndk ANativeWindow_tryAllocateBuffers; # introduced=30 ANativeWindow_unlockAndPost; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index e65064bebf..f5a99cadd7 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -124,18 +124,6 @@ bool BufferQueueLayer::shouldPresentNow(nsecs_t expectedPresentTime) const { return isDue || !isPlausible; } -bool BufferQueueLayer::setFrameRate(FrameRate frameRate) { - float oldFrameRate = 0.f; - status_t result = mConsumer->getFrameRate(&oldFrameRate); - bool frameRateChanged = result < 0 || frameRate.rate != oldFrameRate; - mConsumer->setFrameRate(frameRate.rate); - return frameRateChanged; -} - -Layer::FrameRate BufferQueueLayer::getFrameRate() const { - return FrameRate(mLatchedFrameRate, Layer::FrameRateCompatibility::Default); -} - // ----------------------------------------------------------------------- // Interface implementation for BufferLayer // ----------------------------------------------------------------------- @@ -578,7 +566,6 @@ void BufferQueueLayer::gatherBufferInfo() { mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse(); float latchedFrameRate; mConsumer->getFrameRate(&latchedFrameRate); - mLatchedFrameRate = latchedFrameRate; } sp BufferQueueLayer::createClone() { diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 626af4b6f1..5f7587c547 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -56,9 +56,6 @@ public: bool shouldPresentNow(nsecs_t expectedPresentTime) const override; - bool setFrameRate(FrameRate frameRate) override; - FrameRate getFrameRate() const override; - // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- @@ -155,8 +152,6 @@ private: std::atomic mSidebandStreamChanged{false}; sp mContentsChangedListener; - - std::atomic mLatchedFrameRate = 0.f; }; } // namespace android diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index da26a374db..d7647d76d3 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -26,6 +26,7 @@ #include "Layer.h" #include +#include #include #include #include @@ -2446,6 +2447,18 @@ void Layer::addChildToDrawing(const sp& layer) { layer->mDrawingParent = this; } +Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t compatibility) { + switch (compatibility) { + case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT: + return FrameRateCompatibility::Default; + case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE: + return FrameRateCompatibility::ExactOrMultiple; + default: + LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility); + return FrameRateCompatibility::Default; + } +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 37ae340653..5d2144aed4 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -161,6 +161,10 @@ public: } bool operator!=(const FrameRate& other) const { return !(*this == other); } + + // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a + // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid. + static FrameRateCompatibility convertCompatibility(int8_t compatibility); }; struct State { @@ -795,7 +799,7 @@ public: */ Rect getCroppedBufferSize(const Layer::State& s) const; - virtual bool setFrameRate(FrameRate frameRate); + bool setFrameRate(FrameRate frameRate); virtual FrameRate getFrameRate() const; protected: diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index b313777253..b851fc6ebb 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -179,4 +179,3 @@ void LayerHistory::clear() { mActiveLayersEnd = 0; } } // namespace android::scheduler::impl - diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a98ff4fe7c..2701c3e6c9 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -34,6 +34,8 @@ #include #include +#include + #include #include @@ -58,6 +60,7 @@ #include #include #include +#include #include #include

To use:

    + *
  • Create a new thermal manager instance by calling the + * {@link AThermal_acquireManager} function.
  • + *
  • Get current thermal status with + * {@link AThermal_getCurrentThermalStatus}.
  • + *
  • Register a thermal status listener with + * {@link AThermal_registerThermalStatusListener}.
  • + *
  • Unregister a thermal status listener with + * {@link AThermal_unregisterThermalStatusListener}.
  • + *
  • Release the thermal manager instance with + * {@link AThermal_releaseManager}.

+ * + */ +typedef struct AThermalManager AThermalManager; + +/** + * Prototype of the function that is called when thermal status changes. + * It's passed the updated thermal status as parameter, as well as the + * pointer provided by the client that registered a callback. + */ +typedef int (*AThermal_StatusCallback)(void *data, AThermalStatus status); + +/** + * Acquire an instance of the thermal manager. This must be freed using + * {@link AThermal_releaseManager}. + * + * @return manager instance on success, nullptr on failure. + */ +AThermalManager* AThermal_acquireManager(); + +/** + * Release the thermal manager pointer acquired via + * {@link AThermal_acquireManager}. + * + * @param manager The manager to be released. + * + */ +void AThermal_releaseManager(AThermalManager *manager); + +/** + * Gets the current thermal status. + * + * @param manager The manager instance to use to query the thermal status. + * Acquired via {@link AThermal_acquireManager}. + * + * @return current thermal status, ATHERMAL_STATUS_ERROR on failure. +*/ +AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager); + +/** + * Register the thermal status listener for thermal status change. + * + * @param manager The manager instance to use to register. + * Acquired via {@link AThermal_acquireManager}. + * @param callback The callback function to be called when thermal status updated. + * @param data The data pointer to be passed when callback is called. + * + * @return 0 on success + * EINVAL if the listener and data pointer were previously added and not removed. + * EPERM if the required permission is not held. + * EPIPE if communication with the system service has failed. + */ +int AThermal_registerThermalStatusListener(AThermalManager *manager, + AThermal_StatusCallback callback, void *data); + +/** + * Unregister the thermal status listener previously resgistered. + * + * @param manager The manager instance to use to unregister. + * Acquired via {@link AThermal_acquireManager}. + * @param callback The callback function to be called when thermal status updated. + * @param data The data pointer to be passed when callback is called. + * + * @return 0 on success + * EINVAL if the listener and data pointer were not previously added. + * EPERM if the required permission is not held. + * EPIPE if communication with the system service has failed. + */ +int AThermal_unregisterThermalStatusListener(AThermalManager *manager, + AThermal_StatusCallback callback, void *data); + + +#endif // __ANDROID_API__ >= 30 + +#ifdef __cplusplus +} +#endif + +#endif // _ANDROID_THERMAL_H + +/** @} */ diff --git a/include/powermanager/PowerManager.h b/include/powermanager/PowerManager.h index 3268b45716..9bac242a12 100644 --- a/include/powermanager/PowerManager.h +++ b/include/powermanager/PowerManager.h @@ -33,6 +33,17 @@ enum { USER_ACTIVITY_EVENT_LAST = USER_ACTIVITY_EVENT_ACCESSIBILITY, // Last valid event code. }; +/** Keep in sync with android.os.temprature and hardware/interfaces/thermal/2.0/types.hal */ +enum class ThermalStatus : uint32_t { + THERMAL_STATUS_NONE = 0, + THERMAL_STATUS_LIGHT = 1, + THERMAL_STATUS_MODERATE = 2, + THERMAL_STATUS_SEVERE = 3, + THERMAL_STATUS_CRITICAL = 4, + THERMAL_STATUS_EMERGENCY = 5, + THERMAL_STATUS_SHUTDOWN = 6, +}; + }; // namespace android #endif // ANDROID_POWERMANAGER_H diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp index 7b3af70927..3e0f136dfb 100644 --- a/services/powermanager/Android.bp +++ b/services/powermanager/Android.bp @@ -1,11 +1,25 @@ cc_library_shared { name: "libpowermanager", - srcs: ["IPowerManager.cpp"], + srcs: [ + "IPowerManager.cpp", + "Temperature.cpp", + "CoolingDevice.cpp", + ":libpowermanager_aidl", + ], + + aidl: { + local_include_dirs: ["."], + include_dirs: [ + "frameworks/base/core/java/android/os", + ], + export_aidl_headers: true + }, shared_libs: [ "libutils", "libbinder", + "liblog" ], cflags: [ @@ -15,3 +29,22 @@ cc_library_shared { "-Wunreachable-code", ], } + +cc_test { + name: "thermalmanager-test", + srcs: ["IThermalManagerTest.cpp", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], + shared_libs: [ + "libbase", + "libhidlbase", + "liblog", + "libpowermanager", + "libbinder", + "libutils", + ], +} diff --git a/services/powermanager/CoolingDevice.cpp b/services/powermanager/CoolingDevice.cpp new file mode 100644 index 0000000000..ebbc1b4197 --- /dev/null +++ b/services/powermanager/CoolingDevice.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "CoolingDevice" + +#include +#include +#include + +namespace android { +namespace os { + +status_t CoolingDevice::readFromParcel(const android::Parcel *parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + parcel->readFloat(&mValue); + parcel->readUint32(&mType); + parcel->readString16(&mName); + + return OK; +} + +status_t CoolingDevice::writeToParcel(android::Parcel *parcel) const { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + parcel->writeFloat(mValue); + parcel->writeUint32(mType); + parcel->writeString16(mName); + + return OK; +} + +} // namespace os +} // namespace android \ No newline at end of file diff --git a/services/powermanager/IThermalManagerTest.cpp b/services/powermanager/IThermalManagerTest.cpp new file mode 100644 index 0000000000..575b9ee1c4 --- /dev/null +++ b/services/powermanager/IThermalManagerTest.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "ThermalManagerTest" +//#define LOG_NDEBUG 0 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace android; +using namespace android::os; +using namespace std::chrono_literals; + +class IThermalServiceTest : public testing::Test, + public BnThermalStatusListener{ + public: + IThermalServiceTest(); + void setThermalOverride(int level); + virtual binder::Status onStatusChange(int status) override; + int getStatusFromService(); + void SetUp() override; + void TearDown() override; + protected: + sp mThermalSvc; + std::condition_variable mCondition; + int mListenerStatus; + int mServiceStatus; + std::mutex mMutex; +}; + +IThermalServiceTest::IThermalServiceTest() + : mListenerStatus(0), + mServiceStatus(0) { +} + +void IThermalServiceTest::setThermalOverride(int level) { + std::string cmdStr = "cmd thermalservice override-status " + std::to_string(level); + system(cmdStr.c_str()); +} + +binder::Status IThermalServiceTest::onStatusChange(int status) { + std::unique_lock lock(mMutex); + mListenerStatus = status; + ALOGI("IThermalServiceTest::notifyListener %d", mListenerStatus); + mCondition.notify_all(); + return binder::Status::ok(); +} + +int IThermalServiceTest::getStatusFromService() { + int status; + binder::Status ret = mThermalSvc->getCurrentThermalStatus(&status); + if (ret.isOk()) { + return status; + } else { + return BAD_VALUE; + } +} + +void IThermalServiceTest::SetUp() { + setThermalOverride(0); + // use checkService() to avoid blocking if thermal service is not up yet + sp binder = + defaultServiceManager()->checkService(String16("thermalservice")); + EXPECT_NE(binder, nullptr); + mThermalSvc = interface_cast(binder); + EXPECT_NE(mThermalSvc, nullptr); + bool success = false; + binder::Status ret = mThermalSvc->registerThermalStatusListener(this, &success); + ASSERT_TRUE(success); + ASSERT_TRUE(ret.isOk()); + // Wait for listener called after registration, shouldn't timeout + std::unique_lock lock(mMutex); + EXPECT_NE(mCondition.wait_for(lock, 1s), std::cv_status::timeout); +} + +void IThermalServiceTest::TearDown() { + bool success = false; + binder::Status ret = mThermalSvc->unregisterThermalStatusListener(this, &success); + ASSERT_TRUE(success); + ASSERT_TRUE(ret.isOk()); +} + +class IThermalListenerTest : public IThermalServiceTest, public testing::WithParamInterface { + public: + static auto PrintParam(const testing::TestParamInfo &info) { + return std::to_string(info.param); + } +}; + +TEST_P(IThermalListenerTest, TestListener) { + int level = GetParam(); + std::unique_lock lock(mMutex); + // Set the override thermal status + setThermalOverride(level); + // Wait for listener called, shouldn't timeout + EXPECT_NE(mCondition.wait_for(lock, 1s), std::cv_status::timeout); + // Check the result + EXPECT_EQ(level, mListenerStatus); + ALOGI("Thermal listener status %d, expecting %d", mListenerStatus, level); +} + +INSTANTIATE_TEST_SUITE_P(TestListenerLevels, IThermalListenerTest, testing::Range( + static_cast(ThermalStatus::THERMAL_STATUS_LIGHT), + static_cast(ThermalStatus::THERMAL_STATUS_SHUTDOWN)), + IThermalListenerTest::PrintParam); + +class IThermalLevelTest : public IThermalServiceTest, public testing::WithParamInterface { + public: + static auto PrintParam(const testing::TestParamInfo &info) { + return std::to_string(info.param); + } +}; + +TEST_P(IThermalLevelTest, TestGetStatusLevel) { + int level = GetParam(); + setThermalOverride(level); + mServiceStatus = getStatusFromService(); + EXPECT_EQ(level, mServiceStatus); +} + +INSTANTIATE_TEST_SUITE_P(TestStatusLevels, IThermalLevelTest, testing::Range( + static_cast(ThermalStatus::THERMAL_STATUS_NONE), + static_cast(ThermalStatus::THERMAL_STATUS_SHUTDOWN)), + IThermalLevelTest::PrintParam); + +int main(int argc, char **argv) { + std::unique_ptr binderLoop; + binderLoop = std::make_unique( + [&] { IPCThreadState::self()->joinThreadPool(true); }); + + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGV("Test result = %d\n", status); + + return status; +} \ No newline at end of file diff --git a/services/powermanager/Temperature.cpp b/services/powermanager/Temperature.cpp new file mode 100644 index 0000000000..8ec0a87146 --- /dev/null +++ b/services/powermanager/Temperature.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Temperature" + +#include +#include +#include + +namespace android { +namespace os { + +status_t Temperature::readFromParcel(const android::Parcel *parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + parcel->readFloat(&mValue); + parcel->readInt32(&mType); + parcel->readString16(&mName); + parcel->readInt32(&mStatus); + + return OK; +} + +status_t Temperature::writeToParcel(android::Parcel *parcel) const { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + parcel->writeFloat(mValue); + parcel->writeInt32(mType); + parcel->writeString16(mName); + parcel->writeInt32(mStatus); + + return OK; +} + +} // namespace os +} // namespace android \ No newline at end of file -- GitLab From 0cab12d4d25fb809ab333f03266682af97647ab7 Mon Sep 17 00:00:00 2001 From: "Nathaniel R. Lewis" Date: Tue, 5 Nov 2019 02:17:02 +0000 Subject: [PATCH 0830/1255] Change InputReader::mDevices collection type Convert InputReader::mDevices from unordered_map of bare pointers to unordered_map of shared_ptr's. This removes the need for manual deletion of InputDevice instances and prepares for a future patch which will have multiple device ids pointing to the same InputDevice. Cherry-picked from pa/1497945. Bug: 38511270 Test: atest inputflinger_tests libinput_tests Change-Id: I0f3bfd96bfe5904ce1a8d96813e45f8467cee0fa --- services/inputflinger/reader/InputReader.cpp | 63 +++++++++---------- .../inputflinger/reader/include/InputReader.h | 9 +-- .../inputflinger/tests/InputReader_test.cpp | 51 +++++++-------- 3 files changed, 61 insertions(+), 62 deletions(-) diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 3e23fa6c84..8327ed8e30 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -62,11 +62,7 @@ InputReader::InputReader(std::shared_ptr eventHub, } // release lock } -InputReader::~InputReader() { - for (auto& devicePair : mDevices) { - delete devicePair.second; - } -} +InputReader::~InputReader() {} status_t InputReader::start() { if (mThread) { @@ -198,7 +194,8 @@ void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { uint32_t classes = mEventHub->getDeviceClasses(deviceId); int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId); - InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes); + std::shared_ptr device = + createDeviceLocked(deviceId, controllerNumber, identifier, classes); device->configure(when, &mConfig, 0); device->reset(when); @@ -210,7 +207,7 @@ void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { device->getSources()); } - mDevices.insert({deviceId, device}); + mDevices.emplace(deviceId, device); bumpGenerationLocked(); if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { @@ -225,7 +222,7 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { return; } - InputDevice* device = deviceIt->second; + std::shared_ptr device = std::move(deviceIt->second); mDevices.erase(deviceIt); bumpGenerationLocked(); @@ -242,13 +239,13 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { } device->reset(when); - delete device; } -InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, - uint32_t classes) { - InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), +std::shared_ptr InputReader::createDeviceLocked( + int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier, + uint32_t classes) { + std::shared_ptr device = + std::make_shared(&mContext, deviceId, bumpGenerationLocked(), controllerNumber, identifier, classes); device->populateMappers(); return device; @@ -262,7 +259,7 @@ void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* return; } - InputDevice* device = deviceIt->second; + std::shared_ptr& device = deviceIt->second; if (device->isIgnored()) { // ALOGD("Discarding event for ignored deviceId %d.", deviceId); return; @@ -273,7 +270,7 @@ void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* void InputReader::timeoutExpiredLocked(nsecs_t when) { for (auto& devicePair : mDevices) { - InputDevice* device = devicePair.second; + std::shared_ptr& device = devicePair.second; if (!device->isIgnored()) { device->timeoutExpired(when); } @@ -302,7 +299,7 @@ void InputReader::refreshConfigurationLocked(uint32_t changes) { mEventHub->requestReopenDevices(); } else { for (auto& devicePair : mDevices) { - InputDevice* device = devicePair.second; + std::shared_ptr& device = devicePair.second; device->configure(now, &mConfig, changes); } } @@ -313,7 +310,7 @@ void InputReader::updateGlobalMetaStateLocked() { mGlobalMetaState = 0; for (auto& devicePair : mDevices) { - InputDevice* device = devicePair.second; + std::shared_ptr& device = devicePair.second; mGlobalMetaState |= device->getMetaState(); } } @@ -328,7 +325,7 @@ void InputReader::notifyExternalStylusPresenceChanged() { void InputReader::getExternalStylusDevicesLocked(std::vector& outDevices) { for (auto& devicePair : mDevices) { - InputDevice* device = devicePair.second; + std::shared_ptr& device = devicePair.second; if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) { InputDeviceInfo info; device->getDeviceInfo(&info); @@ -339,7 +336,7 @@ void InputReader::getExternalStylusDevicesLocked(std::vector& o void InputReader::dispatchExternalStylusState(const StylusState& state) { for (auto& devicePair : mDevices) { - InputDevice* device = devicePair.second; + std::shared_ptr& device = devicePair.second; device->updateExternalStylusState(state); } } @@ -361,7 +358,7 @@ bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, int32_t keyCode, int32 void InputReader::fadePointerLocked() { for (auto& devicePair : mDevices) { - InputDevice* device = devicePair.second; + std::shared_ptr& device = devicePair.second; device->fadePointer(); } } @@ -386,7 +383,7 @@ void InputReader::getInputDevicesLocked(std::vector& outInputDe outInputDevices.clear(); for (auto& devicePair : mDevices) { - InputDevice* device = devicePair.second; + std::shared_ptr& device = devicePair.second; if (!device->isIgnored()) { InputDeviceInfo info; device->getDeviceInfo(&info); @@ -419,18 +416,18 @@ int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32 if (deviceId >= 0) { auto deviceIt = mDevices.find(deviceId); if (deviceIt != mDevices.end()) { - InputDevice* device = deviceIt->second; + std::shared_ptr& device = deviceIt->second; if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = (device->*getStateFunc)(sourceMask, code); + result = (device.get()->*getStateFunc)(sourceMask, code); } } } else { for (auto& devicePair : mDevices) { - InputDevice* device = devicePair.second; + std::shared_ptr& device = devicePair.second; if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { // If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that // value. Otherwise, return AKEY_STATE_UP as long as one device reports it. - int32_t currentResult = (device->*getStateFunc)(sourceMask, code); + int32_t currentResult = (device.get()->*getStateFunc)(sourceMask, code); if (currentResult >= AKEY_STATE_DOWN) { return currentResult; } else if (currentResult == AKEY_STATE_UP) { @@ -449,7 +446,7 @@ void InputReader::toggleCapsLockState(int32_t deviceId) { return; } - InputDevice* device = deviceIt->second; + std::shared_ptr& device = deviceIt->second; if (device->isIgnored()) { return; } @@ -472,14 +469,14 @@ bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceM if (deviceId >= 0) { auto deviceIt = mDevices.find(deviceId); if (deviceIt != mDevices.end()) { - InputDevice* device = deviceIt->second; + std::shared_ptr& device = deviceIt->second; if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { result = device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); } } } else { for (auto& devicePair : mDevices) { - InputDevice* device = devicePair.second; + std::shared_ptr& device = devicePair.second; if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { result |= device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); } @@ -506,7 +503,7 @@ void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patte AutoMutex _l(mLock); auto deviceIt = mDevices.find(deviceId); if (deviceIt != mDevices.end()) { - InputDevice* device = deviceIt->second; + std::shared_ptr& device = deviceIt->second; device->vibrate(pattern, patternSize, repeat, token); } } @@ -516,7 +513,7 @@ void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { auto deviceIt = mDevices.find(deviceId); if (deviceIt != mDevices.end()) { - InputDevice* device = deviceIt->second; + std::shared_ptr& device = deviceIt->second; device->cancelVibrate(token); } } @@ -526,7 +523,7 @@ bool InputReader::isInputDeviceEnabled(int32_t deviceId) { auto deviceIt = mDevices.find(deviceId); if (deviceIt != mDevices.end()) { - InputDevice* device = deviceIt->second; + std::shared_ptr& device = deviceIt->second; return device->isEnabled(); } ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId); @@ -542,7 +539,7 @@ bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) { return false; } - InputDevice* device = deviceIt->second; + std::shared_ptr& device = deviceIt->second; if (!device->isEnabled()) { ALOGW("Ignoring disabled device %s", device->getName().c_str()); return false; @@ -571,7 +568,7 @@ void InputReader::dump(std::string& dump) { dump += "Input Reader State:\n"; for (const auto& devicePair : mDevices) { - InputDevice* const device = devicePair.second; + const std::shared_ptr& device = devicePair.second; device->dump(dump); } diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index cf1af04417..4f5d2eabf3 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -84,9 +84,10 @@ public: protected: // These members are protected so they can be instrumented by test cases. - virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, - uint32_t classes); + virtual std::shared_ptr createDeviceLocked(int32_t deviceId, + int32_t controllerNumber, + const InputDeviceIdentifier& identifier, + uint32_t classes); // With each iteration of the loop, InputReader reads and processes one incoming message from // the EventHub. @@ -138,7 +139,7 @@ private: static const int EVENT_BUFFER_SIZE = 256; RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; - std::unordered_map mDevices; + std::unordered_map> mDevices; // low-level input event decoding and device management void processEventsLocked(const RawEvent* rawEvents, size_t count); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 01bd9db76f..d870a01bfa 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1091,7 +1091,7 @@ private: // --- InstrumentedInputReader --- class InstrumentedInputReader : public InputReader { - InputDevice* mNextDevice; + std::shared_ptr mNextDevice; public: InstrumentedInputReader(std::shared_ptr eventHub, @@ -1099,33 +1099,31 @@ public: const sp& listener) : InputReader(eventHub, policy, listener), mNextDevice(nullptr) {} - virtual ~InstrumentedInputReader() { - if (mNextDevice) { - delete mNextDevice; - } - } + virtual ~InstrumentedInputReader() {} - void setNextDevice(InputDevice* device) { mNextDevice = device; } + void setNextDevice(std::shared_ptr device) { mNextDevice = device; } - InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const std::string& name, - uint32_t classes, const std::string& location = "") { + std::shared_ptr newDevice(int32_t deviceId, int32_t controllerNumber, + const std::string& name, uint32_t classes, + const std::string& location = "") { InputDeviceIdentifier identifier; identifier.name = name; identifier.location = location; int32_t generation = deviceId + 1; - return new InputDevice(&mContext, deviceId, generation, controllerNumber, identifier, - classes); + return std::make_shared(&mContext, deviceId, generation, controllerNumber, + identifier, classes); } // Make the protected loopOnce method accessible to tests. using InputReader::loopOnce; protected: - virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, - uint32_t classes) { + virtual std::shared_ptr createDeviceLocked(int32_t deviceId, + int32_t controllerNumber, + const InputDeviceIdentifier& identifier, + uint32_t classes) { if (mNextDevice) { - InputDevice* device = mNextDevice; + std::shared_ptr device(mNextDevice); mNextDevice = nullptr; return device; } @@ -1368,7 +1366,8 @@ protected: const std::string& name, uint32_t classes, uint32_t sources, const PropertyMap* configuration) { - InputDevice* device = mReader->newDevice(deviceId, controllerNumber, name, classes); + std::shared_ptr device = + mReader->newDevice(deviceId, controllerNumber, name, classes); FakeInputMapper& mapper = device->addMapper(sources); mReader->setNextDevice(device); addDevice(deviceId, name, classes, configuration); @@ -1404,7 +1403,8 @@ TEST_F(InputReaderTest, GetInputDevices) { TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) { constexpr int32_t deviceId = 1; constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; - InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass); + std::shared_ptr device = + mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass); // Must add at least one mapper or the device will be ignored! device->addMapper(AINPUT_SOURCE_KEYBOARD); mReader->setNextDevice(device); @@ -1584,7 +1584,8 @@ TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { TEST_F(InputReaderTest, DeviceReset_IncrementsSequenceNumber) { constexpr int32_t deviceId = 1; constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; - InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass); + std::shared_ptr device = + mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass); // Must add at least one mapper or the device will be ignored! device->addMapper(AINPUT_SOURCE_KEYBOARD); mReader->setNextDevice(device); @@ -1617,8 +1618,8 @@ TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { constexpr int32_t deviceId = 1; constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; const char* DEVICE_LOCATION = "USB1"; - InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass, - DEVICE_LOCATION); + std::shared_ptr device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, + "fake", deviceClass, DEVICE_LOCATION); FakeInputMapper& mapper = device->addMapper(AINPUT_SOURCE_TOUCHSCREEN); mReader->setNextDevice(device); @@ -1671,7 +1672,7 @@ protected: sp mFakeListener; FakeInputReaderContext* mFakeContext; - InputDevice* mDevice; + std::shared_ptr mDevice; virtual void SetUp() override { mFakeEventHub = std::make_unique(); @@ -1683,13 +1684,13 @@ protected: InputDeviceIdentifier identifier; identifier.name = DEVICE_NAME; identifier.location = DEVICE_LOCATION; - mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION, - DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); + mDevice = + std::make_shared(mFakeContext, DEVICE_ID, DEVICE_GENERATION, + DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); } virtual void TearDown() override { - delete mDevice; - + mDevice = nullptr; delete mFakeContext; mFakeListener.clear(); mFakePolicy.clear(); -- GitLab From 0889c62cba1873c45da9d6ec2731abbd760e0e12 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Wed, 19 Feb 2020 15:04:47 -0800 Subject: [PATCH 0831/1255] Set timeout on dequeue buffer for BLAST Adapter BufferQueue may not block if the queue consumer and producer are controlled by the app. setting the timeout explicitly to prevent this from happening Bug: 146345307 Test: build, boot, libgui_test, manual Change-Id: I5e580b1c45288b48c922a3e312c0d98e40808803 --- libs/gui/BLASTBufferQueue.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index acd833f2a7..30e1351b33 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -101,6 +101,9 @@ BLASTBufferQueue::BLASTBufferQueue(const sp& surface, int width, mHeight(height), mNextTransaction(nullptr) { BufferQueue::createBufferQueue(&mProducer, &mConsumer); + // since the adapter is in the client process, set dequeue timeout + // explicitly so that dequeueBuffer will block + mProducer->setDequeueTimeout(std::numeric_limits::max()); int8_t disableTripleBuffer = property_get_bool("ro.sf.disable_triple_buffer", 0); if (!disableTripleBuffer) { -- GitLab From a7b82e1d297a3a5aa1150ac9556361856e681351 Mon Sep 17 00:00:00 2001 From: "Nathaniel R. Lewis" Date: Wed, 12 Feb 2020 15:40:45 -0800 Subject: [PATCH 0832/1255] Support multiple EventHub devices per InputDevice Some physical devices contain more functions than can be addressed by a single Linux evdev device. Examples of such devices are the Sony DualShock 4 and Wacom Tablets, which appear as multiple evdev devices sharing the same value for the EVIOCGUNIQ ioctl. As more instances of such devices hit the market, apps need a way of figuring out which InputDevices are part of the same physical device. Per conversation with the android input team, a solution proposed to this problem is to merge multiple EventHub devices (which have a 1:1 relation with evdev) into a single android InputDevice. Changes: Decouple the EventHub device id ("eventHubId") from the InputDevice device id ("deviceId"). This requires InputDeviceContext to track the the EventHub devices it represents. Most logic changes are inside InputDeviceContext, so there are minimal changes to InputMappers. Added enum value END_RESERVED_ID to represent the first available id that can be assigned to a normal InputDevice. The android framework assumes specific values for the virtual keyboard and built-in hardware keyboard, so for these two cases, the "deviceId" must match the "eventHubId." Added "EVENTHUB_ID" constants to tests and changed where applicable. Cherry-picked from pa/1475694. Bug: 38511270 Test: atest inputflinger_tests libinput_tests Change-Id: I89df085fadc1c09bc999599ac5db35c9277c4a2a --- include/input/InputDevice.h | 2 + services/inputflinger/reader/InputDevice.cpp | 133 +++-- services/inputflinger/reader/InputReader.cpp | 132 +++-- .../inputflinger/reader/include/InputDevice.h | 94 ++- .../inputflinger/reader/include/InputReader.h | 22 +- .../inputflinger/tests/InputReader_test.cpp | 538 ++++++++++-------- 6 files changed, 547 insertions(+), 374 deletions(-) diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index b6efc82fd4..20a17e3347 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -180,6 +180,8 @@ enum ReservedInputDeviceId : int32_t { VIRTUAL_KEYBOARD_ID = -1, // Device id of the "built-in" keyboard if there is one. BUILT_IN_KEYBOARD_ID = 0, + // First device id available for dynamic devices + END_RESERVED_ID = 1, }; } // namespace android diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index ae82cd4aa4..d0eee64b0c 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -18,6 +18,8 @@ #include "InputDevice.h" +#include + #include "CursorInputMapper.h" #include "ExternalStylusInputMapper.h" #include "InputReaderContext.h" @@ -32,25 +34,28 @@ namespace android { InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation, - int32_t controllerNumber, const InputDeviceIdentifier& identifier, - uint32_t classes) + const InputDeviceIdentifier& identifier) : mContext(context), mId(id), mGeneration(generation), - mControllerNumber(controllerNumber), + mControllerNumber(0), mIdentifier(identifier), - mClasses(classes), + mClasses(0), mSources(0), mIsExternal(false), mHasMic(false), - mDropUntilNextSync(false) { - mDeviceContext = std::make_unique(*this); -} + mDropUntilNextSync(false) {} InputDevice::~InputDevice() {} bool InputDevice::isEnabled() { - return mDeviceContext->isDeviceEnabled(); + if (!hasEventHubDevices()) { + return false; + } + // devices are either all enabled or all disabled, so we only need to check the first + auto& devicePair = mDevices.begin()->second; + auto& contextPtr = devicePair.first; + return contextPtr->isDeviceEnabled(); } void InputDevice::setEnabled(bool enabled, nsecs_t when) { @@ -65,12 +70,15 @@ void InputDevice::setEnabled(bool enabled, nsecs_t when) { return; } + // When resetting some devices, the driver needs to be queried to ensure that a proper reset is + // performed. The querying must happen when the device is enabled, so we reset after enabling + // but before disabling the device. See MultiTouchMotionAccumulator::reset for more information. if (enabled) { - mDeviceContext->enableDevice(); + for_each_subdevice([](auto& context) { context.enableDevice(); }); reset(when); } else { reset(when); - mDeviceContext->disableDevice(); + for_each_subdevice([](auto& context) { context.disableDevice(); }); } // Must change generation to flag this device as changed bumpGeneration(); @@ -118,19 +126,18 @@ void InputDevice::dump(std::string& dump) { for_each_mapper([&dump](InputMapper& mapper) { mapper.dump(dump); }); } -void InputDevice::populateMappers() { - uint32_t classes = mClasses; - std::vector>& mappers = mMappers; - std::unique_ptr& contextPtr = mDeviceContext; - - // External devices. - if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { - setExternal(true); +void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) { + if (mDevices.find(eventHubId) != mDevices.end()) { + return; } + std::unique_ptr contextPtr(new InputDeviceContext(*this, eventHubId)); + uint32_t classes = contextPtr->getDeviceClasses(); + std::vector> mappers; - // Devices with mics. - if (classes & INPUT_DEVICE_CLASS_MIC) { - setMic(true); + // Check if we should skip population + if (!populateMappers) { + mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))}); + return; } // Switch-like devices. @@ -190,22 +197,58 @@ void InputDevice::populateMappers() { if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { mappers.push_back(std::make_unique(*contextPtr)); } + + // insert the context into the devices set + mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))}); +} + +void InputDevice::removeEventHubDevice(int32_t eventHubId) { + mDevices.erase(eventHubId); } void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { mSources = 0; + mClasses = 0; + mControllerNumber = 0; + + for_each_subdevice([this](InputDeviceContext& context) { + mClasses |= context.getDeviceClasses(); + int32_t controllerNumber = context.getDeviceControllerNumber(); + if (controllerNumber > 0) { + if (mControllerNumber && mControllerNumber != controllerNumber) { + ALOGW("InputDevice::configure(): composite device contains multiple unique " + "controller numbers"); + } + mControllerNumber = controllerNumber; + } + }); + + mIsExternal = !!(mClasses & INPUT_DEVICE_CLASS_EXTERNAL); + mHasMic = !!(mClasses & INPUT_DEVICE_CLASS_MIC); if (!isIgnored()) { if (!changes) { // first time only - mDeviceContext->getConfiguration(&mConfiguration); + mConfiguration.clear(); + for_each_subdevice([this](InputDeviceContext& context) { + PropertyMap configuration; + context.getConfiguration(&configuration); + mConfiguration.addAll(&configuration); + }); } if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { sp keyboardLayout = mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier); - if (mDeviceContext->setKeyboardLayoutOverlay(keyboardLayout)) { + bool shouldBumpGeneration = false; + for_each_subdevice( + [&keyboardLayout, &shouldBumpGeneration](InputDeviceContext& context) { + if (context.setKeyboardLayoutOverlay(keyboardLayout)) { + shouldBumpGeneration = true; + } + }); + if (shouldBumpGeneration) { bumpGeneration(); } } @@ -313,7 +356,9 @@ void InputDevice::process(const RawEvent* rawEvents, size_t count) { mDropUntilNextSync = true; reset(rawEvent->when); } else { - for_each_mapper([rawEvent](InputMapper& mapper) { mapper.process(rawEvent); }); + for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) { + mapper.process(rawEvent); + }); } --count; } @@ -348,16 +393,20 @@ int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) { int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { int32_t result = AKEY_STATE_UNKNOWN; - for (auto& mapperPtr : mMappers) { - InputMapper& mapper = *mapperPtr; - if (sourcesMatchMask(mapper.getSources(), sourceMask)) { - // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that - // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it. - int32_t currentResult = (mapper.*getStateFunc)(sourceMask, code); - if (currentResult >= AKEY_STATE_DOWN) { - return currentResult; - } else if (currentResult == AKEY_STATE_UP) { - result = currentResult; + for (auto& deviceEntry : mDevices) { + auto& devicePair = deviceEntry.second; + auto& mappers = devicePair.second; + for (auto& mapperPtr : mappers) { + InputMapper& mapper = *mapperPtr; + if (sourcesMatchMask(mapper.getSources(), sourceMask)) { + // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that + // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it. + int32_t currentResult = (mapper.*getStateFunc)(sourceMask, code); + if (currentResult >= AKEY_STATE_DOWN) { + return currentResult; + } else if (currentResult == AKEY_STATE_UP) { + result = currentResult; + } } } } @@ -424,11 +473,23 @@ std::optional InputDevice::getAssociatedDisplayId() { [](InputMapper& mapper) { return mapper.getAssociatedDisplayId(); }); } -InputDeviceContext::InputDeviceContext(InputDevice& device) +// returns the number of mappers associated with the device +size_t InputDevice::getMapperCount() { + size_t count = 0; + for (auto& deviceEntry : mDevices) { + auto& devicePair = deviceEntry.second; + auto& mappers = devicePair.second; + count += mappers.size(); + } + return count; +} + +InputDeviceContext::InputDeviceContext(InputDevice& device, int32_t eventHubId) : mDevice(device), mContext(device.getContext()), mEventHub(device.getContext()->getEventHub()), - mId(device.getId()) {} + mId(eventHubId), + mDeviceId(device.getId()) {} InputDeviceContext::~InputDeviceContext() {} diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 8327ed8e30..cbfa702015 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -49,6 +49,7 @@ InputReader::InputReader(std::shared_ptr eventHub, mNextSequenceNum(1), mGlobalMetaState(0), mGeneration(1), + mNextInputDeviceId(END_RESERVED_ID), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), mConfigurationChangesToRefresh(0) { @@ -184,30 +185,28 @@ void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { } } -void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { - if (mDevices.find(deviceId) != mDevices.end()) { - ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId); +void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) { + if (mDevices.find(eventHubId) != mDevices.end()) { + ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId); return; } - InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId); - uint32_t classes = mEventHub->getDeviceClasses(deviceId); - int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId); - - std::shared_ptr device = - createDeviceLocked(deviceId, controllerNumber, identifier, classes); + InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId); + std::shared_ptr device = createDeviceLocked(eventHubId, identifier); device->configure(when, &mConfig, 0); device->reset(when); if (device->isIgnored()) { - ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, - identifier.name.c_str()); + ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s' " + "(ignored non-input device)", + device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str()); } else { - ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, identifier.name.c_str(), + ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s',sources=0x%08x", + device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str(), device->getSources()); } - mDevices.emplace(deviceId, device); + mDevices.emplace(eventHubId, device); bumpGenerationLocked(); if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { @@ -215,10 +214,10 @@ void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { } } -void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { - auto deviceIt = mDevices.find(deviceId); +void InputReader::removeDeviceLocked(nsecs_t when, int32_t eventHubId) { + auto deviceIt = mDevices.find(eventHubId); if (deviceIt == mDevices.end()) { - ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId); + ALOGW("Ignoring spurious device removed event for eventHubId %d.", eventHubId); return; } @@ -227,35 +226,52 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { bumpGenerationLocked(); if (device->isIgnored()) { - ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)", device->getId(), - device->getName().c_str()); + ALOGI("Device removed: id=%d, eventHubId=%d, name='%s', descriptor='%s' " + "(ignored non-input device)", + device->getId(), eventHubId, device->getName().c_str(), + device->getDescriptor().c_str()); } else { - ALOGI("Device removed: id=%d, name='%s', sources=0x%08x", device->getId(), - device->getName().c_str(), device->getSources()); + ALOGI("Device removed: id=%d, eventHubId=%d, name='%s', descriptor='%s', sources=0x%08x", + device->getId(), eventHubId, device->getName().c_str(), + device->getDescriptor().c_str(), device->getSources()); } + device->removeEventHubDevice(eventHubId); + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { notifyExternalStylusPresenceChanged(); } + if (device->hasEventHubDevices()) { + device->configure(when, &mConfig, 0); + } device->reset(when); } std::shared_ptr InputReader::createDeviceLocked( - int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier, - uint32_t classes) { - std::shared_ptr device = - std::make_shared(&mContext, deviceId, bumpGenerationLocked(), - controllerNumber, identifier, classes); - device->populateMappers(); + int32_t eventHubId, const InputDeviceIdentifier& identifier) { + auto deviceIt = std::find_if(mDevices.begin(), mDevices.end(), [identifier](auto& devicePair) { + return devicePair.second->getDescriptor().size() && identifier.descriptor.size() && + devicePair.second->getDescriptor() == identifier.descriptor; + }); + + std::shared_ptr device; + if (deviceIt != mDevices.end()) { + device = deviceIt->second; + } else { + int32_t deviceId = (eventHubId < END_RESERVED_ID) ? eventHubId : nextInputDeviceIdLocked(); + device = std::make_shared(&mContext, deviceId, bumpGenerationLocked(), + identifier); + } + device->addEventHubDevice(eventHubId); return device; } -void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, +void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents, size_t count) { - auto deviceIt = mDevices.find(deviceId); + auto deviceIt = mDevices.find(eventHubId); if (deviceIt == mDevices.end()) { - ALOGW("Discarding event for unknown deviceId %d.", deviceId); + ALOGW("Discarding event for unknown eventHubId %d.", eventHubId); return; } @@ -268,6 +284,17 @@ void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* device->process(rawEvents, count); } +InputDevice* InputReader::findInputDevice(int32_t deviceId) { + auto deviceIt = + std::find_if(mDevices.begin(), mDevices.end(), [deviceId](const auto& devicePair) { + return devicePair.second->getId() == deviceId; + }); + if (deviceIt != mDevices.end()) { + return deviceIt->second.get(); + } + return nullptr; +} + void InputReader::timeoutExpiredLocked(nsecs_t when) { for (auto& devicePair : mDevices) { std::shared_ptr& device = devicePair.second; @@ -277,6 +304,10 @@ void InputReader::timeoutExpiredLocked(nsecs_t when) { } } +int32_t InputReader::nextInputDeviceIdLocked() { + return ++mNextInputDeviceId; +} + void InputReader::handleConfigurationChangedLocked(nsecs_t when) { // Reset global meta state because it depends on the list of all configured devices. updateGlobalMetaStateLocked(); @@ -414,12 +445,9 @@ int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32 GetStateFunc getStateFunc) { int32_t result = AKEY_STATE_UNKNOWN; if (deviceId >= 0) { - auto deviceIt = mDevices.find(deviceId); - if (deviceIt != mDevices.end()) { - std::shared_ptr& device = deviceIt->second; - if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = (device.get()->*getStateFunc)(sourceMask, code); - } + InputDevice* device = findInputDevice(deviceId); + if (device && !device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { + result = (device->*getStateFunc)(sourceMask, code); } } else { for (auto& devicePair : mDevices) { @@ -440,13 +468,12 @@ int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32 } void InputReader::toggleCapsLockState(int32_t deviceId) { - auto deviceIt = mDevices.find(deviceId); - if (deviceIt == mDevices.end()) { + InputDevice* device = findInputDevice(deviceId); + if (!device) { ALOGW("Ignoring toggleCapsLock for unknown deviceId %" PRId32 ".", deviceId); return; } - std::shared_ptr& device = deviceIt->second; if (device->isIgnored()) { return; } @@ -467,12 +494,9 @@ bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceM uint8_t* outFlags) { bool result = false; if (deviceId >= 0) { - auto deviceIt = mDevices.find(deviceId); - if (deviceIt != mDevices.end()) { - std::shared_ptr& device = deviceIt->second; - if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); - } + InputDevice* device = findInputDevice(deviceId); + if (device && !device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { + result = device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); } } else { for (auto& devicePair : mDevices) { @@ -501,9 +525,8 @@ void InputReader::requestRefreshConfiguration(uint32_t changes) { void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token) { AutoMutex _l(mLock); - auto deviceIt = mDevices.find(deviceId); - if (deviceIt != mDevices.end()) { - std::shared_ptr& device = deviceIt->second; + InputDevice* device = findInputDevice(deviceId); + if (device) { device->vibrate(pattern, patternSize, repeat, token); } } @@ -511,9 +534,8 @@ void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patte void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { AutoMutex _l(mLock); - auto deviceIt = mDevices.find(deviceId); - if (deviceIt != mDevices.end()) { - std::shared_ptr& device = deviceIt->second; + InputDevice* device = findInputDevice(deviceId); + if (device) { device->cancelVibrate(token); } } @@ -521,9 +543,8 @@ void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { bool InputReader::isInputDeviceEnabled(int32_t deviceId) { AutoMutex _l(mLock); - auto deviceIt = mDevices.find(deviceId); - if (deviceIt != mDevices.end()) { - std::shared_ptr& device = deviceIt->second; + InputDevice* device = findInputDevice(deviceId); + if (device) { return device->isEnabled(); } ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId); @@ -533,13 +554,12 @@ bool InputReader::isInputDeviceEnabled(int32_t deviceId) { bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) { AutoMutex _l(mLock); - auto deviceIt = mDevices.find(deviceId); - if (deviceIt == mDevices.end()) { + InputDevice* device = findInputDevice(deviceId); + if (!device) { ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId); return false; } - std::shared_ptr& device = deviceIt->second; if (!device->isEnabled()) { ALOGW("Ignoring disabled device %s", device->getName().c_str()); return false; diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 0814d1f16e..aaa0d268b3 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -17,18 +17,19 @@ #ifndef _UI_INPUTREADER_INPUT_DEVICE_H #define _UI_INPUTREADER_INPUT_DEVICE_H -#include "EventHub.h" -#include "InputReaderBase.h" -#include "InputReaderContext.h" - #include #include +#include #include -#include #include +#include #include +#include "EventHub.h" +#include "InputReaderBase.h" +#include "InputReaderContext.h" + namespace android { class InputDeviceContext; @@ -38,8 +39,7 @@ class InputMapper; class InputDevice { public: InputDevice(InputReaderContext* context, int32_t id, int32_t generation, - int32_t controllerNumber, const InputDeviceIdentifier& identifier, - uint32_t classes); + const InputDeviceIdentifier& identifier); ~InputDevice(); inline InputReaderContext* getContext() { return mContext; } @@ -50,25 +50,25 @@ public: inline const std::string getDescriptor() { return mIdentifier.descriptor; } inline uint32_t getClasses() const { return mClasses; } inline uint32_t getSources() const { return mSources; } + inline bool hasEventHubDevices() const { return !mDevices.empty(); } inline bool isExternal() { return mIsExternal; } - inline void setExternal(bool external) { mIsExternal = external; } inline std::optional getAssociatedDisplayPort() const { return mAssociatedDisplayPort; } inline std::optional getAssociatedViewport() const { return mAssociatedViewport; } - inline void setMic(bool hasMic) { mHasMic = hasMic; } inline bool hasMic() const { return mHasMic; } - inline bool isIgnored() { return mMappers.empty(); } + inline bool isIgnored() { return !getMapperCount(); } bool isEnabled(); void setEnabled(bool enabled, nsecs_t when); void dump(std::string& dump); - void populateMappers(); + void addEventHubDevice(int32_t eventHubId, bool populateMappers = true); + void removeEventHubDevice(int32_t eventHubId); void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); void reset(nsecs_t when); void process(const RawEvent* rawEvents, size_t count); @@ -99,11 +99,20 @@ public: std::optional getAssociatedDisplayId(); + size_t getMapperCount(); + // construct and add a mapper to the input device template - T& addMapper(Args... args) { - T* mapper = new T(*mDeviceContext, args...); - mMappers.emplace_back(mapper); + T& addMapper(int32_t eventHubId, Args... args) { + // ensure a device entry exists for this eventHubId + addEventHubDevice(eventHubId, false); + + // create mapper + auto& devicePair = mDevices[eventHubId]; + auto& deviceContext = devicePair.first; + auto& mappers = devicePair.second; + T* mapper = new T(*deviceContext, args...); + mappers.emplace_back(mapper); return *mapper; } @@ -116,8 +125,10 @@ private: std::string mAlias; uint32_t mClasses; - std::unique_ptr mDeviceContext; - std::vector> mMappers; + // map from eventHubId to device context and mappers + using MapperVector = std::vector>; + using DevicePair = std::pair, MapperVector>; + std::unordered_map mDevices; uint32_t mSources; bool mIsExternal; @@ -131,10 +142,37 @@ private: PropertyMap mConfiguration; - // run a function against every mapper + // helpers to interate over the devices collection + // run a function against every mapper on every subdevice inline void for_each_mapper(std::function f) { - for (auto& mapperPtr : mMappers) { - f(*mapperPtr); + for (auto& deviceEntry : mDevices) { + auto& devicePair = deviceEntry.second; + auto& mappers = devicePair.second; + for (auto& mapperPtr : mappers) { + f(*mapperPtr); + } + } + } + + // run a function against every mapper on a specific subdevice + inline void for_each_mapper_in_subdevice(int32_t eventHubDevice, + std::function f) { + auto deviceIt = mDevices.find(eventHubDevice); + if (deviceIt != mDevices.end()) { + auto& devicePair = deviceIt->second; + auto& mappers = devicePair.second; + for (auto& mapperPtr : mappers) { + f(*mapperPtr); + } + } + } + + // run a function against every subdevice + inline void for_each_subdevice(std::function f) { + for (auto& deviceEntry : mDevices) { + auto& devicePair = deviceEntry.second; + auto& contextPtr = devicePair.first; + f(*contextPtr); } } @@ -142,10 +180,14 @@ private: // if all mappers return nullopt, return nullopt. template inline std::optional first_in_mappers(std::function(InputMapper&)> f) { - for (auto& mapperPtr : mMappers) { - std::optional ret = f(*mapperPtr); - if (ret) { - return ret; + for (auto& deviceEntry : mDevices) { + auto& devicePair = deviceEntry.second; + auto& mappers = devicePair.second; + for (auto& mapperPtr : mappers) { + std::optional ret = f(*mapperPtr); + if (ret) { + return ret; + } } } return std::nullopt; @@ -159,11 +201,12 @@ private: */ class InputDeviceContext { public: - InputDeviceContext(InputDevice& device); + InputDeviceContext(InputDevice& device, int32_t eventHubId); ~InputDeviceContext(); inline InputReaderContext* getContext() { return mContext; } - inline int32_t getId() { return mId; } + inline int32_t getId() { return mDeviceId; } + inline int32_t getEventHubId() { return mId; } inline uint32_t getDeviceClasses() const { return mEventHub->getDeviceClasses(mId); } inline InputDeviceIdentifier getDeviceIdentifier() const { @@ -259,6 +302,7 @@ private: InputReaderContext* mContext; EventHubInterface* mEventHub; int32_t mId; + int32_t mDeviceId; }; } // namespace android diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index 4f5d2eabf3..31d82f1abe 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -84,10 +84,8 @@ public: protected: // These members are protected so they can be instrumented by test cases. - virtual std::shared_ptr createDeviceLocked(int32_t deviceId, - int32_t controllerNumber, - const InputDeviceIdentifier& identifier, - uint32_t classes); + virtual std::shared_ptr createDeviceLocked( + int32_t deviceId, const InputDeviceIdentifier& identifier); // With each iteration of the loop, InputReader reads and processes one incoming message from // the EventHub. @@ -139,14 +137,16 @@ private: static const int EVENT_BUFFER_SIZE = 256; RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; - std::unordered_map> mDevices; + // An input device can represent a collection of EventHub devices. This map provides a way + // to lookup the input device instance from the EventHub device id. + std::unordered_map> mDevices; // low-level input event decoding and device management void processEventsLocked(const RawEvent* rawEvents, size_t count); - void addDeviceLocked(nsecs_t when, int32_t deviceId); - void removeDeviceLocked(nsecs_t when, int32_t deviceId); - void processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count); + void addDeviceLocked(nsecs_t when, int32_t eventHubId); + void removeDeviceLocked(nsecs_t when, int32_t eventHubId); + void processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents, size_t count); void timeoutExpiredLocked(nsecs_t when); void handleConfigurationChangedLocked(nsecs_t when); @@ -164,6 +164,9 @@ private: int32_t mGeneration; int32_t bumpGenerationLocked(); + int32_t mNextInputDeviceId; + int32_t nextInputDeviceIdLocked(); + void getInputDevicesLocked(std::vector& outInputDevices); nsecs_t mDisableVirtualKeysTimeout; @@ -182,6 +185,9 @@ private: GetStateFunc getStateFunc); bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); + + // find an InputDevice from an InputDevice id + InputDevice* findInputDevice(int32_t deviceId); }; } // namespace android diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index d870a01bfa..578605fa40 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1103,31 +1103,27 @@ public: void setNextDevice(std::shared_ptr device) { mNextDevice = device; } - std::shared_ptr newDevice(int32_t deviceId, int32_t controllerNumber, - const std::string& name, uint32_t classes, + std::shared_ptr newDevice(int32_t deviceId, const std::string& name, const std::string& location = "") { InputDeviceIdentifier identifier; identifier.name = name; identifier.location = location; int32_t generation = deviceId + 1; - return std::make_shared(&mContext, deviceId, generation, controllerNumber, - identifier, classes); + return std::make_shared(&mContext, deviceId, generation, identifier); } // Make the protected loopOnce method accessible to tests. using InputReader::loopOnce; protected: - virtual std::shared_ptr createDeviceLocked(int32_t deviceId, - int32_t controllerNumber, - const InputDeviceIdentifier& identifier, - uint32_t classes) { + virtual std::shared_ptr createDeviceLocked( + int32_t eventHubId, const InputDeviceIdentifier& identifier) { if (mNextDevice) { std::shared_ptr device(mNextDevice); mNextDevice = nullptr; return device; } - return InputReader::createDeviceLocked(deviceId, controllerNumber, identifier, classes); + return InputReader::createDeviceLocked(eventHubId, identifier); } friend class InputReaderTest; @@ -1338,12 +1334,12 @@ protected: mFakePolicy.clear(); } - void addDevice(int32_t deviceId, const std::string& name, uint32_t classes, - const PropertyMap* configuration) { - mFakeEventHub->addDevice(deviceId, name, classes); + void addDevice(int32_t eventHubId, const std::string& name, uint32_t classes, + const PropertyMap* configuration) { + mFakeEventHub->addDevice(eventHubId, name, classes); if (configuration) { - mFakeEventHub->addConfigurationMap(deviceId, configuration); + mFakeEventHub->addConfigurationMap(eventHubId, configuration); } mFakeEventHub->finishDeviceScan(); mReader->loopOnce(); @@ -1362,15 +1358,14 @@ protected: mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_ENABLED_STATE); } - FakeInputMapper& addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber, + FakeInputMapper& addDeviceWithFakeInputMapper(int32_t deviceId, int32_t eventHubId, const std::string& name, uint32_t classes, uint32_t sources, const PropertyMap* configuration) { - std::shared_ptr device = - mReader->newDevice(deviceId, controllerNumber, name, classes); - FakeInputMapper& mapper = device->addMapper(sources); + std::shared_ptr device = mReader->newDevice(deviceId, name); + FakeInputMapper& mapper = device->addMapper(eventHubId, sources); mReader->setNextDevice(device); - addDevice(deviceId, name, classes, configuration); + addDevice(eventHubId, name, classes, configuration); return mapper; } }; @@ -1384,7 +1379,7 @@ TEST_F(InputReaderTest, GetInputDevices) { std::vector inputDevices; mReader->getInputDevices(inputDevices); ASSERT_EQ(1U, inputDevices.size()); - ASSERT_EQ(1, inputDevices[0].getId()); + ASSERT_EQ(END_RESERVED_ID + 1, inputDevices[0].getId()); ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.c_str()); ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType()); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources()); @@ -1393,7 +1388,7 @@ TEST_F(InputReaderTest, GetInputDevices) { // Should also have received a notification describing the new input devices. inputDevices = mFakePolicy->getInputDevices(); ASSERT_EQ(1U, inputDevices.size()); - ASSERT_EQ(1, inputDevices[0].getId()); + ASSERT_EQ(END_RESERVED_ID + 1, inputDevices[0].getId()); ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.c_str()); ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType()); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources()); @@ -1401,14 +1396,14 @@ TEST_F(InputReaderTest, GetInputDevices) { } TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) { - constexpr int32_t deviceId = 1; + constexpr int32_t deviceId = END_RESERVED_ID + 1000; constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; - std::shared_ptr device = - mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass); + constexpr int32_t eventHubId = 1; + std::shared_ptr device = mReader->newDevice(deviceId, "fake"); // Must add at least one mapper or the device will be ignored! - device->addMapper(AINPUT_SOURCE_KEYBOARD); + device->addMapper(eventHubId, AINPUT_SOURCE_KEYBOARD); mReader->setNextDevice(device); - ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr)); + ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(nullptr)); @@ -1438,8 +1433,11 @@ TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) { } TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { + constexpr int32_t deviceId = END_RESERVED_ID + 1000; + constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; + constexpr int32_t eventHubId = 1; FakeInputMapper& mapper = - addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD, + addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass, AINPUT_SOURCE_KEYBOARD, nullptr); mapper.setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); @@ -1447,13 +1445,16 @@ TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { AINPUT_SOURCE_ANY, AKEYCODE_A)) << "Should return unknown when the device id is >= 0 but unknown."; - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(1, - AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return unknown when the device id is valid but the sources are not supported by the device."; + ASSERT_EQ(AKEY_STATE_UNKNOWN, + mReader->getKeyCodeState(deviceId, AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) + << "Should return unknown when the device id is valid but the sources are not " + "supported by the device."; - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) - << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; + ASSERT_EQ(AKEY_STATE_DOWN, + mReader->getKeyCodeState(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, + AKEYCODE_A)) + << "Should return value provided by mapper when device id is valid and the device " + "supports some of the sources."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(-1, AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) @@ -1465,8 +1466,11 @@ TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { } TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { + constexpr int32_t deviceId = END_RESERVED_ID + 1000; + constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; + constexpr int32_t eventHubId = 1; FakeInputMapper& mapper = - addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD, + addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass, AINPUT_SOURCE_KEYBOARD, nullptr); mapper.setScanCodeState(KEY_A, AKEY_STATE_DOWN); @@ -1474,13 +1478,16 @@ TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { AINPUT_SOURCE_ANY, KEY_A)) << "Should return unknown when the device id is >= 0 but unknown."; - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(1, - AINPUT_SOURCE_TRACKBALL, KEY_A)) - << "Should return unknown when the device id is valid but the sources are not supported by the device."; + ASSERT_EQ(AKEY_STATE_UNKNOWN, + mReader->getScanCodeState(deviceId, AINPUT_SOURCE_TRACKBALL, KEY_A)) + << "Should return unknown when the device id is valid but the sources are not " + "supported by the device."; - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A)) - << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; + ASSERT_EQ(AKEY_STATE_DOWN, + mReader->getScanCodeState(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, + KEY_A)) + << "Should return value provided by mapper when device id is valid and the device " + "supports some of the sources."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(-1, AINPUT_SOURCE_TRACKBALL, KEY_A)) @@ -1492,8 +1499,11 @@ TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { } TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { + constexpr int32_t deviceId = END_RESERVED_ID + 1000; + constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; + constexpr int32_t eventHubId = 1; FakeInputMapper& mapper = - addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD, + addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass, AINPUT_SOURCE_KEYBOARD, nullptr); mapper.setSwitchState(SW_LID, AKEY_STATE_DOWN); @@ -1501,13 +1511,16 @@ TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { AINPUT_SOURCE_ANY, SW_LID)) << "Should return unknown when the device id is >= 0 but unknown."; - ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(1, - AINPUT_SOURCE_TRACKBALL, SW_LID)) - << "Should return unknown when the device id is valid but the sources are not supported by the device."; + ASSERT_EQ(AKEY_STATE_UNKNOWN, + mReader->getSwitchState(deviceId, AINPUT_SOURCE_TRACKBALL, SW_LID)) + << "Should return unknown when the device id is valid but the sources are not " + "supported by the device."; - ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(1, - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID)) - << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; + ASSERT_EQ(AKEY_STATE_DOWN, + mReader->getSwitchState(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, + SW_LID)) + << "Should return value provided by mapper when device id is valid and the device " + "supports some of the sources."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(-1, AINPUT_SOURCE_TRACKBALL, SW_LID)) @@ -1519,8 +1532,11 @@ TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { } TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { + constexpr int32_t deviceId = END_RESERVED_ID + 1000; + constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; + constexpr int32_t eventHubId = 1; FakeInputMapper& mapper = - addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD, + addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass, AINPUT_SOURCE_KEYBOARD, nullptr); mapper.addSupportedKeyCode(AKEYCODE_A); @@ -1534,13 +1550,16 @@ TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; - ASSERT_FALSE(mReader->hasKeys(1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return false when device id is valid but the sources are not supported by the device."; + ASSERT_FALSE(mReader->hasKeys(deviceId, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) + << "Should return false when device id is valid but the sources are not supported by " + "the device."; ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; - ASSERT_TRUE(mReader->hasKeys(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; + ASSERT_TRUE(mReader->hasKeys(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, + keyCodes, flags)) + << "Should return value provided by mapper when device id is valid and the device " + "supports some of the sources."; ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); flags[3] = 1; @@ -1555,7 +1574,8 @@ TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { } TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChanged) { - addDevice(1, "ignored", INPUT_DEVICE_CLASS_KEYBOARD, nullptr); + constexpr int32_t eventHubId = 1; + addDevice(eventHubId, "ignored", INPUT_DEVICE_CLASS_KEYBOARD, nullptr); NotifyConfigurationChangedArgs args; @@ -1564,32 +1584,35 @@ TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChange } TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { + constexpr int32_t deviceId = END_RESERVED_ID + 1000; + constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; + constexpr int32_t eventHubId = 1; FakeInputMapper& mapper = - addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD, + addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass, AINPUT_SOURCE_KEYBOARD, nullptr); - mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, 1); + mFakeEventHub->enqueueEvent(0, eventHubId, EV_KEY, KEY_A, 1); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeEventHub->assertQueueIsEmpty()); RawEvent event; ASSERT_NO_FATAL_FAILURE(mapper.assertProcessWasCalled(&event)); ASSERT_EQ(0, event.when); - ASSERT_EQ(1, event.deviceId); + ASSERT_EQ(eventHubId, event.deviceId); ASSERT_EQ(EV_KEY, event.type); ASSERT_EQ(KEY_A, event.code); ASSERT_EQ(1, event.value); } TEST_F(InputReaderTest, DeviceReset_IncrementsSequenceNumber) { - constexpr int32_t deviceId = 1; + constexpr int32_t deviceId = END_RESERVED_ID + 1000; constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; - std::shared_ptr device = - mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass); + constexpr int32_t eventHubId = 1; + std::shared_ptr device = mReader->newDevice(deviceId, "fake"); // Must add at least one mapper or the device will be ignored! - device->addMapper(AINPUT_SOURCE_KEYBOARD); + device->addMapper(eventHubId, AINPUT_SOURCE_KEYBOARD); mReader->setNextDevice(device); - ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr)); + ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr)); NotifyDeviceResetArgs resetArgs; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); @@ -1615,12 +1638,13 @@ TEST_F(InputReaderTest, DeviceReset_IncrementsSequenceNumber) { } TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { - constexpr int32_t deviceId = 1; + constexpr int32_t deviceId = END_RESERVED_ID + 1000; constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; + constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "USB1"; - std::shared_ptr device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, - "fake", deviceClass, DEVICE_LOCATION); - FakeInputMapper& mapper = device->addMapper(AINPUT_SOURCE_TOUCHSCREEN); + std::shared_ptr device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); + FakeInputMapper& mapper = + device->addMapper(eventHubId, AINPUT_SOURCE_TOUCHSCREEN); mReader->setNextDevice(device); const uint8_t hdmi1 = 1; @@ -1640,7 +1664,7 @@ TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { // Add the device, and make sure all of the callbacks are triggered. // The device is added after the input port associations are processed since // we do not yet support dynamic device-to-display associations. - ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr)); + ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled()); @@ -1666,6 +1690,7 @@ protected: static const int32_t DEVICE_GENERATION; static const int32_t DEVICE_CONTROLLER_NUMBER; static const uint32_t DEVICE_CLASSES; + static const int32_t EVENTHUB_ID; std::shared_ptr mFakeEventHub; sp mFakePolicy; @@ -1680,13 +1705,12 @@ protected: mFakeListener = new TestInputListener(); mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener); - mFakeEventHub->addDevice(DEVICE_ID, DEVICE_NAME, 0); + mFakeEventHub->addDevice(EVENTHUB_ID, DEVICE_NAME, 0); InputDeviceIdentifier identifier; identifier.name = DEVICE_NAME; identifier.location = DEVICE_LOCATION; - mDevice = - std::make_shared(mFakeContext, DEVICE_ID, DEVICE_GENERATION, - DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); + mDevice = std::make_shared(mFakeContext, DEVICE_ID, DEVICE_GENERATION, + identifier); } virtual void TearDown() override { @@ -1699,20 +1723,21 @@ protected: const char* InputDeviceTest::DEVICE_NAME = "device"; const char* InputDeviceTest::DEVICE_LOCATION = "USB1"; -const int32_t InputDeviceTest::DEVICE_ID = 1; +const int32_t InputDeviceTest::DEVICE_ID = END_RESERVED_ID + 1000; const int32_t InputDeviceTest::DEVICE_GENERATION = 2; const int32_t InputDeviceTest::DEVICE_CONTROLLER_NUMBER = 0; const uint32_t InputDeviceTest::DEVICE_CLASSES = INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_JOYSTICK; +const int32_t InputDeviceTest::EVENTHUB_ID = 1; TEST_F(InputDeviceTest, ImmutableProperties) { ASSERT_EQ(DEVICE_ID, mDevice->getId()); ASSERT_STREQ(DEVICE_NAME, mDevice->getName().c_str()); - ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses()); + ASSERT_EQ(0U, mDevice->getClasses()); } -TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsTrue) { - ASSERT_EQ(mDevice->isEnabled(), true); +TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsFalse) { + ASSERT_EQ(mDevice->isEnabled(), false); } TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { @@ -1759,9 +1784,10 @@ TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) { // Configuration. - mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8("key"), String8("value")); + mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, String8("key"), String8("value")); - FakeInputMapper& mapper1 = mDevice->addMapper(AINPUT_SOURCE_KEYBOARD); + FakeInputMapper& mapper1 = + mDevice->addMapper(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD); mapper1.setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC); mapper1.setMetaState(AMETA_ALT_ON); mapper1.addSupportedKeyCode(AKEYCODE_A); @@ -1772,7 +1798,8 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe mapper1.setScanCodeState(3, AKEY_STATE_UP); mapper1.setSwitchState(4, AKEY_STATE_DOWN); - FakeInputMapper& mapper2 = mDevice->addMapper(AINPUT_SOURCE_TOUCHSCREEN); + FakeInputMapper& mapper2 = + mDevice->addMapper(EVENTHUB_ID, AINPUT_SOURCE_TOUCHSCREEN); mapper2.setMetaState(AMETA_SHIFT_ON); InputReaderConfiguration config; @@ -1843,6 +1870,7 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe // Event handling. RawEvent event; + event.deviceId = EVENTHUB_ID; mDevice->process(&event, 1); ASSERT_NO_FATAL_FAILURE(mapper1.assertProcessWasCalled()); @@ -1853,7 +1881,7 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe // 1. Device is disabled if the viewport corresponding to the associated display is not found // 2. Device is disabled when setEnabled API is called TEST_F(InputDeviceTest, Configure_AssignsDisplayPort) { - mDevice->addMapper(AINPUT_SOURCE_TOUCHSCREEN); + mDevice->addMapper(EVENTHUB_ID, AINPUT_SOURCE_TOUCHSCREEN); // First Configuration. mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0); @@ -1902,6 +1930,7 @@ protected: static const int32_t DEVICE_GENERATION; static const int32_t DEVICE_CONTROLLER_NUMBER; static const uint32_t DEVICE_CLASSES; + static const int32_t EVENTHUB_ID; std::shared_ptr mFakeEventHub; sp mFakePolicy; @@ -1909,7 +1938,7 @@ protected: FakeInputReaderContext* mFakeContext; InputDevice* mDevice; - virtual void SetUp() override { + virtual void SetUp(uint32_t classes) { mFakeEventHub = std::make_unique(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = new TestInputListener(); @@ -1917,12 +1946,13 @@ protected: InputDeviceIdentifier identifier; identifier.name = DEVICE_NAME; identifier.location = DEVICE_LOCATION; - mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION, - DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); + mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION, identifier); - mFakeEventHub->addDevice(mDevice->getId(), DEVICE_NAME, 0); + mFakeEventHub->addDevice(EVENTHUB_ID, DEVICE_NAME, classes); } + virtual void SetUp() override { SetUp(DEVICE_CLASSES); } + virtual void TearDown() override { delete mDevice; delete mFakeContext; @@ -1931,7 +1961,7 @@ protected: } void addConfigurationProperty(const char* key, const char* value) { - mFakeEventHub->addConfigurationProperty(mDevice->getId(), String8(key), String8(value)); + mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, String8(key), String8(value)); } void configureDevice(uint32_t changes) { @@ -1940,7 +1970,7 @@ protected: template T& addMapperAndConfigure(Args... args) { - T& mapper = mDevice->addMapper(args...); + T& mapper = mDevice->addMapper(EVENTHUB_ID, args...); configureDevice(0); mDevice->reset(ARBITRARY_TIME); return mapper; @@ -1962,7 +1992,7 @@ protected: int32_t value) { RawEvent event; event.when = when; - event.deviceId = mapper.getDeviceId(); + event.deviceId = mapper.getDeviceContext().getEventHubId(); event.type = type; event.code = code; event.value = value; @@ -2007,11 +2037,11 @@ protected: const char* InputMapperTest::DEVICE_NAME = "device"; const char* InputMapperTest::DEVICE_LOCATION = "USB1"; -const int32_t InputMapperTest::DEVICE_ID = 1; +const int32_t InputMapperTest::DEVICE_ID = END_RESERVED_ID + 1000; const int32_t InputMapperTest::DEVICE_GENERATION = 2; const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0; const uint32_t InputMapperTest::DEVICE_CLASSES = 0; // not needed for current tests - +const int32_t InputMapperTest::EVENTHUB_ID = 1; // --- SwitchInputMapperTest --- @@ -2028,10 +2058,10 @@ TEST_F(SwitchInputMapperTest, GetSources) { TEST_F(SwitchInputMapperTest, GetSwitchState) { SwitchInputMapper& mapper = addMapperAndConfigure(); - mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 1); + mFakeEventHub->setSwitchState(EVENTHUB_ID, SW_LID, 1); ASSERT_EQ(1, mapper.getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); - mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 0); + mFakeEventHub->setSwitchState(EVENTHUB_ID, SW_LID, 0); ASSERT_EQ(0, mapper.getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); } @@ -2105,8 +2135,8 @@ TEST_F(KeyboardInputMapperTest, GetSources) { TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { const int32_t USAGE_A = 0x070004; const int32_t USAGE_UNKNOWN = 0x07ffff; - mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); - mFakeEventHub->addKey(DEVICE_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); + mFakeEventHub->addKey(EVENTHUB_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE); KeyboardInputMapper& mapper = addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, @@ -2203,8 +2233,8 @@ TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { } TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) { - mFakeEventHub->addKey(DEVICE_ID, KEY_LEFTSHIFT, 0, AKEYCODE_SHIFT_LEFT, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFTSHIFT, 0, AKEYCODE_SHIFT_LEFT, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0); KeyboardInputMapper& mapper = addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, @@ -2242,10 +2272,10 @@ TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) { } TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateDPad) { - mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); KeyboardInputMapper& mapper = addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, @@ -2263,10 +2293,10 @@ TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateD } TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { - mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); addConfigurationProperty("keyboard.orientationAware", "1"); KeyboardInputMapper& mapper = @@ -2339,7 +2369,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_NotOrientationAware) { // If the keyboard is not orientation aware, // key events should not be associated with a specific display id - mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); KeyboardInputMapper& mapper = addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, @@ -2364,7 +2394,7 @@ TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_NotOrientationAware TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_OrientationAware) { // If the keyboard is orientation aware, // key events should be associated with the internal viewport - mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); addConfigurationProperty("keyboard.orientationAware", "1"); KeyboardInputMapper& mapper = @@ -2399,10 +2429,10 @@ TEST_F(KeyboardInputMapperTest, GetKeyCodeState) { addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 1); + mFakeEventHub->setKeyCodeState(EVENTHUB_ID, AKEYCODE_A, 1); ASSERT_EQ(1, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); - mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 0); + mFakeEventHub->setKeyCodeState(EVENTHUB_ID, AKEYCODE_A, 0); ASSERT_EQ(0, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); } @@ -2411,10 +2441,10 @@ TEST_F(KeyboardInputMapperTest, GetScanCodeState) { addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 1); + mFakeEventHub->setScanCodeState(EVENTHUB_ID, KEY_A, 1); ASSERT_EQ(1, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); - mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 0); + mFakeEventHub->setScanCodeState(EVENTHUB_ID, KEY_A, 0); ASSERT_EQ(0, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); } @@ -2423,7 +2453,7 @@ TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) { addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0); const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; uint8_t flags[2] = { 0, 0 }; @@ -2433,99 +2463,100 @@ TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) { } TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) { - mFakeEventHub->addLed(DEVICE_ID, LED_CAPSL, true /*initially on*/); - mFakeEventHub->addLed(DEVICE_ID, LED_NUML, false /*initially off*/); - mFakeEventHub->addLed(DEVICE_ID, LED_SCROLLL, false /*initially off*/); - mFakeEventHub->addKey(DEVICE_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0); + mFakeEventHub->addLed(EVENTHUB_ID, LED_CAPSL, true /*initially on*/); + mFakeEventHub->addLed(EVENTHUB_ID, LED_NUML, false /*initially off*/); + mFakeEventHub->addLed(EVENTHUB_ID, LED_SCROLLL, false /*initially off*/); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0); KeyboardInputMapper& mapper = addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); // Initialization should have turned all of the lights off. - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL)); // Toggle caps lock on. process(mapper, ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 1); process(mapper, ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 0); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); + ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState()); // Toggle num lock on. process(mapper, ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 1); process(mapper, ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 0); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); + ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL)); + ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper.getMetaState()); // Toggle caps lock off. process(mapper, ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 1); process(mapper, ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 0); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL)); + ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState()); // Toggle scroll lock on. process(mapper, ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 1); process(mapper, ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 0); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL)); + ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML)); + ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper.getMetaState()); // Toggle num lock off. process(mapper, ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 1); process(mapper, ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 0); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML)); + ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper.getMetaState()); // Toggle scroll lock off. process(mapper, ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 1); process(mapper, ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 0); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); - ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML)); + ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_NONE, mapper.getMetaState()); } TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) { // keyboard 1. - mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); // keyboard 2. const std::string USB2 = "USB2"; constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1; + constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1; InputDeviceIdentifier identifier; identifier.name = "KEYBOARD2"; identifier.location = USB2; std::unique_ptr device2 = std::make_unique(mFakeContext, SECOND_DEVICE_ID, DEVICE_GENERATION, - DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); - mFakeEventHub->addDevice(SECOND_DEVICE_ID, DEVICE_NAME, 0 /*classes*/); - mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); - mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); - mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); - mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); + identifier); + mFakeEventHub->addDevice(SECOND_EVENTHUB_ID, DEVICE_NAME, 0 /*classes*/); + mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); + mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); + mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); + mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); KeyboardInputMapper& mapper = addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); KeyboardInputMapper& mapper2 = - device2->addMapper(AINPUT_SOURCE_KEYBOARD, + device2->addMapper(SECOND_EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/); device2->reset(ARBITRARY_TIME); @@ -2577,14 +2608,23 @@ TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) { AKEYCODE_DPAD_LEFT, newDisplayId)); } -TEST_F(KeyboardInputMapperTest, ExternalDevice_WakeBehavior) { +// --- KeyboardInputMapperTest_ExternalDevice --- + +class KeyboardInputMapperTest_ExternalDevice : public InputMapperTest { +protected: + virtual void SetUp() override { + InputMapperTest::SetUp(DEVICE_CLASSES | INPUT_DEVICE_CLASS_EXTERNAL); + } +}; + +TEST_F(KeyboardInputMapperTest_ExternalDevice, WakeBehavior) { // For external devices, non-media keys will trigger wake on key down. Media keys need to be // marked as WAKE in the keylayout file to trigger wake. - mDevice->setExternal(true); - mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE, POLICY_FLAG_WAKE); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE, + POLICY_FLAG_WAKE); KeyboardInputMapper& mapper = addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, @@ -2616,13 +2656,12 @@ TEST_F(KeyboardInputMapperTest, ExternalDevice_WakeBehavior) { ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); } -TEST_F(KeyboardInputMapperTest, ExternalDevice_DoNotWakeByDefaultBehavior) { +TEST_F(KeyboardInputMapperTest_ExternalDevice, DoNotWakeByDefaultBehavior) { // Tv Remote key's wake behavior is prescribed by the keylayout file. - mDevice->setExternal(true); - mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); - mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); - mFakeEventHub->addKey(DEVICE_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, POLICY_FLAG_WAKE); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, POLICY_FLAG_WAKE); addConfigurationProperty("keyboard.doNotWakeByDefault", "1"); KeyboardInputMapper& mapper = @@ -3564,10 +3603,10 @@ void TouchInputMapperTest::prepareVirtualDisplay(int32_t orientation) { } void TouchInputMapperTest::prepareVirtualKeys() { - mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[0]); - mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[1]); - mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); - mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, 0, AKEYCODE_MENU, POLICY_FLAG_WAKE); + mFakeEventHub->addVirtualKeyDefinition(EVENTHUB_ID, VIRTUAL_KEYS[0]); + mFakeEventHub->addVirtualKeyDefinition(EVENTHUB_ID, VIRTUAL_KEYS[1]); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); + mFakeEventHub->addKey(EVENTHUB_ID, KEY_MENU, 0, AKEYCODE_MENU, POLICY_FLAG_WAKE); } void TouchInputMapperTest::prepareLocationCalibration() { @@ -3628,33 +3667,29 @@ protected: }; void SingleTouchInputMapperTest::prepareButtons() { - mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); + mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); } void SingleTouchInputMapperTest::prepareAxes(int axes) { if (axes & POSITION) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_X, - RAW_X_MIN, RAW_X_MAX, 0, 0); - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_Y, - RAW_Y_MIN, RAW_Y_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_X, RAW_X_MIN, RAW_X_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0); } if (axes & PRESSURE) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_PRESSURE, - RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_PRESSURE, RAW_PRESSURE_MIN, + RAW_PRESSURE_MAX, 0, 0); } if (axes & TOOL) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TOOL_WIDTH, - RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_TOOL_WIDTH, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, + 0); } if (axes & DISTANCE) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_DISTANCE, - RAW_DISTANCE_MIN, RAW_DISTANCE_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_DISTANCE, RAW_DISTANCE_MIN, + RAW_DISTANCE_MAX, 0, 0); } if (axes & TILT) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_X, - RAW_TILT_MIN, RAW_TILT_MAX, 0, 0); - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_Y, - RAW_TILT_MIN, RAW_TILT_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_TILT_X, RAW_TILT_MIN, RAW_TILT_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_TILT_Y, RAW_TILT_MIN, RAW_TILT_MAX, 0, 0); } } @@ -3710,8 +3745,8 @@ TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNot } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) { - mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_X); - mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_Y); + mFakeEventHub->addRelativeAxis(EVENTHUB_ID, REL_X); + mFakeEventHub->addRelativeAxis(EVENTHUB_ID, REL_Y); prepareButtons(); prepareAxes(POSITION); SingleTouchInputMapper& mapper = addMapperAndConfigure(); @@ -4778,7 +4813,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueI prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); - mFakeEventHub->addKey(DEVICE_ID, BTN_TOOL_FINGER, 0, AKEYCODE_UNKNOWN, 0); + mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_FINGER, 0, AKEYCODE_UNKNOWN, 0); SingleTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs motionArgs; @@ -4940,51 +4975,47 @@ protected: void MultiTouchInputMapperTest::prepareAxes(int axes) { if (axes & POSITION) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_X, - RAW_X_MIN, RAW_X_MAX, 0, 0); - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_Y, - RAW_Y_MIN, RAW_Y_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0); } if (axes & TOUCH) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR, - RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MAJOR, RAW_TOUCH_MIN, + RAW_TOUCH_MAX, 0, 0); if (axes & MINOR) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR, - RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, RAW_TOUCH_MIN, + RAW_TOUCH_MAX, 0, 0); } } if (axes & TOOL) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR, - RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX, + 0, 0); if (axes & MINOR) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR, - RAW_TOOL_MAX, RAW_TOOL_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MAX, + RAW_TOOL_MAX, 0, 0); } } if (axes & ORIENTATION) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_ORIENTATION, - RAW_ORIENTATION_MIN, RAW_ORIENTATION_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_ORIENTATION, RAW_ORIENTATION_MIN, + RAW_ORIENTATION_MAX, 0, 0); } if (axes & PRESSURE) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_PRESSURE, - RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_PRESSURE, RAW_PRESSURE_MIN, + RAW_PRESSURE_MAX, 0, 0); } if (axes & DISTANCE) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_DISTANCE, - RAW_DISTANCE_MIN, RAW_DISTANCE_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_DISTANCE, RAW_DISTANCE_MIN, + RAW_DISTANCE_MAX, 0, 0); } if (axes & ID) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TRACKING_ID, - RAW_ID_MIN, RAW_ID_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TRACKING_ID, RAW_ID_MIN, RAW_ID_MAX, 0, + 0); } if (axes & SLOT) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_SLOT, - RAW_SLOT_MIN, RAW_SLOT_MAX, 0, 0); - mFakeEventHub->setAbsoluteAxisValue(DEVICE_ID, ABS_MT_SLOT, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_SLOT, RAW_SLOT_MIN, RAW_SLOT_MAX, 0, 0); + mFakeEventHub->setAbsoluteAxisValue(EVENTHUB_ID, ABS_MT_SLOT, 0); } if (axes & TOOL_TYPE) { - mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOOL_TYPE, - 0, MT_TOOL_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); } } @@ -6273,7 +6304,7 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIs addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT); - mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); + mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); MultiTouchInputMapper& mapper = addMapperAndConfigure(); NotifyMotionArgs motionArgs; @@ -6452,35 +6483,6 @@ TEST_F(MultiTouchInputMapperTest, Configure_AssignsDisplayPort) { ASSERT_EQ(DISPLAY_ID, args.displayId); } -/** - * Expect fallback to internal viewport if device is external and external viewport is not present. - */ -TEST_F(MultiTouchInputMapperTest, Viewports_Fallback) { - prepareAxes(POSITION); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - mDevice->setExternal(true); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); - - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources()); - - NotifyMotionArgs motionArgs; - - // Expect the event to be sent to the internal viewport, - // because an external viewport is not present. - processPosition(mapper, 100, 100); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(ADISPLAY_ID_DEFAULT, motionArgs.displayId); - - // Expect the event to be sent to the external viewport if it is present. - prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL); - processPosition(mapper, 100, 100); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId); -} - TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) { // Setup for second display. sp fakePointerController = new FakePointerController(); @@ -6517,27 +6519,28 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) { // Create the second touch screen device, and enable multi fingers. const std::string USB2 = "USB2"; constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1; + constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1; InputDeviceIdentifier identifier; identifier.name = "TOUCHSCREEN2"; identifier.location = USB2; std::unique_ptr device2 = std::make_unique(mFakeContext, SECOND_DEVICE_ID, DEVICE_GENERATION, - DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES); - mFakeEventHub->addDevice(SECOND_DEVICE_ID, DEVICE_NAME, 0 /*classes*/); - mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, - 0 /*flat*/, 0 /*fuzz*/); - mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, - 0 /*flat*/, 0 /*fuzz*/); - mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_TRACKING_ID, RAW_ID_MIN, RAW_ID_MAX, - 0 /*flat*/, 0 /*fuzz*/); - mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_SLOT, RAW_SLOT_MIN, RAW_SLOT_MAX, - 0 /*flat*/, 0 /*fuzz*/); - mFakeEventHub->setAbsoluteAxisValue(SECOND_DEVICE_ID, ABS_MT_SLOT, 0 /*value*/); - mFakeEventHub->addConfigurationProperty(SECOND_DEVICE_ID, String8("touch.deviceType"), - String8("touchScreen")); + identifier); + mFakeEventHub->addDevice(SECOND_EVENTHUB_ID, DEVICE_NAME, 0 /*classes*/); + mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, + 0 /*flat*/, 0 /*fuzz*/); + mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, + 0 /*flat*/, 0 /*fuzz*/); + mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_TRACKING_ID, RAW_ID_MIN, RAW_ID_MAX, + 0 /*flat*/, 0 /*fuzz*/); + mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_SLOT, RAW_SLOT_MIN, RAW_SLOT_MAX, + 0 /*flat*/, 0 /*fuzz*/); + mFakeEventHub->setAbsoluteAxisValue(SECOND_EVENTHUB_ID, ABS_MT_SLOT, 0 /*value*/); + mFakeEventHub->addConfigurationProperty(SECOND_EVENTHUB_ID, String8("touch.deviceType"), + String8("touchScreen")); // Setup the second touch screen device. - MultiTouchInputMapper& mapper2 = device2->addMapper(); + MultiTouchInputMapper& mapper2 = device2->addMapper(SECOND_EVENTHUB_ID); device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/); device2->reset(ARBITRARY_TIME); @@ -6598,7 +6601,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) { // Unrotated video frame TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2}); std::vector frames{frame}; - mFakeEventHub->setVideoFrames({{mDevice->getId(), frames}}); + mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}}); processPosition(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); @@ -6628,7 +6631,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_AreRotated) { clearViewports(); prepareDisplay(orientation); std::vector frames{frame}; - mFakeEventHub->setVideoFrames({{mDevice->getId(), frames}}); + mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}}); processPosition(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); @@ -6650,7 +6653,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreRotated) { NotifyMotionArgs motionArgs; prepareDisplay(DISPLAY_ORIENTATION_90); - mFakeEventHub->setVideoFrames({{mDevice->getId(), frames}}); + mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}}); processPosition(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); @@ -6824,4 +6827,41 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType) { ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); } +// --- MultiTouchInputMapperTest_ExternalDevice --- + +class MultiTouchInputMapperTest_ExternalDevice : public MultiTouchInputMapperTest { +protected: + virtual void SetUp() override { + InputMapperTest::SetUp(DEVICE_CLASSES | INPUT_DEVICE_CLASS_EXTERNAL); + } +}; + +/** + * Expect fallback to internal viewport if device is external and external viewport is not present. + */ +TEST_F(MultiTouchInputMapperTest_ExternalDevice, Viewports_Fallback) { + prepareAxes(POSITION); + addConfigurationProperty("touch.deviceType", "touchScreen"); + prepareDisplay(DISPLAY_ORIENTATION_0); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); + + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources()); + + NotifyMotionArgs motionArgs; + + // Expect the event to be sent to the internal viewport, + // because an external viewport is not present. + processPosition(mapper, 100, 100); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(ADISPLAY_ID_DEFAULT, motionArgs.displayId); + + // Expect the event to be sent to the external viewport if it is present. + prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL); + processPosition(mapper, 100, 100); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId); +} + } // namespace android -- GitLab From c7ef27eeccb801ed6d82b62a1d743f246f66eec9 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 3 Feb 2020 19:19:15 -0800 Subject: [PATCH 0833/1255] Let InputReaderContext hold a single PointerController InputMappers obtain the pointer controller directly from the policy, which, when we support multiple pointer controller, makes it natural to have one pointer controller for an input device. Rather than that, we want to build a system that makes it more natural to have one pointer per display. To give more control over the management of pointers, we make it so that InputReaderContext is responsible for managing the pointer controller. Bug: 146385350 Test: atest inputflinger_tests Change-Id: I0b9276ed4a7f55f04f910dd484ecc7f767b8723b --- services/inputflinger/reader/InputDevice.cpp | 4 -- services/inputflinger/reader/InputReader.cpp | 48 +++++++++++++++++-- .../inputflinger/reader/include/InputDevice.h | 2 - .../inputflinger/reader/include/InputReader.h | 6 +++ .../reader/include/InputReaderContext.h | 2 + .../reader/mapper/CursorInputMapper.cpp | 32 +------------ .../reader/mapper/CursorInputMapper.h | 3 -- .../reader/mapper/InputMapper.cpp | 2 - .../inputflinger/reader/mapper/InputMapper.h | 1 - .../reader/mapper/TouchInputMapper.cpp | 17 ++----- .../reader/mapper/TouchInputMapper.h | 1 - .../inputflinger/tests/InputReader_test.cpp | 26 ++++++++++ 12 files changed, 83 insertions(+), 61 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index d0eee64b0c..f2afc818ff 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -449,10 +449,6 @@ void InputDevice::updateMetaState(int32_t keyCode) { for_each_mapper([keyCode](InputMapper& mapper) { mapper.updateMetaState(keyCode); }); } -void InputDevice::fadePointer() { - for_each_mapper([](InputMapper& mapper) { mapper.fadePointer(); }); -} - void InputDevice::bumpGeneration() { mGeneration = mContext->bumpGeneration(); } diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index cbfa702015..6ab5902bb7 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -326,6 +326,10 @@ void InputReader::refreshConfigurationLocked(uint32_t changes) { InputReaderConfiguration::changesToString(changes).c_str()); nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + if (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) { + updatePointerDisplayLocked(); + } + if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) { mEventHub->requestReopenDevices(); } else { @@ -387,10 +391,43 @@ bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, int32_t keyCode, int32 } } +sp InputReader::getPointerControllerLocked(int32_t deviceId) { + sp controller = mPointerController.promote(); + if (controller == nullptr) { + controller = mPolicy->obtainPointerController(deviceId); + mPointerController = controller; + updatePointerDisplayLocked(); + } + return controller; +} + +void InputReader::updatePointerDisplayLocked() { + sp controller = mPointerController.promote(); + if (controller == nullptr) { + return; + } + + std::optional viewport = + mConfig.getDisplayViewportById(mConfig.defaultPointerDisplayId); + if (!viewport) { + ALOGW("Can't find the designated viewport with ID %" PRId32 " to update cursor input " + "mapper. Fall back to default display", + mConfig.defaultPointerDisplayId); + viewport = mConfig.getDisplayViewportById(ADISPLAY_ID_DEFAULT); + } + if (!viewport) { + ALOGE("Still can't find a viable viewport to update cursor input mapper. Skip setting it to" + " PointerController."); + return; + } + + controller->setDisplayViewport(*viewport); +} + void InputReader::fadePointerLocked() { - for (auto& devicePair : mDevices) { - std::shared_ptr& device = devicePair.second; - device->fadePointer(); + sp controller = mPointerController.promote(); + if (controller != nullptr) { + controller->fade(PointerControllerInterface::TRANSITION_GRADUAL); } } @@ -688,6 +725,11 @@ void InputReader::ContextImpl::fadePointer() { mReader->fadePointerLocked(); } +sp InputReader::ContextImpl::getPointerController(int32_t deviceId) { + // lock is already held by the input loop + return mReader->getPointerControllerLocked(deviceId); +} + void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) { // lock is already held by the input loop mReader->requestTimeoutAtTimeLocked(when); diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index aaa0d268b3..71313fc86f 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -88,8 +88,6 @@ public: int32_t getMetaState(); void updateMetaState(int32_t keyCode); - void fadePointer(); - void bumpGeneration(); void notifyReset(nsecs_t when); diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index 31d82f1abe..ca1a081e48 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -23,6 +23,7 @@ #include "InputReaderContext.h" #include "InputThread.h" +#include #include #include @@ -102,6 +103,7 @@ protected: virtual void disableVirtualKeysUntil(nsecs_t time) override; virtual bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) override; virtual void fadePointer() override; + virtual sp getPointerController(int32_t deviceId) override; virtual void requestTimeoutAtTime(nsecs_t when) override; virtual int32_t bumpGeneration() override; virtual void getExternalStylusDevices(std::vector& outDevices) override; @@ -159,6 +161,10 @@ private: void getExternalStylusDevicesLocked(std::vector& outDevices); void dispatchExternalStylusState(const StylusState& state); + // The PointerController that is shared among all the input devices that need it. + wp mPointerController; + sp getPointerControllerLocked(int32_t deviceId); + void updatePointerDisplayLocked(); void fadePointerLocked(); int32_t mGeneration; diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h index e14fbbec3d..d5527cf926 100644 --- a/services/inputflinger/reader/include/InputReaderContext.h +++ b/services/inputflinger/reader/include/InputReaderContext.h @@ -28,6 +28,7 @@ class InputDevice; class InputListenerInterface; class InputMapper; class InputReaderPolicyInterface; +class PointerControllerInterface; struct StylusState; /* Internal interface used by individual input devices to access global input device state @@ -45,6 +46,7 @@ public: virtual bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) = 0; virtual void fadePointer() = 0; + virtual sp getPointerController(int32_t deviceId) = 0; virtual void requestTimeoutAtTime(nsecs_t when) = 0; virtual int32_t bumpGeneration() = 0; diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 78f33823d0..c74987dfec 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -132,7 +132,7 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* mYPrecision = 1.0f; mXScale = 1.0f; mYScale = 1.0f; - mPointerController = getPolicy()->obtainPointerController(getDeviceId()); + mPointerController = getContext()->getPointerController(getDeviceId()); break; case Parameters::MODE_NAVIGATION: mSource = AINPUT_SOURCE_TRACKBALL; @@ -189,34 +189,10 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* } } - // Update the PointerController if viewports changed. - if (mParameters.mode == Parameters::MODE_POINTER) { - updatePointerControllerDisplayViewport(*config); - } bumpGeneration(); } } -void CursorInputMapper::updatePointerControllerDisplayViewport( - const InputReaderConfiguration& config) { - std::optional viewport = - config.getDisplayViewportById(config.defaultPointerDisplayId); - if (!viewport) { - ALOGW("Can't find the designated viewport with ID %" PRId32 " to update cursor input " - "mapper. Fall back to default display", - config.defaultPointerDisplayId); - viewport = config.getDisplayViewportById(ADISPLAY_ID_DEFAULT); - } - - if (!viewport) { - ALOGE("Still can't find a viable viewport to update cursor input mapper. Skip setting it to" - " PointerController."); - return; - } - - mPointerController->setDisplayViewport(*viewport); -} - void CursorInputMapper::configureParameters() { mParameters.mode = Parameters::MODE_POINTER; String8 cursorModeString; @@ -481,12 +457,6 @@ int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCod } } -void CursorInputMapper::fadePointer() { - if (mPointerController != nullptr) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } -} - std::optional CursorInputMapper::getAssociatedDisplayId() { if (mParameters.hasAssociatedDisplay) { if (mParameters.mode == Parameters::MODE_POINTER) { diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index 94ab30674d..f65ac3934a 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -66,8 +66,6 @@ public: virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override; - virtual void fadePointer() override; - virtual std::optional getAssociatedDisplayId() override; private: @@ -117,7 +115,6 @@ private: void dumpParameters(std::string& dump); void sync(nsecs_t when); - void updatePointerControllerDisplayViewport(const InputReaderConfiguration& config); }; } // namespace android diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp index 92af6123cc..a5b98967e7 100644 --- a/services/inputflinger/reader/mapper/InputMapper.cpp +++ b/services/inputflinger/reader/mapper/InputMapper.cpp @@ -71,8 +71,6 @@ void InputMapper::updateMetaState(int32_t keyCode) {} void InputMapper::updateExternalStylusState(const StylusState& state) {} -void InputMapper::fadePointer() {} - status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) { return getDeviceContext().getAbsoluteAxisInfo(axis, axisInfo); } diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h index 09888bfe20..949c7ea34e 100644 --- a/services/inputflinger/reader/mapper/InputMapper.h +++ b/services/inputflinger/reader/mapper/InputMapper.h @@ -71,7 +71,6 @@ public: virtual void updateExternalStylusState(const StylusState& state); - virtual void fadePointer(); virtual std::optional getAssociatedDisplayId() { return std::nullopt; } protected: diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index e832804e16..9cbbf0c376 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -756,16 +756,11 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { mOrientedRanges.clear(); } - // Create or update pointer controller if needed. + // Create pointer controller if needed. if (mDeviceMode == DEVICE_MODE_POINTER || (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) { - if (mPointerController == nullptr || viewportChanged) { - mPointerController = getPolicy()->obtainPointerController(getDeviceId()); - // Set the DisplayViewport for the PointerController to the default pointer display - // that is recommended by the configuration before using it. - std::optional defaultViewport = - mConfig.getDisplayViewportById(mConfig.defaultPointerDisplayId); - mPointerController->setDisplayViewport(defaultViewport.value_or(mViewport)); + if (mPointerController == nullptr) { + mPointerController = getContext()->getPointerController(getDeviceId()); } } else { mPointerController.clear(); @@ -3624,12 +3619,6 @@ bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties return changed; } -void TouchInputMapper::fadePointer() { - if (mPointerController != nullptr) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } -} - void TouchInputMapper::cancelTouch(nsecs_t when) { abortPointerUsage(when, 0 /*policyFlags*/); abortTouches(when, 0 /* policyFlags*/); diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 3a61206481..e21a33abed 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -148,7 +148,6 @@ public: virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) override; - virtual void fadePointer() override; virtual void cancelTouch(nsecs_t when) override; virtual void timeoutExpired(nsecs_t when) override; virtual void updateExternalStylusState(const StylusState& state) override; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 578605fa40..752213a499 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -830,6 +830,7 @@ class FakeInputReaderContext : public InputReaderContext { bool mUpdateGlobalMetaStateWasCalled; int32_t mGeneration; uint32_t mNextSequenceNum; + wp mPointerController; public: FakeInputReaderContext(std::shared_ptr eventHub, @@ -857,6 +858,18 @@ public: return mGeneration; } + void updatePointerDisplay() { + sp controller = mPointerController.promote(); + if (controller != nullptr) { + InputReaderConfiguration config; + mPolicy->getReaderConfiguration(&config); + auto viewport = config.getDisplayViewportById(config.defaultPointerDisplayId); + if (viewport) { + controller->setDisplayViewport(*viewport); + } + } + } + private: virtual void updateGlobalMetaState() { mUpdateGlobalMetaStateWasCalled = true; @@ -883,6 +896,16 @@ private: virtual bool shouldDropVirtualKey(nsecs_t, int32_t, int32_t) { return false; } + virtual sp getPointerController(int32_t deviceId) { + sp controller = mPointerController.promote(); + if (controller == nullptr) { + controller = mPolicy->obtainPointerController(deviceId); + mPointerController = controller; + updatePointerDisplay(); + } + return controller; + } + virtual void fadePointer() { } @@ -1965,6 +1988,9 @@ protected: } void configureDevice(uint32_t changes) { + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + mFakeContext->updatePointerDisplay(); + } mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes); } -- GitLab From 3be1c493d03ca1b091b191da83777a5e16e909c8 Mon Sep 17 00:00:00 2001 From: Howard Ro Date: Thu, 20 Feb 2020 04:19:41 +0000 Subject: [PATCH 0834/1255] Revert "Update statsd binary path for apex" Revert submission 10356003-statsd_apex Reason for revert: https://android-build.googleplex.com/builds/quarterdeck?branch=git_master&target=build_test&lkgb=6221366&fkbb=6221428 Reverted Changes: Ic84e77269:Update init.rc for statsd setup I6f3fab4b4:Update statsd binary path for apex Ib4ea98aed:Migrate Statsd to the apex Change-Id: If6ce6de80710be4c4e02f2875cac17303fefbd16 --- libs/dumputils/dump_utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp index 1b42b6927f..90fded0e85 100644 --- a/libs/dumputils/dump_utils.cpp +++ b/libs/dumputils/dump_utils.cpp @@ -35,7 +35,7 @@ static const char* native_processes_to_dump[] = { "/system/bin/mediaserver", "/system/bin/netd", "/system/bin/sdcard", - "/apex/com.android.os.statsd/bin/statsd", + "/system/bin/statsd", "/system/bin/surfaceflinger", "/system/bin/vehicle_network_service", "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec -- GitLab From 6a446a247edf6b909e103754e18d6e35166993fa Mon Sep 17 00:00:00 2001 From: Howard Ro Date: Thu, 20 Feb 2020 04:57:00 +0000 Subject: [PATCH 0835/1255] Revert^2 "Update statsd binary path for apex" 3be1c493d03ca1b091b191da83777a5e16e909c8 Change-Id: If487f503cc5f0d04d9ea0b9a37fa8d17c997cf48 --- libs/dumputils/dump_utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp index 90fded0e85..1b42b6927f 100644 --- a/libs/dumputils/dump_utils.cpp +++ b/libs/dumputils/dump_utils.cpp @@ -35,7 +35,7 @@ static const char* native_processes_to_dump[] = { "/system/bin/mediaserver", "/system/bin/netd", "/system/bin/sdcard", - "/system/bin/statsd", + "/apex/com.android.os.statsd/bin/statsd", "/system/bin/surfaceflinger", "/system/bin/vehicle_network_service", "/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec -- GitLab From b83097dd02257962bb94ffcf323671e476c3560c Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Tue, 18 Feb 2020 19:49:27 -0800 Subject: [PATCH 0836/1255] Enable effect layers with blur Change-Id: Ia13f0b6d816aa918433297567735482dc5b3502e Test: launch apps Bug: 149792636 Fixes: 148804546 --- services/surfaceflinger/EffectLayer.cpp | 6 ++++++ services/surfaceflinger/EffectLayer.h | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp index 9d45e333d8..44d4d756e0 100644 --- a/services/surfaceflinger/EffectLayer.cpp +++ b/services/surfaceflinger/EffectLayer.cpp @@ -69,6 +69,8 @@ std::vector EffectLayer::prepareClien // Set color for color fill settings. layerSettings->source.solidColor = getColor().rgb; results.push_back(*layerSettings); + } else if (hasBlur()) { + results.push_back(*layerSettings); } return results; @@ -148,6 +150,10 @@ bool EffectLayer::fillsColor() const { mDrawingState.color.b >= 0.0_hf; } +bool EffectLayer::hasBlur() const { + return getBackgroundBlurRadius() > 0; +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/EffectLayer.h b/services/surfaceflinger/EffectLayer.h index 33758b6378..1dcb633251 100644 --- a/services/surfaceflinger/EffectLayer.h +++ b/services/surfaceflinger/EffectLayer.h @@ -62,7 +62,9 @@ protected: private: // Returns true if there is a valid color to fill. bool fillsColor() const; - bool hasSomethingToDraw() const { return fillsColor() || drawShadows(); } + // Returns true if this layer has a blur value. + bool hasBlur() const; + bool hasSomethingToDraw() const { return fillsColor() || drawShadows() || hasBlur(); } }; } // namespace android -- GitLab From 9244aeaf7ba06fbbcdddfda20abe3b6d89004cb8 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Wed, 5 Feb 2020 20:31:40 -0800 Subject: [PATCH 0837/1255] Use cc_defaults in inputflinger targets We add a cc_defaults for all of the targets in inputflinger, and include those defaults in inputflinger_tests. This makes it so that building the test compiles all of the sources in the test target and includes them in the executable. The primary benefit of this refactor is that running the test on any device will now test the inputflinger code that the test was compiled with instead of testing the libraries that were on the device. Also, the device does not need to be re-flashed or need its libraries to be updated when running the tests after modifying inputflinger code. Bug: None Test: atest inputflinger_tests Change-Id: Ic0406355e5b485c8bf29a65f7c7c37ea8cb68eab --- services/inputflinger/Android.bp | 72 ++++++++++++------- services/inputflinger/dispatcher/Android.bp | 41 +++++++++-- services/inputflinger/reader/Android.bp | 31 +++++--- .../reader/mapper/CursorInputMapper.cpp | 2 +- .../mapper/ExternalStylusInputMapper.cpp | 2 +- .../reader/mapper/InputMapper.cpp | 2 +- .../reader/mapper/JoystickInputMapper.cpp | 2 +- .../reader/mapper/KeyboardInputMapper.cpp | 2 +- .../reader/mapper/MultiTouchInputMapper.cpp | 2 +- .../mapper/RotaryEncoderInputMapper.cpp | 2 +- .../reader/mapper/SwitchInputMapper.cpp | 2 +- .../reader/mapper/TouchInputMapper.cpp | 2 +- .../reader/mapper/VibratorInputMapper.cpp | 2 +- services/inputflinger/reporter/Android.bp | 24 ++++--- services/inputflinger/tests/Android.bp | 52 +++++++------- .../inputflinger/tests/InputReader_test.cpp | 2 +- 16 files changed, 154 insertions(+), 88 deletions(-) diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 5c80d551b8..439d9bf312 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Default flags to be used throughout all libraries in inputflinger. cc_defaults { name: "inputflinger_defaults", cflags: [ @@ -23,22 +24,25 @@ cc_defaults { ], } -cc_library_shared { - name: "libinputflinger", - defaults: ["inputflinger_defaults"], +///////////////////////////////////////////////// +// libinputflinger +///////////////////////////////////////////////// +filegroup { + name: "libinputflinger_sources", srcs: [ "InputClassifier.cpp", "InputClassifierConverter.cpp", "InputManager.cpp", ], +} +cc_defaults { + name: "libinputflinger_defaults", + srcs: [":libinputflinger_sources"], shared_libs: [ "android.hardware.input.classifier@1.0", "libbase", - "libinputflinger_base", - "libinputreporter", - "libinputreader", "libbinder", "libcrypto", "libcutils", @@ -50,60 +54,76 @@ cc_library_shared { "libui", "server_configurable_flags", ], +} - static_libs: [ - "libinputdispatcher", +cc_library_shared { + name: "libinputflinger", + defaults: [ + "inputflinger_defaults", + "libinputflinger_defaults", ], - cflags: [ // TODO(b/23084678): Move inputflinger to its own process and mark it hidden //-fvisibility=hidden ], - - export_include_dirs: [ - ".", - "include", + shared_libs: [ + // This should consist only of dependencies from inputflinger. Other dependencies should be + // in cc_defaults so that they are included in the tests. + "libinputflinger_base", + "libinputreporter", + "libinputreader", + ], + static_libs: [ + "libinputdispatcher", ], - export_static_lib_headers: [ "libinputdispatcher", ], + export_include_dirs: [ + ".", + "include", + ], } +///////////////////////////////////////////////// +// libinputflinger_base +///////////////////////////////////////////////// + cc_library_headers { name: "libinputflinger_headers", - header_libs: ["libinputreporter_headers"], export_include_dirs: ["include"], - export_header_lib_headers: ["libinputreporter_headers"], } -cc_library_shared { - name: "libinputflinger_base", - defaults: ["inputflinger_defaults"], - +filegroup { + name: "libinputflinger_base_sources", srcs: [ "InputListener.cpp", "InputReaderBase.cpp", "InputThread.cpp", ], +} +cc_defaults { + name: "libinputflinger_base_defaults", + srcs: [":libinputflinger_base_sources"], shared_libs: [ "libbase", "libinput", "liblog", "libutils", ], - header_libs: [ "libinputflinger_headers", ], +} +cc_library_shared { + name: "libinputflinger_base", + defaults: [ + "inputflinger_defaults", + "libinputflinger_base_defaults", + ], export_header_lib_headers: [ "libinputflinger_headers", ], } - -subdirs = [ - "host", - "tests", -] diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp index 3f956a88fb..a98f4b42d0 100644 --- a/services/inputflinger/dispatcher/Android.bp +++ b/services/inputflinger/dispatcher/Android.bp @@ -12,9 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -cc_library_static { - name: "libinputdispatcher", - defaults: ["inputflinger_defaults"], +cc_library_headers { + name: "libinputdispatcher_headers", + export_include_dirs: [ + "include", + ], +} + +filegroup { + name: "libinputdispatcher_sources", srcs: [ "Connection.cpp", "Entry.cpp", @@ -24,20 +30,41 @@ cc_library_static { "InputState.cpp", "InputTarget.cpp", "Monitor.cpp", - "TouchState.cpp" + "TouchState.cpp", ], +} + +cc_defaults { + name: "libinputdispatcher_defaults", + srcs: [":libinputdispatcher_sources"], shared_libs: [ "libbase", "libcrypto", "libcutils", "libinput", - "libinputreporter", - "libinputflinger_base", "liblog", "libstatslog", "libui", "libutils", ], + header_libs: [ + "libinputdispatcher_headers", + ], +} - export_include_dirs: ["include"], +cc_library_static { + name: "libinputdispatcher", + defaults: [ + "inputflinger_defaults", + "libinputdispatcher_defaults", + ], + shared_libs: [ + // This should consist only of dependencies from inputflinger. Other dependencies should be + // in cc_defaults so that they are included in the tests. + "libinputreporter", + "libinputflinger_base", + ], + export_header_lib_headers: [ + "libinputdispatcher_headers", + ], } diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index 23c08b25f3..83a610f768 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -21,10 +21,8 @@ cc_library_headers { ], } -cc_library_shared { - name: "libinputreader", - defaults: ["inputflinger_defaults"], - +filegroup { + name: "libinputreader_sources", srcs: [ "EventHub.cpp", "InputDevice.cpp", @@ -44,14 +42,16 @@ cc_library_shared { "mapper/TouchInputMapper.cpp", "mapper/VibratorInputMapper.cpp", "InputReader.cpp", - "InputReaderFactory.cpp", "TouchVideoDevice.cpp", ], +} +cc_defaults { + name: "libinputreader_defaults", + srcs: [":libinputreader_sources"], shared_libs: [ "libbase", "libcap", - "libinputflinger_base", "libcrypto", "libcutils", "libinput", @@ -59,13 +59,26 @@ cc_library_shared { "libui", "libutils", ], - header_libs: [ - "libinputflinger_headers", "libinputreader_headers", ], +} +cc_library_shared { + name: "libinputreader", + defaults: [ + "inputflinger_defaults", + "libinputreader_defaults" + ], + srcs: [ + "InputReaderFactory.cpp", + ], + shared_libs: [ + // This should consist only of dependencies from inputflinger. Other dependencies should be + // in cc_defaults so that they are included in the tests. + "libinputflinger_base", + ], export_header_lib_headers: [ - "libinputflinger_headers", + "libinputreader_headers", ], } diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 78f33823d0..520a4a4f52 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Macros.h" +#include "../Macros.h" #include "CursorInputMapper.h" diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp index 37e4047890..37d1d7499c 100644 --- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp +++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Macros.h" +#include "../Macros.h" #include "ExternalStylusInputMapper.h" diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp index 92af6123cc..c5f99c9b63 100644 --- a/services/inputflinger/reader/mapper/InputMapper.cpp +++ b/services/inputflinger/reader/mapper/InputMapper.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Macros.h" +#include "../Macros.h" #include "InputMapper.h" diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp index 57c85b6280..7c3b1d9b40 100644 --- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp +++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Macros.h" +#include "../Macros.h" #include "JoystickInputMapper.h" diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp index 9ab707fb60..ab354a2e2b 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Macros.h" +#include "../Macros.h" #include "KeyboardInputMapper.h" diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp index d195a07eff..d77c8c8609 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Macros.h" +#include "../Macros.h" #include "MultiTouchInputMapper.h" diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp index a1cce5695b..ed93f14cea 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Macros.h" +#include "../Macros.h" #include "RotaryEncoderInputMapper.h" diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp index 52b24498ac..e79aeb28c4 100644 --- a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Macros.h" +#include "../Macros.h" #include "SwitchInputMapper.h" diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index e832804e16..b3a6df8f15 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Macros.h" +#include "../Macros.h" #include "TouchInputMapper.h" diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp index 1b584ea7b9..7665680feb 100644 --- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Macros.h" +#include "../Macros.h" #include "VibratorInputMapper.h" diff --git a/services/inputflinger/reporter/Android.bp b/services/inputflinger/reporter/Android.bp index 5956fb0794..fbc51dadc0 100644 --- a/services/inputflinger/reporter/Android.bp +++ b/services/inputflinger/reporter/Android.bp @@ -17,25 +17,33 @@ cc_library_headers { export_include_dirs: ["."], } -cc_library_shared { - name: "libinputreporter", - defaults: ["inputflinger_defaults"], - +filegroup { + name: "libinputreporter_sources", srcs: [ - "InputReporter.cpp", + "InputReporter.cpp", ], +} +cc_defaults { + name: "libinputreporter_defaults", + srcs: [":libinputreporter_sources"], shared_libs: [ "liblog", "libutils", ], - header_libs: [ - "libinputflinger_headers", + "libinputreporter_headers", ], +} +cc_library_shared { + name: "libinputreporter", + defaults: [ + "inputflinger_defaults", + "libinputreporter_defaults", + ], export_header_lib_headers: [ - "libinputflinger_headers", + "libinputreporter_headers", ], } diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index f913d826bc..73d22727f0 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -1,7 +1,31 @@ -// Build the unit tests. +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. cc_test { name: "inputflinger_tests", + defaults: [ + "inputflinger_defaults", + // For all targets inside inputflinger, these tests build all of their sources using their + // defaults rather than including them as shared or static libraries. By doing so, the tests + // will always run against the compiled version of the inputflinger code rather than the + // version on the device. + "libinputflinger_base_defaults", + "libinputreader_defaults", + "libinputreporter_defaults", + "libinputdispatcher_defaults", + "libinputflinger_defaults", + ], srcs: [ "BlockingQueue_test.cpp", "EventHub_test.cpp", @@ -12,31 +36,5 @@ cc_test { "InputReader_test.cpp", "UinputDevice.cpp", ], - cflags: [ - "-Wall", - "-Werror", - "-Wextra", - "-Wno-unused-parameter", - "-Wthread-safety", - ], - shared_libs: [ - "android.hardware.input.classifier@1.0", - "libbase", - "libbinder", - "libcutils", - "liblog", - "libutils", - "libhardware", - "libhardware_legacy", - "libui", - "libinput", - "libinputflinger", - "libinputreader", - "libinputflinger_base", - "libinputservice", - ], - header_libs: [ - "libinputreader_headers", - ], require_root: true, } diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index f9ebfc07b2..af11256892 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1714,7 +1714,7 @@ protected: mFakePolicy = new FakeInputReaderPolicy(); mTestListener = new TestInputListener(); - mReader = createInputReader(mFakePolicy, mTestListener); + mReader = new InputReader(std::make_shared(), mFakePolicy, mTestListener); ASSERT_EQ(mReader->start(), OK); // Since this test is run on a real device, all the input devices connected -- GitLab From 2dd6f393e4a92208c5bddd994fa4c719d86690ea Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Tue, 18 Feb 2020 17:43:36 -0800 Subject: [PATCH 0838/1255] Enable per-device GPU clock configuration Some devices have larger screen, or less powerful GPUs. On them, we should allow a higher GPU clock whenever rendering blurs. Test: ./libcompositionengine_test --gtest_filter=Output* Bug: 149792636 Change-Id: Ic08ba9edc060a721b49cbbd448d7ad9d310aadb7 --- .../CompositionRefreshArgs.h | 3 + .../include/compositionengine/Output.h | 3 +- .../include/compositionengine/impl/Output.h | 3 +- .../include/compositionengine/mock/Output.h | 5 +- .../CompositionEngine/src/Output.cpp | 13 ++-- .../CompositionEngine/tests/OutputTest.cpp | 73 +++++++++++++++---- services/surfaceflinger/SurfaceFlinger.cpp | 5 +- services/surfaceflinger/SurfaceFlinger.h | 3 + 8 files changed, 84 insertions(+), 24 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index 4a0d6ee140..d3712d9a5e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -57,6 +57,9 @@ struct CompositionRefreshArgs { // Forces a color mode on the outputs being refreshed ui::ColorMode forceOutputColorMode{ui::ColorMode::NATIVE}; + // If true, GPU clocks will be increased when rendering blurs + bool blursAreExpensive{false}; + // If true, the complete output geometry needs to be recomputed this frame bool updatingOutputGeometryThisFrame{false}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 9622e7818b..a5711a3806 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -265,7 +265,8 @@ protected: virtual void prepareFrame() = 0; virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0; virtual void finishFrame(const CompositionRefreshArgs&) = 0; - virtual std::optional composeSurfaces(const Region&) = 0; + virtual std::optional composeSurfaces( + const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) = 0; virtual void postFramebuffer() = 0; virtual void chooseCompositionStrategy() = 0; virtual bool getSkipColorTransform() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index d41337c824..6f25e6391b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -83,7 +83,8 @@ public: void prepareFrame() override; void devOptRepaintFlash(const CompositionRefreshArgs&) override; void finishFrame(const CompositionRefreshArgs&) override; - std::optional composeSurfaces(const Region&) override; + std::optional composeSurfaces( + const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) override; void postFramebuffer() override; void cacheClientCompositionRequests(uint32_t) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 346c2d1764..4661c5d616 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -98,7 +98,10 @@ public: MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&)); - MOCK_METHOD1(composeSurfaces, std::optional(const Region&)); + MOCK_METHOD2(composeSurfaces, + std::optional( + const Region&, + const compositionengine::CompositionRefreshArgs& refreshArgs)); MOCK_CONST_METHOD0(getSkipColorTransform, bool()); MOCK_METHOD0(postFramebuffer, void()); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index e792f45bb7..248933e8f0 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -774,7 +774,7 @@ void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& if (!dirtyRegion.isEmpty()) { base::unique_fd readyFence; // redraw the whole screen - static_cast(composeSurfaces(dirtyRegion)); + static_cast(composeSurfaces(dirtyRegion, refreshArgs)); mRenderSurface->queueBuffer(std::move(readyFence)); } @@ -787,7 +787,7 @@ void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& prepareFrame(); } -void Output::finishFrame(const compositionengine::CompositionRefreshArgs&) { +void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) { ATRACE_CALL(); ALOGV(__FUNCTION__); @@ -797,7 +797,7 @@ void Output::finishFrame(const compositionengine::CompositionRefreshArgs&) { // Repaint the framebuffer (if needed), getting the optional fence for when // the composition completes. - auto optReadyFence = composeSurfaces(Region::INVALID_REGION); + auto optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs); if (!optReadyFence) { return; } @@ -806,7 +806,8 @@ void Output::finishFrame(const compositionengine::CompositionRefreshArgs&) { mRenderSurface->queueBuffer(std::move(*optReadyFence)); } -std::optional Output::composeSurfaces(const Region& debugRegion) { +std::optional Output::composeSurfaces( + const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs) { ATRACE_CALL(); ALOGV(__FUNCTION__); @@ -894,8 +895,10 @@ std::optional Output::composeSurfaces(const Region& debugRegion // or complex GPU shaders and it's expensive. We boost the GPU frequency so that // GPU composition can finish in time. We must reset GPU frequency afterwards, // because high frequency consumes extra battery. + const bool expensiveBlurs = + refreshArgs.blursAreExpensive && mLayerRequestingBackgroundBlur != nullptr; const bool expensiveRenderingExpected = - clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3; + clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3 || expensiveBlurs; if (expensiveRenderingExpected) { setExpensiveRenderingExpected(true); } diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index be0e9e4bc8..63bb459dbe 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -2463,7 +2463,9 @@ struct OutputDevOptRepaintFlashTest : public testing::Test { // Sets up the helper functions called by the function under test to use // mock implementations. MOCK_CONST_METHOD1(getDirtyRegion, Region(bool)); - MOCK_METHOD1(composeSurfaces, std::optional(const Region&)); + MOCK_METHOD2(composeSurfaces, + std::optional( + const Region&, const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD0(postFramebuffer, void()); MOCK_METHOD0(prepareFrame, void()); }; @@ -2526,7 +2528,7 @@ TEST_F(OutputDevOptRepaintFlashTest, alsoComposesSurfacesAndQueuesABufferIfDirty InSequence seq; EXPECT_CALL(mOutput, getDirtyRegion(false)).WillOnce(Return(kNotEmptyRegion)); - EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion))); + EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs))); EXPECT_CALL(*mRenderSurface, queueBuffer(_)); EXPECT_CALL(mOutput, postFramebuffer()); EXPECT_CALL(mOutput, prepareFrame()); @@ -2542,7 +2544,9 @@ struct OutputFinishFrameTest : public testing::Test { struct OutputPartialMock : public OutputPartialMockBase { // Sets up the helper functions called by the function under test to use // mock implementations. - MOCK_METHOD1(composeSurfaces, std::optional(const Region&)); + MOCK_METHOD2(composeSurfaces, + std::optional( + const Region&, const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD0(postFramebuffer, void()); }; @@ -2568,7 +2572,7 @@ TEST_F(OutputFinishFrameTest, takesEarlyOutifComposeSurfacesReturnsNoFence) { mOutput.mState.isEnabled = true; InSequence seq; - EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION))); + EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _)); mOutput.finishFrame(mRefreshArgs); } @@ -2577,7 +2581,7 @@ TEST_F(OutputFinishFrameTest, queuesBufferIfComposeSurfacesReturnsAFence) { mOutput.mState.isEnabled = true; InSequence seq; - EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION))) + EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _)) .WillOnce(Return(ByMove(base::unique_fd()))); EXPECT_CALL(*mRenderSurface, queueBuffer(_)); @@ -2804,7 +2808,8 @@ struct OutputComposeSurfacesTest : public testing::Test { struct ExecuteState : public CallOrderStateMachineHelper { auto execute() { - getInstance()->mReadyFence = getInstance()->mOutput.composeSurfaces(kDebugRegion); + getInstance()->mReadyFence = + getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); return nextState(); } }; @@ -2832,6 +2837,7 @@ struct OutputComposeSurfacesTest : public testing::Test { static const mat4 kDefaultColorTransformMat; static const Region kDebugRegion; + static const compositionengine::CompositionRefreshArgs kDefaultRefreshArgs; static const HdrCapabilities kHdrCapabilities; StrictMock mCompositionEngine; @@ -2851,6 +2857,7 @@ const Rect OutputComposeSurfacesTest::kDefaultOutputViewport{1005, 1006, 1007, 1 const Rect OutputComposeSurfacesTest::kDefaultOutputSourceClip{1009, 1010, 1011, 1012}; const Rect OutputComposeSurfacesTest::kDefaultOutputDestinationClip{1013, 1014, 1015, 1016}; const mat4 OutputComposeSurfacesTest::kDefaultColorTransformMat{mat4() * 0.5f}; +const compositionengine::CompositionRefreshArgs OutputComposeSurfacesTest::kDefaultRefreshArgs; const Region OutputComposeSurfacesTest::kDebugRegion{Rect{100, 101, 102, 103}}; const HdrCapabilities OutputComposeSurfacesTest:: kHdrCapabilities{{}, @@ -3193,7 +3200,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifDisplayIsNotSecure) mLayer2.mLayerFEState.hasProtectedContent = true; EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true)); - mOutput.composeSurfaces(kDebugRegion); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifRenderEngineDoesNotSupportIt) { @@ -3201,7 +3208,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifRenderEngineDoesNotS mLayer2.mLayerFEState.hasProtectedContent = true; EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false)); - mOutput.composeSurfaces(kDebugRegion); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLayers) { @@ -3213,7 +3220,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLa EXPECT_CALL(mRenderEngine, useProtectedContext(false)); EXPECT_CALL(*mRenderSurface, setProtected(false)); - mOutput.composeSurfaces(kDebugRegion); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) { @@ -3233,7 +3240,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) { EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, true, _, _)).WillOnce(Return(NO_ERROR)); - mOutput.composeSurfaces(kDebugRegion); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEverywhere) { @@ -3243,7 +3250,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEveryw EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true)); EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); - mOutput.composeSurfaces(kDebugRegion); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifFailsToEnableInRenderEngine) { @@ -3254,7 +3261,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifFailsToEnableInRende EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false)); EXPECT_CALL(mRenderEngine, useProtectedContext(true)); - mOutput.composeSurfaces(kDebugRegion); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderEngine) { @@ -3265,7 +3272,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRend EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false)); EXPECT_CALL(*mRenderSurface, setProtected(true)); - mOutput.composeSurfaces(kDebugRegion); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderSurface) { @@ -3276,7 +3283,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRend EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); EXPECT_CALL(mRenderEngine, useProtectedContext(true)); - mOutput.composeSurfaces(kDebugRegion); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } struct OutputComposeSurfacesTest_SetsExpensiveRendering : public OutputComposeSurfacesTest { @@ -3302,7 +3309,43 @@ TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering, IfExepensiveOutputDatas EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, true, _, _)).WillOnce(Return(NO_ERROR)); - mOutput.composeSurfaces(kDebugRegion); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); +} + +struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur + : public OutputComposeSurfacesTest_SetsExpensiveRendering { + OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur() { + mLayer.layerFEState.backgroundBlurRadius = 10; + mOutput.editState().isEnabled = true; + + EXPECT_CALL(mLayer.outputLayer, updateCompositionState(false, true)); + EXPECT_CALL(mLayer.outputLayer, writeStateToHWC(false)); + EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace)) + .WillOnce(Return(std::vector{})); + EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, true, _, _)).WillOnce(Return(NO_ERROR)); + EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u)); + EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u)) + .WillRepeatedly(Return(&mLayer.outputLayer)); + } + + NonInjectedLayer mLayer; + compositionengine::CompositionRefreshArgs mRefreshArgs; +}; + +TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreExpensive) { + mRefreshArgs.blursAreExpensive = true; + mOutput.updateAndWriteCompositionState(mRefreshArgs); + + EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)); + mOutput.composeSurfaces(kDebugRegion, mRefreshArgs); +} + +TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreNotExpensive) { + mRefreshArgs.blursAreExpensive = false; + mOutput.updateAndWriteCompositionState(mRefreshArgs); + + EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)).Times(0); + mOutput.composeSurfaces(kDebugRegion, mRefreshArgs); } /* diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a98ff4fe7c..78c9ab18f1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -360,11 +360,13 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("ro.surface_flinger.supports_background_blur", value, "0"); bool supportsBlurs = atoi(value); - property_get("debug.sf.disableBlurs", value, "0"); + property_get("debug.sf.disable_blurs", value, "0"); bool disableBlurs = atoi(value); mEnableBlurs = supportsBlurs && !disableBlurs; ALOGI_IF(!mEnableBlurs, "Disabling blur effects. supported: %d, disabled: %d", supportsBlurs, disableBlurs); + property_get("ro.sf.blurs_are_expensive", value, "0"); + mBlursAreExpensive = atoi(value); const size_t defaultListSize = MAX_LAYERS; auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize)); @@ -1896,6 +1898,7 @@ void SurfaceFlinger::handleMessageRefresh() { refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty; refreshArgs.updatingGeometryThisFrame = mGeometryInvalid || mVisibleRegionsDirty; + refreshArgs.blursAreExpensive = mBlursAreExpensive; if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) { refreshArgs.colorTransformMatrix = mDrawingState.colorMatrix; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 0144b4ee6d..cdf1c89073 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1039,7 +1039,10 @@ private: const std::shared_ptr mTimeStats; const std::unique_ptr mFrameTracer; bool mUseHwcVirtualDisplays = false; + // Disable blurs, for debugging bool mEnableBlurs = false; + // If blurs are considered expensive and should require high GPU frequency. + bool mBlursAreExpensive = false; std::atomic mFrameMissedCount = 0; std::atomic mHwcFrameMissedCount = 0; std::atomic mGpuFrameMissedCount = 0; -- GitLab From 030fbc11b063068a8cb6e0e1a361d6c79fd61c9b Mon Sep 17 00:00:00 2001 From: Dan Stoza Date: Wed, 19 Feb 2020 15:32:01 -0800 Subject: [PATCH 0839/1255] sf: Update PowerAdvisor to talk to AIDL Power HAL Updates the PowerAdvisor to talk to the AIDL Power HAL, and hooks up the new DISPLAY_UPDATE_IMMINENT Boost present in that HAL. Test: libsurfaceflinger_unittest Test: libcompositionengine_test Test: Manual with ALOGV Bug: 132390048 Bug: 146453294 Change-Id: I3cb3e8d04303373de24b6dc150ce724aac89407c --- services/surfaceflinger/Android.bp | 1 + .../tests/MockPowerAdvisor.h | 1 + .../DisplayHardware/PowerAdvisor.cpp | 215 +++++++++++++++--- .../DisplayHardware/PowerAdvisor.h | 26 ++- services/surfaceflinger/SurfaceFlinger.cpp | 3 + .../SurfaceFlingerProperties.cpp | 8 + .../surfaceflinger/SurfaceFlingerProperties.h | 2 + .../sysprop/SurfaceFlingerProperties.sysprop | 12 + .../api/SurfaceFlingerProperties-current.txt | 5 + .../mock/DisplayHardware/MockPowerAdvisor.h | 1 + 10 files changed, 236 insertions(+), 38 deletions(-) diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 4ffdf9761e..08d7d3f0cb 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -33,6 +33,7 @@ cc_defaults { "android.hardware.graphics.composer@2.4", "android.hardware.power@1.0", "android.hardware.power@1.3", + "android.hardware.power-cpp", "libbase", "libbinder", "libbufferhubqueue", diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h index c5a73f22f9..e740b13203 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h @@ -30,6 +30,7 @@ public: ~PowerAdvisor() override; MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected)); + MOCK_METHOD0(notifyDisplayUpdateImminent, void()); }; } // namespace mock diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index 039db73928..550ec6173a 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -14,14 +14,23 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 + #undef LOG_TAG #define LOG_TAG "PowerAdvisor" #include +#include #include #include +#include +#include +#include + +#include "../SurfaceFlingerProperties.h" + #include "PowerAdvisor.h" namespace android { @@ -32,11 +41,36 @@ PowerAdvisor::~PowerAdvisor() = default; namespace impl { namespace V1_0 = android::hardware::power::V1_0; +namespace V1_3 = android::hardware::power::V1_3; using V1_3::PowerHint; +using android::hardware::power::Boost; +using android::hardware::power::IPower; +using android::hardware::power::Mode; +using base::GetIntProperty; +using scheduler::OneShotTimer; + PowerAdvisor::~PowerAdvisor() = default; -PowerAdvisor::PowerAdvisor() = default; +namespace { +int32_t getUpdateTimeout() { + // Default to a timeout of 80ms if nothing else is specified + static int32_t timeout = sysprop::display_update_imminent_timeout_ms(80); + return timeout; +} + +} // namespace + +PowerAdvisor::PowerAdvisor() + : mUseUpdateImminentTimer(getUpdateTimeout() > 0), + mUpdateImminentTimer( + OneShotTimer::Interval(getUpdateTimeout()), + /* resetCallback */ [this] { mSendUpdateImminent.store(false); }, + /* timeoutCallback */ [this] { mSendUpdateImminent.store(true); }) { + if (mUseUpdateImminentTimer) { + mUpdateImminentTimer.start(); + } +} void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) { if (expected) { @@ -47,51 +81,170 @@ void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expec const bool expectsExpensiveRendering = !mExpensiveDisplays.empty(); if (mNotifiedExpensiveRendering != expectsExpensiveRendering) { - const sp powerHal = getPowerHal(); - if (powerHal == nullptr) { + HalWrapper* const halWrapper = getPowerHal(); + if (halWrapper == nullptr) { return; } - auto ret = powerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, - expectsExpensiveRendering); - // If Power HAL 1.3 was available previously but now fails, - // it may restart, so attempt to reconnect next time - if (!ret.isOk()) { + + if (!halWrapper->setExpensiveRendering(expectsExpensiveRendering)) { + // The HAL has become unavailable; attempt to reconnect later mReconnectPowerHal = true; return; } + mNotifiedExpensiveRendering = expectsExpensiveRendering; } } -sp PowerAdvisor::getPowerHal() { - static sp sPowerHal_1_3 = nullptr; - static bool sHasPowerHal_1_3 = true; +void PowerAdvisor::notifyDisplayUpdateImminent() { + if (mSendUpdateImminent.load()) { + HalWrapper* const halWrapper = getPowerHal(); + if (halWrapper == nullptr) { + return; + } - if (mReconnectPowerHal) { - sPowerHal_1_3 = nullptr; - mReconnectPowerHal = false; + if (!halWrapper->notifyDisplayUpdateImminent()) { + // The HAL has become unavailable; attempt to reconnect later + mReconnectPowerHal = true; + return; + } + } + + if (mUseUpdateImminentTimer) { + mUpdateImminentTimer.reset(); } +} - // Power HAL 1.3 is not guaranteed to be available, thus we need to query - // Power HAL 1.0 first and try to cast it to Power HAL 1.3. - // Power HAL 1.0 is always available, thus if we fail to query it, it means - // Power HAL is not available temporarily and we should retry later. However, - // if Power HAL 1.0 is available and we can't cast it to Power HAL 1.3, - // it means Power HAL 1.3 is not available at all, so we should stop trying. - if (sHasPowerHal_1_3 && sPowerHal_1_3 == nullptr) { - sp powerHal_1_0 = V1_0::IPower::getService(); - if (powerHal_1_0 != nullptr) { - // Try to cast to Power HAL 1.3 - sPowerHal_1_3 = V1_3::IPower::castFrom(powerHal_1_0); - if (sPowerHal_1_3 == nullptr) { - ALOGW("No Power HAL 1.3 service in system"); - sHasPowerHal_1_3 = false; - } else { - ALOGI("Loaded Power HAL 1.3 service"); +class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper { +public: + HidlPowerHalWrapper(sp powerHal) : mPowerHal(std::move(powerHal)) {} + + ~HidlPowerHalWrapper() override = default; + + static std::unique_ptr connect() { + // Power HAL 1.3 is not guaranteed to be available, thus we need to query + // Power HAL 1.0 first and try to cast it to Power HAL 1.3. + // Power HAL 1.0 is always available, thus if we fail to query it, it means + // Power HAL is not available temporarily and we should retry later. However, + // if Power HAL 1.0 is available and we can't cast it to Power HAL 1.3, + // it means Power HAL 1.3 is not available at all, so we should stop trying. + sp powerHal = nullptr; + if (sHasPowerHal_1_3) { + sp powerHal_1_0 = V1_0::IPower::getService(); + if (powerHal_1_0 != nullptr) { + // Try to cast to Power HAL 1.3 + powerHal = V1_3::IPower::castFrom(powerHal_1_0); + if (powerHal == nullptr) { + ALOGW("No Power HAL 1.3 service in system"); + sHasPowerHal_1_3 = false; + } else { + ALOGI("Loaded Power HAL 1.3 service"); + } } } + if (powerHal == nullptr) { + return nullptr; + } + + return std::make_unique(std::move(powerHal)); + } + + bool setExpensiveRendering(bool enabled) override { + ALOGV("HIDL setExpensiveRendering %s", enabled ? "T" : "F"); + auto ret = mPowerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, enabled); + return ret.isOk(); + } + + bool notifyDisplayUpdateImminent() override { + // Power HAL 1.x doesn't have a notification for this + ALOGV("HIDL notifyUpdateImminent received but can't send"); + return true; } - return sPowerHal_1_3; + +private: + static bool sHasPowerHal_1_3; + const sp mPowerHal = nullptr; +}; + +bool HidlPowerHalWrapper::sHasPowerHal_1_3 = true; + +class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper { +public: + AidlPowerHalWrapper(sp powerHal) : mPowerHal(std::move(powerHal)) { + auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering); + if (!ret.isOk()) { + mHasExpensiveRendering = false; + } + + ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT, + &mHasDisplayUpdateImminent); + if (!ret.isOk()) { + mHasDisplayUpdateImminent = false; + } + } + + ~AidlPowerHalWrapper() override = default; + + static std::unique_ptr connect() { + // This only waits if the service is actually declared + sp powerHal = waitForVintfService(); + if (powerHal == nullptr) { + return nullptr; + } + ALOGI("Loaded AIDL Power HAL service"); + + return std::make_unique(std::move(powerHal)); + } + + bool setExpensiveRendering(bool enabled) override { + ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F"); + if (!mHasExpensiveRendering) { + ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it"); + return true; + } + + auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled); + return ret.isOk(); + } + + bool notifyDisplayUpdateImminent() override { + ALOGV("AIDL notifyDisplayUpdateImminent"); + if (!mHasDisplayUpdateImminent) { + ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it"); + return true; + } + + auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0); + return ret.isOk(); + } + +private: + const sp mPowerHal = nullptr; + bool mHasExpensiveRendering = false; + bool mHasDisplayUpdateImminent = false; +}; + +PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { + static std::unique_ptr sHalWrapper = nullptr; + + if (mReconnectPowerHal) { + sHalWrapper = nullptr; + mReconnectPowerHal = false; + } + + if (sHalWrapper != nullptr) { + return sHalWrapper.get(); + } + + // First attempt to connect to the AIDL Power HAL + sHalWrapper = AidlPowerHalWrapper::connect(); + + // If that didn't succeed, attempt to connect to the HIDL Power HAL + if (sHalWrapper == nullptr) { + sHalWrapper = HidlPowerHalWrapper::connect(); + } + + return sHalWrapper.get(); } } // namespace impl diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h index 5aa1f22b9e..957d28989b 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h @@ -22,11 +22,10 @@ #undef HWC2_INCLUDE_STRINGIFICATION #undef HWC2_USE_CPP11 +#include #include -#include -#include - +#include "../Scheduler/OneShotTimer.h" #include "DisplayIdentification.h" namespace android { @@ -37,27 +36,40 @@ public: virtual ~PowerAdvisor(); virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0; + virtual void notifyDisplayUpdateImminent() = 0; }; namespace impl { -namespace V1_3 = android::hardware::power::V1_3; - // PowerAdvisor is a wrapper around IPower HAL which takes into account the // full state of the system when sending out power hints to things like the GPU. class PowerAdvisor final : public Hwc2::PowerAdvisor { public: + class HalWrapper { + public: + virtual ~HalWrapper() = default; + + virtual bool setExpensiveRendering(bool enabled) = 0; + virtual bool notifyDisplayUpdateImminent() = 0; + }; + PowerAdvisor(); ~PowerAdvisor() override; void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override; + void notifyDisplayUpdateImminent() override; private: - sp getPowerHal(); + HalWrapper* getPowerHal(); + + bool mReconnectPowerHal = false; std::unordered_set mExpensiveDisplays; bool mNotifiedExpensiveRendering = false; - bool mReconnectPowerHal = false; + + const bool mUseUpdateImminentTimer; + std::atomic_bool mSendUpdateImminent = true; + scheduler::OneShotTimer mUpdateImminentTimer; }; } // namespace impl diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index fbebea04b6..2acf084c19 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1491,11 +1491,13 @@ void SurfaceFlinger::waitForEvent() { void SurfaceFlinger::signalTransaction() { mScheduler->resetIdleTimer(); + mPowerAdvisor.notifyDisplayUpdateImminent(); mEventQueue->invalidate(); } void SurfaceFlinger::signalLayerUpdate() { mScheduler->resetIdleTimer(); + mPowerAdvisor.notifyDisplayUpdateImminent(); mEventQueue->invalidate(); } @@ -5097,6 +5099,7 @@ void SurfaceFlinger::repaintEverything() { void SurfaceFlinger::repaintEverythingForHWC() { mRepaintEverything = true; + mPowerAdvisor.notifyDisplayUpdateImminent(); mEventQueue->invalidate(); } diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 1a611f5d7e..f3352a5a24 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -305,6 +305,14 @@ bool use_frame_rate_api(bool defaultValue) { return defaultValue; } +int32_t display_update_imminent_timeout_ms(int32_t defaultValue) { + auto temp = SurfaceFlingerProperties::display_update_imminent_timeout_ms(); + if (temp.has_value()) { + return *temp; + } + return defaultValue; +} + #define DISPLAY_PRIMARY_SIZE 3 constexpr float kSrgbRedX = 0.4123f; diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index 4c6e191e70..12c711abfc 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -89,6 +89,8 @@ bool support_kernel_idle_timer(bool defaultValue); bool use_frame_rate_api(bool defaultValue); +int32_t display_update_imminent_timeout_ms(int32_t defaultValue); + android::ui::DisplayPrimaries getDisplayNativePrimaries(); } // namespace sysprop } // namespace android diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index b19eae62e5..155f71877d 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -403,3 +403,15 @@ prop { access: Readonly prop_name: "ro.surface_flinger.use_frame_rate_api" } + +# Sets the timeout used to rate limit DISPLAY_UPDATE_IMMINENT Power HAL notifications. +# SurfaceFlinger wakeups will trigger this boost whenever they are separated by more than this +# duration (specified in milliseconds). A value of 0 disables the rate limit, and will result in +# Power HAL notifications every time SF wakes up. +prop { + api_name: "display_update_imminent_timeout_ms" + type: Integer + scope: Public + access: Readonly + prop_name: "ro.surface_flinger.display_update_imminent_timeout_ms" +} diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt index c66523a517..e62c127062 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -35,6 +35,11 @@ props { type: DoubleList prop_name: "ro.surface_flinger.display_primary_white" } + prop { + api_name: "display_update_imminent_timeout_ms" + type: Integer + prop_name: "ro.surface_flinger.display_update_imminent_timeout_ms" + } prop { api_name: "enable_protected_contents" prop_name: "ro.surface_flinger.protected_contents" diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h index 7c65f95cb7..fe57c98df8 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h @@ -30,6 +30,7 @@ public: ~PowerAdvisor() override; MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected)); + MOCK_METHOD0(notifyDisplayUpdateImminent, void()); }; } // namespace mock -- GitLab From bd25f1cad839bbe84f1baa0eb1aa3ddd84fcbde5 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Thu, 23 Jan 2020 10:49:05 -0800 Subject: [PATCH 0840/1255] Add event ID generator. Bug: 144889238 Test: atest libinput_test Change-Id: I0fd192b3c5a08326aa6a6598025c7b8cdc64cce4 Merged-In: I0fd192b3c5a08326aa6a6598025c7b8cdc64cce4 (cherry picked from commit 84b087ec591626e8dd7d3d2c877afb74f0de1b09) --- include/input/Input.h | 32 +++++++++++++++++ libs/input/Input.cpp | 29 +++++++++++++++ libs/input/tests/Android.bp | 1 + libs/input/tests/IdGenerator_test.cpp | 52 +++++++++++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 libs/input/tests/IdGenerator_test.cpp diff --git a/include/input/Input.h b/include/input/Input.h index 14a7288d19..b86d761e48 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -265,6 +265,38 @@ enum class MotionClassification : uint8_t { */ const char* motionClassificationToString(MotionClassification classification); +/** + * Generator of unique numbers used to identify input events. + * + * Layout of ID: + * |--------------------------|---------------------------| + * | 2 bits for source | 30 bits for random number | + * |--------------------------|---------------------------| + */ +class IdGenerator { +private: + static constexpr uint32_t SOURCE_SHIFT = 30; + +public: + // Used to divide integer space to ensure no conflict among these sources./ + enum class Source : int32_t { + INPUT_READER = 0x0 << SOURCE_SHIFT, + INPUT_DISPATCHER = 0x1 << SOURCE_SHIFT, + OTHER = 0x3 << SOURCE_SHIFT, // E.g. app injected events + }; + IdGenerator(Source source); + + int32_t nextId() const; + + // Extract source from given id. + static inline Source getSource(int32_t id) { return static_cast(SOURCE_MASK & id); } + +private: + const Source mSource; + + static constexpr int32_t SOURCE_MASK = 0x3 << SOURCE_SHIFT; +}; + /** * Invalid value for cursor position. Used for non-mouse events, tests and injected events. Don't * use it for direct comparison with any other value, because NaN isn't equal to itself according to diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 2a73dc0149..abd031ae26 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -17,7 +17,9 @@ #define LOG_TAG "Input" //#define LOG_NDEBUG 0 +#include #include +#include #include #include @@ -25,6 +27,7 @@ #ifdef __ANDROID__ #include +#include #endif namespace android { @@ -40,6 +43,32 @@ const char* motionClassificationToString(MotionClassification classification) { } } +// --- IdGenerator --- +IdGenerator::IdGenerator(Source source) : mSource(source) {} + +int32_t IdGenerator::nextId() const { + constexpr uint32_t SEQUENCE_NUMBER_MASK = ~SOURCE_MASK; + int32_t id = 0; + +// Avoid building against syscall getrandom(2) on host, which will fail build on Mac. Host doesn't +// use sequence number so just always return mSource. +#ifdef __ANDROID__ + constexpr size_t BUF_LEN = sizeof(id); + size_t totalBytes = 0; + while (totalBytes < BUF_LEN) { + ssize_t bytes = TEMP_FAILURE_RETRY(getrandom(&id, BUF_LEN, GRND_NONBLOCK)); + if (CC_UNLIKELY(bytes < 0)) { + ALOGW("Failed to fill in random number for sequence number: %s.", strerror(errno)); + id = 0; + break; + } + totalBytes += bytes; + } +#endif // __ANDROID__ + + return (id & SEQUENCE_NUMBER_MASK) | static_cast(mSource); +} + // --- InputEvent --- const char* inputEventTypeToString(int32_t type) { diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index fb21d5e3b1..3b57146461 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -2,6 +2,7 @@ cc_test { name: "libinput_tests", srcs: [ + "IdGenerator_test.cpp", "InputChannel_test.cpp", "InputDevice_test.cpp", "InputEvent_test.cpp", diff --git a/libs/input/tests/IdGenerator_test.cpp b/libs/input/tests/IdGenerator_test.cpp new file mode 100644 index 0000000000..f7fc3c0ef2 --- /dev/null +++ b/libs/input/tests/IdGenerator_test.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +namespace android::test { + +class IdGeneratorTest : public testing::TestWithParam { +protected: + void SetUp() override { mGenerator.reset(new IdGenerator(GetParam())); } + + std::unique_ptr mGenerator; +}; + +TEST_P(IdGeneratorTest, GenerateRandomNumber) { + for (int i = 0; i < 500; ++i) { + mGenerator->nextId(); + } +} + +TEST_P(IdGeneratorTest, GenerateRandomNumberWithProperFlag) { + for (int i = 0; i < 500; ++i) { + int32_t id = mGenerator->nextId(); + IdGenerator::Source source = IdGenerator::getSource(id); + EXPECT_EQ(source, GetParam()) + << std::hex << "Generator generated a value with wrong source. Value: 0x" << id + << " Source: 0x" << static_cast(source); + } +} + +INSTANTIATE_TEST_SUITE_P(SourceInstantiation, IdGeneratorTest, + testing::Values(IdGenerator::Source::INPUT_READER, + IdGenerator::Source::INPUT_DISPATCHER, + IdGenerator::Source::OTHER)); +} // namespace android::test -- GitLab From fbe732ebbb25870086610e9a32acdb37df402612 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Fri, 24 Jan 2020 11:26:14 -0800 Subject: [PATCH 0841/1255] Add ID to native events. To separate this big work into pieces I introduced a placeholder in InputTransport used to initialize native input events received from InputFlinger until InputFlinger can generate random sequence numbers. The work in InputDispatcher wires up ID between events and notify args as well. Bug: 144889238 Test: Builds and some smoke tests. Test: atest libinput_tests Change-Id: I1ef7f243cc89a8b6e07ba9ba30a43c21eedb16ce Merged-In: I1ef7f243cc89a8b6e07ba9ba30a43c21eedb16ce (cherry picked from commit 4cc839fe01cd5bbb16650e85913070386f637e75) --- include/input/Input.h | 14 +++- libs/input/Input.cpp | 26 +++++-- libs/input/InputTransport.cpp | 37 +++++---- libs/input/KeyCharacterMap.cpp | 6 +- libs/input/tests/InputEvent_test.cpp | 37 +++++---- libs/input/tests/VelocityTracker_test.cpp | 11 +-- libs/input/tests/VerifiedInputEvent_test.cpp | 11 +-- .../benchmarks/InputDispatcher_benchmarks.cpp | 5 +- .../dispatcher/InputDispatcher.cpp | 55 +++++++------- .../tests/InputDispatcher_test.cpp | 76 ++++++++++--------- 10 files changed, 160 insertions(+), 118 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index b86d761e48..9e47318203 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -397,6 +397,8 @@ public: virtual int32_t getType() const = 0; + inline int32_t getId() const { return mId; } + inline int32_t getDeviceId() const { return mDeviceId; } inline uint32_t getSource() const { return mSource; } @@ -409,11 +411,15 @@ public: inline std::array getHmac() const { return mHmac; } + static int32_t nextId(); + protected: - void initialize(int32_t deviceId, uint32_t source, int32_t displayId, + void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, std::array hmac); + void initialize(const InputEvent& from); + int32_t mId; int32_t mDeviceId; uint32_t mSource; int32_t mDisplayId; @@ -450,7 +456,7 @@ public: static const char* getLabel(int32_t keyCode); static int32_t getKeyCodeFromLabel(const char* label); - void initialize(int32_t deviceId, uint32_t source, int32_t displayId, + void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, std::array hmac, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime); @@ -674,7 +680,7 @@ public: ssize_t findPointerIndex(int32_t pointerId) const; - void initialize(int32_t deviceId, uint32_t source, int32_t displayId, + void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, std::array hmac, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, float xScale, float yScale, float xOffset, @@ -754,7 +760,7 @@ public: inline bool getInTouchMode() const { return mInTouchMode; } - void initialize(bool hasFocus, bool inTouchMode); + void initialize(int32_t id, bool hasFocus, bool inTouchMode); void initialize(const FocusEvent& from); diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index abd031ae26..c2437673df 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -110,8 +110,9 @@ VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event) event.getButtonState()}; } -void InputEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId, +void InputEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, std::array hmac) { + mId = id; mDeviceId = deviceId; mSource = source; mDisplayId = displayId; @@ -119,12 +120,18 @@ void InputEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId } void InputEvent::initialize(const InputEvent& from) { + mId = from.mId; mDeviceId = from.mDeviceId; mSource = from.mSource; mDisplayId = from.mDisplayId; mHmac = from.mHmac; } +int32_t InputEvent::nextId() { + static IdGenerator idGen(IdGenerator::Source::OTHER); + return idGen.nextId(); +} + // --- KeyEvent --- const char* KeyEvent::getLabel(int32_t keyCode) { @@ -135,11 +142,11 @@ int32_t KeyEvent::getKeyCodeFromLabel(const char* label) { return getKeyCodeByLabel(label); } -void KeyEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId, +void KeyEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, std::array hmac, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime) { - InputEvent::initialize(deviceId, source, displayId, hmac); + InputEvent::initialize(id, deviceId, source, displayId, hmac); mAction = action; mFlags = flags; mKeyCode = keyCode; @@ -298,7 +305,7 @@ void PointerProperties::copyFrom(const PointerProperties& other) { // --- MotionEvent --- -void MotionEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId, +void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, std::array hmac, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, float xScale, @@ -307,7 +314,7 @@ void MotionEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayI nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { - InputEvent::initialize(deviceId, source, displayId, hmac); + InputEvent::initialize(id, deviceId, source, displayId, hmac); mAction = action; mActionButton = actionButton; mFlags = flags; @@ -332,7 +339,8 @@ void MotionEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayI } void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { - InputEvent::initialize(other->mDeviceId, other->mSource, other->mDisplayId, other->mHmac); + InputEvent::initialize(other->mId, other->mDeviceId, other->mSource, other->mDisplayId, + other->mHmac); mAction = other->mAction; mActionButton = other->mActionButton; mFlags = other->mFlags; @@ -540,6 +548,7 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { return BAD_VALUE; } + mId = parcel->readInt32(); mDeviceId = parcel->readInt32(); mSource = parcel->readUint32(); mDisplayId = parcel->readInt32(); @@ -601,6 +610,7 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeInt32(pointerCount); parcel->writeInt32(sampleCount); + parcel->writeInt32(mId); parcel->writeInt32(mDeviceId); parcel->writeUint32(mSource); parcel->writeInt32(mDisplayId); @@ -670,8 +680,8 @@ int32_t MotionEvent::getAxisFromLabel(const char* label) { // --- FocusEvent --- -void FocusEvent::initialize(bool hasFocus, bool inTouchMode) { - InputEvent::initialize(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, AINPUT_SOURCE_UNKNOWN, +void FocusEvent::initialize(int32_t id, bool hasFocus, bool inTouchMode) { + InputEvent::initialize(id, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, AINPUT_SOURCE_UNKNOWN, ADISPLAY_ID_NONE, INVALID_HMAC); mHasFocus = hasFocus; mInTouchMode = inTouchMode; diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index d25a5cc0ef..eda01c5032 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -63,6 +63,10 @@ static const nsecs_t RESAMPLE_MAX_DELTA = 20 * NANOS_PER_MS; // far into the future. This time is further bounded by 50% of the last time delta. static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS; +// A placeholder sequence number used to initialize native input events before InputFlinger is +// migrated to new sequence number system. +static constexpr int32_t INPUT_FLINGER_SEQUENCE_NUM = 0; + /** * System property for enabling / disabling touch resampling. * Resampling extrapolates / interpolates the reported touch event coordinates to better @@ -1142,14 +1146,16 @@ ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const { } void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) { - event->initialize(msg->body.key.deviceId, msg->body.key.source, msg->body.key.displayId, - msg->body.key.hmac, msg->body.key.action, msg->body.key.flags, - msg->body.key.keyCode, msg->body.key.scanCode, msg->body.key.metaState, - msg->body.key.repeatCount, msg->body.key.downTime, msg->body.key.eventTime); + event->initialize(INPUT_FLINGER_SEQUENCE_NUM, msg->body.key.deviceId, msg->body.key.source, + msg->body.key.displayId, msg->body.key.hmac, msg->body.key.action, + msg->body.key.flags, msg->body.key.keyCode, msg->body.key.scanCode, + msg->body.key.metaState, msg->body.key.repeatCount, msg->body.key.downTime, + msg->body.key.eventTime); } void InputConsumer::initializeFocusEvent(FocusEvent* event, const InputMessage* msg) { - event->initialize(msg->body.focus.hasFocus == 1, msg->body.focus.inTouchMode == 1); + event->initialize(INPUT_FLINGER_SEQUENCE_NUM, msg->body.focus.hasFocus == 1, + msg->body.focus.inTouchMode == 1); } void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) { @@ -1161,16 +1167,17 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); } - event->initialize(msg->body.motion.deviceId, msg->body.motion.source, - msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action, - msg->body.motion.actionButton, msg->body.motion.flags, - msg->body.motion.edgeFlags, msg->body.motion.metaState, - msg->body.motion.buttonState, msg->body.motion.classification, - msg->body.motion.xScale, msg->body.motion.yScale, msg->body.motion.xOffset, - msg->body.motion.yOffset, msg->body.motion.xPrecision, - msg->body.motion.yPrecision, msg->body.motion.xCursorPosition, - msg->body.motion.yCursorPosition, msg->body.motion.downTime, - msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords); + event->initialize(INPUT_FLINGER_SEQUENCE_NUM, msg->body.motion.deviceId, + msg->body.motion.source, msg->body.motion.displayId, msg->body.motion.hmac, + msg->body.motion.action, msg->body.motion.actionButton, + msg->body.motion.flags, msg->body.motion.edgeFlags, + msg->body.motion.metaState, msg->body.motion.buttonState, + msg->body.motion.classification, msg->body.motion.xScale, + msg->body.motion.yScale, msg->body.motion.xOffset, msg->body.motion.yOffset, + msg->body.motion.xPrecision, msg->body.motion.yPrecision, + msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition, + msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount, + pointerProperties, pointerCoords); } void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) { diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index 6f9b162986..cb68165433 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -487,9 +487,9 @@ void KeyCharacterMap::addKey(Vector& outEvents, int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) { outEvents.push(); KeyEvent& event = outEvents.editTop(); - event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC, - down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode, 0, metaState, - 0, time, time); + event.initialize(InputEvent::nextId(), deviceId, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, + INVALID_HMAC, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode, + 0, metaState, 0, time, time); } void KeyCharacterMap::addMetaKeys(Vector& outEvents, diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index d0f761887a..553dc4c068 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -182,10 +182,12 @@ TEST_F(KeyEventTest, Properties) { // Initialize and get properties. constexpr nsecs_t ARBITRARY_DOWN_TIME = 1; constexpr nsecs_t ARBITRARY_EVENT_TIME = 2; - event.initialize(2, AINPUT_SOURCE_GAMEPAD, DISPLAY_ID, HMAC, AKEY_EVENT_ACTION_DOWN, + const int32_t id = InputEvent::nextId(); + event.initialize(id, 2, AINPUT_SOURCE_GAMEPAD, DISPLAY_ID, HMAC, AKEY_EVENT_ACTION_DOWN, AKEY_EVENT_FLAG_FROM_SYSTEM, AKEYCODE_BUTTON_X, 121, AMETA_ALT_ON, 1, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME); + ASSERT_EQ(id, event.getId()); ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType()); ASSERT_EQ(2, event.getDeviceId()); ASSERT_EQ(AINPUT_SOURCE_GAMEPAD, event.getSource()); @@ -222,12 +224,16 @@ protected: static constexpr float X_OFFSET = 1; static constexpr float Y_OFFSET = 1.1; + int32_t mId; + void initializeEventWithHistory(MotionEvent* event); void assertEqualsEventWithHistory(const MotionEvent* event); }; void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { + mId = InputEvent::nextId(); + PointerProperties pointerProperties[2]; pointerProperties[0].clear(); pointerProperties[0].id = 1; @@ -257,10 +263,10 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28); - event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, HMAC, AMOTION_EVENT_ACTION_MOVE, 0, - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP, - AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE, - X_SCALE, Y_SCALE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f, + event->initialize(mId, 2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, HMAC, + AMOTION_EVENT_ACTION_MOVE, 0, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, + AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, + MotionClassification::NONE, X_SCALE, Y_SCALE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, pointerProperties, pointerCoords); @@ -308,6 +314,7 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { // Check properties. + ASSERT_EQ(mId, event->getId()); ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType()); ASSERT_EQ(2, event->getDeviceId()); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource()); @@ -577,8 +584,8 @@ TEST_F(MotionEventTest, Transform) { pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle); } MotionEvent event; - event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, INVALID_HMAC, - AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/, + event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, + INVALID_HMAC, AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, 1 /*xScale*/, 1 /*yScale*/, 0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/, @@ -642,10 +649,10 @@ TEST_F(MotionEventTest, Initialize_SetsClassification) { } for (MotionClassification classification : classifications) { - event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, INVALID_HMAC, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, - 0, classification, 1 /*xScale*/, 1 /*yScale*/, 0, 0, 0, 0, - AMOTION_EVENT_INVALID_CURSOR_POSITION, + event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, + DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, + AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, classification, 1 /*xScale*/, + 1 /*yScale*/, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(classification, event.getClassification()); @@ -663,10 +670,10 @@ TEST_F(MotionEventTest, Initialize_SetsCursorPosition) { pointerCoords[i].clear(); } - event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID, INVALID_HMAC, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, - MotionClassification::NONE, 1 /*xScale*/, 1 /*yScale*/, 0, 0, 0, 0, - 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 0 /*downTime*/, + event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID, + INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, + AMETA_NONE, 0, MotionClassification::NONE, 1 /*xScale*/, 1 /*yScale*/, 0, 0, 0, + 0, 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); event.offsetLocation(20, 60); ASSERT_EQ(280, event.getRawXCursorPosition()); diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index 731eb6a000..bf452c07a3 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -176,11 +176,12 @@ static std::vector createMotionEventStream( EXPECT_EQ(pointerIndex, pointerCount); MotionEvent event; - event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, INVALID_HMAC, - action, 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, - AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, 1 /*xScale*/, - 1 /*yScale*/, 0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, - 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, + event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, + DISPLAY_ID, INVALID_HMAC, action, 0 /*actionButton*/, 0 /*flags*/, + AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, + MotionClassification::NONE, 1 /*xScale*/, 1 /*yScale*/, 0 /*xOffset*/, + 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, entry.eventTime.count(), pointerCount, properties, coords); diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp index a59dbe5987..4e8e840d1c 100644 --- a/libs/input/tests/VerifiedInputEvent_test.cpp +++ b/libs/input/tests/VerifiedInputEvent_test.cpp @@ -21,9 +21,10 @@ namespace android { static KeyEvent getKeyEventWithFlags(int32_t flags) { KeyEvent event; - event.initialize(2 /*deviceId*/, AINPUT_SOURCE_GAMEPAD, ADISPLAY_ID_DEFAULT, INVALID_HMAC, - AKEY_EVENT_ACTION_DOWN, flags, AKEYCODE_BUTTON_X, 121 /*scanCode*/, - AMETA_ALT_ON, 1 /*repeatCount*/, 1000 /*downTime*/, 2000 /*eventTime*/); + event.initialize(InputEvent::nextId(), 2 /*deviceId*/, AINPUT_SOURCE_GAMEPAD, + ADISPLAY_ID_DEFAULT, INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, flags, + AKEYCODE_BUTTON_X, 121 /*scanCode*/, AMETA_ALT_ON, 1 /*repeatCount*/, + 1000 /*downTime*/, 2000 /*eventTime*/); return event; } @@ -38,8 +39,8 @@ static MotionEvent getMotionEventWithFlags(int32_t flags) { pointerCoords[i].clear(); } - event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, INVALID_HMAC, - AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags, + event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, + INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, 2 /*xScale*/, 3 /*yScale*/, 4 /*xOffset*/, 5 /*yOffset*/, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/, 280 /*xCursorPosition*/, diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index 9a6ef21724..238cc39646 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -203,8 +203,9 @@ static MotionEvent generateMotionEvent() { const nsecs_t currentTime = now(); MotionEvent event; - event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, INVALID_HMAC, - AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0, + event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, + /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, 1 /* xScale */, 1 /* yScale */, /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0, diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index f9a86dd6bb..70cee18330 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3030,9 +3030,9 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState); KeyEvent event; - event.initialize(args->deviceId, args->source, args->displayId, INVALID_HMAC, args->action, - flags, keyCode, args->scanCode, metaState, repeatCount, args->downTime, - args->eventTime); + event.initialize(args->sequenceNum, args->deviceId, args->source, args->displayId, INVALID_HMAC, + args->action, flags, keyCode, args->scanCode, metaState, repeatCount, + args->downTime, args->eventTime); android::base::Timer t; mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); @@ -3125,13 +3125,14 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mLock.unlock(); MotionEvent event; - event.initialize(args->deviceId, args->source, args->displayId, INVALID_HMAC, - args->action, args->actionButton, args->flags, args->edgeFlags, - args->metaState, args->buttonState, args->classification, 1 /*xScale*/, - 1 /*yScale*/, 0 /* xOffset */, 0 /* yOffset */, args->xPrecision, - args->yPrecision, args->xCursorPosition, args->yCursorPosition, - args->downTime, args->eventTime, args->pointerCount, - args->pointerProperties, args->pointerCoords); + event.initialize(args->sequenceNum, args->deviceId, args->source, args->displayId, + INVALID_HMAC, args->action, args->actionButton, args->flags, + args->edgeFlags, args->metaState, args->buttonState, + args->classification, 1 /*xScale*/, 1 /*yScale*/, 0 /* xOffset */, + 0 /* yOffset */, args->xPrecision, args->yPrecision, + args->xCursorPosition, args->yCursorPosition, args->downTime, + args->eventTime, args->pointerCount, args->pointerProperties, + args->pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { @@ -3227,7 +3228,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec accelerateMetaShortcuts(VIRTUAL_KEYBOARD_ID, action, /*byref*/ keyCode, /*byref*/ metaState); KeyEvent keyEvent; - keyEvent.initialize(VIRTUAL_KEYBOARD_ID, incomingKey.getSource(), + keyEvent.initialize(incomingKey.getId(), VIRTUAL_KEYBOARD_ID, incomingKey.getSource(), incomingKey.getDisplayId(), INVALID_HMAC, action, flags, keyCode, incomingKey.getScanCode(), metaState, incomingKey.getRepeatCount(), incomingKey.getDownTime(), incomingKey.getEventTime()); @@ -3247,11 +3248,12 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec mLock.lock(); KeyEntry* injectedEntry = - new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(), - VIRTUAL_KEYBOARD_ID, keyEvent.getSource(), keyEvent.getDisplayId(), - policyFlags, action, flags, keyEvent.getKeyCode(), - keyEvent.getScanCode(), keyEvent.getMetaState(), - keyEvent.getRepeatCount(), keyEvent.getDownTime()); + new KeyEntry(incomingKey.getId(), incomingKey.getEventTime(), + VIRTUAL_KEYBOARD_ID, incomingKey.getSource(), + incomingKey.getDisplayId(), policyFlags, action, flags, + incomingKey.getKeyCode(), incomingKey.getScanCode(), + incomingKey.getMetaState(), incomingKey.getRepeatCount(), + incomingKey.getDownTime()); injectedEntries.push(injectedEntry); break; } @@ -3281,13 +3283,12 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); MotionEntry* injectedEntry = - new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, - VIRTUAL_KEYBOARD_ID, motionEvent->getSource(), - motionEvent->getDisplayId(), policyFlags, action, actionButton, - motionEvent->getFlags(), motionEvent->getMetaState(), - motionEvent->getButtonState(), motionEvent->getClassification(), - motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), - motionEvent->getYPrecision(), + new MotionEntry(motionEvent->getId(), *sampleEventTimes, VIRTUAL_KEYBOARD_ID, + motionEvent->getSource(), motionEvent->getDisplayId(), + policyFlags, action, actionButton, motionEvent->getFlags(), + motionEvent->getMetaState(), motionEvent->getButtonState(), + motionEvent->getClassification(), motionEvent->getEdgeFlags(), + motionEvent->getXPrecision(), motionEvent->getYPrecision(), motionEvent->getRawXCursorPosition(), motionEvent->getRawYCursorPosition(), motionEvent->getDownTime(), uint32_t(pointerCount), @@ -3298,7 +3299,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec sampleEventTimes += 1; samplePointerCoords += pointerCount; MotionEntry* nextInjectedEntry = - new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, + new MotionEntry(motionEvent->getId(), *sampleEventTimes, VIRTUAL_KEYBOARD_ID, motionEvent->getSource(), motionEvent->getDisplayId(), policyFlags, action, actionButton, motionEvent->getFlags(), @@ -4817,9 +4818,9 @@ void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* comman KeyEvent InputDispatcher::createKeyEvent(const KeyEntry& entry) { KeyEvent event; - event.initialize(entry.deviceId, entry.source, entry.displayId, INVALID_HMAC, entry.action, - entry.flags, entry.keyCode, entry.scanCode, entry.metaState, entry.repeatCount, - entry.downTime, entry.eventTime); + event.initialize(entry.sequenceNum, entry.deviceId, entry.source, entry.displayId, INVALID_HMAC, + entry.action, entry.flags, entry.keyCode, entry.scanCode, entry.metaState, + entry.repeatCount, entry.downTime, entry.eventTime); return event; } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 2fb1b65d93..f05f7e5a79 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -49,9 +49,9 @@ struct PointF { static KeyEvent getTestKeyEvent() { KeyEvent event; - event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC, - AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, - ARBITRARY_TIME); + event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, + INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, + ARBITRARY_TIME, ARBITRARY_TIME); return event; } @@ -300,7 +300,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { KeyEvent event; // Rejects undefined key actions. - event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC, + event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, + INVALID_HMAC, /*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -309,8 +310,8 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { << "Should reject key events with undefined action."; // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API. - event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC, - AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, + event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, + INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, @@ -335,7 +336,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { constexpr MotionClassification classification = MotionClassification::NONE; // Rejects undefined motion actions. - event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, + event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, @@ -346,7 +347,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { << "Should reject motion events with undefined action."; // Rejects pointer down with invalid index. - event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, + event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, @@ -358,7 +359,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer down index too large."; - event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, + event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, @@ -371,7 +372,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { << "Should reject motion events with pointer down index too small."; // Rejects pointer up with invalid index. - event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, + event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, @@ -383,7 +384,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer up index too large."; - event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, + event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), 0, 0, edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, @@ -396,20 +397,22 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { << "Should reject motion events with pointer up index too small."; // Rejects motion events with invalid number of pointers. - event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, - edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0, - 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, + event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, + AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, + 1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with 0 pointers."; - event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, - edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0, - 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, + event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, + AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, + 1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, @@ -418,10 +421,11 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects motion events with invalid pointer ids. pointerProperties[0].id = -1; - event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, - edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0, - 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, + event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, + AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, + 1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, @@ -429,10 +433,11 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { << "Should reject motion events with pointer ids less than 0."; pointerProperties[0].id = MAX_POINTER_ID + 1; - event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, - edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0, - 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, + event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, + AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, + 1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, @@ -442,10 +447,11 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects motion events with duplicate pointer ids. pointerProperties[0].id = 1; pointerProperties[1].id = 1; - event.initialize(DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, - edgeFlags, metaState, 0, classification, 1 /* xScale */, 1 /* yScale */, 0, 0, - 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, + event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, + AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, + 1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, @@ -748,8 +754,9 @@ static int32_t injectKeyDown(const sp& dispatcher, nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid key down event. - event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId, INVALID_HMAC, - AKEY_EVENT_ACTION_DOWN, /* flags */ 0, AKEYCODE_A, KEY_A, AMETA_NONE, + event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId, + INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /* flags */ 0, AKEYCODE_A, KEY_A, + AMETA_NONE, /* repeatCount */ 0, currentTime, currentTime); // Inject event until dispatch out. @@ -777,7 +784,8 @@ static int32_t injectMotionEvent(const sp& dispatcher, int32_t nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid motion down event. - event.initialize(DEVICE_ID, source, displayId, INVALID_HMAC, action, /* actionButton */ 0, + event.initialize(InputEvent::nextId(), DEVICE_ID, source, displayId, INVALID_HMAC, action, + /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, /* xScale */ 1, /* yScale */ 1, /* xOffset */ 0, /* yOffset */ 0, -- GitLab From c51d1ba0d7af0fbc33b8e8dc6e54f6bd7f534267 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Tue, 28 Jan 2020 13:24:04 -0800 Subject: [PATCH 0842/1255] Rename sequenceNum to ID. This is for consistency with ID in other places. Change it to signed type to match Java int type. Bug: 144889238 Test: atest inputflinger_tests Change-Id: I8b6782a67f28aa13f7feaed2c97b8e87105019db Merged-In: I8b6782a67f28aa13f7feaed2c97b8e87105019db (cherry picked from commit 6a5a14e75b1a0fb377c670cb9a1e9ace60c5da74) --- services/inputflinger/InputListener.cpp | 146 +++++++++--------- .../benchmarks/InputDispatcher_benchmarks.cpp | 6 +- services/inputflinger/dispatcher/Entry.cpp | 25 ++- services/inputflinger/dispatcher/Entry.h | 37 ++--- .../dispatcher/InputDispatcher.cpp | 66 ++++---- .../inputflinger/dispatcher/InputState.cpp | 28 ++-- services/inputflinger/include/InputListener.h | 23 ++- services/inputflinger/reader/InputDevice.cpp | 2 +- services/inputflinger/reader/InputReader.cpp | 8 +- .../inputflinger/reader/include/InputReader.h | 6 +- .../reader/include/InputReaderContext.h | 2 +- .../reader/mapper/CursorInputMapper.cpp | 34 ++-- .../reader/mapper/JoystickInputMapper.cpp | 7 +- .../reader/mapper/KeyboardInputMapper.cpp | 5 +- .../mapper/RotaryEncoderInputMapper.cpp | 6 +- .../reader/mapper/SwitchInputMapper.cpp | 2 +- .../mapper/TouchCursorInputMapperCommon.h | 4 +- .../reader/mapper/TouchInputMapper.cpp | 50 +++--- .../tests/InputDispatcher_test.cpp | 25 ++- .../inputflinger/tests/InputReader_test.cpp | 32 ++-- 20 files changed, 246 insertions(+), 268 deletions(-) diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp index de639772a8..e91e803fb8 100644 --- a/services/inputflinger/InputListener.cpp +++ b/services/inputflinger/InputListener.cpp @@ -27,18 +27,15 @@ namespace android { // --- NotifyConfigurationChangedArgs --- -NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs( - uint32_t sequenceNum, nsecs_t eventTime) : - NotifyArgs(sequenceNum, eventTime) { -} +NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(int32_t id, nsecs_t eventTime) + : NotifyArgs(id, eventTime) {} NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs( - const NotifyConfigurationChangedArgs& other) : - NotifyArgs(other.sequenceNum, other.eventTime) { -} + const NotifyConfigurationChangedArgs& other) + : NotifyArgs(other.id, other.eventTime) {} bool NotifyConfigurationChangedArgs::operator==(const NotifyConfigurationChangedArgs& rhs) const { - return sequenceNum == rhs.sequenceNum && eventTime == rhs.eventTime; + return id == rhs.id && eventTime == rhs.eventTime; } void NotifyConfigurationChangedArgs::notify(const sp& listener) const { @@ -48,37 +45,39 @@ void NotifyConfigurationChangedArgs::notify(const sp& li // --- NotifyKeyArgs --- -NotifyKeyArgs::NotifyKeyArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, - uint32_t source, int32_t displayId, uint32_t policyFlags, - int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, - int32_t metaState, nsecs_t downTime) : - NotifyArgs(sequenceNum, eventTime), deviceId(deviceId), source(source), - displayId(displayId), policyFlags(policyFlags), - action(action), flags(flags), keyCode(keyCode), scanCode(scanCode), - metaState(metaState), downTime(downTime) { -} +NotifyKeyArgs::NotifyKeyArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, + int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags, + int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) + : NotifyArgs(id, eventTime), + deviceId(deviceId), + source(source), + displayId(displayId), + policyFlags(policyFlags), + action(action), + flags(flags), + keyCode(keyCode), + scanCode(scanCode), + metaState(metaState), + downTime(downTime) {} -NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) : - NotifyArgs(other.sequenceNum, other.eventTime), deviceId(other.deviceId), - source(other.source), displayId(other.displayId), policyFlags(other.policyFlags), - action(other.action), flags(other.flags), - keyCode(other.keyCode), scanCode(other.scanCode), - metaState(other.metaState), downTime(other.downTime) { -} +NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) + : NotifyArgs(other.id, other.eventTime), + deviceId(other.deviceId), + source(other.source), + displayId(other.displayId), + policyFlags(other.policyFlags), + action(other.action), + flags(other.flags), + keyCode(other.keyCode), + scanCode(other.scanCode), + metaState(other.metaState), + downTime(other.downTime) {} bool NotifyKeyArgs::operator==(const NotifyKeyArgs& rhs) const { - return sequenceNum == rhs.sequenceNum - && eventTime == rhs.eventTime - && deviceId == rhs.deviceId - && source == rhs.source - && displayId == rhs.displayId - && policyFlags == rhs.policyFlags - && action == rhs.action - && flags == rhs.flags - && keyCode == rhs.keyCode - && scanCode == rhs.scanCode - && metaState == rhs.metaState - && downTime == rhs.downTime; + return id == rhs.id && eventTime == rhs.eventTime && deviceId == rhs.deviceId && + source == rhs.source && displayId == rhs.displayId && policyFlags == rhs.policyFlags && + action == rhs.action && flags == rhs.flags && keyCode == rhs.keyCode && + scanCode == rhs.scanCode && metaState == rhs.metaState && downTime == rhs.downTime; } void NotifyKeyArgs::notify(const sp& listener) const { @@ -88,15 +87,17 @@ void NotifyKeyArgs::notify(const sp& listener) const { // --- NotifyMotionArgs --- -NotifyMotionArgs::NotifyMotionArgs( - uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, - int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, - int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification, - int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords, float xPrecision, float yPrecision, - float xCursorPosition, float yCursorPosition, nsecs_t downTime, - const std::vector& videoFrames) - : NotifyArgs(sequenceNum, eventTime), +NotifyMotionArgs::NotifyMotionArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, + int32_t displayId, uint32_t policyFlags, int32_t action, + int32_t actionButton, int32_t flags, int32_t metaState, + int32_t buttonState, MotionClassification classification, + int32_t edgeFlags, uint32_t pointerCount, + const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords, float xPrecision, + float yPrecision, float xCursorPosition, float yCursorPosition, + nsecs_t downTime, + const std::vector& videoFrames) + : NotifyArgs(id, eventTime), deviceId(deviceId), source(source), displayId(displayId), @@ -122,7 +123,7 @@ NotifyMotionArgs::NotifyMotionArgs( } NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) - : NotifyArgs(other.sequenceNum, other.eventTime), + : NotifyArgs(other.id, other.eventTime), deviceId(other.deviceId), source(other.source), displayId(other.displayId), @@ -152,12 +153,11 @@ static inline bool isCursorPositionEqual(float lhs, float rhs) { } bool NotifyMotionArgs::operator==(const NotifyMotionArgs& rhs) const { - bool equal = sequenceNum == rhs.sequenceNum && eventTime == rhs.eventTime && - deviceId == rhs.deviceId && source == rhs.source && displayId == rhs.displayId && - policyFlags == rhs.policyFlags && action == rhs.action && - actionButton == rhs.actionButton && flags == rhs.flags && metaState == rhs.metaState && - buttonState == rhs.buttonState && classification == rhs.classification && - edgeFlags == rhs.edgeFlags && + bool equal = id == rhs.id && eventTime == rhs.eventTime && deviceId == rhs.deviceId && + source == rhs.source && displayId == rhs.displayId && policyFlags == rhs.policyFlags && + action == rhs.action && actionButton == rhs.actionButton && flags == rhs.flags && + metaState == rhs.metaState && buttonState == rhs.buttonState && + classification == rhs.classification && edgeFlags == rhs.edgeFlags && pointerCount == rhs.pointerCount // PointerProperties and PointerCoords are compared separately below && xPrecision == rhs.xPrecision && yPrecision == rhs.yPrecision && @@ -186,23 +186,22 @@ void NotifyMotionArgs::notify(const sp& listener) const // --- NotifySwitchArgs --- -NotifySwitchArgs::NotifySwitchArgs(uint32_t sequenceNum, nsecs_t eventTime, uint32_t policyFlags, - uint32_t switchValues, uint32_t switchMask) : - NotifyArgs(sequenceNum, eventTime), policyFlags(policyFlags), - switchValues(switchValues), switchMask(switchMask) { -} +NotifySwitchArgs::NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags, + uint32_t switchValues, uint32_t switchMask) + : NotifyArgs(id, eventTime), + policyFlags(policyFlags), + switchValues(switchValues), + switchMask(switchMask) {} -NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) : - NotifyArgs(other.sequenceNum, other.eventTime), policyFlags(other.policyFlags), - switchValues(other.switchValues), switchMask(other.switchMask) { -} +NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) + : NotifyArgs(other.id, other.eventTime), + policyFlags(other.policyFlags), + switchValues(other.switchValues), + switchMask(other.switchMask) {} bool NotifySwitchArgs::operator==(const NotifySwitchArgs rhs) const { - return sequenceNum == rhs.sequenceNum - && eventTime == rhs.eventTime - && policyFlags == rhs.policyFlags - && switchValues == rhs.switchValues - && switchMask == rhs.switchMask; + return id == rhs.id && eventTime == rhs.eventTime && policyFlags == rhs.policyFlags && + switchValues == rhs.switchValues && switchMask == rhs.switchMask; } void NotifySwitchArgs::notify(const sp& listener) const { @@ -212,19 +211,14 @@ void NotifySwitchArgs::notify(const sp& listener) const // --- NotifyDeviceResetArgs --- -NotifyDeviceResetArgs::NotifyDeviceResetArgs( - uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId) : - NotifyArgs(sequenceNum, eventTime), deviceId(deviceId) { -} +NotifyDeviceResetArgs::NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId) + : NotifyArgs(id, eventTime), deviceId(deviceId) {} -NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) : - NotifyArgs(other.sequenceNum, other.eventTime), deviceId(other.deviceId) { -} +NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) + : NotifyArgs(other.id, other.eventTime), deviceId(other.deviceId) {} bool NotifyDeviceResetArgs::operator==(const NotifyDeviceResetArgs& rhs) const { - return sequenceNum == rhs.sequenceNum - && eventTime == rhs.eventTime - && deviceId == rhs.deviceId; + return id == rhs.id && eventTime == rhs.eventTime && deviceId == rhs.deviceId; } void NotifyDeviceResetArgs::notify(const sp& listener) const { diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index 238cc39646..3b18813cef 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -229,7 +229,7 @@ static NotifyMotionArgs generateMotionArgs() { const nsecs_t currentTime = now(); // Define a valid motion event. - NotifyMotionArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + NotifyMotionArgs args(/* id */ 0, currentTime, DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, POLICY_FLAG_PASS_TO_USER, AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, @@ -259,14 +259,14 @@ static void benchmarkNotifyMotion(benchmark::State& state) { for (auto _ : state) { // Send ACTION_DOWN motionArgs.action = AMOTION_EVENT_ACTION_DOWN; - motionArgs.sequenceNum = 0; + motionArgs.id = 0; motionArgs.downTime = now(); motionArgs.eventTime = motionArgs.downTime; dispatcher->notifyMotion(&motionArgs); // Send ACTION_UP motionArgs.action = AMOTION_EVENT_ACTION_UP; - motionArgs.sequenceNum = 1; + motionArgs.id = 1; motionArgs.eventTime = now(); dispatcher->notifyMotion(&motionArgs); diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index c4b3789090..49630ad436 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -86,8 +86,8 @@ VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry) // --- EventEntry --- -EventEntry::EventEntry(uint32_t sequenceNum, Type type, nsecs_t eventTime, uint32_t policyFlags) - : sequenceNum(sequenceNum), +EventEntry::EventEntry(int32_t id, Type type, nsecs_t eventTime, uint32_t policyFlags) + : id(id), refCount(1), type(type), eventTime(eventTime), @@ -117,8 +117,8 @@ void EventEntry::releaseInjectionState() { // --- ConfigurationChangedEntry --- -ConfigurationChangedEntry::ConfigurationChangedEntry(uint32_t sequenceNum, nsecs_t eventTime) - : EventEntry(sequenceNum, Type::CONFIGURATION_CHANGED, eventTime, 0) {} +ConfigurationChangedEntry::ConfigurationChangedEntry(int32_t id, nsecs_t eventTime) + : EventEntry(id, Type::CONFIGURATION_CHANGED, eventTime, 0) {} ConfigurationChangedEntry::~ConfigurationChangedEntry() {} @@ -128,8 +128,8 @@ void ConfigurationChangedEntry::appendDescription(std::string& msg) const { // --- DeviceResetEntry --- -DeviceResetEntry::DeviceResetEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId) - : EventEntry(sequenceNum, Type::DEVICE_RESET, eventTime, 0), deviceId(deviceId) {} +DeviceResetEntry::DeviceResetEntry(int32_t id, nsecs_t eventTime, int32_t deviceId) + : EventEntry(id, Type::DEVICE_RESET, eventTime, 0), deviceId(deviceId) {} DeviceResetEntry::~DeviceResetEntry() {} @@ -140,9 +140,8 @@ void DeviceResetEntry::appendDescription(std::string& msg) const { // --- FocusEntry --- // Focus notifications always go to apps, so set the flag POLICY_FLAG_PASS_TO_USER for all entries -FocusEntry::FocusEntry(uint32_t sequenceNum, nsecs_t eventTime, sp connectionToken, - bool hasFocus) - : EventEntry(sequenceNum, Type::FOCUS, eventTime, POLICY_FLAG_PASS_TO_USER), +FocusEntry::FocusEntry(int32_t id, nsecs_t eventTime, sp connectionToken, bool hasFocus) + : EventEntry(id, Type::FOCUS, eventTime, POLICY_FLAG_PASS_TO_USER), connectionToken(connectionToken), hasFocus(hasFocus) {} @@ -154,11 +153,11 @@ void FocusEntry::appendDescription(std::string& msg) const { // --- KeyEntry --- -KeyEntry::KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, +KeyEntry::KeyEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime) - : EventEntry(sequenceNum, Type::KEY, eventTime, policyFlags), + : EventEntry(id, Type::KEY, eventTime, policyFlags), deviceId(deviceId), source(source), displayId(displayId), @@ -198,7 +197,7 @@ void KeyEntry::recycle() { // --- MotionEntry --- -MotionEntry::MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, +MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification, @@ -206,7 +205,7 @@ MotionEntry::MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t device float xCursorPosition, float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xOffset, float yOffset) - : EventEntry(sequenceNum, Type::MOTION, eventTime, policyFlags), + : EventEntry(id, Type::MOTION, eventTime, policyFlags), eventTime(eventTime), deviceId(deviceId), source(source), diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index b5b61ccb98..c58ae23cc5 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -30,7 +30,7 @@ namespace android::inputdispatcher { // Sequence number for synthesized or injected events. -constexpr uint32_t SYNTHESIZED_EVENT_SEQUENCE_NUM = 0; +constexpr int32_t SYNTHESIZED_EVENT_ID = 0; struct EventEntry { enum class Type { @@ -56,7 +56,7 @@ struct EventEntry { } } - uint32_t sequenceNum; + int32_t id; mutable int32_t refCount; Type type; nsecs_t eventTime; @@ -78,22 +78,20 @@ struct EventEntry { * Key repeat is a synthesized event, because it is related to an actual hardware state * (a key is currently pressed), but the repeat itself is generated by the framework. */ - inline bool isSynthesized() const { - return isInjected() || sequenceNum == SYNTHESIZED_EVENT_SEQUENCE_NUM; - } + inline bool isSynthesized() const { return isInjected() || id == SYNTHESIZED_EVENT_ID; } void release(); virtual void appendDescription(std::string& msg) const = 0; protected: - EventEntry(uint32_t sequenceNum, Type type, nsecs_t eventTime, uint32_t policyFlags); + EventEntry(int32_t id, Type type, nsecs_t eventTime, uint32_t policyFlags); virtual ~EventEntry(); void releaseInjectionState(); }; struct ConfigurationChangedEntry : EventEntry { - explicit ConfigurationChangedEntry(uint32_t sequenceNum, nsecs_t eventTime); + explicit ConfigurationChangedEntry(int32_t id, nsecs_t eventTime); virtual void appendDescription(std::string& msg) const; protected: @@ -103,7 +101,7 @@ protected: struct DeviceResetEntry : EventEntry { int32_t deviceId; - DeviceResetEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId); + DeviceResetEntry(int32_t id, nsecs_t eventTime, int32_t deviceId); virtual void appendDescription(std::string& msg) const; protected: @@ -114,7 +112,7 @@ struct FocusEntry : EventEntry { sp connectionToken; bool hasFocus; - FocusEntry(uint32_t sequenceNum, nsecs_t eventTime, sp connectionToken, bool hasFocus); + FocusEntry(int32_t id, nsecs_t eventTime, sp connectionToken, bool hasFocus); virtual void appendDescription(std::string& msg) const; protected: @@ -144,10 +142,9 @@ struct KeyEntry : EventEntry { InterceptKeyResult interceptKeyResult; // set based on the interception result nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER - KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, - int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, - nsecs_t downTime); + KeyEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId, + uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, + int32_t metaState, int32_t repeatCount, nsecs_t downTime); virtual void appendDescription(std::string& msg) const; void recycle(); @@ -176,13 +173,13 @@ struct MotionEntry : EventEntry { PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; - MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, - int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, - int32_t flags, int32_t metaState, int32_t buttonState, - MotionClassification classification, int32_t edgeFlags, float xPrecision, - float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, - uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords, float xOffset, float yOffset); + MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId, + uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags, + int32_t metaState, int32_t buttonState, MotionClassification classification, + int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, + float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, + float xOffset, float yOffset); virtual void appendDescription(std::string& msg) const; protected: diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 70cee18330..2f7b5ad9e6 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -302,7 +302,7 @@ static std::unique_ptr createDispatchEntry(const InputTarget& inp } MotionEntry* combinedMotionEntry = - new MotionEntry(motionEntry.sequenceNum, motionEntry.eventTime, motionEntry.deviceId, + new MotionEntry(motionEntry.id, motionEntry.eventTime, motionEntry.deviceId, motionEntry.source, motionEntry.displayId, motionEntry.policyFlags, motionEntry.action, motionEntry.actionButton, motionEntry.flags, motionEntry.metaState, motionEntry.buttonState, @@ -930,9 +930,9 @@ KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { entry->repeatCount += 1; } else { KeyEntry* newEntry = - new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, entry->deviceId, - entry->source, entry->displayId, policyFlags, entry->action, - entry->flags, entry->keyCode, entry->scanCode, entry->metaState, + new KeyEntry(SYNTHESIZED_EVENT_ID, currentTime, entry->deviceId, entry->source, + entry->displayId, policyFlags, entry->action, entry->flags, + entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount + 1, entry->downTime); mKeyRepeatState.lastKeyEntry = newEntry; @@ -981,7 +981,7 @@ bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime, DeviceReset void InputDispatcher::enqueueFocusEventLocked(const InputWindowHandle& window, bool hasFocus) { FocusEntry* focusEntry = - new FocusEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, now(), window.getToken(), hasFocus); + new FocusEntry(SYNTHESIZED_EVENT_ID, now(), window.getToken(), hasFocus); enqueueInboundEventLocked(focusEntry); } @@ -1076,7 +1076,7 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, setInjectionResult(entry, *dropReason == DropReason::POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); - mReporter->reportDroppedKey(entry->sequenceNum); + mReporter->reportDroppedKey(entry->id); return true; } @@ -2188,8 +2188,8 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const InputTarget& inputTarget) { if (ATRACE_ENABLED()) { std::string message = - StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")", - connection->getInputChannelName().c_str(), eventEntry->sequenceNum); + StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, id=%" PRIx32 ")", + connection->getInputChannelName().c_str(), eventEntry->id); ATRACE_NAME(message.c_str()); } #if DEBUG_DISPATCH_CYCLE @@ -2244,9 +2244,8 @@ void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const InputTarget& inputTarget) { if (ATRACE_ENABLED()) { std::string message = - StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, sequenceNum=%" PRIu32 - ")", - connection->getInputChannelName().c_str(), eventEntry->sequenceNum); + StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, id=%" PRIx32 ")", + connection->getInputChannelName().c_str(), eventEntry->id); ATRACE_NAME(message.c_str()); } @@ -2922,7 +2921,7 @@ MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry& originalMotion } MotionEntry* splitMotionEntry = - new MotionEntry(originalMotionEntry.sequenceNum, originalMotionEntry.eventTime, + new MotionEntry(originalMotionEntry.id, originalMotionEntry.eventTime, originalMotionEntry.deviceId, originalMotionEntry.source, originalMotionEntry.displayId, originalMotionEntry.policyFlags, action, originalMotionEntry.actionButton, originalMotionEntry.flags, @@ -2951,7 +2950,7 @@ void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChange std::scoped_lock _l(mLock); ConfigurationChangedEntry* newEntry = - new ConfigurationChangedEntry(args->sequenceNum, args->eventTime); + new ConfigurationChangedEntry(args->id, args->eventTime); needWake = enqueueInboundEventLocked(newEntry); } // release lock @@ -3030,7 +3029,7 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState); KeyEvent event; - event.initialize(args->sequenceNum, args->deviceId, args->source, args->displayId, INVALID_HMAC, + event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC, args->action, flags, keyCode, args->scanCode, metaState, repeatCount, args->downTime, args->eventTime); @@ -3057,7 +3056,7 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { } KeyEntry* newEntry = - new KeyEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source, + new KeyEntry(args->id, args->eventTime, args->deviceId, args->source, args->displayId, policyFlags, args->action, flags, keyCode, args->scanCode, metaState, repeatCount, args->downTime); @@ -3076,15 +3075,15 @@ bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 - ", policyFlags=0x%x, " + ALOGD("notifyMotion - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, " + "displayId=%" PRId32 ", policyFlags=0x%x, " "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, " "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, " "yCursorPosition=%f, downTime=%" PRId64, - args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, - args->action, args->actionButton, args->flags, args->metaState, args->buttonState, - args->edgeFlags, args->xPrecision, args->yPrecision, args->xCursorPosition, - args->yCursorPosition, args->downTime); + args->id, args->eventTime, args->deviceId, args->source, args->displayId, + args->policyFlags, args->action, args->actionButton, args->flags, args->metaState, + args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, + args->xCursorPosition, args->yCursorPosition, args->downTime); for (uint32_t i = 0; i < args->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " "x=%f, y=%f, pressure=%f, size=%f, " @@ -3125,14 +3124,13 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mLock.unlock(); MotionEvent event; - event.initialize(args->sequenceNum, args->deviceId, args->source, args->displayId, - INVALID_HMAC, args->action, args->actionButton, args->flags, - args->edgeFlags, args->metaState, args->buttonState, - args->classification, 1 /*xScale*/, 1 /*yScale*/, 0 /* xOffset */, - 0 /* yOffset */, args->xPrecision, args->yPrecision, - args->xCursorPosition, args->yCursorPosition, args->downTime, - args->eventTime, args->pointerCount, args->pointerProperties, - args->pointerCoords); + event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC, + args->action, args->actionButton, args->flags, args->edgeFlags, + args->metaState, args->buttonState, args->classification, 1 /*xScale*/, + 1 /*yScale*/, 0 /* xOffset */, 0 /* yOffset */, args->xPrecision, + args->yPrecision, args->xCursorPosition, args->yCursorPosition, + args->downTime, args->eventTime, args->pointerCount, + args->pointerProperties, args->pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { @@ -3144,7 +3142,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { // Just enqueue a new motion event. MotionEntry* newEntry = - new MotionEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source, + new MotionEntry(args->id, args->eventTime, args->deviceId, args->source, args->displayId, policyFlags, args->action, args->actionButton, args->flags, args->metaState, args->buttonState, args->classification, args->edgeFlags, args->xPrecision, @@ -3188,7 +3186,7 @@ void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { std::scoped_lock _l(mLock); DeviceResetEntry* newEntry = - new DeviceResetEntry(args->sequenceNum, args->eventTime, args->deviceId); + new DeviceResetEntry(args->id, args->eventTime, args->deviceId); needWake = enqueueInboundEventLocked(newEntry); } // release lock @@ -4631,7 +4629,7 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& con if (keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK) { if (!handled) { // Report the key as unhandled, since the fallback was not handled. - mReporter->reportUnhandledKey(keyEntry->sequenceNum); + mReporter->reportUnhandledKey(keyEntry->id); } return false; } @@ -4796,7 +4794,7 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& con #endif // Report the key as unhandled, since there is no fallback key. - mReporter->reportUnhandledKey(keyEntry->sequenceNum); + mReporter->reportUnhandledKey(keyEntry->id); } } return false; @@ -4818,7 +4816,7 @@ void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* comman KeyEvent InputDispatcher::createKeyEvent(const KeyEntry& entry) { KeyEvent event; - event.initialize(entry.sequenceNum, entry.deviceId, entry.source, entry.displayId, INVALID_HMAC, + event.initialize(entry.id, entry.deviceId, entry.source, entry.displayId, INVALID_HMAC, entry.action, entry.flags, entry.keyCode, entry.scanCode, entry.metaState, entry.repeatCount, entry.downTime, entry.eventTime); return event; diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index 053598ab02..7fa9e09aad 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -268,9 +268,9 @@ std::vector InputState::synthesizeCancelationEvents( std::vector events; for (KeyMemento& memento : mKeyMementos) { if (shouldCancelKey(memento, options)) { - events.push_back(new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, - memento.deviceId, memento.source, memento.displayId, - memento.policyFlags, AKEY_EVENT_ACTION_UP, + events.push_back(new KeyEntry(SYNTHESIZED_EVENT_ID, currentTime, memento.deviceId, + memento.source, memento.displayId, memento.policyFlags, + AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED, memento.keyCode, memento.scanCode, memento.metaState, 0 /*repeatCount*/, memento.downTime)); @@ -281,11 +281,10 @@ std::vector InputState::synthesizeCancelationEvents( if (shouldCancelMotion(memento, options)) { const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL; - 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, + events.push_back(new MotionEntry(SYNTHESIZED_EVENT_ID, 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, @@ -332,16 +331,15 @@ std::vector InputState::synthesizePointerDownEvents(nsecs_t current : 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, + events.push_back(new MotionEntry(SYNTHESIZED_EVENT_ID, 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*/)); + pointerCount, pointerProperties, pointerCoords, + 0 /*xOffset*/, 0 /*yOffset*/)); } memento.firstNewPointerIdx = INVALID_POINTER_INDEX; diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h index 0dcd2f9c38..f8d0150e87 100644 --- a/services/inputflinger/include/InputListener.h +++ b/services/inputflinger/include/InputListener.h @@ -31,13 +31,12 @@ class InputListenerInterface; /* Superclass of all input event argument objects */ struct NotifyArgs { - uint32_t sequenceNum; + int32_t id; nsecs_t eventTime; - inline NotifyArgs() : sequenceNum(0), eventTime(0) { } + inline NotifyArgs() : id(0), eventTime(0) {} - inline explicit NotifyArgs(uint32_t sequenceNum, nsecs_t eventTime) : - sequenceNum(sequenceNum), eventTime(eventTime) { } + inline explicit NotifyArgs(int32_t id, nsecs_t eventTime) : id(id), eventTime(eventTime) {} virtual ~NotifyArgs() { } @@ -52,7 +51,7 @@ struct NotifyConfigurationChangedArgs : public NotifyArgs { bool operator==(const NotifyConfigurationChangedArgs& rhs) const; - NotifyConfigurationChangedArgs(uint32_t sequenceNum, nsecs_t eventTime); + NotifyConfigurationChangedArgs(int32_t id, nsecs_t eventTime); NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other); @@ -77,9 +76,9 @@ struct NotifyKeyArgs : public NotifyArgs { inline NotifyKeyArgs() { } - NotifyKeyArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, - int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, - int32_t scanCode, int32_t metaState, nsecs_t downTime); + NotifyKeyArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, + int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags, + int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime); bool operator==(const NotifyKeyArgs& rhs) const; @@ -125,7 +124,7 @@ struct NotifyMotionArgs : public NotifyArgs { inline NotifyMotionArgs() { } - NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, + NotifyMotionArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification, int32_t edgeFlags, uint32_t pointerCount, @@ -152,8 +151,8 @@ struct NotifySwitchArgs : public NotifyArgs { inline NotifySwitchArgs() { } - NotifySwitchArgs(uint32_t sequenceNum, nsecs_t eventTime, uint32_t policyFlags, - uint32_t switchValues, uint32_t switchMask); + NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags, uint32_t switchValues, + uint32_t switchMask); NotifySwitchArgs(const NotifySwitchArgs& other); @@ -172,7 +171,7 @@ struct NotifyDeviceResetArgs : public NotifyArgs { inline NotifyDeviceResetArgs() { } - NotifyDeviceResetArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId); + NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId); NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other); diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index f2afc818ff..4b19e5e353 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -454,7 +454,7 @@ void InputDevice::bumpGeneration() { } void InputDevice::notifyReset(nsecs_t when) { - NotifyDeviceResetArgs args(mContext->getNextSequenceNum(), when, mId); + NotifyDeviceResetArgs args(mContext->getNextId(), when, mId); mContext->getListener()->notifyDeviceReset(&args); } diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 6ab5902bb7..2998cc9619 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -46,7 +46,7 @@ InputReader::InputReader(std::shared_ptr eventHub, : mContext(this), mEventHub(eventHub), mPolicy(policy), - mNextSequenceNum(1), + mNextId(1), mGlobalMetaState(0), mGeneration(1), mNextInputDeviceId(END_RESERVED_ID), @@ -313,7 +313,7 @@ void InputReader::handleConfigurationChangedLocked(nsecs_t when) { updateGlobalMetaStateLocked(); // Enqueue configuration changed. - NotifyConfigurationChangedArgs args(mContext.getNextSequenceNum(), when); + NotifyConfigurationChangedArgs args(mContext.getNextId(), when); mQueuedListener->notifyConfigurationChanged(&args); } @@ -761,8 +761,8 @@ EventHubInterface* InputReader::ContextImpl::getEventHub() { return mReader->mEventHub.get(); } -uint32_t InputReader::ContextImpl::getNextSequenceNum() { - return (mReader->mNextSequenceNum)++; +int32_t InputReader::ContextImpl::getNextId() { + return (mReader->mNextId)++; } } // namespace android diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index ca1a081e48..eaa105a8f6 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -111,7 +111,7 @@ protected: virtual InputReaderPolicyInterface* getPolicy() override; virtual InputListenerInterface* getListener() override; virtual EventHubInterface* getEventHub() override; - virtual uint32_t getNextSequenceNum() override; + virtual int32_t getNextId() override; } mContext; friend class ContextImpl; @@ -132,8 +132,8 @@ private: InputReaderConfiguration mConfig; - // used by InputReaderContext::getNextSequenceNum() as a counter for event sequence numbers - uint32_t mNextSequenceNum; + // used by InputReaderContext::getNextId() as a counter for event sequence numbers + uint32_t mNextId; // The event queue. static const int EVENT_BUFFER_SIZE = 256; diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h index d5527cf926..85701e4f63 100644 --- a/services/inputflinger/reader/include/InputReaderContext.h +++ b/services/inputflinger/reader/include/InputReaderContext.h @@ -58,7 +58,7 @@ public: virtual InputListenerInterface* getListener() = 0; virtual EventHubInterface* getEventHub() = 0; - virtual uint32_t getNextSequenceNum() = 0; + virtual int32_t getNextId() = 0; }; } // namespace android diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index c4162bc510..887ab53c76 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -168,7 +168,7 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* } bumpGeneration(); if (changes) { - NotifyDeviceResetArgs args(getContext()->getNextSequenceNum(), when, getDeviceId()); + NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId()); getListener()->notifyDeviceReset(&args); } } @@ -374,8 +374,8 @@ void CursorInputMapper::sync(nsecs_t when) { while (!released.isEmpty()) { int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); buttonState &= ~actionButton; - NotifyMotionArgs releaseArgs(getContext()->getNextSequenceNum(), when, - getDeviceId(), mSource, displayId, policyFlags, + NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, getDeviceId(), + mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, @@ -386,11 +386,11 @@ void CursorInputMapper::sync(nsecs_t when) { } } - NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, motionEventAction, 0, 0, metaState, - currentButtonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, + NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId, + policyFlags, motionEventAction, 0, 0, metaState, currentButtonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, + &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, + xCursorPosition, yCursorPosition, downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); @@ -399,8 +399,8 @@ void CursorInputMapper::sync(nsecs_t when) { while (!pressed.isEmpty()) { int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit()); buttonState |= actionButton; - NotifyMotionArgs pressArgs(getContext()->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, + NotifyMotionArgs pressArgs(getContext()->getNextId(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, @@ -415,10 +415,9 @@ void CursorInputMapper::sync(nsecs_t when) { // Send hover move after UP to tell the application that the mouse is hovering now. if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) { - NotifyMotionArgs hoverArgs(getContext()->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, - currentButtonState, MotionClassification::NONE, + NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, + 0, metaState, currentButtonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, /* videoFrames */ {}); @@ -430,10 +429,9 @@ void CursorInputMapper::sync(nsecs_t when) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - NotifyMotionArgs scrollArgs(getContext()->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, - currentButtonState, MotionClassification::NONE, + NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, + metaState, currentButtonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, /* videoFrames */ {}); diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp index 7c3b1d9b40..030a846727 100644 --- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp +++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp @@ -333,10 +333,9 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { // TODO: Use the input device configuration to control this behavior more finely. uint32_t policyFlags = 0; - NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), - AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, + NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, + ADISPLAY_ID_NONE, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, + buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}); diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp index ab354a2e2b..7be4a58cc3 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp @@ -348,9 +348,8 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT; } - NotifyKeyArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, - getDisplayId(), policyFlags, - down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, + NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, getDisplayId(), + policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime); getListener()->notifyKey(&args); } diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp index ed93f14cea..98858897f4 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp @@ -119,9 +119,9 @@ void RotaryEncoderInputMapper::sync(nsecs_t when) { int32_t metaState = getContext()->getGlobalMetaState(); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor); - NotifyMotionArgs scrollArgs(getContext()->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, - 0, metaState, /* buttonState */ 0, MotionClassification::NONE, + NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, + metaState, /* buttonState */ 0, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}); diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp index e79aeb28c4..4f736810bc 100644 --- a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp @@ -56,7 +56,7 @@ void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) { void SwitchInputMapper::sync(nsecs_t when) { if (mUpdatedSwitchMask) { uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask; - NotifySwitchArgs args(getContext()->getNextSequenceNum(), when, 0 /*policyFlags*/, + NotifySwitchArgs args(getContext()->getNextId(), when, 0 /*policyFlags*/, updatedSwitchValues, mUpdatedSwitchMask); getListener()->notifySwitch(&args); diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h index efa3d6d2b2..2a3e2637f1 100644 --- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h +++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h @@ -65,8 +65,8 @@ static void synthesizeButtonKey(InputReaderContext* context, int32_t action, nse (currentButtonState & buttonState)) || (action == AKEY_EVENT_ACTION_UP && (lastButtonState & buttonState) && !(currentButtonState & buttonState))) { - NotifyKeyArgs args(context->getNextSequenceNum(), when, deviceId, source, displayId, - policyFlags, action, 0, keyCode, 0, context->getGlobalMetaState(), when); + NotifyKeyArgs args(context->getNextId(), when, deviceId, source, displayId, policyFlags, + action, 0, keyCode, 0, context->getGlobalMetaState(), when); context->getListener()->notifyKey(&args); } } diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 7543374ebd..bbc8e537c6 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -386,7 +386,7 @@ void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* c if (changes && resetNeeded) { // Send reset, unless this is the first time the device has been configured, // in which case the reader will call reset itself after all mappers are ready. - NotifyDeviceResetArgs args(getContext()->getNextSequenceNum(), when, getDeviceId()); + NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId()); getListener()->notifyDeviceReset(&args); } } @@ -1824,9 +1824,9 @@ void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t metaState = getContext()->getGlobalMetaState(); policyFlags |= POLICY_FLAG_VIRTUAL; - NotifyKeyArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), - AINPUT_SOURCE_KEYBOARD, mViewport.displayId, policyFlags, keyEventAction, - keyEventFlags, keyCode, scanCode, metaState, downTime); + NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, + mViewport.displayId, policyFlags, keyEventAction, keyEventFlags, keyCode, + scanCode, metaState, downTime); getListener()->notifyKey(&args); } @@ -2498,11 +2498,11 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); const int32_t displayId = mPointerController->getDisplayId(); - NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, - metaState, buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, - 0, 0, x, y, mPointerGesture.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId, + policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, + buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + 1, &pointerProperties, &pointerCoords, 0, 0, x, y, + mPointerGesture.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -3418,8 +3418,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.down = false; // Send up. - NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState, + NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId, + policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -3432,9 +3432,9 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.hovering = false; // Send hover exit. - NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, - metaState, mLastRawState.buttonState, MotionClassification::NONE, + NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId, + policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, + mLastRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, yCursorPosition, mPointerSimple.downTime, @@ -3448,7 +3448,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.downTime = when; // Send down. - NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, + NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, @@ -3459,8 +3459,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, } // Send move. - NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, + NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId, + policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, @@ -3474,7 +3474,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.hovering = true; // Send hover enter. - NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, + NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState, mCurrentRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, @@ -3485,9 +3485,9 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, } // Send hover move. - NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, - metaState, mCurrentRawState.buttonState, MotionClassification::NONE, + NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId, + policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, + mCurrentRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, yCursorPosition, @@ -3507,8 +3507,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, + NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId, + policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties, &pointerCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -3581,8 +3581,8 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32 std::vector frames = getDeviceContext().getVideoFrames(); std::for_each(frames.begin(), frames.end(), [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); }); - NotifyMotionArgs args(getContext()->getNextSequenceNum(), when, deviceId, source, displayId, - policyFlags, action, actionButton, flags, metaState, buttonState, + NotifyMotionArgs args(getContext()->getNextId(), when, deviceId, source, displayId, policyFlags, + action, actionButton, flags, metaState, buttonState, MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition, downTime, std::move(frames)); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index f05f7e5a79..270f891d36 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -89,7 +89,7 @@ public: void assertNotifySwitchWasCalled(const NotifySwitchArgs& args) { ASSERT_TRUE(mLastNotifySwitch); - // We do not check sequenceNum because it is not exposed to the policy + // We do not check id because it is not exposed to the policy EXPECT_EQ(args.eventTime, mLastNotifySwitch->eventTime); EXPECT_EQ(args.policyFlags, mLastNotifySwitch->policyFlags); EXPECT_EQ(args.switchValues, mLastNotifySwitch->switchValues); @@ -171,8 +171,7 @@ private: /** We simply reconstruct NotifySwitchArgs in policy because InputDispatcher is * essentially a passthrough for notifySwitch. */ - mLastNotifySwitch = - NotifySwitchArgs(1 /*sequenceNum*/, when, policyFlags, switchValues, switchMask); + mLastNotifySwitch = NotifySwitchArgs(1 /*id*/, when, policyFlags, switchValues, switchMask); } virtual void pokeUserActivity(nsecs_t, int32_t) { @@ -463,7 +462,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { TEST_F(InputDispatcherTest, NotifyConfigurationChanged_CallsPolicy) { constexpr nsecs_t eventTime = 20; - NotifyConfigurationChangedArgs args(10 /*sequenceNum*/, eventTime); + NotifyConfigurationChangedArgs args(10 /*id*/, eventTime); mDispatcher->notifyConfigurationChanged(&args); ASSERT_TRUE(mDispatcher->waitForIdle()); @@ -471,8 +470,8 @@ TEST_F(InputDispatcherTest, NotifyConfigurationChanged_CallsPolicy) { } TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) { - NotifySwitchArgs args(10 /*sequenceNum*/, 20 /*eventTime*/, 0 /*policyFlags*/, - 1 /*switchValues*/, 2 /*switchMask*/); + NotifySwitchArgs args(10 /*id*/, 20 /*eventTime*/, 0 /*policyFlags*/, 1 /*switchValues*/, + 2 /*switchMask*/); mDispatcher->notifySwitch(&args); // InputDispatcher adds POLICY_FLAG_TRUSTED because the event went through InputListener @@ -813,9 +812,9 @@ static int32_t injectMotionUp(const sp& dispatcher, int32_t sou static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) { nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid key event. - NotifyKeyArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, AINPUT_SOURCE_KEYBOARD, - displayId, POLICY_FLAG_PASS_TO_USER, action, /* flags */ 0, - AKEYCODE_A, KEY_A, AMETA_NONE, currentTime); + NotifyKeyArgs args(/* id */ 0, currentTime, DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId, + POLICY_FLAG_PASS_TO_USER, action, /* flags */ 0, AKEYCODE_A, KEY_A, + AMETA_NONE, currentTime); return args; } @@ -842,7 +841,7 @@ static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid motion event. - NotifyMotionArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, source, displayId, + NotifyMotionArgs args(/* id */ 0, currentTime, DEVICE_ID, source, displayId, POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties, @@ -1005,7 +1004,7 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) { // When device reset happens, that key stream should be terminated with FLAG_CANCELED // on the app side. - NotifyDeviceResetArgs args(10 /*sequenceNum*/, 20 /*eventTime*/, DEVICE_ID); + NotifyDeviceResetArgs args(10 /*id*/, 20 /*eventTime*/, DEVICE_ID); mDispatcher->notifyDeviceReset(&args); window->consumeEvent(AINPUT_EVENT_TYPE_KEY, AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT, AKEY_EVENT_FLAG_CANCELED); @@ -1028,7 +1027,7 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) { // When device reset happens, that motion stream should be terminated with ACTION_CANCEL // on the app side. - NotifyDeviceResetArgs args(10 /*sequenceNum*/, 20 /*eventTime*/, DEVICE_ID); + NotifyDeviceResetArgs args(10 /*id*/, 20 /*eventTime*/, DEVICE_ID); mDispatcher->notifyDeviceReset(&args); window->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, ADISPLAY_ID_DEFAULT, 0 /*expectedFlags*/); @@ -1353,7 +1352,7 @@ TEST_F(InputDispatcherTest, TestMoveEvent) { window->consumeMotionDown(ADISPLAY_ID_DEFAULT); motionArgs.action = AMOTION_EVENT_ACTION_MOVE; - motionArgs.sequenceNum += 1; + motionArgs.id += 1; motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC); motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, motionArgs.pointerCoords[0].getX() - 10); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 4da9d93890..46cd4809fc 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -846,7 +846,7 @@ class FakeInputReaderContext : public InputReaderContext { int32_t mGlobalMetaState; bool mUpdateGlobalMetaStateWasCalled; int32_t mGeneration; - uint32_t mNextSequenceNum; + int32_t mNextId; wp mPointerController; public: @@ -857,7 +857,7 @@ public: mPolicy(policy), mListener(listener), mGlobalMetaState(0), - mNextSequenceNum(1) {} + mNextId(1) {} virtual ~FakeInputReaderContext() { } @@ -941,9 +941,7 @@ private: } - virtual uint32_t getNextSequenceNum() { - return mNextSequenceNum++; - } + virtual int32_t getNextId() { return mNextId++; } }; @@ -1644,7 +1642,7 @@ TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { ASSERT_EQ(1, event.value); } -TEST_F(InputReaderTest, DeviceReset_IncrementsSequenceNumber) { +TEST_F(InputReaderTest, DeviceReset_IncrementsId) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; constexpr int32_t eventHubId = 1; @@ -1656,25 +1654,25 @@ TEST_F(InputReaderTest, DeviceReset_IncrementsSequenceNumber) { NotifyDeviceResetArgs resetArgs; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); - uint32_t prevSequenceNum = resetArgs.sequenceNum; + int32_t prevId = resetArgs.id; disableDevice(deviceId); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); - ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum); - prevSequenceNum = resetArgs.sequenceNum; + ASSERT_TRUE(prevId < resetArgs.id); + prevId = resetArgs.id; enableDevice(deviceId); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); - ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum); - prevSequenceNum = resetArgs.sequenceNum; + ASSERT_TRUE(prevId < resetArgs.id); + prevId = resetArgs.id; disableDevice(deviceId); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); - ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum); - prevSequenceNum = resetArgs.sequenceNum; + ASSERT_TRUE(prevId < resetArgs.id); + prevId = resetArgs.id; } TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { @@ -1816,21 +1814,21 @@ TEST_F(InputReaderIntegrationTest, SendsEventsToInputListener) { NotifyConfigurationChangedArgs configChangedArgs; ASSERT_NO_FATAL_FAILURE( mTestListener->assertNotifyConfigurationChangedWasCalled(&configChangedArgs)); - uint32_t prevSequenceNum = configChangedArgs.sequenceNum; + int32_t prevId = configChangedArgs.id; nsecs_t prevTimestamp = configChangedArgs.eventTime; NotifyKeyArgs keyArgs; keyboard->pressAndReleaseHomeKey(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_LT(prevSequenceNum, keyArgs.sequenceNum); - prevSequenceNum = keyArgs.sequenceNum; + ASSERT_LT(prevId, keyArgs.id); + prevId = keyArgs.id; ASSERT_LE(prevTimestamp, keyArgs.eventTime); prevTimestamp = keyArgs.eventTime; ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_LT(prevSequenceNum, keyArgs.sequenceNum); + ASSERT_LT(prevId, keyArgs.id); ASSERT_LE(prevTimestamp, keyArgs.eventTime); } -- GitLab From 1c7bc86a9b1bdf16b240a96d083102127f036325 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Tue, 28 Jan 2020 13:24:04 -0800 Subject: [PATCH 0843/1255] Let InputFlinger generate event IDs. Also send event IDs via InputMessage and add some atrace calls to form a complete chain of input event processing. Bug: 144889238 Test: systrace shows correct event IDs. Test: atest inputflinger_tests Change-Id: I3c561b03b0ba75c22115ae020e6b41855686ab64 Merged-In: I3c561b03b0ba75c22115ae020e6b41855686ab64 (cherry picked from commit ff1f1bb99489fd372c57908dafdd3817a33db0c5) --- include/input/InputTransport.h | 31 ++--- libs/input/InputTransport.cpp | 53 +++++---- .../tests/InputPublisherAndConsumer_test.cpp | 26 +++-- libs/input/tests/StructLayout_test.cpp | 9 +- services/inputflinger/Android.bp | 1 + services/inputflinger/InputListener.cpp | 18 +++ .../inputflinger/dispatcher/Connection.cpp | 4 +- services/inputflinger/dispatcher/Connection.h | 2 +- services/inputflinger/dispatcher/Entry.h | 10 +- .../dispatcher/InputDispatcher.cpp | 72 ++++++++---- .../inputflinger/dispatcher/InputDispatcher.h | 2 + .../inputflinger/dispatcher/InputState.cpp | 10 +- services/inputflinger/dispatcher/InputState.h | 4 +- services/inputflinger/reader/InputReader.cpp | 6 +- .../inputflinger/reader/include/InputReader.h | 4 +- .../tests/InputDispatcher_test.cpp | 109 ++++++++++++++++++ .../inputflinger/tests/InputReader_test.cpp | 27 ++++- 17 files changed, 293 insertions(+), 95 deletions(-) diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 06fd3bb364..8ca178c1d7 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -82,7 +82,7 @@ struct InputMessage { union Body { struct Key { uint32_t seq; - uint32_t empty1; + int32_t eventId; nsecs_t eventTime __attribute__((aligned(8))); int32_t deviceId; int32_t source; @@ -102,7 +102,7 @@ struct InputMessage { struct Motion { uint32_t seq; - uint32_t empty1; + int32_t eventId; nsecs_t eventTime __attribute__((aligned(8))); int32_t deviceId; int32_t source; @@ -159,6 +159,8 @@ struct InputMessage { struct Focus { uint32_t seq; + int32_t eventId; + uint32_t empty1; // The following two fields take up 4 bytes total uint16_t hasFocus; // actually a bool uint16_t inTouchMode; // actually a bool, but we must maintain 8-byte alignment @@ -276,9 +278,9 @@ public: * Returns BAD_VALUE if seq is 0. * Other errors probably indicate that the channel is broken. */ - status_t publishKeyEvent(uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, - std::array hmac, int32_t action, int32_t flags, - int32_t keyCode, int32_t scanCode, int32_t metaState, + status_t publishKeyEvent(uint32_t seq, int32_t eventId, int32_t deviceId, int32_t source, + int32_t displayId, std::array hmac, int32_t action, + int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime); /* Publishes a motion event to the input channel. @@ -289,14 +291,15 @@ public: * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS. * Other errors probably indicate that the channel is broken. */ - status_t publishMotionEvent(uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, - std::array hmac, int32_t action, int32_t actionButton, - int32_t flags, int32_t edgeFlags, int32_t metaState, - int32_t buttonState, MotionClassification classification, - float xScale, float yScale, float xOffset, float yOffset, - float xPrecision, float yPrecision, float xCursorPosition, - float yCursorPosition, nsecs_t downTime, nsecs_t eventTime, - uint32_t pointerCount, const PointerProperties* pointerProperties, + status_t publishMotionEvent(uint32_t seq, int32_t eventId, int32_t deviceId, int32_t source, + int32_t displayId, std::array hmac, int32_t action, + int32_t actionButton, int32_t flags, int32_t edgeFlags, + int32_t metaState, int32_t buttonState, + MotionClassification classification, float xScale, float yScale, + float xOffset, float yOffset, float xPrecision, float yPrecision, + float xCursorPosition, float yCursorPosition, nsecs_t downTime, + nsecs_t eventTime, uint32_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); /* Publishes a focus event to the input channel. @@ -306,7 +309,7 @@ public: * Returns DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ - status_t publishFocusEvent(uint32_t seq, bool hasFocus, bool inTouchMode); + status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, bool inTouchMode); /* Receives the finished signal from the consumer in reply to the original dispatch signal. * If a signal was received, returns the message sequence number, diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index eda01c5032..7335b30a49 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -63,10 +63,6 @@ static const nsecs_t RESAMPLE_MAX_DELTA = 20 * NANOS_PER_MS; // far into the future. This time is further bounded by 50% of the last time delta. static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS; -// A placeholder sequence number used to initialize native input events before InputFlinger is -// migrated to new sequence number system. -static constexpr int32_t INPUT_FLINGER_SEQUENCE_NUM = 0; - /** * System property for enabling / disabling touch resampling. * Resampling extrapolates / interpolates the reported touch event coordinates to better @@ -143,6 +139,8 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { case InputMessage::Type::KEY: { // uint32_t seq msg->body.key.seq = body.key.seq; + // int32_t eventId + msg->body.key.eventId = body.key.eventId; // nsecs_t eventTime msg->body.key.eventTime = body.key.eventTime; // int32_t deviceId @@ -172,6 +170,8 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { case InputMessage::Type::MOTION: { // uint32_t seq msg->body.motion.seq = body.motion.seq; + // int32_t eventId + msg->body.motion.eventId = body.motion.eventId; // nsecs_t eventTime msg->body.motion.eventTime = body.motion.eventTime; // int32_t deviceId @@ -238,6 +238,7 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { } case InputMessage::Type::FOCUS: { msg->body.focus.seq = body.focus.seq; + msg->body.focus.eventId = body.focus.eventId; msg->body.focus.hasFocus = body.focus.hasFocus; msg->body.focus.inTouchMode = body.focus.inTouchMode; break; @@ -436,11 +437,12 @@ InputPublisher::InputPublisher(const sp& channel) : InputPublisher::~InputPublisher() { } -status_t InputPublisher::publishKeyEvent(uint32_t seq, int32_t deviceId, int32_t source, - int32_t displayId, std::array hmac, - int32_t action, int32_t flags, int32_t keyCode, - int32_t scanCode, int32_t metaState, int32_t repeatCount, - nsecs_t downTime, nsecs_t eventTime) { +status_t InputPublisher::publishKeyEvent(uint32_t seq, int32_t eventId, int32_t deviceId, + int32_t source, int32_t displayId, + std::array hmac, int32_t action, + int32_t flags, int32_t keyCode, int32_t scanCode, + int32_t metaState, int32_t repeatCount, nsecs_t downTime, + nsecs_t eventTime) { if (ATRACE_ENABLED()) { std::string message = StringPrintf("publishKeyEvent(inputChannel=%s, keyCode=%" PRId32 ")", mChannel->getName().c_str(), keyCode); @@ -462,6 +464,7 @@ status_t InputPublisher::publishKeyEvent(uint32_t seq, int32_t deviceId, int32_t InputMessage msg; msg.header.type = InputMessage::Type::KEY; msg.body.key.seq = seq; + msg.body.key.eventId = eventId; msg.body.key.deviceId = deviceId; msg.body.key.source = source; msg.body.key.displayId = displayId; @@ -478,7 +481,7 @@ status_t InputPublisher::publishKeyEvent(uint32_t seq, int32_t deviceId, int32_t } status_t InputPublisher::publishMotionEvent( - uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, + uint32_t seq, int32_t eventId, int32_t deviceId, int32_t source, int32_t displayId, std::array hmac, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, float xScale, float yScale, float xOffset, @@ -519,6 +522,7 @@ status_t InputPublisher::publishMotionEvent( InputMessage msg; msg.header.type = InputMessage::Type::MOTION; msg.body.motion.seq = seq; + msg.body.motion.eventId = eventId; msg.body.motion.deviceId = deviceId; msg.body.motion.source = source; msg.body.motion.displayId = displayId; @@ -549,7 +553,8 @@ status_t InputPublisher::publishMotionEvent( return mChannel->sendMessage(&msg); } -status_t InputPublisher::publishFocusEvent(uint32_t seq, bool hasFocus, bool inTouchMode) { +status_t InputPublisher::publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, + bool inTouchMode) { if (ATRACE_ENABLED()) { std::string message = StringPrintf("publishFocusEvent(inputChannel=%s, hasFocus=%s, inTouchMode=%s)", @@ -561,6 +566,7 @@ status_t InputPublisher::publishFocusEvent(uint32_t seq, bool hasFocus, bool inT InputMessage msg; msg.header.type = InputMessage::Type::FOCUS; msg.body.focus.seq = seq; + msg.body.focus.eventId = eventId; msg.body.focus.hasFocus = hasFocus ? 1 : 0; msg.body.focus.inTouchMode = inTouchMode ? 1 : 0; return mChannel->sendMessage(&msg); @@ -1146,7 +1152,7 @@ ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const { } void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) { - event->initialize(INPUT_FLINGER_SEQUENCE_NUM, msg->body.key.deviceId, msg->body.key.source, + event->initialize(msg->body.key.eventId, msg->body.key.deviceId, msg->body.key.source, msg->body.key.displayId, msg->body.key.hmac, msg->body.key.action, msg->body.key.flags, msg->body.key.keyCode, msg->body.key.scanCode, msg->body.key.metaState, msg->body.key.repeatCount, msg->body.key.downTime, @@ -1154,7 +1160,7 @@ void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) } void InputConsumer::initializeFocusEvent(FocusEvent* event, const InputMessage* msg) { - event->initialize(INPUT_FLINGER_SEQUENCE_NUM, msg->body.focus.hasFocus == 1, + event->initialize(msg->body.focus.eventId, msg->body.focus.hasFocus == 1, msg->body.focus.inTouchMode == 1); } @@ -1167,17 +1173,16 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); } - event->initialize(INPUT_FLINGER_SEQUENCE_NUM, msg->body.motion.deviceId, - msg->body.motion.source, msg->body.motion.displayId, msg->body.motion.hmac, - msg->body.motion.action, msg->body.motion.actionButton, - msg->body.motion.flags, msg->body.motion.edgeFlags, - msg->body.motion.metaState, msg->body.motion.buttonState, - msg->body.motion.classification, msg->body.motion.xScale, - msg->body.motion.yScale, msg->body.motion.xOffset, msg->body.motion.yOffset, - msg->body.motion.xPrecision, msg->body.motion.yPrecision, - msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition, - msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount, - pointerProperties, pointerCoords); + event->initialize(msg->body.motion.eventId, msg->body.motion.deviceId, msg->body.motion.source, + msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action, + msg->body.motion.actionButton, msg->body.motion.flags, + msg->body.motion.edgeFlags, msg->body.motion.metaState, + msg->body.motion.buttonState, msg->body.motion.classification, + msg->body.motion.xScale, msg->body.motion.yScale, msg->body.motion.xOffset, + msg->body.motion.yOffset, msg->body.motion.xPrecision, + msg->body.motion.yPrecision, msg->body.motion.xCursorPosition, + msg->body.motion.yCursorPosition, msg->body.motion.downTime, + msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords); } void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) { diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 885196f3f3..8e2eec85ed 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -73,6 +73,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { status_t status; constexpr uint32_t seq = 15; + int32_t eventId = InputEvent::nextId(); constexpr int32_t deviceId = 1; constexpr uint32_t source = AINPUT_SOURCE_KEYBOARD; constexpr int32_t displayId = ADISPLAY_ID_DEFAULT; @@ -88,8 +89,8 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { constexpr nsecs_t downTime = 3; constexpr nsecs_t eventTime = 4; - status = mPublisher->publishKeyEvent(seq, deviceId, source, displayId, hmac, action, flags, - keyCode, scanCode, metaState, repeatCount, downTime, + status = mPublisher->publishKeyEvent(seq, eventId, deviceId, source, displayId, hmac, action, + flags, keyCode, scanCode, metaState, repeatCount, downTime, eventTime); ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK"; @@ -107,6 +108,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { KeyEvent* keyEvent = static_cast(event); EXPECT_EQ(seq, consumeSeq); + EXPECT_EQ(eventId, keyEvent->getId()); EXPECT_EQ(deviceId, keyEvent->getDeviceId()); EXPECT_EQ(source, keyEvent->getSource()); EXPECT_EQ(displayId, keyEvent->getDisplayId()); @@ -139,6 +141,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { status_t status; constexpr uint32_t seq = 15; + int32_t eventId = InputEvent::nextId(); constexpr int32_t deviceId = 1; constexpr uint32_t source = AINPUT_SOURCE_TOUCHSCREEN; constexpr int32_t displayId = ADISPLAY_ID_DEFAULT; @@ -182,7 +185,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i); } - status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, hmac, action, + status = mPublisher->publishMotionEvent(seq, eventId, deviceId, source, displayId, hmac, action, actionButton, flags, edgeFlags, metaState, buttonState, classification, xScale, yScale, xOffset, yOffset, xPrecision, yPrecision, xCursorPosition, @@ -204,6 +207,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { MotionEvent* motionEvent = static_cast(event); EXPECT_EQ(seq, consumeSeq); + EXPECT_EQ(eventId, motionEvent->getId()); EXPECT_EQ(deviceId, motionEvent->getDeviceId()); EXPECT_EQ(source, motionEvent->getSource()); EXPECT_EQ(displayId, motionEvent->getDisplayId()); @@ -277,10 +281,11 @@ void InputPublisherAndConsumerTest::PublishAndConsumeFocusEvent() { status_t status; constexpr uint32_t seq = 15; + int32_t eventId = InputEvent::nextId(); constexpr bool hasFocus = true; constexpr bool inTouchMode = true; - status = mPublisher->publishFocusEvent(seq, hasFocus, inTouchMode); + status = mPublisher->publishFocusEvent(seq, eventId, hasFocus, inTouchMode); ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK"; uint32_t consumeSeq; @@ -294,6 +299,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeFocusEvent() { FocusEvent* focusEvent = static_cast(event); EXPECT_EQ(seq, consumeSeq); + EXPECT_EQ(eventId, focusEvent->getId()); EXPECT_EQ(hasFocus, focusEvent->getHasFocus()); EXPECT_EQ(inTouchMode, focusEvent->getInTouchMode()); @@ -332,8 +338,8 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZer pointerCoords[i].clear(); } - status = mPublisher->publishMotionEvent(0, 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0, - MotionClassification::NONE, 1 /* xScale */, + status = mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, + 0, 0, 0, MotionClassification::NONE, 1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, @@ -348,8 +354,8 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; - status = mPublisher->publishMotionEvent(1, 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0, - MotionClassification::NONE, 1 /* xScale */, + status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, + 0, 0, 0, MotionClassification::NONE, 1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, @@ -369,8 +375,8 @@ TEST_F(InputPublisherAndConsumerTest, pointerCoords[i].clear(); } - status = mPublisher->publishMotionEvent(1, 0, 0, 0, INVALID_HMAC, 0, 0, 0, 0, 0, 0, - MotionClassification::NONE, 1 /* xScale */, + status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0, + 0, 0, 0, MotionClassification::NONE, 1 /* xScale */, 1 /* yScale */, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index dd127fcabd..1fe7bb90ca 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -35,6 +35,7 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage, body, 8); CHECK_OFFSET(InputMessage::Body::Key, seq, 0); + CHECK_OFFSET(InputMessage::Body::Key, eventId, 4); CHECK_OFFSET(InputMessage::Body::Key, eventTime, 8); CHECK_OFFSET(InputMessage::Body::Key, deviceId, 16); CHECK_OFFSET(InputMessage::Body::Key, source, 20); @@ -49,6 +50,7 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Key, downTime, 88); CHECK_OFFSET(InputMessage::Body::Motion, seq, 0); + CHECK_OFFSET(InputMessage::Body::Motion, eventId, 4); CHECK_OFFSET(InputMessage::Body::Motion, eventTime, 8); CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16); CHECK_OFFSET(InputMessage::Body::Motion, source, 20); @@ -74,8 +76,9 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Motion, pointers, 136); CHECK_OFFSET(InputMessage::Body::Focus, seq, 0); - CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4); - CHECK_OFFSET(InputMessage::Body::Focus, inTouchMode, 6); + CHECK_OFFSET(InputMessage::Body::Focus, eventId, 4); + CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 12); + CHECK_OFFSET(InputMessage::Body::Focus, inTouchMode, 14); CHECK_OFFSET(InputMessage::Body::Finished, seq, 0); CHECK_OFFSET(InputMessage::Body::Finished, handled, 4); @@ -95,7 +98,7 @@ void TestBodySize() { offsetof(InputMessage::Body::Motion, pointers) + sizeof(InputMessage::Body::Motion::Pointer) * MAX_POINTERS); static_assert(sizeof(InputMessage::Body::Finished) == 8); - static_assert(sizeof(InputMessage::Body::Focus) == 8); + static_assert(sizeof(InputMessage::Body::Focus) == 16); } // --- VerifiedInputEvent --- diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 439d9bf312..4ec4e25010 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -108,6 +108,7 @@ cc_defaults { srcs: [":libinputflinger_base_sources"], shared_libs: [ "libbase", + "libcutils", "libinput", "liblog", "libutils", diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp index e91e803fb8..84838ec8a7 100644 --- a/services/inputflinger/InputListener.cpp +++ b/services/inputflinger/InputListener.cpp @@ -16,12 +16,18 @@ #define LOG_TAG "InputListener" +#define ATRACE_TAG ATRACE_TAG_INPUT + //#define LOG_NDEBUG 0 #include "InputListener.h" +#include #include #include +#include + +using android::base::StringPrintf; namespace android { @@ -228,6 +234,13 @@ void NotifyDeviceResetArgs::notify(const sp& listener) c // --- QueuedInputListener --- +static inline void traceEvent(const char* functionName, int32_t id) { + if (ATRACE_ENABLED()) { + std::string message = StringPrintf("%s(id=0x%" PRIx32 ")", functionName, id); + ATRACE_NAME(message.c_str()); + } +} + QueuedInputListener::QueuedInputListener(const sp& innerListener) : mInnerListener(innerListener) { } @@ -241,22 +254,27 @@ QueuedInputListener::~QueuedInputListener() { void QueuedInputListener::notifyConfigurationChanged( const NotifyConfigurationChangedArgs* args) { + traceEvent(__func__, args->id); mArgsQueue.push_back(new NotifyConfigurationChangedArgs(*args)); } void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) { + traceEvent(__func__, args->id); mArgsQueue.push_back(new NotifyKeyArgs(*args)); } void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { + traceEvent(__func__, args->id); mArgsQueue.push_back(new NotifyMotionArgs(*args)); } void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) { + traceEvent(__func__, args->id); mArgsQueue.push_back(new NotifySwitchArgs(*args)); } void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) { + traceEvent(__func__, args->id); mArgsQueue.push_back(new NotifyDeviceResetArgs(*args)); } diff --git a/services/inputflinger/dispatcher/Connection.cpp b/services/inputflinger/dispatcher/Connection.cpp index 6f82f4fd10..188212bccf 100644 --- a/services/inputflinger/dispatcher/Connection.cpp +++ b/services/inputflinger/dispatcher/Connection.cpp @@ -20,11 +20,13 @@ namespace android::inputdispatcher { -Connection::Connection(const sp& inputChannel, bool monitor) +Connection::Connection(const sp& inputChannel, bool monitor, + const IdGenerator& idGenerator) : status(STATUS_NORMAL), inputChannel(inputChannel), monitor(monitor), inputPublisher(inputChannel), + inputState(idGenerator), inputPublisherBlocked(false) {} Connection::~Connection() {} diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h index 8423010502..bb3f2fee19 100644 --- a/services/inputflinger/dispatcher/Connection.h +++ b/services/inputflinger/dispatcher/Connection.h @@ -58,7 +58,7 @@ public: // yet received a "finished" response from the application. std::deque waitQueue; - explicit Connection(const sp& inputChannel, bool monitor); + Connection(const sp& inputChannel, bool monitor, const IdGenerator& idGenerator); inline const std::string getInputChannelName() const { return inputChannel->getName(); } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index c58ae23cc5..ab481bd411 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -29,9 +29,6 @@ namespace android::inputdispatcher { -// Sequence number for synthesized or injected events. -constexpr int32_t SYNTHESIZED_EVENT_ID = 0; - struct EventEntry { enum class Type { CONFIGURATION_CHANGED, @@ -78,7 +75,9 @@ struct EventEntry { * Key repeat is a synthesized event, because it is related to an actual hardware state * (a key is currently pressed), but the repeat itself is generated by the framework. */ - inline bool isSynthesized() const { return isInjected() || id == SYNTHESIZED_EVENT_ID; } + inline bool isSynthesized() const { + return isInjected() || IdGenerator::getSource(id) != IdGenerator::Source::INPUT_READER; + } void release(); @@ -199,7 +198,8 @@ struct DispatchEntry { float windowYScale = 1.0f; nsecs_t deliveryTime; // time when the event was actually delivered - // Set to the resolved action and flags when the event is enqueued. + // Set to the resolved ID, action and flags when the event is enqueued. + int32_t resolvedEventId; int32_t resolvedAction; int32_t resolvedFlags; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 2f7b5ad9e6..308d19b085 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -383,6 +383,7 @@ InputDispatcher::InputDispatcher(const sp& polic : mPolicy(policy), mPendingEvent(nullptr), mLastDropReason(DropReason::NOT_DROPPED), + mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), mNextUnblockedEvent(nullptr), @@ -925,12 +926,13 @@ KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { (POLICY_FLAG_RAW_MASK | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED); if (entry->refCount == 1) { entry->recycle(); + entry->id = mIdGenerator.nextId(); entry->eventTime = currentTime; entry->policyFlags = policyFlags; entry->repeatCount += 1; } else { KeyEntry* newEntry = - new KeyEntry(SYNTHESIZED_EVENT_ID, currentTime, entry->deviceId, entry->source, + new KeyEntry(mIdGenerator.nextId(), currentTime, entry->deviceId, entry->source, entry->displayId, policyFlags, entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount + 1, entry->downTime); @@ -981,7 +983,7 @@ bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime, DeviceReset void InputDispatcher::enqueueFocusEventLocked(const InputWindowHandle& window, bool hasFocus) { FocusEntry* focusEntry = - new FocusEntry(SYNTHESIZED_EVENT_ID, now(), window.getToken(), hasFocus); + new FocusEntry(mIdGenerator.nextId(), now(), window.getToken(), hasFocus); enqueueInboundEventLocked(focusEntry); } @@ -2188,7 +2190,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const InputTarget& inputTarget) { if (ATRACE_ENABLED()) { std::string message = - StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, id=%" PRIx32 ")", + StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, id=0x%" PRIx32 ")", connection->getInputChannelName().c_str(), eventEntry->id); ATRACE_NAME(message.c_str()); } @@ -2244,7 +2246,7 @@ void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const InputTarget& inputTarget) { if (ATRACE_ENABLED()) { std::string message = - StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, id=%" PRIx32 ")", + StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, id=0x%" PRIx32 ")", connection->getInputChannelName().c_str(), eventEntry->id); ATRACE_NAME(message.c_str()); } @@ -2299,6 +2301,7 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp& connectio switch (newEntry->type) { case EventEntry::Type::KEY: { const KeyEntry& keyEntry = static_cast(*newEntry); + dispatchEntry->resolvedEventId = keyEntry.id; dispatchEntry->resolvedAction = keyEntry.action; dispatchEntry->resolvedFlags = keyEntry.flags; @@ -2315,6 +2318,11 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp& connectio case EventEntry::Type::MOTION: { const MotionEntry& motionEntry = static_cast(*newEntry); + // Assign a default value to dispatchEntry that will never be generated by InputReader, + // and assign a InputDispatcher value if it doesn't change in the if-else chain below. + constexpr int32_t DEFAULT_RESOLVED_EVENT_ID = + static_cast(IdGenerator::Source::OTHER); + dispatchEntry->resolvedEventId = DEFAULT_RESOLVED_EVENT_ID; if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE; } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) { @@ -2327,6 +2335,7 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp& connectio dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN; } else { dispatchEntry->resolvedAction = motionEntry.action; + dispatchEntry->resolvedEventId = motionEntry.id; } if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE && !connection->inputState.isHovering(motionEntry.deviceId, motionEntry.source, @@ -2357,6 +2366,17 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp& connectio return; // skip the inconsistent event } + dispatchEntry->resolvedEventId = + dispatchEntry->resolvedEventId == DEFAULT_RESOLVED_EVENT_ID + ? mIdGenerator.nextId() + : motionEntry.id; + if (ATRACE_ENABLED() && dispatchEntry->resolvedEventId != motionEntry.id) { + std::string message = StringPrintf("Transmute MotionEvent(id=0x%" PRIx32 + ") to MotionEvent(id=0x%" PRIx32 ").", + motionEntry.id, dispatchEntry->resolvedEventId); + ATRACE_NAME(message.c_str()); + } + dispatchPointerDownOutsideFocus(motionEntry.source, dispatchEntry->resolvedAction, inputTarget.inputChannel->getConnectionToken()); @@ -2438,14 +2458,16 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, std::array hmac = mHmacKeyManager.sign(verifiedEvent); // Publish the key event. - status = connection->inputPublisher - .publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId, - keyEntry->source, keyEntry->displayId, - std::move(hmac), dispatchEntry->resolvedAction, - dispatchEntry->resolvedFlags, keyEntry->keyCode, - keyEntry->scanCode, keyEntry->metaState, - keyEntry->repeatCount, keyEntry->downTime, - keyEntry->eventTime); + status = + connection->inputPublisher + .publishKeyEvent(dispatchEntry->seq, dispatchEntry->resolvedEventId, + keyEntry->deviceId, keyEntry->source, + keyEntry->displayId, std::move(hmac), + dispatchEntry->resolvedAction, + dispatchEntry->resolvedFlags, keyEntry->keyCode, + keyEntry->scanCode, keyEntry->metaState, + keyEntry->repeatCount, keyEntry->downTime, + keyEntry->eventTime); break; } @@ -2494,9 +2516,11 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, // Publish the motion event. status = connection->inputPublisher - .publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, - motionEntry->source, motionEntry->displayId, - std::move(hmac), dispatchEntry->resolvedAction, + .publishMotionEvent(dispatchEntry->seq, + dispatchEntry->resolvedEventId, + motionEntry->deviceId, motionEntry->source, + motionEntry->displayId, std::move(hmac), + dispatchEntry->resolvedAction, motionEntry->actionButton, dispatchEntry->resolvedFlags, motionEntry->edgeFlags, motionEntry->metaState, @@ -2515,6 +2539,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, case EventEntry::Type::FOCUS: { FocusEntry* focusEntry = static_cast(eventEntry); status = connection->inputPublisher.publishFocusEvent(dispatchEntry->seq, + focusEntry->id, focusEntry->hasFocus, mInTouchMode); break; @@ -2920,10 +2945,17 @@ MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry& originalMotion } } + int32_t newId = mIdGenerator.nextId(); + if (ATRACE_ENABLED()) { + std::string message = StringPrintf("Split MotionEvent(id=0x%" PRIx32 + ") to MotionEvent(id=0x%" PRIx32 ").", + originalMotionEntry.id, newId); + ATRACE_NAME(message.c_str()); + } MotionEntry* splitMotionEntry = - new MotionEntry(originalMotionEntry.id, originalMotionEntry.eventTime, - originalMotionEntry.deviceId, originalMotionEntry.source, - originalMotionEntry.displayId, originalMotionEntry.policyFlags, action, + new MotionEntry(newId, originalMotionEntry.eventTime, originalMotionEntry.deviceId, + originalMotionEntry.source, originalMotionEntry.displayId, + originalMotionEntry.policyFlags, action, originalMotionEntry.actionButton, originalMotionEntry.flags, originalMotionEntry.metaState, originalMotionEntry.buttonState, originalMotionEntry.classification, originalMotionEntry.edgeFlags, @@ -4225,7 +4257,7 @@ status_t InputDispatcher::registerInputChannel(const sp& inputChan return BAD_VALUE; } - sp connection = new Connection(inputChannel, false /*monitor*/); + sp connection = new Connection(inputChannel, false /*monitor*/, mIdGenerator); int fd = inputChannel->getFd(); mConnectionsByFd[fd] = connection; @@ -4254,7 +4286,7 @@ status_t InputDispatcher::registerInputMonitor(const sp& inputChan return BAD_VALUE; } - sp connection = new Connection(inputChannel, true /*monitor*/); + sp connection = new Connection(inputChannel, true /*monitor*/, mIdGenerator); const int fd = inputChannel->getFd(); mConnectionsByFd[fd] = connection; diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 482133ee90..4aa47f89f0 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -156,6 +156,8 @@ private: DropReason mLastDropReason GUARDED_BY(mLock); + const IdGenerator mIdGenerator; + // With each iteration, InputDispatcher nominally processes one queued event, // a timeout, or a response from an input consumer. // This method should only be called on the input dispatcher's own thread. diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index 7fa9e09aad..386056d9b2 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -16,9 +16,11 @@ #include "InputState.h" +#include "InputDispatcher.h" + namespace android::inputdispatcher { -InputState::InputState() {} +InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerator) {} InputState::~InputState() {} @@ -268,7 +270,7 @@ std::vector InputState::synthesizeCancelationEvents( std::vector events; for (KeyMemento& memento : mKeyMementos) { if (shouldCancelKey(memento, options)) { - events.push_back(new KeyEntry(SYNTHESIZED_EVENT_ID, currentTime, memento.deviceId, + events.push_back(new KeyEntry(mIdGenerator.nextId(), currentTime, memento.deviceId, memento.source, memento.displayId, memento.policyFlags, AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED, memento.keyCode, @@ -281,7 +283,7 @@ std::vector InputState::synthesizeCancelationEvents( if (shouldCancelMotion(memento, options)) { const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL; - events.push_back(new MotionEntry(SYNTHESIZED_EVENT_ID, currentTime, memento.deviceId, + events.push_back(new MotionEntry(mIdGenerator.nextId(), currentTime, memento.deviceId, memento.source, memento.displayId, memento.policyFlags, action, 0 /*actionButton*/, memento.flags, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, @@ -331,7 +333,7 @@ std::vector InputState::synthesizePointerDownEvents(nsecs_t current : AMOTION_EVENT_ACTION_POINTER_DOWN | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); - events.push_back(new MotionEntry(SYNTHESIZED_EVENT_ID, currentTime, memento.deviceId, + events.push_back(new MotionEntry(mIdGenerator.nextId(), currentTime, memento.deviceId, memento.source, memento.displayId, memento.policyFlags, action, 0 /*actionButton*/, memento.flags, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h index 08266ae9cd..d97a664d74 100644 --- a/services/inputflinger/dispatcher/InputState.h +++ b/services/inputflinger/dispatcher/InputState.h @@ -30,7 +30,7 @@ static constexpr int32_t INVALID_POINTER_INDEX = -1; * synthesized when events are dropped. */ class InputState { public: - InputState(); + explicit InputState(const IdGenerator& idGenerator); ~InputState(); // Returns true if there is no state to be canceled. @@ -111,6 +111,8 @@ private: void mergePointerStateTo(MotionMemento& other) const; }; + const IdGenerator& mIdGenerator; // InputDispatcher owns it so we won't have dangling reference. + std::vector mKeyMementos; std::vector mMotionMementos; KeyedVector mFallbackKeys; diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 2998cc9619..657a134865 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -46,7 +46,6 @@ InputReader::InputReader(std::shared_ptr eventHub, : mContext(this), mEventHub(eventHub), mPolicy(policy), - mNextId(1), mGlobalMetaState(0), mGeneration(1), mNextInputDeviceId(END_RESERVED_ID), @@ -697,7 +696,8 @@ void InputReader::monitor() { // --- InputReader::ContextImpl --- -InputReader::ContextImpl::ContextImpl(InputReader* reader) : mReader(reader) {} +InputReader::ContextImpl::ContextImpl(InputReader* reader) + : mReader(reader), mIdGenerator(IdGenerator::Source::INPUT_READER) {} void InputReader::ContextImpl::updateGlobalMetaState() { // lock is already held by the input loop @@ -762,7 +762,7 @@ EventHubInterface* InputReader::ContextImpl::getEventHub() { } int32_t InputReader::ContextImpl::getNextId() { - return (mReader->mNextId)++; + return mIdGenerator.nextId(); } } // namespace android diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index eaa105a8f6..693ec30b7d 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -94,6 +94,7 @@ protected: class ContextImpl : public InputReaderContext { InputReader* mReader; + IdGenerator mIdGenerator; public: explicit ContextImpl(InputReader* reader); @@ -132,9 +133,6 @@ private: InputReaderConfiguration mConfig; - // used by InputReaderContext::getNextId() as a counter for event sequence numbers - uint32_t mNextId; - // The event queue. static const int EVENT_BUFFER_SIZE = 256; RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 270f891d36..d30c4f1635 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -16,13 +16,18 @@ #include "../dispatcher/InputDispatcher.h" +#include #include #include #include #include +#include +#include #include +using android::base::StringPrintf; + namespace android::inputdispatcher { // An arbitrary time value. @@ -107,6 +112,11 @@ public: << "Expected onPointerDownOutsideFocus to not have been called"; } + void setKeyRepeatConfiguration(nsecs_t timeout, nsecs_t delay) { + mConfig.keyRepeatTimeout = timeout; + mConfig.keyRepeatDelay = delay; + } + private: std::unique_ptr mFilteredEvent; std::optional mConfigurationChangedTime; @@ -1443,6 +1453,105 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { ASSERT_EQ(0, verifiedKey.repeatCount); } +class InputDispatcherKeyRepeatTest : public InputDispatcherTest { +protected: + static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms + static constexpr nsecs_t KEY_REPEAT_DELAY = 40 * 1000000; // 40 ms + + sp mApp; + sp mWindow; + + virtual void SetUp() override { + mFakePolicy = new FakeInputDispatcherPolicy(); + mFakePolicy->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY); + mDispatcher = new InputDispatcher(mFakePolicy); + mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); + ASSERT_EQ(OK, mDispatcher->start()); + + setUpWindow(); + } + + void setUpWindow() { + mApp = new FakeApplicationHandle(); + mWindow = new FakeWindowHandle(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + + mWindow->setFocus(true); + mDispatcher->setInputWindows({mWindow}, ADISPLAY_ID_DEFAULT); + + mWindow->consumeFocusEvent(true); + } + + void sendAndConsumeKeyDown() { + NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); + keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event + mDispatcher->notifyKey(&keyArgs); + + // Window should receive key down event. + mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); + } + + void expectKeyRepeatOnce(int32_t repeatCount) { + SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount)); + InputEvent* repeatEvent = mWindow->consume(); + ASSERT_NE(nullptr, repeatEvent); + + uint32_t eventType = repeatEvent->getType(); + ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, eventType); + + KeyEvent* repeatKeyEvent = static_cast(repeatEvent); + uint32_t eventAction = repeatKeyEvent->getAction(); + EXPECT_EQ(AKEY_EVENT_ACTION_DOWN, eventAction); + EXPECT_EQ(repeatCount, repeatKeyEvent->getRepeatCount()); + } + + void sendAndConsumeKeyUp() { + NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); + keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event + mDispatcher->notifyKey(&keyArgs); + + // Window should receive key down event. + mWindow->consumeEvent(AINPUT_EVENT_TYPE_KEY, AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT, + 0 /*expectedFlags*/); + } +}; + +TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) { + sendAndConsumeKeyDown(); + for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { + expectKeyRepeatOnce(repeatCount); + } +} + +TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) { + sendAndConsumeKeyDown(); + expectKeyRepeatOnce(1 /*repeatCount*/); + sendAndConsumeKeyUp(); + mWindow->assertNoEvents(); +} + +TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) { + sendAndConsumeKeyDown(); + for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { + InputEvent* repeatEvent = mWindow->consume(); + ASSERT_NE(nullptr, repeatEvent) << "Didn't receive event with repeat count " << repeatCount; + EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER, + IdGenerator::getSource(repeatEvent->getId())); + } +} + +TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) { + sendAndConsumeKeyDown(); + + std::unordered_set idSet; + for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { + InputEvent* repeatEvent = mWindow->consume(); + ASSERT_NE(nullptr, repeatEvent) << "Didn't receive event with repeat count " << repeatCount; + int32_t id = repeatEvent->getId(); + EXPECT_EQ(idSet.end(), idSet.find(id)); + idSet.insert(id); + } +} + /* Test InputDispatcher for MultiDisplay */ class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest { public: diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 46cd4809fc..3ae8b56c11 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1642,7 +1642,7 @@ TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { ASSERT_EQ(1, event.value); } -TEST_F(InputReaderTest, DeviceReset_IncrementsId) { +TEST_F(InputReaderTest, DeviceReset_RandomId) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; constexpr int32_t eventHubId = 1; @@ -1659,22 +1659,37 @@ TEST_F(InputReaderTest, DeviceReset_IncrementsId) { disableDevice(deviceId); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); - ASSERT_TRUE(prevId < resetArgs.id); + ASSERT_NE(prevId, resetArgs.id); prevId = resetArgs.id; enableDevice(deviceId); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); - ASSERT_TRUE(prevId < resetArgs.id); + ASSERT_NE(prevId, resetArgs.id); prevId = resetArgs.id; disableDevice(deviceId); mReader->loopOnce(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); - ASSERT_TRUE(prevId < resetArgs.id); + ASSERT_NE(prevId, resetArgs.id); prevId = resetArgs.id; } +TEST_F(InputReaderTest, DeviceReset_GenerateIdWithInputReaderSource) { + constexpr int32_t deviceId = 1; + constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; + constexpr int32_t eventHubId = 1; + std::shared_ptr device = mReader->newDevice(deviceId, "fake"); + // Must add at least one mapper or the device will be ignored! + device->addMapper(eventHubId, AINPUT_SOURCE_KEYBOARD); + mReader->setNextDevice(device); + ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr)); + + NotifyDeviceResetArgs resetArgs; + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); + ASSERT_EQ(IdGenerator::Source::INPUT_READER, IdGenerator::getSource(resetArgs.id)); +} + TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD; @@ -1821,14 +1836,14 @@ TEST_F(InputReaderIntegrationTest, SendsEventsToInputListener) { keyboard->pressAndReleaseHomeKey(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); - ASSERT_LT(prevId, keyArgs.id); + ASSERT_NE(prevId, keyArgs.id); prevId = keyArgs.id; ASSERT_LE(prevTimestamp, keyArgs.eventTime); prevTimestamp = keyArgs.eventTime; ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); - ASSERT_LT(prevId, keyArgs.id); + ASSERT_NE(prevId, keyArgs.id); ASSERT_LE(prevTimestamp, keyArgs.eventTime); } -- GitLab From 187f68db0dd9fdf369224de3875792b9bb0498c0 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 20 Feb 2020 11:01:37 -0800 Subject: [PATCH 0844/1255] gralloc4: Support RAW plane type RAW12 and RAW16 buffers will have a PlaneLayoutComponentType of type RAW. Update getPlaneLayoutComponentTypeName to include the new type. Test: Gralloc4_test Bug: 149869426 Change-Id: Ib10b7d2c4dc3e7a68fc235391829ae7d6c6b2ea8 --- libs/gralloc/types/Gralloc4.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp index 603e7e559f..53c68b7230 100644 --- a/libs/gralloc/types/Gralloc4.cpp +++ b/libs/gralloc/types/Gralloc4.cpp @@ -1317,6 +1317,8 @@ std::string getPlaneLayoutComponentTypeName(const ExtendableType& planeLayoutCom return "G"; case PlaneLayoutComponentType::B: return "B"; + case PlaneLayoutComponentType::RAW: + return "RAW"; case PlaneLayoutComponentType::A: return "A"; } -- GitLab From 3b653e717315ac19b6800cda747f148615d737a6 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 24 Feb 2020 16:40:50 -0800 Subject: [PATCH 0845/1255] Zero out framenumber when clearing out layer Fixes a bug where the contents of the client composition buffer was not reused because HWC requested clearing the layer. When checking if the composition request changed, the framenumber was always incrementing. Bug: b/146238164 Test: go/wm-smoke Test: adb shell su root dumpsys SurfaceFlinger --timestats -dump -maxlayers 0 Change-Id: I39029835003b40c7e50acf765b52ee9103ce8303 --- services/surfaceflinger/Layer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d7647d76d3..766871e3b0 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -677,6 +677,7 @@ void Layer::prepareClearClientComposition(LayerFE::LayerSettings& layerSettings, layerSettings.source.buffer.buffer = nullptr; layerSettings.source.solidColor = half3(0.0, 0.0, 0.0); layerSettings.disableBlending = true; + layerSettings.bufferId = 0; layerSettings.frameNumber = 0; // If layer is blacked out, force alpha to 1 so that we draw a black color layer. -- GitLab From fbcf9d77fe6321ba7e03d50f965e8c16ea4290c3 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 24 Feb 2020 15:26:37 -0800 Subject: [PATCH 0846/1255] Make bitmap.h C-compatible when __ANDROID_API__ >= 30 C requires a typedef for AHardwareBuffer. Fixes: frameworks/native/include/android/bitmap.h:246:9: error: must use 'struct' tag to refer to type 'AHardwareBuffer' Fixes: 150165785 Test: m checkbuild Change-Id: I6d475e91317ff7a9264144d4cd6c6c9b46d10196 --- include/android/bitmap.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/android/bitmap.h b/include/android/bitmap.h index 727a4af2f9..2631b144af 100644 --- a/include/android/bitmap.h +++ b/include/android/bitmap.h @@ -227,6 +227,7 @@ int AndroidBitmap_compress(const AndroidBitmapInfo* info, AndroidBitmap_CompressWriteFunc fn) __INTRODUCED_IN(30); struct AHardwareBuffer; +typedef struct AHardwareBuffer AHardwareBuffer; /** * Retrieve the native object associated with a HARDWARE Bitmap. -- GitLab From 989ddbe046400612f92a05a71d38f438e4dd19e1 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 6 Feb 2020 09:26:19 -0800 Subject: [PATCH 0847/1255] [SurfaceFlinger] Push atoms on janky events For now define a jank event as a window of 100ms containing at least one missed frame. On the server-side we can then configure whether tracing is triggered based on the number of missed frames in a window. A 100ms window should be safe, as always-on tracing should contain ~10 seconds of trace data Further details on when we report a jank: * We don't report a jank if it occurred more than a second in the past, since we need a good guarantee that the trace will actually contain the jank * We don't report a jank if the display is off or in doze, as missed frames in those power modes are either not actionable or not user-perceived. * We only report a jank on userdebug or eng builds. This will never be enabled on user builds, so there's no reason to incur the cost of pushing the atom on those builds. Bug: 148543048 Test: builds Test: statsd_testdrive 257 Change-Id: Ifc544d544ef8da9adec944507fe71dc5550c13e8 (cherry picked from commit 5f487d4e17ff7347e927f5e5b0a2a97c84ad16c7) Merged-In: Ifc544d544ef8da9adec944507fe71dc5550c13e8 --- services/surfaceflinger/Android.bp | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 118 +++++++++++++-------- services/surfaceflinger/SurfaceFlinger.h | 6 ++ 3 files changed, 82 insertions(+), 43 deletions(-) diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 08d7d3f0cb..c6f1f7ef6e 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -52,6 +52,7 @@ cc_defaults { "libpdx_default_transport", "libprocessgroup", "libprotobuf-cpp-lite", + "libstatslog", "libsync", "libtimestats", "libui", diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ce0a8a1ac0..86f1bc1b27 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -21,28 +21,17 @@ //#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include +#include "SurfaceFlinger.h" +#include +#include +#include +#include +#include #include - -#include -#include - #include #include #include - #include #include #include @@ -51,10 +40,14 @@ #include #include #include +#include +#include +#include +#include #include +#include #include #include - #include #include #include @@ -63,7 +56,13 @@ #include #include #include +#include +#include +#include +#include #include +#include +#include #include #include #include @@ -80,8 +79,14 @@ #include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include "BufferLayer.h" #include "BufferQueueLayer.h" @@ -90,23 +95,19 @@ #include "Colorizer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" -#include "EffectLayer.h" -#include "Layer.h" -#include "LayerVector.h" -#include "MonitoredProducer.h" -#include "NativeWindowSurface.h" -#include "RefreshRateOverlay.h" -#include "StartPropertySetThread.h" -#include "SurfaceFlinger.h" -#include "SurfaceInterceptor.h" - #include "DisplayHardware/ComposerHal.h" #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/VirtualDisplaySurface.h" +#include "EffectLayer.h" #include "Effects/Daltonizer.h" #include "FrameTracer/FrameTracer.h" +#include "Layer.h" +#include "LayerVector.h" +#include "MonitoredProducer.h" +#include "NativeWindowSurface.h" +#include "RefreshRateOverlay.h" #include "RegionSamplingThread.h" #include "Scheduler/DispSync.h" #include "Scheduler/DispSyncSource.h" @@ -115,23 +116,13 @@ #include "Scheduler/MessageQueue.h" #include "Scheduler/PhaseOffsets.h" #include "Scheduler/Scheduler.h" +#include "StartPropertySetThread.h" +#include "SurfaceFlingerProperties.h" +#include "SurfaceInterceptor.h" #include "TimeStats/TimeStats.h" - -#include - #include "android-base/parseint.h" #include "android-base/stringprintf.h" -#include -#include -#include -#include -#include -#include - -#include -#include "SurfaceFlingerProperties.h" - namespace android { using namespace std::string_literals; @@ -334,6 +325,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("ro.bq.gpu_to_cpu_unsupported", value, "0"); mGpuToCpuSupported = !atoi(value); + property_get("ro.build.type", value, "user"); + mIsUserBuild = strcmp(value, "user") == 0; + property_get("debug.sf.showupdates", value, "0"); mDebugRegion = atoi(value); @@ -1812,6 +1806,10 @@ void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { if (frameMissed) { mFrameMissedCount++; mTimeStats->incrementMissedFrames(); + if (mMissedFrameJankCount == 0) { + mMissedFrameJankStart = systemTime(); + } + mMissedFrameJankCount++; } if (hwcFrameMissed) { @@ -1830,6 +1828,40 @@ void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { } } + // Our jank window is always at least 100ms since we missed a + // frame... + static constexpr nsecs_t kMinJankyDuration = + std::chrono::duration_cast(100ms).count(); + // ...but if it's larger than 1s then we missed the trace cutoff. + static constexpr nsecs_t kMaxJankyDuration = + std::chrono::duration_cast(1s).count(); + // If we're in a user build then don't push any atoms + if (!mIsUserBuild && mMissedFrameJankCount > 0) { + const auto displayDevice = getDefaultDisplayDeviceLocked(); + // Only report jank when the display is on, as displays in DOZE + // power mode may operate at a different frame rate than is + // reported in their config, which causes noticeable (but less + // severe) jank. + if (displayDevice && displayDevice->getPowerMode() == HWC_POWER_MODE_NORMAL) { + const nsecs_t currentTime = systemTime(); + const nsecs_t jankDuration = currentTime - mMissedFrameJankStart; + if (jankDuration > kMinJankyDuration && jankDuration < kMaxJankyDuration) { + ATRACE_NAME("Jank detected"); + ALOGD("Detected janky event. Missed frames: %d", mMissedFrameJankCount); + const int32_t jankyDurationMillis = jankDuration / (1000 * 1000); + android::util::stats_write(android::util::DISPLAY_JANK_REPORTED, + jankyDurationMillis, mMissedFrameJankCount); + } + + // We either reported a jank event or we missed the trace + // window, so clear counters here. + if (jankDuration > kMinJankyDuration) { + mMissedFrameJankCount = 0; + mMissedFrameJankStart = 0; + } + } + } + // Now that we're going to make it to the handleMessageTransaction() // call below it's safe to call updateVrFlinger(), which will // potentially trigger a display handoff. diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c79621b1fa..e4a5da1178 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -982,6 +982,7 @@ private: // constant members (no synchronization needed for access) const nsecs_t mBootTime = systemTime(); bool mGpuToCpuSupported = false; + bool mIsUserBuild = true; // Can only accessed from the main thread, these members // don't need synchronization @@ -1225,6 +1226,11 @@ private: // Flags to capture the state of Vsync in HWC HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable; HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable; + + // Fields tracking the current jank event: when it started and how many + // janky frames there are. + nsecs_t mMissedFrameJankStart = 0; + int32_t mMissedFrameJankCount = 0; }; } // namespace android -- GitLab From aca85366df40ebb5ed5070fba1a21c56c43b41c1 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Tue, 25 Feb 2020 12:27:14 -0800 Subject: [PATCH 0848/1255] lshal: read binder stats from binderfs If binderfs is mounted, lshal should read binder stats from /dev/binderfs/binder_logs instead of debugfs. Bug: 150233443 Test: atest lshal_test, adb shell lshal Change-Id: Id585cdcd71c0ab4346045a099c2e3d0ddffcecc0 Merged-In: Id585cdcd71c0ab4346045a099c2e3d0ddffcecc0 --- cmds/lshal/ListCommand.cpp | 7 +++++-- cmds/lshal/ListCommand.h | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp index a7ccf64c50..f426dbbc4f 100644 --- a/cmds/lshal/ListCommand.cpp +++ b/cmds/lshal/ListCommand.cpp @@ -206,9 +206,12 @@ VintfInfo ListCommand::getVintfInfo(const std::string& fqInstanceName, static bool scanBinderContext(pid_t pid, const std::string &contextName, std::function eachLine) { - std::ifstream ifs("/d/binder/proc/" + std::to_string(pid)); + std::ifstream ifs("/dev/binderfs/binder_logs/proc/" + std::to_string(pid)); if (!ifs.is_open()) { - return false; + ifs.open("/d/binder/proc/" + std::to_string(pid)); + if (!ifs.is_open()) { + return false; + } } static const std::regex kContextLine("^context (\\w+)$"); diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h index b3ed23d1fc..acc0dcfc2e 100644 --- a/cmds/lshal/ListCommand.h +++ b/cmds/lshal/ListCommand.h @@ -104,7 +104,8 @@ protected: Status fetchBinderizedEntry(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager, TableEntry *entry); - // Get relevant information for a PID by parsing files under /d/binder. + // Get relevant information for a PID by parsing files under + // /dev/binderfs/binder_logs or /d/binder. // It is a virtual member function so that it can be mocked. virtual bool getPidInfo(pid_t serverPid, PidInfo *info) const; // Retrieve from mCachedPidInfos and call getPidInfo if necessary. -- GitLab From 2d5878e69b6df009a936ab29710ef00673bb7b0a Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Thu, 23 Jan 2020 12:45:10 +0900 Subject: [PATCH 0849/1255] Use std::optional for @nullable (AIDL) Previously, nullable types were mapped to std::unique_ptr for C++ backend. But std::unique_ptr typically involves unnecessary alloc/dealloc. For example, if nullable string is represented in unique_ptr, we should do "unique_ptr(new string(value))" to set a value. To avoid breaking all hand-written parcelables, only new read/write functions are added to Parcel class and they are used only by aidl-generated code and their implementations. Bug: 144773267 Test: build/flash/boot atest --test-mapping frameworks/native/libs/binder Merged-In: I2c801e3b69f2f8ccf44267f15cbf79e1d8fbf19e Change-Id: I2c801e3b69f2f8ccf44267f15cbf79e1d8fbf19e (cherry picked from commit 149be4a25ef423491c73dfc7bfd95e8177e9b4f8) Exempt-From-Owner-Approval: CP from master --- cmds/installd/CrateManager.cpp | 24 +- cmds/installd/CrateManager.h | 10 +- cmds/installd/InstalldNativeService.cpp | 129 +++++---- cmds/installd/InstalldNativeService.h | 78 +++--- cmds/installd/dexopt.cpp | 12 +- cmds/installd/dexopt.h | 8 +- cmds/installd/tests/installd_cache_test.cpp | 5 +- cmds/installd/tests/installd_dexopt_test.cpp | 64 ++--- cmds/installd/tests/installd_service_test.cpp | 39 ++- libs/binder/AppOpsManager.cpp | 12 +- libs/binder/IAppOpsService.cpp | 14 +- libs/binder/Parcel.cpp | 207 +++++++++++++++ libs/binder/include/binder/AppOpsManager.h | 8 +- libs/binder/include/binder/IAppOpsService.h | 8 +- libs/binder/include/binder/Parcel.h | 250 +++++++++++++++++- .../include/binder/ParcelFileDescriptor.h | 1 + 16 files changed, 658 insertions(+), 211 deletions(-) diff --git a/cmds/installd/CrateManager.cpp b/cmds/installd/CrateManager.cpp index 6e079ebbf3..b17cba15d5 100644 --- a/cmds/installd/CrateManager.cpp +++ b/cmds/installd/CrateManager.cpp @@ -86,7 +86,7 @@ void CrateManager::traverseChildDir(const std::string& targetDir, } void CrateManager::traverseAllPackagesForUser( - const std::unique_ptr& uuid, userid_t userId, + const std::optional& uuid, userid_t userId, std::function& onHandlingPackage) { const char* uuid_ = uuid ? uuid->c_str() : nullptr; @@ -96,21 +96,21 @@ void CrateManager::traverseAllPackagesForUser( void CrateManager::createCrate( CratedFolder cratedFolder, - std::function&)>& onCreateCrate) { + std::function& onCreateCrate) { const char* path = cratedFolder->fts_path; if (path == nullptr || *path == '\0') { return; } - std::unique_ptr crateMetadata = std::make_unique(); - crateMetadata->uid = cratedFolder->fts_statp->st_uid; - crateMetadata->packageName = mPackageName; - crateMetadata->id = getValidatedCratedPath(path); + CrateMetadata crateMetadata; + crateMetadata.uid = cratedFolder->fts_statp->st_uid; + crateMetadata.packageName = mPackageName; + crateMetadata.id = getValidatedCratedPath(path); - onCreateCrate(cratedFolder, crateMetadata); + onCreateCrate(cratedFolder, std::move(crateMetadata)); } -void CrateManager::traverseAllCrates(std::function&)>& onCreateCrate) { +void CrateManager::traverseAllCrates(std::function& onCreateCrate) { std::function onVisitCrateDir = [&](FTSENT* cratedFolder) -> void { createCrate(cratedFolder, onCreateCrate); }; @@ -118,11 +118,11 @@ void CrateManager::traverseAllCrates(std::function& CrateMetadata) { +void CrateManager::dump(const CrateMetadata& CrateMetadata) { LOG(DEBUG) << "CrateMetadata = {" - << "uid : \"" << CrateMetadata->uid - << "\", packageName : \"" << CrateMetadata->packageName - << "\", id : \"" << CrateMetadata->id + << "uid : \"" << CrateMetadata.uid + << "\", packageName : \"" << CrateMetadata.packageName + << "\", id : \"" << CrateMetadata.id << "\"}"; } #endif diff --git a/cmds/installd/CrateManager.h b/cmds/installd/CrateManager.h index 4332d4cbc9..1f30b5dc79 100644 --- a/cmds/installd/CrateManager.h +++ b/cmds/installd/CrateManager.h @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include @@ -55,18 +55,18 @@ public: CrateManager(const char* uuid, userid_t userId, const std::string& packageName); ~CrateManager(); - void traverseAllCrates(std::function&)>& onCreateCrate); + void traverseAllCrates(std::function& onCreateCrate); static void traverseChildDir(const std::string& targetDir, std::function& onVisitChildDir); static void traverseAllPackagesForUser( - const std::unique_ptr& uuid, + const std::optional& uuid, userid_t userId, std::function& onHandlingPackage); #if CRATE_DEBUG - static void dump(std::unique_ptr& CrateMetadata); + static void dump(const CrateMetadata& CrateMetadata); #endif private: std::string mRoot; @@ -75,7 +75,7 @@ private: void createCrate( CratedFolder cratedFolder, - std::function&)>& onCreateCrate); + std::function& onCreateCrate); }; } // namespace installd diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index c9b51b597f..26f9d79cd4 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -164,7 +164,7 @@ binder::Status checkUid(uid_t expectedUid) { } } -binder::Status checkArgumentUuid(const std::unique_ptr& uuid) { +binder::Status checkArgumentUuid(const std::optional& uuid) { if (!uuid || is_valid_filename(*uuid)) { return ok(); } else { @@ -173,7 +173,7 @@ binder::Status checkArgumentUuid(const std::unique_ptr& uuid) { } } -binder::Status checkArgumentUuidTestOrNull(const std::unique_ptr& uuid) { +binder::Status checkArgumentUuidTestOrNull(const std::optional& uuid) { if (!uuid || strcmp(uuid->c_str(), kTestUuid) == 0) { return ok(); } else { @@ -212,7 +212,7 @@ binder::Status checkArgumentPath(const std::string& path) { return ok(); } -binder::Status checkArgumentPath(const std::unique_ptr& path) { +binder::Status checkArgumentPath(const std::optional& path) { if (path) { return checkArgumentPath(*path); } else { @@ -418,7 +418,7 @@ static bool prepare_app_profile_dir(const std::string& packageName, int32_t appI return true; } -binder::Status InstalldNativeService::createAppData(const std::unique_ptr& uuid, +binder::Status InstalldNativeService::createAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) { ENFORCE_UID(AID_SYSTEM); @@ -499,7 +499,7 @@ binder::Status InstalldNativeService::createAppData(const std::unique_ptr& uuid, +binder::Status InstalldNativeService::migrateAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); @@ -560,7 +560,7 @@ binder::Status InstalldNativeService::clearAppProfiles(const std::string& packag return res; } -binder::Status InstalldNativeService::clearAppData(const std::unique_ptr& uuid, +binder::Status InstalldNativeService::clearAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); @@ -680,7 +680,7 @@ binder::Status InstalldNativeService::destroyAppProfiles(const std::string& pack return res; } -binder::Status InstalldNativeService::destroyAppData(const std::unique_ptr& uuid, +binder::Status InstalldNativeService::destroyAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); @@ -752,7 +752,7 @@ static gid_t get_cache_gid(uid_t uid) { return (gid != -1) ? gid : uid; } -binder::Status InstalldNativeService::fixupAppData(const std::unique_ptr& uuid, +binder::Status InstalldNativeService::fixupAppData(const std::optional& uuid, int32_t flags) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); @@ -872,7 +872,7 @@ static int32_t copy_directory_recursive(const char* from, const char* to) { } binder::Status InstalldNativeService::snapshotAppData( - const std::unique_ptr& volumeUuid, + const std::optional& volumeUuid, const std::string& packageName, int32_t user, int32_t snapshotId, int32_t storageFlags, int64_t* _aidl_return) { ENFORCE_UID(AID_SYSTEM); @@ -999,7 +999,7 @@ binder::Status InstalldNativeService::snapshotAppData( } binder::Status InstalldNativeService::restoreAppDataSnapshot( - const std::unique_ptr& volumeUuid, const std::string& packageName, + const std::optional& volumeUuid, const std::string& packageName, const int32_t appId, const std::string& seInfo, const int32_t user, const int32_t snapshotId, int32_t storageFlags) { ENFORCE_UID(AID_SYSTEM); @@ -1069,7 +1069,7 @@ binder::Status InstalldNativeService::restoreAppDataSnapshot( } binder::Status InstalldNativeService::destroyAppDataSnapshot( - const std::unique_ptr &volumeUuid, const std::string& packageName, + const std::optional &volumeUuid, const std::string& packageName, const int32_t user, const int64_t ceSnapshotInode, const int32_t snapshotId, int32_t storageFlags) { ENFORCE_UID(AID_SYSTEM); @@ -1102,8 +1102,8 @@ binder::Status InstalldNativeService::destroyAppDataSnapshot( } -binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr& fromUuid, - const std::unique_ptr& toUuid, const std::string& packageName, +binder::Status InstalldNativeService::moveCompleteApp(const std::optional& fromUuid, + const std::optional& toUuid, const std::string& packageName, int32_t appId, const std::string& seInfo, int32_t targetSdkVersion, const std::string& fromCodePath) { ENFORCE_UID(AID_SYSTEM); @@ -1210,7 +1210,7 @@ fail: return res; } -binder::Status InstalldNativeService::createUserData(const std::unique_ptr& uuid, +binder::Status InstalldNativeService::createUserData(const std::optional& uuid, int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); @@ -1228,7 +1228,7 @@ binder::Status InstalldNativeService::createUserData(const std::unique_ptr& uuid, +binder::Status InstalldNativeService::destroyUserData(const std::optional& uuid, int32_t userId, int32_t flags) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); @@ -1265,13 +1265,13 @@ binder::Status InstalldNativeService::destroyUserData(const std::unique_ptr& uuid, +binder::Status InstalldNativeService::freeCache(const std::optional& uuid, int64_t targetFreeBytes, int64_t cacheReservedBytes, int32_t flags) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); std::lock_guard lock(mLock); - auto uuidString = uuid ? *uuid : ""; + auto uuidString = uuid.value_or(""); const char* uuid_ = uuid ? uuid->c_str() : nullptr; auto data_path = create_data_path(uuid_); auto noop = (flags & FLAG_FREE_CACHE_NOOP); @@ -1669,7 +1669,7 @@ static void collectManualExternalStatsForUser(const std::string& path, struct st fts_close(fts); } -binder::Status InstalldNativeService::getAppSize(const std::unique_ptr& uuid, +binder::Status InstalldNativeService::getAppSize(const std::optional& uuid, const std::vector& packageNames, int32_t userId, int32_t flags, int32_t appId, const std::vector& ceDataInodes, const std::vector& codePaths, std::vector* _aidl_return) { @@ -1709,7 +1709,7 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptrc_str() : nullptr; if (!IsQuotaSupported(uuidString)) { @@ -1896,7 +1896,7 @@ static external_sizes getExternalSizesForUserWithQuota(const std::string& uuid, return sizes; } -binder::Status InstalldNativeService::getUserSize(const std::unique_ptr& uuid, +binder::Status InstalldNativeService::getUserSize(const std::optional& uuid, int32_t userId, int32_t flags, const std::vector& appIds, std::vector* _aidl_return) { ENFORCE_UID(AID_SYSTEM); @@ -1916,7 +1916,7 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptrc_str() : nullptr; if (!IsQuotaSupported(uuidString)) { @@ -2028,7 +2028,7 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr& uuid, +binder::Status InstalldNativeService::getExternalSize(const std::optional& uuid, int32_t userId, int32_t flags, const std::vector& appIds, std::vector* _aidl_return) { ENFORCE_UID(AID_SYSTEM); @@ -2043,7 +2043,7 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptrc_str() : nullptr; int64_t totalSize = 0; @@ -2145,9 +2145,9 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr& uuid, + const std::optional& uuid, const std::vector& packageNames, int32_t userId, - std::unique_ptr>>* _aidl_return) { + std::optional>>* _aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); for (const auto& packageName : packageNames) { @@ -2156,15 +2156,15 @@ binder::Status InstalldNativeService::getAppCrates( #ifdef ENABLE_STORAGE_CRATES std::lock_guard lock(mLock); - auto retVector = std::make_unique>>(); + auto retVector = std::vector>(); const char* uuid_ = uuid ? uuid->c_str() : nullptr; - std::function &)> onCreateCrate = - [&](CratedFolder cratedFolder, std::unique_ptr &crateMetadata) -> void { + std::function onCreateCrate = + [&](CratedFolder cratedFolder, CrateMetadata&& crateMetadata) -> void { if (cratedFolder == nullptr) { return; } - retVector->push_back(std::move(crateMetadata)); + retVector.push_back(std::move(crateMetadata)); }; for (const auto& packageName : packageNames) { @@ -2176,15 +2176,15 @@ binder::Status InstalldNativeService::getAppCrates( } #if CRATE_DEBUG - LOG(WARNING) << "retVector->size() =" << retVector->size(); - for (auto iter = retVector->begin(); iter != retVector->end(); ++iter) { - CrateManager::dump(*iter); + LOG(WARNING) << "retVector.size() =" << retVector.size(); + for (auto& item : retVector) { + CrateManager::dump(item); } #endif *_aidl_return = std::move(retVector); #else // ENABLE_STORAGE_CRATES - *_aidl_return = nullptr; + _aidl_return->reset(); /* prevent compile warning fail */ if (userId < 0) { @@ -2195,18 +2195,18 @@ binder::Status InstalldNativeService::getAppCrates( } binder::Status InstalldNativeService::getUserCrates( - const std::unique_ptr& uuid, int32_t userId, - std::unique_ptr>>* _aidl_return) { + const std::optional& uuid, int32_t userId, + std::optional>>* _aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); #ifdef ENABLE_STORAGE_CRATES std::lock_guard lock(mLock); const char* uuid_ = uuid ? uuid->c_str() : nullptr; - auto retVector = std::make_unique>>(); + auto retVector = std::vector>(); - std::function &)> onCreateCrate = - [&](CratedFolder cratedFolder, std::unique_ptr &crateMetadata) -> void { + std::function onCreateCrate = + [&](CratedFolder cratedFolder, CrateMetadata&& crateMetadata) -> void { if (cratedFolder == nullptr) { return; } @@ -2220,15 +2220,15 @@ binder::Status InstalldNativeService::getUserCrates( CrateManager::traverseAllPackagesForUser(uuid, userId, onHandingPackage); #if CRATE_DEBUG - LOG(DEBUG) << "retVector->size() =" << retVector->size(); - for (auto iter = retVector->begin(); iter != retVector->end(); ++iter) { - CrateManager::dump(*iter); + LOG(DEBUG) << "retVector.size() =" << retVector.size(); + for (auto& item : retVector) { + CrateManager::dump(item); } #endif *_aidl_return = std::move(retVector); #else // ENABLE_STORAGE_CRATES - *_aidl_return = nullptr; + _aidl_return->reset(); /* prevent compile warning fail */ if (userId < 0) { @@ -2238,7 +2238,7 @@ binder::Status InstalldNativeService::getUserCrates( return ok(); } -binder::Status InstalldNativeService::setAppQuota(const std::unique_ptr& uuid, +binder::Status InstalldNativeService::setAppQuota(const std::optional& uuid, int32_t userId, int32_t appId, int64_t cacheQuota) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); @@ -2309,19 +2309,19 @@ binder::Status InstalldNativeService::destroyProfileSnapshot(const std::string& return ok(); } -static const char* getCStr(const std::unique_ptr& data, +static const char* getCStr(const std::optional& data, const char* default_value = nullptr) { - return data == nullptr ? default_value : data->c_str(); + return data ? data->c_str() : default_value; } binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid, - const std::unique_ptr& packageName, const std::string& instructionSet, - int32_t dexoptNeeded, const std::unique_ptr& outputPath, int32_t dexFlags, - const std::string& compilerFilter, const std::unique_ptr& uuid, - const std::unique_ptr& classLoaderContext, - const std::unique_ptr& seInfo, bool downgrade, int32_t targetSdkVersion, - const std::unique_ptr& profileName, - const std::unique_ptr& dexMetadataPath, - const std::unique_ptr& compilationReason) { + const std::optional& packageName, const std::string& instructionSet, + int32_t dexoptNeeded, const std::optional& outputPath, int32_t dexFlags, + const std::string& compilerFilter, const std::optional& uuid, + const std::optional& classLoaderContext, + const std::optional& seInfo, bool downgrade, int32_t targetSdkVersion, + const std::optional& profileName, + const std::optional& dexMetadataPath, + const std::optional& compilationReason) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PATH(apkPath); @@ -2367,7 +2367,7 @@ binder::Status InstalldNativeService::compileLayouts(const std::string& apkPath, } binder::Status InstalldNativeService::linkNativeLibraryDirectory( - const std::unique_ptr& uuid, const std::string& packageName, + const std::optional& uuid, const std::string& packageName, const std::string& nativeLibPath32, int32_t userId) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); @@ -2458,7 +2458,7 @@ out: return res; } -binder::Status InstalldNativeService::restoreconAppData(const std::unique_ptr& uuid, +binder::Status InstalldNativeService::restoreconAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, const std::string& seInfo) { ENFORCE_UID(AID_SYSTEM); @@ -2576,7 +2576,7 @@ binder::Status InstalldNativeService::moveAb(const std::string& apkPath, } binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath, - const std::string& instructionSet, const std::unique_ptr& outputPath) { + const std::string& instructionSet, const std::optional& outputPath) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_PATH(apkPath); CHECK_ARGUMENT_PATH(outputPath); @@ -2728,7 +2728,7 @@ binder::Status InstalldNativeService::assertFsverityRootHashMatches(const std::s binder::Status InstalldNativeService::reconcileSecondaryDexFile( const std::string& dexPath, const std::string& packageName, int32_t uid, - const std::vector& isas, const std::unique_ptr& volumeUuid, + const std::vector& isas, const std::optional& volumeUuid, int32_t storage_flag, bool* _aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(volumeUuid); @@ -2743,7 +2743,7 @@ binder::Status InstalldNativeService::reconcileSecondaryDexFile( binder::Status InstalldNativeService::hashSecondaryDexFile( const std::string& dexPath, const std::string& packageName, int32_t uid, - const std::unique_ptr& volumeUuid, int32_t storageFlag, + const std::optional& volumeUuid, int32_t storageFlag, std::vector* _aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(volumeUuid); @@ -2802,7 +2802,7 @@ binder::Status InstalldNativeService::invalidateMounts() { // Mount volume's CE and DE storage to mirror binder::Status InstalldNativeService::tryMountDataMirror( - const std::unique_ptr& uuid) { + const std::optional& uuid) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); if (!sAppDataIsolationEnabled) { @@ -2866,7 +2866,7 @@ binder::Status InstalldNativeService::tryMountDataMirror( // Unmount volume's CE and DE storage from mirror binder::Status InstalldNativeService::onPrivateVolumeRemoved( - const std::unique_ptr& uuid) { + const std::optional& uuid) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(uuid); if (!sAppDataIsolationEnabled) { @@ -2910,7 +2910,7 @@ binder::Status InstalldNativeService::onPrivateVolumeRemoved( } std::string InstalldNativeService::findDataMediaPath( - const std::unique_ptr& uuid, userid_t userid) { + const std::optional& uuid, userid_t userid) { std::lock_guard lock(mMountsLock); const char* uuid_ = uuid ? uuid->c_str() : nullptr; auto path = StringPrintf("%s/media", create_data_path(uuid_).c_str()); @@ -2923,15 +2923,14 @@ std::string InstalldNativeService::findDataMediaPath( } binder::Status InstalldNativeService::isQuotaSupported( - const std::unique_ptr& uuid, bool* _aidl_return) { - auto uuidString = uuid ? *uuid : ""; - *_aidl_return = IsQuotaSupported(uuidString); + const std::optional& uuid, bool* _aidl_return) { + *_aidl_return = IsQuotaSupported(uuid.value_or("")); return ok(); } binder::Status InstalldNativeService::prepareAppProfile(const std::string& packageName, int32_t userId, int32_t appId, const std::string& profileName, const std::string& codePath, - const std::unique_ptr& dexMetadata, bool* _aidl_return) { + const std::optional& dexMetadata, bool* _aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_PACKAGE_NAME(packageName); CHECK_ARGUMENT_PATH(codePath); diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index df01c3ca85..8e22c3e5d9 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -40,74 +40,74 @@ public: static char const* getServiceName() { return "installd"; } virtual status_t dump(int fd, const Vector &args) override; - binder::Status createUserData(const std::unique_ptr& uuid, int32_t userId, + binder::Status createUserData(const std::optional& uuid, int32_t userId, int32_t userSerial, int32_t flags); - binder::Status destroyUserData(const std::unique_ptr& uuid, int32_t userId, + binder::Status destroyUserData(const std::optional& uuid, int32_t userId, int32_t flags); - binder::Status createAppData(const std::unique_ptr& uuid, + binder::Status createAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return); - binder::Status restoreconAppData(const std::unique_ptr& uuid, + binder::Status restoreconAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, const std::string& seInfo); - binder::Status migrateAppData(const std::unique_ptr& uuid, + binder::Status migrateAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags); - binder::Status clearAppData(const std::unique_ptr& uuid, + binder::Status clearAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode); - binder::Status destroyAppData(const std::unique_ptr& uuid, + binder::Status destroyAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode); - binder::Status fixupAppData(const std::unique_ptr& uuid, int32_t flags); + binder::Status fixupAppData(const std::optional& uuid, int32_t flags); - binder::Status snapshotAppData(const std::unique_ptr& volumeUuid, + binder::Status snapshotAppData(const std::optional& volumeUuid, const std::string& packageName, const int32_t user, const int32_t snapshotId, int32_t storageFlags, int64_t* _aidl_return); - binder::Status restoreAppDataSnapshot(const std::unique_ptr& volumeUuid, + binder::Status restoreAppDataSnapshot(const std::optional& volumeUuid, const std::string& packageName, const int32_t appId, const std::string& seInfo, const int32_t user, const int32_t snapshotId, int32_t storageFlags); - binder::Status destroyAppDataSnapshot(const std::unique_ptr &volumeUuid, + binder::Status destroyAppDataSnapshot(const std::optional &volumeUuid, const std::string& packageName, const int32_t user, const int64_t ceSnapshotInode, const int32_t snapshotId, int32_t storageFlags); - binder::Status getAppSize(const std::unique_ptr& uuid, + binder::Status getAppSize(const std::optional& uuid, const std::vector& packageNames, int32_t userId, int32_t flags, int32_t appId, const std::vector& ceDataInodes, const std::vector& codePaths, std::vector* _aidl_return); - binder::Status getUserSize(const std::unique_ptr& uuid, + binder::Status getUserSize(const std::optional& uuid, int32_t userId, int32_t flags, const std::vector& appIds, std::vector* _aidl_return); - binder::Status getExternalSize(const std::unique_ptr& uuid, + binder::Status getExternalSize(const std::optional& uuid, int32_t userId, int32_t flags, const std::vector& appIds, std::vector* _aidl_return); - binder::Status getAppCrates(const std::unique_ptr& uuid, + binder::Status getAppCrates(const std::optional& uuid, const std::vector& packageNames, int32_t userId, - std::unique_ptr>>* + std::optional>>* _aidl_return); binder::Status getUserCrates( - const std::unique_ptr& uuid, int32_t userId, - std::unique_ptr>>* + const std::optional& uuid, int32_t userId, + std::optional>>* _aidl_return); - binder::Status setAppQuota(const std::unique_ptr& uuid, + binder::Status setAppQuota(const std::optional& uuid, int32_t userId, int32_t appId, int64_t cacheQuota); - binder::Status moveCompleteApp(const std::unique_ptr& fromUuid, - const std::unique_ptr& toUuid, const std::string& packageName, + binder::Status moveCompleteApp(const std::optional& fromUuid, + const std::optional& toUuid, const std::string& packageName, int32_t appId, const std::string& seInfo, int32_t targetSdkVersion, const std::string& fromCodePath); binder::Status dexopt(const std::string& apkPath, int32_t uid, - const std::unique_ptr& packageName, const std::string& instructionSet, - int32_t dexoptNeeded, const std::unique_ptr& outputPath, int32_t dexFlags, - const std::string& compilerFilter, const std::unique_ptr& uuid, - const std::unique_ptr& classLoaderContext, - const std::unique_ptr& seInfo, bool downgrade, - int32_t targetSdkVersion, const std::unique_ptr& profileName, - const std::unique_ptr& dexMetadataPath, - const std::unique_ptr& compilationReason); + const std::optional& packageName, const std::string& instructionSet, + int32_t dexoptNeeded, const std::optional& outputPath, int32_t dexFlags, + const std::string& compilerFilter, const std::optional& uuid, + const std::optional& classLoaderContext, + const std::optional& seInfo, bool downgrade, + int32_t targetSdkVersion, const std::optional& profileName, + const std::optional& dexMetadataPath, + const std::optional& compilationReason); binder::Status compileLayouts(const std::string& apkPath, const std::string& packageName, const std::string& outDexFile, int uid, bool* _aidl_return); @@ -130,9 +130,9 @@ public: const std::string& profileName); binder::Status rmPackageDir(const std::string& packageDir); - binder::Status freeCache(const std::unique_ptr& uuid, int64_t targetFreeBytes, + binder::Status freeCache(const std::optional& uuid, int64_t targetFreeBytes, int64_t cacheReservedBytes, int32_t flags); - binder::Status linkNativeLibraryDirectory(const std::unique_ptr& uuid, + binder::Status linkNativeLibraryDirectory(const std::optional& uuid, const std::string& packageName, const std::string& nativeLibPath32, int32_t userId); binder::Status createOatDir(const std::string& oatDir, const std::string& instructionSet); binder::Status linkFile(const std::string& relativePath, const std::string& fromBase, @@ -140,27 +140,27 @@ public: binder::Status moveAb(const std::string& apkPath, const std::string& instructionSet, const std::string& outputPath); binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet, - const std::unique_ptr& outputPath); + const std::optional& outputPath); binder::Status installApkVerity(const std::string& filePath, android::base::unique_fd verityInput, int32_t contentSize); binder::Status assertFsverityRootHashMatches(const std::string& filePath, const std::vector& expectedHash); binder::Status reconcileSecondaryDexFile(const std::string& dexPath, const std::string& packageName, int32_t uid, const std::vector& isa, - const std::unique_ptr& volumeUuid, int32_t storage_flag, bool* _aidl_return); + const std::optional& volumeUuid, int32_t storage_flag, bool* _aidl_return); binder::Status hashSecondaryDexFile(const std::string& dexPath, - const std::string& packageName, int32_t uid, const std::unique_ptr& volumeUuid, + const std::string& packageName, int32_t uid, const std::optional& volumeUuid, int32_t storageFlag, std::vector* _aidl_return); binder::Status invalidateMounts(); - binder::Status isQuotaSupported(const std::unique_ptr& volumeUuid, + binder::Status isQuotaSupported(const std::optional& volumeUuid, bool* _aidl_return); - binder::Status tryMountDataMirror(const std::unique_ptr& volumeUuid); - binder::Status onPrivateVolumeRemoved(const std::unique_ptr& volumeUuid); + binder::Status tryMountDataMirror(const std::optional& volumeUuid); + binder::Status onPrivateVolumeRemoved(const std::optional& volumeUuid); binder::Status prepareAppProfile(const std::string& packageName, int32_t userId, int32_t appId, const std::string& profileName, - const std::string& codePath, const std::unique_ptr& dexMetadata, + const std::string& codePath, const std::optional& dexMetadata, bool* _aidl_return); binder::Status migrateLegacyObbData(); @@ -177,7 +177,7 @@ private: /* Map from UID to cache quota size */ std::unordered_map mCacheQuotas; - std::string findDataMediaPath(const std::unique_ptr& uuid, userid_t userid); + std::string findDataMediaPath(const std::optional& uuid, userid_t userid); }; } // namespace installd diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index 70bbc33b42..ebb8f0f90e 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -2277,7 +2277,7 @@ enum ReconcileSecondaryDexResult { // out_secondary_dex_exists will be set to false. bool reconcile_secondary_dex_file(const std::string& dex_path, const std::string& pkgname, int uid, const std::vector& isas, - const std::unique_ptr& volume_uuid, int storage_flag, + const std::optional& volume_uuid, int storage_flag, /*out*/bool* out_secondary_dex_exists) { *out_secondary_dex_exists = false; // start by assuming the file does not exist. if (isas.size() == 0) { @@ -2298,7 +2298,7 @@ bool reconcile_secondary_dex_file(const std::string& dex_path, /* child -- drop privileges before continuing */ drop_capabilities(uid); - const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str(); + const char* volume_uuid_cstr = volume_uuid ? volume_uuid->c_str() : nullptr; if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr, uid, storage_flag)) { LOG(ERROR) << "Could not validate secondary dex path " << dex_path; @@ -2399,11 +2399,11 @@ bool reconcile_secondary_dex_file(const std::string& dex_path, // the app. // For any other errors (e.g. if any of the parameters are invalid) returns false. bool hash_secondary_dex_file(const std::string& dex_path, const std::string& pkgname, int uid, - const std::unique_ptr& volume_uuid, int storage_flag, + const std::optional& volume_uuid, int storage_flag, std::vector* out_secondary_dex_hash) { out_secondary_dex_hash->clear(); - const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str(); + const char* volume_uuid_cstr = volume_uuid ? volume_uuid->c_str() : nullptr; if (storage_flag != FLAG_STORAGE_CE && storage_flag != FLAG_STORAGE_DE) { LOG(ERROR) << "hash_secondary_dex_file called with invalid storage_flag: " @@ -2924,7 +2924,7 @@ bool prepare_app_profile(const std::string& package_name, appid_t app_id, const std::string& profile_name, const std::string& code_path, - const std::unique_ptr& dex_metadata) { + const std::optional& dex_metadata) { // Prepare the current profile. std::string cur_profile = create_current_profile_path(user_id, package_name, profile_name, /*is_secondary_dex*/ false); @@ -2935,7 +2935,7 @@ bool prepare_app_profile(const std::string& package_name, } // Check if we need to install the profile from the dex metadata. - if (dex_metadata == nullptr) { + if (!dex_metadata) { return true; } diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h index ef739bafd4..92b13c79c1 100644 --- a/cmds/installd/dexopt.h +++ b/cmds/installd/dexopt.h @@ -21,6 +21,8 @@ #include +#include + #include namespace android { @@ -98,17 +100,17 @@ bool prepare_app_profile(const std::string& package_name, appid_t app_id, const std::string& profile_name, const std::string& code_path, - const std::unique_ptr& dex_metadata); + const std::optional& dex_metadata); bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path); bool reconcile_secondary_dex_file(const std::string& dex_path, const std::string& pkgname, int uid, const std::vector& isas, - const std::unique_ptr& volumeUuid, int storage_flag, + const std::optional& volumeUuid, int storage_flag, /*out*/bool* out_secondary_dex_exists); bool hash_secondary_dex_file(const std::string& dex_path, - const std::string& pkgname, int uid, const std::unique_ptr& volume_uuid, + const std::string& pkgname, int uid, const std::optional& volume_uuid, int storage_flag, std::vector* out_secondary_dex_hash); int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set, diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp index 5a5cb53431..863cdfe55b 100644 --- a/cmds/installd/tests/installd_cache_test.cpp +++ b/cmds/installd/tests/installd_cache_test.cpp @@ -114,15 +114,14 @@ static void setxattr(const char* path, const char* key) { class CacheTest : public testing::Test { protected: InstalldNativeService* service; - std::unique_ptr testUuid; + std::optional testUuid; virtual void SetUp() { setenv("ANDROID_LOG_TAGS", "*:v", 1); android::base::InitLogging(nullptr); service = new InstalldNativeService(); - testUuid = std::make_unique(); - *testUuid = std::string(kTestUuid); + testUuid = kTestUuid; system("mkdir -p /data/local/tmp/user/0"); } diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp index 69fefa199b..7d8cf1f9e5 100644 --- a/cmds/installd/tests/installd_dexopt_test.cpp +++ b/cmds/installd/tests/installd_dexopt_test.cpp @@ -193,7 +193,7 @@ protected: const uid_t kTestAppGid = multiuser_get_shared_gid(kTestUserId, kTestAppId); InstalldNativeService* service_; - std::unique_ptr volume_uuid_; + std::optional volume_uuid_; std::string package_name_; std::string apk_path_; std::string empty_dm_file_; @@ -221,7 +221,7 @@ protected: ASSERT_TRUE(init_selinux()); service_ = new InstalldNativeService(); - volume_uuid_ = nullptr; + volume_uuid_ = std::nullopt; package_name_ = "com.installd.test.dexopt"; se_info_ = "default"; app_apk_dir_ = android_app_dir + package_name_; @@ -294,7 +294,7 @@ protected: } // Create a secondary dex file on CE storage - const char* volume_uuid_cstr = volume_uuid_ == nullptr ? nullptr : volume_uuid_->c_str(); + const char* volume_uuid_cstr = volume_uuid_ ? volume_uuid_->c_str() : nullptr; app_private_dir_ce_ = create_data_user_ce_package_path( volume_uuid_cstr, kTestUserId, package_name_.c_str()); secondary_dex_ce_ = app_private_dir_ce_ + "/secondary_ce.jar"; @@ -353,36 +353,32 @@ protected: if (class_loader_context == nullptr) { class_loader_context = "&"; } - std::unique_ptr package_name_ptr(new std::string(package_name_)); int32_t dexopt_needed = 0; // does not matter; - std::unique_ptr out_path = nullptr; // does not matter + std::optional out_path; // does not matter int32_t dex_flags = DEXOPT_SECONDARY_DEX | dex_storage_flag; std::string compiler_filter = "speed-profile"; - std::unique_ptr class_loader_context_ptr( - new std::string(class_loader_context)); - std::unique_ptr se_info_ptr(new std::string(se_info_)); bool downgrade = false; int32_t target_sdk_version = 0; // default - std::unique_ptr profile_name_ptr = nullptr; - std::unique_ptr dm_path_ptr = nullptr; - std::unique_ptr compilation_reason_ptr = nullptr; + std::optional profile_name; + std::optional dm_path; + std::optional compilation_reason; binder::Status result = service_->dexopt(path, uid, - package_name_ptr, + package_name_, kRuntimeIsa, dexopt_needed, out_path, dex_flags, compiler_filter, volume_uuid_, - class_loader_context_ptr, - se_info_ptr, + class_loader_context, + se_info_, downgrade, target_sdk_version, - profile_name_ptr, - dm_path_ptr, - compilation_reason_ptr); + profile_name, + dm_path, + compilation_reason); ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str(); int expected_access = should_dex_be_compiled ? 0 : -1; std::string odex = GetSecondaryDexArtifact(path, "odex"); @@ -481,41 +477,35 @@ protected: bool downgrade, bool should_binder_call_succeed, /*out */ binder::Status* binder_result) { - std::unique_ptr package_name_ptr(new std::string(package_name_)); - std::unique_ptr out_path( - oat_dir == nullptr ? nullptr : new std::string(oat_dir)); - std::unique_ptr class_loader_context_ptr(new std::string("&")); - std::unique_ptr se_info_ptr(new std::string(se_info_)); + std::optional out_path = oat_dir ? std::make_optional(oat_dir) : std::nullopt; + std::string class_loader_context = "&"; int32_t target_sdk_version = 0; // default - std::unique_ptr profile_name_ptr(new std::string("primary.prof")); - std::unique_ptr dm_path_ptr = nullptr; - if (dm_path != nullptr) { - dm_path_ptr.reset(new std::string(dm_path)); - } - std::unique_ptr compilation_reason_ptr(new std::string("test-reason")); + std::string profile_name = "primary.prof"; + std::optional dm_path_opt = dm_path ? std::make_optional(dm_path) : std::nullopt; + std::string compilation_reason = "test-reason"; bool prof_result; ASSERT_BINDER_SUCCESS(service_->prepareAppProfile( - package_name_, kTestUserId, kTestAppId, *profile_name_ptr, apk_path_, - dm_path_ptr, &prof_result)); + package_name_, kTestUserId, kTestAppId, profile_name, apk_path_, + dm_path_opt, &prof_result)); ASSERT_TRUE(prof_result); binder::Status result = service_->dexopt(apk_path_, uid, - package_name_ptr, + package_name_, kRuntimeIsa, dexopt_needed, out_path, dex_flags, compiler_filter, volume_uuid_, - class_loader_context_ptr, - se_info_ptr, + class_loader_context, + se_info_, downgrade, target_sdk_version, - profile_name_ptr, - dm_path_ptr, - compilation_reason_ptr); + profile_name, + dm_path_opt, + compilation_reason); ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str(); if (!should_binder_call_succeed) { @@ -953,7 +943,7 @@ class ProfileTest : public DexoptTest { bool result; ASSERT_BINDER_SUCCESS(service_->prepareAppProfile( package_name, kTestUserId, kTestAppId, profile_name, apk_path_, - /*dex_metadata*/ nullptr, &result)); + /*dex_metadata*/ {}, &result)); ASSERT_EQ(expected_result, result); if (!expected_result) { diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp index a31d510565..727867720d 100644 --- a/cmds/installd/tests/installd_service_test.cpp +++ b/cmds/installd/tests/installd_service_test.cpp @@ -99,15 +99,14 @@ static int stat_mode(const char* path) { class ServiceTest : public testing::Test { protected: InstalldNativeService* service; - std::unique_ptr testUuid; + std::optional testUuid; virtual void SetUp() { setenv("ANDROID_LOG_TAGS", "*:v", 1); android::base::InitLogging(nullptr); service = new InstalldNativeService(); - testUuid = std::make_unique(); - *testUuid = std::string(kTestUuid); + testUuid = kTestUuid; system("mkdir -p /data/local/tmp/user/0"); init_globals_from_data_and_root(); @@ -322,7 +321,7 @@ TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot) { // Request a snapshot of the CE content but not the DE content. int64_t ce_snapshot_inode; - ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), + ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional("TEST"), "com.foo", 0, 37, FLAG_STORAGE_CE, &ce_snapshot_inode)); struct stat buf; memset(&buf, 0, sizeof(buf)); @@ -344,7 +343,7 @@ TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot) { 0700, 10000, 20000, false /* follow_symlinks */)); // Request a snapshot of the DE content but not the CE content. - ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), + ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional("TEST"), "com.foo", 0, 37, FLAG_STORAGE_DE, &ce_snapshot_inode)); // Only DE content snapshot was requested. ASSERT_EQ(ce_snapshot_inode, 0); @@ -365,7 +364,7 @@ TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot) { 0700, 10000, 20000, false /* follow_symlinks */)); // Request a snapshot of both the CE as well as the DE content. - ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), + ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional("TEST"), "com.foo", 0, 37, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr)); ASSERT_TRUE(android::base::ReadFileToString( @@ -407,10 +406,10 @@ TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_TwoSnapshotsWithTheSameId) { 0700, 10000, 20000, false /* follow_symlinks */)); // Request snapshot for the package com.foo. - ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), + ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional("TEST"), "com.foo", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr)); // Now request snapshot with the same id for the package com.bar - ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), + ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional("TEST"), "com.bar", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr)); // Check that both snapshots have correct data in them. @@ -439,9 +438,9 @@ TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_AppDataAbsent) { ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_de_path, true)); int64_t ce_snapshot_inode; - ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), + ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional("TEST"), "com.foo", 0, 73, FLAG_STORAGE_CE, &ce_snapshot_inode)); - ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), + ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional("TEST"), "com.foo", 0, 73, FLAG_STORAGE_DE, nullptr)); // No CE content snapshot was performed. ASSERT_EQ(ce_snapshot_inode, 0); @@ -476,7 +475,7 @@ TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsExistingSnapshot) { "TEST_CONTENT_2_DE", fake_package_de_path + "/file2", 0700, 10000, 20000, false /* follow_symlinks */)); - ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), + ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional("TEST"), "com.foo", 0, 13, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr)); // Previous snapshot (with data for file1) must be cleared. @@ -497,7 +496,7 @@ TEST_F(AppDataSnapshotTest, SnapshotAppData_WrongVolumeUuid) { ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700)); ASSERT_TRUE(mkdirs(rollback_de_dir, 0700)); - EXPECT_BINDER_FAIL(service->snapshotAppData(std::make_unique("FOO"), + EXPECT_BINDER_FAIL(service->snapshotAppData(std::make_optional("FOO"), "com.foo", 0, 17, FLAG_STORAGE_DE, nullptr)); } @@ -524,7 +523,7 @@ TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsCache) { ASSERT_TRUE(android::base::WriteStringToFile( "TEST_CONTENT_DE", fake_package_de_code_cache_path + "/file1", 0700, 10000, 20000, false /* follow_symlinks */)); - ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique("TEST"), + ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional("TEST"), "com.foo", 0, 23, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr)); // The snapshot call must clear cache. struct stat sb; @@ -558,7 +557,7 @@ TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot) { "TEST_CONTENT_DE", fake_package_de_path + "/file1", 0700, 10000, 20000, false /* follow_symlinks */)); - ASSERT_BINDER_SUCCESS(service->restoreAppDataSnapshot(std::make_unique("TEST"), + ASSERT_BINDER_SUCCESS(service->restoreAppDataSnapshot(std::make_optional("TEST"), "com.foo", 10000, "", 0, 239, FLAG_STORAGE_DE | FLAG_STORAGE_CE)); std::string ce_content, de_content; @@ -584,7 +583,7 @@ TEST_F(AppDataSnapshotTest, CreateSnapshotThenDestroyIt) { int64_t ce_snapshot_inode; // Request a snapshot of both the CE as well as the DE content. - ASSERT_TRUE(service->snapshotAppData(std::make_unique("TEST"), + ASSERT_TRUE(service->snapshotAppData(std::make_optional("TEST"), "com.foo", 0, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk()); // Because CE data snapshot was requested, ce_snapshot_inode can't be null. ASSERT_NE(0, ce_snapshot_inode); @@ -594,7 +593,7 @@ TEST_F(AppDataSnapshotTest, CreateSnapshotThenDestroyIt) { ASSERT_EQ(0, stat((rollback_de_dir + "/com.foo").c_str(), &sb)); - ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique("TEST"), + ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_optional("TEST"), "com.foo", 0, ce_snapshot_inode, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk()); // Check snapshot is deleted. ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb)); @@ -615,7 +614,7 @@ TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) { "DE_RESTORE_CONTENT", rollback_de_dir + "/com.foo/file1", 0700, 10000, 20000, false /* follow_symlinks */)); - ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique("TEST"), + ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_optional("TEST"), "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk()); // Check snapshot is deleted. @@ -624,7 +623,7 @@ TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) { ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb)); // Check that deleting already deleted snapshot is no-op. - ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique("TEST"), + ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_optional("TEST"), "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk()); } @@ -637,7 +636,7 @@ TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_WrongVolumeUuid) { ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700)); ASSERT_TRUE(mkdirs(rollback_de_dir, 0700)); - ASSERT_FALSE(service->destroyAppDataSnapshot(std::make_unique("BAR"), + ASSERT_FALSE(service->destroyAppDataSnapshot(std::make_optional("BAR"), "com.foo", 0, 0, 43, FLAG_STORAGE_DE).isOk()); } @@ -650,7 +649,7 @@ TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot_WrongVolumeUuid) { ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700)); ASSERT_TRUE(mkdirs(rollback_de_dir, 0700)); - EXPECT_BINDER_FAIL(service->restoreAppDataSnapshot(std::make_unique("BAR"), + EXPECT_BINDER_FAIL(service->restoreAppDataSnapshot(std::make_optional("BAR"), "com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE)); } diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index aeca12b582..4ab144bdf1 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -115,12 +115,12 @@ int32_t AppOpsManager::checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t ui } int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) { - return noteOp(op, uid, callingPackage, std::unique_ptr(), + return noteOp(op, uid, callingPackage, {}, String16("Legacy AppOpsManager.noteOp call")); } int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::unique_ptr& featureId, const String16& message) { + const std::optional& featureId, const String16& message) { sp service = getService(); int32_t mode = service != nullptr ? service->noteOperation(op, uid, callingPackage, featureId, shouldCollectNotes(op), @@ -132,12 +132,12 @@ int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPa int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, bool startIfModeDefault) { - return startOpNoThrow(op, uid, callingPackage, startIfModeDefault, std::unique_ptr(), + return startOpNoThrow(op, uid, callingPackage, startIfModeDefault, {}, String16("Legacy AppOpsManager.startOpNoThrow call")); } int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, - bool startIfModeDefault, const std::unique_ptr& featureId, + bool startIfModeDefault, const std::optional& featureId, const String16& message) { sp service = getService(); int32_t mode = service != nullptr @@ -149,11 +149,11 @@ int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& c } void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) { - finishOp(op, uid, callingPackage, std::unique_ptr()); + finishOp(op, uid, callingPackage, {}); } void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::unique_ptr& callingFeatureId) { + const std::optional& callingFeatureId) { sp service = getService(); if (service != nullptr) { service->finishOperation(getClientId(), op, uid, callingPackage, callingFeatureId); diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index a5555a304f..50e23b50a7 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -22,6 +22,8 @@ #include #include +#include + namespace android { // ---------------------------------------------------------------------- @@ -47,7 +49,7 @@ public: } virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName, - const std::unique_ptr& featureId, bool shouldCollectAsyncNotedOp, + const std::optional& featureId, bool shouldCollectAsyncNotedOp, const String16& message) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); @@ -64,7 +66,7 @@ public: } virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName, const std::unique_ptr& featureId, + const String16& packageName, const std::optional& featureId, bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); @@ -83,7 +85,7 @@ public: } virtual void finishOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName, const std::unique_ptr& featureId) { + const String16& packageName, const std::optional& featureId) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeStrongBinder(token); @@ -182,7 +184,7 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - std::unique_ptr featureId; + std::optional featureId; data.readString16(&featureId); bool shouldCollectAsyncNotedOp = data.readInt32() == 1; String16 message = data.readString16(); @@ -198,7 +200,7 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - std::unique_ptr featureId; + std::optional featureId; data.readString16(&featureId); bool startIfModeDefault = data.readInt32() == 1; bool shouldCollectAsyncNotedOp = data.readInt32() == 1; @@ -215,7 +217,7 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - std::unique_ptr featureId; + std::optional featureId; data.readString16(&featureId); finishOperation(token, code, uid, packageName, featureId); reply->writeNoException(); diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index beab270387..5f1f682a5b 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -751,6 +751,13 @@ status_t Parcel::writeUtf8AsUtf16(const std::string& str) { return NO_ERROR; } +status_t Parcel::writeUtf8AsUtf16(const std::optional& str) { + if (!str) { + return writeInt32(-1); + } + return writeUtf8AsUtf16(*str); +} + status_t Parcel::writeUtf8AsUtf16(const std::unique_ptr& str) { if (!str) { return writeInt32(-1); @@ -775,6 +782,12 @@ status_t Parcel::writeByteVector(const std::vector& val) { return writeByteVectorInternal(val.data(), val.size()); } +status_t Parcel::writeByteVector(const std::optional>& val) +{ + if (!val) return writeInt32(-1); + return writeByteVectorInternal(val->data(), val->size()); +} + status_t Parcel::writeByteVector(const std::unique_ptr>& val) { if (!val) return writeInt32(-1); @@ -785,6 +798,12 @@ status_t Parcel::writeByteVector(const std::vector& val) { return writeByteVectorInternal(reinterpret_cast(val.data()), val.size()); } +status_t Parcel::writeByteVector(const std::optional>& val) +{ + if (!val) return writeInt32(-1); + return writeByteVectorInternal(reinterpret_cast(val->data()), val->size()); +} + status_t Parcel::writeByteVector(const std::unique_ptr>& val) { if (!val) return writeInt32(-1); @@ -796,6 +815,11 @@ status_t Parcel::writeInt32Vector(const std::vector& val) return writeTypedVector(val, &Parcel::writeInt32); } +status_t Parcel::writeInt32Vector(const std::optional>& val) +{ + return writeNullableTypedVector(val, &Parcel::writeInt32); +} + status_t Parcel::writeInt32Vector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeInt32); @@ -806,6 +830,11 @@ status_t Parcel::writeInt64Vector(const std::vector& val) return writeTypedVector(val, &Parcel::writeInt64); } +status_t Parcel::writeInt64Vector(const std::optional>& val) +{ + return writeNullableTypedVector(val, &Parcel::writeInt64); +} + status_t Parcel::writeInt64Vector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeInt64); @@ -816,6 +845,11 @@ status_t Parcel::writeUint64Vector(const std::vector& val) return writeTypedVector(val, &Parcel::writeUint64); } +status_t Parcel::writeUint64Vector(const std::optional>& val) +{ + return writeNullableTypedVector(val, &Parcel::writeUint64); +} + status_t Parcel::writeUint64Vector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeUint64); @@ -826,6 +860,11 @@ status_t Parcel::writeFloatVector(const std::vector& val) return writeTypedVector(val, &Parcel::writeFloat); } +status_t Parcel::writeFloatVector(const std::optional>& val) +{ + return writeNullableTypedVector(val, &Parcel::writeFloat); +} + status_t Parcel::writeFloatVector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeFloat); @@ -836,6 +875,11 @@ status_t Parcel::writeDoubleVector(const std::vector& val) return writeTypedVector(val, &Parcel::writeDouble); } +status_t Parcel::writeDoubleVector(const std::optional>& val) +{ + return writeNullableTypedVector(val, &Parcel::writeDouble); +} + status_t Parcel::writeDoubleVector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeDouble); @@ -846,6 +890,11 @@ status_t Parcel::writeBoolVector(const std::vector& val) return writeTypedVector(val, &Parcel::writeBool); } +status_t Parcel::writeBoolVector(const std::optional>& val) +{ + return writeNullableTypedVector(val, &Parcel::writeBool); +} + status_t Parcel::writeBoolVector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeBool); @@ -856,6 +905,11 @@ status_t Parcel::writeCharVector(const std::vector& val) return writeTypedVector(val, &Parcel::writeChar); } +status_t Parcel::writeCharVector(const std::optional>& val) +{ + return writeNullableTypedVector(val, &Parcel::writeChar); +} + status_t Parcel::writeCharVector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeChar); @@ -866,12 +920,23 @@ status_t Parcel::writeString16Vector(const std::vector& val) return writeTypedVector(val, &Parcel::writeString16); } +status_t Parcel::writeString16Vector( + const std::optional>>& val) +{ + return writeNullableTypedVector(val, &Parcel::writeString16); +} + status_t Parcel::writeString16Vector( const std::unique_ptr>>& val) { return writeNullableTypedVector(val, &Parcel::writeString16); } +status_t Parcel::writeUtf8VectorAsUtf16Vector( + const std::optional>>& val) { + return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16); +} + status_t Parcel::writeUtf8VectorAsUtf16Vector( const std::unique_ptr>>& val) { return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16); @@ -997,6 +1062,15 @@ status_t Parcel::writeString8(const String8& str) return err; } +status_t Parcel::writeString16(const std::optional& str) +{ + if (!str) { + return writeInt32(-1); + } + + return writeString16(*str); +} + status_t Parcel::writeString16(const std::unique_ptr& str) { if (!str) { @@ -1039,11 +1113,20 @@ status_t Parcel::writeStrongBinderVector(const std::vector>& val) return writeTypedVector(val, &Parcel::writeStrongBinder); } +status_t Parcel::writeStrongBinderVector(const std::optional>>& val) +{ + return writeNullableTypedVector(val, &Parcel::writeStrongBinder); +} + status_t Parcel::writeStrongBinderVector(const std::unique_ptr>>& val) { return writeNullableTypedVector(val, &Parcel::writeStrongBinder); } +status_t Parcel::readStrongBinderVector(std::optional>>* val) const { + return readNullableTypedVector(val, &Parcel::readNullableStrongBinder); +} + status_t Parcel::readStrongBinderVector(std::unique_ptr>>* val) const { return readNullableTypedVector(val, &Parcel::readNullableStrongBinder); } @@ -1142,6 +1225,10 @@ status_t Parcel::writeUniqueFileDescriptorVector(const std::vector>& val) { + return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor); +} + status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor); } @@ -1475,6 +1562,17 @@ status_t Parcel::readByteVector(std::vector* val) const { return readByteVectorInternal(val, size); } +status_t Parcel::readByteVector(std::optional>* val) const { + size_t size; + if (status_t status = reserveOutVector(val, &size); status != OK) return status; + if (!*val) { + // reserveOutVector does not create the out vector if size is < 0. + // This occurs when writing a null byte vector. + return OK; + } + return readByteVectorInternal(&**val, size); +} + status_t Parcel::readByteVector(std::unique_ptr>* val) const { size_t size; if (status_t status = reserveOutVector(val, &size); status != OK) return status; @@ -1486,6 +1584,17 @@ status_t Parcel::readByteVector(std::unique_ptr>* val) const return readByteVectorInternal(val->get(), size); } +status_t Parcel::readByteVector(std::optional>* val) const { + size_t size; + if (status_t status = reserveOutVector(val, &size); status != OK) return status; + if (!*val) { + // reserveOutVector does not create the out vector if size is < 0. + // This occurs when writing a null byte vector. + return OK; + } + return readByteVectorInternal(&**val, size); +} + status_t Parcel::readByteVector(std::unique_ptr>* val) const { size_t size; if (status_t status = reserveOutVector(val, &size); status != OK) return status; @@ -1497,6 +1606,10 @@ status_t Parcel::readByteVector(std::unique_ptr>* val) cons return readByteVectorInternal(val->get(), size); } +status_t Parcel::readInt32Vector(std::optional>* val) const { + return readNullableTypedVector(val, &Parcel::readInt32); +} + status_t Parcel::readInt32Vector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readInt32); } @@ -1505,6 +1618,10 @@ status_t Parcel::readInt32Vector(std::vector* val) const { return readTypedVector(val, &Parcel::readInt32); } +status_t Parcel::readInt64Vector(std::optional>* val) const { + return readNullableTypedVector(val, &Parcel::readInt64); +} + status_t Parcel::readInt64Vector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readInt64); } @@ -1513,6 +1630,10 @@ status_t Parcel::readInt64Vector(std::vector* val) const { return readTypedVector(val, &Parcel::readInt64); } +status_t Parcel::readUint64Vector(std::optional>* val) const { + return readNullableTypedVector(val, &Parcel::readUint64); +} + status_t Parcel::readUint64Vector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readUint64); } @@ -1521,6 +1642,10 @@ status_t Parcel::readUint64Vector(std::vector* val) const { return readTypedVector(val, &Parcel::readUint64); } +status_t Parcel::readFloatVector(std::optional>* val) const { + return readNullableTypedVector(val, &Parcel::readFloat); +} + status_t Parcel::readFloatVector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readFloat); } @@ -1529,6 +1654,10 @@ status_t Parcel::readFloatVector(std::vector* val) const { return readTypedVector(val, &Parcel::readFloat); } +status_t Parcel::readDoubleVector(std::optional>* val) const { + return readNullableTypedVector(val, &Parcel::readDouble); +} + status_t Parcel::readDoubleVector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readDouble); } @@ -1537,6 +1666,28 @@ status_t Parcel::readDoubleVector(std::vector* val) const { return readTypedVector(val, &Parcel::readDouble); } +status_t Parcel::readBoolVector(std::optional>* val) const { + const int32_t start = dataPosition(); + int32_t size; + status_t status = readInt32(&size); + val->reset(); + + if (status != OK || size < 0) { + return status; + } + + setDataPosition(start); + val->emplace(); + + status = readBoolVector(&**val); + + if (status != OK) { + val->reset(); + } + + return status; +} + status_t Parcel::readBoolVector(std::unique_ptr>* val) const { const int32_t start = dataPosition(); int32_t size; @@ -1589,6 +1740,10 @@ status_t Parcel::readBoolVector(std::vector* val) const { return OK; } +status_t Parcel::readCharVector(std::optional>* val) const { + return readNullableTypedVector(val, &Parcel::readChar); +} + status_t Parcel::readCharVector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readChar); } @@ -1597,6 +1752,11 @@ status_t Parcel::readCharVector(std::vector* val) const { return readTypedVector(val, &Parcel::readChar); } +status_t Parcel::readString16Vector( + std::optional>>* val) const { + return readNullableTypedVector(val, &Parcel::readString16); +} + status_t Parcel::readString16Vector( std::unique_ptr>>* val) const { return readNullableTypedVector(val, &Parcel::readString16); @@ -1606,6 +1766,11 @@ status_t Parcel::readString16Vector(std::vector* val) const { return readTypedVector(val, &Parcel::readString16); } +status_t Parcel::readUtf8VectorFromUtf16Vector( + std::optional>>* val) const { + return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16); +} + status_t Parcel::readUtf8VectorFromUtf16Vector( std::unique_ptr>>* val) const { return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16); @@ -1798,6 +1963,21 @@ status_t Parcel::readUtf8FromUtf16(std::string* str) const { return NO_ERROR; } +status_t Parcel::readUtf8FromUtf16(std::optional* str) const { + const int32_t start = dataPosition(); + int32_t size; + status_t status = readInt32(&size); + str->reset(); + + if (status != OK || size < 0) { + return status; + } + + setDataPosition(start); + str->emplace(); + return readUtf8FromUtf16(&**str); +} + status_t Parcel::readUtf8FromUtf16(std::unique_ptr* str) const { const int32_t start = dataPosition(); int32_t size; @@ -1874,6 +2054,29 @@ String16 Parcel::readString16() const return String16(); } +status_t Parcel::readString16(std::optional* pArg) const +{ + const int32_t start = dataPosition(); + int32_t size; + status_t status = readInt32(&size); + pArg->reset(); + + if (status != OK || size < 0) { + return status; + } + + setDataPosition(start); + pArg->emplace(); + + status = readString16(&**pArg); + + if (status != OK) { + pArg->reset(); + } + + return status; +} + status_t Parcel::readString16(std::unique_ptr* pArg) const { const int32_t start = dataPosition(); @@ -2079,6 +2282,10 @@ status_t Parcel::readUniqueParcelFileDescriptor(base::unique_fd* val) const return OK; } +status_t Parcel::readUniqueFileDescriptorVector(std::optional>* val) const { + return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor); +} + status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor); } diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index 5b6eb6863e..e4641822ad 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -21,6 +21,8 @@ #include +#include + #ifdef __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif @@ -134,18 +136,18 @@ public: // const String16&) instead int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage); int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::unique_ptr& featureId, const String16& message); + const std::optional& featureId, const String16& message); // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&, // const String16&) instead int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, bool startIfModeDefault); int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, - bool startIfModeDefault, const std::unique_ptr& featureId, + bool startIfModeDefault, const std::optional& featureId, const String16& message); // @Deprecated, use finishOp(int32_t, int32_t, const String16&, bool, const String16&) instead void finishOp(int32_t op, int32_t uid, const String16& callingPackage); void finishOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::unique_ptr& featureId); + const std::optional& featureId); void startWatchingMode(int32_t op, const String16& packageName, const sp& callback); void stopWatchingMode(const sp& callback); diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index 1b4bcce20f..95a80ff268 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -21,6 +21,8 @@ #include #include +#include + #ifdef __ANDROID_VNDK__ #error "This header is not visible to vendors" #endif @@ -36,13 +38,13 @@ public: virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName, - const std::unique_ptr& featureId, bool shouldCollectAsyncNotedOp, + const std::optional& featureId, bool shouldCollectAsyncNotedOp, const String16& message) = 0; virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName, const std::unique_ptr& featureId, + const String16& packageName, const std::optional& featureId, bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) = 0; virtual void finishOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName, const std::unique_ptr& featureId) = 0; + const String16& packageName, const std::optional& featureId) = 0; virtual void startWatchingMode(int32_t op, const String16& packageName, const sp& callback) = 0; virtual void stopWatchingMode(const sp& callback) = 0; diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 4b1a758f38..97f1aeeb7b 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -120,6 +120,7 @@ public: status_t writeCString(const char* str); status_t writeString8(const String8& str); status_t writeString16(const String16& str); + status_t writeString16(const std::optional& str); status_t writeString16(const std::unique_ptr& str); status_t writeString16(const char16_t* str, size_t len); status_t writeStrongBinder(const sp& val); @@ -131,33 +132,48 @@ public: // Take a UTF8 encoded string, convert to UTF16, write it to the parcel. status_t writeUtf8AsUtf16(const std::string& str); + status_t writeUtf8AsUtf16(const std::optional& str); status_t writeUtf8AsUtf16(const std::unique_ptr& str); + status_t writeByteVector(const std::optional>& val); status_t writeByteVector(const std::unique_ptr>& val); status_t writeByteVector(const std::vector& val); + status_t writeByteVector(const std::optional>& val); status_t writeByteVector(const std::unique_ptr>& val); status_t writeByteVector(const std::vector& val); + status_t writeInt32Vector(const std::optional>& val); status_t writeInt32Vector(const std::unique_ptr>& val); status_t writeInt32Vector(const std::vector& val); + status_t writeInt64Vector(const std::optional>& val); status_t writeInt64Vector(const std::unique_ptr>& val); status_t writeInt64Vector(const std::vector& val); + status_t writeUint64Vector(const std::optional>& val); status_t writeUint64Vector(const std::unique_ptr>& val); status_t writeUint64Vector(const std::vector& val); + status_t writeFloatVector(const std::optional>& val); status_t writeFloatVector(const std::unique_ptr>& val); status_t writeFloatVector(const std::vector& val); + status_t writeDoubleVector(const std::optional>& val); status_t writeDoubleVector(const std::unique_ptr>& val); status_t writeDoubleVector(const std::vector& val); + status_t writeBoolVector(const std::optional>& val); status_t writeBoolVector(const std::unique_ptr>& val); status_t writeBoolVector(const std::vector& val); + status_t writeCharVector(const std::optional>& val); status_t writeCharVector(const std::unique_ptr>& val); status_t writeCharVector(const std::vector& val); + status_t writeString16Vector( + const std::optional>>& val); status_t writeString16Vector( const std::unique_ptr>>& val); status_t writeString16Vector(const std::vector& val); + status_t writeUtf8VectorAsUtf16Vector( + const std::optional>>& val); status_t writeUtf8VectorAsUtf16Vector( const std::unique_ptr>>& val); status_t writeUtf8VectorAsUtf16Vector(const std::vector& val); + status_t writeStrongBinderVector(const std::optional>>& val); status_t writeStrongBinderVector(const std::unique_ptr>>& val); status_t writeStrongBinderVector(const std::vector>& val); @@ -166,13 +182,19 @@ public: template && std::is_same_v,int8_t>, bool> = 0> status_t writeEnumVector(const std::vector& val); template && std::is_same_v,int8_t>, bool> = 0> + status_t writeEnumVector(const std::optional>& val); + template && std::is_same_v,int8_t>, bool> = 0> status_t writeEnumVector(const std::unique_ptr>& val); // Write an Enum vector with underlying type != int8_t. template && !std::is_same_v,int8_t>, bool> = 0> status_t writeEnumVector(const std::vector& val); template && !std::is_same_v,int8_t>, bool> = 0> + status_t writeEnumVector(const std::optional>& val); + template && !std::is_same_v,int8_t>, bool> = 0> status_t writeEnumVector(const std::unique_ptr>& val); + template + status_t writeParcelableVector(const std::optional>>& val); template status_t writeParcelableVector(const std::unique_ptr>>& val); template @@ -180,6 +202,8 @@ public: template status_t writeParcelableVector(const std::vector& val); + template + status_t writeNullableParcelable(const std::optional& parcelable); template status_t writeNullableParcelable(const std::unique_ptr& parcelable); @@ -194,6 +218,8 @@ public: template status_t writeVectorSize(const std::vector& val); template + status_t writeVectorSize(const std::optional>& val); + template status_t writeVectorSize(const std::unique_ptr>& val); // Place a native_handle into the parcel (the native_handle's file- @@ -228,6 +254,8 @@ public: // Place a vector of file desciptors into the parcel. Each descriptor is // dup'd as in writeDupFileDescriptor + status_t writeUniqueFileDescriptorVector( + const std::optional>& val); status_t writeUniqueFileDescriptorVector( const std::unique_ptr>& val); status_t writeUniqueFileDescriptorVector( @@ -278,6 +306,7 @@ public: // Read a UTF16 encoded string, convert to UTF8 status_t readUtf8FromUtf16(std::string* str) const; + status_t readUtf8FromUtf16(std::optional* str) const; status_t readUtf8FromUtf16(std::unique_ptr* str) const; const char* readCString() const; @@ -285,25 +314,32 @@ public: status_t readString8(String8* pArg) const; String16 readString16() const; status_t readString16(String16* pArg) const; + status_t readString16(std::optional* pArg) const; status_t readString16(std::unique_ptr* pArg) const; const char16_t* readString16Inplace(size_t* outLen) const; sp readStrongBinder() const; status_t readStrongBinder(sp* val) const; status_t readNullableStrongBinder(sp* val) const; - // Read an Enum vector with underlying type int8_t. // Does not use padding; each byte is contiguous. template && std::is_same_v,int8_t>, bool> = 0> status_t readEnumVector(std::vector* val) const; template && std::is_same_v,int8_t>, bool> = 0> status_t readEnumVector(std::unique_ptr>* val) const; + template && std::is_same_v,int8_t>, bool> = 0> + status_t readEnumVector(std::optional>* val) const; // Read an Enum vector with underlying type != int8_t. template && !std::is_same_v,int8_t>, bool> = 0> status_t readEnumVector(std::vector* val) const; template && !std::is_same_v,int8_t>, bool> = 0> status_t readEnumVector(std::unique_ptr>* val) const; + template && !std::is_same_v,int8_t>, bool> = 0> + status_t readEnumVector(std::optional>* val) const; + template + status_t readParcelableVector( + std::optional>>* val) const; template status_t readParcelableVector( std::unique_ptr>>* val) const; @@ -312,6 +348,8 @@ public: status_t readParcelable(Parcelable* parcelable) const; + template + status_t readParcelable(std::optional* parcelable) const; template status_t readParcelable(std::unique_ptr* parcelable) const; @@ -321,30 +359,44 @@ public: template status_t readNullableStrongBinder(sp* val) const; + status_t readStrongBinderVector(std::optional>>* val) const; status_t readStrongBinderVector(std::unique_ptr>>* val) const; status_t readStrongBinderVector(std::vector>* val) const; + status_t readByteVector(std::optional>* val) const; status_t readByteVector(std::unique_ptr>* val) const; status_t readByteVector(std::vector* val) const; + status_t readByteVector(std::optional>* val) const; status_t readByteVector(std::unique_ptr>* val) const; status_t readByteVector(std::vector* val) const; + status_t readInt32Vector(std::optional>* val) const; status_t readInt32Vector(std::unique_ptr>* val) const; status_t readInt32Vector(std::vector* val) const; + status_t readInt64Vector(std::optional>* val) const; status_t readInt64Vector(std::unique_ptr>* val) const; status_t readInt64Vector(std::vector* val) const; + status_t readUint64Vector(std::optional>* val) const; status_t readUint64Vector(std::unique_ptr>* val) const; status_t readUint64Vector(std::vector* val) const; + status_t readFloatVector(std::optional>* val) const; status_t readFloatVector(std::unique_ptr>* val) const; status_t readFloatVector(std::vector* val) const; + status_t readDoubleVector(std::optional>* val) const; status_t readDoubleVector(std::unique_ptr>* val) const; status_t readDoubleVector(std::vector* val) const; + status_t readBoolVector(std::optional>* val) const; status_t readBoolVector(std::unique_ptr>* val) const; status_t readBoolVector(std::vector* val) const; + status_t readCharVector(std::optional>* val) const; status_t readCharVector(std::unique_ptr>* val) const; status_t readCharVector(std::vector* val) const; + status_t readString16Vector( + std::optional>>* val) const; status_t readString16Vector( std::unique_ptr>>* val) const; status_t readString16Vector(std::vector* val) const; + status_t readUtf8VectorFromUtf16Vector( + std::optional>>* val) const; status_t readUtf8VectorFromUtf16Vector( std::unique_ptr>>* val) const; status_t readUtf8VectorFromUtf16Vector(std::vector* val) const; @@ -358,10 +410,15 @@ public: template status_t resizeOutVector(std::vector* val) const; template + status_t resizeOutVector(std::optional>* val) const; + template status_t resizeOutVector(std::unique_ptr>* val) const; template status_t reserveOutVector(std::vector* val, size_t* size) const; template + status_t reserveOutVector(std::optional>* val, + size_t* size) const; + template status_t reserveOutVector(std::unique_ptr>* val, size_t* size) const; @@ -396,6 +453,8 @@ public: // Retrieve a vector of smart file descriptors from the parcel. + status_t readUniqueFileDescriptorVector( + std::optional>* val) const; status_t readUniqueFileDescriptorVector( std::unique_ptr>* val) const; status_t readUniqueFileDescriptorVector( @@ -490,6 +549,9 @@ private: status_t unsafeReadTypedVector(std::vector* val, status_t(Parcel::*read_func)(U*) const) const; template + status_t readNullableTypedVector(std::optional>* val, + status_t(Parcel::*read_func)(T*) const) const; + template status_t readNullableTypedVector(std::unique_ptr>* val, status_t(Parcel::*read_func)(T*) const) const; template @@ -499,9 +561,15 @@ private: status_t unsafeWriteTypedVector(const std::vector& val, status_t(Parcel::*write_func)(U)); template + status_t writeNullableTypedVector(const std::optional>& val, + status_t(Parcel::*write_func)(const T&)); + template status_t writeNullableTypedVector(const std::unique_ptr>& val, status_t(Parcel::*write_func)(const T&)); template + status_t writeNullableTypedVector(const std::optional>& val, + status_t(Parcel::*write_func)(T)); + template status_t writeNullableTypedVector(const std::unique_ptr>& val, status_t(Parcel::*write_func)(T)); template @@ -688,6 +756,15 @@ status_t Parcel::writeVectorSize(const std::vector& val) { return writeInt32(static_cast(val.size())); } +template +status_t Parcel::writeVectorSize(const std::optional>& val) { + if (!val) { + return writeInt32(-1); + } + + return writeVectorSize(*val); +} + template status_t Parcel::writeVectorSize(const std::unique_ptr>& val) { if (!val) { @@ -712,6 +789,22 @@ status_t Parcel::resizeOutVector(std::vector* val) const { return OK; } +template +status_t Parcel::resizeOutVector(std::optional>* val) const { + int32_t size; + status_t err = readInt32(&size); + if (err != NO_ERROR) { + return err; + } + + val->reset(); + if (size >= 0) { + val->emplace(size_t(size)); + } + + return OK; +} + template status_t Parcel::resizeOutVector(std::unique_ptr>* val) const { int32_t size; @@ -744,6 +837,25 @@ status_t Parcel::reserveOutVector(std::vector* val, size_t* size) const { return OK; } +template +status_t Parcel::reserveOutVector(std::optional>* val, size_t* size) const { + int32_t read_size; + status_t err = readInt32(&read_size); + if (err != NO_ERROR) { + return err; + } + + if (read_size >= 0) { + *size = static_cast(read_size); + val->emplace(); + (*val)->reserve(*size); + } else { + val->reset(); + } + + return OK; +} + template status_t Parcel::reserveOutVector(std::unique_ptr>* val, size_t* size) const { @@ -838,6 +950,30 @@ status_t Parcel::readTypedVector(std::vector* val, return unsafeReadTypedVector(val, read_func); } +template +status_t Parcel::readNullableTypedVector(std::optional>* val, + status_t(Parcel::*read_func)(T*) const) const { + const size_t start = dataPosition(); + int32_t size; + status_t status = readInt32(&size); + val->reset(); + + if (status != OK || size < 0) { + return status; + } + + setDataPosition(start); + val->emplace(); + + status = unsafeReadTypedVector(&**val, read_func); + + if (status != OK) { + val->reset(); + } + + return status; +} + template status_t Parcel::readNullableTypedVector(std::unique_ptr>* val, status_t(Parcel::*read_func)(T*) const) const { @@ -898,6 +1034,16 @@ status_t Parcel::writeTypedVector(const std::vector& val, return unsafeWriteTypedVector(val, write_func); } +template +status_t Parcel::writeNullableTypedVector(const std::optional>& val, + status_t(Parcel::*write_func)(const T&)) { + if (!val) { + return this->writeInt32(-1); + } + + return unsafeWriteTypedVector(*val, write_func); +} + template status_t Parcel::writeNullableTypedVector(const std::unique_ptr>& val, status_t(Parcel::*write_func)(const T&)) { @@ -908,6 +1054,16 @@ status_t Parcel::writeNullableTypedVector(const std::unique_ptr>& return unsafeWriteTypedVector(*val, write_func); } +template +status_t Parcel::writeNullableTypedVector(const std::optional>& val, + status_t(Parcel::*write_func)(T)) { + if (!val) { + return this->writeInt32(-1); + } + + return unsafeWriteTypedVector(*val, write_func); +} + template status_t Parcel::writeNullableTypedVector(const std::unique_ptr>& val, status_t(Parcel::*write_func)(T)) { @@ -923,6 +1079,30 @@ status_t Parcel::readParcelableVector(std::vector* val) const { return unsafeReadTypedVector(val, &Parcel::readParcelable); } +template +status_t Parcel::readParcelableVector(std::optional>>* val) const { + const size_t start = dataPosition(); + int32_t size; + status_t status = readInt32(&size); + val->reset(); + + if (status != OK || size < 0) { + return status; + } + + setDataPosition(start); + val->emplace(); + + using NullableT = std::optional; + status = unsafeReadTypedVector(&**val, &Parcel::readParcelable); + + if (status != OK) { + val->reset(); + } + + return status; +} + template status_t Parcel::readParcelableVector(std::unique_ptr>>* val) const { const size_t start = dataPosition(); @@ -937,7 +1117,8 @@ status_t Parcel::readParcelableVector(std::unique_ptrreset(new std::vector>()); - status = unsafeReadTypedVector(val->get(), &Parcel::readParcelable); + using NullableT = std::unique_ptr; + status = unsafeReadTypedVector(val->get(), &Parcel::readParcelable); if (status != OK) { val->reset(); @@ -946,6 +1127,29 @@ status_t Parcel::readParcelableVector(std::unique_ptr +status_t Parcel::readParcelable(std::optional* parcelable) const { + const size_t start = dataPosition(); + int32_t present; + status_t status = readInt32(&present); + parcelable->reset(); + + if (status != OK || !present) { + return status; + } + + setDataPosition(start); + parcelable->emplace(); + + status = readParcelable(&**parcelable); + + if (status != OK) { + parcelable->reset(); + } + + return status; +} + template status_t Parcel::readParcelable(std::unique_ptr* parcelable) const { const size_t start = dataPosition(); @@ -969,6 +1173,11 @@ status_t Parcel::readParcelable(std::unique_ptr* parcelable) const { return status; } +template +status_t Parcel::writeNullableParcelable(const std::optional& parcelable) { + return writeRawNullableParcelable(parcelable ? &*parcelable : nullptr); +} + template status_t Parcel::writeNullableParcelable(const std::unique_ptr& parcelable) { return writeRawNullableParcelable(parcelable.get()); @@ -979,6 +1188,16 @@ status_t Parcel::writeParcelableVector(const std::vector& val) { return unsafeWriteTypedVector(val, &Parcel::writeParcelable); } +template +status_t Parcel::writeParcelableVector(const std::optional>>& val) { + if (!val) { + return this->writeInt32(-1); + } + + using NullableT = std::optional; + return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable); +} + template status_t Parcel::writeParcelableVector(const std::unique_ptr>>& val) { if (val.get() == nullptr) { @@ -994,7 +1213,8 @@ status_t Parcel::writeParcelableVector(const std::shared_ptrwriteInt32(-1); } - return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable); + using NullableT = std::unique_ptr; + return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable); } template,int32_t>, bool>> @@ -1011,6 +1231,11 @@ status_t Parcel::writeEnumVector(const std::vector& val) { return writeByteVectorInternal(reinterpret_cast(val.data()), val.size()); } template && std::is_same_v,int8_t>, bool>> +status_t Parcel::writeEnumVector(const std::optional>& val) { + if (!val) return writeInt32(-1); + return writeByteVectorInternal(reinterpret_cast(val->data()), val->size()); +} +template && std::is_same_v,int8_t>, bool>> status_t Parcel::writeEnumVector(const std::unique_ptr>& val) { if (!val) return writeInt32(-1); return writeByteVectorInternal(reinterpret_cast(val->data()), val->size()); @@ -1020,6 +1245,10 @@ status_t Parcel::writeEnumVector(const std::vector& val) { return writeTypedVector(val, &Parcel::writeEnum); } template && !std::is_same_v,int8_t>, bool>> +status_t Parcel::writeEnumVector(const std::optional>& val) { + return writeNullableTypedVector(val, &Parcel::writeEnum); +} +template && !std::is_same_v,int8_t>, bool>> status_t Parcel::writeEnumVector(const std::unique_ptr>& val) { return writeNullableTypedVector(val, &Parcel::writeEnum); } @@ -1051,6 +1280,17 @@ status_t Parcel::readEnumVector(std::vector* val) const { return readByteVectorInternal(val, size); } template && std::is_same_v,int8_t>, bool>> +status_t Parcel::readEnumVector(std::optional>* val) const { + size_t size; + if (status_t status = reserveOutVector(val, &size); status != OK) return status; + if (!*val) { + // reserveOutVector does not create the out vector if size is < 0. + // This occurs when writing a null Enum vector. + return OK; + } + return readByteVectorInternal(&**val, size); +} +template && std::is_same_v,int8_t>, bool>> status_t Parcel::readEnumVector(std::unique_ptr>* val) const { size_t size; if (status_t status = reserveOutVector(val, &size); status != OK) return status; @@ -1066,6 +1306,10 @@ status_t Parcel::readEnumVector(std::vector* val) const { return readTypedVector(val, &Parcel::readEnum); } template && !std::is_same_v,int8_t>, bool>> +status_t Parcel::readEnumVector(std::optional>* val) const { + return readNullableTypedVector(val, &Parcel::readEnum); +} +template && !std::is_same_v,int8_t>, bool>> status_t Parcel::readEnumVector(std::unique_ptr>* val) const { return readNullableTypedVector(val, &Parcel::readEnum); } diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h index 4635ad84c6..2ede6c4b59 100644 --- a/libs/binder/include/binder/ParcelFileDescriptor.h +++ b/libs/binder/include/binder/ParcelFileDescriptor.h @@ -32,6 +32,7 @@ public: ParcelFileDescriptor(); explicit ParcelFileDescriptor(android::base::unique_fd fd); ParcelFileDescriptor(ParcelFileDescriptor&& other) : mFd(std::move(other.mFd)) { } + ParcelFileDescriptor& operator=(ParcelFileDescriptor&& other) = default; ~ParcelFileDescriptor() override; int get() const { return mFd.get(); } -- GitLab From 65d2971e87dd06e4f5a6f276299523efe23b755d Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Wed, 26 Feb 2020 11:52:10 +0000 Subject: [PATCH 0850/1255] Never send Binder / HIDL txn from atrace. Test: atrace ss atrace wm sanity check output Bug: 137366208 Change-Id: I98b6933db9b168ab290f04286535d1a109b59843 Merged-In: I98b6933db9b168ab290f04286535d1a109b59843 --- cmds/atrace/atrace.cpp | 81 ------------------------------------------ 1 file changed, 81 deletions(-) diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index cf75bbab3b..544e26c666 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -571,81 +571,6 @@ static bool setPrintTgidEnableIfPresent(bool enable) return true; } -// Poke all the binder-enabled processes in the system to get them to re-read -// their system properties. -static bool pokeBinderServices() -{ - sp sm = defaultServiceManager(); - Vector services = sm->listServices(); - for (size_t i = 0; i < services.size(); i++) { - sp obj = sm->checkService(services[i]); - if (obj != nullptr) { - Parcel data; - if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data, - nullptr, 0) != OK) { - if (false) { - // XXX: For some reason this fails on tablets trying to - // poke the "phone" service. It's not clear whether some - // are expected to fail. - String8 svc(services[i]); - fprintf(stderr, "error poking binder service %s\n", - svc.string()); - return false; - } - } - } - } - return true; -} - -// Poke all the HAL processes in the system to get them to re-read -// their system properties. -static void pokeHalServices() -{ - using ::android::hidl::base::V1_0::IBase; - using ::android::hidl::manager::V1_0::IServiceManager; - using ::android::hardware::hidl_string; - using ::android::hardware::Return; - - sp sm = ::android::hardware::defaultServiceManager(); - - if (sm == nullptr) { - fprintf(stderr, "failed to get IServiceManager to poke hal services\n"); - return; - } - - auto listRet = sm->list([&](const auto &interfaces) { - for (size_t i = 0; i < interfaces.size(); i++) { - string fqInstanceName = interfaces[i]; - string::size_type n = fqInstanceName.find('/'); - if (n == std::string::npos || interfaces[i].size() == n+1) - continue; - hidl_string fqInterfaceName = fqInstanceName.substr(0, n); - hidl_string instanceName = fqInstanceName.substr(n+1, std::string::npos); - Return> interfaceRet = sm->get(fqInterfaceName, instanceName); - if (!interfaceRet.isOk()) { - // ignore - continue; - } - - sp interface = interfaceRet; - if (interface == nullptr) { - // ignore - continue; - } - - auto notifyRet = interface->notifySyspropsChanged(); - if (!notifyRet.isOk()) { - // ignore - } - } - }); - if (!listRet.isOk()) { - // TODO(b/34242478) fix this when we determine the correct ACL - //fprintf(stderr, "failed to list services: %s\n", listRet.description().c_str()); - } -} - // Set the trace tags that userland tracing uses, and poke the running // processes to pick up the new value. static bool setTagsProperty(uint64_t tags) @@ -876,10 +801,6 @@ static bool setUpUserspaceTracing() } ok &= setAppCmdlineProperty(&packageList[0]); ok &= setTagsProperty(tags); -#if !ATRACE_SHMEM - ok &= pokeBinderServices(); - pokeHalServices(); -#endif if (g_tracePdx) { ok &= ServiceUtility::PokeServices(); } @@ -891,8 +812,6 @@ static void cleanUpUserspaceTracing() { setTagsProperty(0); clearAppProperties(); - pokeBinderServices(); - pokeHalServices(); if (g_tracePdx) { ServiceUtility::PokeServices(); -- GitLab From 77f83368b1292557b70ff82b16a27a96ab424b04 Mon Sep 17 00:00:00 2001 From: Jon Spivack Date: Thu, 13 Feb 2020 18:10:45 -0800 Subject: [PATCH 0851/1255] Add flag to cmd for dynamic services When cmd is called with the -w flag, it will call ServiceManager::waitForService instead of checkService. This will make dynamic services start and block until they are ready for use. Bug: 149526916 Test: atest ApexRollbackTests (with and without this flag applied within for dynamic apexd) Change-Id: Iad0c3d7aa75e5830da10a84bd753d3011438259f --- cmds/cmd/cmd.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp index 8dad47502f..be2c702034 100644 --- a/cmds/cmd/cmd.cpp +++ b/cmds/cmd/cmd.cpp @@ -185,7 +185,7 @@ int cmdMain(const std::vector& argv, TextOutput& outputLog, Te int argc = argv.size(); if (argc == 0) { - errorLog << "cmd: No service specified; use -l to list all services" << endl; + errorLog << "cmd: No service specified; use -l to list all running services. Use -w to start and wait for a service." << endl; return 20; } @@ -203,14 +203,22 @@ int cmdMain(const std::vector& argv, TextOutput& outputLog, Te return 0; } - const auto cmd = argv[0]; + bool waitForService = ((argc > 1) && (argv[0] == "-w")); + int serviceIdx = (waitForService) ? 1 : 0; + const auto cmd = argv[serviceIdx]; Vector args; String16 serviceName = String16(cmd.data(), cmd.size()); - for (int i = 1; i < argc; i++) { + for (int i = serviceIdx + 1; i < argc; i++) { args.add(String16(argv[i].data(), argv[i].size())); } - sp service = sm->checkService(serviceName); + sp service; + if(waitForService) { + service = sm->waitForService(serviceName); + } else { + service = sm->checkService(serviceName); + } + if (service == nullptr) { if (runMode == RunMode::kStandalone) { ALOGW("Can't find service %.*s", static_cast(cmd.size()), cmd.data()); -- GitLab From 93c3ef1067011d8d9e3eecff4b35293a885ed9f1 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Wed, 26 Feb 2020 13:25:25 -0800 Subject: [PATCH 0852/1255] Have a single blur implementation After experimenting with both Gaussian and Kawase, we concluded that Kawase has similar visuals and better performance. This CL removes GaussianBlurFilter and promotes KawaseBlurFilter to just BlurFilter. Bug: 149792636 Test: librenderengine_test Test: visual Change-Id: I6d5790b2735754b5a39dd7367280871ab43f723c --- libs/renderengine/Android.bp | 2 - libs/renderengine/gl/GLESRenderEngine.cpp | 10 +- libs/renderengine/gl/GLESRenderEngine.h | 2 - libs/renderengine/gl/filters/BlurFilter.cpp | 105 +++++++- libs/renderengine/gl/filters/BlurFilter.h | 26 +- .../gl/filters/GaussianBlurFilter.cpp | 236 ------------------ .../gl/filters/GaussianBlurFilter.h | 69 ----- .../gl/filters/KawaseBlurFilter.cpp | 137 ---------- .../gl/filters/KawaseBlurFilter.h | 54 ---- 9 files changed, 123 insertions(+), 518 deletions(-) delete mode 100644 libs/renderengine/gl/filters/GaussianBlurFilter.cpp delete mode 100644 libs/renderengine/gl/filters/GaussianBlurFilter.h delete mode 100644 libs/renderengine/gl/filters/KawaseBlurFilter.cpp delete mode 100644 libs/renderengine/gl/filters/KawaseBlurFilter.h diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 3d77059b9d..1075f161e4 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -59,8 +59,6 @@ filegroup { "gl/Program.cpp", "gl/ProgramCache.cpp", "gl/filters/BlurFilter.cpp", - "gl/filters/KawaseBlurFilter.cpp", - "gl/filters/GaussianBlurFilter.cpp", "gl/filters/GenericProgram.cpp", ], } diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index e11b59ff24..daf7d72b95 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -50,8 +50,6 @@ #include "Program.h" #include "ProgramCache.h" #include "filters/BlurFilter.h" -#include "filters/GaussianBlurFilter.h" -#include "filters/KawaseBlurFilter.h" extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); @@ -430,13 +428,7 @@ GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisp } if (args.supportsBackgroundBlur) { - char isGaussian[PROPERTY_VALUE_MAX]; - property_get("debug.sf.gaussianBlur", isGaussian, "0"); - if (atoi(isGaussian)) { - mBlurFilter = new GaussianBlurFilter(*this); - } else { - mBlurFilter = new KawaseBlurFilter(*this); - } + mBlurFilter = new BlurFilter(*this); checkErrors("BlurFilter creation"); } diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index ebf78fe6c8..4cd0b3d3b5 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -261,8 +261,6 @@ private: friend class ImageManager; friend class GLFramebuffer; friend class BlurFilter; - friend class GaussianBlurFilter; - friend class KawaseBlurFilter; friend class GenericProgram; std::unique_ptr mFlushTracer; std::unique_ptr mImageManager = std::make_unique(this); diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index eb66c8f2a7..4d6694a744 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -31,13 +31,24 @@ namespace renderengine { namespace gl { BlurFilter::BlurFilter(GLESRenderEngine& engine) - : mEngine(engine), mCompositionFbo(engine), mBlurredFbo(engine), mMixProgram(engine) { + : mEngine(engine), + mCompositionFbo(engine), + mBlurredFbo(engine), + mPingPongFbo(engine), + mMixProgram(engine), + mBlurProgram(engine) { mMixProgram.compile(getVertexShader(), getMixFragShader()); mMPosLoc = mMixProgram.getAttributeLocation("aPosition"); mMUvLoc = mMixProgram.getAttributeLocation("aUV"); mMTextureLoc = mMixProgram.getUniformLocation("uTexture"); mMCompositionTextureLoc = mMixProgram.getUniformLocation("uCompositionTexture"); mMMixLoc = mMixProgram.getUniformLocation("uMix"); + + mBlurProgram.compile(getVertexShader(), getFragmentShader()); + mBPosLoc = mBlurProgram.getAttributeLocation("aPosition"); + mBUvLoc = mBlurProgram.getAttributeLocation("aUV"); + mBTextureLoc = mBlurProgram.getUniformLocation("uTexture"); + mBOffsetLoc = mBlurProgram.getUniformLocation("uOffset"); } status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t radius) { @@ -52,7 +63,7 @@ status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t ra const uint32_t fboWidth = floorf(mDisplayWidth * kFboScale); const uint32_t fboHeight = floorf(mDisplayHeight * kFboScale); mBlurredFbo.allocateBuffers(fboWidth, fboHeight); - allocateTextures(); + mPingPongFbo.allocateBuffers(fboWidth, fboHeight); mTexturesAllocated = true; } @@ -96,6 +107,65 @@ void BlurFilter::drawMesh(GLuint uv, GLuint position) { mEngine.checkErrors("Drawing blur mesh"); } +status_t BlurFilter::prepare() { + ATRACE_NAME("BlurFilter::prepare"); + + if (mPingPongFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { + ALOGE("Invalid FBO"); + return mPingPongFbo.getStatus(); + } + if (!mBlurProgram.isValid()) { + ALOGE("Invalid shader"); + return GL_INVALID_OPERATION; + } + + blit(mCompositionFbo, mBlurredFbo); + + // Kawase is an approximation of Gaussian, but it behaves differently from it. + // A radius transformation is required for approximating them, and also to introduce + // non-integer steps, necessary to smoothly interpolate large radii. + auto radius = mRadius / 6.0f; + + // Calculate how many passes we'll do, based on the radius. + // Too many passes will make the operation expensive. + auto passes = min(kMaxPasses, (uint32_t)ceil(radius)); + + // We'll ping pong between our textures, to accumulate the result of various offsets. + mBlurProgram.useProgram(); + GLFramebuffer* draw = &mPingPongFbo; + GLFramebuffer* read = &mBlurredFbo; + float stepX = radius / (float)mCompositionFbo.getBufferWidth() / (float)passes; + float stepY = radius / (float)mCompositionFbo.getBufferHeight() / (float)passes; + glActiveTexture(GL_TEXTURE0); + glUniform1i(mBTextureLoc, 0); + for (auto i = 0; i < passes; i++) { + ATRACE_NAME("BlurFilter::renderPass"); + draw->bind(); + + glViewport(0, 0, draw->getBufferWidth(), draw->getBufferHeight()); + glBindTexture(GL_TEXTURE_2D, read->getTextureName()); + glUniform2f(mBOffsetLoc, stepX * i, stepY * i); + mEngine.checkErrors("Setting uniforms"); + + drawMesh(mBUvLoc, mBPosLoc); + + // Swap buffers for next iteration + auto tmp = draw; + draw = read; + read = tmp; + } + + // Copy texture, given that we're expected to end on mBlurredFbo. + if (draw == &mBlurredFbo) { + blit(mPingPongFbo, mBlurredFbo); + } + + // Cleanup + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + return NO_ERROR; +} + status_t BlurFilter::render(bool multiPass) { ATRACE_NAME("BlurFilter::render"); @@ -145,6 +215,28 @@ string BlurFilter::getVertexShader() const { )SHADER"; } +string BlurFilter::getFragmentShader() const { + return R"SHADER(#version 310 es + precision mediump float; + + uniform sampler2D uTexture; + uniform vec2 uOffset; + + highp in vec2 vUV; + out vec4 fragColor; + + void main() { + fragColor = texture(uTexture, vUV, 0.0); + fragColor += texture(uTexture, vUV + vec2( uOffset.x, uOffset.y), 0.0); + fragColor += texture(uTexture, vUV + vec2( uOffset.x, -uOffset.y), 0.0); + fragColor += texture(uTexture, vUV + vec2(-uOffset.x, uOffset.y), 0.0); + fragColor += texture(uTexture, vUV + vec2(-uOffset.x, -uOffset.y), 0.0); + + fragColor = vec4(fragColor.rgb * 0.2, 1.0); + } + )SHADER"; +} + string BlurFilter::getMixFragShader() const { string shader = R"SHADER(#version 310 es precision mediump float; @@ -165,6 +257,15 @@ string BlurFilter::getMixFragShader() const { return shader; } +void BlurFilter::blit(GLFramebuffer& read, GLFramebuffer& draw) const { + read.bindAsReadBuffer(); + draw.bindAsDrawBuffer(); + glBlitFramebuffer(0, 0, read.getBufferWidth(), read.getBufferHeight(), 0, 0, + draw.getBufferWidth(), draw.getBufferHeight(), GL_COLOR_BUFFER_BIT, + GL_LINEAR); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + } // namespace gl } // namespace renderengine } // namespace android diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h index 52dc8aab3c..32af8b0864 100644 --- a/libs/renderengine/gl/filters/BlurFilter.h +++ b/libs/renderengine/gl/filters/BlurFilter.h @@ -27,10 +27,17 @@ namespace android { namespace renderengine { namespace gl { +/** + * This is an implementation of a Kawase blur, as described in here: + * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/ + * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf + */ class BlurFilter { public: // Downsample FBO to improve performance static constexpr float kFboScale = 0.25f; + // Maximum number of render passes + static constexpr uint32_t kMaxPasses = 6; // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited // image, up to this radius. static constexpr float kMaxCrossFadeRadius = 30.0f; @@ -40,17 +47,18 @@ public: // Set up render targets, redirecting output to offscreen texture. status_t setAsDrawTarget(const DisplaySettings&, uint32_t radius); - // Allocate any textures needed for the filter. - virtual void allocateTextures() = 0; // Execute blur passes, rendering to offscreen texture. - virtual status_t prepare() = 0; + status_t prepare(); // Render blur to the bound framebuffer (screen). status_t render(bool multiPass); -protected: +private: uint32_t mRadius; void drawMesh(GLuint uv, GLuint position); + void blit(GLFramebuffer& read, GLFramebuffer& draw) const; string getVertexShader() const; + string getFragmentShader() const; + string getMixFragShader() const; GLESRenderEngine& mEngine; // Frame buffer holding the composited background. @@ -59,9 +67,7 @@ protected: GLFramebuffer mBlurredFbo; uint32_t mDisplayWidth; uint32_t mDisplayHeight; - -private: - string getMixFragShader() const; + GLFramebuffer mPingPongFbo; bool mTexturesAllocated = false; GenericProgram mMixProgram; @@ -70,6 +76,12 @@ private: GLuint mMMixLoc; GLuint mMTextureLoc; GLuint mMCompositionTextureLoc; + + GenericProgram mBlurProgram; + GLuint mBPosLoc; + GLuint mBUvLoc; + GLuint mBTextureLoc; + GLuint mBOffsetLoc; }; } // namespace gl diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp deleted file mode 100644 index a0d7af8218..0000000000 --- a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp +++ /dev/null @@ -1,236 +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. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "GaussianBlurFilter.h" -#include -#include -#include -#include -#include -#include - -#include - -#define PI 3.14159265359 -#define THETA 0.352 -#define K 1.0 / (2.0 * THETA * THETA) - -namespace android { -namespace renderengine { -namespace gl { - -GaussianBlurFilter::GaussianBlurFilter(GLESRenderEngine& engine) - : BlurFilter(engine), - mVerticalPassFbo(engine), - mVerticalProgram(engine), - mHorizontalProgram(engine) { - mVerticalProgram.compile(getVertexShader(), getFragmentShader(false)); - mVPosLoc = mVerticalProgram.getAttributeLocation("aPosition"); - mVUvLoc = mVerticalProgram.getAttributeLocation("aUV"); - mVTextureLoc = mVerticalProgram.getUniformLocation("uTexture"); - mVGaussianOffsetLoc = mVerticalProgram.getUniformLocation("uGaussianOffsets"); - mVNumSamplesLoc = mVerticalProgram.getUniformLocation("uSamples"); - mVGaussianWeightLoc = mVerticalProgram.getUniformLocation("uGaussianWeights"); - - mHorizontalProgram.compile(getVertexShader(), getFragmentShader(true)); - mHPosLoc = mHorizontalProgram.getAttributeLocation("aPosition"); - mHUvLoc = mHorizontalProgram.getAttributeLocation("aUV"); - mHTextureLoc = mHorizontalProgram.getUniformLocation("uTexture"); - mHGaussianOffsetLoc = mHorizontalProgram.getUniformLocation("uGaussianOffsets"); - mHNumSamplesLoc = mHorizontalProgram.getUniformLocation("uSamples"); - mHGaussianWeightLoc = mHorizontalProgram.getUniformLocation("uGaussianWeights"); -} - -void GaussianBlurFilter::allocateTextures() { - mVerticalPassFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight()); -} - -static void calculateLinearGaussian(uint32_t samples, double dimension, - GLfloat* gaussianLinearOffsets, GLfloat* gaussianWeights, - GLfloat* gaussianLinearWeights) { - // The central point in the symmetric bell curve is not offset. - // This decision allows one less sampling in the GPU. - gaussianLinearWeights[0] = gaussianWeights[0]; - gaussianLinearOffsets[0] = 0.0; - - // Calculate the linear weights. - // This is a vector reduction where an element of the packed reduced array - // contains the sum of two adjacent members of the original packed array. - // We start preserving the element 1 of the array and then perform sum for - // every other (i+=2) element of the gaussianWeights array. - gaussianLinearWeights[1] = gaussianWeights[1]; - const auto start = 1 + ((samples - 1) & 0x1); - for (size_t i = start; i < samples; i += 2) { - gaussianLinearWeights[start + i / 2] = gaussianWeights[i] + gaussianWeights[i + 1]; - } - - // Calculate the texture coordinates offsets as an average of the initial offsets, - // weighted by the Gaussian weights as described in the original article. - gaussianLinearOffsets[1] = 1.0 / dimension; - for (size_t i = start; i < samples; i += 2) { - GLfloat offset_1 = float(i) / dimension; - GLfloat offset_2 = float(i + 1) / dimension; - gaussianLinearOffsets[start + i / 2] = - (offset_1 * gaussianWeights[i] + offset_2 * gaussianWeights[i + 1]) / - gaussianLinearWeights[start + i / 2]; - } -} -status_t GaussianBlurFilter::prepare() { - ATRACE_NAME("GaussianBlurFilter::prepare"); - - if (mVerticalPassFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid vertical FBO"); - return mVerticalPassFbo.getStatus(); - } - if (!mVerticalProgram.isValid()) { - ALOGE("Invalid vertical shader"); - return GL_INVALID_OPERATION; - } - if (!mHorizontalProgram.isValid()) { - ALOGE("Invalid horizontal shader"); - return GL_INVALID_OPERATION; - } - - mCompositionFbo.bindAsReadBuffer(); - mBlurredFbo.bindAsDrawBuffer(); - glBlitFramebuffer(0, 0, mCompositionFbo.getBufferWidth(), mCompositionFbo.getBufferHeight(), 0, - 0, mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight(), - GL_COLOR_BUFFER_BIT, GL_LINEAR); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - - // First, we'll apply the vertical pass, that receives the flattened background layers. - mVerticalPassFbo.bind(); - mVerticalProgram.useProgram(); - - // Precompute gaussian bell curve, and send it to the shader to avoid unnecessary computations. - double radiusD = fmax(1.0, mRadius * kFboScale); - auto samples = int(fmin(radiusD, kNumSamples)); - GLfloat gaussianWeights[kNumSamples] = {}; - - gaussianWeights[0] = 1.0f; - auto totalWeight = gaussianWeights[0]; - - // Gaussian weights calculation. - for (size_t i = 1; i < samples; i++) { - const double normalized = i / radiusD; - gaussianWeights[i] = (float)exp(-K * normalized * normalized); - totalWeight += 2.0 * gaussianWeights[i]; - } - - // Gaussian weights normalization to avoid work in the GPU. - for (size_t i = 0; i < samples; i++) { - gaussianWeights[i] /= totalWeight; - } - - auto width = mVerticalPassFbo.getBufferWidth(); - auto height = mVerticalPassFbo.getBufferHeight(); - glViewport(0, 0, width, height); - - // Allocate space for the corrected Gaussian weights and offsets. - // We could use less space, but let's keep the code simple. - GLfloat gaussianLinearWeights[kNumSamples] = {}; - GLfloat gaussianLinearOffsets[kNumSamples] = {}; - - // Calculate the weights and offsets for the vertical pass. - // This only need to be called every time mRadius or height changes, so it could be optimized. - calculateLinearGaussian(samples, double(height), gaussianLinearOffsets, gaussianWeights, - gaussianLinearWeights); - // set uniforms - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName()); - glUniform1i(mVTextureLoc, 0); - glUniform1i(mVNumSamplesLoc, 1 + (samples + 1) / 2); - glUniform1fv(mVGaussianWeightLoc, kNumSamples, gaussianLinearWeights); - glUniform1fv(mVGaussianOffsetLoc, kNumSamples, gaussianLinearOffsets); - mEngine.checkErrors("Setting vertical pass uniforms"); - - drawMesh(mVUvLoc, mVPosLoc); - - // Blur vertically on a secondary pass - mBlurredFbo.bind(); - mHorizontalProgram.useProgram(); - - // Calculate the weights and offsets for the horizontal pass. - // This only needs to be called every time mRadius or width change, so it could be optimized. - calculateLinearGaussian(samples, double(width), gaussianLinearOffsets, gaussianWeights, - gaussianLinearWeights); - // set uniforms - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mVerticalPassFbo.getTextureName()); - glUniform1i(mHTextureLoc, 0); - glUniform1i(mHNumSamplesLoc, 1 + (samples + 1) / 2); - glUniform1fv(mHGaussianWeightLoc, kNumSamples, gaussianLinearWeights); - glUniform1fv(mHGaussianOffsetLoc, kNumSamples, gaussianLinearOffsets); - mEngine.checkErrors("Setting horizontal pass uniforms"); - - drawMesh(mHUvLoc, mHPosLoc); - - // reset active texture - mBlurredFbo.unbind(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, 0); - - // unbind program - glUseProgram(0); - - return NO_ERROR; -} - -string GaussianBlurFilter::getFragmentShader(bool horizontal) const { - stringstream shader; - shader << "#version 310 es\n" - << "#define DIRECTION " << (horizontal ? "1" : "0") << "\n" - << "#define NUM_SAMPLES " << 1 + (kNumSamples + 1) / 2 << - R"SHADER( - precision mediump float; - - uniform sampler2D uTexture; - uniform float[NUM_SAMPLES] uGaussianWeights; - uniform float[NUM_SAMPLES] uGaussianOffsets; - uniform int uSamples; - - highp in vec2 vUV; - out vec4 fragColor; - - void main() { - #if DIRECTION == 1 - const vec2 direction = vec2(1.0, 0.0); - #else - const vec2 direction = vec2(0.0, 1.0); - #endif - - // Iteration zero outside loop to avoid sampling the central point twice. - vec4 blurred = uGaussianWeights[0] * (texture(uTexture, vUV, 0.0)); - - // Iterate one side of the bell to halve the loop iterations. - for (int i = 1; i <= uSamples; i++) { - vec2 offset = uGaussianOffsets[i] * direction; - blurred += uGaussianWeights[i] * (texture(uTexture, vUV + offset, 0.0)); - blurred += uGaussianWeights[i] * (texture(uTexture, vUV - offset, 0.0)); - } - - fragColor = vec4(blurred.rgb, 1.0); - } - )SHADER"; - return shader.str(); -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.h b/libs/renderengine/gl/filters/GaussianBlurFilter.h deleted file mode 100644 index 44f5fde9f7..0000000000 --- a/libs/renderengine/gl/filters/GaussianBlurFilter.h +++ /dev/null @@ -1,69 +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 -#include "../GLESRenderEngine.h" -#include "../GLFramebuffer.h" -#include "BlurFilter.h" -#include "GenericProgram.h" - -using namespace std; - -namespace android { -namespace renderengine { -namespace gl { - -// Class that implements a Gaussian Filter that uses Linear Sampling -// to halve the number of samples and reduce runtime by 40% as described in: -// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling -class GaussianBlurFilter : public BlurFilter { -public: - static constexpr uint32_t kNumSamples = 22; - - explicit GaussianBlurFilter(GLESRenderEngine& engine); - status_t prepare() override; - void allocateTextures() override; - -private: - string getFragmentShader(bool horizontal) const; - - // Initial, vertical render pass - GLFramebuffer mVerticalPassFbo; - - // Vertical pass and its uniforms - GenericProgram mVerticalProgram; - GLuint mVPosLoc; - GLuint mVUvLoc; - GLuint mVTextureLoc; - GLuint mVGaussianOffsetLoc; - GLuint mVNumSamplesLoc; - GLuint mVGaussianWeightLoc; - - // Horizontal pass and its uniforms - GenericProgram mHorizontalProgram; - GLuint mHPosLoc; - GLuint mHUvLoc; - GLuint mHTextureLoc; - GLuint mHGaussianOffsetLoc; - GLuint mHNumSamplesLoc; - GLuint mHGaussianWeightLoc; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android \ No newline at end of file diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp deleted file mode 100644 index 7524c6dfe2..0000000000 --- a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "KawaseBlurFilter.h" -#include -#include -#include -#include -#include - -#include - -namespace android { -namespace renderengine { -namespace gl { - -KawaseBlurFilter::KawaseBlurFilter(GLESRenderEngine& engine) - : BlurFilter(engine), mFbo(engine), mProgram(engine) { - mProgram.compile(getVertexShader(), getFragmentShader()); - mPosLoc = mProgram.getAttributeLocation("aPosition"); - mUvLoc = mProgram.getAttributeLocation("aUV"); - mTextureLoc = mProgram.getUniformLocation("uTexture"); - mOffsetLoc = mProgram.getUniformLocation("uOffset"); -} - -void KawaseBlurFilter::allocateTextures() { - mFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight()); -} - -status_t KawaseBlurFilter::prepare() { - ATRACE_NAME("KawaseBlurFilter::prepare"); - - if (mFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid FBO"); - return mFbo.getStatus(); - } - if (!mProgram.isValid()) { - ALOGE("Invalid shader"); - return GL_INVALID_OPERATION; - } - - blit(mCompositionFbo, mBlurredFbo); - - // Kawase is an approximation of Gaussian, but it behaves differently from it. - // A radius transformation is required for approximating them, and also to introduce - // non-integer steps, necessary to smoothly interpolate large radii. - auto radius = mRadius / 6.0f; - - // Calculate how many passes we'll do, based on the radius. - // Too many passes will make the operation expensive. - auto passes = min(kMaxPasses, (uint32_t)ceil(radius)); - - // We'll ping pong between our textures, to accumulate the result of various offsets. - mProgram.useProgram(); - GLFramebuffer* draw = &mFbo; - GLFramebuffer* read = &mBlurredFbo; - float stepX = radius / (float)mCompositionFbo.getBufferWidth() / (float)passes; - float stepY = radius / (float)mCompositionFbo.getBufferHeight() / (float)passes; - glActiveTexture(GL_TEXTURE0); - glUniform1i(mTextureLoc, 0); - for (auto i = 0; i < passes; i++) { - ATRACE_NAME("KawaseBlurFilter::renderPass"); - draw->bind(); - - glViewport(0, 0, draw->getBufferWidth(), draw->getBufferHeight()); - glBindTexture(GL_TEXTURE_2D, read->getTextureName()); - glUniform2f(mOffsetLoc, stepX * i, stepY * i); - mEngine.checkErrors("Setting uniforms"); - - drawMesh(mUvLoc, mPosLoc); - - // Swap buffers for next iteration - auto tmp = draw; - draw = read; - read = tmp; - } - - // Copy texture, given that we're expected to end on mBlurredFbo. - if (draw == &mBlurredFbo) { - blit(mFbo, mBlurredFbo); - } - - // Cleanup - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - return NO_ERROR; -} - -string KawaseBlurFilter::getFragmentShader() const { - return R"SHADER(#version 310 es - precision mediump float; - - uniform sampler2D uTexture; - uniform vec2 uOffset; - - highp in vec2 vUV; - out vec4 fragColor; - - void main() { - fragColor = texture(uTexture, vUV, 0.0); - fragColor += texture(uTexture, vUV + vec2( uOffset.x, uOffset.y), 0.0); - fragColor += texture(uTexture, vUV + vec2( uOffset.x, -uOffset.y), 0.0); - fragColor += texture(uTexture, vUV + vec2(-uOffset.x, uOffset.y), 0.0); - fragColor += texture(uTexture, vUV + vec2(-uOffset.x, -uOffset.y), 0.0); - - fragColor = vec4(fragColor.rgb * 0.2, 1.0); - } - )SHADER"; -} - -void KawaseBlurFilter::blit(GLFramebuffer& read, GLFramebuffer& draw) const { - read.bindAsReadBuffer(); - draw.bindAsDrawBuffer(); - glBlitFramebuffer(0, 0, read.getBufferWidth(), read.getBufferHeight(), 0, 0, - draw.getBufferWidth(), draw.getBufferHeight(), GL_COLOR_BUFFER_BIT, - GL_LINEAR); - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.h b/libs/renderengine/gl/filters/KawaseBlurFilter.h deleted file mode 100644 index 20009cf9bb..0000000000 --- a/libs/renderengine/gl/filters/KawaseBlurFilter.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 -#include "../GLESRenderEngine.h" -#include "../GLFramebuffer.h" -#include "BlurFilter.h" -#include "GenericProgram.h" - -using namespace std; - -namespace android { -namespace renderengine { -namespace gl { - -class KawaseBlurFilter : public BlurFilter { -public: - static constexpr uint32_t kMaxPasses = 6; - - explicit KawaseBlurFilter(GLESRenderEngine& engine); - status_t prepare() override; - void allocateTextures() override; - -private: - string getFragmentShader() const; - void blit(GLFramebuffer& read, GLFramebuffer& draw) const; - - GLFramebuffer mFbo; - - GenericProgram mProgram; - GLuint mPosLoc; - GLuint mUvLoc; - GLuint mTextureLoc; - GLuint mOffsetLoc; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android -- GitLab From a09852aa9db21aa375479c7b139b81db5c7822c5 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 20 Feb 2020 14:23:42 -0800 Subject: [PATCH 0853/1255] SurfaceFlinger: update the refresh rate overlay based on kernel idle timer The frameworks maintains its own copy of inactivity timer to track the kernel idle timer. Update the refresh rate overlay based on that timer. Test: Enable refresh rate overlay from developer options Bug: 149710432 Change-Id: I6c50d64575149317106f72fecdd50cef4e08db6a --- .../surfaceflinger/Scheduler/Scheduler.cpp | 2 ++ services/surfaceflinger/Scheduler/Scheduler.h | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 31 +++++++++++++++++++ services/surfaceflinger/SurfaceFlinger.h | 2 ++ .../tests/unittests/TestableScheduler.h | 1 + 5 files changed, 37 insertions(+) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 3a4433298a..a0d63ba863 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -512,6 +512,8 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { // need to update the DispSync model anyway. disableHardwareVsync(false /* makeUnavailable */); } + + mSchedulerCallback.kernelTimerChanged(state == TimerState::Expired); } void Scheduler::idleTimerCallback(TimerState state) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 46d1a5e7df..6ffda7878a 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -51,6 +51,7 @@ public: virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, scheduler::RefreshRateConfigEvent) = 0; virtual void repaintEverythingForHWC() = 0; + virtual void kernelTimerChanged(bool expired) = 0; }; class Scheduler { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ce0a8a1ac0..cf5e0ec833 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -216,6 +216,7 @@ const String16 sHardwareTest("android.permission.HARDWARE_TEST"); const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); const String16 sDump("android.permission.DUMP"); +const char* KERNEL_IDLE_TIMER_PROP = "vendor.display.enable_kernel_idle_timer"; // --------------------------------------------------------------------------- int64_t SurfaceFlinger::dispSyncPresentTimeOffset; @@ -5106,6 +5107,36 @@ void SurfaceFlinger::repaintEverythingForHWC() { mEventQueue->invalidate(); } +void SurfaceFlinger::kernelTimerChanged(bool expired) { + static bool updateOverlay = + property_get_bool("debug.sf.kernel_idle_timer_update_overlay", true); + if (!updateOverlay || !mRefreshRateOverlay) return; + + // Update the overlay on the main thread to avoid race conditions with + // mRefreshRateConfigs->getCurrentRefreshRate() + postMessageAsync(new LambdaMessage([this, expired]() NO_THREAD_SAFETY_ANALYSIS { + if (mRefreshRateOverlay) { + const auto kernelTimerEnabled = property_get_bool(KERNEL_IDLE_TIMER_PROP, false); + const bool timerExpired = kernelTimerEnabled && expired; + const auto& current = [this]() { + std::lock_guard lock(mActiveConfigLock); + if (mDesiredActiveConfigChanged) { + return mRefreshRateConfigs->getRefreshRateFromConfigId( + mDesiredActiveConfig.configId); + } + + return mRefreshRateConfigs->getCurrentRefreshRate(); + }(); + const auto& min = mRefreshRateConfigs->getMinRefreshRate(); + + if (current != min) { + mRefreshRateOverlay->changeRefreshRate(timerExpired ? min : current); + mEventQueue->invalidate(); + } + } + })); +} + // A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope class WindowDisconnector { public: diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c79621b1fa..07232d46f5 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -524,6 +524,8 @@ private: void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ConfigEvent) override; // force full composition on all displays without resetting the scheduler idle timer. void repaintEverythingForHWC() override; + // Called when kernel idle timer has expired. Used to update the refresh rate overlay. + void kernelTimerChanged(bool expired) override; /* ------------------------------------------------------------------------ * Message handling */ diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 52da34b69a..b0b51bdd8a 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -92,6 +92,7 @@ public: private: void changeRefreshRate(const RefreshRate&, ConfigEvent) override {} void repaintEverythingForHWC() override {} + void kernelTimerChanged(bool /*expired*/) override {} }; } // namespace android -- GitLab From 3d367c8b3410968cbe783bb9c8e8542a73a4213e Mon Sep 17 00:00:00 2001 From: Ana Krulec Date: Tue, 25 Feb 2020 15:02:01 -0800 Subject: [PATCH 0854/1255] SF: Use content detection flag to protect the content detection policy Somewhere in the process of migration we forgot to include the use_content_detection_for_refresh_rate sysprop flag. This CL guards the content detection policy with this guard. Test: Turn the flag off. No content detection. Turn the flag on. Observe content detection. Test: On Cuttlefish. Test: Added unit test in RefreshRateConfigs. Test: atest libsurfaceflinger tests Bug: 150003390 Bug: 150212108 Change-Id: Icff9ab9ffd3604049dfe36efd5d3939e1d77b091 --- .../Scheduler/RefreshRateConfigs.cpp | 10 ++++++++ .../Scheduler/RefreshRateConfigs.h | 4 +++ .../surfaceflinger/Scheduler/Scheduler.cpp | 24 +++++++++++++++--- services/surfaceflinger/Scheduler/Scheduler.h | 7 ++++-- .../SurfaceFlingerDefaultFactory.cpp | 5 ++-- .../unittests/RefreshRateConfigsTest.cpp | 25 +++++++++++++++++++ .../tests/unittests/TestableScheduler.h | 4 +-- 7 files changed, 70 insertions(+), 9 deletions(-) diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index b876ccdc7e..1765d2d8f7 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -107,6 +107,12 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( return *mAvailableRefreshRates.back(); } + // If there are not layers, there is not content detection, so return the current + // refresh rate. + if (layers.empty()) { + return getCurrentRefreshRateByPolicyLocked(); + } + int noVoteLayers = 0; int minVoteLayers = 0; int maxVoteLayers = 0; @@ -272,6 +278,10 @@ const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const { const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicy() const { std::lock_guard lock(mLock); + return getCurrentRefreshRateByPolicyLocked(); +} + +const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() const { if (std::find(mAvailableRefreshRates.begin(), mAvailableRefreshRates.end(), mCurrentRefreshRate) != mAvailableRefreshRates.end()) { return *mCurrentRefreshRate; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 0b5c73c9b7..c8aec86db3 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -199,6 +199,10 @@ private: // display refresh period. std::pair getDisplayFrames(nsecs_t layerPeriod, nsecs_t displayPeriod) const; + // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by + // the policy. + const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock); + // The list of refresh rates, indexed by display config ID. This must not change after this // object is initialized. AllRefreshRatesMapType mRefreshRates; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 3a4433298a..42d42e037b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -99,12 +99,14 @@ std::unique_ptr createDispSync() { Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, const scheduler::RefreshRateConfigs& refreshRateConfig, - ISchedulerCallback& schedulerCallback, bool useContentDetectionV2) + ISchedulerCallback& schedulerCallback, bool useContentDetectionV2, + bool useContentDetection) : mPrimaryDispSync(createDispSync()), mEventControlThread(new impl::EventControlThread(std::move(function))), mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)), mSchedulerCallback(schedulerCallback), mRefreshRateConfigs(refreshRateConfig), + mUseContentDetection(useContentDetection), mUseContentDetectionV2(useContentDetectionV2) { using namespace sysprop; @@ -147,12 +149,14 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, Scheduler::Scheduler(std::unique_ptr primaryDispSync, std::unique_ptr eventControlThread, const scheduler::RefreshRateConfigs& configs, - ISchedulerCallback& schedulerCallback, bool useContentDetectionV2) + ISchedulerCallback& schedulerCallback, bool useContentDetectionV2, + bool useContentDetection) : mPrimaryDispSync(std::move(primaryDispSync)), mEventControlThread(std::move(eventControlThread)), mSupportKernelTimer(false), mSchedulerCallback(schedulerCallback), mRefreshRateConfigs(configs), + mUseContentDetection(useContentDetection), mUseContentDetectionV2(useContentDetectionV2) {} Scheduler::~Scheduler() { @@ -381,6 +385,17 @@ nsecs_t Scheduler::getDispSyncExpectedPresentTime() { void Scheduler::registerLayer(Layer* layer) { if (!mLayerHistory) return; + // If the content detection feature is off, all layers are registered at NoVote. We still + // keep the layer history, since we use it for other features (like Frame Rate API), so layers + // still need to be registered. + if (!mUseContentDetection) { + mLayerHistory->registerLayer(layer, mRefreshRateConfigs.getMinRefreshRate().fps, + mRefreshRateConfigs.getMaxRefreshRate().fps, + scheduler::LayerHistory::LayerVoteType::NoVote); + return; + } + + // In V1 of content detection, all layers are registered as Heuristic (unless it's wallpaper). if (!mUseContentDetectionV2) { const auto lowFps = mRefreshRateConfigs.getMinRefreshRate().fps; const auto highFps = layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER @@ -391,6 +406,7 @@ void Scheduler::registerLayer(Layer* layer) { scheduler::LayerHistory::LayerVoteType::Heuristic); } else { if (layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER) { + // Running Wallpaper at Min is considered as part of content detection. mLayerHistory->registerLayer(layer, mRefreshRateConfigs.getMinRefreshRate().fps, mRefreshRateConfigs.getMaxRefreshRate().fps, scheduler::LayerHistory::LayerVoteType::Min); @@ -537,8 +553,10 @@ void Scheduler::dump(std::string& result) const { StringAppendF(&result, "+ Idle timer: %s\n", mIdleTimer ? mIdleTimer->dump().c_str() : states[0]); - StringAppendF(&result, "+ Touch timer: %s\n\n", + StringAppendF(&result, "+ Touch timer: %s\n", mTouchTimer ? mTouchTimer->dump().c_str() : states[0]); + StringAppendF(&result, "+ Use content detection: %s\n\n", + sysprop::use_content_detection_for_refresh_rate(false) ? "on" : "off"); } template diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 46d1a5e7df..ff0ef6e4c3 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -63,7 +63,7 @@ public: Scheduler(impl::EventControlThread::SetVSyncEnabledFunction, const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback, - bool useContentDetectionV2); + bool useContentDetectionV2, bool useContentDetection); virtual ~Scheduler(); @@ -159,7 +159,7 @@ private: // Used by tests to inject mocks. Scheduler(std::unique_ptr, std::unique_ptr, const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback, - bool useContentDetectionV2); + bool useContentDetectionV2, bool useContentDetection); std::unique_ptr makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs); @@ -245,6 +245,9 @@ private: GUARDED_BY(mVsyncTimelineLock); static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms; + // This variable indicates whether to use the content detection feature at all. + const bool mUseContentDetection; + // This variable indicates whether to use V2 version of the content detection. const bool mUseContentDetectionV2; }; diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index d49133d1fc..9a01d90664 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -33,6 +33,7 @@ #include "NativeWindowSurface.h" #include "StartPropertySetThread.h" #include "SurfaceFlingerDefaultFactory.h" +#include "SurfaceFlingerProperties.h" #include "SurfaceInterceptor.h" #include "DisplayHardware/ComposerHal.h" @@ -76,8 +77,8 @@ std::unique_ptr DefaultFactory::createScheduler( SetVSyncEnabled setVSyncEnabled, const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& schedulerCallback) { return std::make_unique(std::move(setVSyncEnabled), configs, schedulerCallback, - property_get_bool("debug.sf.use_content_detection_v2", - true)); + property_get_bool("debug.sf.use_content_detection_v2", true), + sysprop::use_content_detection_for_refresh_rate(false)); } std::unique_ptr DefaultFactory::createSurfaceInterceptor( diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 7e625135ae..e7e7f66c95 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -247,6 +247,31 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f))); } +TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_noLayers) { + std::vector configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; + auto refreshRateConfigs = std::make_unique(configs, /*currentConfigId=*/ + HWC_CONFIG_ID_72); + + 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}; + + // If there are not layers, there is not content detection, so return the current + // refresh rate. + auto layers = std::vector{}; + EXPECT_EQ(expected72Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ + false)); + + // Current refresh rate can always be changed. + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_60); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ + false)); +} + TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 52da34b69a..ee6e114a83 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -29,7 +29,7 @@ namespace android { class TestableScheduler : public Scheduler, private ISchedulerCallback { public: TestableScheduler(const scheduler::RefreshRateConfigs& configs, bool useContentDetectionV2) - : Scheduler([](bool) {}, configs, *this, useContentDetectionV2) { + : Scheduler([](bool) {}, configs, *this, useContentDetectionV2, true) { if (mUseContentDetectionV2) { mLayerHistory = std::make_unique(); } else { @@ -41,7 +41,7 @@ public: std::unique_ptr eventControlThread, const scheduler::RefreshRateConfigs& configs, bool useContentDetectionV2) : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs, *this, - useContentDetectionV2) { + useContentDetectionV2, true) { if (mUseContentDetectionV2) { mLayerHistory = std::make_unique(); } else { -- GitLab From fff41d77183dd36604c6849487720bba6f19c666 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Wed, 26 Feb 2020 16:55:41 -0800 Subject: [PATCH 0855/1255] Remove unnecessary blit It's possible to keep a pointer to the current buffer, instead of copying it's contents. Bug: 149792636 Test: manual Test: presubmit Change-Id: I04f5fe51580b53a869a1911eb69c6f04ab2eefcf --- libs/renderengine/gl/filters/BlurFilter.cpp | 37 ++++++++++----------- libs/renderengine/gl/filters/BlurFilter.h | 8 +++-- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index 4d6694a744..e704907dac 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -33,8 +33,8 @@ namespace gl { BlurFilter::BlurFilter(GLESRenderEngine& engine) : mEngine(engine), mCompositionFbo(engine), - mBlurredFbo(engine), - mPingPongFbo(engine), + mPingFbo(engine), + mPongFbo(engine), mMixProgram(engine), mBlurProgram(engine) { mMixProgram.compile(getVertexShader(), getMixFragShader()); @@ -62,14 +62,14 @@ status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t ra const uint32_t fboWidth = floorf(mDisplayWidth * kFboScale); const uint32_t fboHeight = floorf(mDisplayHeight * kFboScale); - mBlurredFbo.allocateBuffers(fboWidth, fboHeight); - mPingPongFbo.allocateBuffers(fboWidth, fboHeight); + mPingFbo.allocateBuffers(fboWidth, fboHeight); + mPongFbo.allocateBuffers(fboWidth, fboHeight); mTexturesAllocated = true; } - if (mBlurredFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { + if (mPingFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { ALOGE("Invalid blur buffer"); - return mBlurredFbo.getStatus(); + return mPingFbo.getStatus(); } if (mCompositionFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { ALOGE("Invalid composition buffer"); @@ -110,16 +110,16 @@ void BlurFilter::drawMesh(GLuint uv, GLuint position) { status_t BlurFilter::prepare() { ATRACE_NAME("BlurFilter::prepare"); - if (mPingPongFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { + if (mPongFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { ALOGE("Invalid FBO"); - return mPingPongFbo.getStatus(); + return mPongFbo.getStatus(); } if (!mBlurProgram.isValid()) { ALOGE("Invalid shader"); return GL_INVALID_OPERATION; } - blit(mCompositionFbo, mBlurredFbo); + blit(mCompositionFbo, mPingFbo); // Kawase is an approximation of Gaussian, but it behaves differently from it. // A radius transformation is required for approximating them, and also to introduce @@ -132,8 +132,8 @@ status_t BlurFilter::prepare() { // We'll ping pong between our textures, to accumulate the result of various offsets. mBlurProgram.useProgram(); - GLFramebuffer* draw = &mPingPongFbo; - GLFramebuffer* read = &mBlurredFbo; + GLFramebuffer* read = &mPingFbo; + GLFramebuffer* draw = &mPongFbo; float stepX = radius / (float)mCompositionFbo.getBufferWidth() / (float)passes; float stepY = radius / (float)mCompositionFbo.getBufferHeight() / (float)passes; glActiveTexture(GL_TEXTURE0); @@ -154,11 +154,7 @@ status_t BlurFilter::prepare() { draw = read; read = tmp; } - - // Copy texture, given that we're expected to end on mBlurredFbo. - if (draw == &mBlurredFbo) { - blit(mPingPongFbo, mBlurredFbo); - } + mLastDrawTarget = read; // Cleanup glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -177,9 +173,10 @@ status_t BlurFilter::render(bool multiPass) { // be writing onto it. Let's disable the crossfade, otherwise we'd need 1 extra frame buffer, // as large as the screen size. if (mix >= 1 || multiPass) { - mBlurredFbo.bindAsReadBuffer(); - glBlitFramebuffer(0, 0, mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight(), 0, 0, - mDisplayWidth, mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); + mLastDrawTarget->bindAsReadBuffer(); + glBlitFramebuffer(0, 0, mLastDrawTarget->getBufferWidth(), + mLastDrawTarget->getBufferHeight(), 0, 0, mDisplayWidth, mDisplayHeight, + GL_COLOR_BUFFER_BIT, GL_LINEAR); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); return NO_ERROR; } @@ -187,7 +184,7 @@ status_t BlurFilter::render(bool multiPass) { mMixProgram.useProgram(); glUniform1f(mMMixLoc, mix); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName()); + glBindTexture(GL_TEXTURE_2D, mLastDrawTarget->getTextureName()); glUniform1i(mMTextureLoc, 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName()); diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h index 32af8b0864..eb6120ba92 100644 --- a/libs/renderengine/gl/filters/BlurFilter.h +++ b/libs/renderengine/gl/filters/BlurFilter.h @@ -63,11 +63,13 @@ private: GLESRenderEngine& mEngine; // Frame buffer holding the composited background. GLFramebuffer mCompositionFbo; - // Frame buffer holding the blur result. - GLFramebuffer mBlurredFbo; + // Frame buffers holding the blur passes. + GLFramebuffer mPingFbo; + GLFramebuffer mPongFbo; uint32_t mDisplayWidth; uint32_t mDisplayHeight; - GLFramebuffer mPingPongFbo; + // Buffer holding the final blur pass. + GLFramebuffer* mLastDrawTarget; bool mTexturesAllocated = false; GenericProgram mMixProgram; -- GitLab From 90df585c8aa799c8b8079839bbe5088c0cdf9a05 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 27 Feb 2020 10:17:02 -0800 Subject: [PATCH 0856/1255] gralloc4: lockYCbCr shouldn't return UNSUPPORTED Bug: 150384131 Test: GraphicBuffer_test Change-Id: I87876cf82e8e6250ac755792c2302bf511699758 --- libs/ui/Gralloc4.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp index 30c48c8dc6..6fd4b80f17 100644 --- a/libs/ui/Gralloc4.cpp +++ b/libs/ui/Gralloc4.cpp @@ -364,7 +364,7 @@ status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, cons } *outYcbcr = ycbcr; - return static_cast(Error::UNSUPPORTED); + return static_cast(Error::NONE); } int Gralloc4Mapper::unlock(buffer_handle_t bufferHandle) const { -- GitLab From 882bbf33a2d2d6a8a80d70721cb8e588dab5ea37 Mon Sep 17 00:00:00 2001 From: Philip Quinn Date: Wed, 26 Feb 2020 18:48:28 -0800 Subject: [PATCH 0857/1255] Swap video frame rotation direction. The DISPLAY_ORIENTATION_* values indicate the physical rotation of the display, and not the rotation of the graphics surface (see android.view.Display#getRotation()). To compensate for a physical rotation in one direction, the video frame needs to be rotated in the opposite direction. Bug: 150382187 Test: atest libinput_tests inputflinger_tests Change-Id: Iddd943c35084f7032a8e60273e5e63b59ad10d1c --- libs/input/TouchVideoFrame.cpp | 4 ++-- libs/input/tests/TouchVideoFrame_test.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/input/TouchVideoFrame.cpp b/libs/input/TouchVideoFrame.cpp index 145b4ae03b..c62e0985f1 100644 --- a/libs/input/TouchVideoFrame.cpp +++ b/libs/input/TouchVideoFrame.cpp @@ -43,13 +43,13 @@ const struct timeval& TouchVideoFrame::getTimestamp() const { return mTimestamp; void TouchVideoFrame::rotate(int32_t orientation) { switch (orientation) { case DISPLAY_ORIENTATION_90: - rotateQuarterTurn(true /*clockwise*/); + rotateQuarterTurn(false /*clockwise*/); break; case DISPLAY_ORIENTATION_180: rotate180(); break; case DISPLAY_ORIENTATION_270: - rotateQuarterTurn(false /*clockwise*/); + rotateQuarterTurn(true /*clockwise*/); break; } } diff --git a/libs/input/tests/TouchVideoFrame_test.cpp b/libs/input/tests/TouchVideoFrame_test.cpp index 1ec935859d..654b236bda 100644 --- a/libs/input/tests/TouchVideoFrame_test.cpp +++ b/libs/input/tests/TouchVideoFrame_test.cpp @@ -86,14 +86,14 @@ TEST(TouchVideoFrame, Rotate90_1x1) { TEST(TouchVideoFrame, Rotate90_2x2) { TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP); - TouchVideoFrame frameRotated(2, 2, {3, 1, 4, 2}, TIMESTAMP); + TouchVideoFrame frameRotated(2, 2, {2, 4, 1, 3}, TIMESTAMP); frame.rotate(DISPLAY_ORIENTATION_90); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate90_3x2) { TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); - TouchVideoFrame frameRotated(2, 3, {5, 3, 1, 6, 4, 2}, TIMESTAMP); + TouchVideoFrame frameRotated(2, 3, {2, 4, 6, 1, 3, 5}, TIMESTAMP); frame.rotate(DISPLAY_ORIENTATION_90); ASSERT_EQ(frame, frameRotated); } @@ -171,14 +171,14 @@ TEST(TouchVideoFrame, Rotate270_1x1) { TEST(TouchVideoFrame, Rotate270_2x2) { TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP); - TouchVideoFrame frameRotated(2, 2, {2, 4, 1, 3}, TIMESTAMP); + TouchVideoFrame frameRotated(2, 2, {3, 1, 4, 2}, TIMESTAMP); frame.rotate(DISPLAY_ORIENTATION_270); ASSERT_EQ(frame, frameRotated); } TEST(TouchVideoFrame, Rotate270_3x2) { TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP); - TouchVideoFrame frameRotated(2, 3, {2, 4, 6, 1, 3, 5}, TIMESTAMP); + TouchVideoFrame frameRotated(2, 3, {5, 3, 1, 6, 4, 2}, TIMESTAMP); frame.rotate(DISPLAY_ORIENTATION_270); ASSERT_EQ(frame, frameRotated); } -- GitLab From aad4ebf31b49ce52ce16d81d74c331624e593e4a Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 3 Oct 2019 17:58:30 -0700 Subject: [PATCH 0858/1255] SF: Start restructuring display creation Create the compositionengine::Display first thing, outside of DisplayDevice, and pass it in as part of creating the DisplayDevice, rather than creating it internal to DisplayDevice. Also to start, move the logic to allocate a DisplayId for a HWC backed virtual display into the CompositionEngine class. This is a first step to moving the internal setup of the display to CompositionEngine, and eventually eliminating DisplayDevice entirely, as it is but a thin wrapper around the other class. DisplayTransactionTest is adjusted so the dummy created DisplayDevices have an appropriate compositionengine::Display. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 142831417 Change-Id: I8417682f4ead7b550a8973d4716c627e31b07b6e Merged-In: I8417682f4ead7b550a8973d4716c627e31b07b6e (cherry picked from commit 9370a480fc0a99575a57500b03c9c45d9e52bc1d) --- .../CompositionEngine/Android.bp | 1 + .../compositionengine/DisplayCreationArgs.h | 78 ++- .../include/compositionengine/impl/Display.h | 33 +- .../CompositionEngine/src/Display.cpp | 35 +- .../CompositionEngine/tests/DisplayTest.cpp | 550 ++++++++++++------ services/surfaceflinger/DisplayDevice.cpp | 14 +- services/surfaceflinger/DisplayDevice.h | 10 +- services/surfaceflinger/SurfaceFlinger.cpp | 94 +-- services/surfaceflinger/SurfaceFlinger.h | 3 +- .../SurfaceFlingerDefaultFactory.cpp | 4 +- .../SurfaceFlingerDefaultFactory.h | 2 +- .../surfaceflinger/SurfaceFlingerFactory.h | 2 +- .../tests/unittests/CompositionTest.cpp | 71 ++- .../unittests/DisplayTransactionTest.cpp | 200 +++++-- .../tests/unittests/TestableSurfaceFlinger.h | 35 +- 15 files changed, 772 insertions(+), 360 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 27922900cf..fda451bd9e 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -104,6 +104,7 @@ cc_test { static_libs: [ "libcompositionengine", "libcompositionengine_mocks", + "libgui_mocks", "librenderengine_mocks", "libgmock", "libgtest", diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h index ced4227b44..6bc677d432 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h @@ -18,6 +18,11 @@ #include #include +#include + +#include +#include +#include #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/PowerAdvisor.h" @@ -30,47 +35,86 @@ class CompositionEngine; * A parameter object for creating Display instances */ struct DisplayCreationArgs { - // True if this display is a virtual display - bool isVirtual = false; + struct Physical { + DisplayId id; + DisplayConnectionType type; + }; + + // Required for physical displays. Gives the HWC display id for the existing + // display along with the connection type. + std::optional physical; + + // Size of the display in pixels + ui::Size pixels = ui::Size::INVALID; + + // Pixel format of the display + ui::PixelFormat pixelFormat = static_cast(PIXEL_FORMAT_UNKNOWN); - // Identifies the display to the HWC, if composition is supported by it - std::optional displayId; + // True if virtual displays should be created with the HWC API if possible + bool useHwcVirtualDisplays = false; + + // True if this display should be considered secure + bool isSecure = false; + + // Gives the initial layer stack id to be used for the display + uint32_t layerStackId = ~0u; // Optional pointer to the power advisor interface, if one is needed for // this display. Hwc2::PowerAdvisor* powerAdvisor = nullptr; + + // Debugging. Human readable name for the display. + std::string name; }; /** * A helper for setting up a DisplayCreationArgs value in-line. * Prefer this builder over raw structure initialization. - * - * Instead of: - * - * DisplayCreationArgs{false, false, displayId} - * - * Prefer: - * - * DisplayCreationArgsBuilder().setIsVirtual(false) - * .setDisplayId(displayId).build(); */ class DisplayCreationArgsBuilder { public: DisplayCreationArgs build() { return std::move(mArgs); } - DisplayCreationArgsBuilder& setIsVirtual(bool isVirtual) { - mArgs.isVirtual = isVirtual; + DisplayCreationArgsBuilder& setPhysical(DisplayCreationArgs::Physical physical) { + mArgs.physical = physical; + return *this; + } + + DisplayCreationArgsBuilder& setPixels(ui::Size pixels) { + mArgs.pixels = pixels; return *this; } - DisplayCreationArgsBuilder& setDisplayId(std::optional displayId) { - mArgs.displayId = displayId; + + DisplayCreationArgsBuilder& setPixelFormat(ui::PixelFormat pixelFormat) { + mArgs.pixelFormat = pixelFormat; + return *this; + } + + DisplayCreationArgsBuilder& setUseHwcVirtualDisplays(bool useHwcVirtualDisplays) { + mArgs.useHwcVirtualDisplays = useHwcVirtualDisplays; + return *this; + } + + DisplayCreationArgsBuilder& setIsSecure(bool isSecure) { + mArgs.isSecure = isSecure; return *this; } + + DisplayCreationArgsBuilder& setLayerStackId(uint32_t layerStackId) { + mArgs.layerStackId = layerStackId; + return *this; + } + DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) { mArgs.powerAdvisor = powerAdvisor; return *this; } + DisplayCreationArgsBuilder& setName(std::string name) { + mArgs.name = std::move(name); + return *this; + } + private: DisplayCreationArgs mArgs; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index fb597ce1ff..9ca7d2f9fb 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -16,11 +16,15 @@ #pragma once +#include + #include +#include #include +#include #include - -#include +#include +#include #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/HWComposer.h" @@ -36,11 +40,11 @@ namespace impl { // actually contain the final display state. class Display : public compositionengine::impl::Output, public virtual compositionengine::Display { public: - explicit Display(const compositionengine::DisplayCreationArgs&); virtual ~Display(); // compositionengine::Output overrides std::optional getDisplayId() const override; + bool isValid() const override; void dump(std::string&) const override; using compositionengine::impl::Output::setReleasedLayers; void setReleasedLayers(const CompositionRefreshArgs&) override; @@ -73,22 +77,33 @@ public: virtual void applyLayerRequestsToLayers(const LayerRequests&); // Internal + virtual void setConfiguration(const compositionengine::DisplayCreationArgs&); + virtual std::optional maybeAllocateDisplayIdForVirtualDisplay(ui::Size, + ui::PixelFormat) const; std::unique_ptr createOutputLayer(const sp&) const; + // Testing + void setDisplayIdForTesting(std::optional displayId); + private: - const bool mIsVirtual; + bool mIsVirtual = false; std::optional mId; - Hwc2::PowerAdvisor* const mPowerAdvisor{nullptr}; + Hwc2::PowerAdvisor* mPowerAdvisor = nullptr; }; // 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 -std::shared_ptr createDisplayTemplated(const CompositionEngine& compositionEngine, - const DisplayCreationArgs& args) { - return createOutputTemplated(compositionEngine, args); +template +std::shared_ptr createDisplayTemplated( + const CompositionEngine& compositionEngine, + const compositionengine::DisplayCreationArgs& args) { + auto display = createOutputTemplated(compositionEngine); + + display->setConfiguration(args); + + return display; } std::shared_ptr createDisplay(const compositionengine::CompositionEngine&, diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 1d8a23f460..c3454059aa 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -47,11 +47,36 @@ std::shared_ptr createDisplay( return createDisplayTemplated(compositionEngine, args); } -Display::Display(const DisplayCreationArgs& args) - : mIsVirtual(args.isVirtual), mId(args.displayId), mPowerAdvisor(args.powerAdvisor) {} - Display::~Display() = default; +void Display::setConfiguration(const compositionengine::DisplayCreationArgs& args) { + mIsVirtual = !args.physical; + mId = args.physical ? std::make_optional(args.physical->id) : std::nullopt; + mPowerAdvisor = args.powerAdvisor; + + editState().isSecure = args.isSecure; + + setLayerStackFilter(args.layerStackId, + args.physical ? args.physical->type == DisplayConnectionType::Internal + : false); + setName(args.name); + + if (!args.physical && args.useHwcVirtualDisplays) { + mId = maybeAllocateDisplayIdForVirtualDisplay(args.pixels, args.pixelFormat); + } +} + +std::optional Display::maybeAllocateDisplayIdForVirtualDisplay( + ui::Size pixels, ui::PixelFormat pixelFormat) const { + auto& hwc = getCompositionEngine().getHwComposer(); + return hwc.allocateVirtualDisplay(static_cast(pixels.width), + static_cast(pixels.height), &pixelFormat); +} + +bool Display::isValid() const { + return Output::isValid() && mPowerAdvisor; +} + const std::optional& Display::getId() const { return mId; } @@ -68,6 +93,10 @@ std::optional Display::getDisplayId() const { return mId; } +void Display::setDisplayIdForTesting(std::optional displayId) { + mId = displayId; +} + void Display::disconnect() { if (!mId) { return; diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 16f7a4ef46..88f2686aca 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include "MockHWC2.h" #include "MockHWComposer.h" @@ -40,8 +42,11 @@ namespace { using testing::_; using testing::DoAll; +using testing::Eq; using testing::InSequence; using testing::NiceMock; +using testing::Pointee; +using testing::Ref; using testing::Return; using testing::ReturnRef; using testing::Sequence; @@ -49,8 +54,10 @@ using testing::SetArgPointee; using testing::StrictMock; constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42}; +constexpr DisplayId VIRTUAL_DISPLAY_ID = DisplayId{43}; constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920; constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080; +constexpr int32_t DEFAULT_LAYER_STACK = 123; struct Layer { Layer() { @@ -73,25 +80,126 @@ struct LayerNoHWC2Layer { StrictMock* outputLayer = new StrictMock(); }; -struct DisplayTest : public testing::Test { - class Display : public impl::Display { +struct DisplayTestCommon : public testing::Test { + // Uses the full implementation of a display + class FullImplDisplay : public impl::Display { public: - explicit Display(const compositionengine::DisplayCreationArgs& args) - : impl::Display(args) {} - using impl::Display::injectOutputLayerForTest; virtual void injectOutputLayerForTest(std::unique_ptr) = 0; + + using impl::Display::maybeAllocateDisplayIdForVirtualDisplay; + }; + + // Uses a special implementation with key internal member functions set up + // as mock implementations, to allow for easier testing. + struct PartialMockDisplay : public impl::Display { + PartialMockDisplay(const compositionengine::CompositionEngine& compositionEngine) + : mCompositionEngine(compositionEngine) {} + + // compositionengine::Output overrides + const OutputCompositionState& getState() const override { return mState; } + OutputCompositionState& editState() override { return mState; } + + // compositionengine::impl::Output overrides + const CompositionEngine& getCompositionEngine() const override { + return mCompositionEngine; + }; + + // Mock implementation overrides + MOCK_CONST_METHOD0(getOutputLayerCount, size_t()); + MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex, + compositionengine::OutputLayer*(size_t)); + MOCK_METHOD2(ensureOutputLayer, + compositionengine::OutputLayer*(std::optional, const sp&)); + MOCK_METHOD0(finalizePendingOutputLayers, void()); + MOCK_METHOD0(clearOutputLayers, void()); + MOCK_CONST_METHOD1(dumpState, void(std::string&)); + MOCK_METHOD1(injectOutputLayerForTest, compositionengine::OutputLayer*(const sp&)); + MOCK_METHOD1(injectOutputLayerForTest, void(std::unique_ptr)); + MOCK_CONST_METHOD0(anyLayersRequireClientComposition, bool()); + MOCK_CONST_METHOD0(allLayersRequireClientComposition, bool()); + MOCK_METHOD1(applyChangedTypesToLayers, void(const impl::Display::ChangedTypes&)); + MOCK_METHOD1(applyDisplayRequests, void(const impl::Display::DisplayRequests&)); + MOCK_METHOD1(applyLayerRequestsToLayers, void(const impl::Display::LayerRequests&)); + + const compositionengine::CompositionEngine& mCompositionEngine; + impl::OutputCompositionState mState; }; + static std::string getDisplayNameFromCurrentTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + return std::string("display for ") + test_info->test_case_name() + "." + test_info->name(); + } + + template static std::shared_ptr createDisplay( const compositionengine::CompositionEngine& compositionEngine, - compositionengine::DisplayCreationArgs&& args) { + compositionengine::DisplayCreationArgs args) { + args.name = getDisplayNameFromCurrentTest(); return impl::createDisplayTemplated(compositionEngine, args); } - DisplayTest() { + template + static std::shared_ptr> createPartialMockDisplay( + const compositionengine::CompositionEngine& compositionEngine, + compositionengine::DisplayCreationArgs args) { + args.name = getDisplayNameFromCurrentTest(); + auto display = std::make_shared>(compositionEngine); + + display->setConfiguration(args); + + return display; + } + + DisplayTestCommon() { EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer)); + } + + DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() { + return DisplayCreationArgsBuilder() + .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) + .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(true) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .build(); + } + DisplayCreationArgs getDisplayCreationArgsForNonHWCVirtualDisplay() { + return DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(false) + .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) + .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(false) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .build(); + } + + StrictMock mHwComposer; + StrictMock mPowerAdvisor; + StrictMock mCompositionEngine; + sp mNativeWindow = new StrictMock(); +}; + +struct PartialMockDisplayTestCommon : public DisplayTestCommon { + using Display = DisplayTestCommon::PartialMockDisplay; + std::shared_ptr mDisplay = + createPartialMockDisplay(mCompositionEngine, + getDisplayCreationArgsForPhysicalHWCDisplay()); +}; + +struct FullDisplayImplTestCommon : public DisplayTestCommon { + using Display = DisplayTestCommon::FullImplDisplay; + std::shared_ptr mDisplay = + createDisplay(mCompositionEngine, + getDisplayCreationArgsForPhysicalHWCDisplay()); +}; + +struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon { + DisplayWithLayersTestCommon() { mDisplay->injectOutputLayerForTest( std::unique_ptr(mLayer1.outputLayer)); mDisplay->injectOutputLayerForTest( @@ -100,65 +208,166 @@ struct DisplayTest : public testing::Test { std::unique_ptr(mLayer3.outputLayer)); } - StrictMock mHwComposer; - StrictMock mPowerAdvisor; - StrictMock mCompositionEngine; - sp mNativeWindow = new StrictMock(); Layer mLayer1; Layer mLayer2; LayerNoHWC2Layer mLayer3; StrictMock hwc2LayerUnknown; - - std::shared_ptr mDisplay = createDisplay(mCompositionEngine, - DisplayCreationArgsBuilder() - .setDisplayId(DEFAULT_DISPLAY_ID) - .setPowerAdvisor(&mPowerAdvisor) - .build()); + std::shared_ptr mDisplay = + createDisplay(mCompositionEngine, + getDisplayCreationArgsForPhysicalHWCDisplay()); }; /* * Basic construction */ -TEST_F(DisplayTest, canInstantiateDisplay) { - { - constexpr DisplayId display1 = DisplayId{123u}; - auto display = - impl::createDisplay(mCompositionEngine, - DisplayCreationArgsBuilder().setDisplayId(display1).build()); - EXPECT_FALSE(display->isSecure()); - EXPECT_FALSE(display->isVirtual()); - EXPECT_EQ(display1, display->getId()); - } +struct DisplayCreationTest : public DisplayTestCommon { + using Display = DisplayTestCommon::FullImplDisplay; +}; - { - constexpr DisplayId display2 = DisplayId{546u}; - auto display = - impl::createDisplay(mCompositionEngine, - DisplayCreationArgsBuilder().setDisplayId(display2).build()); - EXPECT_FALSE(display->isSecure()); - EXPECT_FALSE(display->isVirtual()); - EXPECT_EQ(display2, display->getId()); - } +TEST_F(DisplayCreationTest, createPhysicalInternalDisplay) { + auto display = + impl::createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalHWCDisplay()); + EXPECT_TRUE(display->isSecure()); + EXPECT_FALSE(display->isVirtual()); + EXPECT_EQ(DEFAULT_DISPLAY_ID, display->getId()); +} - { - constexpr DisplayId display3 = DisplayId{789u}; - auto display = impl::createDisplay(mCompositionEngine, - DisplayCreationArgsBuilder() - .setIsVirtual(true) - .setDisplayId(display3) - .build()); - EXPECT_FALSE(display->isSecure()); - EXPECT_TRUE(display->isVirtual()); - EXPECT_EQ(display3, display->getId()); - } +TEST_F(DisplayCreationTest, createNonHwcVirtualDisplay) { + auto display = impl::createDisplay(mCompositionEngine, + getDisplayCreationArgsForNonHWCVirtualDisplay()); + EXPECT_FALSE(display->isSecure()); + EXPECT_TRUE(display->isVirtual()); + EXPECT_EQ(std::nullopt, display->getId()); +} + +/* + * Display::setConfiguration() + */ + +using DisplaySetConfigurationTest = PartialMockDisplayTestCommon; + +TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) { + mDisplay->setConfiguration( + DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(true) + .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) + .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(true) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); + + EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId()); + EXPECT_TRUE(mDisplay->isSecure()); + EXPECT_FALSE(mDisplay->isVirtual()); + EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); + EXPECT_TRUE(mDisplay->getState().layerStackInternal); + EXPECT_FALSE(mDisplay->isValid()); +} + +TEST_F(DisplaySetConfigurationTest, configuresExternalInsecurePhysicalDisplay) { + mDisplay->setConfiguration( + DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(true) + .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::External}) + .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) + .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(false) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); + + EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId()); + EXPECT_FALSE(mDisplay->isSecure()); + EXPECT_FALSE(mDisplay->isVirtual()); + EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); + EXPECT_FALSE(mDisplay->getState().layerStackInternal); + EXPECT_FALSE(mDisplay->isValid()); +} + +TEST_F(DisplaySetConfigurationTest, configuresHwcBackedVirtualDisplay) { + EXPECT_CALL(mHwComposer, + allocateVirtualDisplay(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH, + Pointee(Eq(static_cast( + PIXEL_FORMAT_RGBA_8888))))) + .WillOnce(Return(VIRTUAL_DISPLAY_ID)); + + mDisplay->setConfiguration( + DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(true) + .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) + .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(false) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); + + EXPECT_EQ(VIRTUAL_DISPLAY_ID, mDisplay->getId()); + EXPECT_FALSE(mDisplay->isSecure()); + EXPECT_TRUE(mDisplay->isVirtual()); + EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); + EXPECT_FALSE(mDisplay->getState().layerStackInternal); + EXPECT_FALSE(mDisplay->isValid()); +} + +TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfHwcAllocationFails) { + EXPECT_CALL(mHwComposer, + allocateVirtualDisplay(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH, + Pointee(Eq(static_cast( + PIXEL_FORMAT_RGBA_8888))))) + .WillOnce(Return(std::nullopt)); + + mDisplay->setConfiguration( + DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(true) + .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) + .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(false) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); + + EXPECT_EQ(std::nullopt, mDisplay->getId()); + EXPECT_FALSE(mDisplay->isSecure()); + EXPECT_TRUE(mDisplay->isVirtual()); + EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); + EXPECT_FALSE(mDisplay->getState().layerStackInternal); + EXPECT_FALSE(mDisplay->isValid()); +} + +TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfShouldNotUseHwc) { + mDisplay->setConfiguration( + DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(false) + .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) + .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(false) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .setName(getDisplayNameFromCurrentTest()) + .build()); + + EXPECT_EQ(std::nullopt, mDisplay->getId()); + EXPECT_FALSE(mDisplay->isSecure()); + EXPECT_TRUE(mDisplay->isVirtual()); + EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); + EXPECT_FALSE(mDisplay->getState().layerStackInternal); + EXPECT_FALSE(mDisplay->isValid()); } /* * Display::disconnect() */ -TEST_F(DisplayTest, disconnectDisconnectsDisplay) { +using DisplayDisconnectTest = PartialMockDisplayTestCommon; + +TEST_F(DisplayDisconnectTest, disconnectsDisplay) { // The first call to disconnect will disconnect the display with the HWC and // set mHwcId to -1. EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(1); @@ -175,7 +384,9 @@ TEST_F(DisplayTest, disconnectDisconnectsDisplay) { * Display::setColorTransform() */ -TEST_F(DisplayTest, setColorTransformSetsTransform) { +using DisplaySetColorTransformTest = PartialMockDisplayTestCommon; + +TEST_F(DisplaySetColorTransformTest, setsTransform) { // No change does nothing CompositionRefreshArgs refreshArgs; refreshArgs.colorTransformMatrix = std::nullopt; @@ -202,7 +413,9 @@ TEST_F(DisplayTest, setColorTransformSetsTransform) { * Display::setColorMode() */ -TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) { +using DisplaySetColorModeTest = PartialMockDisplayTestCommon; + +TEST_F(DisplaySetColorModeTest, setsModeUnlessNoChange) { using ColorProfile = Output::ColorProfile; mock::RenderSurface* renderSurface = new StrictMock(); @@ -245,11 +458,11 @@ TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) { EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace); } -TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) { +TEST_F(DisplaySetColorModeTest, doesNothingForVirtualDisplay) { using ColorProfile = Output::ColorProfile; - std::shared_ptr virtualDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgs{true, DEFAULT_DISPLAY_ID})}; + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + std::shared_ptr virtualDisplay = impl::createDisplay(mCompositionEngine, args); mock::DisplayColorProfile* colorProfile = new StrictMock(); virtualDisplay->setDisplayColorProfileForTest( @@ -274,7 +487,9 @@ TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) { * Display::createDisplayColorProfile() */ -TEST_F(DisplayTest, createDisplayColorProfileSetsDisplayColorProfile) { +using DisplayCreateColorProfileTest = PartialMockDisplayTestCommon; + +TEST_F(DisplayCreateColorProfileTest, setsDisplayColorProfile) { EXPECT_TRUE(mDisplay->getDisplayColorProfile() == nullptr); mDisplay->createDisplayColorProfile( DisplayColorProfileCreationArgs{false, HdrCapabilities(), 0, @@ -286,7 +501,9 @@ TEST_F(DisplayTest, createDisplayColorProfileSetsDisplayColorProfile) { * Display::createRenderSurface() */ -TEST_F(DisplayTest, createRenderSurfaceSetsRenderSurface) { +using DisplayCreateRenderSurfaceTest = PartialMockDisplayTestCommon; + +TEST_F(DisplayCreateRenderSurfaceTest, setsRenderSurface) { EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL)).WillRepeatedly(Return(NO_ERROR)); EXPECT_TRUE(mDisplay->getRenderSurface() == nullptr); mDisplay->createRenderSurface(RenderSurfaceCreationArgs{640, 480, mNativeWindow, nullptr}); @@ -297,7 +514,9 @@ TEST_F(DisplayTest, createRenderSurfaceSetsRenderSurface) { * Display::createOutputLayer() */ -TEST_F(DisplayTest, createOutputLayerSetsHwcLayer) { +using DisplayCreateOutputLayerTest = FullDisplayImplTestCommon; + +TEST_F(DisplayCreateOutputLayerTest, setsHwcLayer) { sp layerFE = new StrictMock(); StrictMock hwcLayer; @@ -315,9 +534,11 @@ TEST_F(DisplayTest, createOutputLayerSetsHwcLayer) { * Display::setReleasedLayers() */ -TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNotHwcDisplay) { - std::shared_ptr nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; +using DisplaySetReleasedLayersTest = DisplayWithLayersTestCommon; + +TEST_F(DisplaySetReleasedLayersTest, doesNothingIfNotHwcDisplay) { + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + std::shared_ptr nonHwcDisplay = impl::createDisplay(mCompositionEngine, args); sp layerXLayerFE = new StrictMock(); @@ -336,7 +557,7 @@ TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNotHwcDisplay) { ASSERT_EQ(1, releasedLayers.size()); } -TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNoLayersWithQueuedFrames) { +TEST_F(DisplaySetReleasedLayersTest, doesNothingIfNoLayersWithQueuedFrames) { sp layerXLayerFE = new StrictMock(); { @@ -352,7 +573,7 @@ TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNoLayersWithQueuedFrames) { ASSERT_EQ(1, releasedLayers.size()); } -TEST_F(DisplayTest, setReleasedLayers) { +TEST_F(DisplaySetReleasedLayersTest, setReleasedLayers) { sp unknownLayer = new StrictMock(); CompositionRefreshArgs refreshArgs; @@ -372,59 +593,12 @@ TEST_F(DisplayTest, setReleasedLayers) { * Display::chooseCompositionStrategy() */ -struct DisplayChooseCompositionStrategyTest : public testing::Test { - struct DisplayPartialMock : public impl::Display { - DisplayPartialMock(const compositionengine::CompositionEngine& compositionEngine, - const compositionengine::DisplayCreationArgs& args) - : impl::Display(args), mCompositionEngine(compositionEngine) {} - - // Sets up the helper functions called by chooseCompositionStrategy to - // use a mock implementations. - MOCK_CONST_METHOD0(anyLayersRequireClientComposition, bool()); - MOCK_CONST_METHOD0(allLayersRequireClientComposition, bool()); - MOCK_METHOD1(applyChangedTypesToLayers, void(const impl::Display::ChangedTypes&)); - MOCK_METHOD1(applyDisplayRequests, void(const impl::Display::DisplayRequests&)); - MOCK_METHOD1(applyLayerRequestsToLayers, void(const impl::Display::LayerRequests&)); - - // compositionengine::Output overrides - const OutputCompositionState& getState() const override { return mState; } - OutputCompositionState& editState() override { return mState; } - - // compositionengine::impl::Output overrides - const CompositionEngine& getCompositionEngine() const override { - return mCompositionEngine; - }; - - // These need implementations though are not expected to be called. - MOCK_CONST_METHOD0(getOutputLayerCount, size_t()); - MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex, - compositionengine::OutputLayer*(size_t)); - MOCK_METHOD2(ensureOutputLayer, - compositionengine::OutputLayer*(std::optional, const sp&)); - MOCK_METHOD0(finalizePendingOutputLayers, void()); - MOCK_METHOD0(clearOutputLayers, void()); - MOCK_CONST_METHOD1(dumpState, void(std::string&)); - MOCK_METHOD1(injectOutputLayerForTest, compositionengine::OutputLayer*(const sp&)); - MOCK_METHOD1(injectOutputLayerForTest, void(std::unique_ptr)); - - const compositionengine::CompositionEngine& mCompositionEngine; - impl::OutputCompositionState mState; - }; - - DisplayChooseCompositionStrategyTest() { - EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer)); - } - - StrictMock mHwComposer; - StrictMock mCompositionEngine; - StrictMock - mDisplay{mCompositionEngine, - DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()}; -}; +using DisplayChooseCompositionStrategyTest = PartialMockDisplayTestCommon; TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) { - std::shared_ptr nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + std::shared_ptr nonHwcDisplay = + createPartialMockDisplay(mCompositionEngine, args); EXPECT_FALSE(nonHwcDisplay->getId()); nonHwcDisplay->chooseCompositionStrategy(); @@ -435,33 +609,36 @@ TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) { } TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutOnHwcError) { - EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).WillOnce(Return(false)); + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()).WillOnce(Return(false)); EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, false, _)) .WillOnce(Return(INVALID_OPERATION)); - mDisplay.chooseCompositionStrategy(); + mDisplay->chooseCompositionStrategy(); - auto& state = mDisplay.getState(); + auto& state = mDisplay->getState(); EXPECT_TRUE(state.usesClientComposition); EXPECT_FALSE(state.usesDeviceComposition); } TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { - // Since two calls are made to anyLayersRequireClientComposition with different return values, - // use a Sequence to control the matching so the values are returned in a known order. + // Since two calls are made to anyLayersRequireClientComposition with different return + // values, use a Sequence to control the matching so the values are returned in a known + // order. Sequence s; - EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()) + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) .InSequence(s) .WillOnce(Return(false)); EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _)) .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); + EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); - mDisplay.chooseCompositionStrategy(); + mDisplay->chooseCompositionStrategy(); - auto& state = mDisplay.getState(); + auto& state = mDisplay->getState(); EXPECT_FALSE(state.usesClientComposition); EXPECT_TRUE(state.usesDeviceComposition); } @@ -473,24 +650,27 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { {{nullptr, HWC2::LayerRequest::ClearClientTarget}}, }; - // Since two calls are made to anyLayersRequireClientComposition with different return values, - // use a Sequence to control the matching so the values are returned in a known order. + // Since two calls are made to anyLayersRequireClientComposition with different return + // values, use a Sequence to control the matching so the values are returned in a known + // order. Sequence s; - EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()) + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) .InSequence(s) .WillOnce(Return(false)); EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _)) .WillOnce(DoAll(SetArgPointee<2>(changes), Return(NO_ERROR))); - EXPECT_CALL(mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1); - EXPECT_CALL(mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1); - EXPECT_CALL(mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1); - EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); + EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1); + EXPECT_CALL(*mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1); + EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1); + EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); - mDisplay.chooseCompositionStrategy(); + mDisplay->chooseCompositionStrategy(); - auto& state = mDisplay.getState(); + auto& state = mDisplay->getState(); EXPECT_FALSE(state.usesClientComposition); EXPECT_TRUE(state.usesDeviceComposition); } @@ -499,13 +679,15 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { * Display::getSkipColorTransform() */ -TEST_F(DisplayTest, getSkipColorTransformDoesNothingIfNonHwcDisplay) { - auto nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; +using DisplayGetSkipColorTransformTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayGetSkipColorTransformTest, doesNothingIfNonHwcDisplay) { + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + auto nonHwcDisplay{impl::createDisplay(mCompositionEngine, args)}; EXPECT_FALSE(nonHwcDisplay->getSkipColorTransform()); } -TEST_F(DisplayTest, getSkipColorTransformChecksHwcCapability) { +TEST_F(DisplayGetSkipColorTransformTest, checksHwcCapability) { EXPECT_CALL(mHwComposer, hasDisplayCapability(std::make_optional(DEFAULT_DISPLAY_ID), HWC2::DisplayCapability::SkipClientColorTransform)) @@ -517,7 +699,9 @@ TEST_F(DisplayTest, getSkipColorTransformChecksHwcCapability) { * Display::anyLayersRequireClientComposition() */ -TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsFalse) { +using DisplayAnyLayersRequireClientCompositionTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayAnyLayersRequireClientCompositionTest, returnsFalse) { EXPECT_CALL(*mLayer1.outputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(*mLayer2.outputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(*mLayer3.outputLayer, requiresClientComposition()).WillOnce(Return(false)); @@ -525,7 +709,7 @@ TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsFalse) { EXPECT_FALSE(mDisplay->anyLayersRequireClientComposition()); } -TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsTrue) { +TEST_F(DisplayAnyLayersRequireClientCompositionTest, returnsTrue) { EXPECT_CALL(*mLayer1.outputLayer, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(*mLayer2.outputLayer, requiresClientComposition()).WillOnce(Return(true)); @@ -536,7 +720,9 @@ TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsTrue) { * Display::allLayersRequireClientComposition() */ -TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsTrue) { +using DisplayAllLayersRequireClientCompositionTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayAllLayersRequireClientCompositionTest, returnsTrue) { EXPECT_CALL(*mLayer1.outputLayer, requiresClientComposition()).WillOnce(Return(true)); EXPECT_CALL(*mLayer2.outputLayer, requiresClientComposition()).WillOnce(Return(true)); EXPECT_CALL(*mLayer3.outputLayer, requiresClientComposition()).WillOnce(Return(true)); @@ -544,7 +730,7 @@ TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsTrue) { EXPECT_TRUE(mDisplay->allLayersRequireClientComposition()); } -TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsFalse) { +TEST_F(DisplayAllLayersRequireClientCompositionTest, returnsFalse) { EXPECT_CALL(*mLayer1.outputLayer, requiresClientComposition()).WillOnce(Return(true)); EXPECT_CALL(*mLayer2.outputLayer, requiresClientComposition()).WillOnce(Return(false)); @@ -555,11 +741,13 @@ TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsFalse) { * Display::applyChangedTypesToLayers() */ -TEST_F(DisplayTest, applyChangedTypesToLayersTakesEarlyOutIfNoChangedLayers) { +using DisplayApplyChangedTypesToLayersTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayApplyChangedTypesToLayersTest, takesEarlyOutIfNoChangedLayers) { mDisplay->applyChangedTypesToLayers(impl::Display::ChangedTypes()); } -TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) { +TEST_F(DisplayApplyChangedTypesToLayersTest, appliesChanges) { EXPECT_CALL(*mLayer1.outputLayer, applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT)) .Times(1); @@ -578,28 +766,30 @@ TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) { * Display::applyDisplayRequests() */ -TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesNoRequests) { +using DisplayApplyDisplayRequestsTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayApplyDisplayRequestsTest, handlesNoRequests) { mDisplay->applyDisplayRequests(static_cast(0)); auto& state = mDisplay->getState(); EXPECT_FALSE(state.flipClientTarget); } -TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesFlipClientTarget) { +TEST_F(DisplayApplyDisplayRequestsTest, handlesFlipClientTarget) { mDisplay->applyDisplayRequests(HWC2::DisplayRequest::FlipClientTarget); auto& state = mDisplay->getState(); EXPECT_TRUE(state.flipClientTarget); } -TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesWriteClientTargetToOutput) { +TEST_F(DisplayApplyDisplayRequestsTest, handlesWriteClientTargetToOutput) { mDisplay->applyDisplayRequests(HWC2::DisplayRequest::WriteClientTargetToOutput); auto& state = mDisplay->getState(); EXPECT_FALSE(state.flipClientTarget); } -TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesAllRequestFlagsSet) { +TEST_F(DisplayApplyDisplayRequestsTest, handlesAllRequestFlagsSet) { mDisplay->applyDisplayRequests(static_cast(~0)); auto& state = mDisplay->getState(); @@ -610,7 +800,9 @@ TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesAllRequestFlagsSet) { * Display::applyLayerRequestsToLayers() */ -TEST_F(DisplayTest, applyLayerRequestsToLayersPreparesAllLayers) { +using DisplayApplyLayerRequestsToLayersTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayApplyLayerRequestsToLayersTest, preparesAllLayers) { EXPECT_CALL(*mLayer1.outputLayer, prepareForDeviceLayerRequests()).Times(1); EXPECT_CALL(*mLayer2.outputLayer, prepareForDeviceLayerRequests()).Times(1); EXPECT_CALL(*mLayer3.outputLayer, prepareForDeviceLayerRequests()).Times(1); @@ -618,7 +810,7 @@ TEST_F(DisplayTest, applyLayerRequestsToLayersPreparesAllLayers) { mDisplay->applyLayerRequestsToLayers(impl::Display::LayerRequests()); } -TEST_F(DisplayTest, applyLayerRequestsToLayers2) { +TEST_F(DisplayApplyLayerRequestsToLayersTest, appliesDeviceLayerRequests) { EXPECT_CALL(*mLayer1.outputLayer, prepareForDeviceLayerRequests()).Times(1); EXPECT_CALL(*mLayer2.outputLayer, prepareForDeviceLayerRequests()).Times(1); EXPECT_CALL(*mLayer3.outputLayer, prepareForDeviceLayerRequests()).Times(1); @@ -637,9 +829,11 @@ TEST_F(DisplayTest, applyLayerRequestsToLayers2) { * Display::presentAndGetFrameFences() */ -TEST_F(DisplayTest, presentAndGetFrameFencesReturnsNoFencesOnNonHwcDisplay) { - auto nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; +using DisplayPresentAndGetFrameFencesTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayPresentAndGetFrameFencesTest, returnsNoFencesOnNonHwcDisplay) { + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + auto nonHwcDisplay{impl::createDisplay(mCompositionEngine, args)}; auto result = nonHwcDisplay->presentAndGetFrameFences(); @@ -648,7 +842,7 @@ TEST_F(DisplayTest, presentAndGetFrameFencesReturnsNoFencesOnNonHwcDisplay) { EXPECT_EQ(0u, result.layerFences.size()); } -TEST_F(DisplayTest, presentAndGetFrameFencesReturnsPresentAndLayerFences) { +TEST_F(DisplayPresentAndGetFrameFencesTest, returnsPresentAndLayerFences) { sp presentFence = new Fence(); sp layer1Fence = new Fence(); sp layer2Fence = new Fence(); @@ -676,7 +870,9 @@ TEST_F(DisplayTest, presentAndGetFrameFencesReturnsPresentAndLayerFences) { * Display::setExpensiveRenderingExpected() */ -TEST_F(DisplayTest, setExpensiveRenderingExpectedForwardsToPowerAdvisor) { +using DisplaySetExpensiveRenderingExpectedTest = DisplayWithLayersTestCommon; + +TEST_F(DisplaySetExpensiveRenderingExpectedTest, forwardsToPowerAdvisor) { EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, true)).Times(1); mDisplay->setExpensiveRenderingExpected(true); @@ -688,7 +884,9 @@ TEST_F(DisplayTest, setExpensiveRenderingExpectedForwardsToPowerAdvisor) { * Display::finishFrame() */ -TEST_F(DisplayTest, finishFrameDoesNotSkipCompositionIfNotDirtyOnHwcDisplay) { +using DisplayFinishFrameTest = DisplayWithLayersTestCommon; + +TEST_F(DisplayFinishFrameTest, doesNotSkipCompositionIfNotDirtyOnHwcDisplay) { mock::RenderSurface* renderSurface = new StrictMock(); mDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); @@ -709,9 +907,9 @@ TEST_F(DisplayTest, finishFrameDoesNotSkipCompositionIfNotDirtyOnHwcDisplay) { mDisplay->finishFrame(refreshArgs); } -TEST_F(DisplayTest, finishFrameSkipsCompositionIfNotDirty) { - std::shared_ptr nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; +TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) { + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + std::shared_ptr nonHwcDisplay = impl::createDisplay(mCompositionEngine, args); mock::RenderSurface* renderSurface = new StrictMock(); nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); @@ -730,9 +928,9 @@ TEST_F(DisplayTest, finishFrameSkipsCompositionIfNotDirty) { nonHwcDisplay->finishFrame(refreshArgs); } -TEST_F(DisplayTest, finishFramePerformsCompositionIfDirty) { - std::shared_ptr nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; +TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) { + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + std::shared_ptr nonHwcDisplay = impl::createDisplay(mCompositionEngine, args); mock::RenderSurface* renderSurface = new StrictMock(); nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); @@ -751,9 +949,9 @@ TEST_F(DisplayTest, finishFramePerformsCompositionIfDirty) { nonHwcDisplay->finishFrame(refreshArgs); } -TEST_F(DisplayTest, finishFramePerformsCompositionIfRepaintEverything) { - std::shared_ptr nonHwcDisplay{ - impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; +TEST_F(DisplayFinishFrameTest, performsCompositionIfRepaintEverything) { + auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); + std::shared_ptr nonHwcDisplay = impl::createDisplay(mCompositionEngine, args); mock::RenderSurface* renderSurface = new StrictMock(); nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); @@ -779,19 +977,10 @@ TEST_F(DisplayTest, finishFramePerformsCompositionIfRepaintEverything) { struct DisplayFunctionalTest : public testing::Test { class Display : public impl::Display { public: - explicit Display(const compositionengine::DisplayCreationArgs& args) - : impl::Display(args) {} - using impl::Display::injectOutputLayerForTest; virtual void injectOutputLayerForTest(std::unique_ptr) = 0; }; - static std::shared_ptr createDisplay( - const compositionengine::CompositionEngine& compositionEngine, - compositionengine::DisplayCreationArgs&& args) { - return impl::createDisplayTemplated(compositionEngine, args); - } - DisplayFunctionalTest() { EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer)); @@ -803,11 +992,18 @@ struct DisplayFunctionalTest : public testing::Test { NiceMock mCompositionEngine; sp mNativeWindow = new NiceMock(); sp mDisplaySurface = new NiceMock(); - std::shared_ptr mDisplay = createDisplay(mCompositionEngine, - DisplayCreationArgsBuilder() - .setDisplayId(DEFAULT_DISPLAY_ID) - .setPowerAdvisor(&mPowerAdvisor) - .build()); + std::shared_ptr mDisplay = impl::createDisplayTemplated< + Display>(mCompositionEngine, + DisplayCreationArgsBuilder() + .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) + .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) + .setIsSecure(true) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&mPowerAdvisor) + .build() + + ); impl::RenderSurface* mRenderSurface = new impl::RenderSurface{mCompositionEngine, *mDisplay, RenderSurfaceCreationArgs{DEFAULT_DISPLAY_WIDTH, diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index cd6bbd1716..b72214d307 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -47,19 +47,17 @@ using android::base::StringAppendF; ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::Transform::ROT_0; -DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp& flinger, - const wp& displayToken, - std::optional displayId) - : flinger(flinger), displayToken(displayToken), displayId(displayId) {} +DisplayDeviceCreationArgs::DisplayDeviceCreationArgs( + const sp& flinger, const wp& displayToken, + std::shared_ptr compositionDisplay) + : flinger(flinger), displayToken(displayToken), compositionDisplay(compositionDisplay) {} -DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args) +DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) : mFlinger(args.flinger), mDisplayToken(args.displayToken), mSequenceId(args.sequenceId), mConnectionType(args.connectionType), - mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay( - compositionengine::DisplayCreationArgs{args.isVirtual(), args.displayId, - args.powerAdvisor})}, + mCompositionDisplay{args.compositionDisplay}, mPhysicalOrientation(args.physicalOrientation), mIsPrimary(args.isPrimary) { mCompositionDisplay->editState().isSecure = args.isSecure; diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index d970b821e8..fb6c817133 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -64,7 +64,7 @@ public: constexpr static float sDefaultMinLumiance = 0.0; constexpr static float sDefaultMaxLumiance = 500.0; - explicit DisplayDevice(DisplayDeviceCreationArgs&& args); + explicit DisplayDevice(DisplayDeviceCreationArgs& args); virtual ~DisplayDevice(); std::shared_ptr getCompositionDisplay() const { @@ -211,13 +211,10 @@ struct DisplayDeviceCreationArgs { // We use a constructor to ensure some of the values are set, without // assuming a default value. DisplayDeviceCreationArgs(const sp&, const wp& displayToken, - std::optional); - - bool isVirtual() const { return !connectionType; } - + std::shared_ptr); const sp flinger; const wp displayToken; - const std::optional displayId; + const std::shared_ptr compositionDisplay; int32_t sequenceId{0}; std::optional connectionType; @@ -231,7 +228,6 @@ struct DisplayDeviceCreationArgs { std::unordered_map> hwcColorModes; int initialPowerMode{HWC_POWER_MODE_NORMAL}; bool isPrimary{false}; - Hwc2::PowerAdvisor* powerAdvisor{nullptr}; }; class DisplayRenderArea : public RenderArea { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ce0a8a1ac0..236a30f65d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -2325,16 +2326,17 @@ void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bo } sp SurfaceFlinger::setupNewDisplayDeviceInternal( - const wp& displayToken, const std::optional& displayId, + const wp& displayToken, + std::shared_ptr compositionDisplay, const DisplayDeviceState& state, const sp& dispSurface, const sp& producer) { - DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId); + auto displayId = compositionDisplay->getDisplayId(); + DisplayDeviceCreationArgs creationArgs(this, displayToken, compositionDisplay); creationArgs.sequenceId = state.sequenceId; creationArgs.isSecure = state.isSecure; creationArgs.displaySurface = dispSurface; creationArgs.hasWideColorGamut = false; creationArgs.supportedPerFrameMetadata = 0; - creationArgs.powerAdvisor = displayId ? &mPowerAdvisor : nullptr; if (const auto& physical = state.physical) { creationArgs.connectionType = physical->type; @@ -2379,7 +2381,7 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( // virtual displays are always considered enabled creationArgs.initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF; - sp display = getFactory().createDisplayDevice(std::move(creationArgs)); + sp display = getFactory().createDisplayDevice(creationArgs); if (maxFrameBufferAcquiredBuffers >= 3) { nativeWindowSurface->preallocateBuffers(); @@ -2485,53 +2487,68 @@ void SurfaceFlinger::processDisplayChangesLocked() { if (draw.indexOfKey(curr.keyAt(i)) < 0) { const DisplayDeviceState& state(curr[i]); + int width = 0; + int height = 0; + ui::PixelFormat pixelFormat = static_cast(PIXEL_FORMAT_UNKNOWN); + if (state.physical) { + const auto& activeConfig = + getCompositionEngine().getHwComposer().getActiveConfig( + state.physical->id); + width = activeConfig->getWidth(); + height = activeConfig->getHeight(); + pixelFormat = static_cast(PIXEL_FORMAT_RGBA_8888); + } else if (state.surface != nullptr) { + int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width); + ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); + status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height); + ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); + int intPixelFormat; + status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat); + ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status); + pixelFormat = static_cast(intPixelFormat); + } else { + // Virtual displays without a surface are dormant: + // they have external state (layer stack, projection, + // etc.) but no internal state (i.e. a DisplayDevice). + continue; + } + + compositionengine::DisplayCreationArgsBuilder builder; + if (const auto& physical = state.physical) { + builder.setPhysical({physical->id, physical->type}); + } + builder.setPixels(ui::Size(width, height)); + builder.setPixelFormat(pixelFormat); + builder.setIsSecure(state.isSecure); + builder.setLayerStackId(state.layerStack); + builder.setPowerAdvisor(&mPowerAdvisor); + builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays || + getHwComposer().isUsingVrComposer()); + builder.setName(state.displayName); + auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); + sp dispSurface; sp producer; sp bqProducer; sp bqConsumer; getFactory().createBufferQueue(&bqProducer, &bqConsumer, false); - std::optional displayId; - if (state.isVirtual()) { - // Virtual displays without a surface are dormant: - // they have external state (layer stack, projection, - // etc.) but no internal state (i.e. a DisplayDevice). - if (state.surface != nullptr) { - // Allow VR composer to use virtual displays. - if (mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer()) { - int width = 0; - int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width); - ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); - int height = 0; - status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height); - ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); - int intFormat = 0; - status = state.surface->query(NATIVE_WINDOW_FORMAT, &intFormat); - ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status); - auto format = static_cast(intFormat); - - displayId = - getHwComposer().allocateVirtualDisplay(width, height, &format); - } - - // TODO: Plumb requested format back up to consumer + std::optional displayId = compositionDisplay->getId(); - sp vds = - new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, - bqProducer, bqConsumer, - state.displayName); + if (state.isVirtual()) { + sp vds = + new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, + bqProducer, bqConsumer, state.displayName); - dispSurface = vds; - producer = vds; - } + dispSurface = vds; + producer = vds; } else { ALOGE_IF(state.surface != nullptr, "adding a supported display, but rendering " "surface is provided (%p), ignoring it", state.surface.get()); - LOG_FATAL_IF(!state.physical); - displayId = state.physical->id; + LOG_ALWAYS_FATAL_IF(!displayId); dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer); producer = bqProducer; } @@ -2539,7 +2556,8 @@ void SurfaceFlinger::processDisplayChangesLocked() { const wp& displayToken = curr.keyAt(i); if (dispSurface != nullptr) { mDisplays.emplace(displayToken, - setupNewDisplayDeviceInternal(displayToken, displayId, state, + setupNewDisplayDeviceInternal(displayToken, + compositionDisplay, state, dispSurface, producer)); if (!state.isVirtual()) { LOG_ALWAYS_FATAL_IF(!displayId); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c79621b1fa..9b16a28f7c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -810,7 +810,8 @@ private: * Display management */ sp setupNewDisplayDeviceInternal( - const wp& displayToken, const std::optional& displayId, + const wp& displayToken, + std::shared_ptr compositionDisplay, const DisplayDeviceState& state, const sp& dispSurface, const sp& producer); diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index d49133d1fc..033e54232d 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -90,8 +90,8 @@ sp DefaultFactory::createStartPropertySetThread( return new StartPropertySetThread(timestampPropertyValue); } -sp DefaultFactory::createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) { - return new DisplayDevice(std::move(creationArgs)); +sp DefaultFactory::createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) { + return new DisplayDevice(creationArgs); } sp DefaultFactory::createGraphicBuffer(uint32_t width, uint32_t height, diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h index 89194c7ad1..bd40cfbcf2 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h @@ -37,7 +37,7 @@ public: ISchedulerCallback&) override; std::unique_ptr createSurfaceInterceptor(SurfaceFlinger*) override; sp createStartPropertySetThread(bool timestampPropertyValue) override; - sp createDisplayDevice(DisplayDeviceCreationArgs&&) override; + sp createDisplayDevice(DisplayDeviceCreationArgs&) override; sp createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, std::string requestorName) override; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index 209bd0caba..6f4fcc6900 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -83,7 +83,7 @@ public: virtual sp createStartPropertySetThread( bool timestampPropertyValue) = 0; - virtual sp createDisplayDevice(DisplayDeviceCreationArgs&&) = 0; + virtual sp createDisplayDevice(DisplayDeviceCreationArgs&) = 0; virtual sp createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, std::string requestorName) = 0; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 06ef8e78c2..680b0a038e 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -39,6 +39,7 @@ #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" +#include "mock/DisplayHardware/MockPowerAdvisor.h" #include "mock/MockDispSync.h" #include "mock/MockEventControlThread.h" #include "mock/MockEventThread.h" @@ -186,6 +187,7 @@ public: renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); mock::TimeStats* mTimeStats = new mock::TimeStats(); mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); + Hwc2::mock::PowerAdvisor mPowerAdvisor; sp mClientTargetAcquireFence = Fence::NO_FENCE; @@ -284,8 +286,27 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1); EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1); EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1); + + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + auto ceDisplayArgs = + compositionengine::DisplayCreationArgsBuilder() + .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) + .setIsSecure(Derived::IS_SECURE) + .setLayerStackId(DEFAULT_LAYER_STACK) + .setPowerAdvisor(&test->mPowerAdvisor) + .setName(std::string("Injected display for ") + + test_info->test_case_name() + "." + test_info->name()) + .build(); + + auto compositionDisplay = + compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), + ceDisplayArgs); + test->mDisplay = - FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID, + FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, DisplayConnectionType::Internal, true /* isPrimary */) .setDisplaySurface(test->mDisplaySurface) .setNativeWindow(test->mNativeWindow) @@ -325,18 +346,17 @@ struct BaseDisplayVariant { template static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) - .WillRepeatedly( - [](const renderengine::DisplaySettings& displaySettings, - const std::vector&, - ANativeWindowBuffer*, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { - EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); - EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), - displaySettings.physicalDisplay); - EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), - displaySettings.clip); - return NO_ERROR; - }); + .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings, + const std::vector&, + ANativeWindowBuffer*, const bool, base::unique_fd&&, + base::unique_fd*) -> status_t { + EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.physicalDisplay); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.clip); + return NO_ERROR; + }); } static void setupNonEmptyFrameCompositionCallExpectations(CompositionTest* test) { @@ -375,19 +395,18 @@ struct BaseDisplayVariant { .WillOnce(DoAll(SetArgPointee<0>(test->mNativeWindowBuffer), SetArgPointee<1>(-1), Return(0))); EXPECT_CALL(*test->mRenderEngine, drawLayers) - .WillRepeatedly( - [](const renderengine::DisplaySettings& displaySettings, - const std::vector&, - ANativeWindowBuffer*, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { - EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); - EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), - displaySettings.physicalDisplay); - EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), - displaySettings.clip); - EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace); - return NO_ERROR; - }); + .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings, + const std::vector&, + ANativeWindowBuffer*, const bool, base::unique_fd&&, + base::unique_fd*) -> status_t { + EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.physicalDisplay); + EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + displaySettings.clip); + EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace); + return NO_ERROR; + }); } template diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 4da064766c..6d00cccb48 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -25,8 +25,12 @@ #include #include +#include #include +#include +#include #include +#include #include #include #include @@ -39,6 +43,7 @@ #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" +#include "mock/DisplayHardware/MockPowerAdvisor.h" #include "mock/MockDispSync.h" #include "mock/MockEventControlThread.h" #include "mock/MockEventThread.h" @@ -51,11 +56,14 @@ namespace android { namespace { using testing::_; +using testing::AnyNumber; using testing::DoAll; using testing::Mock; using testing::ResultOf; using testing::Return; +using testing::ReturnRefOfCopy; using testing::SetArgPointee; +using testing::StrictMock; using android::Hwc2::ColorMode; using android::Hwc2::Error; @@ -107,6 +115,7 @@ public: void injectMockComposer(int virtualDisplayCount); void injectFakeBufferQueueFactory(); void injectFakeNativeWindowSurfaceFactory(); + sp injectDefaultInternalDisplay(std::function); // -------------------------------------------------------------------- // Postcondition helpers @@ -126,6 +135,7 @@ public: TestableSurfaceFlinger mFlinger; sp mNativeWindow = new mock::NativeWindow(); sp mBuffer = new GraphicBuffer(); + Hwc2::mock::PowerAdvisor mPowerAdvisor; // These mocks are created by the test, but are destroyed by SurfaceFlinger // by virtue of being stored into a std::unique_ptr. However we still need @@ -231,6 +241,49 @@ void DisplayTransactionTest::injectFakeNativeWindowSurfaceFactory() { }); } +sp DisplayTransactionTest::injectDefaultInternalDisplay( + std::function injectExtra) { + constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777}; + constexpr int DEFAULT_DISPLAY_WIDTH = 1080; + constexpr int DEFAULT_DISPLAY_HEIGHT = 1920; + + // The DisplayDevice is required to have a framebuffer (behind the + // ANativeWindow interface) which uses the actual hardware display + // size. + EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) + .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0))); + EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) + .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0))); + EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)); + EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)); + EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)); + EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(AnyNumber()); + + auto compositionDisplay = compositionengine::impl:: + createDisplay(mFlinger.getCompositionEngine(), + compositionengine::DisplayCreationArgsBuilder() + .setPhysical( + {DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) + .setPowerAdvisor(&mPowerAdvisor) + .build()); + + auto injector = + FakeDisplayDeviceInjector(mFlinger, compositionDisplay, DisplayConnectionType::Internal, + true /* isPrimary */); + + injector.setNativeWindow(mNativeWindow); + if (injectExtra) { + injectExtra(injector); + } + + auto displayDevice = injector.inject(); + + Mock::VerifyAndClear(mNativeWindow.get()); + + return displayDevice; +} + bool DisplayTransactionTest::hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId) { return mFlinger.mutableHwcPhysicalDisplayIdMap().count(hwcDisplayId) == 1; } @@ -353,9 +406,21 @@ struct DisplayVariant { static constexpr Primary PRIMARY = primary; static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) { + auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder(); + if (auto displayId = DISPLAY_ID::get()) { + ceDisplayArgs.setPhysical({*displayId, DisplayConnectionType::Internal}); + } else { + ceDisplayArgs.setUseHwcVirtualDisplays(false); + } + ceDisplayArgs.setPixels({WIDTH, HEIGHT}).setPowerAdvisor(&test->mPowerAdvisor).build(); + + auto compositionDisplay = + compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), + ceDisplayArgs.build()); + auto injector = - FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(), CONNECTION_TYPE::value, - static_cast(PRIMARY)); + FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, + CONNECTION_TYPE::value, static_cast(PRIMARY)); injector.setSecure(static_cast(SECURE)); injector.setNativeWindow(test->mNativeWindow); @@ -458,6 +523,25 @@ struct HwcDisplayVariant { injectHwcDisplayWithNoDefaultCapabilities(test); } + static std::shared_ptr injectCompositionDisplay( + DisplayTransactionTest* test) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() + .setPhysical({*DisplayVariant::DISPLAY_ID::get(), + PhysicalDisplay::CONNECTION_TYPE}) + .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT}) + .setIsSecure(static_cast(DisplayVariant::SECURE)) + .setPowerAdvisor(&test->mPowerAdvisor) + .setName(std::string("Injected display for ") + + test_info->test_case_name() + "." + test_info->name()) + .build(); + + return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), + ceDisplayArgs); + } + static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) { constexpr auto CONNECTION_TYPE = PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal @@ -577,6 +661,23 @@ struct NonHwcVirtualDisplayVariant static void injectHwcDisplay(DisplayTransactionTest*) {} + static std::shared_ptr injectCompositionDisplay( + DisplayTransactionTest* test) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() + .setPixels({Base::WIDTH, Base::HEIGHT}) + .setIsSecure(static_cast(Base::SECURE)) + .setPowerAdvisor(&test->mPowerAdvisor) + .setName(std::string("Injected display for ") + + test_info->test_case_name() + "." + test_info->name()) + .build(); + + return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), + ceDisplayArgs); + } + static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) { EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0); } @@ -602,6 +703,33 @@ struct HwcVirtualDisplayVariant secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER>; using Self = HwcVirtualDisplayVariant; + static std::shared_ptr injectCompositionDisplay( + DisplayTransactionTest* test) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() + .setUseHwcVirtualDisplays(false) + .setPixels({Base::WIDTH, Base::HEIGHT}) + .setIsSecure(static_cast(Base::SECURE)) + .setPowerAdvisor(&test->mPowerAdvisor) + .setName(std::string("Injected display for ") + + test_info->test_case_name() + "." + test_info->name()) + .build(); + + auto compositionDisplay = + compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), + ceDisplayArgs); + compositionDisplay->setDisplayIdForTesting(Base::DISPLAY_ID::get()); + + // Insert display data so that the HWC thinks it created the virtual display. + if (const auto displayId = Base::DISPLAY_ID::get()) { + test->mFlinger.mutableHwcDisplayData().try_emplace(*displayId); + } + + return compositionDisplay; + } + static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) { Base::setupNativeWindowSurfaceCreationCallExpectations(test); EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1); @@ -1199,14 +1327,6 @@ TEST_F(DisplayTransactionTest, resetDisplayStateClearsState) { */ class GetBestColorModeTest : public DisplayTransactionTest { public: - static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777}; - - GetBestColorModeTest() - : DisplayTransactionTest(), - mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, - DisplayConnectionType::Internal, - true /* isPrimary */)) {} - void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; } void addHwcColorModesMapping(ui::ColorMode colorMode, @@ -1219,21 +1339,12 @@ public: void setInputRenderIntent(ui::RenderIntent renderIntent) { mInputRenderIntent = renderIntent; } void getBestColorMode() { - mInjector.setHwcColorModes(mHwcColorModes); - mInjector.setHasWideColorGamut(mHasWideColorGamut); - mInjector.setNativeWindow(mNativeWindow); - - // Creating a DisplayDevice requires getting default dimensions from the - // native window. - EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(1080 /* arbitrary */), Return(0))); - EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(1920 /* arbitrary */), Return(0))); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1); - auto displayDevice = mInjector.inject(); + auto displayDevice = + injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) { + injector.setHwcColorModes(mHwcColorModes); + injector.setHasWideColorGamut(mHasWideColorGamut); + injector.setNativeWindow(mNativeWindow); + }); displayDevice->getCompositionDisplay() ->getDisplayColorProfile() @@ -1250,7 +1361,6 @@ private: ui::RenderIntent mInputRenderIntent; bool mHasWideColorGamut = false; std::unordered_map> mHwcColorModes; - FakeDisplayDeviceInjector mInjector; }; TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeSRGB) { @@ -1305,7 +1415,6 @@ TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDISPLAY_BT2020) { class DisplayDeviceSetProjectionTest : public DisplayTransactionTest { public: - static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777}; static constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1080; // arbitrary static constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1920; // arbitrary @@ -1323,23 +1432,9 @@ public: mDisplayDevice(createDisplayDevice()) {} sp createDisplayDevice() { - // The DisplayDevice is required to have a framebuffer (behind the - // ANativeWindow interface) which uses the actual hardware display - // size. - EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(mHardwareDisplaySize.width), Return(0))); - EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(mHardwareDisplaySize.height), Return(0))); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)); - EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)); - - return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, - DisplayConnectionType::Internal, true /* isPrimary */) - .setNativeWindow(mNativeWindow) - .setPhysicalOrientation(mPhysicalOrientation) - .inject(); + return injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) { + injector.setPhysicalOrientation(mPhysicalOrientation); + }); } ui::Size SwapWH(const ui::Size size) const { return ui::Size(size.height, size.width); } @@ -1652,6 +1747,9 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { // surfaces. injectFakeNativeWindowSurfaceFactory(); + // A compositionengine::Display has already been created + auto compositionDisplay = Case::Display::injectCompositionDisplay(this); + // -------------------------------------------------------------------- // Call Expectations @@ -1674,9 +1772,8 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { state.isSecure = static_cast(Case::Display::SECURE); - auto device = - mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::DISPLAY_ID::get(), - state, displaySurface, producer); + auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state, + displaySurface, producer); // -------------------------------------------------------------------- // Postconditions @@ -1715,14 +1812,7 @@ TEST_F(SetupNewDisplayDeviceInternalTest, createNonHwcVirtualDisplay) { } TEST_F(SetupNewDisplayDeviceInternalTest, createHwcVirtualDisplay) { - using Case = HwcVirtualDisplayCase; - - // Insert display data so that the HWC thinks it created the virtual display. - const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(displayId); - mFlinger.mutableHwcDisplayData().try_emplace(*displayId); - - setupNewDisplayDeviceInternalTest(); + setupNewDisplayDeviceInternalTest(); } TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) { diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 3a4f349d45..84e55ae07c 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -97,8 +98,8 @@ public: return new StartPropertySetThread(timestampPropertyValue); } - sp createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) override { - return new DisplayDevice(std::move(creationArgs)); + sp createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) override { + return new DisplayDevice(creationArgs); } sp createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, @@ -277,13 +278,14 @@ public: auto resetDisplayState() { return mFlinger->resetDisplayState(); } - auto setupNewDisplayDeviceInternal(const wp& displayToken, - const std::optional& displayId, - const DisplayDeviceState& state, - const sp& dispSurface, - const sp& producer) { - return mFlinger->setupNewDisplayDeviceInternal(displayToken, displayId, state, dispSurface, - producer); + auto setupNewDisplayDeviceInternal( + const wp& displayToken, + std::shared_ptr compositionDisplay, + const DisplayDeviceState& state, + const sp& dispSurface, + const sp& producer) { + return mFlinger->setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state, + dispSurface, producer); } auto handleTransactionLocked(uint32_t transactionFlags) { @@ -359,6 +361,7 @@ public: auto& getHwComposer() const { return static_cast(mFlinger->getHwComposer()); } + auto& getCompositionEngine() const { return mFlinger->getCompositionEngine(); } const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; } @@ -543,10 +546,11 @@ public: class FakeDisplayDeviceInjector { public: FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, - std::optional displayId, + std::shared_ptr compositionDisplay, std::optional connectionType, bool isPrimary) - : mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), mDisplayToken, displayId) { + : mFlinger(flinger), + mCreationArgs(flinger.mFlinger.get(), mDisplayToken, compositionDisplay) { mCreationArgs.connectionType = connectionType; mCreationArgs.isPrimary = isPrimary; } @@ -609,16 +613,17 @@ public: } sp inject() { + const auto displayId = mCreationArgs.compositionDisplay->getDisplayId(); + DisplayDeviceState state; if (const auto type = mCreationArgs.connectionType) { - const auto id = mCreationArgs.displayId; - LOG_ALWAYS_FATAL_IF(!id); - state.physical = {*id, *type}; + LOG_ALWAYS_FATAL_IF(!displayId); + state.physical = {*displayId, *type}; } state.isSecure = mCreationArgs.isSecure; - sp device = new DisplayDevice(std::move(mCreationArgs)); + sp device = new DisplayDevice(mCreationArgs); mFlinger.mutableDisplays().emplace(mDisplayToken, device); mFlinger.mutableCurrentState().displays.add(mDisplayToken, state); mFlinger.mutableDrawingState().displays.add(mDisplayToken, state); -- GitLab From 349fd2d2761b541d83cda739c866a1af315b036f Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 27 Feb 2020 12:06:10 -0800 Subject: [PATCH 0859/1255] [RenderEngine] Reorder when ImageManager thread starts Previously the background thread for managing EglImages was intialized as a member variable before the constructor completed running. In very rare circumstances this can potentially stop the running thread if the thread ran before mRunning was initialized. To be less error-prone, require that ImageManger::initThread be explicitly called to guarantee that class member variables are well-defined when the thread begins executing. In case the issue resurfaces after this change, added a debug log to add context. Bug: 146416748 Test: builds. There is no reliable repro, so this fix is speculative Test: systrace to verify thread is running and configured correctly. Change-Id: I141c86240b90c7f87c22b3768c2e188293987b76 --- libs/renderengine/gl/GLESRenderEngine.cpp | 1 + libs/renderengine/gl/ImageManager.cpp | 10 +++++++++- libs/renderengine/gl/ImageManager.h | 6 +++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index e11b59ff24..186aa25014 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -441,6 +441,7 @@ GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisp } mImageManager = std::make_unique(this); + mImageManager->initThread(); mDrawingBuffer = createFramebuffer(); } diff --git a/libs/renderengine/gl/ImageManager.cpp b/libs/renderengine/gl/ImageManager.cpp index 5af0e4f857..62566494f0 100644 --- a/libs/renderengine/gl/ImageManager.cpp +++ b/libs/renderengine/gl/ImageManager.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "RenderEngine" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include @@ -27,7 +30,10 @@ namespace android { namespace renderengine { namespace gl { -ImageManager::ImageManager(GLESRenderEngine* engine) : mEngine(engine) { +ImageManager::ImageManager(GLESRenderEngine* engine) : mEngine(engine) {} + +void ImageManager::initThread() { + mThread = std::thread([this]() { threadMain(); }); pthread_setname_np(mThread.native_handle(), "ImageManager"); // Use SCHED_FIFO to minimize jitter struct sched_param param = {0}; @@ -133,6 +139,8 @@ void ImageManager::threadMain() { entry.barrier->condition.notify_one(); } } + + ALOGD("Reached end of threadMain, terminating ImageManager thread!"); } } // namespace gl diff --git a/libs/renderengine/gl/ImageManager.h b/libs/renderengine/gl/ImageManager.h index b5ba554c4f..be67de8367 100644 --- a/libs/renderengine/gl/ImageManager.h +++ b/libs/renderengine/gl/ImageManager.h @@ -39,6 +39,10 @@ public: }; ImageManager(GLESRenderEngine* engine); ~ImageManager(); + // Starts the background thread for the ImageManager + // We need this to guarantee that the class is fully-constructed before the + // thread begins running. + void initThread(); void cacheAsync(const sp& buffer, const std::shared_ptr& barrier) EXCLUDES(mMutex); status_t cache(const sp& buffer); @@ -57,7 +61,7 @@ private: void queueOperation(const QueueEntry&& entry); void threadMain(); GLESRenderEngine* const mEngine; - std::thread mThread = std::thread([this]() { threadMain(); }); + std::thread mThread; std::condition_variable_any mCondition; std::mutex mMutex; std::queue mQueue GUARDED_BY(mMutex); -- GitLab From b11abe70adc17204605946cbe4b71b6705fd19b1 Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Mon, 24 Feb 2020 21:30:20 +0000 Subject: [PATCH 0860/1255] Revert "libui: rewrite Region with FatVector" Revert submission 10248126-fatvector-region Reason for revert: b/149254345 Reverted Changes: I09dc2fddd:hwui: remove FatVector I265c6c831:libui: rewrite Region with FatVector Change-Id: I2697cea4d4714592fa6a1f170b53ff51d2d62714 Test: boots Bug: 149254345 Change-Id: Ib60dbf3ef41d6439fba095e3e905580bb59d3739 --- include/ui/FatVector.h | 1 - libs/ui/Region.cpp | 94 ++++++++++++++--------------- libs/ui/include/ui/FatVector.h | 93 ---------------------------- libs/ui/include/ui/Region.h | 7 ++- libs/ui/include_vndk/ui/FatVector.h | 1 - 5 files changed, 50 insertions(+), 146 deletions(-) delete mode 120000 include/ui/FatVector.h delete mode 100644 libs/ui/include/ui/FatVector.h delete mode 120000 libs/ui/include_vndk/ui/FatVector.h diff --git a/include/ui/FatVector.h b/include/ui/FatVector.h deleted file mode 120000 index c2047c07e1..0000000000 --- a/include/ui/FatVector.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/ui/include/ui/FatVector.h \ No newline at end of file diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index cd2a448c3e..bf487c4aec 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -67,20 +67,19 @@ const Region Region::INVALID_REGION(Rect::INVALID_RECT); // ---------------------------------------------------------------------------- Region::Region() { - mStorage.push_back(Rect(0, 0)); + mStorage.add(Rect(0,0)); } Region::Region(const Region& rhs) + : mStorage(rhs.mStorage) { - mStorage.clear(); - mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end()); #if defined(VALIDATE_REGIONS) validate(rhs, "rhs copy-ctor"); #endif } Region::Region(const Rect& rhs) { - mStorage.push_back(rhs); + mStorage.add(rhs); } Region::~Region() @@ -101,8 +100,8 @@ Region::~Region() * final, correctly ordered region buffer. Each rectangle will be compared with the span directly * above it, and subdivided to resolve any remaining T-junctions. */ -static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, FatVector& dst, - int spanDirection) { +static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, + Vector& dst, int spanDirection) { dst.clear(); const Rect* current = end - 1; @@ -110,7 +109,7 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, F // add first span immediately do { - dst.push_back(*current); + dst.add(*current); current--; } while (current->top == lastTop && current >= begin); @@ -148,12 +147,12 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, F if (prev.right <= left) break; if (prev.right > left && prev.right < right) { - dst.push_back(Rect(prev.right, top, right, bottom)); + dst.add(Rect(prev.right, top, right, bottom)); right = prev.right; } if (prev.left > left && prev.left < right) { - dst.push_back(Rect(prev.left, top, right, bottom)); + dst.add(Rect(prev.left, top, right, bottom)); right = prev.left; } @@ -167,12 +166,12 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, F if (prev.left >= right) break; if (prev.left > left && prev.left < right) { - dst.push_back(Rect(left, top, prev.left, bottom)); + dst.add(Rect(left, top, prev.left, bottom)); left = prev.left; } if (prev.right > left && prev.right < right) { - dst.push_back(Rect(left, top, prev.right, bottom)); + dst.add(Rect(left, top, prev.right, bottom)); left = prev.right; } // if an entry in the previous span is too far left, nothing further right in the @@ -184,7 +183,7 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, F } if (left < right) { - dst.push_back(Rect(left, top, right, bottom)); + dst.add(Rect(left, top, right, bottom)); } current--; @@ -202,14 +201,13 @@ Region Region::createTJunctionFreeRegion(const Region& r) { if (r.isEmpty()) return r; if (r.isRect()) return r; - FatVector reversed; + Vector reversed; reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL); Region outputRegion; - reverseRectsResolvingJunctions(reversed.data(), reversed.data() + reversed.size(), - outputRegion.mStorage, direction_LTR); - outputRegion.mStorage.push_back( - r.getBounds()); // to make region valid, mStorage must end with bounds + reverseRectsResolvingJunctions(reversed.begin(), reversed.end(), + outputRegion.mStorage, direction_LTR); + outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds #if defined(VALIDATE_REGIONS) validate(outputRegion, "T-Junction free region"); @@ -224,8 +222,7 @@ Region& Region::operator = (const Region& rhs) validate(*this, "this->operator="); validate(rhs, "rhs.operator="); #endif - mStorage.clear(); - mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end()); + mStorage = rhs.mStorage; return *this; } @@ -234,7 +231,7 @@ Region& Region::makeBoundsSelf() if (mStorage.size() >= 2) { const Rect bounds(getBounds()); mStorage.clear(); - mStorage.push_back(bounds); + mStorage.add(bounds); } return *this; } @@ -258,25 +255,25 @@ bool Region::contains(int x, int y) const { void Region::clear() { mStorage.clear(); - mStorage.push_back(Rect(0, 0)); + mStorage.add(Rect(0,0)); } void Region::set(const Rect& r) { mStorage.clear(); - mStorage.push_back(r); + mStorage.add(r); } void Region::set(int32_t w, int32_t h) { mStorage.clear(); - mStorage.push_back(Rect(w, h)); + mStorage.add(Rect(w, h)); } void Region::set(uint32_t w, uint32_t h) { mStorage.clear(); - mStorage.push_back(Rect(w, h)); + mStorage.add(Rect(w, h)); } bool Region::isTriviallyEqual(const Region& region) const { @@ -302,7 +299,8 @@ bool Region::hasSameRects(const Region& other) const { void Region::addRectUnchecked(int l, int t, int r, int b) { Rect rect(l,t,r,b); - mStorage.insert(mStorage.end() - 1, rect); + size_t where = mStorage.size() - 1; + mStorage.insertAt(rect, where, 1); } // ---------------------------------------------------------------------------- @@ -352,7 +350,7 @@ Region& Region::translateSelf(int x, int y) { Region& Region::scaleSelf(float sx, float sy) { size_t count = mStorage.size(); - Rect* rects = mStorage.data(); + Rect* rects = mStorage.editArray(); while (count) { rects->left = static_cast(static_cast(rects->left) * sx + 0.5f); rects->right = static_cast(static_cast(rects->right) * sx + 0.5f); @@ -457,10 +455,10 @@ const Region Region::operation(const Region& rhs, int dx, int dy, uint32_t op) c class Region::rasterizer : public region_operator::region_rasterizer { Rect bounds; - FatVector& storage; + Vector& storage; Rect* head; Rect* tail; - FatVector span; + Vector span; Rect* cur; public: explicit rasterizer(Region& reg) @@ -487,8 +485,8 @@ Region::rasterizer::~rasterizer() flushSpan(); } if (storage.size()) { - bounds.top = storage.front().top; - bounds.bottom = storage.back().bottom; + bounds.top = storage.itemAt(0).top; + bounds.bottom = storage.top().bottom; if (storage.size() == 1) { storage.clear(); } @@ -496,7 +494,7 @@ Region::rasterizer::~rasterizer() bounds.left = 0; bounds.right = 0; } - storage.push_back(bounds); + storage.add(bounds); } void Region::rasterizer::operator()(const Rect& rect) @@ -511,15 +509,15 @@ void Region::rasterizer::operator()(const Rect& rect) return; } } - span.push_back(rect); - cur = span.data() + (span.size() - 1); + span.add(rect); + cur = span.editArray() + (span.size() - 1); } void Region::rasterizer::flushSpan() { bool merge = false; if (tail-head == ssize_t(span.size())) { - Rect const* p = span.data(); + Rect const* p = span.editArray(); Rect const* q = head; if (p->top == q->bottom) { merge = true; @@ -534,17 +532,17 @@ void Region::rasterizer::flushSpan() } } if (merge) { - const int bottom = span.front().bottom; + const int bottom = span[0].bottom; Rect* r = head; while (r != tail) { r->bottom = bottom; r++; } } else { - bounds.left = min(span.front().left, bounds.left); - bounds.right = max(span.back().right, bounds.right); - storage.insert(storage.end(), span.begin(), span.end()); - tail = storage.data() + storage.size(); + bounds.left = min(span.itemAt(0).left, bounds.left); + bounds.right = max(span.top().right, bounds.right); + storage.appendVector(span); + tail = storage.editArray() + storage.size(); head = tail - span.size(); } span.clear(); @@ -552,7 +550,7 @@ void Region::rasterizer::flushSpan() bool Region::validate(const Region& reg, const char* name, bool silent) { - if (reg.mStorage.empty()) { + if (reg.mStorage.isEmpty()) { ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name); // return immediately as the code below assumes mStorage is non-empty return false; @@ -691,8 +689,9 @@ void Region::boolean_operation(uint32_t op, Region& dst, } sk_dst.op(sk_lhs, sk_rhs, sk_op); - if (sk_dst.empty() && dst.empty()) return; - + if (sk_dst.isEmpty() && dst.isEmpty()) + return; + bool same = true; Region::const_iterator head = dst.begin(); Region::const_iterator const tail = dst.end(); @@ -787,7 +786,7 @@ void Region::translate(Region& reg, int dx, int dy) validate(reg, "translate (before)"); #endif size_t count = reg.mStorage.size(); - Rect* rects = reg.mStorage.data(); + Rect* rects = reg.mStorage.editArray(); while (count) { rects->offsetBy(dx, dy); rects++; @@ -867,25 +866,24 @@ status_t Region::unflatten(void const* buffer, size_t size) { ALOGE("Region::unflatten() failed, invalid region"); return BAD_VALUE; } - mStorage.clear(); - mStorage.insert(mStorage.begin(), result.mStorage.begin(), result.mStorage.end()); + mStorage = result.mStorage; return NO_ERROR; } // ---------------------------------------------------------------------------- Region::const_iterator Region::begin() const { - return mStorage.data(); + return mStorage.array(); } Region::const_iterator Region::end() const { // Workaround for b/77643177 // mStorage should never be empty, but somehow it is and it's causing // an abort in ubsan - if (mStorage.empty()) return mStorage.data(); + if (mStorage.isEmpty()) return mStorage.array(); size_t numRects = isRect() ? 1 : mStorage.size() - 1; - return mStorage.data() + numRects; + return mStorage.array() + numRects; } Rect const* Region::getArray(size_t* count) const { diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h deleted file mode 100644 index 25fe3a0a2a..0000000000 --- a/libs/ui/include/ui/FatVector.h +++ /dev/null @@ -1,93 +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. - */ - -#ifndef ANDROID_REGION_FAT_VECTOR_H -#define ANDROID_REGION_FAT_VECTOR_H - -#include -#include -#include -#include - -#include - -namespace android { - -template -class InlineStdAllocator { -public: - struct Allocation { - private: - Allocation(const Allocation&) = delete; - void operator=(const Allocation&) = delete; - - public: - Allocation() {} - // char array instead of T array, so memory is uninitialized, with no destructors run - char array[sizeof(T) * SIZE]; - bool inUse = false; - }; - - typedef T value_type; // needed to implement std::allocator - typedef T* pointer; // needed to implement std::allocator - - explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {} - InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {} - ~InlineStdAllocator() {} - - T* allocate(size_t num, const void* = 0) { - if (!mAllocation.inUse && num <= SIZE) { - mAllocation.inUse = true; - return static_cast(static_cast(mAllocation.array)); - } else { - return static_cast(static_cast(malloc(num * sizeof(T)))); - } - } - - void deallocate(pointer p, size_t) { - if (p == static_cast(static_cast(mAllocation.array))) { - mAllocation.inUse = false; - } else { - // 'free' instead of delete here - destruction handled separately - free(p); - } - } - Allocation& mAllocation; -}; - -/** - * std::vector with SIZE elements preallocated into an internal buffer. - * - * Useful for avoiding the cost of malloc in cases where only SIZE or - * fewer elements are needed in the common case. - */ -template -class FatVector : public std::vector> { -public: - FatVector() - : std::vector>(InlineStdAllocator(mAllocation)) { - this->reserve(SIZE); - } - - explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); } - -private: - typename InlineStdAllocator::Allocation mAllocation; -}; - -} // namespace android - -#endif // ANDROID_REGION_FAT_VECTOR_H diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h index 6bb7b8d21c..2db3b10f13 100644 --- a/libs/ui/include/ui/Region.h +++ b/libs/ui/include/ui/Region.h @@ -21,13 +21,13 @@ #include #include +#include + #include #include #include -#include "FatVector.h" - #include namespace android { @@ -180,7 +180,7 @@ private: // with an extra Rect as the last element which is set to the // bounds of the region. However, if the region is // a simple Rect then mStorage contains only that rect. - FatVector mStorage; + Vector mStorage; }; @@ -235,3 +235,4 @@ static inline void PrintTo(const Region& region, ::std::ostream* os) { }; // namespace android #endif // ANDROID_UI_REGION_H + diff --git a/libs/ui/include_vndk/ui/FatVector.h b/libs/ui/include_vndk/ui/FatVector.h deleted file mode 120000 index bf30166784..0000000000 --- a/libs/ui/include_vndk/ui/FatVector.h +++ /dev/null @@ -1 +0,0 @@ -../../include/ui/FatVector.h \ No newline at end of file -- GitLab From c1b5ffb1bfa2e7ac9d8febd25aed38da5b1ea645 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Thu, 27 Feb 2020 19:31:51 -0800 Subject: [PATCH 0861/1255] [vkjson] Add support of VK_KHR_shader_float16_int8. Bug: b/150335028 Test: adb shell cmd gpu vkjson Change-Id: Ie9808e0f8d79d6992e5cb480a24c0f98e5437df1 --- vulkan/vkjson/vkjson.cc | 18 ++++++++++++++++++ vulkan/vkjson/vkjson.h | 11 +++++++++++ vulkan/vkjson/vkjson_instance.cc | 10 ++++++++++ 3 files changed, 39 insertions(+) diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc index 8f714d89d8..b0b466c0a1 100644 --- a/vulkan/vkjson/vkjson.cc +++ b/vulkan/vkjson/vkjson.cc @@ -590,6 +590,13 @@ inline bool Iterate(Visitor* visitor, &features->variable_pointer_features_khr); } +template +inline bool Iterate(Visitor* visitor, + VkJsonExtShaderFloat16Int8Features* features) { + return visitor->Visit("shaderFloat16Int8FeaturesKHR", + &features->shader_float16_int8_features_khr); +} + template inline bool Iterate(Visitor* visitor, VkMemoryType* type) { return @@ -690,6 +697,13 @@ inline bool Iterate(Visitor* visitor, visitor->Visit("variablePointers", &features->variablePointers); } +template +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR* features) { + return visitor->Visit("shaderFloat16", &features->shaderFloat16) && + visitor->Visit("shaderInt8", &features->shaderInt8); +} + template inline bool Iterate(Visitor* visitor, VkPhysicalDeviceProtectedMemoryFeatures* features) { @@ -824,6 +838,10 @@ inline bool Iterate(Visitor* visitor, VkJsonDevice* device) { ret &= visitor->Visit("VK_KHR_variable_pointers", &device->ext_variable_pointer_features); } + if (device->ext_shader_float16_int8_features.reported) { + ret &= visitor->Visit("VK_KHR_shader_float16_int8", + &device->ext_shader_float16_int8_features); + } } return ret; } diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h index 450fb24862..a283b83d7c 100644 --- a/vulkan/vkjson/vkjson.h +++ b/vulkan/vkjson/vkjson.h @@ -72,6 +72,16 @@ struct VkJsonExtVariablePointerFeatures { VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features_khr; }; +struct VkJsonExtShaderFloat16Int8Features { + VkJsonExtShaderFloat16Int8Features() { + reported = false; + memset(&shader_float16_int8_features_khr, 0, + sizeof(VkPhysicalDeviceShaderFloat16Int8FeaturesKHR)); + } + bool reported; + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_float16_int8_features_khr; +}; + struct VkJsonDevice { VkJsonDevice() { memset(&properties, 0, sizeof(VkPhysicalDeviceProperties)); @@ -101,6 +111,7 @@ struct VkJsonDevice { VkPhysicalDeviceFeatures features; VkJsonExtDriverProperties ext_driver_properties; VkJsonExtVariablePointerFeatures ext_variable_pointer_features; + VkJsonExtShaderFloat16Int8Features ext_shader_float16_int8_features; VkPhysicalDeviceMemoryProperties memory; std::vector queues; std::vector extensions; diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc index 05d4dfea6c..84cfe5e00b 100644 --- a/vulkan/vkjson/vkjson_instance.cc +++ b/vulkan/vkjson/vkjson_instance.cc @@ -136,6 +136,16 @@ VkJsonDevice VkJsonGetDevice(VkInstance instance, features.pNext = &device.ext_variable_pointer_features.variable_pointer_features_khr; } + if (HasExtension("VK_KHR_shader_float16_int8", device.extensions)) { + device.ext_shader_float16_int8_features.reported = true; + device.ext_shader_float16_int8_features.shader_float16_int8_features_khr + .sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; + device.ext_shader_float16_int8_features.shader_float16_int8_features_khr + .pNext = features.pNext; + features.pNext = &device.ext_shader_float16_int8_features + .shader_float16_int8_features_khr; + } vkpGetPhysicalDeviceFeatures2KHR(physical_device, &features); device.features = features.features; } else { -- GitLab From aab256296f079e0cdec39b85c879afbec1c1a847 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Thu, 16 Jan 2020 11:22:11 +0800 Subject: [PATCH 0862/1255] Add TouchIntegrationTest tests Base on InputReaderIntegrationTest which would test the threading functionality. This would emulate the touch screen device and send the raw events to verify if InputListener could really receive the MotionEvent. - Add tests for handling single touch and multi touch. - Add test for handling MT_TOOL_PALM. Bug: 117933934 Test: atest TouchIntegrationTest Change-Id: I450c0159ac60d7da0471235407b3c537ab94fa6f --- .../inputflinger/tests/InputReader_test.cpp | 132 +++++++++++++++++- .../inputflinger/tests/TestInputListener.cpp | 19 +-- .../inputflinger/tests/TestInputListener.h | 5 +- services/inputflinger/tests/UinputDevice.cpp | 69 ++++++++- services/inputflinger/tests/UinputDevice.h | 36 +++++ 5 files changed, 243 insertions(+), 18 deletions(-) diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 3ae8b56c11..618aefc741 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1748,7 +1748,7 @@ protected: virtual void SetUp() override { mFakePolicy = new FakeInputReaderPolicy(); - mTestListener = new TestInputListener(); + mTestListener = new TestInputListener(50ms); mReader = new InputReader(std::make_shared(), mFakePolicy, mTestListener); ASSERT_EQ(mReader->start(), OK); @@ -1847,6 +1847,135 @@ TEST_F(InputReaderIntegrationTest, SendsEventsToInputListener) { ASSERT_LE(prevTimestamp, keyArgs.eventTime); } +// --- TouchProcessTest --- +class TouchIntegrationTest : public InputReaderIntegrationTest { +protected: + static const int32_t FIRST_SLOT = 0; + static const int32_t SECOND_SLOT = 1; + static const int32_t FIRST_TRACKING_ID = 0; + static const int32_t SECOND_TRACKING_ID = 1; + const std::string UNIQUE_ID = "local:0"; + + virtual void SetUp() override { + InputReaderIntegrationTest::SetUp(); + // At least add an internal display. + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, + DISPLAY_ORIENTATION_0, UNIQUE_ID, NO_PORT, + ViewportType::VIEWPORT_INTERNAL); + + mDevice = createUinputDevice(Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT)); + ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled()); + } + + void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height, + int32_t orientation, const std::string& uniqueId, + std::optional physicalPort, + ViewportType viewportType) { + mFakePolicy->addDisplayViewport(displayId, width, height, orientation, uniqueId, + physicalPort, viewportType); + mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO); + } + + std::unique_ptr mDevice; +}; + +TEST_F(TouchIntegrationTest, InputEvent_ProcessSingleTouch) { + NotifyMotionArgs args; + const Point centerPoint = mDevice->getCenterPoint(); + + // ACTION_DOWN + mDevice->sendDown(centerPoint); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); + + // ACTION_MOVE + mDevice->sendMove(centerPoint + Point(1, 1)); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); + + // ACTION_UP + mDevice->sendUp(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); +} + +TEST_F(TouchIntegrationTest, InputEvent_ProcessMultiTouch) { + NotifyMotionArgs args; + const Point centerPoint = mDevice->getCenterPoint(); + + // ACTION_DOWN + mDevice->sendDown(centerPoint); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); + + // ACTION_POINTER_DOWN (Second slot) + const Point secondPoint = centerPoint + Point(100, 100); + mDevice->sendSlot(SECOND_SLOT); + mDevice->sendTrackingId(SECOND_TRACKING_ID); + mDevice->sendDown(secondPoint + Point(1, 1)); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + args.action); + + // ACTION_MOVE (Second slot) + mDevice->sendMove(secondPoint); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); + + // ACTION_POINTER_UP (Second slot) + mDevice->sendUp(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + args.action); + + // ACTION_UP + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendUp(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); +} + +TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { + NotifyMotionArgs args; + const Point centerPoint = mDevice->getCenterPoint(); + + // ACTION_DOWN + mDevice->sendDown(centerPoint); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); + + // ACTION_POINTER_DOWN (Second slot) + const Point secondPoint = centerPoint + Point(100, 100); + mDevice->sendSlot(SECOND_SLOT); + mDevice->sendTrackingId(SECOND_TRACKING_ID); + mDevice->sendDown(secondPoint); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + args.action); + + // ACTION_MOVE (Second slot) + mDevice->sendMove(secondPoint + Point(1, 1)); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); + + // Send MT_TOOL_PALM, which indicates that the touch IC has determined this to be a grip event. + // Expect to receive ACTION_CANCEL, to abort the entire gesture. + mDevice->sendToolType(MT_TOOL_PALM); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, args.action); + + // ACTION_POINTER_UP (Second slot) + mDevice->sendUp(); + + // ACTION_UP + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendUp(); + + // Expect no event received after abort the entire gesture. + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled()); +} + // --- InputDeviceTest --- class InputDeviceTest : public testing::Test { protected: @@ -7032,5 +7161,4 @@ TEST_F(MultiTouchInputMapperTest_ExternalDevice, Viewports_Fallback) { ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId); } - } // namespace android diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp index 06b05acdab..86ff3b1d4d 100644 --- a/services/inputflinger/tests/TestInputListener.cpp +++ b/services/inputflinger/tests/TestInputListener.cpp @@ -19,20 +19,11 @@ #include "TestInputListener.h" -namespace { - -using std::chrono_literals::operator""ms; - -// Timeout for waiting for an expected event -static constexpr std::chrono::duration WAIT_TIMEOUT = 5ms; - -} // namespace - namespace android { // --- TestInputListener --- -TestInputListener::TestInputListener() { } +TestInputListener::TestInputListener(const std::chrono::milliseconds timeout) : mTimeout(timeout) {} TestInputListener::~TestInputListener() { } @@ -95,9 +86,9 @@ void TestInputListener::assertCalled(NotifyArgsType* outEventArgs, std::string m std::vector& queue = std::get>(mQueues); if (queue.empty()) { - const bool eventReceived = - mCondition.wait_for(lock, WAIT_TIMEOUT, - [&queue]() REQUIRES(mLock) { return !queue.empty(); }); + const bool eventReceived = mCondition.wait_for(lock, mTimeout, [&queue]() REQUIRES(mLock) { + return !queue.empty(); + }); if (!eventReceived) { FAIL() << "Timed out waiting for event: " << message.c_str(); } @@ -114,7 +105,7 @@ void TestInputListener::assertNotCalled(std::string message) { base::ScopedLockAssertion assumeLocked(mLock); std::vector& queue = std::get>(mQueues); - const bool eventReceived = mCondition.wait_for(lock, WAIT_TIMEOUT, [&queue]() REQUIRES(mLock) { + const bool eventReceived = mCondition.wait_for(lock, mTimeout, [&queue]() REQUIRES(mLock) { return !queue.empty(); }); if (eventReceived) { diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h index 945e2ea58c..4262f5adfb 100644 --- a/services/inputflinger/tests/TestInputListener.h +++ b/services/inputflinger/tests/TestInputListener.h @@ -21,6 +21,8 @@ #include #include "InputListener.h" +using std::chrono_literals::operator""ms; + namespace android { // --- TestInputListener --- @@ -30,7 +32,7 @@ protected: virtual ~TestInputListener(); public: - TestInputListener(); + TestInputListener(const std::chrono::milliseconds timeout = 5ms); void assertNotifyConfigurationChangedWasCalled( NotifyConfigurationChangedArgs* outEventArgs = nullptr); @@ -73,6 +75,7 @@ private: std::mutex mLock; std::condition_variable mCondition; + const std::chrono::milliseconds mTimeout; std::tuple, // std::vector, // diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp index 2775d21ce2..99480b71db 100644 --- a/services/inputflinger/tests/UinputDevice.cpp +++ b/services/inputflinger/tests/UinputDevice.cpp @@ -119,7 +119,7 @@ void UinputKeyboard::pressAndReleaseKey(int key) { EXPECT_NO_FATAL_FAILURE(releaseKey(key)); } -// --- UinputHomeKey--- +// --- UinputHomeKey --- UinputHomeKey::UinputHomeKey() : UinputKeyboard({KEY_HOME}) {} @@ -127,4 +127,71 @@ void UinputHomeKey::pressAndReleaseHomeKey() { EXPECT_NO_FATAL_FAILURE(pressAndReleaseKey(KEY_HOME)); } +// --- UinputTouchScreen --- +UinputTouchScreen::UinputTouchScreen(const Rect* size) + : UinputDevice(UinputTouchScreen::DEVICE_NAME), mSize(*size) {} + +void UinputTouchScreen::configureDevice(int fd, uinput_user_dev* device) { + // Setup the touch screen device + ioctl(fd, UI_SET_EVBIT, EV_KEY); + ioctl(fd, UI_SET_EVBIT, EV_REL); + ioctl(fd, UI_SET_EVBIT, EV_ABS); + ioctl(fd, UI_SET_ABSBIT, ABS_MT_SLOT); + ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOUCH_MAJOR); + ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_X); + ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y); + ioctl(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID); + ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOOL_TYPE); + ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT); + ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH); + + device->absmin[ABS_MT_SLOT] = RAW_SLOT_MIN; + device->absmax[ABS_MT_SLOT] = RAW_SLOT_MAX; + device->absmin[ABS_MT_TOUCH_MAJOR] = RAW_TOUCH_MIN; + device->absmax[ABS_MT_TOUCH_MAJOR] = RAW_TOUCH_MAX; + device->absmin[ABS_MT_POSITION_X] = mSize.left; + device->absmax[ABS_MT_POSITION_X] = mSize.right - 1; + device->absmin[ABS_MT_POSITION_Y] = mSize.top; + device->absmax[ABS_MT_POSITION_Y] = mSize.bottom - 1; + device->absmin[ABS_MT_TRACKING_ID] = RAW_ID_MIN; + device->absmax[ABS_MT_TRACKING_ID] = RAW_ID_MAX; +} + +void UinputTouchScreen::sendSlot(int32_t slot) { + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_SLOT, slot)); +} + +void UinputTouchScreen::sendTrackingId(int32_t trackingId) { + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_TRACKING_ID, trackingId)); +} + +void UinputTouchScreen::sendDown(const Point& point) { + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, BTN_TOUCH, 1)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0)); +} + +void UinputTouchScreen::sendMove(const Point& point) { + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0)); +} + +void UinputTouchScreen::sendUp() { + sendTrackingId(0xffffffff); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, BTN_TOUCH, 0)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0)); +} + +void UinputTouchScreen::sendToolType(int32_t toolType) { + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_TOOL_TYPE, toolType)); + EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0)); +} + +// Get the center x, y base on the range definition. +const Point UinputTouchScreen::getCenterPoint() { + return Point(mSize.left + mSize.width() / 2, mSize.top + mSize.height() / 2); +} + } // namespace android diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h index 57d9011695..ec3cd9fdba 100644 --- a/services/inputflinger/tests/UinputDevice.h +++ b/services/inputflinger/tests/UinputDevice.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include @@ -106,6 +108,40 @@ private: UinputHomeKey(); }; +// --- UinputTouchScreen --- +// A touch screen device with specific size. +class UinputTouchScreen : public UinputDevice { +public: + static constexpr const char* DEVICE_NAME = "Test Touch Screen"; + static const int32_t RAW_TOUCH_MIN = 0; + static const int32_t RAW_TOUCH_MAX = 31; + static const int32_t RAW_ID_MIN = 0; + static const int32_t RAW_ID_MAX = 9; + static const int32_t RAW_SLOT_MIN = 0; + static const int32_t RAW_SLOT_MAX = 9; + static const int32_t RAW_PRESSURE_MIN = 0; + static const int32_t RAW_PRESSURE_MAX = 255; + + template + friend std::unique_ptr createUinputDevice(Ts... args); + + void sendSlot(int32_t slot); + void sendTrackingId(int32_t trackingId); + void sendDown(const Point& point); + void sendMove(const Point& point); + void sendUp(); + void sendToolType(int32_t toolType); + + const Point getCenterPoint(); + +protected: + UinputTouchScreen(const Rect* size); + +private: + void configureDevice(int fd, uinput_user_dev* device) override; + const Rect mSize; +}; + } // namespace android #endif // _UI_TEST_INPUT_UINPUT_INJECTOR_H -- GitLab From ff731d8be6048e2aaa857aeae6a60eb5ede43a70 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 18 Feb 2020 17:22:46 -0800 Subject: [PATCH 0863/1255] Expose configGroup to DisplayConfig Bug: 149784270 Test: Simulate multiple config with debug change ag/10355181 Change-Id: Id78013918c2f4a30abfe68d458b4d0a1f8147070 --- libs/ui/include/ui/DisplayConfig.h | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/libs/ui/include/ui/DisplayConfig.h b/libs/ui/include/ui/DisplayConfig.h index 09b8211a9d..d6fbaab387 100644 --- a/libs/ui/include/ui/DisplayConfig.h +++ b/libs/ui/include/ui/DisplayConfig.h @@ -33,6 +33,7 @@ struct DisplayConfig { nsecs_t appVsyncOffset = 0; nsecs_t sfVsyncOffset = 0; nsecs_t presentationDeadline = 0; + int configGroup = -1; }; static_assert(std::is_trivially_copyable_v); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f3755f466c..1d00624199 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -853,6 +853,7 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, const auto offsets = mPhaseConfiguration->getOffsetsForRefreshRate(config.refreshRate); config.appVsyncOffset = offsets.late.app; config.sfVsyncOffset = offsets.late.sf; + config.configGroup = hwConfig->getConfigGroup(); // This is how far in advance a buffer must be queued for // presentation at a given time. If you want a buffer to appear -- GitLab From 0d2aad706c7977f7dc8f70e6a2fd0426e5c698e1 Mon Sep 17 00:00:00 2001 From: Paul Chang Date: Thu, 13 Feb 2020 20:04:03 +0800 Subject: [PATCH 0864/1255] Support to screenshot to interactive bugreport. - Take screenshot only after critical dumpsys has finished -- so calling app can be shown earlier without disrupting critical dumpsys after starting bugreport. - Show a visual indication to indicate screenshot is taken via IDumpstateListener.onScreenshotTaken(). - Copy the screenshot file to calling app after consent is granted for letting calling app can get and show the screenshot earlier, otherwise calling app may need to wait several minutes to get the screenshot to show. - Rename do_fb --> do_screenshot because do_fb basically means do_screenshot. BUG:149525300 Test: Flash and press bug report shortcut and check the screenshot Change-Id: Ibaca13bfabc1350448d05df12be5ee9291860c0e Merged-In: Ibaca13bfabc1350448d05df12be5ee9291860c0e --- cmds/dumpstate/DumpstateService.cpp | 2 +- .../binder/android/os/IDumpstateListener.aidl | 5 ++ cmds/dumpstate/dumpstate.cpp | 74 +++++++++++++------ cmds/dumpstate/dumpstate.h | 5 +- cmds/dumpstate/tests/dumpstate_smoke_test.cpp | 6 ++ cmds/dumpstate/tests/dumpstate_test.cpp | 25 ++++--- 6 files changed, 82 insertions(+), 35 deletions(-) diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp index 87ea520f84..466575f2fa 100644 --- a/cmds/dumpstate/DumpstateService.cpp +++ b/cmds/dumpstate/DumpstateService.cpp @@ -120,7 +120,7 @@ binder::Status DumpstateService::startBugreport(int32_t calling_uid, options->Initialize(static_cast(bugreport_mode), bugreport_fd, screenshot_fd); - if (bugreport_fd.get() == -1 || (options->do_fb && screenshot_fd.get() == -1)) { + if (bugreport_fd.get() == -1 || (options->do_screenshot && screenshot_fd.get() == -1)) { MYLOGE("Invalid filedescriptor"); signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT); } diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl index e486460753..e17f18e204 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl @@ -61,4 +61,9 @@ interface IDumpstateListener { * Called when taking bugreport finishes successfully. */ void onFinished(); + + /** + * Called when screenshot is taken. + */ + void onScreenshotTaken(boolean success); } diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 814a4edafd..344011675d 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -647,6 +647,24 @@ android::binder::Status Dumpstate::ConsentCallback::onReportApproved() { std::lock_guard lock(lock_); result_ = APPROVED; MYLOGD("User approved consent to share bugreport\n"); + + // Maybe copy screenshot so calling app can display the screenshot to the user as soon as + // consent is granted. + if (ds.options_->is_screenshot_copied) { + return android::binder::Status::ok(); + } + + if (!ds.options_->do_screenshot || ds.options_->screenshot_fd.get() == -1 || + !ds.do_early_screenshot_) { + return android::binder::Status::ok(); + } + + bool copy_succeeded = android::os::CopyFileToFd(ds.screenshot_path_, + ds.options_->screenshot_fd.get()); + ds.options_->is_screenshot_copied = copy_succeeded; + if (copy_succeeded) { + android::os::UnlinkAndLogOnError(ds.screenshot_path_); + } return android::binder::Status::ok(); } @@ -1407,7 +1425,7 @@ static Dumpstate::RunStatus dumpstate() { /* Dump Bluetooth HCI logs */ ds.AddDir("/data/misc/bluetooth/logs", true); - if (ds.options_->do_fb && !ds.do_early_screenshot_) { + if (ds.options_->do_screenshot && !ds.do_early_screenshot_) { MYLOGI("taking late screenshot\n"); ds.TakeScreenshot(); } @@ -2149,7 +2167,7 @@ static void PrepareToWriteToFile() { ds.base_name_ += "-wifi"; } - if (ds.options_->do_fb) { + if (ds.options_->do_screenshot) { ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png"); } ds.tmp_path_ = ds.GetPath(".tmp"); @@ -2229,43 +2247,45 @@ static inline const char* ModeToString(Dumpstate::BugreportMode mode) { } static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) { + // Modify com.android.shell.BugreportProgressService#isDefaultScreenshotRequired as well for + // default system screenshots. options->bugreport_mode = ModeToString(mode); switch (mode) { case Dumpstate::BugreportMode::BUGREPORT_FULL: - options->do_fb = true; + options->do_screenshot = true; options->dumpstate_hal_mode = DumpstateMode::FULL; break; case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE: // Currently, the dumpstate binder is only used by Shell to update progress. options->do_start_service = true; options->do_progress_updates = true; - options->do_fb = false; + options->do_screenshot = true; options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE; break; case Dumpstate::BugreportMode::BUGREPORT_REMOTE: options->do_vibrate = false; options->is_remote_mode = true; - options->do_fb = false; + options->do_screenshot = false; options->dumpstate_hal_mode = DumpstateMode::REMOTE; break; case Dumpstate::BugreportMode::BUGREPORT_WEAR: options->do_start_service = true; options->do_progress_updates = true; options->do_zip_file = true; - options->do_fb = true; + options->do_screenshot = true; options->dumpstate_hal_mode = DumpstateMode::WEAR; break; // TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY. case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY: options->telephony_only = true; options->do_progress_updates = true; - options->do_fb = false; + options->do_screenshot = false; options->dumpstate_hal_mode = DumpstateMode::CONNECTIVITY; break; case Dumpstate::BugreportMode::BUGREPORT_WIFI: options->wifi_only = true; options->do_zip_file = true; - options->do_fb = false; + options->do_screenshot = false; options->dumpstate_hal_mode = DumpstateMode::WIFI; break; case Dumpstate::BugreportMode::BUGREPORT_DEFAULT: @@ -2275,12 +2295,13 @@ static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOpt static void LogDumpOptions(const Dumpstate::DumpOptions& options) { MYLOGI( - "do_zip_file: %d do_vibrate: %d use_socket: %d use_control_socket: %d do_fb: %d " + "do_zip_file: %d do_vibrate: %d use_socket: %d use_control_socket: %d do_screenshot: %d " "is_remote_mode: %d show_header_only: %d do_start_service: %d telephony_only: %d " "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s dumpstate_hal_mode: %s " "args: %s\n", options.do_zip_file, options.do_vibrate, options.use_socket, options.use_control_socket, - options.do_fb, options.is_remote_mode, options.show_header_only, options.do_start_service, + options.do_screenshot, options.is_remote_mode, options.show_header_only, + options.do_start_service, options.telephony_only, options.wifi_only, options.do_progress_updates, options.bugreport_fd.get(), options.bugreport_mode.c_str(), toString(options.dumpstate_hal_mode).c_str(), options.args.c_str()); @@ -2313,7 +2334,7 @@ Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) case 'S': use_control_socket = true; break; case 'v': show_header_only = true; break; case 'q': do_vibrate = false; break; - case 'p': do_fb = true; break; + case 'p': do_screenshot = true; break; case 'P': do_progress_updates = true; break; case 'R': is_remote_mode = true; break; case 'V': break; // compatibility no-op @@ -2543,11 +2564,6 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, Vibrate(150); } - if (options_->do_fb && do_early_screenshot_) { - MYLOGI("taking early screenshot\n"); - TakeScreenshot(); - } - if (options_->do_zip_file && zip_file != nullptr) { if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) { MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(), @@ -2593,19 +2609,20 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, PrintHeader(); if (options_->telephony_only) { + MaybeTakeEarlyScreenshot(); MaybeCheckUserConsent(calling_uid, calling_package); DumpstateTelephonyOnly(calling_package); DumpstateBoard(); } else if (options_->wifi_only) { + MaybeTakeEarlyScreenshot(); MaybeCheckUserConsent(calling_uid, calling_package); DumpstateWifiOnly(); } else { - // Invoking the critical dumpsys calls before DumpTraces() to try and - // keep the system stats as close to its initial state as possible. + // Invoke critical dumpsys first to preserve system state, before doing anything else. RunDumpsysCritical(); - // Run consent check only after critical dumpsys has finished -- so the consent - // isn't going to pollute the system state / logs. + // Take screenshot and get consent only after critical dumpsys has finished. + MaybeTakeEarlyScreenshot(); MaybeCheckUserConsent(calling_uid, calling_package); // Dump state for the default case. This also drops root. @@ -2640,7 +2657,9 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, MYLOGI("User denied consent. Returning\n"); return status; } - if (options_->do_fb && options_->screenshot_fd.get() != -1) { + if (options_->do_screenshot && + options_->screenshot_fd.get() != -1 && + !options_->is_screenshot_copied) { bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_, options_->screenshot_fd.get()); if (copy_succeeded) { @@ -2694,6 +2713,14 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, : RunStatus::OK; } +void Dumpstate::MaybeTakeEarlyScreenshot() { + if (!options_->do_screenshot || !do_early_screenshot_) { + return; + } + + TakeScreenshot(); +} + void Dumpstate::MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package) { if (calling_uid == AID_SHELL || !CalledByApi()) { // No need to get consent for shell triggered dumpstates, or not through @@ -3630,6 +3657,11 @@ void Dumpstate::TakeScreenshot(const std::string& path) { } else { MYLOGE("Failed to take screenshot on %s\n", real_path.c_str()); } + if (listener_ != nullptr) { + // Show a visual indication to indicate screenshot is taken via + // IDumpstateListener.onScreenshotTaken() + listener_->onScreenshotTaken(status == 0); + } } bool is_dir(const char* pathname) { diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 111c098992..7e277873cb 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -359,7 +359,8 @@ class Dumpstate { // Writes bugreport content to a socket; only flatfile format is supported. bool use_socket = false; bool use_control_socket = false; - bool do_fb = false; + bool do_screenshot = false; + bool is_screenshot_copied = false; bool is_remote_mode = false; bool show_header_only = false; bool do_start_service = false; @@ -494,6 +495,8 @@ class Dumpstate { RunStatus DumpstateDefaultAfterCritical(); + void MaybeTakeEarlyScreenshot(); + void MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package); // Removes the in progress files output files (tmp file, zip/txt file, screenshot), diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp index dac90d91b0..f26e4db976 100644 --- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp @@ -167,6 +167,12 @@ class DumpstateListener : public BnDumpstateListener { return binder::Status::ok(); } + binder::Status onScreenshotTaken(bool success) override { + std::lock_guard lock(lock_); + dprintf(out_fd_, "\rResult of taking screenshot: %s", success ? "success" : "failure"); + return binder::Status::ok(); + } + bool getIsFinished() { std::lock_guard lock(lock_); return is_finished_; diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 76b996081d..0a0c40ee0d 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -65,6 +65,7 @@ class DumpstateListenerMock : public IDumpstateListener { MOCK_METHOD1(onProgress, binder::Status(int32_t progress)); MOCK_METHOD1(onError, binder::Status(int32_t error_code)); MOCK_METHOD0(onFinished, binder::Status()); + MOCK_METHOD1(onScreenshotTaken, binder::Status(bool success)); protected: MOCK_METHOD0(onAsBinder, IBinder*()); @@ -173,7 +174,7 @@ TEST_F(DumpOptionsTest, InitializeNone) { EXPECT_FALSE(options_.use_control_socket); EXPECT_FALSE(options_.show_header_only); EXPECT_TRUE(options_.do_vibrate); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); @@ -199,7 +200,7 @@ TEST_F(DumpOptionsTest, InitializeAdbBugreport) { // Other options retain default values EXPECT_TRUE(options_.do_vibrate); EXPECT_FALSE(options_.show_header_only); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); EXPECT_FALSE(options_.use_socket); @@ -225,7 +226,7 @@ TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) { EXPECT_FALSE(options_.do_zip_file); EXPECT_FALSE(options_.use_control_socket); EXPECT_FALSE(options_.show_header_only); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); @@ -234,7 +235,7 @@ TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) { TEST_F(DumpOptionsTest, InitializeFullBugReport) { options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd); EXPECT_TRUE(options_.do_add_date); - EXPECT_TRUE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::FULL); @@ -254,7 +255,7 @@ TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) { EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.do_progress_updates); EXPECT_TRUE(options_.do_start_service); - EXPECT_FALSE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::INTERACTIVE); // Other options retain default values @@ -271,7 +272,7 @@ TEST_F(DumpOptionsTest, InitializeRemoteBugReport) { EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.is_remote_mode); EXPECT_FALSE(options_.do_vibrate); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::REMOTE); // Other options retain default values @@ -284,7 +285,7 @@ TEST_F(DumpOptionsTest, InitializeRemoteBugReport) { TEST_F(DumpOptionsTest, InitializeWearBugReport) { options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd); EXPECT_TRUE(options_.do_add_date); - EXPECT_TRUE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.do_progress_updates); EXPECT_TRUE(options_.do_start_service); @@ -301,7 +302,7 @@ TEST_F(DumpOptionsTest, InitializeWearBugReport) { TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) { options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd); EXPECT_TRUE(options_.do_add_date); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.telephony_only); EXPECT_TRUE(options_.do_progress_updates); @@ -318,7 +319,7 @@ TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) { TEST_F(DumpOptionsTest, InitializeWifiBugReport) { options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd); EXPECT_TRUE(options_.do_add_date); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.wifi_only); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WIFI); @@ -346,7 +347,7 @@ TEST_F(DumpOptionsTest, InitializeDefaultBugReport) { EXPECT_EQ(status, Dumpstate::RunStatus::OK); EXPECT_TRUE(options_.do_add_date); - EXPECT_TRUE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); @@ -384,7 +385,7 @@ TEST_F(DumpOptionsTest, InitializePartial1) { // Other options retain default values EXPECT_FALSE(options_.show_header_only); EXPECT_TRUE(options_.do_vibrate); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); @@ -407,7 +408,7 @@ TEST_F(DumpOptionsTest, InitializePartial2) { EXPECT_EQ(status, Dumpstate::RunStatus::OK); EXPECT_TRUE(options_.show_header_only); EXPECT_FALSE(options_.do_vibrate); - EXPECT_TRUE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_progress_updates); EXPECT_TRUE(options_.is_remote_mode); -- GitLab From 9c051c08749e5dfb39a730d2bb1b8aec6900ab41 Mon Sep 17 00:00:00 2001 From: Dan Stoza Date: Fri, 28 Feb 2020 10:19:07 -0800 Subject: [PATCH 0865/1255] sf: Remember that AIDL Power HAL isn't present Updates PowerAdvisor to cache if the AIDL Power HAL isn't available, so it doesn't continuously try to find it if there isn't a Power HAL 1.3 implementation to fall back to. Bug: 150442909 Test: Manual, no vintf logspam on a device with Power HAL 1.0 Change-Id: Icb56be73b0d156aae8acdfa72e07f3f05c648e1e --- .../DisplayHardware/PowerAdvisor.cpp | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index 550ec6173a..06e0cbb044 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -124,24 +124,20 @@ public: static std::unique_ptr connect() { // Power HAL 1.3 is not guaranteed to be available, thus we need to query // Power HAL 1.0 first and try to cast it to Power HAL 1.3. - // Power HAL 1.0 is always available, thus if we fail to query it, it means - // Power HAL is not available temporarily and we should retry later. However, - // if Power HAL 1.0 is available and we can't cast it to Power HAL 1.3, - // it means Power HAL 1.3 is not available at all, so we should stop trying. sp powerHal = nullptr; - if (sHasPowerHal_1_3) { - sp powerHal_1_0 = V1_0::IPower::getService(); - if (powerHal_1_0 != nullptr) { - // Try to cast to Power HAL 1.3 - powerHal = V1_3::IPower::castFrom(powerHal_1_0); - if (powerHal == nullptr) { - ALOGW("No Power HAL 1.3 service in system"); - sHasPowerHal_1_3 = false; - } else { - ALOGI("Loaded Power HAL 1.3 service"); - } + sp powerHal_1_0 = V1_0::IPower::getService(); + if (powerHal_1_0 != nullptr) { + // Try to cast to Power HAL 1.3 + powerHal = V1_3::IPower::castFrom(powerHal_1_0); + if (powerHal == nullptr) { + ALOGW("No Power HAL 1.3 service in system, disabling PowerAdvisor"); + } else { + ALOGI("Loaded Power HAL 1.3 service"); } + } else { + ALOGW("No Power HAL found, disabling PowerAdvisor"); } + if (powerHal == nullptr) { return nullptr; } @@ -162,12 +158,9 @@ public: } private: - static bool sHasPowerHal_1_3; const sp mPowerHal = nullptr; }; -bool HidlPowerHalWrapper::sHasPowerHal_1_3 = true; - class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper { public: AidlPowerHalWrapper(sp powerHal) : mPowerHal(std::move(powerHal)) { @@ -226,7 +219,13 @@ private: PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { static std::unique_ptr sHalWrapper = nullptr; + static bool sHasHal = true; + + if (!sHasHal) { + return nullptr; + } + // If we used to have a HAL, but it stopped responding, attempt to reconnect if (mReconnectPowerHal) { sHalWrapper = nullptr; mReconnectPowerHal = false; @@ -244,6 +243,12 @@ PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { sHalWrapper = HidlPowerHalWrapper::connect(); } + // If we make it to this point and still don't have a HAL, it's unlikely we + // will, so stop trying + if (sHalWrapper == nullptr) { + sHasHal = false; + } + return sHalWrapper.get(); } -- GitLab From de7156e40ab3ed00971df71187ed028587731d2e Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 28 Feb 2020 17:29:39 -0800 Subject: [PATCH 0866/1255] SurfaceFlinger: getRefreshRateForContentV2 always returns valid config Make sure getRefreshRateForContentV2 always returns an allowed config. Bug: 150477881 Test: YouTube video playback Change-Id: I2271e4e1b3855875d8bc55d300d33636ca9de3fc --- services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 1765d2d8f7..15b158d95f 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -235,13 +235,13 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( ? getBestRefreshRate(scores.rbegin(), scores.rend()) : getBestRefreshRate(scores.begin(), scores.end()); - return bestRefreshRate == nullptr ? *mCurrentRefreshRate : *bestRefreshRate; + return *bestRefreshRate; } template const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const { - const RefreshRate* bestRefreshRate = nullptr; - float max = 0; + const RefreshRate* bestRefreshRate = begin->first; + float max = begin->second; for (auto i = begin; i != end; ++i) { const auto [refreshRate, score] = *i; ALOGV("%s scores %.2f", refreshRate->name.c_str(), score); -- GitLab From 0d73666f60cbf10d0b415d13733a1587962a65c0 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 28 Feb 2020 18:22:30 -0800 Subject: [PATCH 0867/1255] SurfaceFlinger: fix infrequent frames logic While playing video in YouTube, the UI posts sometimes 2 buffers very close to each other, but overall frame rate is very low (~fps). Fix the infrequent logic to detect this scenario. Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Bug: 147516364 Change-Id: Ie821252f793a18bb8830ac6582b9d99ab8b1c8f6 --- .../surfaceflinger/Scheduler/LayerInfoV2.cpp | 6 +- .../tests/unittests/LayerHistoryTestV2.cpp | 57 +++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp index b755798a92..b4365bf03f 100644 --- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp @@ -82,14 +82,14 @@ bool LayerInfoV2::isFrequent(nsecs_t now) const { } } - const auto numFrames = std::distance(it, mFrameTimes.end()) - 1; - if (numFrames <= 0) { + const auto numFrames = std::distance(it, mFrameTimes.end()); + if (numFrames < FREQUENT_LAYER_WINDOW_SIZE) { return false; } // Layer is considered frequent if the average frame rate is higher than the threshold const auto totalTime = mFrameTimes.back().queueTime - it->queueTime; - return (1e9f * numFrames) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER; + return (1e9f * (numFrames - 1)) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER; } bool LayerInfoV2::hasEnoughDataForHeuristic() const { diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp index 959c256262..37da76b172 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp @@ -36,6 +36,7 @@ class LayerHistoryTestV2 : public testing::Test { protected: static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE; static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS; + static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfoV2::FREQUENT_LAYER_WINDOW_SIZE; static constexpr float LO_FPS = 30.f; static constexpr auto LO_FPS_PERIOD = static_cast(1e9f / LO_FPS); @@ -451,5 +452,61 @@ TEST_F(LayerHistoryTestV2, multipleLayers) { EXPECT_EQ(0, frequentLayerCount(time)); } +TEST_F(LayerHistoryTestV2, inactiveLayers) { + auto layer = createLayer(); + + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + + nsecs_t time = systemTime(); + + // the very first updates makes the layer frequent + for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) { + history().record(layer.get(), time, time); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + + EXPECT_EQ(1, layerCount()); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + } + + // the next update with the MAX_FREQUENT_LAYER_PERIOD_NS will get us to infrequent + history().record(layer.get(), time, time); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + + EXPECT_EQ(1, layerCount()); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + + // advance the time for the previous frame to be inactive + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + + // Now event if we post a quick few frame we should stay infrequent + for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) { + history().record(layer.get(), time, time); + time += HI_FPS_PERIOD; + + EXPECT_EQ(1, layerCount()); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + } + + // More quick frames will get us to frequent again + history().record(layer.get(), time, time); + time += HI_FPS_PERIOD; + + EXPECT_EQ(1, layerCount()); + ASSERT_EQ(1, history().summarize(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); +} + } // namespace } // namespace android::scheduler -- GitLab From c7812be6375a2a9f2c7db1e5f0015d452721d9c2 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Thu, 27 Feb 2020 22:40:27 +0800 Subject: [PATCH 0868/1255] Pass source to dispatchBatchedInputEventPending (2/2) The API requestUnbufferedDispatch allow View could receive the event in unbuffered way. But doing processUnbufferedRequest in onInputEvent is too late for the first event. Instead, we should pass the source of the input event up to dispatchBatchedInputEventPending, and then we can use that to determine whether we could consume event immediately or not. Bug: 149715123 Test: atest ViewUnbufferedTest Change-Id: I9cd6f76cc3ba74647b57036b3f4979efa8751b95 --- include/input/InputTransport.h | 7 +++++++ libs/input/InputTransport.cpp | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 8ca178c1d7..7ca9031f77 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -404,6 +404,13 @@ public: */ bool hasPendingBatch() const; + /* Returns the source of first pending batch if exist. + * + * Should be called after calling consume() with consumeBatches == false to determine + * whether consume() should be called again later on with consumeBatches == true. + */ + int32_t getPendingBatchSource() const; + private: // True if touch resampling is enabled. const bool mResampleTouch; diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 7335b30a49..ef7cc7d531 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -1130,6 +1130,16 @@ bool InputConsumer::hasPendingBatch() const { return !mBatches.isEmpty(); } +int32_t InputConsumer::getPendingBatchSource() const { + if (mBatches.isEmpty()) { + return AINPUT_SOURCE_CLASS_NONE; + } + + const Batch& batch = mBatches.itemAt(0); + const InputMessage& head = batch.samples.itemAt(0); + return head.body.motion.source; +} + ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const { for (size_t i = 0; i < mBatches.size(); i++) { const Batch& batch = mBatches.itemAt(i); -- GitLab From 8181bb0fd087cb4be77a589aa67702a1fef01103 Mon Sep 17 00:00:00 2001 From: Eran Messeri Date: Thu, 27 Feb 2020 00:47:48 +0000 Subject: [PATCH 0869/1255] Individual attestation: Feature file Add a file for the unique attestation feature. Bug: 140920022 Test: That it compiles. Change-Id: I6e4577b793d6b28bff855d74b313be7eeeab3f05 Merged-In: I6e4577b793d6b28bff855d74b313be7eeeab3f05 (cherry picked from commit 9606640a396ce74520bb17da909e622485774e5d) --- ...oid.hardware.device_unique_attestation.xml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 data/etc/android.hardware.device_unique_attestation.xml diff --git a/data/etc/android.hardware.device_unique_attestation.xml b/data/etc/android.hardware.device_unique_attestation.xml new file mode 100644 index 0000000000..309be7a2c1 --- /dev/null +++ b/data/etc/android.hardware.device_unique_attestation.xml @@ -0,0 +1,20 @@ + + + + + + + -- GitLab From 6b9e9918b9b56f1d6bf3abbfba32ce661f1f97f6 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 21 Jan 2020 10:50:24 -0800 Subject: [PATCH 0870/1255] [SurfaceFlinger] Add hwc information to winscope: * String blob of HWC dump * Fill in HWC composition enum Caveat is that only the primary display information is filled in. Bug: 119443475 Test: Winscope trace Change-Id: I246dc8df5e16388d8e58afeabfe944b158e1a39d --- services/surfaceflinger/Layer.cpp | 22 ++++++++++++++----- services/surfaceflinger/Layer.h | 3 ++- services/surfaceflinger/SurfaceFlinger.cpp | 12 ++++++++-- services/surfaceflinger/SurfaceFlinger.h | 2 ++ services/surfaceflinger/SurfaceTracing.cpp | 6 +++++ services/surfaceflinger/SurfaceTracing.h | 1 + .../surfaceflinger/layerproto/layers.proto | 21 ++++++++++++++++-- .../layerproto/layerstrace.proto | 3 +++ 8 files changed, 60 insertions(+), 10 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d7647d76d3..84cf23e3d0 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -718,9 +718,14 @@ std::vector Layer::prepareClientCompo Hwc2::IComposerClient::Composition Layer::getCompositionType( const sp& display) const { const auto outputLayer = findOutputLayerForDisplay(display); - LOG_FATAL_IF(!outputLayer); - return outputLayer->getState().hwc ? (*outputLayer->getState().hwc).hwcCompositionType - : Hwc2::IComposerClient::Composition::CLIENT; + if (outputLayer == nullptr) { + return Hwc2::IComposerClient::Composition::INVALID; + } + if (outputLayer->getState().hwc) { + return (*outputLayer->getState().hwc).hwcCompositionType; + } else { + return Hwc2::IComposerClient::Composition::CLIENT; + } } bool Layer::getClearClientTarget(const sp& display) const { @@ -2051,13 +2056,20 @@ void Layer::setInputInfo(const InputWindowInfo& info) { setTransactionFlags(eTransactionNeeded); } -LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags) const { +LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags, + const sp& device) const { LayerProto* layerProto = layersProto.add_layers(); writeToProtoDrawingState(layerProto, traceFlags); writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags); + // Only populate for the primary display. + if (device) { + const Hwc2::IComposerClient::Composition compositionType = getCompositionType(device); + layerProto->set_hwc_composition_type(static_cast(compositionType)); + } + for (const sp& layer : mDrawingChildren) { - layer->writeToProto(layersProto, traceFlags); + layer->writeToProto(layersProto, traceFlags, device); } return layerProto; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 5d2144aed4..20d72324c3 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -506,7 +506,8 @@ public: bool isRemovedFromCurrentState() const; LayerProto* writeToProto(LayersProto& layersProto, - uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + uint32_t traceFlags = SurfaceTracing::TRACE_ALL, + const sp& device = nullptr) const; // Write states that are modified by the main thread. This includes drawing // state as well as buffer data. This should be called in the main or tracing diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ce0a8a1ac0..6ff478cf6a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4398,13 +4398,20 @@ void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { } LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { + Mutex::Autolock _l(mStateLock); + const auto device = getDefaultDisplayDeviceLocked(); LayersProto layersProto; for (const sp& layer : mDrawingState.layersSortedByZ) { - layer->writeToProto(layersProto, traceFlags); + layer->writeToProto(layersProto, traceFlags, device); } + return layersProto; } +void SurfaceFlinger::dumpHwc(std::string& result) const { + getHwComposer().dump(result); +} + void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags) const { // Add a fake invisible root layer to the proto output and parent all the offscreen layers to // it. @@ -4419,7 +4426,8 @@ void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t rootProto->add_children(offscreenLayer->sequence); // Add layer - LayerProto* layerProto = offscreenLayer->writeToProto(layersProto, traceFlags); + LayerProto* layerProto = + offscreenLayer->writeToProto(layersProto, traceFlags, nullptr /*device*/); layerProto->set_parent(offscreenRootLayerId); } } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c79621b1fa..fa1a189833 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -918,6 +918,8 @@ private: LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; void dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + // Dumps state from HW Composer + void dumpHwc(std::string& result) const; LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) EXCLUDES(mStateLock); void dumpOffscreenLayers(std::string& result) EXCLUDES(mStateLock); diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp index eb5c7de0fe..c5556ec28f 100644 --- a/services/surfaceflinger/SurfaceTracing.cpp +++ b/services/surfaceflinger/SurfaceTracing.cpp @@ -170,6 +170,12 @@ LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) { mFlinger.dumpOffscreenLayersProto(layers); entry.mutable_layers()->Swap(&layers); + if (mTraceFlags & SurfaceTracing::TRACE_HWC) { + std::string hwcDump; + mFlinger.dumpHwc(hwcDump); + entry.set_hwc_blob(hwcDump); + } + return entry; } diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index 18524f02d8..3c24881d7c 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -56,6 +56,7 @@ public: TRACE_CRITICAL = 1 << 0, TRACE_INPUT = 1 << 1, TRACE_EXTRA = 1 << 2, + TRACE_HWC = 1 << 3, TRACE_ALL = 0xffffffff }; void setTraceFlags(uint32_t flags); diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto index 8afe5039f8..7f1f542e4b 100644 --- a/services/surfaceflinger/layerproto/layers.proto +++ b/services/surfaceflinger/layerproto/layers.proto @@ -9,6 +9,23 @@ message LayersProto { repeated LayerProto layers = 1; } +// Must match definition in the IComposerClient HAL +enum HwcCompositionType { + // Invalid composition type + INVALID = 0; + // Layer was composited by the client into the client target buffer + CLIENT = 1; + // Layer was composited by the device through hardware overlays + DEVICE = 2; + // Layer was composited by the device using a color + SOLID_COLOR = 3; + // Similar to DEVICE, but the layer position may have been asynchronously set + // through setCursorPosition + CURSOR = 4; + // Layer was composited by the device via a sideband stream. + SIDEBAND = 5; +} + // Information about each layer. message LayerProto { // unique id per layer. @@ -73,7 +90,7 @@ message LayerProto { int32 window_type = 33 [deprecated=true]; int32 app_id = 34 [deprecated=true]; // The layer's composition type - int32 hwc_composition_type = 35; + HwcCompositionType hwc_composition_type = 35; // If it's a buffer layer, indicate if the content is protected bool is_protected = 36; // Current frame number being rendered. @@ -190,4 +207,4 @@ message InputWindowInfoProto { message ColorTransformProto { // This will be a 4x4 matrix of float values repeated float val = 1; -} \ No newline at end of file +} diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto index bee17d2d86..ac33a0ef9c 100644 --- a/services/surfaceflinger/layerproto/layerstrace.proto +++ b/services/surfaceflinger/layerproto/layerstrace.proto @@ -48,4 +48,7 @@ message LayersTraceProto { optional string where = 2; optional LayersProto layers = 3; + + // Blob for the current HWC information for all layers, reported by dumpsys. + optional string hwc_blob = 4; } -- GitLab From e3021d703130f9f28a94bef0e7179e75794a59cf Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 28 Feb 2020 15:25:41 -0800 Subject: [PATCH 0871/1255] Remove device state when device is reset When device reset is received in MotionClassifier, don't just set the classification for that device to 'none'. Instead, remove all state related to that device. This prevents growing indefinitely the unordered_maps that contain device-related state. Also, log the feature state to the InputClassifier dump. Bug: 150419367 Test: run several touch integration tests several times, and then do 'dumpsys input'. Ensure that the list doesn't grow as the tests are executed multiple times. Change-Id: I2e1ac359458a321f87e4599bb19350623afc9b2b --- services/inputflinger/BlockingQueue.h | 5 +---- services/inputflinger/InputClassifier.cpp | 9 ++++++++- services/inputflinger/InputClassifier.h | 2 ++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h index db9f26ec12..b612ca77ce 100644 --- a/services/inputflinger/BlockingQueue.h +++ b/services/inputflinger/BlockingQueue.h @@ -45,10 +45,7 @@ public: T pop() { std::unique_lock lock(mLock); android::base::ScopedLockAssertion assumeLock(mLock); - mHasElements.wait(lock, [this]{ - android::base::ScopedLockAssertion assumeLock(mLock); - return !this->mQueue.empty(); - }); + mHasElements.wait(lock, [this]() REQUIRES(mLock) { return !this->mQueue.empty(); }); T t = std::move(mQueue.front()); mQueue.erase(mQueue.begin()); return t; diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index ae9a34882e..e5e83d752c 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -250,7 +250,7 @@ void MotionClassifier::callInputClassifierHal() { case ClassifierEventType::DEVICE_RESET: { const int32_t deviceId = *(event.getDeviceId()); halResponseOk = mService->resetDevice(deviceId).isOk(); - setClassification(deviceId, MotionClassification::NONE); + clearDeviceState(deviceId); break; } case ClassifierEventType::HAL_RESET: { @@ -321,6 +321,12 @@ void MotionClassifier::updateLastDownTime(int32_t deviceId, nsecs_t downTime) { mClassifications[deviceId] = MotionClassification::NONE; } +void MotionClassifier::clearDeviceState(int32_t deviceId) { + std::scoped_lock lock(mLock); + mClassifications.erase(deviceId); + mLastDownTimes.erase(deviceId); +} + MotionClassification MotionClassifier::classify(const NotifyMotionArgs& args) { if ((args.action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN) { updateLastDownTime(args.deviceId, args.downTime); @@ -455,6 +461,7 @@ void InputClassifier::serviceDied(uint64_t /*cookie*/, void InputClassifier::dump(std::string& dump) { std::scoped_lock lock(mLock); dump += "Input Classifier State:\n"; + dump += StringPrintf(INDENT1 "Deep press: %s\n", deepPressEnabled() ? "enabled" : "disabled"); dump += INDENT1 "Motion Classifier:\n"; if (mMotionClassifier) { diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h index 47e20dbf75..96923526da 100644 --- a/services/inputflinger/InputClassifier.h +++ b/services/inputflinger/InputClassifier.h @@ -212,6 +212,8 @@ private: void updateLastDownTime(int32_t deviceId, nsecs_t downTime); + void clearDeviceState(int32_t deviceId); + /** * Exit the InputClassifier HAL thread. * Useful for tests to ensure proper cleanup. -- GitLab From 13bc0bef0eb7d6d53574c3904e0996591fb6b22b Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 27 Feb 2020 16:48:20 -0800 Subject: [PATCH 0872/1255] SurfaceFlinger: add VSYNC-predicted as debug option Add a trace point for the predicted VSYNC event. This is controlled by debug.sf.show_predicted_vsync (default off) Fixes: 150414668 Test: adb shell stop && adb shell setprop debug.sf.show_predicted_vsync 1 && adb shell start Change-Id: Idd140dd2cb98c6bdd25197a742084cd5d4debd90 --- .../surfaceflinger/Scheduler/VSyncReactor.cpp | 29 +++++++++++++++++-- .../surfaceflinger/Scheduler/VSyncReactor.h | 3 ++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index 949ba4ca52..8987dcdc58 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -19,8 +19,10 @@ #define LOG_TAG "VSyncReactor" //#define LOG_NDEBUG 0 #include "VSyncReactor.h" +#include #include #include +#include "../TracedOrdinal.h" #include "TimeKeeper.h" #include "VSyncDispatch.h" #include "VSyncTracker.h" @@ -32,12 +34,35 @@ nsecs_t SystemClock::now() const { return systemTime(SYSTEM_TIME_MONOTONIC); } +class PredictedVsyncTracer { +public: + PredictedVsyncTracer(VSyncDispatch& dispatch) + : mRegistration(dispatch, + std::bind(&PredictedVsyncTracer::callback, this, std::placeholders::_1, + std::placeholders::_2), + "PredictedVsyncTracer") { + mRegistration.schedule(0, 0); + } + +private: + TracedOrdinal mParity = {"VSYNC-predicted", 0}; + VSyncCallbackRegistration mRegistration; + + void callback(nsecs_t /*vsyncTime*/, nsecs_t /*targetWakeupTim*/) { + mParity = !mParity; + mRegistration.schedule(0, 0); + } +}; + VSyncReactor::VSyncReactor(std::unique_ptr clock, std::unique_ptr dispatch, std::unique_ptr tracker, size_t pendingFenceLimit) : mClock(std::move(clock)), mTracker(std::move(tracker)), mDispatch(std::move(dispatch)), - mPendingLimit(pendingFenceLimit) {} + mPendingLimit(pendingFenceLimit), + mPredictedVsyncTracer(property_get_bool("debug.sf.show_predicted_vsync", false) + ? std::make_unique(*mDispatch) + : nullptr) {} VSyncReactor::~VSyncReactor() = default; @@ -287,7 +312,7 @@ status_t VSyncReactor::addEventListener(const char* name, nsecs_t phase, auto it = mCallbacks.find(callback); if (it == mCallbacks.end()) { // TODO (b/146557561): resolve lastCallbackTime semantics in DispSync i/f. - static auto constexpr maxListeners = 3; + static auto constexpr maxListeners = 4; if (mCallbacks.size() >= maxListeners) { ALOGE("callback %s not added, exceeded callback limit of %i (currently %zu)", name, maxListeners, mCallbacks.size()); diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index aa8a38d871..7d8a8e3bb0 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -30,6 +30,7 @@ class Clock; class VSyncDispatch; class VSyncTracker; class CallbackRepeater; +class PredictedVsyncTracer; // TODO (b/145217110): consider renaming. class VSyncReactor : public android::DispSync { @@ -86,6 +87,8 @@ private: std::unordered_map> mCallbacks GUARDED_BY(mMutex); + + const std::unique_ptr mPredictedVsyncTracer; }; class SystemClock : public Clock { -- GitLab From b13d750d9497f0f3f05955955f34231635ce2931 Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Mon, 2 Mar 2020 15:40:02 -0800 Subject: [PATCH 0873/1255] Remove frame rate functions from buffer queue Remove the frame rate functions that were recently added to buffer queue in ag/10028291. Modifying buffer queue is considered risky because we have prebuilt binaries that use the classes in unknown ways. We added an alternative mechanism for communicating frame rate info in ag/10221036, so this code is no longer used for anything. Bug: 150642189 Test: - Built and deployed to a Pixel 4, confirmed normal behavior. - Built all the surface flinger unit tests. - Ran the setFrameRate() cts test. Change-Id: I26a620e842e79a378f58a78a088cff872a49de0d --- libs/gui/BufferHubConsumer.cpp | 10 -------- libs/gui/BufferQueueConsumer.cpp | 12 ---------- libs/gui/BufferQueueCore.cpp | 3 +-- libs/gui/BufferQueueProducer.cpp | 10 -------- libs/gui/ConsumerBase.cpp | 18 -------------- libs/gui/IGraphicBufferConsumer.cpp | 16 ------------- libs/gui/IGraphicBufferProducer.cpp | 24 ------------------- libs/gui/include/gui/BufferHubConsumer.h | 6 ----- libs/gui/include/gui/BufferQueueConsumer.h | 6 ----- libs/gui/include/gui/BufferQueueCore.h | 3 --- libs/gui/include/gui/BufferQueueProducer.h | 3 --- libs/gui/include/gui/ConsumerBase.h | 6 ----- libs/gui/include/gui/IGraphicBufferConsumer.h | 10 -------- libs/gui/include/gui/IGraphicBufferProducer.h | 3 --- libs/gui/include/gui/Surface.h | 1 - .../include/gui/mock/GraphicBufferConsumer.h | 2 -- services/surfaceflinger/BufferQueueLayer.cpp | 2 -- services/surfaceflinger/MonitoredProducer.cpp | 4 ---- services/surfaceflinger/MonitoredProducer.h | 1 - 19 files changed, 1 insertion(+), 139 deletions(-) diff --git a/libs/gui/BufferHubConsumer.cpp b/libs/gui/BufferHubConsumer.cpp index 0ddb87e0be..b5cdeb280a 100644 --- a/libs/gui/BufferHubConsumer.cpp +++ b/libs/gui/BufferHubConsumer.cpp @@ -147,16 +147,6 @@ status_t BufferHubConsumer::discardFreeBuffers() { return INVALID_OPERATION; } -status_t BufferHubConsumer::setFrameRate(float /*frameRate*/) { - ALOGE("BufferHubConsumer::setFrameRate: not implemented."); - return INVALID_OPERATION; -} - -status_t BufferHubConsumer::getFrameRate(float* /*frameRate*/) const { - ALOGE("BufferHubConsumer::getFrameRate: not implemented."); - return INVALID_OPERATION; -} - status_t BufferHubConsumer::dumpState(const String8& /*prefix*/, String8* /*outResult*/) const { ALOGE("BufferHubConsumer::dumpState: not implemented."); return INVALID_OPERATION; diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 4435265bb2..da6143c59f 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -783,18 +783,6 @@ status_t BufferQueueConsumer::discardFreeBuffers() { return NO_ERROR; } -status_t BufferQueueConsumer::setFrameRate(float frameRate) { - std::lock_guard lock(mCore->mMutex); - mCore->mFrameRate = frameRate; - return NO_ERROR; -} - -status_t BufferQueueConsumer::getFrameRate(float* frameRate) const { - std::lock_guard lock(mCore->mMutex); - *frameRate = mCore->mFrameRate; - return NO_ERROR; -} - status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResult) const { struct passwd* pwd = getpwnam("shell"); uid_t shellUid = pwd ? pwd->pw_uid : 0; diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 9e5d681b37..a1803d8f0e 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -130,8 +130,7 @@ BufferQueueCore::BufferQueueCore() mLastQueuedSlot(INVALID_BUFFER_SLOT), mUniqueId(getUniqueId()), mAutoPrerotation(false), - mTransformHintInUse(0), - mFrameRate(0) { + mTransformHintInUse(0) { int numStartingBuffers = getMaxBufferCountLocked(); for (int s = 0; s < numStartingBuffers; s++) { mFreeSlots.insert(s); diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 9e86838592..3f4c5da193 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1676,14 +1676,4 @@ status_t BufferQueueProducer::setAutoPrerotation(bool autoPrerotation) { return NO_ERROR; } -status_t BufferQueueProducer::setFrameRate(float frameRate) { - ATRACE_CALL(); - BQ_LOGV("setFrameRate: %.0f", frameRate); - - std::lock_guard lock(mCore->mMutex); - - mCore->mFrameRate = frameRate; - return NO_ERROR; -} - } // namespace android diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 515f45c546..9f91d9d3aa 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -363,24 +363,6 @@ status_t ConsumerBase::discardFreeBuffers() { return OK; } -status_t ConsumerBase::setFrameRate(float frameRate) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - CB_LOGE("setFrameRate: ConsumerBase is abandoned!"); - return NO_INIT; - } - return mConsumer->setFrameRate(frameRate); -} - -status_t ConsumerBase::getFrameRate(float* frameRate) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - CB_LOGE("getFrameRate: ConsumerBase is abandoned!"); - return NO_INIT; - } - return mConsumer->getFrameRate(frameRate); -} - void ConsumerBase::dumpState(String8& result) const { dumpState(result, ""); } diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index 2521a7cbd7..c705d3926d 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -51,8 +51,6 @@ enum class Tag : uint32_t { GET_SIDEBAND_STREAM, GET_OCCUPANCY_HISTORY, DISCARD_FREE_BUFFERS, - SET_FRAME_RATE, - GET_FRAME_RATE, DUMP_STATE, LAST = DUMP_STATE, }; @@ -165,16 +163,6 @@ public: Tag::DISCARD_FREE_BUFFERS); } - status_t setFrameRate(float frameRate) override { - using Signature = decltype(&IGraphicBufferConsumer::setFrameRate); - return callRemote(Tag::SET_FRAME_RATE, frameRate); - } - - status_t getFrameRate(float* frameRate) const override { - using Signature = decltype(&IGraphicBufferConsumer::getFrameRate); - return callRemote(Tag::GET_FRAME_RATE, frameRate); - } - status_t dumpState(const String8& prefix, String8* outResult) const override { using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const; return callRemote(Tag::DUMP_STATE, prefix, outResult); @@ -232,10 +220,6 @@ status_t BnGraphicBufferConsumer::onTransact(uint32_t code, const Parcel& data, return callLocal(data, reply, &IGraphicBufferConsumer::getOccupancyHistory); case Tag::DISCARD_FREE_BUFFERS: return callLocal(data, reply, &IGraphicBufferConsumer::discardFreeBuffers); - case Tag::SET_FRAME_RATE: - return callLocal(data, reply, &IGraphicBufferConsumer::setFrameRate); - case Tag::GET_FRAME_RATE: - return callLocal(data, reply, &IGraphicBufferConsumer::getFrameRate); case Tag::DUMP_STATE: { using Signature = status_t (IGraphicBufferConsumer::*)(const String8&, String8*) const; return callLocal(data, reply, &IGraphicBufferConsumer::dumpState); diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 7b5596e43c..ad00939976 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -74,7 +74,6 @@ enum { GET_CONSUMER_USAGE, SET_LEGACY_BUFFER_DROP, SET_AUTO_PREROTATION, - SET_FRAME_RATE, }; class BpGraphicBufferProducer : public BpInterface @@ -560,14 +559,6 @@ public: } return result; } - - virtual status_t setFrameRate(float frameRate) { - Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); - data.writeFloat(frameRate); - status_t result = remote()->transact(SET_FRAME_RATE, data, &reply, IBinder::FLAG_ONEWAY); - return result; - } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -700,8 +691,6 @@ public: status_t setAutoPrerotation(bool autoPrerotation) override { return mBase->setAutoPrerotation(autoPrerotation); } - - status_t setFrameRate(float frameRate) override { return mBase->setFrameRate(frameRate); } }; IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, @@ -721,12 +710,6 @@ status_t IGraphicBufferProducer::setAutoPrerotation(bool autoPrerotation) { return INVALID_OPERATION; } -status_t IGraphicBufferProducer::setFrameRate(float frameRate) { - // No-op for IGBP other than BufferQueue. - (void)frameRate; - return INVALID_OPERATION; -} - status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) { status_t res = OK; res = parcel->writeUint32(USE_BUFFER_QUEUE); @@ -1096,13 +1079,6 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(result); return NO_ERROR; } - case SET_FRAME_RATE: { - CHECK_INTERFACE(IGraphicBuffer, data, reply); - float frameRate = data.readFloat(); - status_t result = setFrameRate(frameRate); - reply->writeInt32(result); - return NO_ERROR; - } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/include/gui/BufferHubConsumer.h b/libs/gui/include/gui/BufferHubConsumer.h index d75620342e..d38077014b 100644 --- a/libs/gui/include/gui/BufferHubConsumer.h +++ b/libs/gui/include/gui/BufferHubConsumer.h @@ -93,12 +93,6 @@ public: // See |IGraphicBufferConsumer::discardFreeBuffers| status_t discardFreeBuffers() override; - // See |IGraphicBufferConsumer::setFrameRate| - status_t setFrameRate(float frameRate) override; - - // See |IGraphicBufferConsumer::getFrameRate| - status_t getFrameRate(float* frameRate) const override; - // See |IGraphicBufferConsumer::dumpState| status_t dumpState(const String8& prefix, String8* outResult) const override; diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h index e9f04490d8..7db69eca9d 100644 --- a/libs/gui/include/gui/BufferQueueConsumer.h +++ b/libs/gui/include/gui/BufferQueueConsumer.h @@ -149,12 +149,6 @@ public: // See IGraphicBufferConsumer::discardFreeBuffers virtual status_t discardFreeBuffers() override; - // See IGraphicBufferConsumer::setFrameRate. - virtual status_t setFrameRate(float frameRate) override; - - // See IGraphicBufferConsumer::getFrameRate. - virtual status_t getFrameRate(float* frameRate) const override; - // dump our state in a String status_t dumpState(const String8& prefix, String8* outResult) const override; diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 05c20742f9..557c28b1b7 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -354,9 +354,6 @@ private: // mTransformHintInUse is to cache the mTransformHint used by the producer. uint32_t mTransformHintInUse; - // The frame rate the app intends to run at. - float mFrameRate; - }; // class BufferQueueCore } // namespace android diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index cbace5bb8b..a7f7d1defa 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -198,9 +198,6 @@ public: // See IGraphicBufferProducer::setAutoPrerotation virtual status_t setAutoPrerotation(bool autoPrerotation); - // See IGraphicBufferProducer::setFrameRate - virtual status_t setFrameRate(float frameRate) override; - private: // This is required by the IBinder::DeathRecipient interface virtual void binderDied(const wp& who); diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h index cfed9aa6bd..8ff0cd0f6e 100644 --- a/libs/gui/include/gui/ConsumerBase.h +++ b/libs/gui/include/gui/ConsumerBase.h @@ -111,12 +111,6 @@ public: // See IGraphicBufferConsumer::discardFreeBuffers status_t discardFreeBuffers(); - // See IGraphicBufferConsumer::setFrameRate - status_t setFrameRate(float frameRate); - - // See IGraphicBufferConsumer::getFrameRate - status_t getFrameRate(float* frameRate); - private: ConsumerBase(const ConsumerBase&); void operator=(const ConsumerBase&); diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h index 56fe949c9c..0b92e7df62 100644 --- a/libs/gui/include/gui/IGraphicBufferConsumer.h +++ b/libs/gui/include/gui/IGraphicBufferConsumer.h @@ -275,16 +275,6 @@ public: // call to free up any of its locally cached buffers. virtual status_t discardFreeBuffers() = 0; - // Set the frame rate the producer will run at. - // - // Return of a value other than NO_ERROR means an unknown error has occurred. - virtual status_t setFrameRate(float frameRate) = 0; - - // Get the frame rate the producer will run at. - // - // Return of a value other than NO_ERROR means an unknown error has occurred. - virtual status_t getFrameRate(float* frameRate) const = 0; - // dump state into a string virtual status_t dumpState(const String8& prefix, String8* outResult) const = 0; diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 87989da19b..d7f34920c4 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -639,9 +639,6 @@ public: // the width and height used for dequeueBuffer will be additionally swapped. virtual status_t setAutoPrerotation(bool autoPrerotation); - // Sets the apps intended frame rate. - virtual status_t setFrameRate(float frameRate); - #ifndef NO_BINDER // Static method exports any IGraphicBufferProducer object to a parcel. It // handles null producer as well. diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index ad7cbfe914..917c0d4831 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -178,7 +178,6 @@ public: status_t getUniqueId(uint64_t* outId) const; status_t getConsumerUsage(uint64_t* outUsage) const; - // See IGraphicBufferProducer::setFrameRate status_t setFrameRate(float frameRate, int8_t compatibility); protected: diff --git a/libs/gui/include/gui/mock/GraphicBufferConsumer.h b/libs/gui/include/gui/mock/GraphicBufferConsumer.h index e940cf3248..98f24c2d44 100644 --- a/libs/gui/include/gui/mock/GraphicBufferConsumer.h +++ b/libs/gui/include/gui/mock/GraphicBufferConsumer.h @@ -49,8 +49,6 @@ public: MOCK_CONST_METHOD1(getSidebandStream, status_t(sp*)); MOCK_METHOD2(getOccupancyHistory, status_t(bool, std::vector*)); MOCK_METHOD0(discardFreeBuffers, status_t()); - MOCK_METHOD1(setFrameRate, status_t(float)); - MOCK_CONST_METHOD1(getFrameRate, status_t(float*)); MOCK_CONST_METHOD2(dumpState, status_t(const String8&, String8*)); }; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index f5a99cadd7..18f7f44fa5 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -564,8 +564,6 @@ void BufferQueueLayer::gatherBufferInfo() { mBufferInfo.mApi = mConsumer->getCurrentApi(); mBufferInfo.mPixelFormat = mFormat; mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse(); - float latchedFrameRate; - mConsumer->getFrameRate(&latchedFrameRate); } sp BufferQueueLayer::createClone() { diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index 40a63d77b5..5009e10532 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -162,10 +162,6 @@ status_t MonitoredProducer::setAutoPrerotation(bool autoPrerotation) { return mProducer->setAutoPrerotation(autoPrerotation); } -status_t MonitoredProducer::setFrameRate(float frameRate) { - return mProducer->setFrameRate(frameRate); -} - IBinder* MonitoredProducer::onAsBinder() { return this; } diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index 4bda831aeb..788919b3da 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -71,7 +71,6 @@ public: virtual status_t getUniqueId(uint64_t* outId) const override; virtual status_t getConsumerUsage(uint64_t* outUsage) const override; virtual status_t setAutoPrerotation(bool autoPrerotation) override; - virtual status_t setFrameRate(float frameRate) override; // The Layer which created this producer, and on which queued Buffer's will be displayed. sp getLayer() const; -- GitLab From 47040bfbf505ca6865f05b568d428f796856ad29 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 28 Feb 2020 15:03:13 -0800 Subject: [PATCH 0874/1255] Test MotionEvents for InputDispatcher::verifyInputEvent We recently added a new api, InputDispatcher::verifyInputEvent. There are currently tests for this api for key events. However, a motion event test is currently missing. Add the missing test here. Bug: 149845127 Test: atest inputflinger_tests Change-Id: I791a789a9df4d62d4100b61611b52a98c77c4787 --- .../tests/InputDispatcher_test.cpp | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index d30c4f1635..1f283b18ac 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1445,7 +1445,6 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { ASSERT_EQ(keyArgs.action, verifiedKey.action); ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos); - ASSERT_EQ(keyArgs.eventTime, verifiedKey.eventTimeNanos); ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags); ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode); ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode); @@ -1453,6 +1452,43 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { ASSERT_EQ(0, verifiedKey.repeatCount); } +TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { + sp application = new FakeApplicationHandle(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); + + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + + mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + + NotifyMotionArgs motionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT); + mDispatcher->notifyMotion(&motionArgs); + + InputEvent* event = window->consume(); + ASSERT_NE(event, nullptr); + + std::unique_ptr verified = mDispatcher->verifyInputEvent(*event); + ASSERT_NE(verified, nullptr); + ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION); + + EXPECT_EQ(motionArgs.eventTime, verified->eventTimeNanos); + EXPECT_EQ(motionArgs.deviceId, verified->deviceId); + EXPECT_EQ(motionArgs.source, verified->source); + EXPECT_EQ(motionArgs.displayId, verified->displayId); + + const VerifiedMotionEvent& verifiedMotion = static_cast(*verified); + + EXPECT_EQ(motionArgs.pointerCoords[0].getX(), verifiedMotion.rawX); + EXPECT_EQ(motionArgs.pointerCoords[0].getY(), verifiedMotion.rawY); + EXPECT_EQ(motionArgs.action & AMOTION_EVENT_ACTION_MASK, verifiedMotion.actionMasked); + EXPECT_EQ(motionArgs.downTime, verifiedMotion.downTimeNanos); + EXPECT_EQ(motionArgs.flags & VERIFIED_MOTION_EVENT_FLAGS, verifiedMotion.flags); + EXPECT_EQ(motionArgs.metaState, verifiedMotion.metaState); + EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState); +} + class InputDispatcherKeyRepeatTest : public InputDispatcherTest { protected: static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms -- GitLab From a125784e31c6be4441c5f17bed40510a85bd4540 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Fri, 31 Jan 2020 13:48:28 -0800 Subject: [PATCH 0875/1255] SurfaceFlinger: Cache updateInputWindows call This is a conservative but safe cache. We invalidate it if any layer with InputInfo, or any layer whose children/relative-children have input info updates their drawing state. Not all these drawing state updates will result in Input changes, but we can be confident that without some drawing state change there wont be any Input changes, and thus it seems the cache is safe. This will solve the case of moving layers that don't have any InputInfo assosciated generating setInputWindows calls. Bug: 148675756 Test: Existing tests pass. go/wm-smoke Change-Id: Ie5979b25370c2d5c3d8a55f187fc6fda1cc75b27 --- services/surfaceflinger/BufferLayer.cpp | 4 +++ services/surfaceflinger/Layer.cpp | 29 ++++++++++++++++++++++ services/surfaceflinger/Layer.h | 4 +++ services/surfaceflinger/SurfaceFlinger.cpp | 15 +++++++++++ services/surfaceflinger/SurfaceFlinger.h | 5 ++++ 5 files changed, 57 insertions(+) diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index d7ec86863f..e4d754c712 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -485,6 +485,10 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, } } + if (recomputeVisibleRegions == true) { + maybeDirtyInput(); + } + return true; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 64cfb3d699..3765d0d39d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -993,6 +993,9 @@ uint32_t Layer::doTransaction(uint32_t flags) { commitTransaction(c); mPendingStatesSnapshot = mPendingStates; mCurrentState.callbackHandles = {}; + + maybeDirtyInput(); + return flags; } @@ -2472,6 +2475,32 @@ Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t comp } } +bool Layer::maybeDirtyInput() { + // No sense redirtying input. + if (mFlinger->inputDirty()) return true; + + if (hasInput()) { + mFlinger->dirtyInput(); + return true; + } + + // If a child or relative dirties the input, no sense continuing to traverse + // so we return early and halt the recursion. We traverse ourselves instead + // of using traverse() so we can implement this early halt. + for (const sp& child : mDrawingChildren) { + if (child->maybeDirtyInput()) { + return true; + } + } + for (const wp& weakRelative : mDrawingState.zOrderRelatives) { + sp relative = weakRelative.promote(); + if (relative && relative->maybeDirtyInput()) { + return true; + } + } + return false; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 20d72324c3..e21a866616 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -997,6 +997,10 @@ protected: // Window types from WindowManager.LayoutParams const int mWindowType; + // Called when mDrawingState has changed. If we or one of our children/relatives hasInput() + // then we will dirty the setInputWindows cache. + bool maybeDirtyInput(); + private: /** * Returns an unsorted vector of all layers that are part of this tree. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c995db4972..6f49c7a0ce 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2769,6 +2769,19 @@ void SurfaceFlinger::updateInputFlinger() { void SurfaceFlinger::updateInputWindowInfo() { std::vector inputHandles; + // We use a simple caching algorithm here. mInputDirty begins as true, + // after we call setInputWindows we set it to false, so + // in the future we wont call it again.. We set input dirty to true again + // when any layer that hasInput() has a transaction performed on it + // or when any parent or relative parent of such a layer has a transaction + // performed on it. Not all of these transactions will really result in + // input changes but all input changes will spring from these transactions + // so the cache is safe but not optimal. It seems like it might be annoyingly + // costly to cache and comapre the actual InputWindowHandle vector though. + if (!mInputDirty) { + return; + } + mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (layer->hasInput()) { // When calculating the screen bounds we ignore the transparent region since it may @@ -2780,6 +2793,8 @@ void SurfaceFlinger::updateInputWindowInfo() { mInputFlinger->setInputWindows(inputHandles, mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener : nullptr); + + mInputDirty = false; } void SurfaceFlinger::commitInputWindowCommands() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 83f01319d3..e162da60c6 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1236,6 +1236,11 @@ private: // janky frames there are. nsecs_t mMissedFrameJankStart = 0; int32_t mMissedFrameJankCount = 0; + + // See updateInputWindowInfo() for details + std::atomic mInputDirty = true; + void dirtyInput() { mInputDirty = true; } + bool inputDirty() { return mInputDirty; } }; } // namespace android -- GitLab From 59db0a38cc14c27aa44840741338db6e1838e685 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 2 Mar 2020 18:04:20 -0800 Subject: [PATCH 0876/1255] SurfaceFlinger: fix setDesiredActiveConfig setDesiredActiveConfig is trying to initiate a config change even if the desired config is alreadt the active config. This creates an issue where mVSyncModulator->onRefreshRateChangeInitiated() is called but the counter part mVSyncModulator->onRefreshRateChangeCompleted() is never called since the refresh rate never changed. Test: collected systrace on taimen Bug: 150647346 Change-Id: I2659183bf2a4e1676627d84379f4d533bdb9b5fc --- services/surfaceflinger/SurfaceFlinger.cpp | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c995db4972..27bd53cc29 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -906,15 +906,24 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { auto refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId); ALOGV("setDesiredActiveConfig(%s)", refreshRate.name.c_str()); - // Don't check against the current mode yet. Worst case we set the desired - // config twice. However event generation config might have changed so we need to update it - // accordingly std::lock_guard lock(mActiveConfigLock); - const Scheduler::ConfigEvent prevConfig = mDesiredActiveConfig.event; - mDesiredActiveConfig = info; - mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig; + if (mDesiredActiveConfigChanged) { + // If a config change is pending, just cache the latest request in + // mDesiredActiveConfig + const Scheduler::ConfigEvent prevConfig = mDesiredActiveConfig.event; + mDesiredActiveConfig = info; + mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig; + } else { + // Check is we are already at the desired config + const auto display = getDefaultDisplayDeviceLocked(); + if (!display || display->getActiveConfig() == refreshRate.configId) { + return; + } + + // Initiate a config change. + mDesiredActiveConfigChanged = true; + mDesiredActiveConfig = info; - if (!mDesiredActiveConfigChanged) { // This will trigger HWC refresh without resetting the idle timer. repaintEverythingForHWC(); // Start receiving vsync samples now, so that we can detect a period @@ -927,7 +936,6 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { mPhaseConfiguration->setRefreshRateFps(refreshRate.fps); mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets()); } - mDesiredActiveConfigChanged = true; if (mRefreshRateOverlay) { mRefreshRateOverlay->changeRefreshRate(refreshRate); -- GitLab From e93e6c9feb4c09295a7e3ee5e4121a1ac6e2f6bb Mon Sep 17 00:00:00 2001 From: Kris Chen Date: Tue, 3 Mar 2020 17:50:11 +0800 Subject: [PATCH 0877/1255] dumpstate: add fingerprint HAL dump Bug: 150008549 Test: adb bugreport Change-Id: I9b256c72a2a0906486560e7cf361403c98b2c0b0 --- libs/dumputils/dump_utils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp index 1b42b6927f..5b65c95e95 100644 --- a/libs/dumputils/dump_utils.cpp +++ b/libs/dumputils/dump_utils.cpp @@ -57,6 +57,7 @@ static const char* hal_interfaces_to_dump[] { "android.hardware.audio@5.0::IDevicesFactory", "android.hardware.audio@6.0::IDevicesFactory", "android.hardware.biometrics.face@1.0::IBiometricsFace", + "android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint", "android.hardware.bluetooth@1.0::IBluetoothHci", "android.hardware.camera.provider@2.4::ICameraProvider", "android.hardware.drm@1.0::IDrmFactory", -- GitLab From 1733796cecd0bd363e50b29bd690ac4b3a0f0c44 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Mon, 2 Mar 2020 15:51:15 -0800 Subject: [PATCH 0878/1255] SF: Confine display serial number to EDID parser The EDID parser falls back to the serial number if the display name is missing. Previously, this string was only used to compute a hash for display ID encoding, but is now propagated through DeviceProductInfo. Though DeviceProductInfo is currently a hidden API, stop exposing the serial number in the first place to avoid inadvertently leaking it. Bug: 138677816 Test: libsurfaceflinger_unittest Change-Id: I13f4e7f4d0e9e90866b74ac33a048e8809158a43 --- .../DisplayHardware/DisplayIdentification.cpp | 30 +++++++++++-------- .../DisplayHardware/DisplayIdentification.h | 3 +- .../unittests/DisplayIdentificationTest.cpp | 23 +++++++++++--- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp index 9aaef6501d..f24f3142f1 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp @@ -104,9 +104,8 @@ uint16_t DisplayId::manufacturerId() const { return static_cast(value >> 40); } -DisplayId DisplayId::fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash) { - return {(static_cast(manufacturerId) << 40) | (static_cast(displayNameHash) << 8) | - port}; +DisplayId DisplayId::fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t modelHash) { + return {(static_cast(manufacturerId) << 40) | (static_cast(modelHash) << 8) | port}; } bool isEdid(const DisplayIdentificationData& data) { @@ -209,23 +208,30 @@ std::optional parseEdid(const DisplayIdentificationData& edid) { view.remove_prefix(kDescriptorLength); } - if (displayName.empty()) { + std::string_view modelString = displayName; + + if (modelString.empty()) { ALOGW("Invalid EDID: falling back to serial number due to missing display name."); - displayName = serialNumber; + modelString = serialNumber; } - if (displayName.empty()) { + if (modelString.empty()) { ALOGW("Invalid EDID: falling back to ASCII text due to missing serial number."); - displayName = asciiText; + modelString = asciiText; } - if (displayName.empty()) { + if (modelString.empty()) { ALOGE("Invalid EDID: display name and fallback descriptors are missing."); return {}; } + // Hash model string instead of using product code or (integer) serial number, since the latter + // have been observed to change on some displays with multiple inputs. + const auto modelHash = static_cast(std::hash()(modelString)); + return Edid{.manufacturerId = manufacturerId, + .productId = productId, .pnpId = *pnpId, + .modelHash = modelHash, .displayName = displayName, - .productId = productId, .manufactureWeek = manufactureWeek, .manufactureOrModelYear = manufactureOrModelYear}; } @@ -253,10 +259,8 @@ std::optional parseDisplayIdentificationData( return {}; } - // Hash display name instead of using product code or serial number, since the latter have been - // observed to change on some displays with multiple inputs. - const auto hash = static_cast(std::hash()(edid->displayName)); - return DisplayIdentificationInfo{.id = DisplayId::fromEdid(port, edid->manufacturerId, hash), + const auto displayId = DisplayId::fromEdid(port, edid->manufacturerId, edid->modelHash); + return DisplayIdentificationInfo{.id = displayId, .name = std::string(edid->displayName), .deviceProductInfo = buildDeviceProductInfo(*edid)}; } diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h index 0a18ba15b7..d91b95773b 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h +++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h @@ -34,7 +34,7 @@ struct DisplayId { uint16_t manufacturerId() const; - static DisplayId fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash); + static DisplayId fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t modelHash); }; inline bool operator==(DisplayId lhs, DisplayId rhs) { @@ -61,6 +61,7 @@ struct Edid { uint16_t manufacturerId; uint16_t productId; PnpId pnpId; + uint32_t modelHash; std::string_view displayName; uint8_t manufactureOrModelYear; uint8_t manufactureWeek; diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp index a023367752..c2ddfcee45 100644 --- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +#include +#include + #include #include @@ -124,6 +127,10 @@ DisplayIdentificationData asDisplayIdentificationData(const unsigned char (&byte return DisplayIdentificationData(bytes, bytes + N - 1); } +uint32_t hash(const char* str) { + return static_cast(std::hash()(str)); +} + } // namespace const DisplayIdentificationData& getInternalEdid() { @@ -173,7 +180,8 @@ TEST(DisplayIdentificationTest, parseEdid) { EXPECT_EQ(0x4ca3u, edid->manufacturerId); EXPECT_STREQ("SEC", edid->pnpId.data()); // ASCII text should be used as fallback if display name and serial number are missing. - EXPECT_EQ("121AT11-801", edid->displayName); + EXPECT_EQ(hash("121AT11-801"), edid->modelHash); + EXPECT_TRUE(edid->displayName.empty()); EXPECT_EQ(12610, edid->productId); EXPECT_EQ(21, edid->manufactureOrModelYear); EXPECT_EQ(0, edid->manufactureWeek); @@ -182,6 +190,7 @@ TEST(DisplayIdentificationTest, parseEdid) { ASSERT_TRUE(edid); EXPECT_EQ(0x22f0u, edid->manufacturerId); EXPECT_STREQ("HWP", edid->pnpId.data()); + EXPECT_EQ(hash("HP ZR30w"), edid->modelHash); EXPECT_EQ("HP ZR30w", edid->displayName); EXPECT_EQ(10348, edid->productId); EXPECT_EQ(22, edid->manufactureOrModelYear); @@ -191,6 +200,7 @@ TEST(DisplayIdentificationTest, parseEdid) { ASSERT_TRUE(edid); EXPECT_EQ(0x4c2du, edid->manufacturerId); EXPECT_STREQ("SAM", edid->pnpId.data()); + EXPECT_EQ(hash("SAMSUNG"), edid->modelHash); EXPECT_EQ("SAMSUNG", edid->displayName); EXPECT_EQ(2302, edid->productId); EXPECT_EQ(21, edid->manufactureOrModelYear); @@ -200,6 +210,7 @@ TEST(DisplayIdentificationTest, parseEdid) { ASSERT_TRUE(edid); EXPECT_EQ(13481, edid->manufacturerId); EXPECT_STREQ("MEI", edid->pnpId.data()); + EXPECT_EQ(hash("Panasonic-TV"), edid->modelHash); EXPECT_EQ("Panasonic-TV", edid->displayName); EXPECT_EQ(41622, edid->productId); EXPECT_EQ(29, edid->manufactureOrModelYear); @@ -209,6 +220,7 @@ TEST(DisplayIdentificationTest, parseEdid) { ASSERT_TRUE(edid); EXPECT_EQ(8355, edid->manufacturerId); EXPECT_STREQ("HEC", edid->pnpId.data()); + EXPECT_EQ(hash("Hisense"), edid->modelHash); EXPECT_EQ("Hisense", edid->displayName); EXPECT_EQ(0, edid->productId); EXPECT_EQ(29, edid->manufactureOrModelYear); @@ -218,6 +230,7 @@ TEST(DisplayIdentificationTest, parseEdid) { ASSERT_TRUE(edid); EXPECT_EQ(3724, edid->manufacturerId); EXPECT_STREQ("CTL", edid->pnpId.data()); + EXPECT_EQ(hash("LP2361"), edid->modelHash); EXPECT_EQ("LP2361", edid->displayName); EXPECT_EQ(9373, edid->productId); EXPECT_EQ(23, edid->manufactureOrModelYear); @@ -234,13 +247,15 @@ TEST(DisplayIdentificationTest, parseInvalidEdid) { auto edid = parseEdid(data); ASSERT_TRUE(edid); // Serial number should be used as fallback if display name is invalid. - EXPECT_EQ("CN4202137Q", edid->displayName); + const auto modelHash = hash("CN4202137Q"); + EXPECT_EQ(modelHash, edid->modelHash); + EXPECT_TRUE(edid->displayName.empty()); // Parsing should succeed even if EDID is truncated. data.pop_back(); edid = parseEdid(data); ASSERT_TRUE(edid); - EXPECT_EQ("CN4202137Q", edid->displayName); + EXPECT_EQ(modelHash, edid->modelHash); } TEST(DisplayIdentificationTest, getPnpId) { @@ -278,7 +293,7 @@ TEST(DisplayIdentificationTest, deviceProductInfo) { ASSERT_TRUE(displayIdInfo); ASSERT_TRUE(displayIdInfo->deviceProductInfo); const auto& info = *displayIdInfo->deviceProductInfo; - EXPECT_STREQ("121AT11-801", info.name.data()); + EXPECT_STREQ("", info.name.data()); EXPECT_STREQ("SEC", info.manufacturerPnpId.data()); EXPECT_STREQ("12610", info.productId.data()); ASSERT_TRUE(std::holds_alternative(info.manufactureOrModelDate)); -- GitLab From 5e95aa26c5c8ee4c7277d1e2f026c8189388c804 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 4 Mar 2020 10:26:05 -0800 Subject: [PATCH 0879/1255] SurfaceFlinger: do not assert if setActiveConfigWithConstraints fails setActiveConfigWithConstraints may fail if a hotplug event is just about to be sent. Replace the assert with an ALOGW. Fixes: 150768854 Test: boot Change-Id: Idfbfd383cd8942953a996fdda9a82d285c9d1c4f --- services/surfaceflinger/SurfaceFlinger.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 27bd53cc29..597e4d3ef2 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1074,7 +1074,9 @@ bool SurfaceFlinger::performSetActiveConfig() { mUpcomingActiveConfig.configId.value(), constraints, &outTimeline); if (status != NO_ERROR) { - LOG_ALWAYS_FATAL("setActiveConfigWithConstraints failed: %d", status); + // setActiveConfigWithConstraints may fail if a hotplug event is just about + // to be sent. We just log the error in this case. + ALOGW("setActiveConfigWithConstraints failed: %d", status); return false; } -- GitLab From 0a52509e8cdc6da93daab9c34fdbb63232fa8adf Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 3 Mar 2020 12:51:24 -0800 Subject: [PATCH 0880/1255] ISurfaceComposer: boundary check input on CAPTURE_LAYERS Add a sanity check on numExcludeHandles to make sure we don't cause an overflow. Test: adb shell /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test Fixes: 146435753 Change-Id: I2c700392727e2f4e0e434fb4c1800f2973c7418b Merged-In: I2c700392727e2f4e0e434fb4c1800f2973c7418b --- libs/gui/ISurfaceComposer.cpp | 3 +++ libs/gui/include/gui/ISurfaceComposer.h | 2 ++ services/surfaceflinger/SurfaceFlinger.cpp | 6 +++--- services/surfaceflinger/SurfaceFlinger.h | 3 +-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index ce41eaba1d..04c21a9e1d 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1281,6 +1281,9 @@ status_t BnSurfaceComposer::onTransact( std::unordered_set, SpHash> excludeHandles; int numExcludeHandles = data.readInt32(); + if (numExcludeHandles >= static_cast(MAX_LAYERS)) { + return BAD_VALUE; + } excludeHandles.reserve(numExcludeHandles); for (int i = 0; i < numExcludeHandles; i++) { excludeHandles.emplace(data.readStrongBinder()); diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 0659f0de06..09487eab8b 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -76,6 +76,8 @@ class ISurfaceComposer: public IInterface { public: DECLARE_META_INTERFACE(SurfaceComposer) + static constexpr size_t MAX_LAYERS = 4096; + // flags for setTransactionState() enum { eSynchronous = 0x01, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 27bd53cc29..385a093ae8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -367,7 +367,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("ro.sf.blurs_are_expensive", value, "0"); mBlursAreExpensive = atoi(value); - const size_t defaultListSize = MAX_LAYERS; + const size_t defaultListSize = ISurfaceComposer::MAX_LAYERS; auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize)); mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize; @@ -3066,9 +3066,9 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, const sp= MAX_LAYERS) { + if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) { ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(), - MAX_LAYERS); + ISurfaceComposer::MAX_LAYERS); return NO_MEMORY; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 83f01319d3..e7f9930392 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -351,7 +351,6 @@ private: // every half hour. enum { LOG_FRAME_STATS_PERIOD = 30*60*60 }; - static const size_t MAX_LAYERS = 4096; static const int MAX_TRACING_MEMORY = 100 * 1024 * 1024; // 100MB protected: @@ -976,7 +975,7 @@ private: // Can't be unordered_set because wp<> isn't hashable std::set> mGraphicBufferProducerList; - size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS; + size_t mMaxGraphicBufferProducerListSize = ISurfaceComposer::MAX_LAYERS; // protected by mStateLock (but we could use another lock) bool mLayersRemoved = false; -- GitLab From 134266b6136e6bd20bc9991b8402470011315321 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 3 Mar 2020 19:22:29 -0800 Subject: [PATCH 0881/1255] [AChoreographer] Resolves a deadlock This deadlock could occur when posting a delayed frame callback while a pending refresh rate callback had not yet been processed by the looper thread. Resolve the deadlock by releasing the lock in Choreographer::scheduleCallbacks once the earliest dueTime is retrieved. Bug: 150731776 Test: ChoreographerNativeTest Change-Id: I9e1ace12beb4bbc75af0671ddf1b1653d04c9df4 --- libs/nativedisplay/AChoreographer.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index 0f7e2fb936..0ff33ac747 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -185,9 +185,18 @@ void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCall } void Choreographer::scheduleCallbacks() { - AutoMutex _{mLock}; - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - if (mFrameCallbacks.top().dueTime <= now) { + const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t dueTime; + { + AutoMutex _{mLock}; + // If there are no pending callbacks then don't schedule a vsync + if (mFrameCallbacks.empty()) { + return; + } + dueTime = mFrameCallbacks.top().dueTime; + } + + if (dueTime <= now) { ALOGV("choreographer %p ~ scheduling vsync", this); scheduleVsync(); return; -- GitLab From 1e219c147e9b6ab34058613424a3c86b69b5e6dc Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 27 Feb 2020 16:27:49 -0800 Subject: [PATCH 0882/1255] libbinder: move AppOpManager globals into function Bug: 148177595 Test: N/A Change-Id: Ibf19d8fbe82595f249fddf8c918c1750bc750f66 --- libs/binder/AppOpsManager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index aeca12b582..b2a6f3bbe9 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -43,11 +43,10 @@ const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_IGNORED; } // namespace -static String16 _appops("appops"); -static pthread_mutex_t gClientIdMutex = PTHREAD_MUTEX_INITIALIZER; -static sp gClientId; - static const sp& getClientId() { + static pthread_mutex_t gClientIdMutex = PTHREAD_MUTEX_INITIALIZER; + static sp gClientId; + pthread_mutex_lock(&gClientIdMutex); if (gClientId == nullptr) { gClientId = new BBinder(); @@ -72,6 +71,7 @@ sp AppOpsManager::getService() { return NULL; } #else sp AppOpsManager::getService() { + static String16 _appops("appops"); std::lock_guard scoped_lock(mLock); int64_t startTime = 0; -- GitLab From d83ecb04f9c78e23e8f413167f0b25642efef490 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 4 Mar 2020 18:02:02 -0800 Subject: [PATCH 0883/1255] libbinder: cleanup appOpNote globals Removed unused. Moved used to functions (save memory when unused). Bug: 148177595 Test: th Change-Id: Ifb374759206b411efcc269c2977573213c60ccb4 --- libs/binder/AppOpsManager.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index aeca12b582..0bba6ca19b 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -56,12 +56,6 @@ static const sp& getClientId() { return gClientId; } -thread_local uint64_t notedAppOpsInThisBinderTransaction[2]; -thread_local int32_t uidOfThisBinderTransaction = -1; - -// Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note -uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0}; - AppOpsManager::AppOpsManager() { } @@ -192,6 +186,9 @@ void AppOpsManager::setCameraAudioRestriction(int32_t mode) { // check it the appops needs to be collected and cache result bool AppOpsManager::shouldCollectNotes(int32_t opcode) { + // Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note + static uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0}; + if (appOpsToNote[opcode] == 0) { if (getService()->shouldCollectNotes(opcode)) { appOpsToNote[opcode] = 2; -- GitLab From 15a63a8b8fde09c61b62cb11dd70112019d6c7d0 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 27 Feb 2020 16:31:13 -0800 Subject: [PATCH 0884/1255] libbinder: remove __BRILLO__ carveouts distracting Test: N/A Bug: 148177595 Change-Id: I7fd165fdcff7b04688d5763994460b74a781d24e --- libs/binder/AppOpsManager.cpp | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index b2a6f3bbe9..a22cf25671 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -30,19 +30,6 @@ namespace android { -namespace { - -#if defined(__BRILLO__) -// Because Brillo has no application model, security policy is managed -// statically (at build time) with SELinux controls. -// As a consequence, it also never runs the AppOpsManager service. -const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_ALLOWED; -#else -const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_IGNORED; -#endif // defined(__BRILLO__) - -} // namespace - static const sp& getClientId() { static pthread_mutex_t gClientIdMutex = PTHREAD_MUTEX_INITIALIZER; static sp gClientId; @@ -65,10 +52,6 @@ AppOpsManager::AppOpsManager() { } -#if defined(__BRILLO__) -// There is no AppOpsService on Brillo -sp AppOpsManager::getService() { return NULL; } -#else sp AppOpsManager::getService() { static String16 _appops("appops"); @@ -96,14 +79,13 @@ sp AppOpsManager::getService() } return service; } -#endif // defined(__BRILLO__) int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage) { sp service = getService(); return service != nullptr ? service->checkOperation(op, uid, callingPackage) - : APP_OPS_MANAGER_UNAVAILABLE_MODE; + : AppOpsManager::MODE_IGNORED; } int32_t AppOpsManager::checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid, @@ -111,7 +93,7 @@ int32_t AppOpsManager::checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t ui sp service = getService(); return service != nullptr ? service->checkAudioOperation(op, usage, uid, callingPackage) - : APP_OPS_MANAGER_UNAVAILABLE_MODE; + : AppOpsManager::MODE_IGNORED; } int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) { @@ -125,7 +107,7 @@ int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPa int32_t mode = service != nullptr ? service->noteOperation(op, uid, callingPackage, featureId, shouldCollectNotes(op), message) - : APP_OPS_MANAGER_UNAVAILABLE_MODE; + : AppOpsManager::MODE_IGNORED; return mode; } @@ -143,7 +125,7 @@ int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& c int32_t mode = service != nullptr ? service->startOperation(getClientId(), op, uid, callingPackage, featureId, startIfModeDefault, shouldCollectNotes(op), message) - : APP_OPS_MANAGER_UNAVAILABLE_MODE; + : AppOpsManager::MODE_IGNORED; return mode; } -- GitLab From 9d3bbd4b7eb4ee3cf9f5608deecb5b769e93e57e Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 4 Mar 2020 19:59:05 -0800 Subject: [PATCH 0885/1255] Remove unused texture. Bug: b/150303018 Test: issue can no longer be reproduced Change-Id: I78f24f4f9917a43c0962619961aba3309bbee116 --- libs/renderengine/gl/GLESRenderEngine.cpp | 9 --------- libs/renderengine/gl/GLESRenderEngine.h | 1 - 2 files changed, 10 deletions(-) diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 416ebfefc4..0d4305b868 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -381,15 +381,6 @@ GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisp LOG_ALWAYS_FATAL_IF(!success, "can't make default context current"); } - const uint16_t protTexData[] = {0}; - glGenTextures(1, &mProtectedTexName); - glBindTexture(GL_TEXTURE_2D, mProtectedTexName); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData); - // mColorBlindnessCorrection = M; if (mUseColorManagement) { diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 4cd0b3d3b5..32dbad1050 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -178,7 +178,6 @@ private: EGLSurface mDummySurface; EGLContext mProtectedEGLContext; EGLSurface mProtectedDummySurface; - GLuint mProtectedTexName; GLint mMaxViewportDims[2]; GLint mMaxTextureSize; GLuint mVpWidth; -- GitLab From 6c016640bf208e7d3117c1a2d085df98af87149b Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 26 Feb 2020 13:16:34 -0800 Subject: [PATCH 0886/1255] lshal: avoid FQName globals. These aren't really needed here, and they are costing 20Kib memory/user. Bug: 148177595 Test: boot/lshal Change-Id: Id0d311319c47553fac5d1d208409cef83073fddf (cherry picked from commit 7a99e04990d28fa20f63d820cb709888dafa1576) Merged-In: Id0d311319c47553fac5d1d208409cef83073fddf --- cmds/lshal/ListCommand.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp index f426dbbc4f..fb11cee33e 100644 --- a/cmds/lshal/ListCommand.cpp +++ b/cmds/lshal/ListCommand.cpp @@ -406,7 +406,7 @@ bool ListCommand::addEntryWithInstance(const TableEntry& entry, return false; } - if (fqInstance.getPackage() == gIBaseFqName.package()) { + if (fqInstance.getPackage() == "android.hidl.base") { return true; // always remove IBase from manifest } -- GitLab From a562a490ce15c4cff8b5c8ff6f0bc998b471aa43 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 26 Feb 2020 16:02:08 -0800 Subject: [PATCH 0887/1255] libbinder: avoid attached objects for stability Attached objects require a heap allocation, and stability is always attached. This avoids a heap allocation per binder object (Android R regression). Bug: 148177595 Test: binderStabilityTest Change-Id: I5eab8be5d87fdd9468bcbd8d54913ca713559314 (cherry picked from commit a7fb018627317740d3cb1d80727899146e611804) Merged-In: I5eab8be5d87fdd9468bcbd8d54913ca713559314 --- libs/binder/Binder.cpp | 2 +- libs/binder/BpBinder.cpp | 1 + libs/binder/Stability.cpp | 22 +++++++++++++++------- libs/binder/include/binder/Binder.h | 11 ++++++++++- libs/binder/include/binder/BpBinder.h | 7 +++++++ 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index 2f6e9c3a1b..e0fb54384e 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -141,7 +141,7 @@ public: // --------------------------------------------------------------------------- -BBinder::BBinder() : mExtras(nullptr) +BBinder::BBinder() : mExtras(nullptr), mStability(0) { } diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index f16c39cdc1..d2b9b8f018 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -138,6 +138,7 @@ BpBinder* BpBinder::create(int32_t handle) { BpBinder::BpBinder(int32_t handle, int32_t trackedUid) : mHandle(handle) + , mStability(0) , mAlive(1) , mObitsSent(0) , mObituaries(nullptr) diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp index 7ce5e36292..e1565fac43 100644 --- a/libs/binder/Stability.cpp +++ b/libs/binder/Stability.cpp @@ -15,6 +15,9 @@ */ #include +#include +#include + namespace android { namespace internal { @@ -78,11 +81,12 @@ status_t Stability::set(IBinder* binder, int32_t stability, bool log) { if (currentStability == stability) return OK; - binder->attachObject( - reinterpret_cast(&Stability::get), - reinterpret_cast(stability), - nullptr /*cleanupCookie*/, - nullptr /*cleanup function*/); + BBinder* local = binder->localBinder(); + if (local != nullptr) { + local->mStability = static_cast(stability); + } else { + binder->remoteBinder()->mStability = static_cast(stability); + } return OK; } @@ -90,8 +94,12 @@ status_t Stability::set(IBinder* binder, int32_t stability, bool log) { Stability::Level Stability::get(IBinder* binder) { if (binder == nullptr) return UNDECLARED; - return static_cast(reinterpret_cast( - binder->findObject(reinterpret_cast(&Stability::get)))); + BBinder* local = binder->localBinder(); + if (local != nullptr) { + return static_cast(local->mStability); + } + + return static_cast(binder->remoteBinder()->mStability); } bool Stability::check(int32_t provided, Level required) { diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h index 3be61f9409..74e52db53f 100644 --- a/libs/binder/include/binder/Binder.h +++ b/libs/binder/include/binder/Binder.h @@ -24,6 +24,10 @@ // --------------------------------------------------------------------------- namespace android { +namespace internal { +class Stability; +} + class BBinder : public IBinder { public: @@ -88,7 +92,12 @@ private: Extras* getOrCreateExtras(); std::atomic mExtras; - void* mReserved0; + + friend ::android::internal::Stability; + union { + int32_t mStability; + void* mReserved0; + }; }; // --------------------------------------------------------------------------- diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 7dca733b52..8e871b8214 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -27,6 +27,10 @@ // --------------------------------------------------------------------------- namespace android { +namespace internal { +class Stability; +}; + using binder_proxy_limit_callback = void(*)(int); class BpBinder : public IBinder @@ -116,6 +120,9 @@ protected: private: const int32_t mHandle; + friend ::android::internal::Stability; + int32_t mStability; + struct Obituary { wp recipient; void* cookie; -- GitLab From 2e1dd89a34ed859d6105bc4f680f1b0738e2aa0a Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 5 Mar 2020 13:48:36 -0800 Subject: [PATCH 0888/1255] SurfaceFlinger: delete RefreshRate copy constructor Avoid copying RefreshRate objects Change-Id: Ic00f14bd03465d163e82ee7f4bf34346f1920ad6 Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Bug: 150887328 --- .../surfaceflinger/RefreshRateOverlay.cpp | 8 ++--- .../surfaceflinger/Scheduler/PhaseOffsets.cpp | 8 ++--- .../Scheduler/RefreshRateConfigs.cpp | 29 ++++++++-------- .../Scheduler/RefreshRateConfigs.h | 7 ++-- .../surfaceflinger/Scheduler/Scheduler.cpp | 4 +-- services/surfaceflinger/SurfaceFlinger.cpp | 14 ++++---- .../unittests/RefreshRateConfigsTest.cpp | 34 +++++++++---------- 7 files changed, 53 insertions(+), 51 deletions(-) diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 682679c703..c675971156 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -168,9 +168,9 @@ bool RefreshRateOverlay::createLayer() { } void RefreshRateOverlay::primeCache() { - auto allRefreshRates = mFlinger.mRefreshRateConfigs->getAllRefreshRates(); + auto& allRefreshRates = mFlinger.mRefreshRateConfigs->getAllRefreshRates(); if (allRefreshRates.size() == 1) { - auto fps = allRefreshRates.begin()->second.fps; + auto fps = allRefreshRates.begin()->second->fps; half4 color = {LOW_FPS_COLOR, ALPHA}; mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color)); return; @@ -178,8 +178,8 @@ void RefreshRateOverlay::primeCache() { std::vector supportedFps; supportedFps.reserve(allRefreshRates.size()); - for (auto [ignored, refreshRate] : allRefreshRates) { - supportedFps.push_back(refreshRate.fps); + for (auto& [ignored, refreshRate] : allRefreshRates) { + supportedFps.push_back(refreshRate->fps); } std::sort(supportedFps.begin(), supportedFps.end()); diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 63d9c4bc5a..c04447d106 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -71,10 +71,10 @@ std::unordered_map PhaseOffsets::initializeOffsets std::unordered_map offsets; for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) { - if (refreshRate.fps > 65.0f) { - offsets.emplace(refreshRate.fps, getHighFpsOffsets(refreshRate.vsyncPeriod)); + if (refreshRate->fps > 65.0f) { + offsets.emplace(refreshRate->fps, getHighFpsOffsets(refreshRate->vsyncPeriod)); } else { - offsets.emplace(refreshRate.fps, getDefaultOffsets(refreshRate.vsyncPeriod)); + offsets.emplace(refreshRate->fps, getDefaultOffsets(refreshRate->vsyncPeriod)); } } return offsets; @@ -238,7 +238,7 @@ static std::vector getRefreshRatesFromConfigs( refreshRates.reserve(allRefreshRates.size()); for (const auto& [ignored, refreshRate] : allRefreshRates) { - refreshRates.emplace_back(refreshRate.fps); + refreshRates.emplace_back(refreshRate->fps); } return refreshRates; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 15b158d95f..9edbaee22f 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -286,12 +286,12 @@ const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() con mCurrentRefreshRate) != mAvailableRefreshRates.end()) { return *mCurrentRefreshRate; } - return mRefreshRates.at(mDefaultConfig); + return *mRefreshRates.at(mDefaultConfig); } void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) { std::lock_guard lock(mLock); - mCurrentRefreshRate = &mRefreshRates.at(configId); + mCurrentRefreshRate = mRefreshRates.at(configId).get(); } RefreshRateConfigs::RefreshRateConfigs(const std::vector& configs, @@ -326,7 +326,7 @@ status_t RefreshRateConfigs::setPolicy(HwcConfigIndexType defaultConfigId, float if (mRefreshRates.count(defaultConfigId) == 0) { return BAD_VALUE; } - const RefreshRate& refreshRate = mRefreshRates.at(defaultConfigId); + const RefreshRate& refreshRate = *mRefreshRates.at(defaultConfigId); if (!refreshRate.inPolicy(minRefreshRate, maxRefreshRate)) { return BAD_VALUE; } @@ -361,10 +361,10 @@ void RefreshRateConfigs::getSortedRefreshRateList( outRefreshRates->clear(); outRefreshRates->reserve(mRefreshRates.size()); for (const auto& [type, refreshRate] : mRefreshRates) { - if (shouldAddRefreshRate(refreshRate)) { + if (shouldAddRefreshRate(*refreshRate)) { ALOGV("getSortedRefreshRateList: config %d added to list policy", - refreshRate.configId.value()); - outRefreshRates->push_back(&refreshRate); + refreshRate->configId.value()); + outRefreshRates->push_back(refreshRate.get()); } } @@ -376,7 +376,7 @@ void RefreshRateConfigs::getSortedRefreshRateList( void RefreshRateConfigs::constructAvailableRefreshRates() { // Filter configs based on current policy and sort based on vsync period - HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig).configGroup; + HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig)->configGroup; ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f", mDefaultConfig.value(), group.value(), mMinRefreshRateFps, mMaxRefreshRateFps); getSortedRefreshRateList( @@ -403,16 +403,15 @@ void RefreshRateConfigs::init(const std::vector& configs, LOG_ALWAYS_FATAL_IF(configs.empty()); LOG_ALWAYS_FATAL_IF(currentHwcConfig.value() >= configs.size()); - auto buildRefreshRate = [&](InputConfig config) -> RefreshRate { - const float fps = 1e9f / config.vsyncPeriod; - return RefreshRate(config.configId, config.vsyncPeriod, config.configGroup, - base::StringPrintf("%2.ffps", fps), fps); - }; - for (const auto& config : configs) { - mRefreshRates.emplace(config.configId, buildRefreshRate(config)); + const float fps = 1e9f / config.vsyncPeriod; + mRefreshRates.emplace(config.configId, + std::make_unique(config.configId, config.vsyncPeriod, + config.configGroup, + base::StringPrintf("%2.ffps", fps), + fps)); if (config.configId == currentHwcConfig) { - mCurrentRefreshRate = &mRefreshRates.at(config.configId); + mCurrentRefreshRate = mRefreshRates.at(config.configId).get(); } } diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index c8aec86db3..9cd59593bb 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -59,6 +59,8 @@ public: configGroup(configGroup), name(std::move(name)), fps(fps) {} + + RefreshRate(const RefreshRate&) = delete; // This config ID corresponds to the position of the config in the vector that is stored // on the device. const HwcConfigIndexType configId; @@ -85,7 +87,8 @@ public: bool operator==(const RefreshRate& other) const { return !(*this != other); } }; - using AllRefreshRatesMapType = std::unordered_map; + using AllRefreshRatesMapType = + std::unordered_map>; // Sets the current policy to choose refresh rates. Returns NO_ERROR if the requested policy is // valid, or a negative error value otherwise. policyChanged, if non-null, will be set to true @@ -163,7 +166,7 @@ public: // Returns the refresh rate that corresponds to a HwcConfigIndexType. This won't change at // runtime. const RefreshRate& getRefreshRateFromConfigId(HwcConfigIndexType configId) const { - return mRefreshRates.at(configId); + return *mRefreshRates.at(configId); }; // Stores the current configId the device operates at diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 54442391ea..96fa0610d0 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -463,7 +463,7 @@ void Scheduler::chooseRefreshRateForContent() { return; } mFeatures.configId = newConfigId; - auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); + auto& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); mSchedulerCallback.changeRefreshRate(newRefreshRate, ConfigEvent::Changed); } } @@ -515,7 +515,7 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { // TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate // magic number - const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate(); + const auto& refreshRate = mRefreshRateConfigs.getCurrentRefreshRate(); constexpr float FPS_THRESHOLD_FOR_KERNEL_TIMER = 65.0f; if (state == TimerState::Reset && refreshRate.fps > FPS_THRESHOLD_FOR_KERNEL_TIMER) { // If we're not in performance mode then the kernel timer shouldn't do diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c995db4972..8587fb2c43 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -903,7 +903,7 @@ int SurfaceFlinger::getActiveConfig(const sp& displayToken) { void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { ATRACE_CALL(); - auto refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId); + auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId); ALOGV("setDesiredActiveConfig(%s)", refreshRate.name.c_str()); // Don't check against the current mode yet. Worst case we set the desired @@ -976,7 +976,7 @@ void SurfaceFlinger::setActiveConfigInternal() { mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId); display->setActiveConfig(mUpcomingActiveConfig.configId); - auto refreshRate = + auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId); mPhaseConfiguration->setRefreshRateFps(refreshRate.fps); mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets()); @@ -996,7 +996,7 @@ void SurfaceFlinger::desiredActiveConfigChangeDone() { mDesiredActiveConfig.event = Scheduler::ConfigEvent::None; mDesiredActiveConfigChanged = false; - auto const refreshRate = + const auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(mDesiredActiveConfig.configId); mScheduler->resyncToHardwareVsync(true, refreshRate.vsyncPeriod); mPhaseConfiguration->setRefreshRateFps(refreshRate.fps); @@ -1029,7 +1029,7 @@ bool SurfaceFlinger::performSetActiveConfig() { desiredActiveConfig = mDesiredActiveConfig; } - auto refreshRate = + auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(desiredActiveConfig.configId); ALOGV("performSetActiveConfig changing active config to %d(%s)", refreshRate.configId.value(), refreshRate.name.c_str()); @@ -5128,7 +5128,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r n = data.readInt32(); if (n == 1 && !mRefreshRateOverlay) { mRefreshRateOverlay = std::make_unique(*this); - auto current = mRefreshRateConfigs->getCurrentRefreshRate(); + auto& current = mRefreshRateConfigs->getCurrentRefreshRate(); mRefreshRateOverlay->changeRefreshRate(current); } else if (n == 0) { mRefreshRateOverlay.reset(); @@ -5177,7 +5177,7 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { if (mRefreshRateOverlay) { const auto kernelTimerEnabled = property_get_bool(KERNEL_IDLE_TIMER_PROP, false); const bool timerExpired = kernelTimerEnabled && expired; - const auto& current = [this]() { + const auto& current = [this]() -> const RefreshRate& { std::lock_guard lock(mActiveConfigLock); if (mDesiredActiveConfigChanged) { return mRefreshRateConfigs->getRefreshRateFromConfigId( @@ -5857,7 +5857,7 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const spgetActiveConfig(), vsyncPeriod); auto configId = mScheduler->getPreferredConfigId(); - auto preferredRefreshRate = configId + auto& preferredRefreshRate = configId ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId) // NOTE: Choose the default config ID, if Scheduler doesn't have one in mind. : mRefreshRateConfigs->getRefreshRateFromConfigId(defaultConfig); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index e7e7f66c95..4a179b6d0f 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -93,8 +93,8 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) { auto refreshRateConfigs = std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); - const auto minRate = refreshRateConfigs->getMinRefreshRate(); - const auto performanceRate = refreshRateConfigs->getMaxRefreshRate(); + const auto& minRate = refreshRateConfigs->getMinRefreshRate(); + const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate(); RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; ASSERT_EQ(expectedDefaultConfig, minRate); @@ -102,8 +102,8 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) { 90}; ASSERT_EQ(expectedPerformanceConfig, performanceRate); - const auto minRateByPolicy = refreshRateConfigs->getMinRefreshRateByPolicy(); - const auto performanceRateByPolicy = refreshRateConfigs->getMaxRefreshRateByPolicy(); + const auto& minRateByPolicy = refreshRateConfigs->getMinRefreshRateByPolicy(); + const auto& performanceRateByPolicy = refreshRateConfigs->getMaxRefreshRateByPolicy(); ASSERT_EQ(minRateByPolicy, minRate); ASSERT_EQ(performanceRateByPolicy, performanceRate); } @@ -115,10 +115,10 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differe auto refreshRateConfigs = std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); - const auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy(); - const auto performanceRate = refreshRateConfigs->getMaxRefreshRate(); - const auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy(); - const auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy(); + const auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy(); + const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate(); + const auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy(); + const auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy(); RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; ASSERT_EQ(expectedDefaultConfig, minRate); @@ -128,8 +128,8 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differe ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 60, 90, nullptr), 0); refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); - const auto minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy(); - const auto performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy(); + const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy(); + const auto& performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy(); RefreshRate expectedPerformanceConfig = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_1, "90fps", 90}; @@ -145,8 +145,8 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_policyChange) { auto refreshRateConfigs = std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy(); - auto performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy(); + auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy(); + auto& performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy(); RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; ASSERT_EQ(expectedDefaultConfig, minRate); @@ -156,8 +156,8 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_policyChange) { ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0); - auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy(); - auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy(); + auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy(); + auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy(); ASSERT_EQ(expectedDefaultConfig, minRate60); ASSERT_EQ(expectedDefaultConfig, performanceRate60); } @@ -169,19 +169,19 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getCurrentRefreshRate) { auto refreshRateConfigs = std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); { - auto current = refreshRateConfigs->getCurrentRefreshRate(); + auto& current = refreshRateConfigs->getCurrentRefreshRate(); EXPECT_EQ(current.configId, HWC_CONFIG_ID_60); } refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); { - auto current = refreshRateConfigs->getCurrentRefreshRate(); + auto& current = refreshRateConfigs->getCurrentRefreshRate(); EXPECT_EQ(current.configId, HWC_CONFIG_ID_90); } ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0); { - auto current = refreshRateConfigs->getCurrentRefreshRate(); + auto& current = refreshRateConfigs->getCurrentRefreshRate(); EXPECT_EQ(current.configId, HWC_CONFIG_ID_90); } } -- GitLab From 80826e0e14e547aba00ad558fb1d0c1d93e7cebc Mon Sep 17 00:00:00 2001 From: Chris Ye Date: Thu, 5 Mar 2020 15:14:21 -0800 Subject: [PATCH 0889/1255] Move the non-NDK APIs to powermanager internal directory. Move the header files with non-NDK APIs to be inside powermanager. Bug: 150878392 Change-Id: I34d0619a0fd3bc913ef79040207b5943add6b372 --- services/powermanager/Android.bp | 7 ++++++- .../powermanager/include}/android/CoolingDevice.h | 0 .../powermanager/include}/android/Temperature.h | 0 3 files changed, 6 insertions(+), 1 deletion(-) rename {include => services/powermanager/include}/android/CoolingDevice.h (100%) rename {include => services/powermanager/include}/android/Temperature.h (100%) diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp index 3e0f136dfb..b0d3e3bde0 100644 --- a/services/powermanager/Android.bp +++ b/services/powermanager/Android.bp @@ -9,7 +9,7 @@ cc_library_shared { ], aidl: { - local_include_dirs: ["."], + local_include_dirs: ["include"], include_dirs: [ "frameworks/base/core/java/android/os", ], @@ -28,6 +28,11 @@ cc_library_shared { "-Wunused", "-Wunreachable-code", ], + + local_include_dirs: ["include"], + export_include_dirs: [ + "include", + ], } cc_test { diff --git a/include/android/CoolingDevice.h b/services/powermanager/include/android/CoolingDevice.h similarity index 100% rename from include/android/CoolingDevice.h rename to services/powermanager/include/android/CoolingDevice.h diff --git a/include/android/Temperature.h b/services/powermanager/include/android/Temperature.h similarity index 100% rename from include/android/Temperature.h rename to services/powermanager/include/android/Temperature.h -- GitLab From 0fe51b11ad3cebb12d1973fbc250c53d6d3cc9b6 Mon Sep 17 00:00:00 2001 From: Hunter Knepshield Date: Thu, 5 Mar 2020 16:58:20 -0800 Subject: [PATCH 0890/1255] Include TelephonyRegistry in connectivity bug reports. This appears to be a simple case of omission, and it often contains useful debugging information that survives telephony process crashes since it lives in the system server. Package names have already been scrubbed from the dump (from change Iad7be2d7), and the output contains no other PII. Bug: 150409813 Bug: 146521742 Test: adb shell am bug-report --telephony, verify TelReg is dumped Change-Id: I068d50f1247d4e266d90b0557c6166cabd1bcf3f --- cmds/dumpstate/dumpstate.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 344011675d..e5bbb286ca 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1728,6 +1728,8 @@ static void DumpstateTelephonyOnly(const std::string& calling_package) { RunDumpsys("DUMPSYS", {"netpolicy"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); RunDumpsys("DUMPSYS", {"network_management"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); + RunDumpsys("DUMPSYS", {"telephony.registry"}, CommandOptions::WithTimeout(90).Build(), + SEC_TO_MSEC(10)); if (include_sensitive_info) { // Contains raw IP addresses, omit from reports on user builds. RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); -- GitLab From d9a25c40400a30f4f5a5df4204f3b3c4fb2c31f4 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Tue, 3 Mar 2020 18:59:19 +0800 Subject: [PATCH 0891/1255] Reduce setInputWindows calls The compare function 'Region::isTriviallyEqual' is just compare the first iterator between two regions, and it will always get false if we passed it from binder that would create a new one even they are equal. That would cause the layer to recompute the visible regions and make it direct to call 'updateInputWindowInfo' continually. - Change to use Region::hasSameRects to reduce some unnecessary calls. Bug: 133780957 Test: manual, open debug logs and watch a video Change-Id: Ibc9c488c179b403b203a1853cd6f3be9bb23fbaa --- services/surfaceflinger/LayerRejecter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp index d3364a0929..e6c8654cbf 100644 --- a/services/surfaceflinger/LayerRejecter.cpp +++ b/services/surfaceflinger/LayerRejecter.cpp @@ -120,7 +120,7 @@ bool LayerRejecter::reject(const sp& buf, const BufferItem& item) // We latch the transparent region here, instead of above where we latch // the rest of the geometry because it is only content but not necessarily // resize dependent. - if (!mFront.activeTransparentRegion_legacy.isTriviallyEqual( + if (!mFront.activeTransparentRegion_legacy.hasSameRects( mFront.requestedTransparentRegion_legacy)) { mFront.activeTransparentRegion_legacy = mFront.requestedTransparentRegion_legacy; -- GitLab From 1f7c37f373068c41ba77413fc6dc4eb8bac28f0b Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Sun, 23 Feb 2020 03:02:43 +0900 Subject: [PATCH 0892/1255] Use {llndk,vndksp}.libraries.txt from VNDK APEX /system/etc/{llndk,vndksp}.libraries.txt files will be deprecated. These files can be read from VNDK APEX. Bug: 145184886 Test: build / boot Merged-In: Ic6f46033bd525325562e04ef9e8bcb8ebb5b5d41 Change-Id: Ic6f46033bd525325562e04ef9e8bcb8ebb5b5d41 (cherry picked from commit 78396804770bf3c3a1143f823a466cc0c6849104) --- libs/graphicsenv/GraphicsEnv.cpp | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index befabee66d..4809c1f0d8 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -61,26 +61,25 @@ enum NativeLibrary { VNDKSP = 1, }; -static constexpr const char* kNativeLibrariesSystemConfigPath[] = {"/etc/llndk.libraries.txt", - "/etc/vndksp.libraries.txt"}; +static constexpr const char* kNativeLibrariesSystemConfigPath[] = + {"/apex/com.android.vndk.v{}/etc/llndk.libraries.{}.txt", + "/apex/com.android.vndk.v{}/etc/vndksp.libraries.{}.txt"}; static std::string vndkVersionStr() { #ifdef __BIONIC__ - std::string version = android::base::GetProperty("ro.vndk.version", ""); - if (version != "" && version != "current") { - return "." + version; - } + return android::base::GetProperty("ro.vndk.version", ""); #endif return ""; } static void insertVndkVersionStr(std::string* fileName) { LOG_ALWAYS_FATAL_IF(!fileName, "fileName should never be nullptr"); - size_t insertPos = fileName->find_last_of("."); - if (insertPos == std::string::npos) { - insertPos = fileName->length(); + std::string version = vndkVersionStr(); + size_t pos = fileName->find("{}"); + while (pos != std::string::npos) { + fileName->replace(pos, 2, version); + pos = fileName->find("{}", pos + version.size()); } - fileName->insert(insertPos, vndkVersionStr()); } static bool readConfig(const std::string& configFile, std::vector* soNames) { @@ -103,11 +102,7 @@ static bool readConfig(const std::string& configFile, std::vector* } static const std::string getSystemNativeLibraries(NativeLibrary type) { - static const char* androidRootEnv = getenv("ANDROID_ROOT"); - static const std::string rootDir = androidRootEnv != nullptr ? androidRootEnv : "/system"; - - std::string nativeLibrariesSystemConfig = rootDir + kNativeLibrariesSystemConfigPath[type]; - + std::string nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type]; insertVndkVersionStr(&nativeLibrariesSystemConfig); std::vector soNames; -- GitLab From 559b4339c728ee56c4eebc4d3c50866564501afa Mon Sep 17 00:00:00 2001 From: Courtney Goeltzenleuchter Date: Fri, 6 Mar 2020 11:12:19 -0700 Subject: [PATCH 0893/1255] Enable context virtualization only for GL Only the GL back-end requires context virtualization. So only require it for that case and not for Vulkan back-end. Test: dEQP with ANGLE and ANGLE build with args.gn with angle_enable_gl=false Bug: 150892231 Change-Id: I443841c2543d0c6446d0f11122bf18dc9acbf428 --- opengl/libs/EGL/egl_display.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index 67d69b4d06..a58e87ca3e 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -158,13 +158,16 @@ static bool addAnglePlatformAttributes(egl_connection_t* const cnx, // NOTE: This is only valid if the backend is OpenGL attrs.push_back(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE); attrs.push_back(vendorEGL); + + // Context virtualization is only available on GL back-end. + // Needed to support threading with GL back-end + attrs.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE); + attrs.push_back(EGL_FALSE); break; default: - ALOGV("%s: Requesting Unknown (%d) ANGLE back-end", __FUNCTION__, cnx->angleBackend); + ALOGE("%s: Requesting Unknown (%d) ANGLE back-end", __FUNCTION__, cnx->angleBackend); break; } - attrs.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE); - attrs.push_back(EGL_FALSE); return true; } -- GitLab From d8fcca96b6425d8334a0566df20bd8ef4e7e66ca Mon Sep 17 00:00:00 2001 From: chaviw Date: Fri, 6 Mar 2020 13:07:18 -0800 Subject: [PATCH 0894/1255] Remove HWC trace from default surface traces. HWC traces are very large so it ends up causing a lot of frames to get deleted from the SurfaceFlinger traces. The buffer can only handle 5MB so logging HWC ends up crossing that size very quickly. Test: No longer trace HWC information by default Change-Id: Ifa34f2fd886bd15dbf689c3ed4314c988a9ef049 Fixes: 150963168 --- services/surfaceflinger/SurfaceTracing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index 3c24881d7c..57dc7c885c 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -97,7 +97,7 @@ private: std::condition_variable mCanStartTrace; std::mutex& mSfLock; - uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_ALL; + uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_CRITICAL | TRACE_INPUT; const char* mWhere GUARDED_BY(mSfLock) = ""; mutable std::mutex mTraceLock; -- GitLab From 9a2cc990b0a4f7670b38d28913a5ef0e809ffe4f Mon Sep 17 00:00:00 2001 From: Rob Carr Date: Fri, 6 Mar 2020 12:44:45 -0800 Subject: [PATCH 0895/1255] SurfaceFlinger: Ensure syncInputWindows is processed. Imagine the following situation: 1. We set mPendingInputWindowCommands.syncInputWindows = true, and block on the condition variable from a binder thread. 2. We Handle MessageQueue::INVALIDATE 3. This will invoke handleTransaction which will copy mPendingInputWindowCommands to mInputWindowCommands and clear mPendingInputWindowCommands 4. Now imagine due to the performSetActiveConfig conditional in MessageQueue::INVALIDATE handler we break out of our handling before calling updateInputFlinger. 5. Since we didn't call updateInputFlinger we will never receive setInputWindowsFinished and the condition variable is still blocking 6. The next time we enter MessageQueue::INVALIDATE we have already cleared mPendingInput WindowCommands, and so by the time we get to updateInputFligner we no longer think a sync is required and don't request the callback. 7. No callback ever arrives, our binder thread blocks for the whole 5 seconds. To fix this we just ensure mInputWindowCommands.syncInputWindows wont become false after becoming true until we actually are sure we will broadcast the condition variable. Bug: 147257069 Test: Existing tests pass Change-Id: I5f5728c29f36bb5e0bdf11b3f34e956bb529706f --- services/surfaceflinger/SurfaceFlinger.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ffb8ae925a..28c6eaf6e0 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2808,7 +2808,7 @@ void SurfaceFlinger::updateInputWindowInfo() { } void SurfaceFlinger::commitInputWindowCommands() { - mInputWindowCommands = mPendingInputWindowCommands; + mInputWindowCommands.merge(mPendingInputWindowCommands); mPendingInputWindowCommands.clear(); } @@ -5783,6 +5783,7 @@ void SurfaceFlinger::setInputWindowsFinished() { Mutex::Autolock _l(mStateLock); mPendingSyncInputWindows = false; + mTransactionCV.broadcast(); } -- GitLab From 39db0b34a86c142b5ec05e89c74be83669326d22 Mon Sep 17 00:00:00 2001 From: Rob Carr Date: Fri, 6 Mar 2020 15:46:16 -0800 Subject: [PATCH 0896/1255] SurfaceControl: Remove transferTouchFocus As it's unused. Bug: 147257069 Test: Existing tests pass Change-Id: I60ef95d6cd86ed28db73ebbb0d02062194f9c0e7 --- libs/gui/LayerState.cpp | 21 -------------------- libs/gui/SurfaceComposerClient.cpp | 9 --------- libs/gui/include/gui/LayerState.h | 6 ------ libs/gui/include/gui/SurfaceComposerClient.h | 1 - services/surfaceflinger/SurfaceFlinger.cpp | 4 ---- 5 files changed, 41 deletions(-) diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index a9c9b7460b..f7158d0472 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -443,39 +443,18 @@ void layer_state_t::merge(const layer_state_t& other) { // ------------------------------- InputWindowCommands ---------------------------------------- void InputWindowCommands::merge(const InputWindowCommands& other) { - transferTouchFocusCommands - .insert(transferTouchFocusCommands.end(), - std::make_move_iterator(other.transferTouchFocusCommands.begin()), - std::make_move_iterator(other.transferTouchFocusCommands.end())); - syncInputWindows |= other.syncInputWindows; } void InputWindowCommands::clear() { - transferTouchFocusCommands.clear(); syncInputWindows = false; } void InputWindowCommands::write(Parcel& output) const { - output.writeUint32(static_cast(transferTouchFocusCommands.size())); - for (const auto& transferTouchFocusCommand : transferTouchFocusCommands) { - output.writeStrongBinder(transferTouchFocusCommand.fromToken); - output.writeStrongBinder(transferTouchFocusCommand.toToken); - } - output.writeBool(syncInputWindows); } void InputWindowCommands::read(const Parcel& input) { - size_t count = input.readUint32(); - transferTouchFocusCommands.clear(); - for (size_t i = 0; i < count; i++) { - TransferTouchFocusCommand transferTouchFocusCommand; - transferTouchFocusCommand.fromToken = input.readStrongBinder(); - transferTouchFocusCommand.toToken = input.readStrongBinder(); - transferTouchFocusCommands.emplace_back(transferTouchFocusCommand); - } - syncInputWindows = input.readBool(); } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index dc4860ab12..2307fbf56b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1290,15 +1290,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInput return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::transferTouchFocus( - const sp& fromToken, const sp& toToken) { - InputWindowCommands::TransferTouchFocusCommand transferTouchFocusCommand; - transferTouchFocusCommand.fromToken = fromToken; - transferTouchFocusCommand.toToken = toToken; - mInputWindowCommands.transferTouchFocusCommands.emplace_back(transferTouchFocusCommand); - return *this; -} - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() { mInputWindowCommands.syncInputWindows = true; return *this; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 7e3d5d50d3..2b2f7735ba 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -271,12 +271,6 @@ struct DisplayState { }; struct InputWindowCommands { - struct TransferTouchFocusCommand { - sp fromToken; - sp toToken; - }; - - std::vector transferTouchFocusCommands; bool syncInputWindows{false}; void merge(const InputWindowCommands& other); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 0cf141d577..2fb9538390 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -507,7 +507,6 @@ public: #ifndef NO_INPUT Transaction& setInputWindowInfo(const sp& sc, const InputWindowInfo& info); - Transaction& transferTouchFocus(const sp& fromToken, const sp& toToken); Transaction& syncInputWindows(); #endif diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ffb8ae925a..965366197b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3745,10 +3745,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) { uint32_t flags = 0; - if (!inputWindowCommands.transferTouchFocusCommands.empty()) { - flags |= eTraversalNeeded; - } - if (inputWindowCommands.syncInputWindows) { flags |= eTraversalNeeded; } -- GitLab From d90cc65d74b26b7346d4a55704606a54b6956b34 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Sat, 8 Feb 2020 16:52:02 -0800 Subject: [PATCH 0897/1255] dumpstate: collect snapshotctl logs without root. Test: bugreport Bug: 148818798 Change-Id: I83e394420225bd9543e013e8ed71b37850d07314 Merged-In: I83e394420225bd9543e013e8ed71b37850d07314 --- cmds/dumpstate/dumpstate.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 814a4edafd..e0ed9fea10 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1459,6 +1459,8 @@ static Dumpstate::RunStatus dumpstate() { ds.AddDir(WMTRACE_DATA_DIR, false); } + ds.AddDir(SNAPSHOTCTL_LOG_DIR, false); + RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard); /* Migrate the ril_dumpstate to a device specific dumpstate? */ @@ -1587,7 +1589,6 @@ Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() { 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); -- GitLab From a13f2d58e01d980d39d3617032120c5f9b6423bd Mon Sep 17 00:00:00 2001 From: Brian Lindahl Date: Thu, 5 Mar 2020 11:54:17 +0100 Subject: [PATCH 0898/1255] Allow GPU composition to occur at a lower resolution Add a vendor-specified system property to allow GPU fallback composition to occur at a lower resolution than the display mode resolution. Bug: 144574809 Test: Tested with sysprop disabled, and tested backport in Android Q with sysprop enabled. Unable to test on Android R due to device issues. Change-Id: I02948ce72f49d20416d0e4dd45a4cffe99e28820 --- .../DisplayHardware/FramebufferSurface.cpp | 38 ++++++++++++++++--- .../DisplayHardware/FramebufferSurface.h | 17 ++++++++- services/surfaceflinger/SurfaceFlinger.cpp | 8 +++- services/surfaceflinger/SurfaceFlinger.h | 6 +++ .../SurfaceFlingerProperties.cpp | 16 ++++++++ .../surfaceflinger/SurfaceFlingerProperties.h | 3 ++ .../sysprop/SurfaceFlingerProperties.sysprop | 20 ++++++++++ .../api/SurfaceFlingerProperties-current.txt | 10 +++++ 8 files changed, 110 insertions(+), 8 deletions(-) diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 36544b6653..aeffb0e185 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -57,9 +57,12 @@ using ui::Dataspace; */ FramebufferSurface::FramebufferSurface(HWComposer& hwc, DisplayId displayId, - const sp& consumer) + const sp& consumer, + uint32_t maxWidth, uint32_t maxHeight) : ConsumerBase(consumer), mDisplayId(displayId), + mMaxWidth(maxWidth), + mMaxHeight(maxHeight), mCurrentBufferSlot(-1), mCurrentBuffer(), mCurrentFence(Fence::NO_FENCE), @@ -75,14 +78,16 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, DisplayId displayId, GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER); const auto& activeConfig = mHwc.getActiveConfig(displayId); - mConsumer->setDefaultBufferSize(activeConfig->getWidth(), - activeConfig->getHeight()); + ui::Size limitedSize = + limitFramebufferSize(activeConfig->getWidth(), activeConfig->getHeight()); + mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height); mConsumer->setMaxAcquiredBufferCount( SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1); } -void FramebufferSurface::resizeBuffers(const uint32_t width, const uint32_t height) { - mConsumer->setDefaultBufferSize(width, height); +void FramebufferSurface::resizeBuffers(uint32_t width, uint32_t height) { + ui::Size limitedSize = limitFramebufferSize(width, height); + mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height); } status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) { @@ -177,6 +182,29 @@ void FramebufferSurface::onFrameCommitted() { } } +ui::Size FramebufferSurface::limitFramebufferSize(uint32_t width, uint32_t height) { + // TODO(b/149495759): Use the ui::Size constructor once it no longer is broken. + ui::Size framebufferSize; + framebufferSize.width = width; + framebufferSize.height = height; + bool wasLimited = true; + if (width > mMaxWidth && mMaxWidth != 0) { + float aspectRatio = float(width) / float(height); + framebufferSize.height = mMaxWidth / aspectRatio; + framebufferSize.width = mMaxWidth; + wasLimited = true; + } + if (height > mMaxHeight && mMaxHeight != 0) { + float aspectRatio = float(width) / float(height); + framebufferSize.height = mMaxHeight; + framebufferSize.width = mMaxHeight * aspectRatio; + wasLimited = true; + } + ALOGI_IF(wasLimited, "framebuffer size has been limited to [%dx%d] from [%dx%d]", + framebufferSize.width, framebufferSize.height, width, height); + return framebufferSize; +} + void FramebufferSurface::dumpAsString(String8& result) const { Mutex::Autolock lock(mMutex); result.appendFormat(" FramebufferSurface: dataspace: %s(%d)\n", diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index 7f451a5ac6..a1859f33bb 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "DisplayIdentification.h" @@ -39,7 +40,8 @@ class HWComposer; class FramebufferSurface : public ConsumerBase, public compositionengine::DisplaySurface { public: FramebufferSurface(HWComposer& hwc, DisplayId displayId, - const sp& consumer); + const sp& consumer, uint32_t maxWidth, + uint32_t maxHeight); virtual status_t beginFrame(bool mustRecompose); virtual status_t prepareFrame(CompositionType compositionType); @@ -47,7 +49,7 @@ public: virtual void onFrameCommitted(); virtual void dumpAsString(String8& result) const; - virtual void resizeBuffers(const uint32_t width, const uint32_t height); + virtual void resizeBuffers(uint32_t width, uint32_t height); virtual const sp& getClientTargetAcquireFence() const override; @@ -58,6 +60,9 @@ private: virtual void dumpLocked(String8& result, const char* prefix) const; + // Limits the width and height by the maximum width specified in the constructor. + ui::Size limitFramebufferSize(uint32_t width, uint32_t height); + // nextBuffer waits for and then latches the next buffer from the // BufferQueue and releases the previously latched buffer to the // BufferQueue. The new buffer is returned in the 'buffer' argument. @@ -66,6 +71,14 @@ private: const DisplayId mDisplayId; + // Framebuffer size has a dimension limitation in pixels based on the graphics capabilities of + // the device. + const uint32_t mMaxWidth; + + // Framebuffer size has a dimension limitation in pixels based on the graphics capabilities of + // the device. + const uint32_t mMaxHeight; + // mCurrentBufferIndex is the slot index of the current buffer or // INVALID_BUFFER_SLOT to indicate that either there is no current buffer // or the buffer is not associated with a slot. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 163a1c743b..5a7372787d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -217,6 +217,8 @@ uint64_t SurfaceFlinger::maxVirtualDisplaySize; bool SurfaceFlinger::hasSyncFramework; bool SurfaceFlinger::useVrFlinger; int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers; +uint32_t SurfaceFlinger::maxGraphicsWidth; +uint32_t SurfaceFlinger::maxGraphicsHeight; bool SurfaceFlinger::hasWideColorDisplay; ui::Rotation SurfaceFlinger::internalDisplayOrientation = ui::ROTATION_0; bool SurfaceFlinger::useColorManagement; @@ -283,6 +285,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2); + maxGraphicsWidth = std::max(max_graphics_width(0), 0); + maxGraphicsHeight = std::max(max_graphics_height(0), 0); + hasWideColorDisplay = has_wide_color_display(false); useColorManagement = use_color_management(false); @@ -2593,7 +2598,8 @@ void SurfaceFlinger::processDisplayChangesLocked() { state.surface.get()); LOG_ALWAYS_FATAL_IF(!displayId); - dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer); + dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer, + maxGraphicsWidth, maxGraphicsHeight); producer = bqProducer; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index e7f9930392..7586793081 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -225,6 +226,11 @@ public: // FramebufferSurface static int64_t maxFrameBufferAcquiredBuffers; + // Controls the maximum width and height in pixels that the graphics pipeline can support for + // GPU fallback composition. For example, 8k devices with 4k GPUs, or 4k devices with 2k GPUs. + static uint32_t maxGraphicsWidth; + static uint32_t maxGraphicsHeight; + // Indicate if a device has wide color gamut display. This is typically // found on devices with wide color gamut (e.g. Display-P3) display. static bool hasWideColorDisplay; diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index f3352a5a24..9d78702a08 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -70,6 +70,22 @@ int64_t max_frame_buffer_acquired_buffers(int64_t defaultValue) { defaultValue); } +int32_t max_graphics_width(int32_t defaultValue) { + auto temp = SurfaceFlingerProperties::max_graphics_width(); + if (temp.has_value()) { + return *temp; + } + return defaultValue; +} + +int32_t max_graphics_height(int32_t defaultValue) { + auto temp = SurfaceFlingerProperties::max_graphics_height(); + if (temp.has_value()) { + return *temp; + } + return defaultValue; +} + bool has_wide_color_display(bool defaultValue) { auto temp = SurfaceFlingerProperties::has_wide_color_display(); if (temp.has_value()) { diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index 12c711abfc..c63adfe3c2 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -37,6 +37,9 @@ bool use_context_priority(bool defaultValue); int64_t max_frame_buffer_acquired_buffers(int64_t defaultValue); +int32_t max_graphics_width(int32_t defaultValue); +int32_t max_graphics_height(int32_t defaultValue); + bool has_wide_color_display(bool defaultValue); bool running_without_sync_framework(bool defaultValue); diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index 155f71877d..cfc301bd22 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -67,6 +67,26 @@ prop { prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers" } +# Controls the maximum width in pixels that the graphics pipeline can support for GPU fallback +# composition. For example, 8k displays with 4k GPUs, or 4k displays with 2k GPUs. +prop { + api_name: "max_graphics_width" + type: Integer + scope: System + access: Readonly + prop_name: "ro.surface_flinger.max_graphics_width" +} + +# Controls the maximum height in pixels that the graphics pipeline can support for GPU fallback +# composition. For example, 8k displays with 4k GPUs, or 4k displays with 2k GPUs. +prop { + api_name: "max_graphics_height" + type: Integer + scope: System + access: Readonly + prop_name: "ro.surface_flinger.max_graphics_height" +} + # hasWideColorDisplay indicates that the device has # or can support a wide-color display, e.g. color space # greater than sRGB. Typical display may have same diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt index e62c127062..ba60a7defb 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -61,6 +61,16 @@ props { type: Long prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers" } + prop { + api_name: "max_graphics_height" + type: Integer + prop_name: "ro.surface_flinger.max_graphics_height" + } + prop { + api_name: "max_graphics_width" + type: Integer + prop_name: "ro.surface_flinger.max_graphics_width" + } prop { api_name: "max_virtual_display_dimension" type: Long -- GitLab From a79435bd6f7de397ac7f65f68c8db0f7173eabe5 Mon Sep 17 00:00:00 2001 From: Rob Carr Date: Fri, 6 Mar 2020 14:46:07 -0800 Subject: [PATCH 0899/1255] SurfaceFlinger: Avoid destroying Layer on Binder thread BufferQueueLayer::onFrameAvailable passes 'this' as an sp to SurfaceInterceptor. This constructs a temporary sp. We are on a binder thread and not holding any locks, so at this point the main thread could drop it's last references. Then when we destroy our temporary sp it is the last reference and we end up invoking ~Layer from the Binder thread, an invalid operation which in this case leads to dead-lock (as we attempt to reacquire the already acquired BufferQueue mutex from the BufferQueueLayer d'tor) Bug: 149473038 Test: Existing tests pass Change-Id: I77a20bedf2db3b974ac03d804f70993514478fb2 --- services/surfaceflinger/BufferQueueLayer.cpp | 2 +- services/surfaceflinger/SurfaceInterceptor.cpp | 17 ++++++++++++----- services/surfaceflinger/SurfaceInterceptor.h | 6 +++--- .../unittests/mock/MockSurfaceInterceptor.h | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 18f7f44fa5..fac9024121 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -441,7 +441,7 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { mQueueItemCondition.broadcast(); } - mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(), + mFlinger->mInterceptor->saveBufferUpdate(layerId, item.mGraphicBuffer->getWidth(), item.mGraphicBuffer->getHeight(), item.mFrameNumber); mFlinger->signalLayerUpdate(); diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index 1f9d46c330..5b3cd698b5 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -524,11 +524,11 @@ void SurfaceInterceptor::addSurfaceDeletionLocked(Increment* increment, deletion->set_id(getLayerId(layer)); } -void SurfaceInterceptor::addBufferUpdateLocked(Increment* increment, const sp& layer, +void SurfaceInterceptor::addBufferUpdateLocked(Increment* increment, int32_t layerId, uint32_t width, uint32_t height, uint64_t frameNumber) { BufferUpdate* update(increment->mutable_buffer_update()); - update->set_id(getLayerId(layer)); + update->set_id(layerId); update->set_w(width); update->set_h(height); update->set_frame_number(frameNumber); @@ -644,15 +644,22 @@ void SurfaceInterceptor::saveSurfaceDeletion(const sp& layer) { addSurfaceDeletionLocked(createTraceIncrementLocked(), layer); } -void SurfaceInterceptor::saveBufferUpdate(const sp& layer, uint32_t width, +/** + * Here we pass the layer by ID instead of by sp<> since this is called without + * holding the state-lock from a Binder thread. If we required the caller + * to pass 'this' by sp<> the temporary sp<> constructed could end up + * being the last reference and we might accidentally destroy the Layer + * from this binder thread. + */ +void SurfaceInterceptor::saveBufferUpdate(int32_t layerId, uint32_t width, uint32_t height, uint64_t frameNumber) { - if (!mEnabled || layer == nullptr) { + if (!mEnabled) { return; } ATRACE_CALL(); std::lock_guard protoGuard(mTraceMutex); - addBufferUpdateLocked(createTraceIncrementLocked(), layer, width, height, frameNumber); + addBufferUpdateLocked(createTraceIncrementLocked(), layerId, width, height, frameNumber); } void SurfaceInterceptor::saveVSyncEvent(nsecs_t timestamp) { diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h index a665f62ad7..896bdcc259 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -67,7 +67,7 @@ public: // Intercept surface data virtual void saveSurfaceCreation(const sp& layer) = 0; virtual void saveSurfaceDeletion(const sp& layer) = 0; - virtual void saveBufferUpdate(const sp& layer, uint32_t width, uint32_t height, + virtual void saveBufferUpdate(int32_t layerId, uint32_t width, uint32_t height, uint64_t frameNumber) = 0; // Intercept display data @@ -102,7 +102,7 @@ public: // Intercept surface data void saveSurfaceCreation(const sp& layer) override; void saveSurfaceDeletion(const sp& layer) override; - void saveBufferUpdate(const sp& layer, uint32_t width, uint32_t height, + void saveBufferUpdate(int32_t layerId, uint32_t width, uint32_t height, uint64_t frameNumber) override; // Intercept display data @@ -130,7 +130,7 @@ private: Increment* createTraceIncrementLocked(); void addSurfaceCreationLocked(Increment* increment, const sp& layer); void addSurfaceDeletionLocked(Increment* increment, const sp& layer); - void addBufferUpdateLocked(Increment* increment, const sp& layer, uint32_t width, + void addBufferUpdateLocked(Increment* increment, int32_t layerId, uint32_t width, uint32_t height, uint64_t frameNumber); void addVSyncUpdateLocked(Increment* increment, nsecs_t timestamp); void addDisplayCreationLocked(Increment* increment, const DisplayDeviceState& info); diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h index 458b2f3da2..5beee1c0ec 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h +++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h @@ -39,7 +39,7 @@ public: const Vector&, uint32_t)); MOCK_METHOD1(saveSurfaceCreation, void(const sp&)); MOCK_METHOD1(saveSurfaceDeletion, void(const sp&)); - MOCK_METHOD4(saveBufferUpdate, void(const sp&, uint32_t, uint32_t, uint64_t)); + MOCK_METHOD4(saveBufferUpdate, void(int32_t, uint32_t, uint32_t, uint64_t)); MOCK_METHOD1(saveDisplayCreation, void(const DisplayDeviceState&)); MOCK_METHOD1(saveDisplayDeletion, void(int32_t)); MOCK_METHOD2(savePowerModeUpdate, void(int32_t, int32_t)); -- GitLab From 56c07ad531cb86a5ece0212c41ee9d4e2b2ea3bc Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 6 Mar 2020 18:20:56 -0800 Subject: [PATCH 0900/1255] libbinder_ndk: remove logspam on incStrong AIBinder_incStrong is frequently called on a null binder out of convenience, because in cases where ownership is required on a binder that may or may not be nullptr, ignoring the incStrong on nullptr is consistent. Fixes: 150894288 Test: atest CtsNdkBinderTestCases Change-Id: I247811a7d4600711c015647f77900bf3183890e2 (cherry picked from commit 42666b84bcdb268cd2e474eb7024a32651cc07c6) Merged-In: I247811a7d4600711c015647f77900bf3183890e2 --- libs/binder/ndk/ibinder.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp index 75dcdc8389..649faa1c76 100644 --- a/libs/binder/ndk/ibinder.cpp +++ b/libs/binder/ndk/ibinder.cpp @@ -486,7 +486,6 @@ pid_t AIBinder_getCallingPid() { void AIBinder_incStrong(AIBinder* binder) { if (binder == nullptr) { - LOG(ERROR) << __func__ << ": on null binder"; return; } -- GitLab From cf1868c814eb466c06dcd572c787db59cf0e3729 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Wed, 4 Mar 2020 17:32:44 -0800 Subject: [PATCH 0901/1255] SF: Remove a redundant write The Layer compositionState structure was only intended to be updated during the call from the LayerFE::prepareCompositionState() call, which in turn calls preparePerFrameCompositionState(). Both BufferQueueLayer and BufferStateLayer were updating the buffer entry in the composition state structure in updateActiveBuffer(), which was redundant with an update of the buffer entry also being made there. This *may* also have resulted in the StrongPointer code reporting a write race, resulting in a reported bug. Test: go/wm-smoke Test: atest CtsColorModeTestCases Test: atest CtsDisplayTestCases Test: atest CtsGraphicsTestCases Test: atest CtsUiRenderingTestCases Test: atest CtsViewTestCases Test: atest android.media.cts.EncodeVirtualDisplayWithCompositionTest Bug: 149663608 Change-Id: I5b2fc552a92746adfe3693059dab315a573a4860 --- services/surfaceflinger/BufferQueueLayer.cpp | 2 -- services/surfaceflinger/BufferStateLayer.cpp | 1 - 2 files changed, 3 deletions(-) diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 18f7f44fa5..e53d254da2 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -346,8 +346,6 @@ status_t BufferQueueLayer::updateActiveBuffer() { mPreviousBufferId = getCurrentBufferId(); mBufferInfo.mBuffer = mConsumer->getCurrentBuffer(&mBufferInfo.mBufferSlot, &mBufferInfo.mFence); - auto* layerCompositionState = editCompositionState(); - layerCompositionState->buffer = mBufferInfo.mBuffer; if (mBufferInfo.mBuffer == nullptr) { // this can only happen if the very first buffer was rejected. diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index de5429bef2..3ed6889d14 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -616,7 +616,6 @@ status_t BufferStateLayer::updateActiveBuffer() { mPreviousBufferId = getCurrentBufferId(); mBufferInfo.mBuffer = s.buffer; mBufferInfo.mFence = s.acquireFence; - editCompositionState()->buffer = mBufferInfo.mBuffer; return NO_ERROR; } -- GitLab From 2339279e6f955f38c73c4b39a972b17bbb34d4d3 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Mon, 9 Mar 2020 14:01:06 -0700 Subject: [PATCH 0902/1255] Set reserved size in Gralloc4 to 0 We are not using the reserved size at the moment. Set to zero Bug: 150908307 Test: build, boot, GraphicBuffer_test, GraphicBufferAllocator_test Change-Id: I673063671afcae91bd659279a34169848b89763a --- libs/ui/Gralloc4.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp index 6fd4b80f17..d8e40593e5 100644 --- a/libs/ui/Gralloc4.cpp +++ b/libs/ui/Gralloc4.cpp @@ -77,6 +77,7 @@ static inline void sBufferDescriptorInfo(std::string name, uint32_t width, uint3 outDescriptorInfo->layerCount = layerCount; outDescriptorInfo->format = static_cast(format); outDescriptorInfo->usage = usage; + outDescriptorInfo->reservedSize = 0; } } // anonymous namespace -- GitLab From 6fb599bf5b3a1b33c49dbe97c5afab8901245928 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 5 Mar 2020 13:48:22 -0800 Subject: [PATCH 0903/1255] SurfaceFlinger: no touch boost for layer that explicitly voted Avoid switching to peak refresh rate on touch when we have layers that explicitly voted via setFrateRate() and they occupy > 80% of the screen. Test: App that calls to setFrameRate + touch Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Bug: 147516364 Fixes: 150976355 Change-Id: I3590beeba1c3ff4c9a1b1575a607ef949ca6dd10 --- .../Scheduler/LayerHistoryV2.cpp | 2 - .../Scheduler/RefreshRateConfigs.cpp | 36 +- .../Scheduler/RefreshRateConfigs.h | 6 +- .../surfaceflinger/Scheduler/Scheduler.cpp | 21 +- .../unittests/RefreshRateConfigsTest.cpp | 337 +++++++++++++----- 5 files changed, 289 insertions(+), 113 deletions(-) diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp index 6ef6ce414b..8a14572cb9 100644 --- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp @@ -212,7 +212,5 @@ void LayerHistoryV2::clear() { for (const auto& [layer, info] : activeLayers()) { info->clearHistory(); } - - mActiveLayersEnd = 0; } } // namespace android::scheduler::impl diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 15b158d95f..ae4c3e5fd9 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -95,22 +95,19 @@ std::pair RefreshRateConfigs::getDisplayFrames(nsecs_t layerPe } const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( - const std::vector& layers, bool touchActive) const { + const std::vector& layers, bool touchActive, + bool* touchConsidered) const { ATRACE_CALL(); ALOGV("getRefreshRateForContent %zu layers", layers.size()); + *touchConsidered = false; std::lock_guard lock(mLock); - // For now if the touch is active return the peak refresh rate - // This should be optimized to consider other layers as well. - if (touchActive) { - return *mAvailableRefreshRates.back(); - } - // If there are not layers, there is not content detection, so return the current // refresh rate. if (layers.empty()) { - return getCurrentRefreshRateByPolicyLocked(); + *touchConsidered = touchActive; + return touchActive ? *mAvailableRefreshRates.back() : getCurrentRefreshRateByPolicyLocked(); } int noVoteLayers = 0; @@ -118,17 +115,30 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( int maxVoteLayers = 0; int explicitDefaultVoteLayers = 0; int explicitExactOrMultipleVoteLayers = 0; + float maxExplicitWeight = 0; for (const auto& layer : layers) { - if (layer.vote == LayerVoteType::NoVote) + if (layer.vote == LayerVoteType::NoVote) { noVoteLayers++; - else if (layer.vote == LayerVoteType::Min) + } else if (layer.vote == LayerVoteType::Min) { minVoteLayers++; - else if (layer.vote == LayerVoteType::Max) + } else if (layer.vote == LayerVoteType::Max) { maxVoteLayers++; - else if (layer.vote == LayerVoteType::ExplicitDefault) + } else if (layer.vote == LayerVoteType::ExplicitDefault) { explicitDefaultVoteLayers++; - else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple) + maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); + } else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple) { explicitExactOrMultipleVoteLayers++; + maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); + } + } + + // Consider the touch event if there are no ExplicitDefault layers. + // ExplicitDefault are mostly interactive (as opposed to ExplicitExactOrMultiple) + // and therefore if those posted an explicit vote we should not change it + // if get get a touch event. + if (touchActive && explicitDefaultVoteLayers == 0) { + *touchConsidered = true; + return *mAvailableRefreshRates.back(); } // Only if all layers want Min we should return Min diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index c8aec86db3..d29a3c8337 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -134,9 +134,11 @@ public: // Returns the refresh rate that fits best to the given layers. This function also gets a // boolean flag that indicates whether user touched the screen recently to be factored in when - // choosing the refresh rate. + // choosing the refresh rate and returns whether the refresh rate was chosen as a result of + // a touch event. const RefreshRate& getRefreshRateForContentV2(const std::vector& layers, - bool touchActive) const EXCLUDES(mLock); + bool touchActive, bool* touchConsidered) const + EXCLUDES(mLock); // Returns all the refresh rates supported by the device. This won't change at runtime. const AllRefreshRatesMapType& getAllRefreshRates() const EXCLUDES(mLock); diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 54442391ea..52045dc150 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -483,7 +483,7 @@ void Scheduler::notifyTouchEvent() { // that is currently on top. b/142507166 will give us this capability. std::lock_guard lock(mFeatureStateLock); if (mLayerHistory) { - mLayerHistory->clear(); + // Layer History will be cleared based on RefreshRateConfigs::getRefreshRateForContentV2 mTouchTimer->reset(); @@ -620,10 +620,21 @@ HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() { return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements).configId; } - return mRefreshRateConfigs - .getRefreshRateForContentV2(mFeatures.contentRequirements, - mTouchTimer && mFeatures.touch == TouchState::Active) - .configId; + bool touchConsidered; + const auto& ret = + mRefreshRateConfigs + .getRefreshRateForContentV2(mFeatures.contentRequirements, + mTouchTimer && + mFeatures.touch == TouchState::Active, + &touchConsidered) + .configId; + if (touchConsidered) { + // Clear layer history if refresh rate was selected based on touch to allow + // the hueristic to pick up with the new rate. + mLayerHistory->clear(); + } + + return ret; } std::optional Scheduler::getPreferredConfigId() { diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index e7e7f66c95..9d323962b9 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -21,6 +21,7 @@ #include #include +#include "../../Scheduler/RefreshRateConfigs.h" #include "DisplayHardware/HWC2.h" #include "Scheduler/RefreshRateConfigs.h" @@ -248,6 +249,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { } TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_noLayers) { + bool ignored; std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72}, @@ -263,16 +265,17 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_noLayers) { auto layers = std::vector{}; EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ - false)); + false, &ignored)); // Current refresh rate can always be changed. refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_60); EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ - false)); + false, &ignored)); } TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { + bool ignored; std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; @@ -288,134 +291,163 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { lr.vote = LayerVoteType::Min; lr.name = "Min"; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.vote = LayerVoteType::Max; lr.name = "Max"; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 60.0f; lr.name = "60Hz Heuristic"; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 45.0f; lr.name = "45Hz Heuristic"; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 30.0f; lr.name = "30Hz Heuristic"; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 24.0f; lr.name = "24Hz Heuristic"; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.name = ""; ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0); lr.vote = LayerVoteType::Min; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.vote = LayerVoteType::Max; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 60.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 45.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 30.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 24.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0); lr.vote = LayerVoteType::Min; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.vote = LayerVoteType::Max; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 60.0f; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 45.0f; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 30.0f; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 24.0f; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0); lr.vote = LayerVoteType::Min; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.vote = LayerVoteType::Max; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 60.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 45.0f; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 30.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 24.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); } TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_72_90) { + bool ignored; std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72}, @@ -432,35 +464,43 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_72_90) { lr.vote = LayerVoteType::Min; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.vote = LayerVoteType::Max; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 60.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 45.0f; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 30.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 24.0f; EXPECT_EQ(expected72Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); } TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90_120) { + bool ignored; std::vector configs{ {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}, {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, @@ -486,24 +526,28 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90_120) { lr2.desiredRefreshRate = 60.0f; lr2.vote = LayerVoteType::Heuristic; EXPECT_EQ(expected120Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 48.0f; lr2.vote = LayerVoteType::Heuristic; EXPECT_EQ(expected72Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 48.0f; lr2.vote = LayerVoteType::Heuristic; EXPECT_EQ(expected72Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); } TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_DifferentTypes) { + bool ignored; std::vector configs{ {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}, {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, @@ -531,7 +575,8 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_Different lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; EXPECT_EQ(expected120Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -540,7 +585,8 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_Different lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; EXPECT_EQ(expected120Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -549,7 +595,8 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_Different lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "60Hz ExplicitDefault"; EXPECT_EQ(expected120Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -558,7 +605,8 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_Different lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -567,7 +615,8 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_Different lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz Heuristic"; EXPECT_EQ(expected72Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitDefault; @@ -576,7 +625,8 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_Different lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::Heuristic; @@ -585,7 +635,8 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_Different lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; EXPECT_EQ(expected72Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -594,7 +645,8 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_Different lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; EXPECT_EQ(expected72Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.desiredRefreshRate = 24.0f; lr1.vote = LayerVoteType::ExplicitDefault; @@ -603,10 +655,12 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_Different lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.name = "90Hz ExplicitExactOrMultiple"; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); } TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60) { + bool ignored; std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}}}; @@ -621,35 +675,43 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60) { lr.vote = LayerVoteType::Min; EXPECT_EQ(expected30Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.vote = LayerVoteType::Max; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 60.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 45.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 30.0f; EXPECT_EQ(expected30Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 24.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); } TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90) { + bool ignored; std::vector configs{ {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}, {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, @@ -669,57 +731,71 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90) { lr.vote = LayerVoteType::Min; lr.name = "Min"; EXPECT_EQ(expected30Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.vote = LayerVoteType::Max; lr.name = "Max"; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 90.0f; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr.desiredRefreshRate = 60.0f; lr.name = "60Hz Heuristic"; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true, + &ignored)); lr.desiredRefreshRate = 45.0f; lr.name = "45Hz Heuristic"; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true, + &ignored)); lr.desiredRefreshRate = 30.0f; lr.name = "30Hz Heuristic"; EXPECT_EQ(expected30Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true, + &ignored)); lr.desiredRefreshRate = 24.0f; lr.name = "24Hz Heuristic"; EXPECT_EQ(expected72Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true, + &ignored)); lr.desiredRefreshRate = 24.0f; lr.vote = LayerVoteType::ExplicitExactOrMultiple; lr.name = "24Hz ExplicitExactOrMultiple"; EXPECT_EQ(expected72Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true, + &ignored)); } TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_PriorityTest) { + bool ignored; std::vector configs{ {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}, {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, @@ -739,48 +815,56 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_PriorityTest) { lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::Max; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 24.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 24.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.vote = LayerVoteType::Max; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60.0f; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.vote = LayerVoteType::Max; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60.0f; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 15.0f; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 45.0f; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 30.0f; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 45.0f; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); } TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_24FpsVideo) { + bool ignored; std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; @@ -798,7 +882,8 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_24FpsVideo) { for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { lr.desiredRefreshRate = fps; const auto& refreshRate = - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored); printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str()); EXPECT_EQ(expected60Config, refreshRate); } @@ -833,6 +918,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent_Explici } TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Explicit) { + bool ignored; std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; @@ -852,21 +938,24 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Expli lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 90.0f; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.vote = LayerVoteType::ExplicitDefault; lr1.desiredRefreshRate = 90.0f; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60.0f; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 90.0f; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60.0f; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); } TEST_F(RefreshRateConfigsTest, testInPolicy) { @@ -880,6 +969,7 @@ TEST_F(RefreshRateConfigsTest, testInPolicy) { } TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_75HzContent) { + bool ignored; std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; @@ -897,13 +987,15 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_75HzContent) { for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) { lr.desiredRefreshRate = fps; const auto& refreshRate = - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored); printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str()); EXPECT_EQ(expected90Config, refreshRate); } } TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_Multiples) { + bool ignored; std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; @@ -925,7 +1017,8 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_Multiples) { lr2.desiredRefreshRate = 90.0f; lr2.name = "90Hz Heuristic"; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60.0f; @@ -934,7 +1027,8 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_Multiples) { lr2.desiredRefreshRate = 90.0f; lr2.name = "90Hz ExplicitDefault"; EXPECT_EQ(expected60Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60.0f; @@ -942,7 +1036,8 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_Multiples) { lr2.vote = LayerVoteType::Max; lr2.name = "Max"; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 30.0f; @@ -951,7 +1046,8 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_Multiples) { lr2.desiredRefreshRate = 90.0f; lr2.name = "90Hz Heuristic"; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 30.0f; @@ -959,10 +1055,12 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_Multiples) { lr2.vote = LayerVoteType::Max; lr2.name = "Max"; EXPECT_EQ(expected90Config, - refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false)); + refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, + &ignored)); } TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) { + bool ignored; std::vector configs{ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; @@ -982,28 +1080,32 @@ TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) { lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::NoVote; lr2.name = "NoVote"; - EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false)); + EXPECT_EQ(expected60Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60.0f; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::NoVote; lr2.name = "NoVote"; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, true)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, true, &ignored)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60.0f; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, true)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, true, &ignored)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60.0f; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored)); // The other layer starts to provide buffers lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -1012,7 +1114,60 @@ TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 90.0f; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false)); + EXPECT_EQ(expected90Config, + refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored)); +} + +TEST_F(RefreshRateConfigsTest, touchConsidered) { + bool touchConsidered; + std::vector configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); + + refreshRateConfigs->getRefreshRateForContentV2({}, false, &touchConsidered); + EXPECT_EQ(false, touchConsidered); + + refreshRateConfigs->getRefreshRateForContentV2({}, true, &touchConsidered); + EXPECT_EQ(true, touchConsidered); + + auto layers = std::vector{LayerRequirement{.weight = 1.0f}, + LayerRequirement{.weight = 1.0f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60.0f; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Heuristic; + lr2.name = "NoVote"; + refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered); + EXPECT_EQ(true, touchConsidered); + + lr1.vote = LayerVoteType::ExplicitDefault; + lr1.desiredRefreshRate = 60.0f; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Heuristic; + lr2.name = "NoVote"; + refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered); + EXPECT_EQ(false, touchConsidered); + + lr1.vote = LayerVoteType::ExplicitExactOrMultiple; + lr1.desiredRefreshRate = 60.0f; + lr1.name = "60Hz ExplicitExactOrMultiple"; + lr2.vote = LayerVoteType::Heuristic; + lr2.name = "NoVote"; + refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered); + EXPECT_EQ(true, touchConsidered); + + lr1.vote = LayerVoteType::ExplicitDefault; + lr1.desiredRefreshRate = 60.0f; + lr1.name = "60Hz ExplicitExactrMultiple"; + lr2.vote = LayerVoteType::Heuristic; + lr2.name = "NoVote"; + refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered); + EXPECT_EQ(false, touchConsidered); } } // namespace -- GitLab From 5b8afb5ae3d96a7c82920fada3a5f12f3bcc6bdf Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 6 Mar 2020 14:57:26 -0800 Subject: [PATCH 0904/1255] SurfaceFlinger: treat the desiredRefreshRate of ExplicitDefault as max When a an app calls to ANativeWindow_setFrameRate(..., ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) it usually uses the frame render time to calculate the desired refresh rate. Change the platform side algorithm to consider the desired refresh rate in that case to the highest frame production rate. Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Bug: 147516364 Bug: 150977265 Change-Id: Icda006de0aeb22da8244baee936947495f813e1b --- .../Scheduler/RefreshRateConfigs.cpp | 25 ++++++---- .../unittests/RefreshRateConfigsTest.cpp | 48 +++++++++++++++++++ 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index ae4c3e5fd9..16be5e27b5 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -23,6 +23,9 @@ #include #include +#undef LOG_TAG +#define LOG_TAG "RefreshRateConfigs" + namespace android::scheduler { using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType; @@ -178,16 +181,17 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( const auto layerPeriod = round(1e9f / layer.desiredRefreshRate); if (layer.vote == LayerVoteType::ExplicitDefault) { const auto layerScore = [&]() { - const auto [displayFramesQuot, displayFramesRem] = - getDisplayFrames(layerPeriod, displayPeriod); - if (displayFramesQuot == 0) { - // Layer desired refresh rate is higher the display rate. - return static_cast(layerPeriod) / static_cast(displayPeriod); + // Find the actual rate the layer will render, assuming + // that layerPeriod is the minimal time to render a frame + auto actualLayerPeriod = displayPeriod; + int multiplier = 1; + while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) { + multiplier++; + actualLayerPeriod = displayPeriod * multiplier; } - - return 1.0f - - (static_cast(displayFramesRem) / - static_cast(layerPeriod)); + return std::min(1.0f, + static_cast(layerPeriod) / + static_cast(actualLayerPeriod)); }(); ALOGV("%s (ExplicitDefault, weight %.2f) %.2fHz gives %s score of %.2f", @@ -250,6 +254,7 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( template const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const { + constexpr auto EPSILON = 0.001f; const RefreshRate* bestRefreshRate = begin->first; float max = begin->second; for (auto i = begin; i != end; ++i) { @@ -258,7 +263,7 @@ const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) ATRACE_INT(refreshRate->name.c_str(), round(score * 100)); - if (score > max) { + if (score > max * (1 + EPSILON)) { max = score; bestRefreshRate = refreshRate; } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 9d323962b9..7a11f58cad 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -1170,6 +1170,54 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) { EXPECT_EQ(false, touchConsidered); } +TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_ExplicitDefault) { + bool ignored; + std::vector configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}, + {HWC_CONFIG_ID_120, HWC_GROUP_ID_0, VSYNC_120}}}; + + auto refreshRateConfigs = std::make_unique(configs, /*currentConfigId=*/ + HWC_CONFIG_ID_60); + + auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + auto& lr = layers[0]; + + // Prepare a table with the vote and the expected refresh rate + const std::vector> testCases = { + {130, 120}, {120, 120}, {119, 120}, {110, 120}, + + {100, 90}, {90, 90}, {89, 90}, + + {80, 72}, {73, 72}, {72, 72}, {71, 72}, {70, 72}, + + {65, 60}, {60, 60}, {59, 60}, {58, 60}, + + {55, 90}, {50, 90}, {45, 90}, + + {42, 120}, {40, 120}, {39, 120}, + + {37, 72}, {36, 72}, {35, 72}, + + {30, 60}, + }; + + for (const auto& test : testCases) { + lr.vote = LayerVoteType::ExplicitDefault; + lr.desiredRefreshRate = test.first; + + std::stringstream ss; + ss << "ExplicitDefault " << test.first << " fps"; + lr.name = ss.str(); + + const auto& refreshRate = + refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored); + EXPECT_FLOAT_EQ(refreshRate.fps, test.second) + << "Expecting " << test.first << "fps => " << test.second << "Hz"; + } +} + } // namespace } // namespace scheduler } // namespace android -- GitLab From 8e82b8d99e9ffb73bf3bb3c7c6aaa956e2228a41 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 9 Mar 2020 16:11:00 -0700 Subject: [PATCH 0905/1255] [RenderEngine] Fix use-after-move error GLESREnderEngine::waitFence takes ownership of the file descriptor, so callers must dup it first. Otherwise, this results in a use-after-free error on devices that do not support EGL_ANDROID_native_fence_sync. Bug: 150954608 Test: WITH_TIDY=1 m -j Change-Id: I7e6d88c0f282a317fd8e603dccb918f3d5bc0fcc --- libs/renderengine/gl/GLESRenderEngine.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index e11b59ff24..055182991a 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -973,9 +973,13 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, return NO_ERROR; } - if (bufferFence.get() >= 0 && !waitFence(std::move(bufferFence))) { - ATRACE_NAME("Waiting before draw"); - sync_wait(bufferFence.get(), -1); + if (bufferFence.get() >= 0) { + // Duplicate the fence for passing to waitFence. + base::unique_fd bufferFenceDup(dup(bufferFence.get())); + if (bufferFenceDup < 0 || !waitFence(std::move(bufferFenceDup))) { + ATRACE_NAME("Waiting before draw"); + sync_wait(bufferFence.get(), -1); + } } if (buffer == nullptr) { -- GitLab From 2aa78cbe3ad98182677e65f1c67d3f4d824a03c3 Mon Sep 17 00:00:00 2001 From: Rob Carr Date: Tue, 10 Mar 2020 14:27:49 -0700 Subject: [PATCH 0906/1255] SurfaceFlinger: Avoid overlapping calls to BOOT_FINISHED Handling BOOT_FINISHED we write to mInputFlinger and mWindowManager. This could trigger crashes if we write from multiple concurrent threads or if we try and use it from the main thread while decing the strong pointer. The easiest way to work around this seems to just to only be willing to handle BOOT_FINISHED once, until the WM dies. Bug: 150227563 Bug: 150225569 Test: Existing tests pass Change-Id: I10f4b9359a5f3dc49e3360f28fbe808f0fc2afc8 --- services/surfaceflinger/SurfaceFlinger.cpp | 6 ++++++ services/surfaceflinger/SurfaceFlinger.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 224f093466..29fe5d9e6e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -409,6 +409,7 @@ SurfaceFlinger::~SurfaceFlinger() = default; void SurfaceFlinger::binderDied(const wp& /* who */) { // the window manager died on us. prepare its eulogy. + mBootFinished = false; // restore initial conditions (default device unblank, etc) initializeDisplays(); @@ -525,6 +526,11 @@ compositionengine::CompositionEngine& SurfaceFlinger::getCompositionEngine() con void SurfaceFlinger::bootFinished() { + if (mBootFinished == true) { + ALOGE("Extra call to bootFinished"); + return; + } + mBootFinished = true; if (mStartPropertySetThread->join() != NO_ERROR) { ALOGE("Join StartPropertySetThread failed!"); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index e892faf412..e6b91e6627 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1129,6 +1129,10 @@ private: // to linkToDeath sp mWindowManager; + // We want to avoid multiple calls to BOOT_FINISHED as they come in on + // different threads without a lock and could trigger unsynchronized writes to + // to mWindowManager or mInputFlinger + std::atomic mBootFinished = false; std::unique_ptr mVrFlinger; std::atomic mVrFlingerRequestsDisplay = false; -- GitLab From e17055a1c85e338d0928931d199bd31594ffa8df Mon Sep 17 00:00:00 2001 From: Jon Spivack Date: Fri, 6 Mar 2020 13:58:01 -0800 Subject: [PATCH 0907/1255] LazyServiceRegistrar: Add flag to prevent shutdown This flag can be used to temporarily prevent dynamic services from being killed. For example, if a service needs to perform a task in the background it can set this flag and then disable it once the task is complete. The service will then go back to standard lazy behavior. Bug: 150967269 Test: aidl_lazy_test Change-Id: I840bbe4b6b0406f0e4de610367290448e7edd3de --- cmds/servicemanager/ServiceManager.cpp | 2 ++ libs/binder/LazyServiceRegistrar.cpp | 36 ++++++++++++++++--- .../include/binder/LazyServiceRegistrar.h | 6 ++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index abe64365f3..1e88aaf63b 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -532,6 +532,8 @@ Status ServiceManager::tryUnregisterService(const std::string& name, const sp 2) { // client callbacks are either disabled or there are other clients LOG(INFO) << "Tried to unregister " << name << ", but there are clients: " << clients; + // Set this flag to ensure the clients are acknowledged in the next callback + serviceIt->second.guaranteeClient = true; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp index 71d8130df9..74aece81f7 100644 --- a/libs/binder/LazyServiceRegistrar.cpp +++ b/libs/binder/LazyServiceRegistrar.cpp @@ -31,11 +31,16 @@ using AidlServiceManager = android::os::IServiceManager; class ClientCounterCallback : public ::android::os::BnClientCallback { public: - ClientCounterCallback() : mNumConnectedServices(0) {} + ClientCounterCallback() : mNumConnectedServices(0), mForcePersist(false) {} bool registerService(const sp& service, const std::string& name, bool allowIsolated, int dumpFlags); + /** + * Set a flag to prevent services from automatically shutting down + */ + void forcePersist(bool persist); + protected: Status onClients(const sp& service, bool clients) override; @@ -60,6 +65,8 @@ private: * Map of registered names and services */ std::map mRegisteredServices; + + bool mForcePersist; }; bool ClientCounterCallback::registerService(const sp& service, const std::string& name, @@ -88,6 +95,14 @@ bool ClientCounterCallback::registerService(const sp& service, const st return true; } +void ClientCounterCallback::forcePersist(bool persist) { + mForcePersist = persist; + if(!mForcePersist) { + // Attempt a shutdown in case the number of clients hit 0 while the flag was on + tryShutdown(); + } +} + /** * onClients is oneway, so no need to worry about multi-threading. Note that this means multiple * invocations could occur on different threads however. @@ -103,14 +118,21 @@ Status ClientCounterCallback::onClients(const sp& service, bool clients mNumConnectedServices, mRegisteredServices.size(), String8(service->getInterfaceDescriptor()).string(), clients); - if (mNumConnectedServices == 0) { - tryShutdown(); - } - + tryShutdown(); return Status::ok(); } void ClientCounterCallback::tryShutdown() { + if(mNumConnectedServices > 0) { + // Should only shut down if there are no clients + return; + } + + if(mForcePersist) { + ALOGI("Shutdown prevented by forcePersist override flag."); + return; + } + ALOGI("Trying to shut down the service. No clients in use for any service in process."); auto manager = interface_cast(asBinder(defaultServiceManager())); @@ -165,5 +187,9 @@ status_t LazyServiceRegistrar::registerService(const sp& service, const return OK; } +void LazyServiceRegistrar::forcePersist(bool persist) { + mClientCC->forcePersist(persist); +} + } // namespace hardware } // namespace android \ No newline at end of file diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h index efdecc4eca..6d711bc10f 100644 --- a/libs/binder/include/binder/LazyServiceRegistrar.h +++ b/libs/binder/include/binder/LazyServiceRegistrar.h @@ -34,6 +34,12 @@ class LazyServiceRegistrar { const std::string& name = "default", bool allowIsolated = false, int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT); + /** + * Force the service to persist, even when it has 0 clients. + * If setting this flag from the server side, make sure to do so before calling registerService, + * or there may be a race with the default dynamic shutdown. + */ + void forcePersist(bool persist); private: std::shared_ptr mClientCC; -- GitLab From 5793c7d8d85e25a4226178a96b3b7f81a76da501 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 10 Mar 2020 19:55:50 -0700 Subject: [PATCH 0908/1255] [SurfaceFlinger] Resolve deadlock in SurfaceTracing. SurfaceTracing cannot acquire mStateLock while mDrawingStateLock is held. SurfaceTracing only needs to acquire mStateLock for getting the default DisplayDevice for getting a layer's HWC composition type. As a workaround, grab the DisplayDevice ahead of time. Bug: 151108871 Test: builds Change-Id: I84a76694e9890242c666ec5e3eb04d4114f8240a --- services/surfaceflinger/SurfaceFlinger.cpp | 12 +++++++----- services/surfaceflinger/SurfaceFlinger.h | 3 ++- services/surfaceflinger/SurfaceTracing.cpp | 11 +++++++---- services/surfaceflinger/SurfaceTracing.h | 10 +++++++--- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 29fe5d9e6e..30528190d8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4482,12 +4482,11 @@ void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { result.append("\n"); } -LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { - Mutex::Autolock _l(mStateLock); - const auto device = getDefaultDisplayDeviceLocked(); +LayersProto SurfaceFlinger::dumpDrawingStateProto( + uint32_t traceFlags, const sp& displayDevice) const { LayersProto layersProto; for (const sp& layer : mDrawingState.layersSortedByZ) { - layer->writeToProto(layersProto, traceFlags, device); + layer->writeToProto(layersProto, traceFlags, displayDevice); } return layersProto; @@ -4519,7 +4518,10 @@ void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) { LayersProto layersProto; - postMessageSync(new LambdaMessage([&]() { layersProto = dumpDrawingStateProto(traceFlags); })); + postMessageSync(new LambdaMessage([&]() { + const auto& displayDevice = getDefaultDisplayDeviceLocked(); + layersProto = dumpDrawingStateProto(traceFlags, displayDevice); + })); return layersProto; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index e6b91e6627..ba265adc39 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -923,7 +923,8 @@ private: void dumpDisplayIdentificationData(std::string& result) const; void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const; void dumpWideColorInfo(std::string& result) const; - LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL, + const sp& displayDevice = nullptr) const; void dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; // Dumps state from HW Composer diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp index c5556ec28f..20c8d7a3aa 100644 --- a/services/surfaceflinger/SurfaceTracing.cpp +++ b/services/surfaceflinger/SurfaceTracing.cpp @@ -45,19 +45,21 @@ void SurfaceTracing::mainLoop() { } void SurfaceTracing::addFirstEntry() { + const auto displayDevice = mFlinger.getDefaultDisplayDevice(); LayersTraceProto entry; { std::scoped_lock lock(mSfLock); - entry = traceLayersLocked("tracing.enable"); + entry = traceLayersLocked("tracing.enable", displayDevice); } addTraceToBuffer(entry); } LayersTraceProto SurfaceTracing::traceWhenNotified() { + const auto displayDevice = mFlinger.getDefaultDisplayDevice(); std::unique_lock lock(mSfLock); mCanStartTrace.wait(lock); android::base::ScopedLockAssertion assumeLock(mSfLock); - LayersTraceProto entry = traceLayersLocked(mWhere); + LayersTraceProto entry = traceLayersLocked(mWhere, displayDevice); lock.unlock(); return entry; } @@ -160,13 +162,14 @@ void SurfaceTracing::setTraceFlags(uint32_t flags) { mTraceFlags = flags; } -LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) { +LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where, + const sp& displayDevice) { ATRACE_CALL(); LayersTraceProto entry; entry.set_elapsed_realtime_nanos(elapsedRealtimeNano()); entry.set_where(where); - LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags)); + LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags, displayDevice)); mFlinger.dumpOffscreenLayersProto(layers); entry.mutable_layers()->Swap(&layers); diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index 3c24881d7c..4b9f7778ed 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -16,17 +16,19 @@ #pragma once +#include #include #include #include -#include #include #include #include #include #include +#include "DisplayDevice.h" + using namespace android::surfaceflinger; namespace android { @@ -85,13 +87,15 @@ private: void mainLoop(); void addFirstEntry(); LayersTraceProto traceWhenNotified(); - LayersTraceProto traceLayersLocked(const char* where) REQUIRES(mSfLock); + LayersTraceProto traceLayersLocked(const char* where, + const sp& displayDevice) + REQUIRES(mSfLock); // Returns true if trace is enabled. bool addTraceToBuffer(LayersTraceProto& entry); void writeProtoFileLocked() REQUIRES(mTraceLock); - const SurfaceFlinger& mFlinger; + SurfaceFlinger& mFlinger; status_t mLastErr = NO_ERROR; std::thread mThread; std::condition_variable mCanStartTrace; -- GitLab From 4df68ab970391e00f3312d3c832224a04c1a40f9 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Wed, 11 Mar 2020 18:12:01 +0800 Subject: [PATCH 0909/1255] Fix touch fails after drag and drop The drag surface would reparent to null in the end of drag & drop. But the deatched layer didn't dirty the input cause InputFlinger would not receive the latest input windows. - Dirty input when remove layer from current state. Bug: 151171041 Test: atest DragDropTest CrossAppDragAndDropTests Change-Id: I3cf9b063801260f276eb20b3aa474b4b3e692cfb --- services/surfaceflinger/Layer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3765d0d39d..1b9246e2c6 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -219,6 +219,9 @@ void Layer::removeFromCurrentState() { } mFlinger->markLayerPendingRemovalLocked(this); + if (hasInput()) { + mFlinger->dirtyInput(); + } } void Layer::onRemovedFromCurrentState() { -- GitLab From f59c2b7ad16b19ba00765d75d38fec74fe8f9435 Mon Sep 17 00:00:00 2001 From: Paul Chang Date: Tue, 10 Mar 2020 02:08:55 +0800 Subject: [PATCH 0910/1255] Take screenshot only when screenshot is requested - Take screenshot only when screenshot is requested for preventing from taking screenshot unnecessarily BUG: 149525300 Test: Flash and test interactive/full bugreports generated using Shell, and Shell flow does not break during tests Change-Id: Ie5cbe97f9e6e32fecc3d95893b9804b6e716c628 --- cmds/dumpstate/DumpstateService.cpp | 5 +++-- cmds/dumpstate/DumpstateService.h | 3 ++- cmds/dumpstate/binder/android/os/IDumpstate.aidl | 4 +++- cmds/dumpstate/dumpstate.cpp | 14 ++++++++------ cmds/dumpstate/dumpstate.h | 3 ++- cmds/dumpstate/tests/dumpstate_smoke_test.cpp | 8 ++++---- cmds/dumpstate/tests/dumpstate_test.cpp | 12 ++++++------ 7 files changed, 28 insertions(+), 21 deletions(-) diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp index 466575f2fa..a0b9cbbe20 100644 --- a/cmds/dumpstate/DumpstateService.cpp +++ b/cmds/dumpstate/DumpstateService.cpp @@ -84,7 +84,8 @@ binder::Status DumpstateService::startBugreport(int32_t calling_uid, android::base::unique_fd bugreport_fd, android::base::unique_fd screenshot_fd, int bugreport_mode, - const sp& listener) { + const sp& listener, + bool is_screenshot_requested) { MYLOGI("startBugreport() with mode: %d\n", bugreport_mode); // Ensure there is only one bugreport in progress at a time. @@ -118,7 +119,7 @@ binder::Status DumpstateService::startBugreport(int32_t calling_uid, std::unique_ptr options = std::make_unique(); options->Initialize(static_cast(bugreport_mode), bugreport_fd, - screenshot_fd); + screenshot_fd, is_screenshot_requested); if (bugreport_fd.get() == -1 || (options->do_screenshot && screenshot_fd.get() == -1)) { MYLOGE("Invalid filedescriptor"); diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h index 6dc0225f02..ac8d3acbb5 100644 --- a/cmds/dumpstate/DumpstateService.h +++ b/cmds/dumpstate/DumpstateService.h @@ -41,7 +41,8 @@ class DumpstateService : public BinderService, public BnDumpst binder::Status startBugreport(int32_t calling_uid, const std::string& calling_package, android::base::unique_fd bugreport_fd, android::base::unique_fd screenshot_fd, int bugreport_mode, - const sp& listener) override; + const sp& listener, + bool is_screenshot_requested) override; // No-op binder::Status cancelBugreport(); diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl index 3f359c86c5..ba008bb27e 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl @@ -64,10 +64,12 @@ interface IDumpstate { * @param screenshotFd the file to which screenshot should be written * @param bugreportMode the mode that specifies other run time options; must be one of above * @param listener callback for updates; optional + * @param isScreenshotRequested indicates screenshot is requested or not */ void startBugreport(int callingUid, @utf8InCpp String callingPackage, FileDescriptor bugreportFd, FileDescriptor screenshotFd, - int bugreportMode, IDumpstateListener listener); + int bugreportMode, IDumpstateListener listener, + boolean isScreenshotRequested); /* * Cancels the bugreport currently in progress. diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index e7029bd0db..733b71eb56 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -2247,20 +2247,21 @@ static inline const char* ModeToString(Dumpstate::BugreportMode mode) { } } -static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) { +static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options, + bool is_screenshot_requested) { // Modify com.android.shell.BugreportProgressService#isDefaultScreenshotRequired as well for // default system screenshots. options->bugreport_mode = ModeToString(mode); switch (mode) { case Dumpstate::BugreportMode::BUGREPORT_FULL: - options->do_screenshot = true; + options->do_screenshot = is_screenshot_requested; options->dumpstate_hal_mode = DumpstateMode::FULL; break; case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE: // Currently, the dumpstate binder is only used by Shell to update progress. options->do_start_service = true; options->do_progress_updates = true; - options->do_screenshot = true; + options->do_screenshot = is_screenshot_requested; options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE; break; case Dumpstate::BugreportMode::BUGREPORT_REMOTE: @@ -2273,7 +2274,7 @@ static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOpt options->do_start_service = true; options->do_progress_updates = true; options->do_zip_file = true; - options->do_screenshot = true; + options->do_screenshot = is_screenshot_requested; options->dumpstate_hal_mode = DumpstateMode::WEAR; break; // TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY. @@ -2310,7 +2311,8 @@ static void LogDumpOptions(const Dumpstate::DumpOptions& options) { void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode, const android::base::unique_fd& bugreport_fd_in, - const android::base::unique_fd& screenshot_fd_in) { + const android::base::unique_fd& screenshot_fd_in, + bool is_screenshot_requested) { // In the new API world, date is always added; output is always a zip file. // TODO(111441001): remove these options once they are obsolete. do_add_date = true; @@ -2320,7 +2322,7 @@ void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode, bugreport_fd.reset(dup(bugreport_fd_in.get())); screenshot_fd.reset(dup(screenshot_fd_in.get())); - SetOptionsFromMode(bugreport_mode, this); + SetOptionsFromMode(bugreport_mode, this, is_screenshot_requested); } Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) { diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 7e277873cb..7b8d2821e5 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -390,7 +390,8 @@ class Dumpstate { /* Initializes options from the requested mode. */ void Initialize(BugreportMode bugreport_mode, const android::base::unique_fd& bugreport_fd, - const android::base::unique_fd& screenshot_fd); + const android::base::unique_fd& screenshot_fd, + bool is_screenshot_requested); /* Returns true if the options set so far are consistent. */ bool ValidateOptions() const; diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp index f26e4db976..047a1c38f0 100644 --- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp @@ -451,7 +451,7 @@ TEST_F(DumpstateBinderTest, Baseline) { sp listener(new DumpstateListener(dup(fileno(stdout)))); android::binder::Status status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd), - Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener); + Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener, true); // startBugreport is an async call. Verify binder call succeeded first, then wait till listener // gets expected callbacks. EXPECT_TRUE(status.isOk()); @@ -488,7 +488,7 @@ TEST_F(DumpstateBinderTest, ServiceDies_OnInvalidInput) { android::binder::Status status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd), 2000, // invalid bugreport mode - listener); + listener, false); EXPECT_EQ(listener->getErrorCode(), IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT); // The service should have died, freeing itself up for a new invocation. @@ -519,13 +519,13 @@ TEST_F(DumpstateBinderTest, SimultaneousBugreportsNotAllowed) { sp listener1(new DumpstateListener(dup(fileno(stdout)))); android::binder::Status status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd), - Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1); + Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1, true); EXPECT_TRUE(status.isOk()); // try to make another call to startBugreport. This should fail. sp listener2(new DumpstateListener(dup(fileno(stdout)))); status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd2), std::move(screenshot_fd2), - Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2); + Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2, true); EXPECT_FALSE(status.isOk()); WaitTillExecutionComplete(listener2.get()); EXPECT_EQ(listener2->getErrorCode(), diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 0a0c40ee0d..2efb130776 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -233,7 +233,7 @@ TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) { } TEST_F(DumpOptionsTest, InitializeFullBugReport) { - options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd, true); EXPECT_TRUE(options_.do_add_date); EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); @@ -250,7 +250,7 @@ TEST_F(DumpOptionsTest, InitializeFullBugReport) { } TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) { - options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd, true); EXPECT_TRUE(options_.do_add_date); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.do_progress_updates); @@ -267,7 +267,7 @@ TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) { } TEST_F(DumpOptionsTest, InitializeRemoteBugReport) { - options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd, false); EXPECT_TRUE(options_.do_add_date); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.is_remote_mode); @@ -283,7 +283,7 @@ TEST_F(DumpOptionsTest, InitializeRemoteBugReport) { } TEST_F(DumpOptionsTest, InitializeWearBugReport) { - options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd, true); EXPECT_TRUE(options_.do_add_date); EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); @@ -300,7 +300,7 @@ TEST_F(DumpOptionsTest, InitializeWearBugReport) { } TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) { - options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd, false); EXPECT_TRUE(options_.do_add_date); EXPECT_FALSE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); @@ -317,7 +317,7 @@ TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) { } TEST_F(DumpOptionsTest, InitializeWifiBugReport) { - options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd, false); EXPECT_TRUE(options_.do_add_date); EXPECT_FALSE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); -- GitLab From 0854b996a3c1f0b7f065d6767e0aac297afbdbac Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 11 Mar 2020 12:09:42 -0700 Subject: [PATCH 0911/1255] SurfaceFlinger: Ignore mInputDirty if syncing input-windows. It's possible we sync input windows but then don't actually have any changes resulting in input being dirtied. This could lead to extremly long waits on Binder threads and "Set transaction state timed-out" errors. To fix this we ignore the cache state if we are processing a sync command. I thought about just not invoking setInputWindows and signalling the CV but I thought maybe someone could be relying on the fencing semantics of syncInputWindows even in cases where this transaction had no change. Bug: 151182359 Test: android.media.cts.EncodeVirtualDisplayWithCompositionTest Change-Id: Ia4e5f21c37db68a1a3bec36051c34df3be5fce52 --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 29fe5d9e6e..91b1c73419 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2800,7 +2800,7 @@ void SurfaceFlinger::updateInputWindowInfo() { // input changes but all input changes will spring from these transactions // so the cache is safe but not optimal. It seems like it might be annoyingly // costly to cache and comapre the actual InputWindowHandle vector though. - if (!mInputDirty) { + if (!mInputDirty && !mInputWindowCommands.syncInputWindows) { return; } -- GitLab From 73d9f7833d1e29c2af616b903edb8764ab3c8dc8 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Thu, 5 Mar 2020 15:06:19 -0800 Subject: [PATCH 0912/1255] Rename featureId -> attributionTag Bug: 148792795 Test: TH Change-Id: Ic56606795e5e68ba76794198faf496eec6d87cd0 Exempt-From-Owner-Approval: API rename Merged-In: Ic56606795e5e68ba76794198faf496eec6d87cd0 --- libs/binder/AppOpsManager.cpp | 14 +++++----- libs/binder/IAppOpsService.cpp | 30 ++++++++++----------- libs/binder/include/binder/AppOpsManager.h | 6 ++--- libs/binder/include/binder/IAppOpsService.h | 6 ++--- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index 43b0da307b..2174ce2a88 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -96,11 +96,11 @@ int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPa } int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::unique_ptr& featureId, const String16& message) { + const std::unique_ptr& attributionTag, const String16& message) { sp service = getService(); int32_t mode = service != nullptr - ? service->noteOperation(op, uid, callingPackage, featureId, shouldCollectNotes(op), - message) + ? service->noteOperation(op, uid, callingPackage, attributionTag, + shouldCollectNotes(op), message) : AppOpsManager::MODE_IGNORED; return mode; @@ -113,12 +113,12 @@ int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& c } int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, - bool startIfModeDefault, const std::unique_ptr& featureId, + bool startIfModeDefault, const std::unique_ptr& attributionTag, const String16& message) { sp service = getService(); int32_t mode = service != nullptr ? service->startOperation(getClientId(), op, uid, callingPackage, - featureId, startIfModeDefault, shouldCollectNotes(op), message) + attributionTag, startIfModeDefault, shouldCollectNotes(op), message) : AppOpsManager::MODE_IGNORED; return mode; @@ -129,10 +129,10 @@ void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPac } void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::unique_ptr& callingFeatureId) { + const std::unique_ptr& attributionTag) { sp service = getService(); if (service != nullptr) { - service->finishOperation(getClientId(), op, uid, callingPackage, callingFeatureId); + service->finishOperation(getClientId(), op, uid, callingPackage, attributionTag); } } diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index a5555a304f..0714723e02 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -47,14 +47,14 @@ public: } virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName, - const std::unique_ptr& featureId, bool shouldCollectAsyncNotedOp, + const std::unique_ptr& attributionTag, bool shouldCollectAsyncNotedOp, const String16& message) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); - data.writeString16(featureId); + data.writeString16(attributionTag); data.writeInt32(shouldCollectAsyncNotedOp ? 1 : 0); data.writeString16(message); remote()->transact(NOTE_OPERATION_TRANSACTION, data, &reply); @@ -64,7 +64,7 @@ public: } virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName, const std::unique_ptr& featureId, + const String16& packageName, const std::unique_ptr& attributionTag, bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); @@ -72,7 +72,7 @@ public: data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); - data.writeString16(featureId); + data.writeString16(attributionTag); data.writeInt32(startIfModeDefault ? 1 : 0); data.writeInt32(shouldCollectAsyncNotedOp ? 1 : 0); data.writeString16(message); @@ -83,14 +83,14 @@ public: } virtual void finishOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName, const std::unique_ptr& featureId) { + const String16& packageName, const std::unique_ptr& attributionTag) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeStrongBinder(token); data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); - data.writeString16(featureId); + data.writeString16(attributionTag); remote()->transact(FINISH_OPERATION_TRANSACTION, data, &reply); } @@ -182,11 +182,11 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - std::unique_ptr featureId; - data.readString16(&featureId); + std::unique_ptr attributionTag; + data.readString16(&attributionTag); bool shouldCollectAsyncNotedOp = data.readInt32() == 1; String16 message = data.readString16(); - int32_t res = noteOperation(code, uid, packageName, featureId, + int32_t res = noteOperation(code, uid, packageName, attributionTag, shouldCollectAsyncNotedOp, message); reply->writeNoException(); reply->writeInt32(res); @@ -198,12 +198,12 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - std::unique_ptr featureId; - data.readString16(&featureId); + std::unique_ptr attributionTag; + data.readString16(&attributionTag); bool startIfModeDefault = data.readInt32() == 1; bool shouldCollectAsyncNotedOp = data.readInt32() == 1; String16 message = data.readString16(); - int32_t res = startOperation(token, code, uid, packageName, featureId, + int32_t res = startOperation(token, code, uid, packageName, attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message); reply->writeNoException(); reply->writeInt32(res); @@ -215,9 +215,9 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - std::unique_ptr featureId; - data.readString16(&featureId); - finishOperation(token, code, uid, packageName, featureId); + std::unique_ptr attributionTag; + data.readString16(&attributionTag); + finishOperation(token, code, uid, packageName, attributionTag); reply->writeNoException(); return NO_ERROR; } break; diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index 5b6eb6863e..2ee5930f2b 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -134,18 +134,18 @@ public: // const String16&) instead int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage); int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::unique_ptr& featureId, const String16& message); + const std::unique_ptr& attributionTag, const String16& message); // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&, // const String16&) instead int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, bool startIfModeDefault); int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, - bool startIfModeDefault, const std::unique_ptr& featureId, + bool startIfModeDefault, const std::unique_ptr& attributionTag, const String16& message); // @Deprecated, use finishOp(int32_t, int32_t, const String16&, bool, const String16&) instead void finishOp(int32_t op, int32_t uid, const String16& callingPackage); void finishOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::unique_ptr& featureId); + const std::unique_ptr& attributionTag); void startWatchingMode(int32_t op, const String16& packageName, const sp& callback); void stopWatchingMode(const sp& callback); diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index 1b4bcce20f..1ffb8deaba 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -36,13 +36,13 @@ public: virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName, - const std::unique_ptr& featureId, bool shouldCollectAsyncNotedOp, + const std::unique_ptr& attributionTag, bool shouldCollectAsyncNotedOp, const String16& message) = 0; virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName, const std::unique_ptr& featureId, + const String16& packageName, const std::unique_ptr& attributionTag, bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) = 0; virtual void finishOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName, const std::unique_ptr& featureId) = 0; + const String16& packageName, const std::unique_ptr& attributionTag) = 0; virtual void startWatchingMode(int32_t op, const String16& packageName, const sp& callback) = 0; virtual void stopWatchingMode(const sp& callback) = 0; -- GitLab From 3f6efd831564cb05d3c7e7699b009e3e7cbcf4da Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Thu, 5 Mar 2020 15:06:19 -0800 Subject: [PATCH 0913/1255] Rename featureId -> attributionTag Bug: 148792795 Test: TH Change-Id: Ic56606795e5e68ba76794198faf496eec6d87cd0 Exempt-From-Owner-Approval: API rename Merged-In: Ic56606795e5e68ba76794198faf496eec6d87cd0 --- libs/binder/AppOpsManager.cpp | 14 +++++----- libs/binder/IAppOpsService.cpp | 30 ++++++++++----------- libs/binder/include/binder/AppOpsManager.h | 6 ++--- libs/binder/include/binder/IAppOpsService.h | 6 ++--- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index e732829ada..1c6b49135d 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -96,11 +96,11 @@ int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPa } int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::optional& featureId, const String16& message) { + const std::optional& attributionTag, const String16& message) { sp service = getService(); int32_t mode = service != nullptr - ? service->noteOperation(op, uid, callingPackage, featureId, shouldCollectNotes(op), - message) + ? service->noteOperation(op, uid, callingPackage, attributionTag, + shouldCollectNotes(op), message) : AppOpsManager::MODE_IGNORED; return mode; @@ -113,12 +113,12 @@ int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& c } int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, - bool startIfModeDefault, const std::optional& featureId, + bool startIfModeDefault, const std::optional& attributionTag, const String16& message) { sp service = getService(); int32_t mode = service != nullptr ? service->startOperation(getClientId(), op, uid, callingPackage, - featureId, startIfModeDefault, shouldCollectNotes(op), message) + attributionTag, startIfModeDefault, shouldCollectNotes(op), message) : AppOpsManager::MODE_IGNORED; return mode; @@ -129,10 +129,10 @@ void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPac } void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::optional& callingFeatureId) { + const std::optional& attributionTag) { sp service = getService(); if (service != nullptr) { - service->finishOperation(getClientId(), op, uid, callingPackage, callingFeatureId); + service->finishOperation(getClientId(), op, uid, callingPackage, attributionTag); } } diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index 50e23b50a7..cd78866624 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -49,14 +49,14 @@ public: } virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName, - const std::optional& featureId, bool shouldCollectAsyncNotedOp, + const std::optional& attributionTag, bool shouldCollectAsyncNotedOp, const String16& message) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); - data.writeString16(featureId); + data.writeString16(attributionTag); data.writeInt32(shouldCollectAsyncNotedOp ? 1 : 0); data.writeString16(message); remote()->transact(NOTE_OPERATION_TRANSACTION, data, &reply); @@ -66,7 +66,7 @@ public: } virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName, const std::optional& featureId, + const String16& packageName, const std::optional& attributionTag, bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); @@ -74,7 +74,7 @@ public: data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); - data.writeString16(featureId); + data.writeString16(attributionTag); data.writeInt32(startIfModeDefault ? 1 : 0); data.writeInt32(shouldCollectAsyncNotedOp ? 1 : 0); data.writeString16(message); @@ -85,14 +85,14 @@ public: } virtual void finishOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName, const std::optional& featureId) { + const String16& packageName, const std::optional& attributionTag) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeStrongBinder(token); data.writeInt32(code); data.writeInt32(uid); data.writeString16(packageName); - data.writeString16(featureId); + data.writeString16(attributionTag); remote()->transact(FINISH_OPERATION_TRANSACTION, data, &reply); } @@ -184,11 +184,11 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - std::optional featureId; - data.readString16(&featureId); + std::optional attributionTag; + data.readString16(&attributionTag); bool shouldCollectAsyncNotedOp = data.readInt32() == 1; String16 message = data.readString16(); - int32_t res = noteOperation(code, uid, packageName, featureId, + int32_t res = noteOperation(code, uid, packageName, attributionTag, shouldCollectAsyncNotedOp, message); reply->writeNoException(); reply->writeInt32(res); @@ -200,12 +200,12 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - std::optional featureId; - data.readString16(&featureId); + std::optional attributionTag; + data.readString16(&attributionTag); bool startIfModeDefault = data.readInt32() == 1; bool shouldCollectAsyncNotedOp = data.readInt32() == 1; String16 message = data.readString16(); - int32_t res = startOperation(token, code, uid, packageName, featureId, + int32_t res = startOperation(token, code, uid, packageName, attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp, message); reply->writeNoException(); reply->writeInt32(res); @@ -217,9 +217,9 @@ status_t BnAppOpsService::onTransact( int32_t code = data.readInt32(); int32_t uid = data.readInt32(); String16 packageName = data.readString16(); - std::optional featureId; - data.readString16(&featureId); - finishOperation(token, code, uid, packageName, featureId); + std::optional attributionTag; + data.readString16(&attributionTag); + finishOperation(token, code, uid, packageName, attributionTag); reply->writeNoException(); return NO_ERROR; } break; diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index e4641822ad..4169243c1f 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -136,18 +136,18 @@ public: // const String16&) instead int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage); int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::optional& featureId, const String16& message); + const std::optional& attributionTag, const String16& message); // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&, // const String16&) instead int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, bool startIfModeDefault); int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, - bool startIfModeDefault, const std::optional& featureId, + bool startIfModeDefault, const std::optional& attributionTag, const String16& message); // @Deprecated, use finishOp(int32_t, int32_t, const String16&, bool, const String16&) instead void finishOp(int32_t op, int32_t uid, const String16& callingPackage); void finishOp(int32_t op, int32_t uid, const String16& callingPackage, - const std::optional& featureId); + const std::optional& attributionTag); void startWatchingMode(int32_t op, const String16& packageName, const sp& callback); void stopWatchingMode(const sp& callback); diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index 95a80ff268..a4a20c8b10 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -38,13 +38,13 @@ public: virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName, - const std::optional& featureId, bool shouldCollectAsyncNotedOp, + const std::optional& attributionTag, bool shouldCollectAsyncNotedOp, const String16& message) = 0; virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName, const std::optional& featureId, + const String16& packageName, const std::optional& attributionTag, bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) = 0; virtual void finishOperation(const sp& token, int32_t code, int32_t uid, - const String16& packageName, const std::optional& featureId) = 0; + const String16& packageName, const std::optional& attributionTag) = 0; virtual void startWatchingMode(int32_t op, const String16& packageName, const sp& callback) = 0; virtual void stopWatchingMode(const sp& callback) = 0; -- GitLab From 316be1d90807543dbe0fea925062351bd08d276e Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 6 Mar 2020 21:54:36 -0800 Subject: [PATCH 0914/1255] Remove mips. Test: treehugger Change-Id: Ifac6515bb84c8da2faf53ef310caec7adff3f234 -- GitLab From 858c55f73a760a06ac398562a9274641239e1322 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 11 Mar 2020 17:48:31 -0700 Subject: [PATCH 0915/1255] sf: avoid assumption remote binder is local We are lucky that a test was passing a remote binder here and that I happened to reorder elements in BpBinder, since this caused a crash, where before, 'owner' was getting set to some random bits inside of a BpBinder object. Bug: 150904694 Test: move mTrackingUid around in BpBinder, then `atest CompositionSamplingListenerTest` passes Change-Id: I552a669113844a6b7ceaba5a1197fd04ca7e18d5 --- services/surfaceflinger/RegionSamplingThread.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 0031d70160..68cd84f661 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -201,9 +201,10 @@ RegionSamplingThread::~RegionSamplingThread() { void RegionSamplingThread::addListener(const Rect& samplingArea, const sp& stopLayerHandle, const sp& listener) { - wp stopLayer = stopLayerHandle != nullptr - ? static_cast(stopLayerHandle.get())->owner - : nullptr; + wp stopLayer; + if (stopLayerHandle != nullptr && stopLayerHandle->localBinder() != nullptr) { + stopLayer = static_cast(stopLayerHandle.get())->owner; + } sp asBinder = IInterface::asBinder(listener); asBinder->linkToDeath(this); -- GitLab From a276b054b4d04bd085b558dad79b732660d7fea3 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Sat, 7 Mar 2020 22:53:54 +0900 Subject: [PATCH 0916/1255] Add aidl::nullable type for nullable in AIDL This provides source-level compatibility between new(std::optional) and old(std::unique_ptr). Bug: 144773267 Test: m Merged-In: I378dbf848a51a705a9e06f9cd4b0def9728c3bff Change-Id: I378dbf848a51a705a9e06f9cd4b0def9728c3bff (cherry picked from commit debae060db85753036c9a4132d90b1017839547c) Exempt-From-Owner-Approval: cherry-pick from master --- libs/binder/include/binder/Nullable.h | 44 +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 libs/binder/include/binder/Nullable.h diff --git a/libs/binder/include/binder/Nullable.h b/libs/binder/include/binder/Nullable.h new file mode 100644 index 0000000000..a98583dc16 --- /dev/null +++ b/libs/binder/include/binder/Nullable.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include + +namespace android { + +namespace aidl { + +// nullable/make_nullable provide source-level compatibility between std::opional and std::unique_ptr +// usage: +// nullable a; +// nullable b = make_nullable(...); +// auto c = make_nullable(...); +// c.reset(); +// c = make_nullable(...); +// c = std::move(a); + +template +using nullable = std::optional; + +template +inline nullable make_nullable(Args&&... args) { + return std::make_optional(std::forward(args)...); +} + +} // namespace aidl + +} // namespace android \ No newline at end of file -- GitLab From 65d85bfe14c304eadc24653d1bf64fbc752ca49d Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Thu, 12 Mar 2020 07:03:46 +0000 Subject: [PATCH 0917/1255] Revert "Add aidl::nullable type for nullable in AIDL" Revert "Use aidl::nullable for nullable type in C++" Revert submission 10632869-nullable-compat-rvc-dev-plus-aosp Reason for revert: incorrect merged-in line Reverted Changes: I33822bc76:Use aidl::nullable for nullable type in C++ I378dbf848:Add aidl::nullable type for nullable in AIDL Change-Id: Idcdb59e74d050768aff5f44819a13831c2ce9899 Exempt-From-Owner-Approval: revert wrong submission --- libs/binder/include/binder/Nullable.h | 44 --------------------------- 1 file changed, 44 deletions(-) delete mode 100644 libs/binder/include/binder/Nullable.h diff --git a/libs/binder/include/binder/Nullable.h b/libs/binder/include/binder/Nullable.h deleted file mode 100644 index a98583dc16..0000000000 --- a/libs/binder/include/binder/Nullable.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include -#include - -namespace android { - -namespace aidl { - -// nullable/make_nullable provide source-level compatibility between std::opional and std::unique_ptr -// usage: -// nullable a; -// nullable b = make_nullable(...); -// auto c = make_nullable(...); -// c.reset(); -// c = make_nullable(...); -// c = std::move(a); - -template -using nullable = std::optional; - -template -inline nullable make_nullable(Args&&... args) { - return std::make_optional(std::forward(args)...); -} - -} // namespace aidl - -} // namespace android \ No newline at end of file -- GitLab From 175753ba48a88d524be89afbe05ea0fd6806ea4f Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Sat, 7 Mar 2020 22:53:54 +0900 Subject: [PATCH 0918/1255] Add aidl::nullable type for nullable in AIDL This provides source-level compatibility between new(std::optional) and old(std::unique_ptr). Bug: 144773267 Test: m (cherry picked from commit debae060db85753036c9a4132d90b1017839547c) Change-Id: I258f3bf66b168c4ffe3e528ac1dc5be2076a3b66 Merged-In: I378dbf848a51a705a9e06f9cd4b0def9728c3bff Exempt-From-Owner-Approval: approved in master. --- libs/binder/include/binder/Nullable.h | 44 +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 libs/binder/include/binder/Nullable.h diff --git a/libs/binder/include/binder/Nullable.h b/libs/binder/include/binder/Nullable.h new file mode 100644 index 0000000000..a98583dc16 --- /dev/null +++ b/libs/binder/include/binder/Nullable.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include + +namespace android { + +namespace aidl { + +// nullable/make_nullable provide source-level compatibility between std::opional and std::unique_ptr +// usage: +// nullable a; +// nullable b = make_nullable(...); +// auto c = make_nullable(...); +// c.reset(); +// c = make_nullable(...); +// c = std::move(a); + +template +using nullable = std::optional; + +template +inline nullable make_nullable(Args&&... args) { + return std::make_optional(std::forward(args)...); +} + +} // namespace aidl + +} // namespace android \ No newline at end of file -- GitLab From ed9884cd37bfe1cf29dd25eae0018500139ff762 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Sat, 7 Mar 2020 22:53:54 +0900 Subject: [PATCH 0919/1255] Add aidl::nullable type for nullable in AIDL This provides source-level compatibility between new(std::optional) and old(std::unique_ptr). Bug: 144773267 Test: m Merged-In: I258f3bf66b168c4ffe3e528ac1dc5be2076a3b66 Merged-In: I378dbf848a51a705a9e06f9cd4b0def9728c3bff Change-Id: I378dbf848a51a705a9e06f9cd4b0def9728c3bff (cherry picked from commit debae060db85753036c9a4132d90b1017839547c) Exempt-From-Owner-Approval: cp from master with owner's approval --- libs/binder/include/binder/Nullable.h | 44 +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 libs/binder/include/binder/Nullable.h diff --git a/libs/binder/include/binder/Nullable.h b/libs/binder/include/binder/Nullable.h new file mode 100644 index 0000000000..b605bd3315 --- /dev/null +++ b/libs/binder/include/binder/Nullable.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include + +namespace android { + +namespace aidl { + +// nullable/make_nullable provide source-level compatibility between std::opional and std::unique_ptr +// usage: +// nullable a; +// nullable b = make_nullable(...); +// auto c = make_nullable(...); +// c.reset(); +// c = make_nullable(...); +// c = std::move(a); + +template +using nullable = std::unique_ptr; + +template +inline nullable make_nullable(Args&&... args) { + return std::make_unique(std::forward(args)...); +} + +} // namespace aidl + +} // namespace android \ No newline at end of file -- GitLab From 4ef0425787f2953a57610fcd53e777b1658c9bc7 Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Wed, 12 Feb 2020 17:12:22 +0100 Subject: [PATCH 0920/1255] SF: Refactor processDisplayChangesLocked() This change introduces three new functions: * processAddedDisplay() * processRemovedDisplay() * processChangedDisplay() and refactors processDisplayChangesLocked(). Where code reuse is required the appropriate function is called. Context: SurfaceFlinger::processDisplayChangesLocked() is a 150 line function, which does a non-trivial iteration of mCurrentState and mDisplayState, detects added, removed and changed displays and executes the corresponding logic to handle the changes. Currently if the surface of a display is different in curr and drawing state the code is destroying and recreatig the display object. The logic for display (re)creation is reused by playing with the iterator (skipping i++) and modifying the iterated collection (mDrawingState). This makes the code unnecessary complex and unreadable. Bug: 143451809 Test: flash device and check it boots Test: atest libsurfaceflinger_unittest Change-Id: I03afda7c1807ab36f8e03e7a4e43c804b3199149 (cherry picked from commit ae685593f893e01d95e64bbc08a7147590435dbf) --- services/surfaceflinger/SurfaceFlinger.cpp | 289 +++++++++++---------- services/surfaceflinger/SurfaceFlinger.h | 7 +- 2 files changed, 154 insertions(+), 142 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 61c60440d9..29fa29e375 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2383,13 +2383,14 @@ void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bo sp SurfaceFlinger::setupNewDisplayDeviceInternal( const wp& displayToken, std::shared_ptr compositionDisplay, - const DisplayDeviceState& state, const sp& dispSurface, + const DisplayDeviceState& state, + const sp& displaySurface, const sp& producer) { auto displayId = compositionDisplay->getDisplayId(); DisplayDeviceCreationArgs creationArgs(this, displayToken, compositionDisplay); creationArgs.sequenceId = state.sequenceId; creationArgs.isSecure = state.isSecure; - creationArgs.displaySurface = dispSurface; + creationArgs.displaySurface = displaySurface; creationArgs.hasWideColorGamut = false; creationArgs.supportedPerFrameMetadata = 0; @@ -2465,6 +2466,140 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( return display; } +void SurfaceFlinger::processDisplayAdded(const wp& displayToken, + const DisplayDeviceState& state) { + int width = 0; + int height = 0; + ui::PixelFormat pixelFormat = static_cast(PIXEL_FORMAT_UNKNOWN); + if (state.physical) { + const auto& activeConfig = + getCompositionEngine().getHwComposer().getActiveConfig(state.physical->id); + width = activeConfig->getWidth(); + height = activeConfig->getHeight(); + pixelFormat = static_cast(PIXEL_FORMAT_RGBA_8888); + } else if (state.surface != nullptr) { + int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width); + ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); + status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height); + ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); + int intPixelFormat; + status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat); + ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status); + pixelFormat = static_cast(intPixelFormat); + } else { + // Virtual displays without a surface are dormant: + // they have external state (layer stack, projection, + // etc.) but no internal state (i.e. a DisplayDevice). + return; + } + + compositionengine::DisplayCreationArgsBuilder builder; + if (const auto& physical = state.physical) { + builder.setPhysical({physical->id, physical->type}); + } + builder.setPixels(ui::Size(width, height)); + builder.setPixelFormat(pixelFormat); + builder.setIsSecure(state.isSecure); + builder.setLayerStackId(state.layerStack); + builder.setPowerAdvisor(&mPowerAdvisor); + builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer()); + builder.setName(state.displayName); + const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); + + sp displaySurface; + sp producer; + sp bqProducer; + sp bqConsumer; + getFactory().createBufferQueue(&bqProducer, &bqConsumer, /*consumerIsSurfaceFlinger =*/false); + + std::optional displayId = compositionDisplay->getId(); + + if (state.isVirtual()) { + sp vds = + new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, bqProducer, + bqConsumer, state.displayName); + + displaySurface = vds; + producer = vds; + } else { + ALOGE_IF(state.surface != nullptr, + "adding a supported display, but rendering " + "surface is provided (%p), ignoring it", + state.surface.get()); + + LOG_ALWAYS_FATAL_IF(!displayId); + displaySurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer, + maxGraphicsWidth, maxGraphicsHeight); + producer = bqProducer; + } + + if (displaySurface != nullptr) { + mDisplays.emplace(displayToken, + setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state, + displaySurface, producer)); + if (!state.isVirtual()) { + LOG_ALWAYS_FATAL_IF(!displayId); + dispatchDisplayHotplugEvent(displayId->value, true); + } + + const auto displayDevice = mDisplays[displayToken]; + if (displayDevice->isPrimary()) { + mScheduler->onPrimaryDisplayAreaChanged(displayDevice->getWidth() * + displayDevice->getHeight()); + } + } +} + +void SurfaceFlinger::processDisplayRemoved(const wp& displayToken) { + if (const auto display = getDisplayDeviceLocked(displayToken)) { + // Save display ID before disconnecting. + const auto displayId = display->getId(); + display->disconnect(); + + if (!display->isVirtual()) { + LOG_ALWAYS_FATAL_IF(!displayId); + dispatchDisplayHotplugEvent(displayId->value, false); + } + } + + mDisplays.erase(displayToken); +} + +void SurfaceFlinger::processDisplayChanged(const wp& displayToken, + const DisplayDeviceState& currentState, + const DisplayDeviceState& drawingState) { + const sp currentBinder = IInterface::asBinder(currentState.surface); + const sp drawingBinder = IInterface::asBinder(drawingState.surface); + if (currentBinder != drawingBinder) { + // changing the surface is like destroying and recreating the DisplayDevice + if (const auto display = getDisplayDeviceLocked(displayToken)) { + display->disconnect(); + } + mDisplays.erase(displayToken); + processDisplayAdded(displayToken, currentState); + return; + } + + if (const auto display = getDisplayDeviceLocked(displayToken)) { + if (currentState.layerStack != drawingState.layerStack) { + display->setLayerStack(currentState.layerStack); + } + if ((currentState.orientation != drawingState.orientation) || + (currentState.viewport != drawingState.viewport) || + (currentState.frame != drawingState.frame)) { + display->setProjection(currentState.orientation, currentState.viewport, + currentState.frame); + } + if (currentState.width != drawingState.width || + currentState.height != drawingState.height) { + display->setDisplaySize(currentState.width, currentState.height); + if (display->isPrimary()) { + mScheduler->onPrimaryDisplayAreaChanged(currentState.width * currentState.height); + } + } + } +} + void SurfaceFlinger::processDisplayChangesLocked() { // here we take advantage of Vector's copy-on-write semantics to // improve performance by skipping the transaction entirely when @@ -2473,159 +2608,31 @@ void SurfaceFlinger::processDisplayChangesLocked() { const KeyedVector, DisplayDeviceState>& draw(mDrawingState.displays); if (!curr.isIdenticalTo(draw)) { mVisibleRegionsDirty = true; - const size_t cc = curr.size(); - size_t dc = draw.size(); // find the displays that were removed // (ie: in drawing state but not in current state) // also handle displays that changed // (ie: displays that are in both lists) - for (size_t i = 0; i < dc;) { - const ssize_t j = curr.indexOfKey(draw.keyAt(i)); + for (size_t i = 0; i < draw.size(); i++) { + const wp& displayToken = draw.keyAt(i); + const ssize_t j = curr.indexOfKey(displayToken); if (j < 0) { // in drawing state but not in current state - if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) { - // Save display ID before disconnecting. - const auto displayId = display->getId(); - display->disconnect(); - - if (!display->isVirtual()) { - LOG_ALWAYS_FATAL_IF(!displayId); - dispatchDisplayHotplugEvent(displayId->value, false); - } - } - - mDisplays.erase(draw.keyAt(i)); + processDisplayRemoved(displayToken); } else { // this display is in both lists. see if something changed. - const DisplayDeviceState& state(curr[j]); - const wp& displayToken = curr.keyAt(j); - const sp state_binder = IInterface::asBinder(state.surface); - const sp draw_binder = IInterface::asBinder(draw[i].surface); - if (state_binder != draw_binder) { - // changing the surface is like destroying and - // recreating the DisplayDevice, so we just remove it - // from the drawing state, so that it get re-added - // below. - if (const auto display = getDisplayDeviceLocked(displayToken)) { - display->disconnect(); - } - mDisplays.erase(displayToken); - mDrawingState.displays.removeItemsAt(i); - dc--; - // at this point we must loop to the next item - continue; - } - - if (const auto display = getDisplayDeviceLocked(displayToken)) { - if (state.layerStack != draw[i].layerStack) { - display->setLayerStack(state.layerStack); - } - if ((state.orientation != draw[i].orientation) || - (state.viewport != draw[i].viewport) || (state.frame != draw[i].frame)) { - display->setProjection(state.orientation, state.viewport, state.frame); - } - if (state.width != draw[i].width || state.height != draw[i].height) { - display->setDisplaySize(state.width, state.height); - if (display->isPrimary()) { - mScheduler->onPrimaryDisplayAreaChanged(state.width * state.height); - } - } - } + const DisplayDeviceState& currentState = curr[j]; + const DisplayDeviceState& drawingState = draw[i]; + processDisplayChanged(displayToken, currentState, drawingState); } - ++i; } // find displays that were added // (ie: in current state but not in drawing state) - for (size_t i = 0; i < cc; i++) { - if (draw.indexOfKey(curr.keyAt(i)) < 0) { - const DisplayDeviceState& state(curr[i]); - - int width = 0; - int height = 0; - ui::PixelFormat pixelFormat = static_cast(PIXEL_FORMAT_UNKNOWN); - if (state.physical) { - const auto& activeConfig = - getCompositionEngine().getHwComposer().getActiveConfig( - state.physical->id); - width = activeConfig->getWidth(); - height = activeConfig->getHeight(); - pixelFormat = static_cast(PIXEL_FORMAT_RGBA_8888); - } else if (state.surface != nullptr) { - int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width); - ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); - status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height); - ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); - int intPixelFormat; - status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat); - ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status); - pixelFormat = static_cast(intPixelFormat); - } else { - // Virtual displays without a surface are dormant: - // they have external state (layer stack, projection, - // etc.) but no internal state (i.e. a DisplayDevice). - continue; - } - - compositionengine::DisplayCreationArgsBuilder builder; - if (const auto& physical = state.physical) { - builder.setPhysical({physical->id, physical->type}); - } - builder.setPixels(ui::Size(width, height)); - builder.setPixelFormat(pixelFormat); - builder.setIsSecure(state.isSecure); - builder.setLayerStackId(state.layerStack); - builder.setPowerAdvisor(&mPowerAdvisor); - builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays || - getHwComposer().isUsingVrComposer()); - builder.setName(state.displayName); - auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); - - sp dispSurface; - sp producer; - sp bqProducer; - sp bqConsumer; - getFactory().createBufferQueue(&bqProducer, &bqConsumer, false); - - std::optional displayId = compositionDisplay->getId(); - - if (state.isVirtual()) { - sp vds = - new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, - bqProducer, bqConsumer, state.displayName); - - dispSurface = vds; - producer = vds; - } else { - ALOGE_IF(state.surface != nullptr, - "adding a supported display, but rendering " - "surface is provided (%p), ignoring it", - state.surface.get()); - - LOG_ALWAYS_FATAL_IF(!displayId); - dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer, - maxGraphicsWidth, maxGraphicsHeight); - producer = bqProducer; - } - - const wp& displayToken = curr.keyAt(i); - if (dispSurface != nullptr) { - mDisplays.emplace(displayToken, - setupNewDisplayDeviceInternal(displayToken, - compositionDisplay, state, - dispSurface, producer)); - if (!state.isVirtual()) { - LOG_ALWAYS_FATAL_IF(!displayId); - dispatchDisplayHotplugEvent(displayId->value, true); - } - - const auto displayDevice = mDisplays[displayToken]; - if (displayDevice->isPrimary()) { - mScheduler->onPrimaryDisplayAreaChanged(displayDevice->getWidth() * - displayDevice->getHeight()); - } - } + for (size_t i = 0; i < curr.size(); i++) { + const wp& displayToken = curr.keyAt(i); + if (draw.indexOfKey(displayToken) < 0) { + processDisplayAdded(displayToken, curr[i]); } } } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index ba265adc39..7c2087a00c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -820,9 +820,14 @@ private: const wp& displayToken, std::shared_ptr compositionDisplay, const DisplayDeviceState& state, - const sp& dispSurface, + const sp& displaySurface, const sp& producer); void processDisplayChangesLocked(); + void processDisplayAdded(const wp& displayToken, const DisplayDeviceState& state); + void processDisplayRemoved(const wp& displayToken); + void processDisplayChanged(const wp& displayToken, + const DisplayDeviceState& currentState, + const DisplayDeviceState& drawingState); void processDisplayHotplugEventsLocked(); void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected); -- GitLab From 0049f8bd4c5bf5b6d12e04081a0f4398e4190021 Mon Sep 17 00:00:00 2001 From: Kevin DuBois Date: Wed, 11 Mar 2020 10:30:11 -0700 Subject: [PATCH 0921/1255] SF: increase precision in VSyncPredictor An issue was observed where the sf-app timeline woke up 1ms later than it should have. Issue was tracked down to an imprecision in some of the math in VSyncPredictor, which this issue corrects. Fixes: 151146131 Test: 2 new unit tests, one of which was from bug Test: flash dogfood device with patch Change-Id: I1994b5b532e292a140d4736c7090b68224f75a02 --- .../Scheduler/VSyncPredictor.cpp | 6 +-- .../tests/unittests/VSyncPredictorTest.cpp | 48 +++++++++++++++++-- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index 399da19c75..257b8b16bf 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -115,10 +115,10 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { auto it = mRateMap.find(mIdealPeriod); auto const currentPeriod = std::get<0>(it->second); // TODO (b/144707443): its important that there's some precision in the mean of the ordinals - // for the intercept calculation, so scale the ordinals by 10 to continue + // for the intercept calculation, so scale the ordinals by 1000 to continue // fixed point calculation. Explore expanding // scheduler::utils::calculate_mean to have a fixed point fractional part. - static constexpr int kScalingFactor = 10; + static constexpr int64_t kScalingFactor = 1000; for (auto i = 0u; i < mTimestamps.size(); i++) { traceInt64If("VSP-ts", mTimestamps[i]); @@ -147,7 +147,7 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { return false; } - nsecs_t const anticipatedPeriod = top / bottom * kScalingFactor; + nsecs_t const anticipatedPeriod = top * kScalingFactor / bottom; nsecs_t const intercept = meanTS - (anticipatedPeriod * meanOrdinal / kScalingFactor); auto const percent = std::abs(anticipatedPeriod - mIdealPeriod) * kMaxPercent / mIdealPeriod; diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp index f834af895c..bf2a889c89 100644 --- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp @@ -204,7 +204,7 @@ TEST_F(VSyncPredictorTest, againstOutliersDiscontinuous_500hzLowVariance) { }; auto idealPeriod = 2000000; auto expectedPeriod = 1999892; - auto expectedIntercept = 175409; + auto expectedIntercept = 86342; tracker.setPeriod(idealPeriod); for (auto const& timestamp : simulatedVsyncs) { @@ -335,8 +335,8 @@ TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) { 158929706370359, }; auto const idealPeriod = 11111111; - auto const expectedPeriod = 11113500; - auto const expectedIntercept = -395335; + auto const expectedPeriod = 11113919; + auto const expectedIntercept = -1195945; tracker.setPeriod(idealPeriod); for (auto const& timestamp : simulatedVsyncs) { @@ -355,6 +355,32 @@ TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) { EXPECT_THAT(prediction, Ge(timePoint)); } +// See b/151146131 +TEST_F(VSyncPredictorTest, hasEnoughPrecision) { + VSyncPredictor tracker{mPeriod, 20, kMinimumSamplesForPrediction, kOutlierTolerancePercent}; + std::vector const simulatedVsyncs{840873348817, 840890049444, 840906762675, + 840923581635, 840940161584, 840956868096, + 840973702473, 840990256277, 841007116851, + 841023722530, 841040452167, 841057073002, + 841073800920, 841090474360, 841107278632, + 841123898634, 841140750875, 841157287127, + 841591357014, 840856664232 + + }; + auto const idealPeriod = 16666666; + auto const expectedPeriod = 16698426; + auto const expectedIntercept = 58055; + + tracker.setPeriod(idealPeriod); + for (auto const& timestamp : simulatedVsyncs) { + tracker.addVsyncTimestamp(timestamp); + } + + auto [slope, intercept] = tracker.getVSyncPredictionModel(); + EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError)); + EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError)); +} + TEST_F(VSyncPredictorTest, resetsWhenInstructed) { auto const idealPeriod = 10000; auto const realPeriod = 10500; @@ -390,6 +416,22 @@ TEST_F(VSyncPredictorTest, slopeAlwaysValid) { } } +constexpr nsecs_t operator""_years(unsigned long long years) noexcept { + using namespace std::chrono_literals; + return years * 365 * 24 * 3600 * + std::chrono::duration_cast(1s).count(); +} +TEST_F(VSyncPredictorTest, aPhoneThatHasBeenAroundAWhileCanStillComputePeriod) { + constexpr nsecs_t timeBase = 100_years; + + for (auto i = 0; i < kHistorySize; i++) { + tracker.addVsyncTimestamp(timeBase + i * mPeriod); + } + auto [slope, intercept] = tracker.getVSyncPredictionModel(); + EXPECT_THAT(slope, IsCloseTo(mPeriod, mMaxRoundingError)); + EXPECT_THAT(intercept, Eq(0)); +} + } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues -- GitLab From 00f16423cece5c9b1823a2e32b0e7ac5c5f17116 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Wed, 11 Mar 2020 11:33:04 -0700 Subject: [PATCH 0922/1255] Make blur sysprop persist across boots Test: SurfaceFlinger_test Test: manual on settings app Bug: 149792636 Change-Id: Id53dd87f48285728dfff78e3d8db2cf4708a16eb --- services/surfaceflinger/SurfaceFlinger.cpp | 16 +++++++++------- services/surfaceflinger/SurfaceFlinger.h | 4 +++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 29fa29e375..16a76d1027 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -364,11 +364,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("ro.surface_flinger.supports_background_blur", value, "0"); bool supportsBlurs = atoi(value); - property_get("debug.sf.disable_blurs", value, "0"); - bool disableBlurs = atoi(value); - mEnableBlurs = supportsBlurs && !disableBlurs; - ALOGI_IF(!mEnableBlurs, "Disabling blur effects. supported: %d, disabled: %d", supportsBlurs, - disableBlurs); + mSupportsBlur = supportsBlurs; + ALOGI_IF(!mSupportsBlur, "Disabling blur effects, they are not supported."); property_get("ro.sf.blurs_are_expensive", value, "0"); mBlursAreExpensive = atoi(value); @@ -625,7 +622,7 @@ void SurfaceFlinger::init() { .setUseColorManagerment(useColorManagement) .setEnableProtectedContext(enable_protected_contents(false)) .setPrecacheToneMapperShaderOnly(false) - .setSupportsBackgroundBlur(mEnableBlurs) + .setSupportsBackgroundBlur(mSupportsBlur) .setContextPriority(useContextPriority ? renderengine::RenderEngine::ContextPriority::HIGH : renderengine::RenderEngine::ContextPriority::MEDIUM) @@ -707,6 +704,11 @@ void SurfaceFlinger::readPersistentProperties() { property_get("persist.sys.sf.color_mode", value, "0"); mForceColorMode = static_cast(atoi(value)); + + property_get("persist.sys.sf.disable_blurs", value, "0"); + bool disableBlurs = atoi(value); + mDisableBlurs = disableBlurs; + ALOGI_IF(disableBlurs, "Disabling blur effects, user preference."); } void SurfaceFlinger::startBootAnim() { @@ -3594,7 +3596,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (layer->setCornerRadius(s.cornerRadius)) flags |= eTraversalNeeded; } - if (what & layer_state_t::eBackgroundBlurRadiusChanged) { + if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs) { if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded; } if (what & layer_state_t::eLayerStackChanged) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 7c2087a00c..44e18a7463 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1060,8 +1060,10 @@ private: const std::shared_ptr mTimeStats; const std::unique_ptr mFrameTracer; bool mUseHwcVirtualDisplays = false; + // If blurs should be enabled on this device. + bool mSupportsBlur = false; // Disable blurs, for debugging - bool mEnableBlurs = false; + std::atomic mDisableBlurs = false; // If blurs are considered expensive and should require high GPU frequency. bool mBlursAreExpensive = false; std::atomic mFrameMissedCount = 0; -- GitLab From 60e42ea45c1819af7f0ee248aeb8d5b0683bf60f Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 9 Mar 2020 19:17:31 -0700 Subject: [PATCH 0923/1255] SurfaceFlinger: Layer::getFrameRate() with relatives If an app set a framerate on a layer, then getFrameRate() on ancestors/successors of this layer should return NoVote to allow the refresh rate heuristic to be based on the the actual layers that voted. Bug: 151274728 Test: Swappy with ANativeWindow_setFrateRate Change-Id: Icfdf8e8fd4d92ba520bbc894bb9971b980691518 --- libs/gui/ISurfaceComposer.cpp | 3 +- services/surfaceflinger/Layer.cpp | 85 +++- services/surfaceflinger/Layer.h | 11 +- .../surfaceflinger/Scheduler/LayerHistory.cpp | 4 +- .../Scheduler/LayerHistoryV2.cpp | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 26 +- .../surfaceflinger/tests/unittests/Android.bp | 1 + .../tests/unittests/LayerHistoryTest.cpp | 10 +- .../tests/unittests/LayerHistoryTestV2.cpp | 30 +- .../tests/unittests/SetFrameRateTest.cpp | 473 ++++++++++++++++++ .../tests/unittests/TestableSurfaceFlinger.h | 1 + .../tests/unittests/mock/MockLayer.h | 2 +- 12 files changed, 601 insertions(+), 49 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index ce41eaba1d..915ebf922a 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1140,8 +1140,7 @@ public: return err; } - err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply, - IBinder::FLAG_ONEWAY); + err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply); if (err != NO_ERROR) { ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err); return err; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 64cfb3d699..b952eb6300 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -116,6 +116,7 @@ Layer::Layer(const LayerCreationArgs& args) mCurrentState.frameRateSelectionPriority = PRIORITY_UNSET; mCurrentState.metadata = args.metadata; mCurrentState.shadowRadius = 0.f; + mCurrentState.treeHasFrameRateVote = false; // drawing state & current state are identical mDrawingState = mCurrentState; @@ -1331,6 +1332,44 @@ bool Layer::setShadowRadius(float shadowRadius) { return true; } +void Layer::updateTreeHasFrameRateVote() { + const auto traverseTree = [&](const LayerVector::Visitor& visitor) { + auto parent = getParent(); + while (parent) { + visitor(parent.get()); + parent = parent->getParent(); + } + + traverse(LayerVector::StateSet::Current, visitor); + }; + + // update parents and children about the vote + // First traverse the tree and count how many layers has votes + int layersWithVote = 0; + traverseTree([&layersWithVote](Layer* layer) { + if (layer->mCurrentState.frameRate.rate > 0 || + layer->mCurrentState.frameRate.type == FrameRateCompatibility::NoVote) { + layersWithVote++; + } + }); + + // Now update the other layers + bool transactionNeeded = false; + traverseTree([layersWithVote, &transactionNeeded](Layer* layer) { + if (layer->mCurrentState.treeHasFrameRateVote != layersWithVote > 0) { + layer->mCurrentState.sequence++; + layer->mCurrentState.treeHasFrameRateVote = layersWithVote > 0; + layer->mCurrentState.modified = true; + layer->setTransactionFlags(eTransactionNeeded); + transactionNeeded = true; + } + }); + + if (transactionNeeded) { + mFlinger->setTransactionFlags(eTraversalNeeded); + } +} + bool Layer::setFrameRate(FrameRate frameRate) { if (!mFlinger->useFrameRateApi) { return false; @@ -1342,12 +1381,26 @@ bool Layer::setFrameRate(FrameRate frameRate) { mCurrentState.sequence++; mCurrentState.frameRate = frameRate; mCurrentState.modified = true; + + updateTreeHasFrameRateVote(); + setTransactionFlags(eTransactionNeeded); return true; } -Layer::FrameRate Layer::getFrameRate() const { - return getDrawingState().frameRate; +Layer::FrameRate Layer::getFrameRateForLayerTree() const { + const auto frameRate = getDrawingState().frameRate; + if (frameRate.rate > 0 || frameRate.type == FrameRateCompatibility::NoVote) { + return frameRate; + } + + // This layer doesn't have a frame rate. If one of its ancestors or successors + // have a vote, return a NoVote for ancestors/successors to set the vote + if (getDrawingState().treeHasFrameRateVote) { + return {0, FrameRateCompatibility::NoVote}; + } + + return frameRate; } void Layer::deferTransactionUntil_legacy(const sp& barrierLayer, uint64_t frameNumber) { @@ -1605,6 +1658,7 @@ void Layer::addChild(const sp& layer) { mCurrentChildren.add(layer); layer->setParent(this); + updateTreeHasFrameRateVote(); } ssize_t Layer::removeChild(const sp& layer) { @@ -1612,7 +1666,24 @@ ssize_t Layer::removeChild(const sp& layer) { setTransactionFlags(eTransactionNeeded); layer->setParent(nullptr); - return mCurrentChildren.remove(layer); + const auto removeResult = mCurrentChildren.remove(layer); + + updateTreeHasFrameRateVote(); + layer->updateTreeHasFrameRateVote(); + + return removeResult; +} + +void Layer::reparentChildren(const sp& newParent) { + if (attachChildren()) { + setTransactionFlags(eTransactionNeeded); + } + + for (const sp& child : mCurrentChildren) { + newParent->addChild(child); + } + mCurrentChildren.clear(); + updateTreeHasFrameRateVote(); } bool Layer::reparentChildren(const sp& newParentHandle) { @@ -1628,13 +1699,7 @@ bool Layer::reparentChildren(const sp& newParentHandle) { return false; } - if (attachChildren()) { - setTransactionFlags(eTransactionNeeded); - } - for (const sp& child : mCurrentChildren) { - newParent->addChild(child); - } - mCurrentChildren.clear(); + reparentChildren(newParent); return true; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 20d72324c3..72f6de3710 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -259,6 +259,9 @@ public: int32_t frameRateSelectionPriority; FrameRate frameRate; + + // Indicates whether parents / children of this layer had set FrameRate + bool treeHasFrameRateVote; }; explicit Layer(const LayerCreationArgs& args); @@ -344,7 +347,8 @@ public: virtual void deferTransactionUntil_legacy(const sp& barrierLayer, uint64_t frameNumber); virtual bool setOverrideScalingMode(int32_t overrideScalingMode); virtual bool setMetadata(const LayerMetadata& data); - virtual bool reparentChildren(const sp& layer); + bool reparentChildren(const sp& newParentHandle); + void reparentChildren(const sp& newParent); virtual void setChildrenDrawingParent(const sp& layer); virtual bool reparent(const sp& newParentHandle); virtual bool detachChildren(); @@ -801,7 +805,7 @@ public: Rect getCroppedBufferSize(const Layer::State& s) const; bool setFrameRate(FrameRate frameRate); - virtual FrameRate getFrameRate() const; + virtual FrameRate getFrameRateForLayerTree() const; protected: // constant @@ -830,6 +834,7 @@ protected: // For unit tests friend class TestableSurfaceFlinger; friend class RefreshRateSelectionTest; + friend class SetFrameRateTest; virtual void commitTransaction(const State& stateToCommit); @@ -1013,6 +1018,8 @@ private: LayerVector makeChildrenTraversalList(LayerVector::StateSet stateSet, const std::vector& layersInTree); + void updateTreeHasFrameRateVote(); + // Cached properties computed from drawing state // Effective transform taking into account parent transforms and any parent scaling. ui::Transform mEffectiveTransform; diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index a8e675683a..8958d9ae19 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -39,7 +39,7 @@ namespace android::scheduler::impl { namespace { bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) { - if (layer.getFrameRate().rate > 0) { + if (layer.getFrameRateForLayerTree().rate > 0) { return layer.isVisible(); } return layer.isVisible() && info.getLastUpdatedTime() >= threshold; @@ -109,7 +109,7 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { // Only use the layer if the reference still exists. if (layer || CC_UNLIKELY(mTraceEnabled)) { // Check if frame rate was set on layer. - const auto frameRate = layer->getFrameRate(); + const auto frameRate = layer->getFrameRateForLayerTree(); if (frameRate.rate > 0.f) { const auto voteType = [&]() { switch (frameRate.type) { diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp index 6ef6ce414b..101060c1ac 100644 --- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp @@ -40,7 +40,7 @@ namespace android::scheduler::impl { namespace { bool isLayerActive(const Layer& layer, const LayerInfoV2& info, nsecs_t threshold) { - if (layer.getFrameRate().rate > 0) { + if (layer.getFrameRateForLayerTree().rate > 0) { return layer.isVisible(); } return layer.isVisible() && info.getLastUpdatedTime() >= threshold; @@ -166,7 +166,7 @@ void LayerHistoryV2::partitionLayers(nsecs_t now) { if (const auto layer = weak.promote(); layer && isLayerActive(*layer, *info, threshold)) { i++; // Set layer vote if set - const auto frameRate = layer->getFrameRate(); + const auto frameRate = layer->getFrameRateForLayerTree(); const auto voteType = [&]() { switch (frameRate.type) { case Layer::FrameRateCompatibility::Default: diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c995db4972..67b02c8c15 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -6024,18 +6024,22 @@ status_t SurfaceFlinger::setFrameRate(const sp& surface, return BAD_VALUE; } - Mutex::Autolock lock(mStateLock); - if (authenticateSurfaceTextureLocked(surface)) { - sp layer = (static_cast(surface.get()))->getLayer(); - if (layer->setFrameRate( - Layer::FrameRate(frameRate, - Layer::FrameRate::convertCompatibility(compatibility)))) { - setTransactionFlags(eTraversalNeeded); + postMessageAsync(new LambdaMessage([=]() NO_THREAD_SAFETY_ANALYSIS { + Mutex::Autolock lock(mStateLock); + if (authenticateSurfaceTextureLocked(surface)) { + sp layer = (static_cast(surface.get()))->getLayer(); + if (layer->setFrameRate( + Layer::FrameRate(frameRate, + Layer::FrameRate::convertCompatibility(compatibility)))) { + setTransactionFlags(eTraversalNeeded); + } + } else { + ALOGE("Attempt to set frame rate on an unrecognized IGraphicBufferProducer"); + return BAD_VALUE; } - } else { - ALOGE("Attempt to set frame rate on an unrecognized IGraphicBufferProducer"); - return BAD_VALUE; - } + return NO_ERROR; + })); + return NO_ERROR; } diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 1cd8731fa9..2f2fb20e21 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -50,6 +50,7 @@ cc_test { "PhaseOffsetsTest.cpp", "SchedulerTest.cpp", "SchedulerUtilsTest.cpp", + "SetFrameRateTest.cpp", "RefreshRateConfigsTest.cpp", "RefreshRateSelectionTest.cpp", "RefreshRateStatsTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 18e9941385..7557faf8a9 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -84,7 +84,7 @@ TEST_F(LayerHistoryTest, oneLayer) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -113,7 +113,7 @@ TEST_F(LayerHistoryTest, explicitTimestamp) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -137,15 +137,15 @@ TEST_F(LayerHistoryTest, multipleLayers) { EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer1, getFrameSelectionPriority()).WillRepeatedly(Return(1)); - EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer2, getFrameSelectionPriority()).WillRepeatedly(Return(1)); - EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer2, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer3, getFrameSelectionPriority()).WillRepeatedly(Return(1)); - EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer3, getFrameRateForLayerTree()).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 37da76b172..8559a5e7d7 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp @@ -91,7 +91,7 @@ namespace { TEST_F(LayerHistoryTestV2, oneLayer) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -122,7 +122,7 @@ TEST_F(LayerHistoryTestV2, oneLayer) { TEST_F(LayerHistoryTestV2, oneInvisibleLayer) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -146,7 +146,7 @@ TEST_F(LayerHistoryTestV2, oneInvisibleLayer) { TEST_F(LayerHistoryTestV2, explicitTimestamp) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -167,7 +167,7 @@ TEST_F(LayerHistoryTestV2, explicitTimestamp) { TEST_F(LayerHistoryTestV2, oneLayerNoVote) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::NoVote); @@ -194,7 +194,7 @@ TEST_F(LayerHistoryTestV2, oneLayerNoVote) { TEST_F(LayerHistoryTestV2, oneLayerMinVote) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Min); @@ -222,7 +222,7 @@ TEST_F(LayerHistoryTestV2, oneLayerMinVote) { TEST_F(LayerHistoryTestV2, oneLayerMaxVote) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Max); @@ -250,7 +250,7 @@ TEST_F(LayerHistoryTestV2, oneLayerMaxVote) { TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) { auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()) + EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly( Return(Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::Default))); @@ -273,7 +273,8 @@ TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) { 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 + // TODO: activeLayerCount() should be 0 but it is 1 since getFrameRateForLayerTree() returns a + // value > 0 EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } @@ -281,7 +282,7 @@ TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) { TEST_F(LayerHistoryTestV2, oneLayerExplicitExactVote) { auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()) + EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly(Return( Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::ExactOrMultiple))); @@ -305,7 +306,8 @@ TEST_F(LayerHistoryTestV2, oneLayerExplicitExactVote) { 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 + // TODO: activeLayerCount() should be 0 but it is 1 since getFrameRateForLayerTree() returns a + // value > 0 EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } @@ -316,13 +318,13 @@ TEST_F(LayerHistoryTestV2, multipleLayers) { auto layer3 = createLayer(); EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer2, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer3, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); nsecs_t time = systemTime(); @@ -456,7 +458,7 @@ TEST_F(LayerHistoryTestV2, inactiveLayers) { auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); - EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); nsecs_t time = systemTime(); diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp new file mode 100644 index 0000000000..b06908559d --- /dev/null +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -0,0 +1,473 @@ +/* + * 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 "LibSurfaceFlingerUnittests" + +#include +#include +#include + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#include "BufferQueueLayer.h" +#include "BufferStateLayer.h" +#include "EffectLayer.h" +#include "Layer.h" +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" +#include "TestableSurfaceFlinger.h" +#include "mock/DisplayHardware/MockComposer.h" +#include "mock/MockDispSync.h" +#include "mock/MockEventControlThread.h" +#include "mock/MockEventThread.h" +#include "mock/MockMessageQueue.h" + +namespace android { + +using testing::_; +using testing::DoAll; +using testing::Mock; +using testing::Return; +using testing::SetArgPointee; + +using android::Hwc2::IComposer; +using android::Hwc2::IComposerClient; + +using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; + +using FrameRate = Layer::FrameRate; +using FrameRateCompatibility = Layer::FrameRateCompatibility; + +class LayerFactory { +public: + virtual ~LayerFactory() = default; + + virtual std::string name() = 0; + virtual sp createLayer(TestableSurfaceFlinger& flinger) = 0; + +protected: + static constexpr uint32_t WIDTH = 100; + static constexpr uint32_t HEIGHT = 100; + static constexpr uint32_t LAYER_FLAGS = 0; +}; + +class BufferQueueLayerFactory : public LayerFactory { +public: + std::string name() override { return "BufferQueueLayer"; } + sp createLayer(TestableSurfaceFlinger& flinger) override { + sp client; + LayerCreationArgs args(flinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT, + LAYER_FLAGS, LayerMetadata()); + return new BufferQueueLayer(args); + } +}; + +class BufferStateLayerFactory : public LayerFactory { +public: + std::string name() override { return "BufferStateLayer"; } + sp createLayer(TestableSurfaceFlinger& flinger) override { + sp client; + LayerCreationArgs args(flinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT, + LAYER_FLAGS, LayerMetadata()); + return new BufferStateLayer(args); + } +}; + +class EffectLayerFactory : public LayerFactory { +public: + std::string name() override { return "EffectLayer"; } + sp createLayer(TestableSurfaceFlinger& flinger) override { + sp client; + LayerCreationArgs args(flinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS, + LayerMetadata()); + return new EffectLayer(args); + } +}; + +std::string PrintToStringParamName( + const ::testing::TestParamInfo>& info) { + return info.param->name(); +} + +/** + * This class tests the behaviour of Layer::SetFrameRate and Layer::GetFrameRate + */ +class SetFrameRateTest : public ::testing::TestWithParam> { +protected: + const FrameRate FRAME_RATE_VOTE1 = FrameRate(67.f, FrameRateCompatibility::Default); + const FrameRate FRAME_RATE_VOTE2 = FrameRate(14.f, FrameRateCompatibility::ExactOrMultiple); + const FrameRate FRAME_RATE_VOTE3 = FrameRate(99.f, FrameRateCompatibility::NoVote); + const FrameRate FRAME_RATE_TREE = FrameRate(0, FrameRateCompatibility::NoVote); + const FrameRate FRAME_RATE_NO_VOTE = FrameRate(0, FrameRateCompatibility::Default); + + SetFrameRateTest(); + + void setupScheduler(); + void setupComposer(uint32_t virtualDisplayCount); + + void addChild(sp layer, sp child); + void removeChild(sp layer, sp child); + void reparentChildren(sp layer, sp child); + void commitTransaction(); + + TestableSurfaceFlinger mFlinger; + Hwc2::mock::Composer* mComposer = nullptr; + mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); + + std::vector> mLayers; +}; + +SetFrameRateTest::SetFrameRateTest() { + 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()); + + mFlinger.mutableUseFrameRateApi() = true; + + setupScheduler(); + setupComposer(0); + + mFlinger.mutableEventQueue().reset(mMessageQueue); +} +void SetFrameRateTest::addChild(sp layer, sp child) { + layer.get()->addChild(child.get()); +} + +void SetFrameRateTest::removeChild(sp layer, sp child) { + layer.get()->removeChild(child.get()); +} + +void SetFrameRateTest::reparentChildren(sp parent, sp newParent) { + parent.get()->reparentChildren(newParent); +} + +void SetFrameRateTest::commitTransaction() { + for (auto layer : mLayers) { + layer.get()->commitTransaction(layer.get()->getCurrentState()); + } +} + +void SetFrameRateTest::setupScheduler() { + auto eventThread = std::make_unique(); + auto sfEventThread = std::make_unique(); + + EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*eventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(eventThread.get(), ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress))); + + EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) + .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress))); + + auto primaryDispSync = std::make_unique(); + + EXPECT_CALL(*primaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0)); + EXPECT_CALL(*primaryDispSync, getPeriod()) + .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE)); + EXPECT_CALL(*primaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0)); + mFlinger.setupScheduler(std::move(primaryDispSync), + std::make_unique(), std::move(eventThread), + std::move(sfEventThread)); +} + +void SetFrameRateTest::setupComposer(uint32_t virtualDisplayCount) { + mComposer = new Hwc2::mock::Composer(); + EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); + mFlinger.setupComposer(std::unique_ptr(mComposer)); + + Mock::VerifyAndClear(mComposer); +} + +namespace { +/* ------------------------------------------------------------------------ + * Test cases + */ +TEST_P(SetFrameRateTest, SetAndGet) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto layer = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + layer->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE1, layer->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetParent) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + + child2->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + child2->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetParentAllVote) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + + child2->setFrameRate(FRAME_RATE_VOTE1); + child1->setFrameRate(FRAME_RATE_VOTE2); + parent->setFrameRate(FRAME_RATE_VOTE3); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + child2->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + + child1->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + + parent->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetChild) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + + parent->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + + parent->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetChildAllVote) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + + child2->setFrameRate(FRAME_RATE_VOTE1); + child1->setFrameRate(FRAME_RATE_VOTE2); + parent->setFrameRate(FRAME_RATE_VOTE3); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + parent->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + child1->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + child2->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + + parent->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); + + addChild(child1, child2); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + + parent->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + + parent->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree()); + + removeChild(child1, child2); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); + + parent->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2_1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + addChild(child1, child2_1); + + child2->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2_1->getFrameRateForLayerTree()); + + child2->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2_1->getFrameRateForLayerTree()); +} + +TEST_P(SetFrameRateTest, SetAndGetRearentChildren) { + EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + + const auto& layerFactory = GetParam(); + + auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto parent2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); + + addChild(parent, child1); + addChild(child1, child2); + + child2->setFrameRate(FRAME_RATE_VOTE1); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + reparentChildren(parent, parent2); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, parent2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); + + child2->setFrameRate(FRAME_RATE_NO_VOTE); + commitTransaction(); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, parent2->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); + EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); +} + +INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest, + testing::Values(std::make_shared(), + std::make_shared(), + std::make_shared()), + PrintToStringParamName); + +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 84e55ae07c..414085c900 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -394,6 +394,7 @@ public: auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; } auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; } auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; } + auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; } auto fromHandle(const sp& handle) { Mutex::Autolock _l(mFlinger->mStateLock); diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h index e2f6abdf8d..119f58033c 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -31,7 +31,7 @@ public: MOCK_METHOD0(getFrameSelectionPriority, int32_t()); MOCK_CONST_METHOD0(isVisible, bool()); MOCK_METHOD0(createClone, sp()); - MOCK_CONST_METHOD0(getFrameRate, FrameRate()); + MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate()); }; } // namespace android::mock -- GitLab From bb108a18393edde0e767d882dceef70a9fb1839e Mon Sep 17 00:00:00 2001 From: Jon Spivack Date: Fri, 13 Mar 2020 20:45:18 -0700 Subject: [PATCH 0924/1255] ServiceManager: Check guaranteeClient before unregistering services If tryUnregisterService is called while a service has set guaranteeClient to true, it should not succeed. The flag means that a client exists and is about to be counted. Not checking this flag can lead to a race. Bug: 151485917 Test: aidl_lazy_test Change-Id: If7ef7a5c7521ea40521bd351385fb8bd650aba08 --- cmds/servicemanager/ServiceManager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index abe64365f3..0154620efb 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -522,6 +522,11 @@ Status ServiceManager::tryUnregisterService(const std::string& name, const spsecond.guaranteeClient) { + LOG(INFO) << "Tried to unregister " << name << ", but there is about to be a client."; + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); + } + int clients = handleServiceClientCallback(name, false); // clients < 0: feature not implemented or other error. Assume clients. -- GitLab From 822b10aedfa435a7252bd73074708694fd20eb4c Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 17 Mar 2020 17:51:27 -0700 Subject: [PATCH 0925/1255] [GpuStats] Lazily-register statsd callbacks Previously statsd callbacks were registered when GpuStats was instantiated. But, statsd is enforcing permissions to verify that the calling process had permission to register callbacks. The permission enforcement is happening too early so the callback registration silently fails. As a workaround, perform callback registration the first time GpuStats is asked to track stats instead. Bug: 151682677 Test: builds, boots Test: adb logcat | grep REGISTER_STATS Test: adb shell cmd stats pull-source 10054 Test: adb shell cmd stats pull-source 10055 Change-Id: I2d4a4e320825ee5cb393a6560baa8756779b729f --- services/gpuservice/gpustats/GpuStats.cpp | 25 ++++++++++++------- .../gpustats/include/gpustats/GpuStats.h | 5 +++- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp index d0945326b3..263bf61c12 100644 --- a/services/gpuservice/gpustats/GpuStats.cpp +++ b/services/gpuservice/gpustats/GpuStats.cpp @@ -30,16 +30,11 @@ namespace android { -GpuStats::GpuStats() { - AStatsManager_registerPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO, - GpuStats::pullAtomCallback, nullptr, this); - AStatsManager_registerPullAtomCallback(android::util::GPU_STATS_APP_INFO, - GpuStats::pullAtomCallback, nullptr, this); -} - GpuStats::~GpuStats() { - AStatsManager_unregisterPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO); - AStatsManager_unregisterPullAtomCallback(android::util::GPU_STATS_APP_INFO); + if (mStatsdRegistered) { + AStatsManager_unregisterPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO); + AStatsManager_unregisterPullAtomCallback(android::util::GPU_STATS_APP_INFO); + } } static void addLoadingCount(GpuStatsInfo::Driver driver, bool isDriverLoaded, @@ -97,6 +92,7 @@ void GpuStats::insertDriverStats(const std::string& driverPackageName, ATRACE_CALL(); std::lock_guard lock(mLock); + registerStatsdCallbacksIfNeeded(); ALOGV("Received:\n" "\tdriverPackageName[%s]\n" "\tdriverVersionName[%s]\n" @@ -150,6 +146,7 @@ void GpuStats::insertTargetStats(const std::string& appPackageName, const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode); std::lock_guard lock(mLock); + registerStatsdCallbacksIfNeeded(); if (!mAppStats.count(appStatsKey)) { return; } @@ -179,6 +176,16 @@ void GpuStats::interceptSystemDriverStatsLocked() { mGlobalStats[0].glesVersion = property_get_int32("ro.opengles.version", 0); } +void GpuStats::registerStatsdCallbacksIfNeeded() { + if (!mStatsdRegistered) { + AStatsManager_registerPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO, + GpuStats::pullAtomCallback, nullptr, this); + AStatsManager_registerPullAtomCallback(android::util::GPU_STATS_APP_INFO, + GpuStats::pullAtomCallback, nullptr, this); + mStatsdRegistered = true; + } +} + void GpuStats::dump(const Vector& args, std::string* result) { ATRACE_CALL(); diff --git a/services/gpuservice/gpustats/include/gpustats/GpuStats.h b/services/gpuservice/gpustats/include/gpustats/GpuStats.h index 8ca4e4ed71..55f0da1bc5 100644 --- a/services/gpuservice/gpustats/include/gpustats/GpuStats.h +++ b/services/gpuservice/gpustats/include/gpustats/GpuStats.h @@ -30,7 +30,6 @@ namespace android { class GpuStats { public: - GpuStats(); ~GpuStats(); // Insert new gpu driver stats into global stats and app stats. @@ -66,12 +65,16 @@ private: void dumpAppLocked(std::string* result); // Append cpuVulkanVersion and glesVersion to system driver stats void interceptSystemDriverStatsLocked(); + // Registers statsd callbacks if they have not already been registered + void registerStatsdCallbacksIfNeeded(); // Below limits the memory usage of GpuStats to be less than 10KB. This is // the preferred number for statsd while maintaining nice data quality. static const size_t MAX_NUM_APP_RECORDS = 100; // GpuStats access should be guarded by mLock. std::mutex mLock; + // True if statsd callbacks have been registered. + bool mStatsdRegistered = false; // Key is driver version code. std::unordered_map mGlobalStats; // Key is +. -- GitLab From 1652397ab77904092509a0315ad026f0b4f10a18 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 4 Mar 2020 17:48:39 -0800 Subject: [PATCH 0926/1255] Properly initialize MotionClassifier InputClassifier will now play a more active role in managing the lifecycle of MotionClassifier. In the previous version of the code, we had a circular reference: MotionClassifier owned a wp, that sometimes got promoted to sp<>. But the InputClassifier was the official owner of MotionClassifier, and owned a unique_ptr. The owner of InputClassifier in real code is InputManager, and in test code, it's the test class. When the owner of InputClassifier destroyed InputClassifier, this could sometimes happen at the time when the MotionClassifier also held a reference to the InputClassifier. That meant that the proper owner of InputClassifier was not invoking the destructor. Instead, the MotionClassifier was invoking the InputClassifier destructor. To fix the situation, we now do the following: 1. InputClassifier will never die before MotionClassifier. 2. MotionClassifier constructor is now allowed to block. It would block for some time because calling getService takes a while. To account for this, InputClassifier launches a new thread to create MotionClassifier. 3. When MotionClassifier is ready to process events, InputClassifier updates mMotionClassifier, which makes it non-null. 4. We now create a separate death recipient, which is co-owned by InputClassifier and MotionClassifier. This is done so that the refcount of the deathrecipient does not affect the refcount of InputClassifier, and thus enforces the ownership of InputClassifier by the InputManager. Now, no one can call ~InputClassifier except for its real owner. 5. MotionClassifier will subscribe the death recipient to the death of the HAL. InputClassifier will delete MotionClassifier if HAL dies. MotionClassifier no longer holds on to the death recipient. 6. We move the loop of the MotionClassifier thread to focus only on processing events. That thread will no longer do any initialization. 7. Remove the thread check inside MotionClassifier. It isn't really useful, now that there's only 1 function for the entire thread. Ownership summary: Both InputClassifier and MotionClassifier own DeathRecipient. DeathRecipient has a reference to InputClassifier. Thus, we must guarantee that DeathRecipient dies before InputClassifier. InputClassifier owns MotionClassifier. This is OK, since even if InputClassifier dies, it will first delete MotionClassifier. That will cause MotionClassifier to release 1 refCount from DeathRecipient. That means the only reference remaining to DeathRecipient will be inside InputClassifier, so InputClassifier will always be alive until DeathRecipient is dead. Similar argument applies if MotionClassifier and DeathRecipient die in different order (as observed from InputClassifier). Tests: 1) Manually running inputflinger_tests on cuttlefish: build/launch cuttlefish using go/acloud m inputflinger_tests adb push out/target/product/vsoc_x86/data/nativetest/inputflinger_tests/inputflinger_tests /data/nativetest/inputflinger_tests/inputflinger_tests adb shell /data/nativetest/inputflinger_tests # ./inputflinger_tests --gtest_filter=*InputClassifierTest* --gtest_repeat=1000 --gtest_break_on_failure 2) Boot flame and open logcat. Observe in logcat: StartInputManagerService took to complete: 2ms Previously, in synchronous approach ( b/130184032) it was about 100 ms (so we did not regress). 3) Kill the HAL while system_server is running, and dumpsys input before and after: adb shell dumpsys input (observe that MotionClassifier is non-null on flame) adb shell -t killall android.hardware.input.classifier@1.0-service adb shell dumpsys input (observe that MotionCLassifier is null) Bug: 149155998 Test: see "Tests" section above Change-Id: Ic76b82bd5f2cd374e3b001400eb495ca36de7353 --- services/inputflinger/InputClassifier.cpp | 134 +++++++----------- services/inputflinger/InputClassifier.h | 88 +++++++----- .../tests/InputClassifier_test.cpp | 33 ++++- 3 files changed, 135 insertions(+), 120 deletions(-) diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index e5e83d752c..8ba1f7f8c1 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -46,8 +46,6 @@ using namespace android::hardware::input; namespace android { -static constexpr bool DEBUG = false; - // Category (=namespace) name for the input settings that are applied at boot time static const char* INPUT_NATIVE_BOOT = "input_native_boot"; // Feature flag name for the deep press feature @@ -141,53 +139,46 @@ std::optional ClassifierEvent::getDeviceId() const { // --- MotionClassifier --- -MotionClassifier::MotionClassifier(sp deathRecipient) : - mDeathRecipient(deathRecipient), mEvents(MAX_EVENTS) { - mHalThread = std::thread(&MotionClassifier::callInputClassifierHal, this); +MotionClassifier::MotionClassifier( + sp service) + : mEvents(MAX_EVENTS), mService(service) { + // Under normal operation, we do not need to reset the HAL here. But in the case where system + // crashed, but HAL didn't, we may be connecting to an existing HAL process that might already + // have received events in the past. That means, that HAL could be in an inconsistent state + // once it receives events from the newly created MotionClassifier. + mEvents.push(ClassifierEvent::createHalResetEvent()); + + mHalThread = std::thread(&MotionClassifier::processEvents, this); #if defined(__linux__) // Set the thread name for debugging pthread_setname_np(mHalThread.native_handle(), "InputClassifier"); #endif } -/** - * This function may block for some time to initialize the HAL, so it should only be called - * from the "InputClassifier HAL" thread. - */ -bool MotionClassifier::init() { - ensureHalThread(__func__); +std::unique_ptr MotionClassifier::create( + sp deathRecipient) { + if (!deepPressEnabled()) { + // If feature is not enabled, MotionClassifier should stay null to avoid unnecessary work. + // When MotionClassifier is null, InputClassifier will forward all events + // to the next InputListener, unmodified. + return nullptr; + } sp service = classifier::V1_0::IInputClassifier::getService(); if (!service) { // Not really an error, maybe the device does not have this HAL, // but somehow the feature flag is flipped ALOGI("Could not obtain InputClassifier HAL"); - return false; + return nullptr; } - sp recipient = mDeathRecipient.promote(); - if (recipient != nullptr) { - const bool linked = service->linkToDeath(recipient, 0 /* cookie */).withDefault(false); - if (!linked) { - ALOGE("Could not link MotionClassifier to the HAL death"); - return false; - } - } - - // Under normal operation, we do not need to reset the HAL here. But in the case where system - // crashed, but HAL didn't, we may be connecting to an existing HAL process that might already - // have received events in the past. That means, that HAL could be in an inconsistent state - // once it receives events from the newly created MotionClassifier. - mEvents.push(ClassifierEvent::createHalResetEvent()); - - { - std::scoped_lock lock(mLock); - if (mService) { - ALOGE("MotionClassifier::%s should only be called once", __func__); - } - mService = service; + const bool linked = service->linkToDeath(deathRecipient, 0 /* cookie */).withDefault(false); + if (!linked) { + ALOGE("Could not link death recipient to the HAL death"); + return nullptr; } - return true; + // Using 'new' to access a non-public constructor + return std::unique_ptr(new MotionClassifier(service)); } MotionClassifier::~MotionClassifier() { @@ -195,14 +186,6 @@ MotionClassifier::~MotionClassifier() { mHalThread.join(); } -void MotionClassifier::ensureHalThread(const char* function) { - if (DEBUG) { - if (std::this_thread::get_id() != mHalThread.get_id()) { - LOG_FATAL("Function %s should only be called from InputClassifier thread", function); - } - } -} - /** * Obtain the classification from the HAL for a given MotionEvent. * Should only be called from the InputClassifier thread (mHalThread). @@ -213,23 +196,7 @@ void MotionClassifier::ensureHalThread(const char* function) { * To remove any possibility of negatively affecting the touch latency, the HAL * is called from a dedicated thread. */ -void MotionClassifier::callInputClassifierHal() { - ensureHalThread(__func__); - const bool initialized = init(); - if (!initialized) { - // MotionClassifier no longer useful. - // Deliver death notification from a separate thread - // because ~MotionClassifier may be invoked, which calls mHalThread.join() - std::thread([deathRecipient = mDeathRecipient](){ - sp recipient = deathRecipient.promote(); - if (recipient != nullptr) { - recipient->serviceDied(0 /*cookie*/, nullptr); - } - }).detach(); - return; - } - // From this point on, mService is guaranteed to be non-null. - +void MotionClassifier::processEvents() { while (true) { ClassifierEvent event = mEvents.pop(); bool halResponseOk = true; @@ -389,24 +356,30 @@ void MotionClassifier::dump(std::string& dump) { } } +// --- HalDeathRecipient -// --- InputClassifier --- +InputClassifier::HalDeathRecipient::HalDeathRecipient(InputClassifier& parent) : mParent(parent) {} -InputClassifier::InputClassifier(const sp& listener) : - mListener(listener) { - // The rest of the initialization is done in onFirstRef, because we need to obtain - // an sp to 'this' in order to register for HAL death notifications +void InputClassifier::HalDeathRecipient::serviceDied( + uint64_t cookie, const wp& who) { + sp service = who.promote(); + if (service) { + service->unlinkToDeath(this); + } + mParent.setMotionClassifier(nullptr); } -void InputClassifier::onFirstRef() { - if (!deepPressEnabled()) { - // If feature is not enabled, MotionClassifier should stay null to avoid unnecessary work. - // When MotionClassifier is null, InputClassifier will forward all events - // to the next InputListener, unmodified. - return; - } - std::scoped_lock lock(mLock); - mMotionClassifier = std::make_unique(this); +// --- InputClassifier --- + +InputClassifier::InputClassifier(const sp& listener) + : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) { + mInitializeMotionClassifierThread = std::thread( + [this] { setMotionClassifier(MotionClassifier::create(mHalDeathRecipient)); }); +#if defined(__linux__) + // Set the thread name for debugging + pthread_setname_np(mInitializeMotionClassifierThread.native_handle(), + "Create MotionClassifier"); +#endif } void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { @@ -447,15 +420,10 @@ void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) { mListener->notifyDeviceReset(args); } -void InputClassifier::serviceDied(uint64_t /*cookie*/, - const wp& who) { +void InputClassifier::setMotionClassifier( + std::unique_ptr motionClassifier) { std::scoped_lock lock(mLock); - ALOGE("InputClassifier HAL has died. Setting mMotionClassifier to null"); - mMotionClassifier = nullptr; - sp service = who.promote(); - if (service) { - service->unlinkToDeath(this); - } + mMotionClassifier = std::move(motionClassifier); } void InputClassifier::dump(std::string& dump) { @@ -472,4 +440,8 @@ void InputClassifier::dump(std::string& dump) { dump += "\n"; } +InputClassifier::~InputClassifier() { + mInitializeMotionClassifierThread.join(); +} + } // namespace android diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h index 96923526da..8f586956e5 100644 --- a/services/inputflinger/InputClassifier.h +++ b/services/inputflinger/InputClassifier.h @@ -19,8 +19,8 @@ #include #include -#include #include +#include #include "BlockingQueue.h" #include "InputListener.h" @@ -113,23 +113,23 @@ protected: */ class MotionClassifier final : public MotionClassifierInterface { public: - /** - * The deathRecipient will be subscribed to the HAL death. If the death recipient - * owns MotionClassifier and receives HAL death, it should delete its copy of it. - * The callback serviceDied will also be sent if the MotionClassifier itself fails - * to initialize. If the MotionClassifier fails to initialize, it is not useful, and - * should be deleted. - * If no death recipient is supplied, then the registration step will be skipped, so there will - * be no listeners registered for the HAL death. This is useful for testing - * MotionClassifier in isolation. + /* + * Create an instance of MotionClassifier. + * The death recipient, if provided, will be subscribed to the HAL death. + * The death recipient could be used to destroy MotionClassifier. + * + * This function should be called asynchronously, because getService takes a long time. */ - explicit MotionClassifier(sp deathRecipient = nullptr); + static std::unique_ptr create( + sp deathRecipient); + ~MotionClassifier(); /** * Classifies events asynchronously; that is, it doesn't block events on a classification, - * but instead sends them over to the classifier HAL and after a classification is - * determined, it then marks the next event it sees in the stream with it. + * but instead sends them over to the classifier HAL. After a classification of a specific + * event is determined, MotionClassifier then marks the next event in the stream with this + * classification. * * Therefore, it is acceptable to have the classifications be delayed by 1-2 events * in a particular gesture. @@ -141,15 +141,9 @@ public: virtual void dump(std::string& dump) override; private: - /** - * Initialize MotionClassifier. - * Return true if initializaion is successful. - */ - bool init(); - /** - * Entity that will be notified of the HAL death (most likely InputClassifier). - */ - wp mDeathRecipient; + friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation + explicit MotionClassifier( + sp service); // The events that need to be sent to the HAL. BlockingQueue mEvents; @@ -164,14 +158,9 @@ private: */ std::thread mHalThread; /** - * Print an error message if the caller is not on the InputClassifier thread. - * Caller must supply the name of the calling function as __func__ + * Process events and call the InputClassifier HAL */ - void ensureHalThread(const char* function); - /** - * Call the InputClassifier HAL - */ - void callInputClassifierHal(); + void processEvents(); /** * Access to the InputClassifier HAL. May be null if init() hasn't completed yet. * When init() successfully completes, mService is guaranteed to remain non-null and to not @@ -225,19 +214,15 @@ private: const char* getServiceStatus() REQUIRES(mLock); }; - /** * Implementation of the InputClassifierInterface. * Represents a separate stage of input processing. All of the input events go through this stage. * Acts as a passthrough for all input events except for motion events. * The events of motion type are sent to MotionClassifier. */ -class InputClassifier : public InputClassifierInterface, - public android::hardware::hidl_death_recipient { +class InputClassifier : public InputClassifierInterface { public: explicit InputClassifier(const sp& listener); - // Some of the constructor logic is finished in onFirstRef - virtual void onFirstRef() override; virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; virtual void notifyKey(const NotifyKeyArgs* args) override; @@ -245,17 +230,44 @@ public: virtual void notifySwitch(const NotifySwitchArgs* args) override; virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; - virtual void serviceDied(uint64_t cookie, - const wp& who) override; - virtual void dump(std::string& dump) override; + ~InputClassifier(); + private: // Protect access to mMotionClassifier, since it may become null via a hidl callback std::mutex mLock; - std::unique_ptr mMotionClassifier GUARDED_BY(mLock); // The next stage to pass input events to sp mListener; + + std::unique_ptr mMotionClassifier GUARDED_BY(mLock); + std::thread mInitializeMotionClassifierThread; + /** + * Set the value of mMotionClassifier. + * This is called from 2 different threads: + * 1) mInitializeMotionClassifierThread, when we have constructed a MotionClassifier + * 2) A binder thread of the HalDeathRecipient, which is created when HAL dies. This would cause + * mMotionClassifier to become nullptr. + */ + void setMotionClassifier(std::unique_ptr motionClassifier); + + /** + * The deathRecipient will call setMotionClassifier(null) when the HAL dies. + */ + class HalDeathRecipient : public android::hardware::hidl_death_recipient { + public: + explicit HalDeathRecipient(InputClassifier& parent); + virtual void serviceDied(uint64_t cookie, + const wp& who) override; + + private: + InputClassifier& mParent; + }; + // We retain a reference to death recipient, because the death recipient will be calling + // ~MotionClassifier if the HAL dies. + // If we don't retain a reference, and MotionClassifier is the only owner of the death + // recipient, the serviceDied call will cause death recipient to call its own destructor. + sp mHalDeathRecipient; }; } // namespace android diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp index 40086ef708..b4e755a595 100644 --- a/services/inputflinger/tests/InputClassifier_test.cpp +++ b/services/inputflinger/tests/InputClassifier_test.cpp @@ -22,6 +22,9 @@ #include using namespace android::hardware::input; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::input::common::V1_0::Classification; namespace android { @@ -132,6 +135,27 @@ TEST_F(InputClassifierTest, SendToNextStage_NotifyDeviceResetArgs) { ASSERT_EQ(args, outArgs); } +/** + * A minimal implementation of IInputClassifier. + */ +struct TestHal : public android::hardware::input::classifier::V1_0::IInputClassifier { + Return classify( + const android::hardware::input::common::V1_0::MotionEvent& event) override { + return Classification::NONE; + }; + Return reset() override { return Void(); }; + Return resetDevice(int32_t deviceId) override { return Void(); }; +}; + +/** + * An entity that will be subscribed to the HAL death. + */ +class TestDeathRecipient : public android::hardware::hidl_death_recipient { +public: + virtual void serviceDied(uint64_t cookie, + const wp& who) override{}; +}; + // --- MotionClassifierTest --- class MotionClassifierTest : public testing::Test { @@ -139,7 +163,14 @@ protected: std::unique_ptr mMotionClassifier; virtual void SetUp() override { - mMotionClassifier = std::make_unique(); + mMotionClassifier = MotionClassifier::create(new TestDeathRecipient()); + if (mMotionClassifier == nullptr) { + // If the device running this test does not have IInputClassifier service, + // use the test HAL instead. + // Using 'new' to access non-public constructor + mMotionClassifier = + std::unique_ptr(new MotionClassifier(new TestHal())); + } } }; -- GitLab From 8f4435a3370ec3a7ad56ecb3721d29a0292c06a9 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 11 Mar 2020 17:43:28 -0700 Subject: [PATCH 0927/1255] [Vulkan] Expose instance extensions from implicit layers. Previously the vulkan loader only exposes instance extensions from the driver implementation. Per vkEnumerateInstanceExtensionProperties spec the loader must also advertise instance extensions from implicitly enabled layers. Bug: b/143293104 Test: vkEnumerateInstanceExtensionProperties returns the instance extensions from implicit layers. Change-Id: I17f4ce370bf5f4bba295165a28836e2b7c03a318 --- vulkan/libvulkan/api.cpp | 65 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp index aae72db0fe..e607b058eb 100644 --- a/vulkan/libvulkan/api.cpp +++ b/vulkan/libvulkan/api.cpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -1280,9 +1282,66 @@ VkResult EnumerateInstanceExtensionProperties( return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS; } - // TODO(b/143293104): expose extensions from implicitly enabled layers - return vulkan::driver::EnumerateInstanceExtensionProperties( - nullptr, pPropertyCount, pProperties); + // If the pLayerName is nullptr, we must advertise all instance extensions + // from all implicitly enabled layers and the driver implementation. If + // there are duplicates among layers and the driver implementation, always + // only preserve the top layer closest to the application regardless of the + // spec version. + std::vector properties; + std::unordered_set extensionNames; + + // Expose extensions from implicitly enabled layers. + const std::string layersSetting = + android::GraphicsEnv::getInstance().getDebugLayers(); + if (!layersSetting.empty()) { + std::vector layers = + android::base::Split(layersSetting, ":"); + for (uint32_t i = 0; i < layers.size(); i++) { + const Layer* layer = FindLayer(layers[i].c_str()); + if (!layer) { + continue; + } + uint32_t count = 0; + const VkExtensionProperties* props = + GetLayerInstanceExtensions(*layer, count); + if (count > 0) { + for (uint32_t i = 0; i < count; ++i) { + if (extensionNames.emplace(props[i].extensionName).second) { + properties.push_back(props[i]); + } + } + } + } + } + + // TODO(b/143293104): Parse debug.vulkan.layers properties + + // Expose extensions from driver implementation. + { + uint32_t count = 0; + VkResult result = vulkan::driver::EnumerateInstanceExtensionProperties( + nullptr, &count, nullptr); + if (result == VK_SUCCESS && count > 0) { + std::vector props(count); + result = vulkan::driver::EnumerateInstanceExtensionProperties( + nullptr, &count, props.data()); + for (auto prop : props) { + if (extensionNames.emplace(prop.extensionName).second) { + properties.push_back(prop); + } + } + } + } + + uint32_t totalCount = properties.size(); + if (!pProperties || *pPropertyCount > totalCount) { + *pPropertyCount = totalCount; + } + if (pProperties) { + std::copy(properties.data(), properties.data() + *pPropertyCount, + pProperties); + } + return *pPropertyCount < totalCount ? VK_INCOMPLETE : VK_SUCCESS; } VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, -- GitLab From 2d112c5f625d09bb703b8909289d11f02ee44398 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Mon, 2 Mar 2020 17:46:00 +0800 Subject: [PATCH 0928/1255] Fix input infos are inconsistent between WMS and InputFlinger (2/2) In single focus system, the top focused display may change to the new one when receive a key event. And we would expect the focus could be changed before the event enqueued into inbound queue. This patch refactor 'setInputWindows' to prevent early callback and wakeup in first display, and make sure 'syncInputWindow' could wait until all input windows from all displays updated. Bug: 150250453 Test: atest libinput_tests inputflinger_tests Test: atest --rerun-until-failure 100 WindowFocusTests#testMovingDisplayToTopByKeyEvent Change-Id: I38f53d83738c4fbf570ea3b99e46341a5f9a4c0f --- services/inputflinger/InputManager.cpp | 6 +- .../benchmarks/InputDispatcher_benchmarks.cpp | 4 +- .../dispatcher/InputDispatcher.cpp | 173 +++++++++--------- .../inputflinger/dispatcher/InputDispatcher.h | 6 +- .../include/InputDispatcherInterface.h | 7 +- .../tests/InputDispatcher_test.cpp | 62 +++---- 6 files changed, 131 insertions(+), 127 deletions(-) diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index c7c61cf1ef..f2a0014da4 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -111,8 +111,10 @@ void InputManager::setInputWindows(const std::vector& infos, handlesPerDisplay.emplace(info.displayId, std::vector>()); handlesPerDisplay[info.displayId].push_back(new BinderWindowHandle(info)); } - for (auto const& i : handlesPerDisplay) { - mDispatcher->setInputWindows(i.second, i.first, setInputWindowsListener); + mDispatcher->setInputWindows(handlesPerDisplay); + + if (setInputWindowsListener) { + setInputWindowsListener->onSetInputWindowsFinished(); } } diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index 3b18813cef..7c5c9c5f0c 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -252,7 +252,7 @@ static void benchmarkNotifyMotion(benchmark::State& state) { sp application = new FakeApplicationHandle(); sp window = new FakeWindowHandle(application, dispatcher, "Fake Window"); - dispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + dispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); NotifyMotionArgs motionArgs = generateMotionArgs(); @@ -288,7 +288,7 @@ static void benchmarkInjectMotion(benchmark::State& state) { sp application = new FakeApplicationHandle(); sp window = new FakeWindowHandle(application, dispatcher, "Fake Window"); - dispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + dispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); for (auto _ : state) { MotionEvent event = generateMotionEvent(); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 308d19b085..4ec61b0c63 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3621,6 +3621,18 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( mWindowHandlesByDisplay[displayId] = newHandles; } +void InputDispatcher::setInputWindows( + const std::unordered_map>>& handlesPerDisplay) { + { // acquire lock + std::scoped_lock _l(mLock); + for (auto const& i : handlesPerDisplay) { + setInputWindowsLocked(i.second, i.first); + } + } + // Wake up poll loop since it may need to make new input dispatching choices. + mLooper->wake(); +} + /** * Called from InputManagerService, update window handle list by displayId that can receive input. * A window handle contains information about InputChannel, Touch Region, Types, Focused,... @@ -3628,9 +3640,8 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( * For focused handle, check if need to change and send a cancel event to previous one. * For removed handle, check if need to send a cancel event if already in touch. */ -void InputDispatcher::setInputWindows(const std::vector>& inputWindowHandles, - int32_t displayId, - const sp& setInputWindowsListener) { +void InputDispatcher::setInputWindowsLocked( + const std::vector>& inputWindowHandles, int32_t displayId) { if (DEBUG_FOCUS) { std::string windowList; for (const sp& iwh : inputWindowHandles) { @@ -3638,109 +3649,97 @@ void InputDispatcher::setInputWindows(const std::vector>& } ALOGD("setInputWindows displayId=%" PRId32 " %s", displayId, windowList.c_str()); } - { // acquire lock - std::scoped_lock _l(mLock); - // Copy old handles for release if they are no longer present. - const std::vector> oldWindowHandles = - getWindowHandlesLocked(displayId); + // Copy old handles for release if they are no longer present. + const std::vector> oldWindowHandles = getWindowHandlesLocked(displayId); - updateWindowHandlesForDisplayLocked(inputWindowHandles, displayId); + updateWindowHandlesForDisplayLocked(inputWindowHandles, displayId); - sp newFocusedWindowHandle = nullptr; - bool foundHoveredWindow = false; - for (const sp& windowHandle : getWindowHandlesLocked(displayId)) { - // Set newFocusedWindowHandle to the top most focused window instead of the last one - if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus && - windowHandle->getInfo()->visible) { - newFocusedWindowHandle = windowHandle; - } - if (windowHandle == mLastHoverWindowHandle) { - foundHoveredWindow = true; - } + sp newFocusedWindowHandle = nullptr; + bool foundHoveredWindow = false; + for (const sp& windowHandle : getWindowHandlesLocked(displayId)) { + // Set newFocusedWindowHandle to the top most focused window instead of the last one + if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus && + windowHandle->getInfo()->visible) { + newFocusedWindowHandle = windowHandle; } - - if (!foundHoveredWindow) { - mLastHoverWindowHandle = nullptr; + if (windowHandle == mLastHoverWindowHandle) { + foundHoveredWindow = true; } + } - sp oldFocusedWindowHandle = - getValueByKey(mFocusedWindowHandlesByDisplay, displayId); + if (!foundHoveredWindow) { + mLastHoverWindowHandle = nullptr; + } - if (!haveSameToken(oldFocusedWindowHandle, newFocusedWindowHandle)) { - if (oldFocusedWindowHandle != nullptr) { - if (DEBUG_FOCUS) { - ALOGD("Focus left window: %s in display %" PRId32, - oldFocusedWindowHandle->getName().c_str(), displayId); - } - sp focusedInputChannel = - getInputChannelLocked(oldFocusedWindowHandle->getToken()); - if (focusedInputChannel != nullptr) { - CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, - "focus left window"); - synthesizeCancelationEventsForInputChannelLocked(focusedInputChannel, options); - enqueueFocusEventLocked(*oldFocusedWindowHandle, false /*hasFocus*/); - } - mFocusedWindowHandlesByDisplay.erase(displayId); + sp oldFocusedWindowHandle = + getValueByKey(mFocusedWindowHandlesByDisplay, displayId); + + if (!haveSameToken(oldFocusedWindowHandle, newFocusedWindowHandle)) { + if (oldFocusedWindowHandle != nullptr) { + if (DEBUG_FOCUS) { + ALOGD("Focus left window: %s in display %" PRId32, + oldFocusedWindowHandle->getName().c_str(), displayId); } - if (newFocusedWindowHandle != nullptr) { - if (DEBUG_FOCUS) { - ALOGD("Focus entered window: %s in display %" PRId32, - newFocusedWindowHandle->getName().c_str(), displayId); - } - mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle; - enqueueFocusEventLocked(*newFocusedWindowHandle, true /*hasFocus*/); + sp focusedInputChannel = + getInputChannelLocked(oldFocusedWindowHandle->getToken()); + if (focusedInputChannel != nullptr) { + CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, + "focus left window"); + synthesizeCancelationEventsForInputChannelLocked(focusedInputChannel, options); + enqueueFocusEventLocked(*oldFocusedWindowHandle, false /*hasFocus*/); } - - if (mFocusedDisplayId == displayId) { - onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle); + mFocusedWindowHandlesByDisplay.erase(displayId); + } + if (newFocusedWindowHandle != nullptr) { + if (DEBUG_FOCUS) { + ALOGD("Focus entered window: %s in display %" PRId32, + newFocusedWindowHandle->getName().c_str(), displayId); } + mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle; + enqueueFocusEventLocked(*newFocusedWindowHandle, true /*hasFocus*/); } - ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId); - if (stateIndex >= 0) { - TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex); - for (size_t i = 0; i < state.windows.size();) { - TouchedWindow& touchedWindow = state.windows[i]; - if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { - if (DEBUG_FOCUS) { - ALOGD("Touched window was removed: %s in display %" PRId32, - touchedWindow.windowHandle->getName().c_str(), displayId); - } - sp touchedInputChannel = - getInputChannelLocked(touchedWindow.windowHandle->getToken()); - if (touchedInputChannel != nullptr) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "touched window was removed"); - synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, - options); - } - state.windows.erase(state.windows.begin() + i); - } else { - ++i; - } - } + if (mFocusedDisplayId == displayId) { + onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle); } + } - // Release information for windows that are no longer present. - // This ensures that unused input channels are released promptly. - // Otherwise, they might stick around until the window handle is destroyed - // which might not happen until the next GC. - for (const sp& oldWindowHandle : oldWindowHandles) { - if (!hasWindowHandleLocked(oldWindowHandle)) { + ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId); + if (stateIndex >= 0) { + TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex); + for (size_t i = 0; i < state.windows.size();) { + TouchedWindow& touchedWindow = state.windows[i]; + if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { if (DEBUG_FOCUS) { - ALOGD("Window went away: %s", oldWindowHandle->getName().c_str()); + ALOGD("Touched window was removed: %s in display %" PRId32, + touchedWindow.windowHandle->getName().c_str(), displayId); + } + sp touchedInputChannel = + getInputChannelLocked(touchedWindow.windowHandle->getToken()); + if (touchedInputChannel != nullptr) { + CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, + "touched window was removed"); + synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, options); } - oldWindowHandle->releaseChannel(); + state.windows.erase(state.windows.begin() + i); + } else { + ++i; } } - } // release lock - - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); + } - if (setInputWindowsListener) { - setInputWindowsListener->onSetInputWindowsFinished(); + // Release information for windows that are no longer present. + // This ensures that unused input channels are released promptly. + // Otherwise, they might stick around until the window handle is destroyed + // which might not happen until the next GC. + for (const sp& oldWindowHandle : oldWindowHandles) { + if (!hasWindowHandleLocked(oldWindowHandle)) { + if (DEBUG_FOCUS) { + ALOGD("Window went away: %s", oldWindowHandle->getName().c_str()); + } + oldWindowHandle->releaseChannel(); + } } } diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 4aa47f89f0..cbba7e1318 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -109,8 +109,8 @@ public: virtual std::unique_ptr verifyInputEvent(const InputEvent& event) override; virtual void setInputWindows( - const std::vector>& inputWindowHandles, int32_t displayId, - const sp& setInputWindowsListener = nullptr) override; + const std::unordered_map>>& + handlesPerDisplay) override; virtual void setFocusedApplication( int32_t displayId, const sp& inputApplicationHandle) override; virtual void setFocusedDisplay(int32_t displayId) override; @@ -278,6 +278,8 @@ private: std::unordered_map>> mWindowHandlesByDisplay GUARDED_BY(mLock); + void setInputWindowsLocked(const std::vector>& inputWindowHandles, + int32_t displayId) REQUIRES(mLock); // Get window handles by display, return an empty vector if not found. std::vector> getWindowHandlesLocked(int32_t displayId) const REQUIRES(mLock); diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index 6e986768fc..09dc92c8fa 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -19,6 +19,7 @@ #include #include +#include namespace android { @@ -99,13 +100,13 @@ public: */ virtual std::unique_ptr verifyInputEvent(const InputEvent& event) = 0; - /* Sets the list of input windows. + /* Sets the list of input windows per display. * * This method may be called on any thread (usually by the input manager). */ virtual void setInputWindows( - const std::vector >& inputWindowHandles, int32_t displayId, - const sp& setInputWindowsListener = nullptr) = 0; + const std::unordered_map>>& + handlesPerDisplay) = 0; /* Sets the focused application on the given display. * diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 1f283b18ac..29f3dac03e 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -871,7 +871,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) { sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; @@ -888,7 +888,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) { sp windowSecond = new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({windowTop, windowSecond}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}}); ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; @@ -910,7 +910,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_FocusedWindow) { // Display should have only one focused window windowSecond->setFocus(true); - mDispatcher->setInputWindows({windowTop, windowSecond}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}}); windowSecond->consumeFocusEvent(true); ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher)) @@ -935,7 +935,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_FocusPriority) { windowTop->setFocus(true); windowSecond->setFocus(true); - mDispatcher->setInputWindows({windowTop, windowSecond}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}}); windowTop->consumeFocusEvent(true); ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher)) << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED"; @@ -960,7 +960,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_InputWindowInfo) { windowSecond->setFocus(true); // Release channel for window is no longer valid. windowTop->releaseChannel(); - mDispatcher->setInputWindows({windowTop, windowSecond}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}}); windowSecond->consumeFocusEvent(true); // Test inject a key down, should dispatch to a valid window. @@ -986,7 +986,7 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - mDispatcher->setInputWindows({windowLeft, windowRight}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowLeft, windowRight}}}); // Inject an event with coordinate in the area of right window, with mouse cursor in the area of // left window. This event should be dispatched to the left window. @@ -1003,7 +1003,7 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) { new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocus(true); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); window->consumeFocusEvent(true); NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); @@ -1025,7 +1025,7 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) { sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); NotifyMotionArgs motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, @@ -1053,7 +1053,7 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) { "Second Window", ADISPLAY_ID_DEFAULT); // Add the windows to the dispatcher - mDispatcher->setInputWindows({firstWindow, secondWindow}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); // Send down to the first window NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, @@ -1090,7 +1090,7 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) { "Second Window", ADISPLAY_ID_DEFAULT); // Add the windows to the dispatcher - mDispatcher->setInputWindows({firstWindow, secondWindow}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); // Send down to the first window NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, @@ -1152,7 +1152,7 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { | InputWindowInfo::FLAG_SPLIT_TOUCH); // Add the windows to the dispatcher - mDispatcher->setInputWindows({firstWindow, secondWindow}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); PointF pointInFirst = {300, 200}; PointF pointInSecond = {300, 600}; @@ -1204,7 +1204,7 @@ TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) { new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocus(true); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); window->consumeFocusEvent(true); @@ -1220,7 +1220,7 @@ TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); mDispatcher->notifyKey(&keyArgs); @@ -1235,7 +1235,7 @@ TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) { sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); // Send key NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); @@ -1289,7 +1289,7 @@ TEST_F(InputDispatcherTest, GestureMonitor_ReceivesMotionEvents) { sp application = new FakeApplicationHandle(); sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT, true /*isGestureMonitor*/); @@ -1309,7 +1309,7 @@ TEST_F(InputDispatcherTest, GestureMonitor_DoesNotReceiveKeyEvents) { mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocus(true); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); window->consumeFocusEvent(true); FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT, @@ -1325,7 +1325,7 @@ TEST_F(InputDispatcherTest, GestureMonitor_CanPilferAfterWindowIsRemovedMidStrea sp application = new FakeApplicationHandle(); sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT, true /*isGestureMonitor*/); @@ -1351,7 +1351,7 @@ TEST_F(InputDispatcherTest, TestMoveEvent) { sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); NotifyMotionArgs motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, @@ -1387,29 +1387,29 @@ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) { window->setFocus(true); SCOPED_TRACE("Check default value of touch mode"); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/); SCOPED_TRACE("Remove the window to trigger focus loss"); window->setFocus(false); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); window->consumeFocusEvent(false /*hasFocus*/, true /*inTouchMode*/); SCOPED_TRACE("Disable touch mode"); mDispatcher->setInTouchMode(false); window->setFocus(true); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); window->consumeFocusEvent(true /*hasFocus*/, false /*inTouchMode*/); SCOPED_TRACE("Remove the window to trigger focus loss"); window->setFocus(false); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); window->consumeFocusEvent(false /*hasFocus*/, false /*inTouchMode*/); SCOPED_TRACE("Enable touch mode again"); mDispatcher->setInTouchMode(true); window->setFocus(true); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/); window->assertNoEvents(); @@ -1423,7 +1423,7 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocus(true); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/); NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN); @@ -1459,7 +1459,7 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); NotifyMotionArgs motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, @@ -1512,7 +1512,7 @@ protected: mWindow = new FakeWindowHandle(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); mWindow->setFocus(true); - mDispatcher->setInputWindows({mWindow}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); mWindow->consumeFocusEvent(true); } @@ -1602,7 +1602,7 @@ public: // Set focus window for primary display, but focused display would be second one. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1); windowInPrimary->setFocus(true); - mDispatcher->setInputWindows({windowInPrimary}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowInPrimary}}}); windowInPrimary->consumeFocusEvent(true); application2 = new FakeApplicationHandle(); @@ -1614,7 +1614,7 @@ public: // Set focus window for second display. mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2); windowInSecondary->setFocus(true); - mDispatcher->setInputWindows({windowInSecondary}, SECOND_DISPLAY_ID); + mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}}); windowInSecondary->consumeFocusEvent(true); } @@ -1664,7 +1664,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE); // Remove all windows in secondary display. - mDispatcher->setInputWindows({}, SECOND_DISPLAY_ID); + mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {}}}); // Expect old focus should receive a cancel event. windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, AKEY_EVENT_ACTION_UP, ADISPLAY_ID_NONE, @@ -1828,7 +1828,7 @@ class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { mFocusedWindow->setFocus(true); // Expect one focus window exist in display. - mDispatcher->setInputWindows({mUnfocusedWindow, mFocusedWindow}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}}); mFocusedWindow->consumeFocusEvent(true); } @@ -1916,7 +1916,7 @@ class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest { mWindow2->setId(1); mWindow2->setFrame(Rect(100, 100, 200, 200)); - mDispatcher->setInputWindows({mWindow1, mWindow2}, ADISPLAY_ID_DEFAULT); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}}); } protected: -- GitLab From 38a4b21e9a2495b8585e082cde57fad06b115d96 Mon Sep 17 00:00:00 2001 From: Tej Singh Date: Fri, 13 Mar 2020 19:04:51 -0700 Subject: [PATCH 0929/1255] Update GpuStats/SFStats for puller API feedback Update gpustats and surfaceflinger for statsd native puller API feedback. Test: make Test: atest libsurfaceflinger_unittest Test: atest gpuservice_unittest Bug: 150788562 Change-Id: I1ba09b0c06ec7fb50dfd2b63ed0291a54e69d917 --- services/gpuservice/gpustats/GpuStats.cpp | 12 ++++++------ .../surfaceflinger/TimeStats/TimeStats.cpp | 13 ++++++------- services/surfaceflinger/TimeStats/TimeStats.h | 14 +++++++------- .../tests/unittests/TimeStatsTest.cpp | 19 +++++++++---------- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp index 263bf61c12..231d0684c9 100644 --- a/services/gpuservice/gpustats/GpuStats.cpp +++ b/services/gpuservice/gpustats/GpuStats.cpp @@ -32,8 +32,8 @@ namespace android { GpuStats::~GpuStats() { if (mStatsdRegistered) { - AStatsManager_unregisterPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO); - AStatsManager_unregisterPullAtomCallback(android::util::GPU_STATS_APP_INFO); + AStatsManager_clearPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO); + AStatsManager_clearPullAtomCallback(android::util::GPU_STATS_APP_INFO); } } @@ -178,10 +178,10 @@ void GpuStats::interceptSystemDriverStatsLocked() { void GpuStats::registerStatsdCallbacksIfNeeded() { if (!mStatsdRegistered) { - AStatsManager_registerPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO, - GpuStats::pullAtomCallback, nullptr, this); - AStatsManager_registerPullAtomCallback(android::util::GPU_STATS_APP_INFO, - GpuStats::pullAtomCallback, nullptr, this); + AStatsManager_setPullAtomCallback(android::util::GPU_STATS_GLOBAL_INFO, nullptr, + GpuStats::pullAtomCallback, this); + AStatsManager_setPullAtomCallback(android::util::GPU_STATS_APP_INFO, nullptr, + GpuStats::pullAtomCallback, this); mStatsdRegistered = true; } } diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 8038eba2e1..4f59bf247c 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -188,17 +188,16 @@ TimeStats::TimeStats(std::unique_ptr statsDelegate, TimeStats::~TimeStats() { std::lock_guard lock(mMutex); - mStatsDelegate->unregisterStatsPullAtomCallback( - android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); - mStatsDelegate->unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO); + mStatsDelegate->clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); + mStatsDelegate->clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO); } void TimeStats::onBootFinished() { std::lock_guard lock(mMutex); - mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, - TimeStats::pullAtomCallback, nullptr, this); - mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO, - TimeStats::pullAtomCallback, nullptr, this); + mStatsDelegate->setStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, + nullptr, TimeStats::pullAtomCallback, this); + mStatsDelegate->setStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO, + nullptr, TimeStats::pullAtomCallback, this); } void TimeStats::parseArgs(bool asProto, const Vector& args, std::string& result) { diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index ddebeb184b..f9bd90babd 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -165,15 +165,15 @@ public: virtual AStatsEvent* addStatsEventToPullData(AStatsEventList* data) { return AStatsEventList_addStatsEvent(data); } - virtual void registerStatsPullAtomCallback(int32_t atom_tag, - AStatsManager_PullAtomCallback callback, - AStatsManager_PullAtomMetadata* metadata, - void* cookie) { - return AStatsManager_registerPullAtomCallback(atom_tag, callback, metadata, cookie); + virtual void setStatsPullAtomCallback(int32_t atom_tag, + AStatsManager_PullAtomMetadata* metadata, + AStatsManager_PullAtomCallback callback, + void* cookie) { + return AStatsManager_setPullAtomCallback(atom_tag, metadata, callback, cookie); } - virtual void unregisterStatsPullAtomCallback(int32_t atom_tag) { - return AStatsManager_unregisterPullAtomCallback(atom_tag); + virtual void clearStatsPullAtomCallback(int32_t atom_tag) { + return AStatsManager_clearPullAtomCallback(atom_tag); } virtual void statsEventSetAtomId(AStatsEvent* event, uint32_t atom_id) { diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index a7a4d4837e..4f65aee43f 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -152,9 +152,9 @@ public: struct AStatsEvent* addStatsEventToPullData(AStatsEventList*) override { return mEvent; } - void registerStatsPullAtomCallback(int32_t atom_tag, - AStatsManager_PullAtomCallback callback, - AStatsManager_PullAtomMetadata*, void* cookie) override { + void setStatsPullAtomCallback(int32_t atom_tag, AStatsManager_PullAtomMetadata*, + AStatsManager_PullAtomCallback callback, + void* cookie) override { mAtomTags.push_back(atom_tag); mCallback = callback; mCookie = cookie; @@ -164,7 +164,7 @@ public: return (*mCallback)(atom_tag, nullptr, cookie); } - MOCK_METHOD1(unregisterStatsPullAtomCallback, void(int32_t)); + MOCK_METHOD1(clearStatsPullAtomCallback, void(int32_t)); MOCK_METHOD2(statsEventSetAtomId, void(AStatsEvent*, uint32_t)); MOCK_METHOD2(statsEventWriteInt32, void(AStatsEvent*, int32_t)); MOCK_METHOD2(statsEventWriteInt64, void(AStatsEvent*, int64_t)); @@ -261,18 +261,18 @@ TEST_F(TimeStatsTest, disabledByDefault) { ASSERT_FALSE(mTimeStats->isEnabled()); } -TEST_F(TimeStatsTest, registersCallbacksAfterBoot) { +TEST_F(TimeStatsTest, setsCallbacksAfterBoot) { mTimeStats->onBootFinished(); EXPECT_THAT(mDelegate->mAtomTags, UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, android::util::SURFACEFLINGER_STATS_LAYER_INFO)); } -TEST_F(TimeStatsTest, unregistersCallbacksOnDestruction) { +TEST_F(TimeStatsTest, clearsCallbacksOnDestruction) { EXPECT_CALL(*mDelegate, - unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO)); + clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO)); EXPECT_CALL(*mDelegate, - unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO)); + clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO)); mTimeStats.reset(); } @@ -1039,8 +1039,7 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) { insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000); - // Now make sure that TimeStats flushes global stats to register the - // callback. + // Now make sure that TimeStats flushes global stats to set the callback. mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL); mTimeStats->setPresentFenceGlobal(std::make_shared(3000000)); mTimeStats->setPresentFenceGlobal(std::make_shared(5000000)); -- GitLab From 422b529ac0f4dd4acb9cdd7d67d43071870c94b8 Mon Sep 17 00:00:00 2001 From: Stefano Galarraga Date: Fri, 13 Mar 2020 08:37:51 +0000 Subject: [PATCH 0930/1255] Merge "Add neuralnetworks HAL Dump" Bug: 145388549 Test: Manually, take bugreport and look for lines with "neuralnetworks@" sysTid" Change-Id: If9fe80bcf0ff8235da87418666d2a63c496ba4ba Merged-In: If9fe80bcf0ff8235da87418666d2a63c496ba4ba --- libs/dumputils/dump_utils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp index 5b65c95e95..b2b74dce6e 100644 --- a/libs/dumputils/dump_utils.cpp +++ b/libs/dumputils/dump_utils.cpp @@ -75,6 +75,7 @@ static const char* hal_interfaces_to_dump[] { "android.hardware.automotive.audiocontrol@1.0::IAudioControl", "android.hardware.automotive.vehicle@2.0::IVehicle", "android.hardware.automotive.evs@1.0::IEvsCamera", + "android.hardware.neuralnetworks@1.0::IDevice", NULL, }; -- GitLab From c65e8644c524ab1c75e1596864940c2d8dcb8761 Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 18 Mar 2020 15:35:48 -0700 Subject: [PATCH 0931/1255] Remove promoting weak pointer off main thread. If a Layer weak pointer is promoted on a thread other than the main thread, it risks calling the destructor off the main thread. This causes a lot of issues since there is no lock held in the Layer destructor. The destructor expects to only ever get called on the main thread The change here stores a raw pointer instead of a weak pointer. This should be safe since BufferLayerConsumer lifecycle follows the Layer lifecycle so the raw Layer pointer will never be invalid. Test: Not easy to reproduce but no issues with this change Fixes: 150879387 Change-Id: I51fbc2ca5052c5dbf8e875b557a034d40e4a0b39 --- services/surfaceflinger/BufferLayerConsumer.cpp | 10 ++-------- services/surfaceflinger/BufferLayerConsumer.h | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 5e04d9597a..e50a9095fe 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -443,10 +443,7 @@ void BufferLayerConsumer::freeBufferLocked(int slotIndex) { } void BufferLayerConsumer::onDisconnect() { - sp l = mLayer.promote(); - if (l.get()) { - l->onDisconnect(); - } + mLayer->onDisconnect(); } void BufferLayerConsumer::onSidebandStreamChanged() { @@ -480,10 +477,7 @@ void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) { void BufferLayerConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, FrameEventHistoryDelta* outDelta) { - sp l = mLayer.promote(); - if (l.get()) { - l->addAndGetFrameTimestamps(newTimestamps, outDelta); - } + mLayer->addAndGetFrameTimestamps(newTimestamps, outDelta); } void BufferLayerConsumer::abandonLocked() { diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index 39ed3707dd..c71a1d9f7a 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -332,7 +332,7 @@ private: const uint32_t mTexName; // The layer for this BufferLayerConsumer - const wp mLayer; + Layer* mLayer; wp mContentsChangedListener; -- GitLab From ad66337afe89e3f66dff834d6f40d2071f5a1a7b Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Thu, 19 Mar 2020 12:44:36 -0700 Subject: [PATCH 0932/1255] Use a VBO when drawing blurs Until now, we were uploading the vertex and uv data for every draw call, this is not great. This CL created a packed vertex buffer, uploads it to the graphics card and reuses it. Test: SurfaceFlinger_tests Test: manual Bug: 149792636 Change-Id: Iee72a9a815a8ea43880a21c1b4c61320dea20dff --- libs/renderengine/Android.bp | 1 + libs/renderengine/gl/GLVertexBuffer.cpp | 55 ++++++++++++++ libs/renderengine/gl/GLVertexBuffer.h | 49 +++++++++++++ libs/renderengine/gl/filters/BlurFilter.cpp | 79 +++++++++++---------- libs/renderengine/gl/filters/BlurFilter.h | 4 ++ 5 files changed, 149 insertions(+), 39 deletions(-) create mode 100644 libs/renderengine/gl/GLVertexBuffer.cpp create mode 100644 libs/renderengine/gl/GLVertexBuffer.h diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 1075f161e4..eb6080fc21 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -55,6 +55,7 @@ filegroup { "gl/GLShadowTexture.cpp", "gl/GLShadowVertexGenerator.cpp", "gl/GLSkiaShadowPort.cpp", + "gl/GLVertexBuffer.cpp", "gl/ImageManager.cpp", "gl/Program.cpp", "gl/ProgramCache.cpp", diff --git a/libs/renderengine/gl/GLVertexBuffer.cpp b/libs/renderengine/gl/GLVertexBuffer.cpp new file mode 100644 index 0000000000..e50c471b6d --- /dev/null +++ b/libs/renderengine/gl/GLVertexBuffer.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "GLVertexBuffer.h" + +#include +#include +#include +#include + +namespace android { +namespace renderengine { +namespace gl { + +GLVertexBuffer::GLVertexBuffer() { + glGenBuffers(1, &mBufferName); +} + +GLVertexBuffer::~GLVertexBuffer() { + glDeleteBuffers(1, &mBufferName); +} + +void GLVertexBuffer::allocateBuffers(const GLfloat data[], const GLuint size) { + ATRACE_CALL(); + bind(); + glBufferData(GL_ARRAY_BUFFER, size * sizeof(GLfloat), data, GL_STATIC_DRAW); + unbind(); +} + +void GLVertexBuffer::bind() const { + glBindBuffer(GL_ARRAY_BUFFER, mBufferName); +} + +void GLVertexBuffer::unbind() const { + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +} // namespace gl +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/gl/GLVertexBuffer.h b/libs/renderengine/gl/GLVertexBuffer.h new file mode 100644 index 0000000000..c0fd0c1b04 --- /dev/null +++ b/libs/renderengine/gl/GLVertexBuffer.h @@ -0,0 +1,49 @@ +/* + * 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 + +#include +#include +#include + +struct ANativeWindowBuffer; + +namespace android { +namespace renderengine { +namespace gl { + +class GLESRenderEngine; + +class GLVertexBuffer { +public: + explicit GLVertexBuffer(); + ~GLVertexBuffer(); + + void allocateBuffers(const GLfloat data[], const GLuint size); + uint32_t getBufferName() const { return mBufferName; } + void bind() const; + void unbind() const; + +private: + uint32_t mBufferName; +}; + +} // namespace gl +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index e704907dac..6ba78dc025 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -49,6 +49,20 @@ BlurFilter::BlurFilter(GLESRenderEngine& engine) mBUvLoc = mBlurProgram.getAttributeLocation("aUV"); mBTextureLoc = mBlurProgram.getUniformLocation("uTexture"); mBOffsetLoc = mBlurProgram.getUniformLocation("uOffset"); + + static constexpr auto size = 2.0f; + static constexpr auto translation = 1.0f; + const GLfloat vboData[] = { + // Vertex data + translation-size, -translation-size, + translation-size, -translation+size, + translation+size, -translation+size, + // UV data + 0.0f, 0.0f-translation, + 0.0f, size-translation, + size, size-translation + }; + mMeshBuffer.allocateBuffers(vboData, 12 /* size */); } status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t radius) { @@ -65,15 +79,23 @@ status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t ra mPingFbo.allocateBuffers(fboWidth, fboHeight); mPongFbo.allocateBuffers(fboWidth, fboHeight); mTexturesAllocated = true; - } - if (mPingFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid blur buffer"); - return mPingFbo.getStatus(); - } - if (mCompositionFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid composition buffer"); - return mCompositionFbo.getStatus(); + if (mPingFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { + ALOGE("Invalid ping buffer"); + return mPingFbo.getStatus(); + } + if (mPongFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { + ALOGE("Invalid pong buffer"); + return mPongFbo.getStatus(); + } + if (mCompositionFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { + ALOGE("Invalid composition buffer"); + return mCompositionFbo.getStatus(); + } + if (!mBlurProgram.isValid()) { + ALOGE("Invalid shader"); + return GL_INVALID_OPERATION; + } } mCompositionFbo.bind(); @@ -82,43 +104,22 @@ status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t ra } void BlurFilter::drawMesh(GLuint uv, GLuint position) { - static constexpr auto size = 2.0f; - static constexpr auto translation = 1.0f; - GLfloat positions[] = { - translation-size, -translation-size, - translation-size, -translation+size, - translation+size, -translation+size - }; - GLfloat texCoords[] = { - 0.0f, 0.0f-translation, - 0.0f, size-translation, - size, size-translation - }; - // set attributes glEnableVertexAttribArray(uv); - glVertexAttribPointer(uv, 2 /* size */, GL_FLOAT, GL_FALSE, 0, texCoords); glEnableVertexAttribArray(position); - glVertexAttribPointer(position, 2 /* size */, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), - positions); + mMeshBuffer.bind(); + glVertexAttribPointer(position, 2 /* size */, GL_FLOAT, GL_FALSE, + 2 * sizeof(GLfloat) /* stride */, 0 /* offset */); + glVertexAttribPointer(uv, 2 /* size */, GL_FLOAT, GL_FALSE, 0 /* stride */, + (GLvoid*)(6 * sizeof(GLfloat)) /* offset */); + mMeshBuffer.unbind(); // draw mesh glDrawArrays(GL_TRIANGLES, 0 /* first */, 3 /* count */); - mEngine.checkErrors("Drawing blur mesh"); } status_t BlurFilter::prepare() { ATRACE_NAME("BlurFilter::prepare"); - - if (mPongFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid FBO"); - return mPongFbo.getStatus(); - } - if (!mBlurProgram.isValid()) { - ALOGE("Invalid shader"); - return GL_INVALID_OPERATION; - } - blit(mCompositionFbo, mPingFbo); // Kawase is an approximation of Gaussian, but it behaves differently from it. @@ -136,16 +137,15 @@ status_t BlurFilter::prepare() { GLFramebuffer* draw = &mPongFbo; float stepX = radius / (float)mCompositionFbo.getBufferWidth() / (float)passes; float stepY = radius / (float)mCompositionFbo.getBufferHeight() / (float)passes; + glViewport(0, 0, draw->getBufferWidth(), draw->getBufferHeight()); glActiveTexture(GL_TEXTURE0); glUniform1i(mBTextureLoc, 0); for (auto i = 0; i < passes; i++) { ATRACE_NAME("BlurFilter::renderPass"); draw->bind(); - glViewport(0, 0, draw->getBufferWidth(), draw->getBufferHeight()); glBindTexture(GL_TEXTURE_2D, read->getTextureName()); glUniform2f(mBOffsetLoc, stepX * i, stepY * i); - mEngine.checkErrors("Setting uniforms"); drawMesh(mBUvLoc, mBPosLoc); @@ -189,17 +189,18 @@ status_t BlurFilter::render(bool multiPass) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName()); glUniform1i(mMCompositionTextureLoc, 1); - mEngine.checkErrors("Setting final pass uniforms"); drawMesh(mMUvLoc, mMPosLoc); glUseProgram(0); glActiveTexture(GL_TEXTURE0); + mEngine.checkErrors("Drawing blur mesh"); return NO_ERROR; } string BlurFilter::getVertexShader() const { return R"SHADER(#version 310 es + precision mediump float; in vec2 aPosition; in highp vec2 aUV; @@ -219,7 +220,7 @@ string BlurFilter::getFragmentShader() const { uniform sampler2D uTexture; uniform vec2 uOffset; - highp in vec2 vUV; + in highp vec2 vUV; out vec4 fragColor; void main() { diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h index eb6120ba92..3eb5c96664 100644 --- a/libs/renderengine/gl/filters/BlurFilter.h +++ b/libs/renderengine/gl/filters/BlurFilter.h @@ -19,6 +19,7 @@ #include #include "../GLESRenderEngine.h" #include "../GLFramebuffer.h" +#include "../GLVertexBuffer.h" #include "GenericProgram.h" using namespace std; @@ -72,6 +73,9 @@ private: GLFramebuffer* mLastDrawTarget; bool mTexturesAllocated = false; + // VBO containing vertex and uv data of a fullscreen triangle. + GLVertexBuffer mMeshBuffer; + GenericProgram mMixProgram; GLuint mMPosLoc; GLuint mMUvLoc; -- GitLab From 5251a6a258f0ee90b8c1ea4275f84a21fae7a03d Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Thu, 19 Mar 2020 13:04:16 -0700 Subject: [PATCH 0933/1255] Remove obsolete functionality Multi-texture targets were introduce to optimize performance of lens blur, which is long gone. Test: make Bug: 149792636 Change-Id: Ibbc2552deb1a7d2a631e7d0bd6fa2532ab7719d4 --- libs/renderengine/gl/GLFramebuffer.cpp | 25 ------------------------- libs/renderengine/gl/GLFramebuffer.h | 2 -- 2 files changed, 27 deletions(-) diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp index 153935b678..cb0d5cf95c 100644 --- a/libs/renderengine/gl/GLFramebuffer.cpp +++ b/libs/renderengine/gl/GLFramebuffer.cpp @@ -32,23 +32,14 @@ namespace renderengine { namespace gl { GLFramebuffer::GLFramebuffer(GLESRenderEngine& engine) - : GLFramebuffer(engine, false /* multiTarget */) {} - -GLFramebuffer::GLFramebuffer(GLESRenderEngine& engine, bool multiTarget) : mEngine(engine), mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) { glGenTextures(1, &mTextureName); - if (multiTarget) { - glGenTextures(1, &mSecondaryTextureName); - } glGenFramebuffers(1, &mFramebufferName); } GLFramebuffer::~GLFramebuffer() { glDeleteFramebuffers(1, &mFramebufferName); glDeleteTextures(1, &mTextureName); - if (mSecondaryTextureName != -1) { - glDeleteTextures(1, &mSecondaryTextureName); - } } bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected, @@ -87,28 +78,12 @@ void GLFramebuffer::allocateBuffers(uint32_t width, uint32_t height) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); - const bool multiTarget = mSecondaryTextureName != -1; - if (multiTarget) { - glBindTexture(GL_TEXTURE_2D, mSecondaryTextureName); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); - } - mBufferHeight = height; mBufferWidth = width; mEngine.checkErrors("Allocating Fbo texture"); bind(); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextureName, 0); - if (multiTarget) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, - mSecondaryTextureName, 0); - GLenum buffers[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT}; - glDrawBuffers(2, buffers); - } mStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); unbind(); glBindTexture(GL_TEXTURE_2D, 0); diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h index 69102d6e78..b88da3b133 100644 --- a/libs/renderengine/gl/GLFramebuffer.h +++ b/libs/renderengine/gl/GLFramebuffer.h @@ -42,7 +42,6 @@ public: void allocateBuffers(uint32_t width, uint32_t height); EGLImageKHR getEGLImage() const { return mEGLImage; } uint32_t getTextureName() const { return mTextureName; } - uint32_t getSecondaryTextureName() const { return mSecondaryTextureName; } uint32_t getFramebufferName() const { return mFramebufferName; } int32_t getBufferHeight() const { return mBufferHeight; } int32_t getBufferWidth() const { return mBufferWidth; } @@ -59,7 +58,6 @@ private: bool usingFramebufferCache = false; GLenum mStatus = GL_FRAMEBUFFER_UNSUPPORTED; uint32_t mTextureName, mFramebufferName; - uint32_t mSecondaryTextureName = -1; int32_t mBufferHeight = 0; int32_t mBufferWidth = 0; -- GitLab From bdb9e6d75bf6c4c73d948d1ada85d74b103b1a1e Mon Sep 17 00:00:00 2001 From: Sushil Chauhan Date: Thu, 19 Mar 2020 16:15:46 -0700 Subject: [PATCH 0934/1255] sf: Construct Phase Offsets for unknown fps External display can support a Refresh Rate value which doesn't exist in keys of mOffsets map which has been created with RefreshRateConfigs of Primary display, based on current design. This is not a fatal error scenario. In such a case, construct Phase Offsets with current logic. CRs-Fixed: 2643508 Bug: 151859083 Test: boot Change-Id: Ib89f0dbc3db6bdd3e41681c31c567890487c453f --- .../surfaceflinger/Scheduler/PhaseOffsets.cpp | 29 +++++++++++++------ .../surfaceflinger/Scheduler/PhaseOffsets.h | 5 ++-- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index c04447d106..7941cda6ef 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -71,15 +71,20 @@ std::unordered_map PhaseOffsets::initializeOffsets std::unordered_map offsets; for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) { - if (refreshRate->fps > 65.0f) { - offsets.emplace(refreshRate->fps, getHighFpsOffsets(refreshRate->vsyncPeriod)); - } else { - offsets.emplace(refreshRate->fps, getDefaultOffsets(refreshRate->vsyncPeriod)); - } + const float fps = refreshRate->fps; + offsets.emplace(fps, getPhaseOffsets(fps, refreshRate->vsyncPeriod)); } return offsets; } +PhaseOffsets::Offsets PhaseOffsets::getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const { + if (fps > 65.0f) { + return getHighFpsOffsets(vsyncPeriod); + } else { + return getDefaultOffsets(vsyncPeriod); + } +} + PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const { const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000); const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000); @@ -159,8 +164,15 @@ PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(float fps) const { [&fps](const std::pair& candidateFps) { return fpsEqualsWithMargin(fps, candidateFps.first); }); - LOG_ALWAYS_FATAL_IF(iter == mOffsets.end()); - return iter->second; + + if (iter != mOffsets.end()) { + return iter->second; + } + + // Unknown refresh rate. This might happen if we get a hotplug event for an external display. + // In this case just construct the offset. + ALOGW("Can't find offset for %.2f fps", fps); + return getPhaseOffsets(fps, static_cast(1e9f / fps)); } static void validateSysprops() { @@ -288,8 +300,7 @@ PhaseOffsets::Offsets PhaseDurations::getOffsetsForRefreshRate(float fps) const return iter->second; } - // Unknown refresh rate. This might happen if we get a hotplug event for the default display. - // This happens only during tests and not during regular device operation. + // Unknown refresh rate. This might happen if we get a hotplug event for an external display. // In this case just construct the offset. ALOGW("Can't find offset for %.2f fps", fps); return constructOffsets(static_cast(1e9f / fps)); diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h index b7d4eae5b6..208f06b185 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.h +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h @@ -69,8 +69,9 @@ public: private: std::unordered_map initializeOffsets( const scheduler::RefreshRateConfigs&) const; - Offsets getDefaultOffsets(nsecs_t vsyncDuration) const; - Offsets getHighFpsOffsets(nsecs_t vsyncDuration) const; + Offsets getDefaultOffsets(nsecs_t vsyncPeriod) const; + Offsets getHighFpsOffsets(nsecs_t vsyncPeriod) const; + Offsets getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const; const nsecs_t mThresholdForNextVsync; const std::unordered_map mOffsets; -- GitLab From c84e9978b1b5e8f220cd09304f8fb7ba3c4865db Mon Sep 17 00:00:00 2001 From: Dan Zimmerman Date: Mon, 10 Feb 2020 07:22:22 -0800 Subject: [PATCH 0935/1255] Revert "Revert "[dexopt] Allow secondary dex files to generate app images"" Reason for revert: Breaking up the original topic into individual CLs so that we can merge non-broken code sooner (and fix/merge the broken test on its own). Reverted Changes: Ic30045e59: Revert "[dexopt] Allow secondary dex files to gene... Test: adb shell pm bg-dexopt-job with app installed that uses secondary dexes, verify app image is generated for secondary image. Launch app and verify no class linker/class loader/image space warnings in logcat (cherry-picked from commit b79acc02221cc4573708ae29aac0cd3281d34520) Bug: 149098478 Merged-In: Id6e633fb95798041df75e0e3e8b926aa6038a9ac Change-Id: Id6e633fb95798041df75e0e3e8b926aa6038a9ac --- cmds/installd/dexopt.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index 70bbc33b42..1af6eddb2f 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -1273,11 +1273,6 @@ class Dex2oatFileWrapper { Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool generate_app_image, bool is_public, int uid, bool is_secondary_dex) { - // We don't create an image for secondary dex files. - if (is_secondary_dex) { - return Dex2oatFileWrapper(); - } - const std::string image_path = create_image_filename(out_oat_path); if (image_path.empty()) { // Happens when the out_oat_path has an unknown extension. -- GitLab From 6d414b56539c719694dd06ec6624ba280bf402c5 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 17 Mar 2020 11:18:05 -0700 Subject: [PATCH 0936/1255] [SurfaceFlinger] Adjust missed frame tracking Before, missed frame tracking may be inaccurate if a frame takes longer than one vsync and either an invalidate message is not immediately scheduled afterwards, or the frame takes almost as long as two vsyncs but manages to be on time to be presented for that second vsync. Those scenarios can cause visual jank, but they are not tracked by missed frames which affects testing. * Rename the previous missedFrames to pendingFrames * pendingFrames is used to check for backpressure propagation so there is no change to device behavior * Compute a new missedFrames count by relaxing the check for pendingFrames - if the expected present time of the previous frame was earlier than the actual present time then that frame was missed. We add half a vsync of slop to correct for scheduling drift. Bug: 143647283 Test: boots Test: systrace Change-Id: I0f76d06737f5182c512ca6f36b332b68192250c3 --- services/surfaceflinger/SurfaceFlinger.cpp | 57 +++++++++++++++++----- services/surfaceflinger/SurfaceFlinger.h | 16 +++++- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 29fe5d9e6e..532ccb98ee 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1026,7 +1026,7 @@ bool SurfaceFlinger::performSetActiveConfig() { ATRACE_CALL(); ALOGV("performSetActiveConfig"); if (mCheckPendingFence) { - if (previousFrameMissed()) { + if (previousFramePending()) { // fence has not signaled yet. wait for the next invalidate mEventQueue->invalidate(); return true; @@ -1773,13 +1773,17 @@ void SurfaceFlinger::updateVrFlinger() { setTransactionFlags(eDisplayTransactionNeeded); } -bool SurfaceFlinger::previousFrameMissed(int graceTimeMs) NO_THREAD_SAFETY_ANALYSIS { - ATRACE_CALL(); +sp SurfaceFlinger::previousFrameFence() NO_THREAD_SAFETY_ANALYSIS { // We are storing the last 2 present fences. If sf's phase offset is to be // woken up before the actual vsync but targeting the next vsync, we need to check // fence N-2 - const sp& fence = mVSyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0] - : mPreviousPresentFences[1]; + return mVSyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0] + : mPreviousPresentFences[1]; +} + +bool SurfaceFlinger::previousFramePending(int graceTimeMs) NO_THREAD_SAFETY_ANALYSIS { + ATRACE_CALL(); + const sp& fence = previousFrameFence(); if (fence == Fence::NO_FENCE) { return false; @@ -1792,6 +1796,16 @@ bool SurfaceFlinger::previousFrameMissed(int graceTimeMs) NO_THREAD_SAFETY_ANALY return (fence->getStatus() == Fence::Status::Unsignaled); } +nsecs_t SurfaceFlinger::previousFramePresentTime() NO_THREAD_SAFETY_ANALYSIS { + const sp& fence = previousFrameFence(); + + if (fence == Fence::NO_FENCE) { + return Fence::SIGNAL_TIME_INVALID; + } + + return fence->getSignalTime(); +} + void SurfaceFlinger::populateExpectedPresentTime() { DisplayStatInfo stats; mScheduler->getDisplayStatInfo(&stats); @@ -1809,6 +1823,7 @@ void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { // calculate the expected present time once and use the cached // value throughout this frame to make sure all layers are // seeing this same value. + const nsecs_t lastExpectedPresentTime = mExpectedPresentTime.load(); populateExpectedPresentTime(); // When Backpressure propagation is enabled we want to give a small grace period @@ -1819,12 +1834,32 @@ void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { (mPropagateBackpressureClientComposition || !mHadClientComposition)) ? 1 : 0; - const TracedOrdinal frameMissed = {"FrameMissed", - previousFrameMissed( - graceTimeForPresentFenceMs)}; - const TracedOrdinal hwcFrameMissed = {"HwcFrameMissed", + + // Pending frames may trigger backpressure propagation. + const TracedOrdinal framePending = {"PrevFramePending", + previousFramePending( + graceTimeForPresentFenceMs)}; + + // Frame missed counts for metrics tracking. + // A frame is missed if the prior frame is still pending. If no longer pending, + // then we still count the frame as missed if the predicted present time + // was further in the past than when the fence actually fired. + + // Add some slop to correct for drift. This should generally be + // smaller than a typical frame duration, but should not be so small + // that it reports reasonable drift as a missed frame. + DisplayStatInfo stats; + mScheduler->getDisplayStatInfo(&stats); + const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2; + const nsecs_t previousPresentTime = previousFramePresentTime(); + const TracedOrdinal frameMissed = + {"PrevFrameMissed", + framePending || + (previousPresentTime >= 0 && + (lastExpectedPresentTime < previousPresentTime - frameMissedSlop))}; + const TracedOrdinal hwcFrameMissed = {"PrevHwcFrameMissed", mHadDeviceComposition && frameMissed}; - const TracedOrdinal gpuFrameMissed = {"GpuFrameMissed", + const TracedOrdinal gpuFrameMissed = {"PrevGpuFrameMissed", mHadClientComposition && frameMissed}; if (frameMissed) { @@ -1844,7 +1879,7 @@ void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { mGpuFrameMissedCount++; } - if (frameMissed && mPropagateBackpressure) { + if (framePending && mPropagateBackpressure) { if ((hwcFrameMissed && !gpuFrameMissed) || mPropagateBackpressureClientComposition) { signalLayerUpdate(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index e6b91e6627..5f490d662c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -839,7 +839,21 @@ private: bool isDisplayConfigAllowed(HwcConfigIndexType configId) const REQUIRES(mStateLock); - bool previousFrameMissed(int graceTimeMs = 0); + // Gets the fence for the previous frame. + // Must be called on the main thread. + sp previousFrameFence(); + + // Whether the previous frame has not yet been presented to the display. + // If graceTimeMs is positive, this method waits for at most the provided + // grace period before reporting if the frame missed. + // Must be called on the main thread. + bool previousFramePending(int graceTimeMs = 0); + + // Returns the previous time that the frame was presented. If the frame has + // not been presented yet, then returns Fence::SIGNAL_TIME_PENDING. If there + // is no pending frame, then returns Fence::SIGNAL_TIME_INVALID. + // Must be called on the main thread. + nsecs_t previousFramePresentTime(); // Populates the expected present time for this frame. For negative offsets, performs a // correction using the predicted vsync for the next frame instead. -- GitLab From 1e10136954c181fa0511e70ee90bc808dc63f555 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 13 Feb 2020 13:24:45 -0800 Subject: [PATCH 0937/1255] libui: Fix clamping of input values in ui::Size A previous change to fix a compiler warning broke the clamped-conversion of floating point input values to the int32_t values used internally. As a result, calling setWidth() or steHeight() with any floating point value resulted in a value of INT32_MIN being set, The existing Size_test unit test would have caught this issue, but it would have had to have been manually run since it was not configured to run automatically. No one noticed it was broken for a while since it is relatively new and the existing callers were not setting a floating point value. This change: 1) Fixes clamping of floating point values to work again, as verified by the existing test. 2) Helps enforce that the header remains conversion-warning free by enabling a few conversion warnings (as errors) when building the test. 3) Adds a TEST_MAPPING file, which will run Size_test as part of the presubmit runs (effectively continuously), as well as including the test in the device-test suite in the Android.bp file. 4) Adds a PrintTo() function for more clearly printing out a ui::Size value when using the Google Test framework. Bug: 149495759 Test: atest Size_test Change-Id: I8f18f20e6b5a3ea54eb383486a1f7222a1a2a544 --- libs/ui/include/ui/Size.h | 30 +++++++++++++++++++----------- libs/ui/tests/Android.bp | 1 + libs/ui/tests/Size_test.cpp | 10 ++++++++++ libs/ui/tests/TEST_MAPPING | 7 +++++++ 4 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 libs/ui/tests/TEST_MAPPING diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h index d9b713df4c..c2cda17a6f 100644 --- a/libs/ui/include/ui/Size.h +++ b/libs/ui/include/ui/Size.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -113,13 +114,12 @@ struct Size { std::numeric_limits>::is_bounded && std::numeric_limits>::is_bounded, FromType&&>::type v) { - static constexpr auto toHighest = std::numeric_limits>::max(); - static constexpr auto toLowest = - std::numeric_limits>::lowest(); - static constexpr auto fromHighest = - std::numeric_limits>::max(); - static constexpr auto fromLowest = - std::numeric_limits>::lowest(); + using BareToType = remove_cv_reference_t; + using BareFromType = remove_cv_reference_t; + static constexpr auto toHighest = std::numeric_limits::max(); + static constexpr auto toLowest = std::numeric_limits::lowest(); + static constexpr auto fromHighest = std::numeric_limits::max(); + static constexpr auto fromLowest = std::numeric_limits::lowest(); // A clamp is needed if the range of FromType is not a subset of the range of ToType static constexpr bool isClampNeeded = (toLowest > fromLowest) || (toHighest < fromHighest); @@ -129,10 +129,13 @@ struct Size { return static_cast(v); } - // Otherwise we leverage implicit conversion to safely compare values of - // different types, to ensure we return a value clamped to the range of - // ToType. - return v < toLowest ? toLowest : (static_cast(v) > toHighest ? toHighest : static_cast(v)); + // Otherwise we need to carefully compare the limits of ToType (casted + // for the comparisons to be warning free to FromType) while still + // ensuring we return a value clamped to the range of ToType. + return v < static_cast(toLowest) + ? toLowest + : (v > static_cast(toHighest) ? toHighest + : static_cast(v)); } }; @@ -154,5 +157,10 @@ inline bool operator<(const Size& lhs, const Size& rhs) { return lhs.height < rhs.height; } +// Defining PrintTo helps with Google Tests. +static inline void PrintTo(const Size& size, ::std::ostream* os) { + *os << "Size(" << size.width << ", " << size.height << ")"; +} + } // namespace ui } // namespace android diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index ff55bc2303..605c5a9ba0 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -111,6 +111,7 @@ cc_test { cc_test { name: "Size_test", + test_suites: ["device-tests"], shared_libs: ["libui"], srcs: ["Size_test.cpp"], cflags: ["-Wall", "-Werror"], diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp index 69e1ac8b27..40dc702a8b 100644 --- a/libs/ui/tests/Size_test.cpp +++ b/libs/ui/tests/Size_test.cpp @@ -19,8 +19,18 @@ #include #include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic error "-Wimplicit-int-float-conversion" +#pragma clang diagnostic error "-Wconversion" +#endif // __clang__ + #include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + #include namespace android { diff --git a/libs/ui/tests/TEST_MAPPING b/libs/ui/tests/TEST_MAPPING new file mode 100644 index 0000000000..7fcd7de319 --- /dev/null +++ b/libs/ui/tests/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "Size_test" + } + ] +} -- GitLab From c60da19f2a012a15971dcd8f4fa3b7c22a90a670 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 19 Mar 2020 11:55:01 -0700 Subject: [PATCH 0938/1255] Disable deep press when long press timeout is long If the user sets the long press timeout to anything > default value, then we should disable deep press. That means, if the user is triggering long press too easily, it is likely that the user will trigger deep press too easily as well. To prevent unwanted long press invocations, we disable deep press in such situations. Bug: 148311342 Test: Add logging to both cases where deep press is enabled and disabled. Go to accessibility -> touch & hold delay, and change the value. Ensure that the logging matches expectation (short -> enable, medium/long -> disable). The state should persist across the reboot. Change-Id: Ic631c684609c4436e9eaa6f9389939c5a6e4e1cd Merged-In: Ic631c684609c4436e9eaa6f9389939c5a6e4e1cd (cherry picked from commit c9ac19eb3d3c3f185fea95906541249dd4c3baf8) --- services/inputflinger/Android.bp | 1 - services/inputflinger/InputClassifier.cpp | 55 +++++++------------ services/inputflinger/InputClassifier.h | 4 ++ services/inputflinger/InputManager.cpp | 4 ++ services/inputflinger/InputManager.h | 2 + .../tests/InputClassifier_test.cpp | 22 ++++++++ 6 files changed, 52 insertions(+), 36 deletions(-) diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 4ec4e25010..f67c9d006b 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -52,7 +52,6 @@ cc_defaults { "libstatslog", "libutils", "libui", - "server_configurable_flags", ], } diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 8ba1f7f8c1..77a0716269 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -27,7 +27,6 @@ #if defined(__linux__) #include #endif -#include #include #include @@ -46,11 +45,6 @@ using namespace android::hardware::input; namespace android { -// Category (=namespace) name for the input settings that are applied at boot time -static const char* INPUT_NATIVE_BOOT = "input_native_boot"; -// Feature flag name for the deep press feature -static const char* DEEP_PRESS_ENABLED = "deep_press_enabled"; - //Max number of elements to store in mEvents. static constexpr size_t MAX_EVENTS = 5; @@ -77,20 +71,6 @@ static bool isTouchEvent(const NotifyMotionArgs& args) { return args.source == AINPUT_SOURCE_TOUCHPAD || args.source == AINPUT_SOURCE_TOUCHSCREEN; } -// Check if the "deep touch" feature is on. -static bool deepPressEnabled() { - std::string flag_value = server_configurable_flags::GetServerConfigurableFlag( - INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "true"); - std::transform(flag_value.begin(), flag_value.end(), flag_value.begin(), ::tolower); - if (flag_value == "1" || flag_value == "true") { - ALOGI("Deep press feature enabled."); - return true; - } - ALOGI("Deep press feature is not enabled."); - return false; -} - - // --- ClassifierEvent --- ClassifierEvent::ClassifierEvent(std::unique_ptr args) : @@ -157,12 +137,6 @@ MotionClassifier::MotionClassifier( std::unique_ptr MotionClassifier::create( sp deathRecipient) { - if (!deepPressEnabled()) { - // If feature is not enabled, MotionClassifier should stay null to avoid unnecessary work. - // When MotionClassifier is null, InputClassifier will forward all events - // to the next InputListener, unmodified. - return nullptr; - } sp service = classifier::V1_0::IInputClassifier::getService(); if (!service) { @@ -372,14 +346,25 @@ void InputClassifier::HalDeathRecipient::serviceDied( // --- InputClassifier --- InputClassifier::InputClassifier(const sp& listener) - : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) { - mInitializeMotionClassifierThread = std::thread( - [this] { setMotionClassifier(MotionClassifier::create(mHalDeathRecipient)); }); + : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {} + +void InputClassifier::setMotionClassifierEnabled(bool enabled) { + if (enabled) { + ALOGI("Enabling motion classifier"); + if (mInitializeMotionClassifierThread.joinable()) { + mInitializeMotionClassifierThread.join(); + } + mInitializeMotionClassifierThread = std::thread( + [this] { setMotionClassifier(MotionClassifier::create(mHalDeathRecipient)); }); #if defined(__linux__) - // Set the thread name for debugging - pthread_setname_np(mInitializeMotionClassifierThread.native_handle(), - "Create MotionClassifier"); + // Set the thread name for debugging + pthread_setname_np(mInitializeMotionClassifierThread.native_handle(), + "Create MotionClassifier"); #endif + } else { + ALOGI("Disabling motion classifier"); + setMotionClassifier(nullptr); + } } void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { @@ -429,8 +414,6 @@ void InputClassifier::setMotionClassifier( void InputClassifier::dump(std::string& dump) { std::scoped_lock lock(mLock); dump += "Input Classifier State:\n"; - dump += StringPrintf(INDENT1 "Deep press: %s\n", deepPressEnabled() ? "enabled" : "disabled"); - dump += INDENT1 "Motion Classifier:\n"; if (mMotionClassifier) { mMotionClassifier->dump(dump); @@ -441,7 +424,9 @@ void InputClassifier::dump(std::string& dump) { } InputClassifier::~InputClassifier() { - mInitializeMotionClassifierThread.join(); + if (mInitializeMotionClassifierThread.joinable()) { + mInitializeMotionClassifierThread.join(); + } } } // namespace android diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h index 8f586956e5..03510a623c 100644 --- a/services/inputflinger/InputClassifier.h +++ b/services/inputflinger/InputClassifier.h @@ -90,6 +90,7 @@ public: */ class InputClassifierInterface : public virtual RefBase, public InputListenerInterface { public: + virtual void setMotionClassifierEnabled(bool enabled) = 0; /** * Dump the state of the input classifier. * This method may be called on any thread (usually by the input manager). @@ -234,6 +235,9 @@ public: ~InputClassifier(); + // Called from InputManager + virtual void setMotionClassifierEnabled(bool enabled) override; + private: // Protect access to mMotionClassifier, since it may become null via a hidl callback std::mutex mLock; diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index c7c61cf1ef..fc771a2c58 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -132,4 +132,8 @@ void InputManager::unregisterInputChannel(const sp& channel) { mDispatcher->unregisterInputChannel(channel); } +void InputManager::setMotionClassifierEnabled(bool enabled) { + mClassifier->setMotionClassifierEnabled(enabled); +} + } // namespace android diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index 586097f6a3..0158441fd1 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -100,6 +100,8 @@ public: virtual void registerInputChannel(const sp& channel); virtual void unregisterInputChannel(const sp& channel); + void setMotionClassifierEnabled(bool enabled); + private: sp mReader; diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp index b4e755a595..ab74a0498d 100644 --- a/services/inputflinger/tests/InputClassifier_test.cpp +++ b/services/inputflinger/tests/InputClassifier_test.cpp @@ -135,6 +135,28 @@ TEST_F(InputClassifierTest, SendToNextStage_NotifyDeviceResetArgs) { ASSERT_EQ(args, outArgs); } +TEST_F(InputClassifierTest, SetMotionClassifier_Enabled) { + mClassifier->setMotionClassifierEnabled(true); +} + +TEST_F(InputClassifierTest, SetMotionClassifier_Disabled) { + mClassifier->setMotionClassifierEnabled(false); +} + +/** + * Try to break it by calling setMotionClassifierEnabled multiple times. + */ +TEST_F(InputClassifierTest, SetMotionClassifier_Multiple) { + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(false); + mClassifier->setMotionClassifierEnabled(false); + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(true); +} + /** * A minimal implementation of IInputClassifier. */ -- GitLab From d011f5077cb21b421927d89af6f055fa6887c805 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Sun, 22 Mar 2020 18:34:51 -0700 Subject: [PATCH 0939/1255] Also check equality of background blurs Test: manually fling the shade Fixes: 152161119 Change-Id: I5d4439b2f30ad2efa1e2bd8d732ec0ae69b0a443 --- .../CompositionEngine/src/ClientCompositionRequestCache.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp index acaaf4e1b9..2d9f01b9fd 100644 --- a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp +++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp @@ -35,7 +35,8 @@ inline bool equalIgnoringSource(const renderengine::LayerSettings& lhs, return lhs.geometry == rhs.geometry && lhs.alpha == rhs.alpha && lhs.sourceDataspace == rhs.sourceDataspace && lhs.colorTransform == rhs.colorTransform && - lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow; + lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow && + lhs.backgroundBlurRadius == rhs.backgroundBlurRadius; } inline bool equalIgnoringBuffer(const renderengine::Buffer& lhs, const renderengine::Buffer& rhs) { -- GitLab From 307664c50a35d92585b707af6b1cc207cf7cfb41 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Fri, 21 Feb 2020 21:14:12 +0900 Subject: [PATCH 0940/1255] use vector for byte[] in AIDL In native world, byte stream is typically represented in uint8_t[] or vector. C++ backend already generates that way. This change involves NDK backend. Now NDK backend also uses vector just like C++ backend. By the way, to keep the published NDK APIs stable, the signatures of helper functions are changed to uint8_t and they still use existing APIs. Bug: 144957764 Test: atest CtsNdkBinderTestCases Merged-In: I03572bfcb89ca5fb06f75b9d44fbe12426758237 Change-Id: I03572bfcb89ca5fb06f75b9d44fbe12426758237 (cherry picked from commit 85985c387b024e66a835973c3bd12a6241a514ea) Exempt-From-Owner-Approval: cp from master to avoid merge-conflict --- .../include_ndk/android/binder_parcel_utils.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h index df5df13c19..09949ea259 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h @@ -831,34 +831,34 @@ inline binder_status_t AParcel_readVector(const AParcel* parcel, } /** - * Writes a vector of int8_t to the next location in a non-null parcel. + * Writes a vector of uint8_t to the next location in a non-null parcel. */ -inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector& vec) { - return AParcel_writeByteArray(parcel, vec.data(), vec.size()); +inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector& vec) { + return AParcel_writeByteArray(parcel, reinterpret_cast(vec.data()), vec.size()); } /** - * Writes an optional vector of int8_t to the next location in a non-null parcel. + * Writes an optional vector of uint8_t to the next location in a non-null parcel. */ inline binder_status_t AParcel_writeVector(AParcel* parcel, - const std::optional>& vec) { + const std::optional>& vec) { if (!vec) return AParcel_writeByteArray(parcel, nullptr, -1); return AParcel_writeVector(parcel, *vec); } /** - * Reads a vector of int8_t from the next location in a non-null parcel. + * Reads a vector of uint8_t from the next location in a non-null parcel. */ -inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector* vec) { +inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector* vec) { void* vectorData = static_cast(vec); return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator); } /** - * Reads an optional vector of int8_t from the next location in a non-null parcel. + * Reads an optional vector of uint8_t from the next location in a non-null parcel. */ inline binder_status_t AParcel_readVector(const AParcel* parcel, - std::optional>* vec) { + std::optional>* vec) { void* vectorData = static_cast(vec); return AParcel_readByteArray(parcel, vectorData, AParcel_nullableStdVectorAllocator); } -- GitLab From 60120a06acdefa44b911a6558b2c140cf3713f38 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 23 Mar 2020 11:23:26 -0700 Subject: [PATCH 0941/1255] SurfaceFlinger: add a test for unknown offset Add a unit test that tries to get phase offset for a refresh rate that is not part of the boot list. The scenarios simulates an external display hotplug with different refresh rate than the internal one. Bug: 151859083 Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Change-Id: I3adee92b91d0c1a337c9a6ffd7431e7b854bbe0d --- .../surfaceflinger/Scheduler/PhaseOffsets.cpp | 57 ++++++++------ .../surfaceflinger/Scheduler/PhaseOffsets.h | 7 +- .../tests/unittests/PhaseOffsetsTest.cpp | 78 +++++++++++++++---- 3 files changed, 100 insertions(+), 42 deletions(-) diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 7941cda6ef..43883fb387 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -36,6 +36,19 @@ bool fpsEqualsWithMargin(float fpsA, float fpsB) { return std::abs(fpsA - fpsB) <= MARGIN; } +std::vector getRefreshRatesFromConfigs( + const android::scheduler::RefreshRateConfigs& refreshRateConfigs) { + const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates(); + std::vector refreshRates; + refreshRates.reserve(allRefreshRates.size()); + + for (const auto& [ignored, refreshRate] : allRefreshRates) { + refreshRates.emplace_back(refreshRate->fps); + } + + return refreshRates; +} + } // namespace namespace android::scheduler { @@ -45,14 +58,21 @@ PhaseConfiguration::~PhaseConfiguration() = default; namespace impl { PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs) - : // Below defines the threshold when an offset is considered to be negative, i.e. targeting - // for the N+2 vsync instead of N+1. This means that: - // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync. - // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync. - mThresholdForNextVsync(getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns") - .value_or(std::numeric_limits::max())), - mOffsets(initializeOffsets(refreshRateConfigs)), - mRefreshRateFps(refreshRateConfigs.getCurrentRefreshRate().fps) {} + : PhaseOffsets(getRefreshRatesFromConfigs(refreshRateConfigs), + refreshRateConfigs.getCurrentRefreshRate().fps, + // Below defines the threshold when an offset is considered to be negative, + // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset + // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For + // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW + // vsync. + getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns") + .value_or(std::numeric_limits::max())) {} + +PhaseOffsets::PhaseOffsets(const std::vector& refreshRates, float currentFps, + nsecs_t thresholdForNextVsync) + : mThresholdForNextVsync(thresholdForNextVsync), + mOffsets(initializeOffsets(refreshRates)), + mRefreshRateFps(currentFps) {} void PhaseOffsets::dump(std::string& result) const { const auto [early, earlyGl, late] = getCurrentOffsets(); @@ -67,12 +87,12 @@ void PhaseOffsets::dump(std::string& result) const { } std::unordered_map PhaseOffsets::initializeOffsets( - const scheduler::RefreshRateConfigs& refreshRateConfigs) const { + const std::vector& refreshRates) const { std::unordered_map offsets; - for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) { - const float fps = refreshRate->fps; - offsets.emplace(fps, getPhaseOffsets(fps, refreshRate->vsyncPeriod)); + for (const auto& refreshRate : refreshRates) { + offsets.emplace(refreshRate, + getPhaseOffsets(refreshRate, static_cast(1e9f / refreshRate))); } return offsets; } @@ -243,19 +263,6 @@ PhaseDurations::Offsets PhaseDurations::constructOffsets(nsecs_t vsyncDuration) }; } -static std::vector getRefreshRatesFromConfigs( - const android::scheduler::RefreshRateConfigs& refreshRateConfigs) { - const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates(); - std::vector refreshRates; - refreshRates.reserve(allRefreshRates.size()); - - for (const auto& [ignored, refreshRate] : allRefreshRates) { - refreshRates.emplace_back(refreshRate->fps); - } - - return refreshRates; -} - std::unordered_map PhaseDurations::initializeOffsets( const std::vector& refreshRates) const { std::unordered_map offsets; diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h index 208f06b185..fa8011d74b 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.h +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h @@ -66,9 +66,12 @@ public: // Returns current offsets in human friendly format. void dump(std::string& result) const override; -private: +protected: + // Used for unit tests + PhaseOffsets(const std::vector& refreshRates, float currentFps, + nsecs_t thresholdForNextVsync); std::unordered_map initializeOffsets( - const scheduler::RefreshRateConfigs&) const; + const std::vector& refreshRates) const; Offsets getDefaultOffsets(nsecs_t vsyncPeriod) const; Offsets getHighFpsOffsets(nsecs_t vsyncPeriod) const; Offsets getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const; diff --git a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp index 910e73baf2..8d49201c61 100644 --- a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp +++ b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp @@ -42,25 +42,25 @@ public: appEarlyGlDuration) {} }; -class PhaseOffsetsTest : public testing::Test { +class PhaseDurationTest : public testing::Test { protected: - PhaseOffsetsTest() - : mPhaseOffsets(60.0f, 10'500'000, 20'500'000, 16'000'000, 33'500'000, 13'500'000, - 38'000'000) {} + PhaseDurationTest() + : mPhaseDurations(60.0f, 10'500'000, 20'500'000, 16'000'000, 33'500'000, 13'500'000, + 38'000'000) {} - ~PhaseOffsetsTest() = default; + ~PhaseDurationTest() = default; - TestablePhaseOffsetsAsDurations mPhaseOffsets; + TestablePhaseOffsetsAsDurations mPhaseDurations; }; namespace { /* ------------------------------------------------------------------------ * Test cases */ -TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_60Hz) { - mPhaseOffsets.setRefreshRateFps(60.0f); - auto currentOffsets = mPhaseOffsets.getCurrentOffsets(); - auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(60.0f); +TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_60Hz) { + mPhaseDurations.setRefreshRateFps(60.0f); + auto currentOffsets = mPhaseDurations.getCurrentOffsets(); + auto offsets = mPhaseDurations.getOffsetsForRefreshRate(60.0f); EXPECT_EQ(currentOffsets, offsets); EXPECT_EQ(offsets.late.sf, 6'166'667); @@ -76,10 +76,10 @@ TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_60Hz) { EXPECT_EQ(offsets.earlyGl.app, 15'166'668); } -TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_90Hz) { - mPhaseOffsets.setRefreshRateFps(90.0f); - auto currentOffsets = mPhaseOffsets.getCurrentOffsets(); - auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(90.0f); +TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_90Hz) { + mPhaseDurations.setRefreshRateFps(90.0f); + auto currentOffsets = mPhaseDurations.getCurrentOffsets(); + auto offsets = mPhaseDurations.getOffsetsForRefreshRate(90.0f); EXPECT_EQ(currentOffsets, offsets); EXPECT_EQ(offsets.late.sf, 611'111); @@ -95,7 +95,7 @@ TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_90Hz) { EXPECT_EQ(offsets.earlyGl.app, 4'055'555); } -TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_DefaultOffsets) { +TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_DefaultOffsets) { TestablePhaseOffsetsAsDurations phaseOffsetsWithDefaultValues(60.0f, -1, -1, -1, -1, -1, -1); auto validateOffsets = [](auto& offsets) { @@ -125,6 +125,54 @@ TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_DefaultOffsets) { validateOffsets(offsets); } +TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_unknownRefreshRate) { + auto offsets = mPhaseDurations.getOffsetsForRefreshRate(14.7f); + + EXPECT_EQ(offsets.late.sf, 57'527'208); + + EXPECT_EQ(offsets.late.app, 37'027'208); + + EXPECT_EQ(offsets.early.sf, 52'027'208); + + EXPECT_EQ(offsets.early.app, 18'527'208); + + EXPECT_EQ(offsets.earlyGl.sf, 54'527'208); + + EXPECT_EQ(offsets.earlyGl.app, 16'527'208); +} + +} // namespace + +class TestablePhaseOffsets : public impl::PhaseOffsets { +public: + TestablePhaseOffsets() : impl::PhaseOffsets({60.0f, 90.0f}, 60.0f, 10'000'000) {} +}; + +class PhaseOffsetsTest : public testing::Test { +protected: + PhaseOffsetsTest() = default; + ~PhaseOffsetsTest() = default; + + TestablePhaseOffsets mPhaseOffsets; +}; + +namespace { +TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_unknownRefreshRate) { + auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(14.7f); + + EXPECT_EQ(offsets.late.sf, 1'000'000); + + EXPECT_EQ(offsets.late.app, 1'000'000); + + EXPECT_EQ(offsets.early.sf, 1'000'000); + + EXPECT_EQ(offsets.early.app, 1'000'000); + + EXPECT_EQ(offsets.earlyGl.sf, 1'000'000); + + EXPECT_EQ(offsets.earlyGl.app, 1'000'000); +} + } // namespace } // namespace scheduler } // namespace android -- GitLab From e71f2409a8d92bf491535e4350813d33e5636d67 Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Mon, 23 Mar 2020 13:04:32 -0700 Subject: [PATCH 0942/1255] Camera NDK: Add android.control.zoomRatio control Test: Build and read docs Bug: 144780745 Change-Id: I0601673d32fad5704aea2149cd217b94e518acdf --- .../zoom-ratio-0.5-crop-11.png | Bin 0 -> 28504 bytes .../zoom-ratio-2-crop-169.png | Bin 0 -> 25510 bytes .../zoom-ratio-2-crop-43.png | Bin 0 -> 25561 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-0.5-crop-11.png create mode 100644 docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.png create mode 100644 docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-43.png diff --git a/docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-0.5-crop-11.png b/docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-0.5-crop-11.png new file mode 100644 index 0000000000000000000000000000000000000000..1acc59d167fc38299abf11bb02d2d6227a71a463 GIT binary patch literal 28504 zcmeAS@N?(olHy`uVBq!ia0y~yV7$Y?z<8E}je&t-i{`1*3=9m6#X;^)4C~IxykuZt zn2;Lbnda-upvAzzz`?-A$i~17Qo_K*z`!U3Wiv7`FiJ77g2fpa!WgCD>^MdZs2U~) zhW1Pb7O0vu1`y-_|A!2$p`naWnt^!%BUCjb1H%F)m}4ZxU|`@Z z@Q5sCVBk9f!i-b3`J@>bn7A`TB1$5BeXNr6bM+Ea@{>~aDsl@zx)^LKtSWK~a#KqZ z6)JLb@`|l0Y?Z(&tn!MjK*IV;3ScEA*|tg%z5xo(`9-M;rg|oN21<5Z3JMA~MJZ`k zK`w4k?L{eRwn`Z#B?VUc`sL;2dgaD?`9315O8$_PoJU;*RUhxMO7FFw; zM31nokl4t0?1+%5>tu=Op1{fHkGS-z9TQo6QKILV%i^XaM+ZkuE{(n4`L0*5|80Ao zXS4b4?SIR@m8Jh*FK7Mv+Vj7AjX%%de#VEzvOuhiZ_h(kCItpCdZ60KQ8r2C(&>^8 zKCl1-lfnaLMvis-7bdWfnd!w-ac1@QZ=h6QbGSKs1v;On#@L9au91#}5aFrq|3SDvV&w42=1l4h4Hv z+kU_tM9}g@wI0nXiGB+fEoz#k7n|j*Xm3CNoc;frqwhaFJiMjqYgSfn?$XWYth$f& z$z}_OA1Zry$MfaOmnOBpN=}_Sw~h07-*=WLU!ULJmb>`Jj|wTfnjOAu>nhAmOf+&M zLqc4b+4+`88m9$>giJBryL!ttj~g2lFWk7XLgxSFWxm0;oVo98O67igZ*TPN(7N;1 z?`^a+Gy=B8&NY8`>!jLcgL@NSpZfLnwWg|SYfJt5xV>vk?ilj0)PE^hd$y6+pHs%F zq~l)2V_vJGCmmncFInQ^xv%_v+^>uMbuR4ua!XE~^7{4Czus$g*xF5Le_yR$e<|4C zcIlh-k(=Az?Rd<$YTdeRZOMnNnMzAbzud}Rf6>?cuFLnkIfj z9DFQu1b_T^+^_rnUiJFJ57g&X9QyR*aewq-F};|KouAKHPp#d@5V>y8CogX9wWf3Q ze@rvKUvqg^Kks`E8H<7gpW5yJ96Yo)`ZRyt2WIZ><)+N#d-nf$#C`hd^!U8Y?Cju6 zQ>IOesyK46=+za??%i9iIc-Q(RXG0Z_4@sJH}_O-e)_0ee_KdsXyoCP$ItEm?|i!V z`@PK{FPFv4HD7nj)4M;u`{}Lh^;>l!HXP`Bv~+r0(2VYO>o&K~*WWc?IDFOP!S!UO zr%#_wnLOFqsASpKoUKPL{l3bd*(YV%m9oNZ&YjXzvVS`SmAAZ5c{qvfoHOv7#tHbN64Ss-^)ws z-O|k6KfWq6mhVYD5r01{Xv>!AKThl4I@RBMFtYQ)zmNU(AxFZlna9+Ay;^cTwp_FI z#`e~Kdp7bgE=8eF6uc zJv!1^a?bL3Kw_fe-*4OZFHJo??IN%F9fzXjE6bPf-|b_wYVn!H8NZ`sECW?|&i!Xe zxpzu5|MxZ_ZWX&*r~ckovXr z-_P^)VR>r$yWbcsHF_s;t3CU9?;P%LiIWzV&8zU{az1rW$hk(!vS`UBrU0>9C%C-l zOoGo2nE@BjV+!ZIV zPFh(uFM|6+0dv!9MGcqNDhIfQJ>--x&arV@Wa~9)_Uvrq^}F-$+nqXbBH)m!PgSgu z%34d#Xjf7&d2^SB9a`Fp=k^L0%vQMZbcP1%yq z{rj`q{xGNeerA$M?f2^c*Zz7k*?&stBO{$Pmeu>d@w`3U`-uPG)hL$za>5gy7d#ad ziZoFbpQP$N?SiX#?2;w(tx8uJl`C}%xI|3XkN10|?$;77=6QC$ef-Shlb*Xh-RYtm z)7eu0$L)Y@ekEIoT>AvGNr9YksoA;8<(YreQf8#6yp~S!3q0b`rnx=;{<=T06%Sjv z7{j0Ut}f#eu8|83o+tS{^wFusk>AWezLQ|jPt>r>T3wgXIDfj#}vN`M{KW zXGdV=v)n^1oL^2T_XlKUttxu>@9+Ei^)}Vo5A|+yDFS`=&MW94Cy=ZcaP9=;r41=;Gqz)gK=n{qpDYdF{_3n;PCeY?lvv_FR>@ zJacVp!r``tHQ75p9+RFbJ!8ujlWYllJ(vIgzVDx!ekC=q|Hwr9!lJ{V66~tqHKs!~ z&S4#=Pt1-f|KhjK{*w?-I8X1h^TqqRt~nKa)ospQ&vC+0%lU}W^Yr&BKGU99&z`?_ zAfA<>gT=q z-$%TYkUA>gBz^C=Y!;;c6Hs89_2AaGz04sNUC=77u|S#OAn$fD_gY7AeOlGxaAE%s zrg-g_6CX3RHi2u^A2S^Sz88GlDrCRiY!frMYJ6eH1}F<`Y3g1-wdK}AmTHJwV+1*(4j#Sk z6=N!W2x6L3uR}on9)@^r&aHAoL-@kIr7~BVR!jD-pPHfa0pb*aEEXrP0%u;m zH>_X}F);QvsO@mHZeK0g6%V$NQNVzikz<`?lwc_XSP4fJlfaz?`AQNTV9zA5F$u&N zZ&7*$X{-o*VNuxOc;Cf90MsmTIKacAup=$Q^$H`HtMG!;g?(?UoJ2&lM@f!uVDMJ< ziOm+L4C}Oh1@B{BRq&&vL_nJFvI7H)kH5lYCzHL+EA0Qzx_ESX;oWnpUN4hl-pa(? z(tXpTeQCet^*KsWpLqh^r7y1RQN1E~@lhaSWa(thg{tel?;N`k95Qdu!tVXb{GR$h zZ|vsFT70NyX-a3tcK%nJyMi+?Bz&ZQTn69!Tuya73ljv<}*aZPaEs5x@dX^%edH zLYk^qy=wT*GJy$fI0Fll!-0?{X@)orm_UsZ!@;kd(n8>n;%I0nXHnR3@1s)=G~IpZ zWMH|jp5ws+PG<~E_XHarR2}Eu2ubx02h^DaV&-p96a-t@Fq6aL*OgWKU$YacNiE2I5-%CzZSfnrOnL5+X`x{gPQBxK_*-Kt^2m^AH0pusF5y#h`ce;_YAEYrytF!k#nFp<|%{RNzA+ z1Iu;x3=dck-xF$hQ02|@5thW*nFM0w7btRqlNbX>g*QXfYhA-5?BK{WkZttn{y1N( z;lZqT8ys69j@hGnVfiPc{K*xv@=dQzjZ`4X!a%x_!zhlgSN~wn+NNL7(8TPdHLPSQ zPx>!;@0vW!1t71f?kK#-$=KKi4owCYP;YISP)xpdKde8dz;Y_+nj{|+QkoNZ!!j$$ zi*P#ZpOVYZVFFKL_k;|lJ`lSqLs>dJ@PnV>S3-z|+RaVMGTFUWpiZg74*>^$^O{>y zrjUx}g(H)|9l4hNMUbFwYIZ1ld$UcN2{kQzT)P+D4;5RL(ee^|N-rm>AFd`l?!C-* zQ8AxWVP8B)%GJA`A1Cg$J*B6QSm`M>lWr|~W7 za($croKDGAB;>ldM7Ef+n{CL%hG+oi_ zYu@*?tlgjj%BQErcqVyu-#EA9$+dUU#;blu1~k5}l*zg4)2#0Q#g@}Nvk&~ay|e0k5LS-+*TX1}|4??TZ8OO6(n#!Zj9CTzGocjAh6Yo|uu^}0S> zIgJ`;vzexPM(^=^oXf;A`i}w={D)>LIQ^7<^4OGTEJm8SHblA4!g}~mA z$D~W1oDh5+@9EhYw0dv#_e=eCUzDvXJ}88SgJgDCwcU=mfhvKs&M77$k`6B89fb(ws$sdGLkY%;jsO3 z!8x`-H)h9#WqxzL`0f8}5HhRykWlscta;|GEtyv?U2@_U(+RlbJJZOObN};s)fp!z zsh0fxdcFK4x7#C9waU466q>Q=5RnlJ@AhI6q5E%PTi-cto8K z+ZD*{!V&phht?q0cX-#oV-i9}(&OjzUYfCiJ>{%e76%+|E;uKQax z3*2|Sbi4LZr@Dr=wzs6)w4X6&Rn^tCZKDNmty-nk)!iNZDD$DGr)SB71B|)i`xO#2 z8t<`cwmp+yaVD_eVdA$nGCwb{CZ?S+j<6NcUR>AoP*wWU;klN@YIn=;*Qy*o{`vX& z<$Zm8QQLB621(w$w!4F)^v&s{jRDow)|tPf=A1a;G0DI}fPC~H}?#7JFQTH2eHm9^yQ)bLBErfQ2OeEj&)t3Pb9x@~kJ zCnx8r`Dihlw>#E*tJf3lHPvxmQ@8?(+XFPJTuMxNt#bgGl2^vuzH7F;;V}ut&-jv`;)dUG?P%;G3%((x^r_{c5?aq`j$=; z`KOQ|(fCQIc#k3XSA#bKA2lD}I;5ghtW*49(;sub*@4!#TsN;NzZk zxsQ|h!EvWh!7;Z!RK4>35x%dx+}v)~#VCioZmw#{I(;zDSlHl;}x%(rf{U} z(d9FS^>Tu#x6>4_@q`rz@@sSD{FvF$x<21sc-q80Gd)WD`f*+9`I=A|4Cy=s4eG3+Bwz zFlWhuG&^2cGCe&RFCAyWa=qZl!$1e`y_VCMw``yBc#4DVp~riib^p49TI}^REl-}5 z2^UwN+FbsC~N>qqR;bpQDYIyLAgYP6Py-G7J6S|Wux_i$` z>qkuv;!Lu#&niB$zPh+Hv--+mmG;nnBNOL`%Y^O(hq9l!pti!9U&x|#%L;by@9`H` zwEvIzrM&!9^UHrH*eY8rK#8McJL?&KCML1sJsDjA{R$Q{O4K5B1b5lyv}rSP8S3win6b2Ua1v>&II6%!NhaEx<58AR%FTMv+ z9L5w`I(hAFw_JyUUM1rP6ET!jn;aQJ~jp>C#f^JJqnT#`%^1D{nmGQJXw zX^(MPV!2GKsXOaMWU|)5x3ld`zC%j4^A&V0Q3VeD(x`3%At8mE?q z{uU2*Z~wh;^NJUIQWkp6ix%a)|9)%M;uRkPY)!A2?%EpH_Tm?h&yp!;DrWEa#P^WP zF8@@QR_-6!_YoSZ+Os~fEsbiHUcD&u>ah#!-9rnl-60s)*;M8jt=xw_A`^vm76#XUE1 zl4hTF$f9bNGlgOE(gLo(Icbpey+Lv7PEM0+<}(*HP2(%}k(#yCc2;(>Z(+GeFpqzb14GTlkGD>Wa1(ocgwXksMMS*e<7X7ibk>u#)= zQTBUP>yx@T$M+Mq+`gBwc}sik-VO3K;O@blH0fN#aFfG3stGCGlngoh&r;d+o)-NgXKECgXeF45xWL0)aPj4dUfTYRPdF!HGJN&ApLD; zV_GJE_feU*4?Slq_7#It_o7*c&t-SPy4o)sL1J=GI-os1hXbmN9P7MoI9R})X$Hps z0u2v-wJR4vieU!E=`0F6^gb#;#t|7<{x~xRg`)4-_a`~lmmRaPrmFEhwRL-{w?ASDj0{}byZ^B)_tF&C;Cl-~vI~+!P1fF$ z`1N&#R^IZzE7~uuJ6I62bxUY;zhO>`J}6)PFiSpveb2&WQ`2IMR^M*>a{6tV*c5g7 zw2y@w9w+=vn^ji$;`-wQ*S_zR+q|21^YYt=b-rq>GW_@W+1G^atzHpzq>c7ANJP?FNMh#*FK$cc4$w zzP-Eq`mzt<@wHRuRlU+YntyhdX~}Wf@_^EGFC-TIJR!xy3;57tbp`EPf$hJJXv=Q6Qh6u zE6DrnvSLF+T?-2fr%b*2Gjqd|B`T}dgxvq7y#LbUtGk~(Nm0EM8&xZn!!F-=#_?H2 zcut5<^@oFB4=&o%bkA-H*FKfBmF^!Vwz}Fn9$4R`UA#rGOuw+Vr$;3+L3Q2Y#jm%! zsqSmp?R{IgAYj>Z7Nx~^_FuaA`A(I=GS8}4-`1af%y=31bLBZX zF>T$p?bd;biqDQ5aXIQAW^y`a?Y)z$QazvRt+nIb2B|w74$Noisaw1F#;fpyXV0Du zty-0uni|IU``g>ic48_IRaI558AN`pd38k-OXA#fAjp++94?^snWgV+4=eYO3OaYdH3$_?#x$L zR(kDxKDT_{Cy9%oj^?~~hg!Kky%+zr^3Kk;_~v+kgX!eULbnv@4>pS*pD`5AomO>Z z>5aZWtbZCD8XX-Eybe9}Zp}2&GyS&TB+kw@_n*0Wu5mh_?;MLj&ugp0^`BbaNuOUk zZC>Rw$w{oC{WhOCT-{fv?eKcNE~W)iH#RsJ2)~&2;8gLJZ+QnA7`^znFI(m&81grI ziORb*k(*z9I<2qH>F@2m+4G&=THh3Q>y;npu3jw5a`?0ZQ|VC~|NG|;FfmOj^^WD4 z_%=~;!KA;@J|{m$y=t!dA+A-#+?Xfy;q`<~_oiLB67u@d<@(C2(T;qOC=j(y*1rr+kEMN%mig{Rms5dV`{@nmhkGpIQ|?XD*>?Vt z>ei=$S<#H5$JTG{zVFBzcr@kV|1Wx{guFk>-mKE^+Ts$p|JY2kx`jK0=co1k{M?~& z+l>3@Hi6lbgRbNUw6FR*>u%c0_Aq(lKT#{1`_y!lf14Ydx`zcsy97_yYJ+uTd*3GQ z-f!!py5nW%&MDDGx0BsG-&Rh!YjyAOk8?_VSs(WJq*orWH(>ep>ABMD*RNmnoJ^16 zzO%D-_NTh{fyu|B{$5-EchaWfq80x0ZKC#mGT!xIk++7OV&k_rw>;hZWx^gUUApx0 zg@=bVwXKiO@-zEV_=R!t@xH}>>i&L>`||UX|H_>=zbT1I3VIsr&0l(Cvisd7d+u77 z1;o_I^vc+_{d)2>^pKy7{jw>he=nWR{WN8+Y;<{0cCb#bgy}Bt8P7hxyrgPU_J`%w z)!o~lrT*2`*Is(px;&^bQ1I#3x8CVq6x;3xs%>=}B zYufE9$`?MGe(3&T(TUZ+_pcAG&7J!x_PHzfy@hJ~W^~=&SIS+xvr6>pr|av!y}j#v z-tMn;)ytpHr}zhI3BGycVe@wV)~&D21E<$~VSIak_jM`v&gkov&-Q;mcl*nu;`+ch z8d^F_mdpR|4ca$FRDS+~D^E`>bdI`sYJE+2)y+pwuiSh0XZ8;EZ|@&($-h)27F(@u z&a?mLQ{|FBHv<2aq>1SM{h|Epvi!WTMO(LSi_Enx`M^-S<%R9*y4bZ@+Y2JU{^U}v zOLb-a``&)Nw$In6Irla++C_dcR9(L0hQZZ{lj}cpb(O}jhkw)m`@&iKa&2|l<;VU1 zn&#EM@_Z_NC#iXN!CAlb)IFd2_Xp?Z_KNwg{I9M5cdnAs+<3poL1zq^Qr4Q7)hH#b zlFO^{+2k)UL8FF)N7AfE>(uELt2PC_{2CG-9?1Fq(UNktri-f;TB~DPuUxp`(A>`V z^j^XBoiF$7`)Trg_Whs*TTRR_$N&4mE;hCPGOzjFB-WMv$zMx0DcT-1K5w_&`^7Y0 zY0s+U{=e@sv-y1=b)69Bk@2Yg{QKgC#KW0~!(V3{Sm1c=%WU(Sv-6Mn1XLXk^WWXO zwdS%x-6Kh_TbB3tG$uX1vfh@Hd1vE~XT9c^ErXY7tnmBz9+cAr0WXdOptcva1N-HO?K@-`mLZ9E&@Zhp90HLK>D<+c1o>&KxHf0vr} z)*YVtH%i9#a@9V@$`}8tUues1ol$kL)k~!Oq0q@d$)Nd9Pfz>Adp2p;yI=WQmAZ+I z@8?cG{?#)2X89L?FL}E@KMStLcniUTI&U#Qk$~$P6crBdmz11o^JZuK%FR4i`J`-G z*!ZN@@SN{@zOeasrG)AHNt5p0KhPO4_w*qZ@y~sH|Mhm<+L)_-lDDbOqU6Jbg;UOy zy}h~Bdt-b{^5g6AH>cZEceA8%^OF|IgIjc5)#ta-;rG3Hfx>p#&vJDn|tOpwfyZ&KAy3JdD^){ zu~QX4KXPvGSD4B7<45!NsnT7Ed-%m~u}CFz^R9Pz5u?iM-pI7edBL+3uE36%;uMLp zv#ZWejeD3kZ~dN6v$CiD^pn(@Q}j^9wP1hYS5vvi6OINO8XBrNPoFipHPYz#O3TOw z(}z8tx7M9q&#}2)3tOSfxt zZ;q1634i+f^Mr*#xrOIb3jTS*DXBwcT2>p_1eF;&fvaR(`;AsJ~p*6M*2MK z{cnG*b6D=h?$~X#Zl-nrykBRNy$bnle`T+Y_|w$j%_I;ry+R??oXpS$Vf zlZmpwxhWG~-28m5 zZr;7^E4j;@+8b7~d=CkIE)e&^gi+@$CzFx8_UG-%mH$GEKizr$u-ScTdbX*(`~FLp zv-7iqpLvI`i#YeWLjHp9_Ir84q204ho0QLKX*>u%SZg4E!!rxSBvlaJ8hFy zWSB&@pP2i}m^CfE53M>roQ~PDck-v}>;E?C&Hc)|tLj|L>-)X;cZN!Oi4{)&=^5$r z&CXs;_3-JnYjwYT-L>`4oHv5IGJf&=*0H@OZ&V_oy2(N}_D|sShbbqINb1+x+HAZ( z(J?&MJpAQPdHby2lcaUm+15M6%OnxR_t(sYw?@HWO8eCE z_czWtA3wZy<?vnT9qsI6De~eXWT2vk-v-iGf@%rVG(@SeT zTkZPlqQidt`|$2}#=-yh0>qwoZ1Acqzf-#XtD&6kzneDdyWTuLdd^?@?H6!=AAj|dy*Dezkay#@3%6K^|5nT*G+y``M~ja!aS}QJkuAZ`Ad|ZJkr~K z^im|hd7xlU5))rP)4tnJF6)@wITqf*wSC35Ykjrzi~7&-@g9D==1<9%!^<{wi|*N7 zD_!Snthdv&g7?dXP3P_ZcIeHiYi-}iEbd#iBQP-V)a`jTnpfq&PPn(Vqu-|OO7J=P zuP-!je|=iF>5r(@%pWW6X{T)e9v=DP++@Yli zFSjoE4+lfz1H}bZtqU*fru zO$gK3p#Fe|vggXwwmgxHs|AgJ9bVjUW#8QOraVuj+>ibE&dg$aRB3s6n7`=T>qTdS z`1dHECg?k*BSa(pkgM zMB9BE9twlTTJD$J7N7Flg{AY*tOExEXD(Y&@6`6VU%Vyi>6xJZGY3N#w#j{y0`)<% z8RSzW(^!<0&R#tH_2FVW$D5Z{xCfYZYxZV!*d|u&{jf~)uwc78W9!w|EB+j)*;KMa zTqlxqj^T<~N{e^#ZN4g|8dThyuAMWv`g(9p)^+|V+pioCIO};n&Rt{m>aX1UW<_Ub zJYQz3w!+=?)k5p9RljyuhqIKWpq)3CX`p$L4KD&<0u_D?O|LDrkH7{3=W{v~)Vj5| zK#Wy*V9Cg_?)e%4VekYc151q>!@;kTvOWSj2x2$1m?CbN87|MKJ|=iND93Y>TUO|S(!(xF4Z zVCn<4<4fB)%4Tqa{UVUZ;-k7F`IjH}_HWM6MWRkEAfLF*I1I77Q9=2FZV-p8#sKtaL4q^2T} zY4|UDt3ZsfoW%+uu%3o;mR})p&tjS6lbj1`8`@MLN}nkS2sV6oa4a}mdS-zcM9dL1 zZ?}Y(c{9ZFGp+|hnyfee=PBOGm&FVY!vrbN5b%x{ESF7qv>;2a67-ms3B?qf@q1B-#9!i%BlwWj6~$Vx*4 z-NrY!HuJ8R2F)UAfY%i}DBR#Yvi+M8bRZtG@Q#7w!PP#r)oij8Ow|-F1aQC%_6E(s zTjx%|vzqO);EI0hw2HZ?Nq>P+X7@w2M~_*dOFADqD6GqoKN=>pS2g{zsixyw&X-pv z)T?b(PkX&MYWwA~J-)nu&n>*Rr7p}qUHW6|Y|T|G+g`E9CG<`zc%*%=Z-JYhbMZ-b zyM@=L*kt*>_xG)~Tk`D4Y7ITDiG1O?OAh_2_1f}ehR>_{R`V`BuFgI=7m%G@9(~A zH@r+V;@QgI{iLtiNDg{jXo@cGikLFD>@&`g=U)-*K-UcNo@K{8E~` z>TYhYzBKRJt6P3NFuro}V%FpP!q#@*3!eHV-`EINAKx+Ti=~_ ztE;n{TmSE8SG==xvrrt`W~zU$uCC5}es1oRdGq`(FZW;mCg*s0;Wd_By|a!L-8+5h zX9BnoZkp}z_QL5kY;LBZlU22*ojU(-;Z^_JE2M3jU$MondDHcQw<1|iRsPSEtoHbY zt_!F9l@G4{uc>ouexT&@#Lm9$ZI-t(UYSlydex=5YN5|dLwD1V0H5AlxBF6}tsY(8 z@x8W3Df-olmDeT2?%dM5`9y_p(M#r#>ge0EU-aI!U%a&azt?pBUB{)$bI$Qd&0Tvd z?`z4XhdS@>b(wxCedzS-q2&5tuQjW@*b?o%iL2B3b1Uv1Ub}kr;_GqMy?MJ{s_lBe?{~)gdwb26$)oQB>%4sLo?rR> zT65i~Egeb8$uFNyk6)%fzvj}ce^xS#N68C2oyf8!tso@3`jXWw&S2DfRn)x+{OGIA47i6YZ6s<$dbmz0ZEC zS&vSxU#VF><j={`FWZ|3myC>%v(=g`+(u z&o`PSwCHk$M&;y5tsEcLeVUrGu_R*iozQ(v$5P^*CJN4#wa!jxFyHg;A=2c;m+kxi zuI=8Lnwn~oazdc$#lrSoEoRbUDb#>Sw_#$KZk;mDZ>mD&o_1k$ps#-95 z=JwoF#dXp~%|Vs#BI@q$JQnwOiemoEQK zt7&W3t8W)y%<=vbI5l_Xblr9L*XQ(~*yZptR(|zOKi160E4S^O(!P272 zx7j0h=U_AY<-gzWzrS+r)2E_SCr>UscFb+n+O%p0e?0yiI?!v!IQ9WX(h6Q%*X)-8|~o z=ZW2j5<8_c?{x1vOV`|$l~E$?`<0eyR@*BjDNc8d6-~c$>UORT|DQggc$V!+kIH41 zl|Gp%Gu!jx#Eqx!tQ3p8SkY9yXYSr}S8l{CZ`!@{hw`nndqd8~1{JXLv->Y<+m_|k z<#&D0+WjYO_Qc#;@T%p^W4`lqR`F&38)1K&g(X*J~VmKq!$MonQ!UUff~LFUpPu) zrJn@Lt~!2ZY1O;hV_~vO?}YAOeC*CS^Vdg1sF&-sQcb z=u)oU>Fkt)XXAdSPdXa$_T$Ps-si#}ySoL|JPez6*!Ep0f4G?D*3vBz)!QfCl-!$M zZPQ*Ic<{T-v9o>}3xrFpGjrbg%>E^E?d`&Qp3ZCQjMnVQ`2V=%<$>K9;WxSD9&PK* z@4dk+9e4iWuFZwd&dfY@2Q(d%`R~uqJw|Jqr|Cv7Q<}|!3pDZSdUAgexCv|Iac2@lQ zH}@mA%`vKwurO5fJ$*`lf91);Q;$#hGV`R;+Q(b1BkowUhPTaFyrX^Z${);Hc@_sA z-7S@fn(wZ#{jc5*W%s@%nU|Mob}!=M;(BpPd;OBB+E*VkMqa#g=~7a#edN|T6DBP9 zvvu1oz1!2kvtzS=+yG6KHzuek6ffL#$fEdjw#dzhrGHZM>OwzezgS%TFW5@ZCMEmx z^VH*ul0KDJs(#|?(tW>};J-_$%N4?3XnUpwF+PbbPHeon>QbrOFXe5ERVJRZIHpQBW< z!Fc8O&?|YFOZENtIVx>A`zPa4*J6Fm!$%JrUoEwtDFU zxA;e`N2HkD$wkZW?Y-JQKXqT&?9Eeu##BCWFW&U%=arSgrxx1_sqKxCoODf&_15-$ z`LD09`*-(&HzaXHG0FaM>RR-2|H3)?|Cf9bbFF#J7UQry&DL9J*-n+X4<sTq{A%9)y?9|xtj7XHUoCVkrdZ_ms!?M^#CFW2;){Qn>9C%w`lBUGDy-AL}g$SNM= zQ2gvn;Gg_`Khu8QJYToWX8P}Ev-2jYfxDHLUZ>RgD%jpR(UBo%^(}t>#*bf= zkJ$+MPtNGLYv zQUa%Rtm;^6A($!nqVn@I&Eow^m)0E#^K7XHbrlp&aIkb=$co^*e`fUr-zRUXw=4|W zn)kIJHZQNQov5isA zl9*&0!`rgQ^VH1A_qG~uoNBUi<-Xpv%Z@$X+IMcoVR>)|azQ%hkJ_n4{$c4ManHTB z&fCJA3Y}zauw@M9Tvz*a17w#V1JgW#jQ$PLA}6?t0qN;%La=?s-f4g$?H3@8yPtZE}^+T=fJtLg2U(r=Yy!H)!Z|^3TlsE_^f$;y;9e^UtbT+Gv^Tl)w%~VnTmQRWsAs<1M`|IUN|JsCK{Q31E(B^r>0&mlGd;adVU%1d!Am%Yg^>pJ~hppq>j=NP$_}=*a z=jmhTMVfAwhwb7LrX1}1v{qNeYTLAo&z-7&8Xv98=a!sUqv`5?tkkn=Q>J$4Hkr4N z-k(s`uaikV#`i)f_v3r;2t#rP<+a;|(V5NWPYfi7u zb8mxM12*2jxbezTqYQpl&U5|i+}n14mVNGC5L^HA^U*K8tMwL7v5UREX}8_2=RbWE zcie4l`~rzig#-~s--3-9r!)?o5C^9b29^>Qg&kHBH()~&i#b5+OS@}8l_CR+gM&Lm z)9U6%UudiubTP18*Vr_wd4K|JQR!`POf|}>Z&)?q#m%)YTi4p=aq(~{Gie&SeD71A zb?x{LFL#Smw+@|~Xb;}KcOZi)Twn24P+p1V33--XLNg|~ez}(#`*-(i;e&pk3_|(K zKgQlY+Vn-?!Mp=&_V4O%me?n}!ukBQ@(Pcex=e2J)iVyi4g0KM2pMUnMJB$!gcB?k^87#Kk?}_`c$2&73&%ju)#K zUHI21--@{9`Q&J(%j2J|Y*pW{%ewr(dH#5w&c)#80={q0>Z?9@cU;U)zwX$}{;MlD zzL#+=;hwL*S14rv^6dh(B|h^fKYrVyu_&@8?u?|*mfrIl)y>O~o$gcr_2JXG+T7Q> zwL8l~1a@j&p1U_HF73zO=9~A8r)4~IpZiwu)mN_SgJ&O1F8N}!NThCVcsBFJmAx*z z@29@aeSd4q&*wtCvr}K+4{`qT^nLE%rqcXNgg8s}^=|(T#pyz#`JdwojN1j~7H^-Gd{yu~Yx#weMGI>VM*UR@WR6#Ocxd*4 z_vh4h&1?0ooz5SqwSSTSd$(n)tFybUYqyHa{AtQp(|^6ZYtbIBA};Rto1bs2&{y7N z(Eq}5pQO(7*$2P(3&qaz|1w?EW%kb*)<>^%rTablJMpuJRqpZ5%a7I`7615d?uvUN z8He-|x9Yw-U6Q(f+WyEo?wKFi_7z^bb&BUJSN6f)C%626*#+{WRsGD%7VlAY>FdlT)BZg* zc2U|fZ`U%fMW>vz*59~n(vcp=^zqK@KkD+=*UH|pmbtri-p-o3`V)IE&0qIcs*JV& zg3Pno&u)5OF%Z0+&9=(+R(`>Z9kas(-abmstBPMVT|b1iO8vd}`byu4Qqv@l?~UA7 zdH?LcOTlqx|Gk%0`}NyIm3wx5)y5lL)qT}B=g$q=zP0}SBk733zEgAdPd_nr@6q0@ zsJHhmo)rn+H}QECxa99u7kOjmohx6Qf4=Wd%9MgXfi=#$=1NKJIo>rdT~GTSJ%0S^ zoGm}tXH4GnE8x@LIgelGCu}iN{rezf(JQe<8)wEGpZkjUH0zuCIDNbP*;i*zf4pn9 zz{aO%V)!1vzG$~CIM3r>af1g-`OlN*%Cp?vKUDWw&M&rD*Ri3+)4F4KWBxtwopy)H zIHvz+{XE@jYxI>52|vx(u$pH}1m*}`Y+QQhg1k^CL;R;5RxMReKCkl?nZE4Xqiugy zXV19j-j?IK=j~jc-P=AiPCKNYrx!1g^y9$_E2oenheKv{KbUNqt`hhxAT+@1$C5Rc z3)`L*%sP^zBsiz%U{?R02}kW`wXZ1p=`z*&&mrF$gHH#Sm3!7K;C~<-|7qHemwzq! z?Kb@OQL#EFzR=7rU~5sUr}y5f;Dk-?Z6swz6aLu97XK z*Mk2%dFJqDTHMx_PU!-{`873@Ov64NZQ8kI)7?jNZpIxb6}xxHCFWkrzQ9Mq0W&mz z>->b$1v3k2_7K_dkx$ zRrn>&y_m=P^UD_(Iu~^8ZduR#seDTRMe}c;D^I6_^Lo|6sXNa7N3&kIovs-+5|Gd+pg0=r@_OZR{i7RP&@lJo&vFTIpKhM6xA10`4eQ{=gj;HjA z3;Uk^JNs40ugG}OPU|05WrDW@k1=Wg%-D8f=gQuojv1#o4)a^C+Y+vM{O{qNF5&!F ziWGlw#(%Cm^i4PIT7S{qC&#?!JSl$7@m1}O`SSCnrc0jxe|lKACiYL}#ubm)M3={W z*}2g5ip82d!Tl-;sHrFX}rxjG>=L4JFDMLDld zKicbmNq7CK>c@F1ud0`c9ZHQ|*4C-<46vHbY{ba@)UA@rfv0IOn&b$?{)41BYIJo+;(l({A{u0n zU%t4`N$tB8SFm+Q|L2{W=7NuR#t25gj6Kb9cS%ze%Ycrf9?OU z_M62w<*L=2?#CSdeC@nI?WYB6H{3pwS{-}!>+1a<1BBz}q`toVtj*g9A z4jt{R=(hg3_1EgZ+KV~QGjUUy*XfA+M%ox*3z=+xSCk9-i@b(A)R_`0+Dq z=YMSdQ-8<%QL>Ghm+Y*s+pbN!%(>;heg5-_8@1xD99Ft?XB}6gdZpL<@8z>Q^_~@f zwAmN7Ml+;+Is4KQ-?dYh{w?c$c*8wf<=gw(S0C2#tp8Wh`_^DXN2Xx>`?jU4o%EB` zy3hK3@I972$M4ROoUh^kVyj~IdQM!Jw)0`ZH%aTAg8z@_Z9T5%r0>`EHPtSrZTr#K zJJZi+ew&>5=4wp6r0s;+bIQ^+N$C0oY&{nCz)+y74I z&w97@r0c&URi%7EK_^eey!^V1|HT{5?)e?F{!IPYc)ObEJDc%UBbOGhA1>nRpU+(i zo|5>mY~OC-j}zw277Oov`tLr^zG4w|a}njV@^AZ!k9|0}+L|%tU(_qzZ{f0mlQhiP zGiwe`RQzCA9BTiw{JQnJ*HMKFjMwF)_CJ~Y+j?%DbX%;3qSi`E$D7_O5e09k1rDeDF-G%=i#TN@rNR0BeS<8HxxpqEQC z_ih*2CwMt#ze=h1GY)Bswb!IY<7b{0S+4tNqTHq$w*VIJXVOc}-*is?8S?Y;oQ_9V z>|T9XzuHLEXO408)qt<}zgTC(61AGV&JdpYOIb$4l}>s9}L+1%QZ8xwo_Ya#Pa z*=tR=%XTeXENnGVJb0)KsT>E-*<6y?q><`DlV z5U+Rf9{<)kR`szr^@{Hw@~_%%G+oE}v{BW?Zv7osW1hR^ZN7Er+@1}oc1+tpe*Em5 z_x`qh`17o%O8T}jI}1*?#y!h8{<(1d&cd31-IKe2YKmRh{9}jk#i_NmGmcEWH_Oc2 za>Dty@*fJnF~tkt+4(i`@K=^-4+xjW|`?Hrq+4;@bivmDf7aMm4B!?SM6MPBw)=e7%?#mJ*#;m7-x45);9l7u>7K5lMkuX!`~jQPBB`}r&4S8=aVi3$7Hl~FFZfWxjcKe6#q_pfi}S1O%4*V`VN zbjsH0?8$&lJEX)cav3Lmso2`;ze#s*SZ;jp+xzv>{>2j>zE56#bRX}k zXJ>!UUA}CR^s*He`#fhIv3-6q=DO*(or(8zSW-$qomUsKt>s(q`JmXRO)WL?0=xUw zS$a=rZ(7YJaCUz{tgrT7`%1Aex!)5NuVk|e?lpD3JMHS}OW9G!{wdkjKd@PKdn@>%a_iv&$)U$XuIo+RE}?V;#~B7gO3*IUEkeQy(eC*{9cAl5nI35 z$DhWw@o(>*Dn9dW&JD%$m+TB2-#+y^|HHlJo$iC|)-$@N3wE7hJ)M;&cy4yP<+;GB z=ZC^?1%)}Dp3md1|8QHzyMj4t619t)FRpO7sp34%=#0kU6_=VPEewqO7_x#^z+*`-BMCV=6 zmaJP--&+4$&bPVy!KvPf2GhRfKK~|kO;zVu!87Fxi*_@dUaY_W!9<}*oiBd_?|hTl z_M&6g54Ws;Ec5qYdVHxZ@~NO=

E;F_x2$-OPDIFJJpy__@C3vij<-{m1u4zPxI; z-MLoB~~l19ks2Qnfy;azB=xXYe}8F>9RF9uFYBFHqCue%E#$CU#1+NEf<$> zeMaZ=(*Nd>zKYtr1}%vBS_@*WCjE$y;5Y_HC!VK}vCZOohU{j1NNJjE3mDXDXK-K|9$ zwauPZXM6uH+jf+j`QOTQ7IO8Qt;{vqx1E{zu3~fXi&Ep`lEuvP&xo%&q_B6>+MLA} z8^fj9!fR#zzkbo{|E(@}&U6dGqM6C}{&d}%Jtg#nk%=zT_I$(dk0wveNU^LfdiTF$ z=987?%1Q?=J)WwV^m{g+r>ge)*sE9XsclucUGMs3sk_$U(^cx~i>ACkRo1D0UiLIc zBhUYAbKOVN&#JHGFql)x;i2y_d-;{?uXOFEJ=JeN>Ki8Yy4uBPi>Ch02~&?7y;(Ki zf6D9aYl> z$eBXNr|ylCyS0AL8s~p58mX-7%ak`Yt+)JEc5=>JbNkTnbnbSoXDRRBMJ)a1k?Ik5 z-c$a)qgdw8%hoTao{l$K-OHnF{^{q6os2cPe|bOOJ$F4^@Z!-*Z^X1HH|xBS`N_Wf{-fPB+XJfBD9L?0q-d-3yE0JH zP4xe}Jzt#K%v`t3eY%h*yxVqp>$&f@SpxQ%{b_%lS9@2&-yAt2d65=)bHA!zM}ZyrDU;>Q(Gg> z7pXgkHGFTGyzsmK`Y-h-1>dM#-|+6?tBt3WWZloj<*4@Yl$KpTxhm;yZ`|}ZU$|HA zVv&0BF!S!5k3}i7cJH$CdfYvK`L^Ga%r7-K>=4p;{(9~gy{CmT^}A<>uW&w_{$a&} zGl{1+?~51ty?e@oll)E6Ho1)6;F01N93JmKZ#&;>=-oE`|Dn$h9zLo_5aELkYdRdr zU=oN~%&A-t9f?X{5{QvugN}njk8N-hgz^~<9yNsRwq{gdILOP80$*t)5F^73Rfeo> zp6~^`+s`Vwj<7KP7clsB<8ZhBpUZwHSXmqn__Mrw+@EZ7TK>v}>Awy)IxOHg@q5er zr^)9%(pQyhN^^2m!bZ#VS+0 z*!Y_#L(^+j0~hGB9maSLhl1LLZ6;6`J^*bsoqj+-78(pSiVO$8wn|+B4V{Cw34ykn z#xXgUKm+AND+9}Q@hm)+FRPmV>HjwCn&74SF%#4{IAiRu3AKbBRH+xPc)>g8_`ftM zpP#ms&OhcIfANs*@SSOspAp5p4dRX&phJ4M_;z=J z&dOonU=e2I$TQf=mIIpSV-zsZW#m|wIa^E=G>^$Bz@f$@a3>*)_XczwRTPszjJ-)N zi|bEC@!vX6B3+)JP4=1j%`8El#c8&KOUvqF<0hq;xygE$f1PqYm;L;_ZtfWC*Piz{>sI5elt7MgHs=?-75H09lJ^D_Ur8?3XiR~{Je6vWKmk9(7d@8 zt!htg{a1cmymIT_NqwPvJ)^tcE$8$0p8loJMoIb6i${*yntE34)85)QM_I4ZG}DUS zxU~M)R}s;PE2eDS{Y7(CzU7PQMykSsucz#IIOn-w)^-yMBi=d%fiEnVCbL~w(zyM? zkEZ;KO<%WPytqkUWOni*p_iXH{V(rmdaY@v*2^che!+UaJucS%Iw6OIlQ+LS6lfoQ zNcCOcWA2Qn@0PDvRr!s6O;g4GzkC-j(tmYi?-R8V%RgZi_sq^XN#%2v8rLayjrQdaW zuj^K2-SKiQJ)IG7tUS}_-TJ>_%TlJyGicP4-!?g4AusIHQF{e}ES7b)ujRjN*5<$X zW#j%ubFL(IZOAH}Vfn65?2LS1>RrKKzaE^vVqPqC*801tkfTufzZ1Ww?mu*D?Uwx+ zl5;J8?4HwK)yMm~*fQ4ap=VcD&(gK-_d{I1&wl=I`X!;?**D97=DyEZ`1N=Eg5LK3 zsegqh`g^}QZGJ!3>yNhj-&VFKK1*$v+bwaHF{`}rHs;*>DF*SU-XyV9#~6G{FS&1C z7913_ZgIj7R>sB+?;rNP|7-m&G40Z>$L3nLA>3PUn|QMvy)d&jKFx89?5tN)YYdm4 zUKFe9f8pCBcMF?&>!cz*{$6?(n0h(wl#fMs*K50ltCs1Ch)-SorEm4DZJX{Jss8`+ zgHvaX{bo(?GA^UMMa#AcMb&=sy0t*axgAR3sqeJ^2T$KKDTzI}?v?4C z>~jl(P2~eBA6JR}C|*&2%Y5n%W~01?ZPy-$T;9|EIQH~Yu}L>VgZ@j3UaLED`?03} zSFNr-pQPRPp|2K;UQ&O`b;@&&SFY^Wl1jj~ZsLShunzE_Ug>eTCRYEmCOy1U_;-Eyr&<4R z`e?1W<)r-k+_KrrbsufH9+Vy3taR)3xBtEFTclPfRBL@bZ#R9L>~HznZLbTZrPs~) zv1XILS(+;UQpLT?FHc+if9dvX_g4I<|37J}iP3wneSse3k;|5BFQ0j``R2WB4Mnr& zviW}+`lhd6ZoFf8{Dj(hLZzoZRA;>1w?8QEn9Dv%NylE@si%C8r|+J(plaRs4R+Hn zK8OzDI2rMBm>3-3s5*>bg5|Br3j@_E;v^X=}=lIH%&wnYDWy1~>d zZ<40{UnE$&f8mtqsLj*ex$Z4&n^u$^cjJYZ!WvfddDUC?2B&F-7zwEbnsK*qbepB< zFe-IPaz1|P@U#04_rJ!e2}wTosk`?))PB1C@TDVrFX>K^F>kqbD?2mhz50r6KdrZv z{I8I@|2$Lb#NmsxD=eZ|!rMyDpQ)dzFUDK4r_4}v$!aDINz-lf0$lVbwr<r`&H_V;BQexq6b@P`>yD~0tZHln6NM-LmRXd|h%--$n+oxClmsGASR2Eri z8~9nzH$mF;`nAB-H!QY3h~3ArvROfS=HXwDw_ljJ>bk`{`OJ!Mdvn5#+ubkUxVL}d zRrhtvg12^y7|Ksr7#FhTkK40OQpzzmCY~?3wMl%u6u(*H32ZykJ&nBiWXloB!l@H1~I}&yf+* zD_2zQ7Wy7>GwP}N-0B@lPU8JPS&trHc5zj#|K;t=_AULgX6wQ%Ri*!v1tu^2GK+uu znq`wkrKiX}f1SN<@u5??Q6f+GWM!>g_H0|!^wcQfIrk){R14O=pCo#x_}S-K|MjH) z8tC5tD8U~(|MViO$WB$;GQlGY_oiv+1rXXe>&5C_y^mP z8S7^JaGz!MC~jY!sqyBFS(fk2zua22I`WG6#WkG!m%mtHk!^KzN68=It{2(!jC}ro zVQ1bN`^QQ_;F|L(&y920+c{25SYw^xb&;LzwEwYqdS96pt-e-xG zP3ZNa1F!UpH(Z*$I_H*4wb%S*TYdz3)iGbnUwG-))h+w~toOR}&?aZjNv8cX^k*j02SaaUQ1s_Id`2XbHZEtfQZE{j{{tF}kk`N<a+__`Hn)>uZB6=;pEW|w=PYqn)fU|^suQ3j$A8Ywr~ll_B|T3V zznt6_uVuc>=y`Nt{fwhNvM+@|i}@ydX_x(L>snQIVT&OD1>WG49Xt7T@BZ3Q`Yycl z#Q!FDd;!KRoGQ=0}NJMNdkzR~?-#zaW0^+H>!_ZoISDH$kq} zdTRCU?FBbin(XPXvXz)&-Me$`()j(8{r3M)Ft{JE{nAb6cN?Asht~JV)oFvR6I(`Cy-o%I$M|@2~f}bIegp zE>HH9?Vfl|rkV|pTy=MS4R2d?)O4HJ$3@E)pDHU`WEHaHjmH0yX^ZtY8_%iGh~DdL zzx{rFhRZkRE#GeNZmD=*P&-BMHoJD*qGQ{HPc>;truFxFEl;dbR@(cA&)e8@eWX~? zT8j$Cw_3Gxj(x3~bMC}%8fa9qy8PnAk0tj$%>R(Ig87bdO}zY)9Pt$YhY#QG-x%;tRnY19 zy3IbnKP=Mvx@X_NJO3|inaHp4wd$Gk^XFS*$tz$HbsR$6FvRvdVt>f^L*$2*gaM84dh!j z(USjD(#jascMHzE|HvtR`cdHWH^(<nA``zBZrFrLVpVxekt^O%JE%@n40f}|YQ}Yk*INP@I4(ruV3DJf9Z#IkkyuUI} zoTnnYHfnKt{TsKuot!^cYfoIhS1o_t-fv+#CHLhjb+$yE`7W6`@8c51rRJwEHGDAJ zTNo!@{4`zSyFp9K{_QefUmok4@%Dq#f6tqOY`3*}S}X4zzR7LX;c$sF;EPG=6(Mff z>3Q`$#|oRjIyPHW9mx3{5+B!U+4i3?*j?B4MX8q4X8*_4amh}a^$vH9e&4!%`Jk4y zk$lYUfR{$h(|0u=-?z!~)%B+ncV0Q;z|Z};Xro+IRSJIze~;!-n|0+phU^!`y|ZiE zwjH#|*|757m79;do*k;5-yQSKX?u

(5rwN_x}Q8Famj=-F@~IlW_U>%v#}B6UJi3*-nYONtVp{5lc&%-rhRAHqRoV<&TY?{|xn~Ws*`?y>bK>F?9Wm zZJQo>DY!Vc{fbPuuuaPIy9*N17CxUYtkD#xwY@k`a?!@*lV18I;jypQroGhMbT@=! z;*E9dtI|4Vz71Ls(*4i&W0>(R>qlEJZd`EHZtbI+^39)~FJ9}HcU9l@-Q~T^Yvvxh z<6dxfcE*}xu^k(|axX-Gm0$ah$?`=~_1c^EhjMK!7?a;*9sAb*YU_!^d}Yz6<&N1m zOx`%_qN(7IevTzOJP+S*3&@l?bm06h-)ixB((dUJhx;<;KD?RKck|Hto1s^$i*?L5 zA27_BHFIMABZYfcR^Kiydw zr|rvG;vd`D4-d$=T;^G+L)0%(yH1ZM*i#dcnB2!g*)^ zO*}C(%;9b{o9QRrZTqJuX+E>6>^+sJ$Mhoe*el~TfpaeWh@Vz!Eyi(o?cI!BDU$`ayjn}97#}_4P zv?TrYiIlz7cCY(Dy=%kmCa+&U$NpG9_PZuicKFxX4GTjQWlkCB+wMB_CtBcE?bRbe zNB64V+{)~JeJ7tm+LyAGO8*3_Q&(oBy(lTasUGmS&tZqe?+^X?#{EUde5LOkdDwj? zd;a}|W7P^%4&U9(b?4XodDhSOZc5HFl55%c_LAf;4vqTHyLmQ=+dsaS`0aAg{58T+ zpNhI<4&R)6Y4`4^iUqPk%M$31-ykN`G{jXuq z+uF1{Hif}orke^G9^QS&>qv6qI~^O7WC^Fs@;l?T;u;$=rd4jW58soac>V2DQy!me1{WK+;eJ76v zO))>u^V+<9`NH{D5+9mRtevK$ZhcE`)5H6xb?xFZ-OiP7vJTtLX!&CI-3h0~W~BQ} zElMsHJrY+eptbI>QzD-)t_ zGoK1+yiw<={(I+jpQ8SQtj*QshgsgV>u%kWS9UjScuzgD z;@E6w$UpaY5Bs;KG8LsWr`vOMjyYTWc+fjB+&(X9)8VPncV5l?yuo2bsrJO+H0v|G z#omIv2CacS=iRr7wj}Ldc+q=xVa~+)zaL*Uoa1oj26I@+Lp}c=w*PN${$6(MPw68m z{rMkU-s@L9JHO*qdl=V}uSdkcwMcHh@VawPddDobHA_Dpxvg$n_)ajd;k!&EQ|3>J z@0zFM-Rqvs|E-w8HSdr&mz>BYVI}Rh3;JiSKfU*e`?CL!_bWGZ`#xBC^nZ=q_S7|Z zPJ1T@$@k3r+*6jy_G!cSEi(7teTd14{*~c9RjvD;@ zxkcz@=FNyB=B<^F?nMOawAXU&|GwXJ{d51!`p*)Hb-#nQzn)O^BBdjBf|I@d{ohr_ zR?k;o{C57wiKCxw%M9uSaQcO>>LJ^A0oU2um4 z$A#68wZj%lya<`AuGaPS=l;UAy0w>f=M-H0Jgd98;+XH%qBoa%ew(gO-t74&%bH(P zoi9MQqk#j29Bf!p3LY<9Vx^?O1VR%O7$xtpFup1i6kr6Qj`jwgJew&Y?kp}2AS9%s z&^%kg;jSK7wF1*efe8nD+b6vOnbpA2;n2jAQXtH-;9iHy1 z*kI0@)xeWyA{;9SHEoITgoD0TL8cl|XIx}SDOf!7MHkdGsOK6uIu0E5c%VO7@!HvV To~cVgcglIX`njxgN@xNAAOYJ< literal 0 HcmV?d00001 diff --git a/docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.png b/docs/images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.png new file mode 100644 index 0000000000000000000000000000000000000000..4ab9ca4fa58047e98144cc8bcd7e621a39313168 GIT binary patch literal 25510 zcmeAS@N?(olHy`uVBq!ia0y~yV7$Y?z_^Wrje&vT>KXHs3=9m6#X;^)4C~IxykuZt zn2;Lbnda-upvAzzz`?-A$i~17Qo_K*z`!U3Wiv7`FiJ77g2fpa!WgCD>^MdZs2U~) zhW1Pb7O0vu1`y-_|A!2$p`naWnt^!%BUCjb1H%F)m}er{{GxPyLrY6beFGzXBO~3Slr-Jq%Dj@q3f;V7 zWr!g#b6ir3lZ!G7N;32F6hP)CCgqow*eWT3EK-00h&xL%(-1c06+^w1oS&-?lF>KR zGth^d4Kf}iYUN*)nVMIU2r}Q!&<3m$MGRq&4Oo3ZMt(_tZfZ$UX0m5qNor9+Q7Tlo z5mYyB73gLKr55Msl!B}d&C4vYgBgG(jIPT$KewPLwYWGlKhMq-YA3Q7RK1NpD7cV< z4-z+E(I6K$J1!f2a4dpi)Q;v%U-oM(kXWzHYrnFU&dg(dva9=^K7W4s)Ku-2 zt5$Wn^+-4}v+)#g?#{ZZb!%I$^wMR^E*KwLd{o|AS9wF_=d`Zg-lcJSt9Gh9 z=q#_SwA78-(&0D9!tw6z^6+mR9UTQnzKdKJEG zYJZp2hX3u8vz@i8?Cq*;wz1~--aMI-tYIkRaI4Ynb-YQDfsuNvg&cK`HOA0^A@+u*Ucz*RYn%f9;C{akYReKWt^iv9op{l02< zzv0z#-`Qd3_r|x|-~aIXe&uu7<923$lsBZGpZDwj|9{`V-l<;o{FwLOcKNy&9tWiJ z-|fBTKhtRGzFoVbj#^fJO8L9QbMmWxS?jR(y6cpMb1XPc>^#>y{}->c*_HUZpHIIY zJ$jVS{$_&Vis#3APaD=Azg+tGq+eCdpKI6eS3K_hn#6qf@89?J;b&6sOFJ+A`TDKG zmx5BEA75uSe2Gb2;nsGJi<>+4k>~2Y{`2knlK=kxzMPqzZ$+)-wkdLv@9*uE{rC6R z*Ww@6d`XAXnJOzQvqTavEO6|7RPk7M+oT_tc8gA*I(6y4l#H{{cid(^WVl;!m^W+5 z!rI^8d@os)zMAq#JJ_g5*23EVdat^*<#NGOw@XV)zg%$Uzxd?jWLXI#W8;;}mbtyH zPR^xY| zJwGWa$wQCjZs-0vZwhk#4@l>44E6Kt^FEfuZ>hI`!&L5BVee0rer~t_&UcN%dlIvb$~Uc!=Gbp1{2W~!Rj)L+c4R#}GgC#^H(gvzY*|@li2K>aFMd}^>(aI@_-DjZb2D{%U`ffAU5y|1tchY! z^*pH+nYs71pS)FfcX##^^~59gc6M?6efP~&9^`R*-kQ1nhqwQMn^UJw70h|+v*hiz z^?N>fna)*OeIV6!zYp_?Lym>-wiWHqo3%Ok_SAEBntT8KdYyIgnR36)qZLz@7soQq zJSyMx+JMunM%AGHU(Ka(Rd1P{jW7Bqow&2^%>S2uVgHvdU8-6CadO=BGpR5A{>*Kk z@%8bKTwBKcJxAw@ds!My65VW+r1}qscY8$snVS` z$1M{Nv53Y;y_;Y2sdLtJ(Zs386^`{tF8-6!7hZL|_}Q7j&k>*Qyy%m)mO20aR}2Ho zm(B+Bd!Kk#*z8j^n#7&rul;`U%F5u(UteDKx$OBEx1&ID?~g~_S@R4O6&use z&+|Rp#vA-`@6pnfCSGwSkaxs&d1p+SBGP{USg-U|o%uucq`6m>6zLQ@$Ao?xj#-$`t$5r zy0^EtXWoZj0b8nT-fY)p^xw0zR`=hzM-S%gUcTep!wqkx86|g3&tA5&`2OY6$7lWa zJ(at)aF3x$mpzO5mh;wEw8M(CbXt?SRuIKPw|e5%BmG}C#}#2 z)ulHkH!Q8*QBk?e*5B$17f7Si#D-MXaJBW%&(3!5xBVvZ@$~zb>+Aont}5=ZX<}k$ zQeXg~gKh^lHFZy4&VGAk%cmxAty`g#5P2~7-O<;dcr;`{W;ZZ!ut+nW)|>U|+oP|` z9O@6nw`=IH&p5UE;>Lf>>_KI_%X<6fKe;ZH_jvn(ACETOP7VIw*lXXdmKwjaM)K;_ zUHeY#Uukk!`B3JYrPED+`rO;5JNxC6&bILPrlRroX-9wMJYxTQ{zLT2n!+%h{na}Y z`5%22yx#u1^5Uh}ve(B%=ZWg43nyRWGAJG}fCQ@GF*9hLCXPJjhe|!$Vi22r3rtZBmd^% z%zoM0T-6qM>#&=q-;sC)Xb+_g=|8xHo`Z@qO* zwdKJ!)4(Oq6(-D>^5n)bw+EaDr%N^7KX>Ys*&YFbn8Sj~%pmI-7zGrX z9z4>4IEH~ynB#_5f%TIT6Gq8RAEr748MRHRO-*&PxN(^0)V}A8)j!Ui(o@V;-BJ7N z+ve`roWOn`;b$&6jHi}(9gtIN{AMV9x8CRP2!L1Wxa{{MMR_DqIM{A581|_O zp5*qfDRcEVJDcVNv)?!zwX6l2;I?^Ye+D10VDQw`Jf_+=<*yn; z^^e{&7dSSwFRb|Mx5wH2v3(u$!LPSt!31@L!VU{|NGfnRz{0dm=+2878Nw43x#KxqT--3sxT%s65&ZQ*c@5iB z?*i`bu9rS1Z!TNalFXAajkO!iHgrHqhFpvlOw&X>143z7*Ux*OKAlpo$zdTo*P zqotbq`uv4V*H+oRVXThmc6c%MSXfhZP>f8K*p`Cc*IBQ1Vs>57mU@$@I~$Y_+9j86 zocdrEBM&rg8yvhr{U|5iLReV(GYQ1lH^MtwTUr=cwyR!&$Ne7_hJ#;)C7OQwDJU_? z>wlO#?W1BM|6|GDlbPQ<7ezR69>-QzcCwwrOci`UL-I*^Gl3B%L`5(WP*ksvqb&;+3 zrep3$YtsbJRr{18 zOM&yjN^sfB2P%QKt`4`>YU@29ykd3xBer{78jKtb4WXbaV=a^DQ%Gsaz*x>C5L2#n z0~$w+%p48{ybWC{j?m(BE(6Q;xg6hMTm~kA80G~^p3oRCP-i$;s^0Y1Oj$s%@$%}k z2}+6r42;g4B`UQX#XUnT^z;eCd$O(ug z3@jH8A4RP+%}J~qF>IgdkPCpSOX_31#Iv{1wiyEZ=+ndKQ)m)lmF z`DrN`btNgCGyQfzP#}Y~@zgDsRclw~xpLiGEEZ^0D{`}MSp|QWfElRnZxmb`)q1MK zKy_R2VRnhABVPsIU%b0F-^_$xMXrh^?(SE)*pT!$m0LIDX@|CK=eOOV7?phHVcUv_ zfw>^ZGcXo&N?bZ@Tl|biH*U|3rD}7n%a?6TKE5jX=g*&8ik^C{TD5ACpt9SA2F7)^ z3qn_iUEG#?Tf@|Js+!*%4@pT$y-d^Xo4?JzI_3Ix)3whIJ=*b+<-^~~$CAqI0t}50 z6car7%m4rT`{mp1{Kf*FJH7s>D85$ zlbM5)k`}$X*>yooTs+vvhbJ{HZP$-(kHatz83-G=6sY^oa%pDgUl#ah)zReReHVlM zZI_A#o}FVk`Oba2CHwQY&kMhCV$a%r>z#S|`SV5GzZd_vt=={ztZwI#zXqi*ugzVw zcyVlB`u1%1<^H0VCOWgn_FcbnB_P#x>1o58p3mJJs@$BN9r{#N)IP*3;)=Bo)gRxD*>I(O#p39b z8@ZVj9{4%D>pb^;ZNkodZ_D;~^_l$(-O|Rfj)(cRp1Jw-WxliBxW)BU1n=Cq5wU7r zUd4=(n^WypDOFW9{IZ}(;Jga6io2(Nu z@BaM!>={2*C$+buBcOhhZt-rT@YU9lTjxxhw(QSQ|EisvUU-#1dT(=NjeP#Aa)s}! z9yH?##n|pH69K{RCNSL3fn(TuKyJC?%Z7Km(S2T zJBQ_^4>~(Md-@RMN(BjyoTq&AE}olU86&AQ&$fD7RIQHl5hMH6){%Qu&Of*NbV6B$ zd&-^X>8a`QG zHcWl+?#4D-79TO2&?B=}KG-Pg#l@tMV8a;Ax$fhR3Cv)13>;f}7+AKa-Vxx2wqyS& zF&zBLEzSfRm_7|^j~(OP2=XNZi^BnZCV`m!1&Rh}+E24H{itZ$seznacH(6QlTpe;?ZyoT z@y<%%ZuyP*pa#GH{km`4BLc1pbV-Lib4qk%VBt|s&^~B7MMNl{k+Fs!I=ZgFz{1rh zZ*CI~Y11`V)$CO$>FuA@>@Y#_#>U*)4^`Vx8W3Tck6{H4V=%{!RqfHCp{ZOZDNNAN z{wK6y>VtK08}HozrM#z+#h^7?Ax4FlNkO25B}a9~j)UxXf3|}I%i#pb{cSy00|LPb zt#N@e!$DrF$qNra0^pzrLz8q*nDb0XRoc|Yz+(Qwrwy!^frCYvkt5F_O4s95Pro=z z=fVIV0S3lb7cTzjzwb~`xJc52L0;cLKyMNoqdYGB~l zBFGrcnI|#r=(dZQjVYk`R@lN35*{ucml(~t?%|dRjqxn6Ucdgs)erWOfCkg*Y5L|i z*`R=)2x)^gT;;qn`@>ghj&)bhGfm+KS?6#-j74F`HUniXMsSEGl!6i~@9S%kbIU!Z zo^KJHHQ`a`sU`*v7ITpGo`r=4(acLBt&t77pv0QHwxtW=Nfuj1j=T%A1w1;0uew4##|_5J;m!L4w1fp!uMehB7#*HY{XWv>4Kq4iIiDdsMN#G~>4X zR`$jOC4;ItALaKqK47~n*|@0*+_9H%I?%(%#ByEWvLYll83hVd84i{{ZM21kuK}nR zT7KiGxHJ=I=eC{(NoNyXZOJ5%LmPgAl7^MHv_4p1|Vf#Zk6f*mKov0rPz(gbbpI%IP?6hwOq ze1xPShXd@Oz;tHk{}qtRV%W{VHs!2RZ;b;3OH*URT9)$r^K1_uuqipkagtc4sAL$ssduqvOQXuL0yL5!W*VO_;%v-=KV*TR<#A(Szsj2 z#m%IUpaBZYg-a&vxX<#6Q$P5dw3HHP=&t3!L+5s$^Wsg}7LNqZEs$%HK6K6fs-waR zjyHGr-v02(sesqLhX?9&hSgIF`Cu;4WXZXDSXW!ym{rOM(#K_BtOo_v^>uM?^ZyFo zb6}cr$P|+OIIKWnzF=`bH0QSPFmmLbm?0&~3UaalhYBM{p2ADzd`KWoP-HmBD;d0a z5hNWnsxTbnRjGXfDa!?nSQK_BCTD%t?&=qxabCu<2~-|COkWopEq1X#LLkOIL2<=? zmJc79ATx;$2^?Qu+`RmuM-jOYZ3wr1gj$42&!3RMWs>qpnXyOXHwV{22L=`=aDsTU zB5+~C<^?O0B^(Qzk40!`a5OYL1ciRvWhZDky-g(`@6hplg&o^$O4kIg{PoK!TZCmP zIK%0)T$}OX<7^N8)DJKAB2E3ZL~qR!&Aq*?Hz+tb^U;ycDHA6?{GhL|zZ}%2>l9XB zQT_ehDSIWQLk}U7XwVo?IKlDb?qS>de>QtR9+NJ)oxA+*LcD?i=YS^V(4$ySlWOe^bi~H@oZ12j6tXs8e zQRU}n7nA#K-M-(ixBvTfef`oob7ZbA7B$PhzHaGa_x?+(*YETCey5m!@0Uy7U%p?#X{`%UTolhp<_wVoT z)jRd~Mi)j#M!wRwx1XPtm1T1*RB+Fq=-+3vPQA81;H^LdL3qS<&~9fd$n?&Rq3gN ziQnJd?NdzqIGr_omv#9&8CmNxpP$v;tB)T9kII9xpEBcqao@^SDOFWgCzV!$+F|GG zz8Oz)4YDqKvtXui`l^h@?)_oflc(#&dObeYyZGnl=fP1?v$~YISK1u?I%WO4@^3ks zYyT8=?tA^??WMKWuI}#E-%^!#$68y}uA0y%WA&maMl3%xEM%9=ydmVs9<~GP%HP#qvG))b)0`T zHs0KvetARU;VIj<@2HYG`*)xHduAz<8kgdG7I{XE*3+H^M84shC6)K))W@%ZkUrtg zvJ>atLHmTckUpVm$hXDU_3V?%=S*84@0Mkhx@?(5kYC*DC0n+I+QwA&UAz1A*|Sx0 zd6}7-oeQk?yLuh!a`2yN)Oy5T_2|~3dyjTKf4a}U;6uW9=NtSAjNe&{7+6cud zC#_hLvR<#~xa8S(wx>jJYv7kd>%O|BHEwa9;E_g}>wx~lCJahzXl!=0JGEI%+SX5MpCP8J5n-$FYsZ0tSdz<+(8TiM!~ ziN!nC-AsVAGZl4XB0NpbIMHb2Ak~z*9+B8Y==ZtD`xdf~zBe4XlhD>vYd_ctPro2+-KbD>0{^ zka8!-k)bJ@+c;{o(5I8G;PB&MV`66GH`+5pAm*@Odmh`vhZcLCuK!wL$-yGtxMoex zVeTI5MGrfmjVEliqHK}XtOlOQA6^X3r}j;9vJhZs3{XhWKKSn&#F~g&f7n&u;gfP z2!J$*pB`iPO|QkgENr`8t-7$zxWDSN<<*ezz?6`Z&x{X}wHP9`pVlKhkU<8Ui296dsMvlCU8~~842r~)}G?8jyOFB+Uj1nHK*?qBn8}el6jD@$EO1w$by?jV+VLCqt z0T1p@yla(xk@w@JDbuI7TQFva{y(93=3&%Hr48*<*ChHy=BVyaJ$m$6fU};R;EL5p zS4GTsm?^S?iC1B=$M0#pZyrjkTeohS`ry_{gB9H1hGoNE4u^ubss2~kKvC>)U=fSL z4lz@nE>>_omjLQa&|u_P=gOPhp5*HC;4y31Cgr%=EY)m*gP;N8k}cqd zeAMY@+q8W1`fZ}Gs^8ESmY0`*6S^VvXCi<0%;GOQ3fsgvKuyF8XBl)Wx^M0~ncp0_ zre|S@%#FiA*UTQ*u^!wy{VKtMpnnPj&lAiIv{t=iuD6ymHpd^lO{b%=V39Q zaug}U%_P9B#Y@_SSZF#@$iGAJRt=cDVoi%;c zjYV=B+P9wBQMeb$Z<(BSYKf}NVN=2*R$3^=i`_UJwcMd_;>YjWgkrDy#RErh?1hAf zf@5$0i!+(oq8dlMnX6mwaVBUVyt_T!|3&15L#FFit=d%Z(rJCha&B(t^_Rrf8NNwO zd@K=S63w~Jv1ft~I7k>cw#;H+*?yH{BDmw!z`#+V&T#PSISxfgo^V)jl|^9(wC@QL zI$+Jnv98>W1JWI2U|Orja4^@@N#%k};~c%%S)UJmWDw}+?dEn^cVd$z(+2nA6sF>u z8y_CFrSm}3tGKxQuBqD-&MGSv?2JCCbJ)FiBRHdJu3Xt>d_XkAA}Iwnrr;tFGlvz@ z^j1h<0(CH_--&@t%gr!!d7K?7(5JE7_}P_0xdsOXP*qU<nQ(Wd2r^Zdzc<^X0;&z*^SKAKQs*$kT*%ev5nN=bIeF72 zqsc{1X8QzItX}oS*Xr_vh0ZTG_uDVZynf%K{nO{n%ipD6Oq0Lo zcG1vKukc>|@A+32Cc8^j->j(m{Qp@%ZS36c{cr9ReCF3sG`v{&=flC~FJCX|%l!Vx z*=dq-BH-1<&FZb~+0D~l?~C~*^vFI~DU`_b-i0b^)b z*orUVdcSA!y~(y=H7WUV)Fk0TLg==K%5FjP>;B4qw9O3(4ZF1af6Zh)xk}H)7Ww;* zeO+_?m87`5|6ewqMRB#i0#u4cw?BHlUZeiM-BwvSLC3q*PcAkbY}VA&jFi3n-*jsG zmFnZ$)|NchwO{b#2aD|rt8IC2XSwmnF#6ouaCO3`TUS^69%{>}Q4Hu~o1j0#hr9U2 zfx63|xY~M7otwYB|5?3*{Qqpbxw^Wgnnk|8ynDaw*S~Q5^KL_jH-{|`~Oc{pTD%P`}sa3XpwG@ z^@(lwKHM$Wx@(iCk@Krgd2jW?H$@+Q^S*w0xnC@xZ1*>FzmN0l7v9`l=lDyi*>-oC)hQvj z#4R5l^S=z|w|7|`u2b&0dZo>-XJw1G-e0p!U##{SNA&StiIu-k3aiIR$@DR(<=t4- zo~>k_!pfu|@PuVw^l#py1^vNQf!X^bT_>-b^JvAzNB;JTf(!rGeX~4u;!M!-aNYQ2 zd3P@FSZ7a3VJZ2>tJ+}~3gkY?SXS|TpBJ_xB;ozMyH|F4hl?-V z@nce8){F3}^nbg&kM%6fjW(NX_bNC(-rwktrt>zXU298cM&6t{abX&yEl=$z8)_RjEIPs{4lzB!-VRWmm+pP-6n6i-{-3I_bG8vRc%s6 z`uh2GUK@&^uj4D5G;O)fGN0XHri+$bR8bbaZg@l?eA`%f>)xVE z;dkoh=}%R>;vMm3?%id*uU|Ho-!J@=TPWRD#-?HE)jz*#AAbH)a;8f0y`cP){!$X_*2T$A zHmcu~U^mykyzdvk%oTx_!`?D8my4#o-WPrPAG7Sgd7nI<{Cu~1-M+SI^4^qcLDwLbOsUhLEPhq>qOdzf6Mzhc*_uIgCc z?!2gIkC(Mw4c_a+s%9JQS>v*@Tz>iz?Ni!U_N=c9II_j^`x)W=f!#}7)+klVMYOfE z^T}O`DUhr4TX^J%ik6m@vuv@IDOY%O@asw2_c5#vbl_)C*%$IGLtoN1?CU)Dg5+nL z{q2IBPoLwJh}2Q5f3#$}F8ASIycq&lYOB9rVE%sR2Gvd$Mlaynp$dYVxs5uh;*H)y;|ee|Njdw@V*;+e%U^ZeO>& z^E&O$8STQyns$ngrXqVdmwZw2_VQlg?8mqF`?c9ucKgT2sa*Zg`=m_P>O%kff1S&< zD!xt@J+w){OU&+NPU_c4VL5xy$Cp?cJ-xTOTe1_ zS6{7J-?lYs=NY~8X>l8?=e39FKYAGcGWFE`35nt#m5rvVXvZHt*)Hc|vc!Dp?!VRF zFXhYspBlfq^y`jK))g-dCMCWszhC3LHc5;zulM!k_48j{JSDK*eB;^Yp{L_NIW0OF zyzG+yyZQ#N$O`*8_Ulb=noEYaRiz#b?w_|;CMR{pkKeq~E7rW(qwHs-|LxU@L;C&B zPd{1jd%pjB-{}pTZR}M4#qN5x%6;3DK*h{A9iL74|5o4m^kSm^I`8Z2_OWD#N_;7Z zZsnh7E4bm5LEmztwn_0NJ>NRqHLmVlxyvixJM6_NgJqj1SH?#E)cU+Cc-=g=*%j|T z%r$?$>gwrDlfvdjix$4VxqExD$^7lEIqkgij;q7|M))n@GZBW z_gL=U^uJN>F77{i{)bmx@Vc4n!b0Lt7SG|f{}rGsb@};{)O}ZM^IwLleGb^NBdG4l ziJS3q-jk-D*kyg(`SxtHya(wC>6dEUbC+wzNxUK?&FK~GUxxC>bAR9 z|9h>_qj>v|Q@jGjx@>>O?=SO=sybp+qWkXid9hXYwhcV1?Y}SI|6=!?ds0`uOY6RP z+N5&SF?=sd{WwK$$HRxbr7w;;-!`iM{gD0hl@-m_-jZ_re(iew(zkAnrm^iL&d)~~0W`lUKiPD+Mj3oB#v*8+dh=@(umT@T-~l~rZQMI)xdjfNp{fj2ju=(zff zC86KUy^AH+IUa>I0*`bbAEL{$)`~S$Evtr4zvALW%H)xTHf`A0mujm6kXZD6V zpPFr+zwE}1h*w9o|CN-t-Iv)^@iD13{BId}yT;XN2TqGyi0MYTsQOCdkb#o?e3MU`;mC-Wc%e=tcOM@g zzpB1OuJ%h{)yJda(pP_r?6=wN-Y@s%$K!tUPtm)l?Z0?pe#NgBi~FZMh^v0P^~+)T ze-qyAdaZYLGJN4c+w^nY)h`ydhvfg57QH3B%G65$w*F4RgX4$pj>^hPlk972(pHzx zia#;;EPq6JNXUiAe@d=m_U22iUw-te`Rjc6k$U~lpFdx%=DSq=?(LU=O8dIWry7~r zzr6SX8O>*CT%h{k`-Dx~XLUXB@&}FeeQB2e)9`Nhd%H=Mv4yUG`p(MK#ZKQmS@nC- zo*D8U)1Til`dRF^>+;_(wfXx$JxsKCEue9j{l(g39=*<*DKdO44hjVt3P_d?n~0lPMw=>`ndUU zqe4Ku_>}kloGe)J?3rK)zJxA-J|X^ zW5JFdIonxfZ*RGJPuB~zjTL-u^6%Y}FI|^^2IqaUPCqB}wUo2+So!fj*}muH&Ad9N zxIvx#c^qs06m_cS|F}7!;r{9=dkrTX4btEHMd)tb@3&b~KTS|{&iM4?q*m1KvbR?j z+tvShEdTQ7^ZCnJ>b`HZVOz33YTDKF{x%<3?$&%hoAoa25@;>*b{*M&g@qfpRNmd* zS6iE`!d)BeeEIiJ=F9B0F|2ocC0;hH*vgq zu_+=tUngEKJuJ6x?I!cbe?Uvf_JY?dzG%PLm*3eN8(pL8@hl6p3O@brT%Ac;y1GlJ zaNmzC`7UlRm|UxI>#qE7Xs1p^R5T{2G92U$JH7A@ zNGk)AqboxbY@Qr6A2^kP#XLf{y$CXF#v;ndkryzNyA_hkIWR1~_2)6GV`w$V>I3>r zr~8Hf77Ab7DYbu*q5;PbUxkTRUp_qOGQI4B^{Q0m8?Rzdao6WXp3|7o%i;5PbFbFp z^w4$DE?@p;+AAwsaBP`yU;@t~*6^(cn_3q=j6Ef0#MZ^cbkONROzDOxB2Tw4Gwz<7 zKjZM$!;zgMqKdCt}LWc3)I50G2vuiKngLrM4I>W)OdpZLgz#eC`7HD{I z>tNRk$byE3r<@K2y7@{X0^mS9z{jGnqiloHE69LALM4+x%v~4XeM~OjOMZVzF+=TLFy~FuFprsMa|ka?bmB}`zOuzRgC&) z5@>m^YDx0OEBW757X6oVH0hBJdHP4{gll`}zm3f=4n(e-GzFey2XiT-)ReW*&pLw@?*~T9rqMs&RqY=WA~nIxp3^(3#KK0 zOc#0YcC0(AT2<0JZM|GlRQRI!4?E}0_Smw#1 zlRA?f-`~GJF2g1i`!TcGwrRK9vuSoqSj}hY&pWvNvup4%_48Ruf>+|gh3D#DIdbKu z$U~p3AA4(7bYR-9 z$F5QTR{wVhsX6d{Q;3MLXyK1rUiTj>EZNCYcRI;RX?Dg*!Mq7Y*Ni_`l&DU7vG1vi z;X{}8F>X^19r|@NaM8a^m-26lR!5qCNzI?X|C!qd5jo47MYE(2{z+SX@oi_Egm1~? z=l33)g?kHr>|g(AqKMu5qf>Y8<^EOgCh)i6w8SwceZN!7tOc(;chBT)F8?NY@-TD^ewvT5uCg3lfwj}tFZQnQNAIm<-PVdYY z(z?ITMbg$Xc3+^(OdA3AGTZWEZQIel(^k>Saxn9hqaH*fP_&0BEDV-81+?R}1~fBE+4^R95# zHmU!UFU=JD!%FhB($7S@?`>h(nft6et6gjEsk;ltPFdRdK7O0f-+AZ%&fr+|K2Kp+ zTdrP{_I~yo=Prw77P{uFe_XsocK-3d5p!I3%Vc-$h+#(VPB6*Y-{I&tC;)<{v91&ZgG9iOy3fu$npN|1RmB z=4UdyA8dPE>~UxQc7fVbpWENQ)EBT_+`;#%XlcJ?-M>gV)9x!Q`!_gcH`Ek6d9T)w zkAG}kl-}@q)5KOkH?AWuAAUDnu2|zg!R?IEy8TCr%c~;3Z~0wtYw`~}(estu#y>CL zomx{AA{j)CI=SuJT?e*^zZ=LB~kh87%UP33&h4rgAb36eXyKx z{Ns|IB0CxF%Wg(pKWFiW9$(>nT{e38*EH_!**ssat>u`tyZb43Y>Z*N!lRN#0mhPY zqxG83^G~0M_7&7E=Ui3hBCNO9T+>PJsCdtmmG8g0r0+PY*JNF=%xwMY z<1g!2;}7`1sOH^&SFK==^p;vd{kf6O9c^pN?r>+UTNlJX(|Ova^4)t1l^vyYYnN@V z^~*YZRkLXFo{9NK;y?S&&R-RjpQ+Q4U>;tknVn=U7Llf2ladj0swTx?Z!c#~$qrUgf_U~DhS$4et^I!RWxwE3J_NC_e zxYN&7%(?1n0}mH!t~YUslUcs;a_thGOC6F2pKmR$_&B}okpIlxCR}soR!4Y7zxnvx z`=_12y4F9D_5Y0cm;cuH`>$TxDJTDIPSdu(FCBZAw@fXXvia^3z3ZEEOTH_Z|B+9c z#?7C3__KLY?cBS6Wy-JYpVQxR?HlWzg`t^yw<)brH#0qR@KkT~osC~_t^Zsvs9BiW zdTafk>54Z!^4{*+{nxug?EIyF-|CkAJmvfU4yTe}h~%Mv&-(8){q0q&usj?o@_EP8 zGwQoICUShfbi8xl-__T4zqW6_d|`djy_o;}i_X^_eELM%Q)PRNtBHMmOY~j+>`Kq` z=Wd?-^J>@rZ1=J{k1fyq&+WT&`OVtS+=Jg^p4C5}eOG#xM*7F258o}RxpX?_uTA`o z{UxGh(>KJ#`Ir9vrth-6JX2@ipRHl(&wm`>m%O_mfAQhgT^{){cQ)p4jsLrU`KI}I zmVHeKwkljd@8+pPdJk0#Q&^mGv=SfOn&uE|JHNl?^7ZF2OQ%;BZo4KevR`Fev&GAs zFV{_x_UpXEF~!0{?g0aXLJ#OH0J#ko;`_7SMlf-&TD~Lte8%ThdxK0DPO91enC(F{dsG>-j40xm3|5S?-ck~Jn7l9dF_-ma{dR%BeV;YgJ&F7E{EletT!# zHYe*MQ}b`Li>q$cKiZPo5mPnmvHhh>cCn5odsmAEvwRVGe}BV_^$)*ywqyst+r&5P zhL>~7k(zbCr{Aea7yNhjL)$NpJ@-G^*6A+enR)6$X4X12j-rsh&J`!` zuav!YAwOo9Se%PTRmLN(AKR7Z-)Y~U`0+Wn%Ms_Qys8M@Dc}DaEz#D~Y82mCu-?cf z=Jxq__YLOgx~KezXnA!aDpw<>&-1ZE)qGFc%8X32_zdxPGD>fhGR|K8$`fC6PH*OA ziH{D>e|py!IyW6o;eYb!L*%VK)^I7EUjaMht_R=z{;_wJ`DgJ)-;{4xYaUN|m@Zj2 zect9Bht}TG|0nJ2Am(m+Qc3x6*Z;%4e(BF^{#NXqGH3D1x6dAR1;n0wKIu>B6#?5# zZPIzYN!$M%P;TBj@6Bp!>9+i(=IVP(GE+i6tmjzDv;5SdjepanKTTpy+E}Bf|1djV zzO1%Dl{<~goJBvzJpXN?quyn)$)5T3cI~mpzw;Lw$>{M;UwEdZytB+FpTk2krEwZh zsQL3RTdGyEov*OYIUie-+p+r5?^7Cj#m`-GZ^TvYGE&!lw|cRSRLR4Ci)AnVJAI|W zLUTIL?bGvlUZ4K6yT`3V*!m^!Jbg>qnd;Lu*>~%zUCw&_*M7GAy4OqZFwI`Wxt7B< z*e`y8^5=!Sy3b!|@w;FCZ|cu`3(K>Zc03H#jWL=3;*pC->2m(~Zi~(bo!ZuG|DO8a z#VtPV-r>9t7pwMfT7SOq)Ld7VoAKhO#rIf9*7fcSV3W*RyJy1oXSWUFwLf2Y=f_h2 z{}Q+RP8p@VN3&M1es=pqyc_qN$KL;xt{H7v)7JLWZS(8NZ6AJ3TfXV^oDCl)-&=b| z^|VIwmjc%U*Bz&SvXxHD7brL;FyZHJ%g3gMla2=c+B5&3cGDv3ofl6}*!*t!_mrdi zKerYKwK?#=#Kc1bI-IIUbOv?Lva*^iCtDbw@`l44i*PmfJ zD*kuccIm3lO^YJue0f%)?tJo*SAXGo6W`m@oj3|0$`v*S1^g zneo!;I!RNXTuGX?t80VT-cofYHNQ(Y{FWxj`&HuAe z>!ZJ=a@@UJskOUhs@x76cO5@Bwv>p-XPcLPugh3kCiDOHJcsH$hjV*lX1DK|DxLI6 zqxW5kN9Y}eybWIZT4qhTI@h`8I~OgUK5wPXw#C+*>VBMuT0gH{xkJdUD%NOwnWZr%yckF*$YJqmRoC_bhApJnP)`ex8}>F#_J{ij)3)4Lxn7 zqSNouxqGkr`r-#h_2+mU(wCcyuvryeXrELbw?o{sV&?O!b9I^~&0DO#aq5OD%aq2e zXH=tdA|q6bA1t4_-)5O==1V`ZDW*@q7@f*0xw~(ZuJilqxo_@<+zGHf*5Q18>9bE< z`{gqa_x$>>X3;_Qo;8=I&I_EraaP7DgUx65o^q0_Obc%dOsxodwA1?K#MG}l3#J?m zkK<8%$Fp4V@RCc}(q;YEnx{;?bSZhtmsG{cHo|v)N1a=|_uAtriZOz6?)qWgt9<`^ z|I)gjy`%Jux%tbvUj6Y^Gup#UQ&jgpKQ#B&<~^T$*7JNUlf3@m{T@~AIks1?TILkr zR(iL|E1D(f*~-~brf*liiN1fe?WSu%_769u;$umhquz0HWS_Zj=Dx4=_~MxxJJ#B0 zZJyEUl6UVHZ%mu}Q#XC{(#Qu_bUmflO*v{U6n5v4@~zDqijQqR`$J~Jz4>R9PX(+# zV{IlLe&qT0=^NJmwAou{xIX1scKE!xQ(axEy+beQ{xYAkzSF+%nwZqf)X6Pbkumm` zC$e?@vYt-8dc~-uF57?Yc0K2f=iVvAKUcc3=~cv`Qvz>f_inY=6m|1vXN32z#kU0a z)@a7F%Y=!=%uSR#l&>(|bB+$rziG?+tm*Wn)%b?X_v09pVX0_D0;B_;q0b6Z}!h$t;=$1uaERD+kdv_x9b)6EzR||xy$>fao^Fk zKf||*9&fHca(GtFqEj{Ln(b)gvB&IFQ6x?x_d#n3Gm9UrmvpINflY`qSX&Lf?} zcQ<9-zI*ajmVarf{^aVKo8lM64^DLrIp_DRO{LyHb@~UTO-4=%wy}FJ7G*8}_G0S# z;;-j^Cf&AXl)N-WF}Cnm&8ltJKUkdC58G(br}WE^+fVoQN8^3>zUjmpg419ld@?`1NeDx$}$nE_K)Go`0m1 z;q=CLF?ofbCJEd*U-m)kpc(T~5x9ZJ+sc;*$R|>yA#CdUyTjpZDez`~AKj zCiJ)Q^0ediPyD5fH-~*TJ#_slceKgFJ*$jwtF=onf4ENb)K>NLlH&8Oi)EiQK2u)E z?)+^1(&hjDTgVn(`cPQ*Yu|Rc9mO)cb3g0u-?%#c`i~V~`*r?Q-ku&<toB56JEjHQe>& zU6S@sOMRBC%zv9WR(DqSC|mA5{@NnpQX9|XUyuGIK3KbM-;?Lw67i?sc}H<1^D#<> z<(~8Ozc~4`$n{{G#eZCu)CfkO+<(RU?wr#vblT1x|C(F5ZRQ-7VEcEc^Mf=0Z&`09 zuBX4}#Q|mBO$@L4Z7yA#bHmH-T=(vpljb3Z9SWSUep&&VgS;SQagJdVe}(ZF!Nm6-{~Y52&Zu;ZAq8+5Qsp+QdX9C&RT1EYXJGegym zv;a3b$UvB)KSPuBr{xR`kWsT4p!J7rsZStd?E;@za=yysY3wi3e{w#B!JxIFMn#T~ z<&09o_RnX-nzFBXHqEl)aIgzmSi6Uzc!!0w0|R7?jfF`dMp!|a8{}mMMuCP0h~?FeRf899YN>eC+mGCDQk#X~7qv6qmAfej79j2!EP zd2(RfKo*4^ZWCR1LBd(#feS;^YZm6&P;P<-EQ-pUoL7re|d0v`Dz2@sy|cON`D(ZUBbV7ullqLvuyP*txKM-wSUJ7 zlU<2V>^0W^6%`Q_b8Yuqzwl@F`-R5Ozgu4_zb|p)r`jy5FO}a9XVrgPc5}kEQKavHrWrK6v{Z@67KX&u9Ga zT>tWsoc+SpZ1#%}m3T;dUGJ}$DU`H1`J{dTSQWD`Jd%{)p49ZUv93R za^qWudE@8G!>YC4=Qc0jx3KqT{*FJb?e0NYPU)-GSh|PvRdu<2|7XelFfnR-Jzwc0 z8~6R5hJl*8=PvK%*;N0%MSq9hywkTrY-Bd`Gkz(!IW1AdRd|>F(lsrGcbL{LdYo>* zaM!OaaqaeY*ULxe#x4Bu;@lL8yJsJoFZuiVise%`tKfa}qF*n)qF2Zid+8-_)UNs- z<(}oeTXuA>$p4lsA}8j!apK#M3s-I|)On?U`Q|Cxk{wTM#cr?GFite7-LhEu>b2>? z*`KeRHr{tzJS41k#=cwiGwV3^D_qE85){06$2ivO{`38=+xu$otJ=PN`gH4jm;3U6 z)c1Zrn|td0a^dNL_vgG6k)G;xxF|pT_`k1j_ip+BB-~`#_roP;H`oWn?e5(2`G&g5 ziqmKB2;XzAkF<$t-97VYMaH|eQ>I<$y*$G$U7Kr4K=*UkyYC;pHjVunW`FK8&~Z&!MSzRzw`>{VpMO?{VHbdG3lD+uqlo-+wv#Zhyf4bJvR_ z7ipO8Grr$)=*8+>{~#wHvFnecvgTVg_)W=K%*!4Z{$0h>T6-n`*S98fg_1XA`X7A0 z<^7THS9YpCzsq;c^P86Q{MezRF>Ng0{x|i_y?G#Yf2+}?PazdAcV54G-6N=gQHkMT z>W7_~+qE~I)vuatCRg9FD(k$7k^B8MH>XHhFSz(oZ>70*;-94TWy}&cU;6sJ5A*7H z|EY@a@);*`v@E_`&b9e2%D*Cf^}NkXLZf!hz4Tb`nY16%?|Mhqr_w9DPwCbi zKJmDy#!vm6?!yl|7&T^?{Zh9L{+XR+x8+5R-QJy#*t9h6y;)Hh5n=J&#QW!aovASb z8_G2QzC3U;b;`^u-mR-wu2qn{C2D9{^vl})j&tkksSlPNDGjoH`esU<*M!MQw=efh zTwf%meWhTlGE+WJ%0)l#7hdvf>nEJwZ&fwD)n3WQt8*>a@ki?Gw!G;$ZWH`?_YRJA zJd6J)y%L*R=9??p`}VUz_jj{dyKAg^pSCq~y7e#bzIMsu6P6;Pf~!AS9Zb?Z ze8YbBp0-QE(o$b8bxiniceDBh+3B^XZ2v~+rK|S7w(hQelfTlfd&4ZNFP2mL{`tG? zU9>BLcj9S7&C{FS?k|?Sb^Y+8>o!aRF=@I^8h%wJI{&-kn-)deNuv?fItNJ(H5Q%=U||WsP5O_PM0|-J`Ar z%7-4kTs1E`f?@Znu%h>8+NWl$v#^-!`Yq8ve&s@{<`R-S2k#_JrS{Ay_ zvobrT>dU2$h?5^T3#(n&amT+>PIubQ(4hHiBB#WE5nF3pG&{*;N%L!72baCO*3FQX z$y_yS(*M3g_b)zcYTIeM_ur4L`i;MSMIFDh;!07(c54muY@PF$|Mebu|ND=5rqBBJ z5dPv<7w&I9a3rAaq1L;%dW)a@kYRPJ+ObPJJy1|wRMP$PwR@iSyOVgi-^!@wT{V6B zFMb)bRpA-3PjdJ%(ZTt88Qk&q?Ppg!wYHym%d;YI4 zWku|fZ_Qin7y7c_Up8Csr~RwzFRiYAo~~GtIbqM9FF{u$c4q%cnzZv}|IUjGcJs17 zE4s5g^nA^;8Rb9jiFnul*{PUQ)A(zM-P>i+(*_x6X6rphg{koU}vD*OLT@s89f(+lOfziPd6 z)C=Al#Cbhr-n-A|WGAl=OWOVV3b#pqw9H$(uj=nsehXjp{o*+pIX}B2P5b7gL>~!= z3C$JMy=y+r?!NUDwr&6ORkz)j{mFUu_N)`OUn_0)*tVXYa7vkJdQt7UOX9!XF8q0` z8MAGDWyW8%tIgq@ANMo67Qfu98@T1y1^$X7J-@AW&dq=O&j0_dc_%C7Lmz(K@PpTu zDb~pSa_QmtC5JA>e!2O*UyH%WMoN6H*CppEt|4E)ew}h=(R7K`zS}Dnl}r&&*S-DG z`qd0G7tZTRa&C6DdF#EW%zLY@UH{TI?Bk!cnqLm;3MeFI(*TdUo&b-#?z0e7K@@RbiTI%A=x7?H8vgp8xcr zNX@)Kd1ZS0$t@+X^I!g-7VB$!EB4&y1NnhTG1YlJE~^zYY(M6@ixvDc-SYJVdq{Zr z>bA}PMKe#W@+)4P%6dMs{A%+fbI=~xKN1aJ>|8a(-%5IX-oA7rhu+d}p5dD+Qa%;D zYn~!#KdCyYf3t_om(xD3PhV%Ke}8o8QJcoYTZb~|tezz8Ai=Ntzxn8nzJ1oeg2e@= z^9WTM28Xz;+Qo4`EYp1Mjum`;mT~diihHkA?PDzQ-aWbP^PCM=UN`5SwApg|53fU8 zmH*VWkGQvYy4*|GxLi-pC-n+JKPMxuH)weCLUaGr1WLvPAYwP_tPwKur_O=f@yd!_z zo{Nfgi>v?65!Y7zDD&3!%kuMV7k_8JOZfQa+~H%}153|VwtAjzjboU0u6X++t<~pO z#YbLUvwN>i|I2rJZ+~mVhhN=N_5J^@ijzC5fA6RdJpN_j7tQZ}t_zO*oV0x21y^ea4>%J%X67m!Dqr@-TC6$ulu~=w z{f9^Wg;y4T^1XAqI!M;LS9XPq_p^k>kApG;ey3-aKa`&`pXcl=y@!XIv|j%0oLqUT z?&fCwoNRLj!2@erHm>@5Z+iRGWTh>kbBtJYyEk8oe6Uz)QpUx1jUhohrxpd*yC_@l z_lv!p_xRq2)mpm#m8%&3_`lk$^It2j_HT#RV)tLRAu;=A?z1Y`DP(IKQ@sD9jgFq) zWbw%_*X>AJE#>z9Sn&bn3c<+AuZC8!-*mrEn7yB|^Q`Kq=(Kks`)7LEzN|@A zlYOL$ir=%kRMpR=hyO48_Vj+QP5bZd`fjU>{l67o(tE@jEqwLP^4Cer4dnLK#{R6` z`BqcxvAt)((>+gDwoi_aTrlOd^M0c(v9ZB!*W><}OP%SL`g(Gwn{M5uLs_2>pZoab z?V{qJB9mvWnK9?_(fCIxe9=|E?DuCazBS#g<4eSHp2|M?)lw__9>#wVXn3&c#^HD95TS$O#BzBfl)QdU%6b*Wq95w+s^>d&DPGlRvZ zi`<>8mCbGYY$a3NkLxqVHBMew&y#!oL(P{Def5j=R&M{Gv?}|`BXv%-?!~i;pRfL; zX=FBYn(PjzjS~twFYetjecx=g=b7dWuGMUsALZ`+vosaD5EEs=$K>R&ZvO6woTn3I zB$;yO8wLFBoX@jX?ul!_Cyfhd4Bvm!x}%@zaed~aqfMsaf4$}??lj){{fFk<^%kCc zEAM@|F|+s8&1B=XK zcRgSItysUX$x7$&ve@ACRq3hP+5W4Zr*@w*U-k2%qU^r~Vm7&2GuE~xrzQrzUjz16 zoamo)_f4N_-iz+B$YhtlU;WJ0bk3ZEtGnDw>!v@C*q<`-N}kovqqlsI2hZzssZ=(y znOBwe$458GD&&*i`Wk$7yov?%TdwUR|9@d;M@P4?LeiU^KQl${br_KJnT->8f>zb@1AkOWzy6m zkA8h_QuulKZusqa%k;PXSw8Fi^yz6|URq48-fumnK~5uPSySz|zsggl%~<{CNrO&W z)%@xypCT?~#4S)+UHep3YSRs`FlB$KAJS2~zpGwtm}>HL=lx{YsO0eT;VnKf7VD?& zt2^TTD{<;Jj=bVZE2g*`H%@Txv-nGy-VlHqn{e{mfJ=A z@xK+aVC$EsPoR?$p>!xZ!22^v-|I?JLLW6plqFcrOpYXE3v`lec^ih z&wP}B+U6oJHSsgo(ob61kvyuOZ(lP0|Lw%xI|?Vm&ztI>pTA5ldD4+}@5|es7d`(x z=c}z&?!&vLU(MnQrmp$+_hlZ+@=q$;gu=vZPo8?TY|c!l+adof*g%UX4>~dQ zv$A$C4e%2Hjiog%P-8gAoAr6&2gq>MK_`YLX`N|KmXO7CO|uwS%vYRkhn_so!p+E$ zw;_V-DRcvE7L&l81!nSG{2-GR1aw#wb{tI7oFWV!=~Gw%T7r11MgwxHy~759h6ilO z7AKqzw`SYw8c+dt31hV2h4{A}a_iQf={f}&ql}o!z;b=nG{>Eg0l^&5P?>h|A|r@X z!&Dg#Ze5icpa;|5@Zi>|IV*U;18WVToDKzRvm~cLPAWPO20B*8NL`B=?9zl#CV`mM zQEX44r!$H&a;#f>rjypzLY5VRNkyLr|CtwXvR(KXHs3=9m6#X;^)4C~IxykuZt zn2;Lbnda-upvAzzz`?-A$i~17Qo_K*z`!U3Wiv7`FiJ77g2fpa!WgCD>^MdZs2U~) zhW1Pb7O0vu1`y-_|A!2$p`naWnt^!%BUCjb1H%F)m}er{{GxPyLrY6beFGzXBO~3Slr-Jq%Dj@q3f;V7 zWr!g#b6ir3lZ!G7N;32F6hP)CCgqow*eWT3EK-00h&xL%(-1c06+^w1oS&-?lF>KR zGth^d4Kf}iYUN*)nVMIU2r}Q!&<3m$MGRq&4Oo3ZMt(_tZfZ$UX0m5qNor9+Q7Tlo z5mYyB73gLKr55Msl!B}d&C4vYgBgG(jIPT$KewPLwYWGlKhMq-YA3Q7RK1NpD7cV< z4-z+E(I6K$J1!f2a4dpi)Q;^5-b`u%1v)r?C5rv z;b>q0qlS8xMHU`?8UHsant}xwI2s&+ISxE9YnA#0Q!}3>q2Mn|+Y_ic7ets0cK9xA zvw`v-s545$*f%O#LJcr!W#GvRUZKbj<^S+xV7u<0;K2uVh_50;^KFr=6Ub-K)rb%sl zvR<{nz7%@x&beu%rK7Xt%o!gk^E{c<)Kp8^<9?Spa_;PyC?qVrGJ1QSA8W;<*sw4+ zZZVw&$;bNwpP!pM)h;P1>CI2ur(4wzwFx(V`cxFPDTT9F&Nk|$v;B_5!)&+qRBqn4 zy3V~v!co?`EadjQb<+7&MOr3Ji3!@yGDc*450? z`-E=ntv28L@tCyA{$KYmE_M(7_V)Jn%l`Ghf^Tihm7Z%=+O^Do{<=K7s+-2?=aw9o zub-2Zm6dUEk!#8Cx7&jY3pdtD?5`8j(9~QQxjF6Pm6gGnx3*+%DSaKbT*&65nCzX} z?{`hg-^FzG_AV8VubDWn;t^+coqy%q&JBs`8?vwKRlQodJmb_9&8}ou*Vex?a%#Ta zO#kxp`TX1KC3lvcn{U7VQpK*kJugqLoWybO=ZnStFRt(Zw{_Qi8Ox%Ux-X06H6Lqx z>@nogtp6D$z{FwV_TX{9{kFT+@Au~MZ#LZe_aT4%2Knmmcgu6j?^Q0p^;~*F?xiK3 zW^#XT^?&BQ|LxiA{9E5QK9p~iwJy8y@6U7l+ZA6@9-r&Zy|<_G8`GYT&n~Wh+oip3 zLuhE|N}J>T^4ojm?eCTS_>eez`<`!J8xqwOo?DgI7rtr0TXsi`k z6QMDtkF2ZXYdg*S5@=BlA^#ooRlhbVwV=u6Mg$Pg%aO^!2s8%sDod zK_91TO77&7X%;U*YkPR8HZXp%Xn_yycrT3yY|~&LmsjEGY@ZF zZRU;V>^L~JQmAn5$vqy|*Tqhqy(9JXw326MB(tuso4a?#l`A2p)3wbd-hB*qa$-8! zx`5qMPu<$-0cXWy-CbF?x2+96x`@AXdi;x1oW7gOpX~a1I{x3HJ15?RF34WLcUs-I z>0l*~XgB`*I~`p-zxPNy(O3#@A;nzji-zROh<}=RFCwZhM|}>lFX|@@cr+cV&Nl zy_8*z#m3(g<*MHpZtZyWY<9ld%S@}bUGMdTt4pugbnRQed?NQz)BZZ1{b!XGK8MY# z;4Z)ZcoToDX@7O{&eXk5b#?nbX|0La*d$l=LeW&~-09QV1-vh+1Y;{M1t*ufR{b$P zZ?o8H^7Qz+olXyX7rwSVq4BRk)BV@Xn=RkEr7O?Rmy2n#h9!Pk3dvoq8QW4tm_O#w^AK&FC zvR)EqR1na#dR@%=*~h+!SiD>le5wBb@A$15pZEQKx7qyE<(+z+O-JR~uCEiy z`QeptZjR-W^{(LeyE6T5L2VdskJaaEpY@1N>*nfF-6x@^rU zecSK+_J0D-p6*JVdR)P+PiAG`NtyLMeesn~MNRuv&-dot+;sHcpLOS%6c+lk?D;q? z-Qnp+-HQ`@7A#R#ovVCt;`TjuoDD8zOrO^5j1m8oF=0pN{=eU%zm|VID!$re-a2Xj zs!ibyykCDTv{CxL-2U%MNA-KshZ8>b7cEz}Q_OkyNRXY$$w5qF&xb?YThh)-S(U$& z;gv9GkgNIN=;iMpZk|^uR`~JJQI*e|ZL7a6x&QCm_E&Ctm8q<6l>2QKxt%b|SL&9^ z+x^zevgLvgQ~8}jcHcP`6V?3Z<>;T3e*g3H^UI&l+pmAd85|V!;@|K0%N?89R{pv7 z>6Z4vHetp}wvc(<)A)Sc+}i%$*j4)ait*)7d)C=3*3Nw5-&9gz14`2=>lF@}@B6;@ z{mS26cgkg&@6?P(?9#qvYX6Pd`+#u%%lOlU?vEct>|Va7@8yQK(u{?7Pn$k|cjtS_-HOYT^S8Q} zY31|uKH_hdzWH1>iXU8u38*mbI#?=K&AzfI1Xim}bYoyMzhu()tqEMMwX`(6jIU{2 zKegq_9*3onnv+p2;gz7?zA&ML+{G3G42%K{jS~b7)*hUCHEDDD`DN^K6%9YKjlbL} zKEE=&^rZ284v01dfjkzU?1GP5Cly#vRnQ05vJL7?%S?Cl*1mL!+tmQ6?irXKx*gck zy=+hI%OkQc_5RK9^a?yF~wB z&!^p|cxwgb_wTTaIp4i3?)?tCGo}B1{d^Xr{9DjI@!*#HS+{nTYTvE>e)pB@6)T3y z`uB~@>@Oa+%U@eOr|$mDzj|M#jjm|&Sua#B_;SH9>+ZIHw|6X@%wo#T_~LNPbH*=; zdbKI3%Yw_&{;sxQ)|~q?zUJbT^;5q*&EKLlqupWkwY6uJc~lf%9F9>3t7UPPx_s`T z+0$&*o0gUb6WXk5R3@Bx@8xE|&-mi7%`O4Y1^mS?l_f6Cxc0#7@pAw9evhK|J#3TC zIMyRs^7U%?3~XD*an!0-I=SL~0@$NO{x zzV1$F=UHa9W7nKdb3<9cG0rH!kw6wHrWR5OO5N@z*^1V}Bd!aqu zF3cuNvpL(9b)hdL*<4d#XwK%fT_g(Os;M(HXBV+L+CZFcb0}BW>aIlG|GlI=$;9zNN zSjv+(dt0TWLz`BO>V#>0(>JYO(=?Iq7YAGF{nrh4HR-8Sr%W^2VO#ZWQ&*hM#lANR zXF4O8LMBKt*0OMJ>A&hAZ`ZUbz{p!NhWq7FAz#b7H!DSQ* zG=iKUvs3iVoo%K?()ov`ImS0(|7#pjU*2mt4vuU4o6@yq?8NLXLoUsdMs{PS(%7{}pwP3n_WRB#~h=qzvRhNck zw58r+sGZ?G^+Nm3FM>RoI;jPQ3%HJHHd}#0fPrO}(}5ti?V1b|*ug=>+Oov9O7j0lX^A@u8bYDa7C!@z z-Z@5SAaF1-dQ0B<(egtlP)BF)M^nv9tc?s`1X)hhg)r9sU_7nlx%kf3=KCKd zr|BQGEnL>&CqBRUy2_E(1_zRt;hD34bC@=(nCgwn$P2@A`k3&YZ^Qq!e2 zUoh@!4#`?6m=`=1y^7RdQ8)PG5lRu`+McBXWKlVEs|5bXqFq1KXqBe zBH0V=JFjrm&hVCheN6(C)MAQX-U+%iNB7uql`~5MUL5whr2r~U`WG1=yT6`*D~)#i z{{Gfj{4U4zWve!69pap^`sW4qFNu0g6V-c{^1NFoYpvwptd>`pn!2=eX}8TqP+>0v za(a_u?^2#TgNB8C(1e}A#VB!SS%9+~l>cEe1JAno2PVjn7rtHQF zEo2;6n!7hcN=F8kCI?X2;9OTHFkvBAJSWRx*T<`MJlt7oXS~*F0L6BKhp=>yS5v6_ z^d=^&&=RwVs|)4ySsr!Wx^Qr(XGnDB%DTDJ!)AXkC;o5*0-mNl` zJ|};Q3SRqlB4^!Fp1hP*7xt{R`;jSgb&ik0`i2QSEKYt3)BN;LCp1^vJelOOi-G;y z`{i%W>}yMEIA|)8pCTR?8Rcu(v!KiRle&=dY}P1#rgbburz#sx^RZVn#GGtNtAGCO zt;q&?p1h0~i?1~ZTAV!gZ6hP2HXmzagDS_LG~2-0M&2f@y&onrs9mpNX-$Fp|AGwD zv?9&v)25lVvwmWm<)Hk!m~GkI<D=CtPZ^K6l)9{jplrou1S_~b=YYR>lSK712dR*11Qxi5%5^LvWSU9$?&MQWFY z4#=#_3}rqDDYMtOFtAsxblLhcG3E=4{p6MY<5~GF67=?5L|P z`x6WeE%qLY@6KT4aA9lYleLz*7jQ?A*Ij0(=#e7{f;CUF+-24NKj2oYd5GY;5zYQ5I0W|JwzkE&x<=we!mJZJpKO z5EC<}b4jBH$PofjOw){ZEOhO>70Y?$+O=J7iSnQn?&G;YhXYhQm@a*_RxzZ~((YR( zukRvJg@jtB_|M1ld-x1?xCy)c1R24=q;P;Gp`cI-T0b}la2$BR#%Qz(VlxAya~x~Q zuP>QVI|>#G-~IOX_T?3Ui$m_*+gqLa^3u|f$VgA;cD|){wZANu#%{}z6crN-N=sAg zl{W9&v}x0vKJ#sxi;fm)y?7ZDmYgY=Z^Ib9_UsR@0A^4f*uu%^%=7Nu-Q6#H&F?Kp zJluBE@I`+|&i#FJm-)_iYi8qJ^yN#*EW28(zt7C~FTA+eef1X5u*vp&Ro&}$z0!)> zk|DVF@3-4uKAqMNc5`dnyXKggm$#R+b;}O{fe$Hpt5+v!Zhxk)IDsp)$)SKV-LX&i ziqG3_NjS)~>*FzL=_#!pA5;TEgT3bG{C53e#xSY5p`S&qbpG39FO|(!jLy#r{O4M^ z?%cUEBreWR-EU4olE&iua<)}B9#?&T=Ue^lP2lh2eX@%uO%i%_Z}0BE73<^nzB&GO z;tgnkHyS7>oZtxOd3S26cIK%mnjv9fZm~bLdHU`DS!~U@IqBRSOXs(@wr)=L^7Rc> zjyBxl>gqaW!UTt#H*fkKKkA_ji$@D#gCh_6F^wsUh_T-^hY_x;?`cUnWgcwVy@zoTzyZ*bL3>J=Zf?nJWaD*U z;b>@>>!8VRCi6b}VNq@L+d5JC{6DKRcnx;HlmfhgvvS9XmN$J=oEa@owewxvzG({QJ;uA9DQ3 ze4FXJOJ9fWLhBN}J-$)UjzvrBfj^&ou49luM-J2MiiY$OgCoz?^&b6xzdwGhotXH> zGv{A9is_&Hyz~3ra`}@?s@H!;&ip)8@ZHVL>6)$2%}T zo^_F?$&5Qcd}QL*5cFkeR7S-TH%J zZ(~KE2}gs&48aXk4sLz;PcCh_{1H~rz{Ls01kGk?%PePaN3a(U^)m3}?a1W$)C3N` z7F9-xI~zizTiC#1&0)@Du;bw}!xP-#=BL0kmV|=CLAehVOMFcH)_=GlvV?_EAY*d+ zpX2!j?nf%qBpPSjh&X)8?I0-X1U#5veHMo-o>WNuG&m@;Bos(9HfKPaa~vw5MDU~K zhr=ev$g?T}qM}#N2u+X$Refum4+OE5A6aqn+QlB$C?Rq2^v19SoM59RKy{@=AnUUw z93h%!d$NrKGy?fJ8X69=tXj2-XC34G=f*MxD&YZPVPYrGy5DwWU^&!rVAIiV-s#tZ zlw%HOE@ZOje2^_v$K+fjz|bfl$kFD`$7b$w%5^Kqcm}44t_*DEo4)j3g9b}S!&07i zx2~>sZV|k?OF7{%`-{7Yjxrn#4lP0(rX1AO)9MN^owfPqjDx1j;}k?W8XPh}Nu`ZV zF$)yxps;+;l2EYM*a_Ni7sxPUl(>_o?7|4KPvOB_2A*~0ZXS%_fM#GitH#iLJEuis zfg#h66365e0e&Wh1T&_OACJ}lVPm_V6SaMUO`)SjqizegFC(J>hhn4PVsM`$k3+O) z6(nxYI4VehTMq5(6j?z@uc6^6=Ya=NF$XiC;{}!=SMu$8z*HR2D$>PZ=g=?A2nzXE zptf3CO3Ib(Jkg5k0zH-!CzuN{ff8IpKPa`;<`_?6?R0RhtelYLWD4@a1sf)4ui?(K zmmE871y-zF`>{Zz9n|sqIFFN36u8SS7D{#X0^ zjI-FJ3B2-0jz)sZf-+D}XT& zyTi3;Q9+gKx^EYY1UU4WBxlZSstheWz$HWmB5Scb@8hAitB7>d7du0t3W=4Sy z7EsV?PuK5fncM0so&AyV*M^ItEUb(I2J;%0@~r!~1JbfBkKXP3oj1$6T<_?yW0$)1_j&l+d~C7ZzkJU(7epIV z<-zuYwna}kWbNzbq@9`J7#k}mvTn_qB{w&xUuNdFaVWo6sc!rIPVtp(xzVPJM9s9r z*DY~w=eu}Xf4|T6yJgaQKOExzay2}D;*^)V`4XF2Pe2`H51;w?A9ydgZn>DKsA!;*6H{t>`t8X}mo2+A(>VRg zzCWirt{c8MzV~VAnaelIGCebs+XdvAm<+ZnHuPyZGO+k~D=c6Of0hv&UnU?c>-+1m z;-}YDG2e2{X3zRuYWr-)^(`!l60l_I08$&K6CN6B8LF-K?8%c9QT5}g>#iA2`Lx;J z)6+9+>*nQq`YJc@Leud>H-!ak=H}+%y&?YdY%-s3sQq2GyF0S)bd$F29Q*oteDZc{ z`l?T_etr-#n$N(|qRhBo+_y3-<@7XNPchHEpH69)T#qfEs59x-rc~~`HJ{IF-R=-n zzH;ixdHer!-1_Bwi=UlYD5e{=!e-NiQ^9fmUtb-6;>zv4|A){0t^dnjT$%ak@#D9@ zH%+{~N_4JOWfR}K`_D!6ySHnd(w_4uWx48k@9k$+&7VDO$CN7~|Gby-W`~_#XS<<& z4y=)0S-0D{PQBXdW=B`wqCVNrnX=OZpb4xf?`ldsfO9KOk zg|J4d{({G~+A-_$SKnR#=y7ko=-S)cPk)}Xs(WRDo#U6i*6(&StNG3Gn5^!9ZLvp~ zjQyt*$|YZ31e%sxr=Ak|$}wSH!oNR1zx?@pes!|upN);b-|wH##w)diuln@r=@)Oj zKe;H$Dzs$V#={-_Mvcw?Go3}%lV5rWU6g0L68_KWeC!pYH0!zR3+vi;+p%tQIAFyR zlw5V;<*dAt#gK!N~9;!CY?OF)a>zP_Y!vW!^rYO-HA2 zZGQJ%T^|NtW>9mj3MBRQ>>)8|lAh7cz_V`W7sgCby~@C%x!g{IuLHLV8cPv>2^A*y){LG z;6}iqMu++T{_=o0X)|{KR@8heARrQ_;H9mi-JM zzXhaM2+Sz8XwN&@y=X~B`7;ZfTMU|x2g0GFN88q)oOtdKXy|uM%x1IPyE{Xow(DM9 z^T<&TFAa64;MPZS4A?2Y>)D-Tqz!$tD2^FX2Il3lRi(G z)3meL_=Qu7K<$!k9?PaFcb`=fdSWmGRG;>`2XQ=8447Fr<5q0(9UCUs9V*`YfAqM; z8rdDvoU#1pqJFsx?Uf=zES?5mIG9pGU@bv|9Tx16=yg!wU`Z%wW{?bpG@%;M#{VVm zC^)!5r;QXCn!Ae`Ky5h(29_oV1~zk!3Cdf$w)FIP-X<*o4w=c@9%GoH>ZH&;J;&kgv5Q_IU+)~B_2ei=;9TG)T$ zayz8ie|G6Xj_J$RtkD4vWV3%yZpl{bb&yZHMCW9T%u5d4b_I@Q8C1ScYMb0vU+qDLuHC@H8jtT`GJ@VjlOI-CcnJ*_WF8XwPck}=Gqxvw-4@!-x+GT|FN--y~FBm^paL>OsB_-v@Oy-llDibEm$VmC9aoe9M^X1FB zXAVWmoDTACmrT=d7HG~6)}O$IFG##Swq_o#^4@Y-tJk9F$Ar*XNu6a5^3Q@E?=n4B ze@~R{dW_ZfDJJRNA9uPKYi`-I=8n%JmpwWlS2ThrDRfc`zQ4bnuE*=P!z6TSsG#40 zn6vi9zozVD=_<%v(0{_3Q75&a{Ot|FN-2}VZf$LCU!B+|on^0%be_oG(izQDJ0rr9 ztusxtIa@$k1lF^Fb=j^zX3_>w(Rfc1+5=eMB_GDE0Z#gkBSNtW=s)jiV93k zW?9gG>_m%N-GvE?ZQ(qSXj9PCv;@zQ9zXJ+$b53t0)FGnW({TI%LR=(rL1Kq&YR0f zXnmOLVBnWh`8kc zz5d%pm4#RiHGq3B(}f`Q$iaJet(CWbRLlAKGWdtwI?k(16MdW#o_~AW=AES3932&v zWnmEVz`F5P)a>`26E77o{jl2z?qOA^facPReirrj9zFO#NW+<3W5DJce|Cre?9hcwZKY88WdEegO^_IT2 zeyQ|+>#2`~h30(P^ZD5S6~1wDy;8-7d%w*OKM@xFx+JD--R_5KUY@>NkIUcK-oNkH zpWxqhMP6E8r41(RDtYU5@!~Cstgq(UFE1QqF8Nv-oN@P6=$6dKY`b2~dcDH+^t5j^ z@@Hpzi;6y7^=E1KzD2gXrPl3~uz14s>hk*ilX6d7NW8K*JiofmUwW#j=$C8%;}&zb z#okajpS`}wIycIC@}$Wt!{^ssS?kWX$?J=P%@cb|%nGYg+!F&-ZHE@72^!^AeYz@6h?@RnX7d z+e*3r=Wcy}{P^+JpTcyay`G<+AH1F?W@8Cw?wt+yR`xZsf4e+=eyvksVWHN)*H2Hs z`0?@ax1ukfV#A&0*wuC|d81*rZqhTJ_x8WfT>f%9{_mu&?yXZ_{I2+w@OD+`syj^Y zG;$*L_uX4HIacZV`dDZAz4p_KqPK=+mgU@cYn{C>H(>h~*QOI?KQ1V4eS3QU*6gs! zTPh#^>6cRZU-dJ{s?aGr{o+jHFYoK^yubVJpZ>+Q)_Pm+*3&|+fhPZ(E5E$X{C?q+ zYWLhzMd9wp|M+bwI$HFr#YC zRa>LceU4FA)XpTy-u-X5b{BBl|C(@w!}iyc;3-q*E`Bs!H*QJZoyiqTEXw{Y{kG+J zpIo5ZXKVBN>vGR6qTbwCDZDjrvU_&L7uCfswkJBgU&$Nn__y?DbA`*xh;8$(-F?3# zd;Q`bp0|JZtKV$+`|n@;#YOsd%TL;@D&xs~`Le{ee^UD1Uz?1!*j9a8w7v365LDGV%8|-Ptd%oD?o=s|sXhzrH=V@Bg>(?-M^vHS;W( z`t+o|&6=JU9T&x4x=z?_Ra8`*dFF=qi_`x03%&K`E^s>n9+2`!8?p%1V_3+f!;cn^w+PK~O zmK@4ApR{kng|y8Rci10I)ppyyQ_)&|x>59&1(((Rcj;#RSaI>nT;8=kU+&dCF14zE zCsX^LeS1(y$dub(&UV@yTwL;U%^i!czt8AL_a3vIdVNvqw4#~Qr<(qo;`#fV?Atd> zbo@(W3}0ql?VRK{xk4+YMMrj~-`w35LdqJ)6AGG}Btc`RGdde~6!X8i?|!(g|H*#A zk}oF`Zv~s@YZRR_y#CXxaQ(dlpEtyE?fP|h%0ltJfX@dWotnB~_H*x}tyPNB)yFp^ z-j%BQzSjJ0{rz1#7Rp|JbvraP^wiVpXJ0aTu??r)d&&eSlolXJFjiGDSiudR5)N{fjp|AU zncGzzDY^8W?VK(>eeLki`>K{mTt0S4xZh@pm}lq4uBVj=h5X;&+ArAnxiiP*_pOgP-6ty%siRge zlrlw^`*79QmF6pUm%Ups|K2y{YTrxiviBD+zV&@6U*YNQ>c5lw?UTg+vIy}vNHX!P zliZRJC}|`c<`T7~Gx4fUZJ}QTXKurWM`u zIG!i-VsCjxx(oJwJe4BpXt_?R%;sI@??V$8zu2$;*IPFyYV#{;snUx_d1H1xy7#S= z@B1uG^ABEkQoQ^;17%tB*@E0A9Zm0E>3e(Imv67v2Y#2ct(+J#DfUTN?yU>_b$^6^ z*9DuUv~JL8nbhiU6&+ct!#z)i_g$*+`X$^IUv|&tef>Y}Uwg{N$&0I_@BB1+9u*tw zT3`Q5^WB`3z^tfQLMNwNJ$m#g^G?g@jBm5^S6p1DpZoH{#>M(4XH8|(dz$vpInAHt z%%#;|RFYL>yZtYO&2bBweRpfA^7gQAW{~MbYv#Q+NsRfpwl~uaqARoqVlgLRJNEUoz*MWnQu zzV_Kl^{KmK=iM&l74MgJkFWivd3Nq!v)cFV+s#(;T{m*xny=Yxo%5r>D)h-8o7fcx z7R4iXRZ$Bx$)#IfqEo_h4bF1=}&KA)Pi_>X1V@A~fsoiXqk4m6oMNzKPLO$w6wIlzK}aCezKhKuK4YnKD;uxu9~`V@`e6c{$iqsAN)Fa z`o$8@PENu4X7gDa?Vmc!|GTitUt8H^=6}8;kFCEhO*);!vdQSOrggCNS@tNicMO`* z*((L}7AP(RFJhb^D8ad-tcqM;@u= zoy?cDI-IYNd79tYnk{mI!pBeAs~I-`Oub$;!NTy;zP3w~g5oDD#R_oT$U0oKv0C6n z%QCLYSVbm|28S0QXMa_D_2c8?t9RbX{OfyiT7UnVXUSh(Lq1)bw(IJ}Z%HZf^PDFA zjJ=-x>6^%L^Sw8W6Jcxh4)r)3;9a+)@pzBq;(I-l=Fj(^tmdl}$)M^OW^&rvTef+J z?BpM{^NP-Vb-nv2X){23i-qI&*LpR9FQp`>9F zOYZG$y>|cq6q{ZWeSD{B|0%`ANi!c$y&oP|>AJT%c;3gmn^L>~{=8ej%v}lTFF72T z=x{*X_hiya@wke{yq!p|{3-6W|9)NHf9bNny|3nGEp@|fGbxzSbT^;OyP`?VKXe@yoK z`A07FdcnNg+q=X&ehQ^9-e46st1;aEB=+R_`k%WNna{bUtZ&?Gw`acWL96{rp7IsT zcYXiNr#XkSpZ%UuB;d+kbMOjBxUr-HYxn zb%bqFYhh-L6Ihe8Hj&L-M!~@i8gvG;8uAL5?b@@qJkS6yXmVg+IW&=hC(j~_*QgmX z=`0JHbPkqeflfNRgC?CD1qw2p2OhL7zNTOd?uAmfeJ&jbYE2S8Bm{(fhp0QfzA9)2wNj0=iYUt+UtrdGEVb`0xB#b}6CA{sTwqTheE*i*(rX zFQnoW-^#=N2O4x1?VR2||4!o+iS=bXD!x-#nG#(d)PzcKat9us$8c_Ym1q**_Ia$^ zpt<#c0h7UwwuP?Xxp4+2g#dpBHj1S6_pL}5G>krZ(`7BYz|E}Au5UtfZ@%68GM7#G zYKV~R|80r4cBJU#D@;H7bk5`HT0f+dge~puW#-Ru-tt|0(W%e>rZs$V6Q02SEmuzK zW67P%hMJdd7xG^<`#E8`m91=cQR@i~CLad2>55C92z}kxxWZNa>W}PeEmv?U3E$n(cgDv~<|Bh3Kp13kq=2)=**|0D6sjEx;pKW#fH?GYK7YdzI znqMFsZ7_LuhuQwyEX}9Ow|Cb$PnqEuaysA6>Pv4voB2}Fi!0&1@UEf#iQXl323bfrkTrG7_ANlo_Dok5)+tEwylt7IXe$^zKpZi<*VIgnkD}25m~f2)#d(&ohtRG`wQLIwXCrGWOXgE z^{w*Knz!>)_I@aB5wKwrv_B;JeN|5w|9Z7s2Eokr4{cr6?)a|0_-59=0$FG2eFr-N zBfd=$yFI@*_cr$rw!?0Vo7@?y1kAH{C+<0}Y;jz{%_(NbN1LP*Z=I)H3p2jg9%gx6 z^`qrp3)$()l_^(r9iQYLRqp%j-f2|vMNrzmq)5A8p&~>v@4kp#UDJ2}+{-b?qV(R@ zFZcezcGP^&rpr;YQ%z=``+DR9@7FJWy1r3zr&V*O7j4geYB6nL{_;;}*PT_6d-_@O z$&I|fJ09mJ=lY&fdSwvgEqU6!Jh3_@x7P3B{dxI6F6}FB-&&EVR4Sixv%l6`MY+Uw z$K=>Yn|`|O&*$u4uzJVd9G#ZN+WGkpE@e)tl0ALtbkCFf?@Jzj?(coceCF5X<}(v} zXG`pUZS^^0D({=nntz@%PR(6p$&$srmljXP3E`I@3P=3=ecRv1s>jI~~9IVNbI2zMk`ccUE`&tDLy%-plya zDY@U}Yw~I$%g?>ww7L4yH*PP_-*79D?)e0uj_HrEd+o%HpQ z+>1nYHlMgS*;-D#_?M5}`Rf}OMi)3}XJ+UHn(r&0^W@8=bBnkZeczGWep6u=o9FHA zOP}e!IK2P7;qA+F;_e08>=Avw_R1a(cJD27G<8n%t~vazX8p}$*E=_C`M9vM+Vs4G zUVQu|!AS~pR~N3?FQ@Z4?%LfudtK6Z+HkJ2O|6N4@P$?9bck*YGwBg*(A6yr=pL_hn?NfT$@=qu4t+KzLkoR;?P2lT?7qZ?7{0TQU zvt55RdFy?@IpJ1pNl#Qe67PQ1j8A!={ri>uX~mC5`PyI0WX_6P-v9CI-kHUx&zm-D z%QhUeU%7t!X_mU@?|kcXWYeeJH2ll zxIUd_=gscGcQcl~tv+?TiTCUI-v!S**3T5@zPaJk&RJr|+x{q@U89%3N_ikmMZo2;AaaEbiw{G0nyRSLp7(?0G zV#z9j@Q)GG9*amnx_*4)_g-tQzC_#C9z5%w>|DM5TA^p^w)e5et~+Mcdd<|DP@d;~ z{NX~yS>n$2zmliDPu(|7E_U(p2iL=yF78v?l4E68`1IK7-DE2ZxwT%x^&{Jfj_6y{&zW0D zKI}F>6k1kWb)11gVZWz~V~Bb0$-1P;Vbgk&mhwm{dJE_`vPiz|Iw*Em!9rMI`-lCF@F_U265@KxdX(-|y=3woda{k`4g_RWs} z^5w_=*?CDv+HReb_&~Pr1|QbAJjKPoDT%WZyaWvri}5-M3%&(#1q)yWQWp z-8(=3HrxHK{FCL$??Q#s&Bf&6PhZ!%uC456I7j~d^NU}i-@J=oR~ocr@x=MdBya2U z3C4cVTmE?0SHITmo!>WJ6ifbnyfjAdw1V>UZFgo)^6Qs#`FDE9Vdbw~*1v+*F(0gF zs+pzmg2m{k(u-o|?>hY-lVtW8FbSrlSbsQv>ulZK`YnPv-8H#i_B`j#J+d=fvET0a zr$xGb{*SqRd3N`_`f~N~?;lB1{2bKe#lttTyi_@n@%2U3+wVuF{Yp++AT1H28@>2{ z>J=?zufo;O;@7B7cJ(!(=PtMx89tZE+>krMSdze)hkk7Nbs(<>QP6%A}=cLWH-3m`nu(QQIDq8wka+lV|?g zmR(oK`hC`-QUxQcjCJ*uUp(A)SA9_X-FbEv_ujv)vviD%#Ha85q*0)F{HI#`1q;T= z)<41T7M!?qSJ;N@QuCSrFO|JIUr$&iJ8|}QJ9CX=Zu~~mSJYb`3y$;L-+SJA=Hw|C z?`fHZJony{tEVT&8x{!3gnzHw;NLBr{9GdCUUZX$ zjqM4Jz$RsB-L~_t`<|(s;J6$;fi+3U>a(r$bkCkeJN}gVH^oh#cIoebnQ0$=T=y&6^Q`}aI`OKg0S9#OEswR1>7pTsE zy>pM`~Rdw_jyjRn0b5Z)H8Q?27k}JTlq|L z{gdCS{VR^%@S0$Gw!Hka>67N$|MP3kmOjkR{KWLGWz*Darv)CrSm~GlDQi;3|F07l zZK-`1m#cVvv3SP2V)tbIm8py~SR&snVZS?d&sU$?c2}`x&f5oXMrld9R&no=+2oKT z7QbES*2aZm|CFOLe;#dwu&Y zZ~ZyJSKe1?@RoZi;`5RcmVQ=PR}r~ZXRd-~u-kq+{`pd2 zxi4olM&5dCUbH!`V#148HEVZ1Dx322bSwK7(bM_yt8!28S+c{%{$YjW#giJIF>~ks zkePJU<O!J?8VKOOe+S{#5r&^Q+Iv609!V)5`jLYkFq=$)2Ot1=G&Ip8xUhi@UZi{RZZd z7rq@(=-n?77-_Pse}U}jy7u?}n_j$LYi0ZD-J_ptl3NZ4B@_$abj&;S$Zwj0dBV@j z%{^ZHA3HqmO#h_L7VZ}D$nD%y;piqCr7a&zb8mm#zhvU^T$PgjUcaaQH;Rh>t2F(f zxk993bivGLcGFlxb{R(gk2m{t|GL<>6Gt_)SD5czDOq7CBP4V8m{9m(+hE&}&)eqt z^%wsswOzJ*@%6v$ujj71s@>hSM0jBs`)6OjPcL2`IdN*w+C6Kv*7kmzF){gP-|bI7 zdY5l|wduwFzRIs}h0pj{*?oF3`CZ)lwHNzt{aB`SaPk|a?K&cpD`O0|2&KG>F5xZT zbnNim|9X;l9(G;qJJE63u)}bQrQ6KQdzWhK7rZ)po$3CE`s3F-_U(9iFEyv7?Q^%` zjB4Mt+jcy+U&GEh@6#!bP@eC9Yu=uG;S(lVKmGL%wfWDTZqBe^J1)5W$oaI#iv15d z80XAce|B}($CVF$*yq^G5KJgvHSD7UKN_Olmh)7+b%Y*Z|~&ZQiA@vT%$?9SciGmDS+^QFFb_FrqP z^zM7QS(cG!`qT1e)4Lwe-I_KCBu zwmj%{|1muPiBF9=}w3d#-oo^Ka9_{hz;IFCqVuVF&lUS6@`tXIK7PGBv%(mi4&c`sF3> z`sS8vMvHB@dvtN=N1GEJG4q}4s;BS16E(-+^OEDoiXU~XXGtiiRc$Q+4P^-=FnwAP zz~-OLYIPz>x3aMH3}<<&_;350cmLkYtLtjGdx2x2GDEYp)wdOrEDj2XI8Xf9@<&oI z<>;0(E0t%oGo04|4d+6JLM40|*sf;U4 zBWhaWm+f!dzv%HNs{_A8ZZI_-5SUPIs(<`gboDG1#NrD7Wf1mfn)`ZKn4i6Kz0jofR^k$T<3TKdTfXoXav&97pKJ!%wwaB z_k3M@dwW>a=8b|kR!RT9rL^H{WA>-N`44_^$oPJq`sMiS!rB@B+Ab0gX9a3c-~@Z& zKoMvm*zzC~4hXjgv=D5C=m{3^dgKI4CW9T*f;FX}TsJ0z9cfp%QlJaLWEdr4POlW< zg>Vg&86{$jvsjHl`xY2DBKjD3@(zS%u>|Fx_mK)rKX7n?!)c)pC3RI+Y7Tp3zspBW zxxQSMIez*7ASHJdp$%`k^=GX*b8Y4H;JR-4fYVDHx4gXJyk-9n-sOuHEf&hiS+1|C zXx46b({jeD?DMN0+ipq^xV~n7U{Fl7Rs7CwGr8IZzIk)sPPu;B@AQ&HlTC-MOTPR` z-}36hTCJ5wO3%-8t9&_m$C>{YyB^uEWTBF#jgAO z^LLk5q~G=|`SmC7)`s`IQCnKi$42wUE9<`4mH2;I)3xbAJ|Qx1?Z29yjjWWOt9LV3 z|9{NL{{9BK65?Y8=FtMt3&Uw_9fuanJN^s!cc(V8nvR&`~@wY&ezhNk=GrcQoU z5*~T_ie5-?wCmBOzwgSr$#7JtG%TFRJn!Aj%P$xG`FX|gv)Zavw(hD^t7ZDKX74So z_r9rlSW|alL%tZNR!~pLe>49epAsQijkUAf@Jz>g)4yQgbd z?z3HbtbCQXkgxc*`6rKk)3Pf0R=a9zXwd#^{eiQ$Xfp>b*KZT)wjW@7I!7clc6sc5jjLHs_iDG-TiF zbNeQ1XWYFP=~sX8;>Ia6FU`|hbw1e3N$>j4c(0z*OG0lC>AVc`|XzRGT?{ z(`#JQPlc_nu`PbL{LB$Mzo%)c{K<>&^?v?4`I^i=?_Q_%?5aQzeMTbx;Q%OsyJ>v{Sk*yd8*WUp0Q&UxgNXqBGW(RoR@I=Jws+f~a6Caca& zvw!-lui*G%-EtMK886dr6+hd5Cv(P%Czi(-ziK|ZdFPqSTDJdYwmbB$oz>;_?P8bg zdCkRBuO~IcT1Y+>-6D5>@u~k8Z)-1G_2a+v_72`RDXAZdE>{QnRhj>)I&PnN@6~P% z(~YLK6>kOg(z}cf{I$AsK>4BUmp6wLwchg{j$hpP^ZsHn&AC@Pe#HC?l$*P6Z6EKu z8trnI=u76-|6S+j)LhVWE(y`$ePCl$b+76L^R5-oYel4m{ok+MHTU(5!^|4nz{#oAXr}=K4p33{upyY&{qwTFvwF}-D88H{}jtT6uWrO*m&y12`YgihZkR%{_~LL zQs(Dd0ynIC|76FvH&J@Y&6_=4=W4|+tegDUdc$kW*;P;NJU$xg-l+K7>9*mvg`Qfo z*t-|&FD+63vTU9u|AmRg+#1c>zXpUYy~}bWpi|m<@i~R=i_;#g^xMnxw>;pU{SM#q zmECq~R`b}l{gl3bzu#)xj8n>z`vMCD%76SkHTR0v*PvHd9{tujm$v!hy36{XPW&qD z`@OJha{Z;3Gxo2Q-u}}j_ExH>^liCSe-HWdeEl7LtMK`vDQsIRXSx5KCGK$k&i1R1 z&n#KG?{w~e)7mX(E5D@Jcl1sWT(QQ^UBA}S@9O;d#+N+%j8&^&ZdJXm*}PD`qpRy# z-_6K>*6v43*?eMlFZzE?GAe!3u4O*GbB@lCvDxZ%-s`u&PB@#n^2)hVn$Od|1hHB6 z@_wC?sDF9hWA7=uZ_R5o|F!92-o#52@5L9J`)|DR>BRTasqSufguYb97%qEsC~wWV zGf((43YzuB(I%i$A9LP4}_in(Z&!KM!56nm5(dRm(r8 zL`qbyzJ<3?@%+($liIe|H|zg1`||c8`_#h86Q2i|Ju+Lh=xY1B2ls!8_nr2r{{Aw& zGNn>8_WJ4>dhfnyo}W5*`CIk>>rQudEI|z!FRLm0iU`y+D6#4e_nq16tn%4bIxs2OP8sC zc_1ArCMs9m(yw~?*5U7~`drz|PQG5aq{#m4?Md#%+qXQM{n0Zu=eqpP{(Cp4oOoO9 zy7NM+ORs<(ONw0C=Y>1JSzdRXTj%l9a&d*q&thAcZ>vHv$wl5R8+^_$0 zidIF-j-223H5KQ%cgUo)tZp|l(-Jzua5nCz@*}4k7xpcB)^XHe@9s}wc2V`Y9#N7P zr-h1Llv?M0=;o&8kctAoyB!g3>i|Q{f@Gn(6vUFw1FMGo)hq>M@Fn<31();_K zOU3OkubZy7R&Sa8xomIOJKJoJi?7Z#Y!fVf-@15);zh-B+zO$vN`JpDzW3$D?wdCGH67Mc_b<90&6f~rIJh=A%IN%VFM-7$zir>B!lrI!HS<pWV^Lf0Ca5o2LBHFw*AI-^I1|`hUHwg7;0cyJ^^A z&0oFa@dvG~Pmjh5O-lNFW&I!P$X#b;I#m zN!{*f^U3b#?Ik`pO7;FL%&U&t@vzbDbFTd-&bQV(eI%dNS=reYeKn0y3~G7L z_o`3R*r~$rQ~`>q%d@}SIx6u-ch=UoFpF~O76dO+`8&w`|VFZoz^UwxARu(`?Y?d1$Xx!t=4wZ-e|9myde@%Y zYEpN;S$cK8KGOEpW%1J!jk9iX{nNkOqBYg;R(k=$&Fk*o ziaA!i;BbY?ca6WLb^5<9|NePOqWA4zhTTElAK`n|CQ6 zDV{d}*7mQx-Bsrvd|H)Z**_!p@P|D60HH2;S%%L-dN<8y!`aFO&5Jr zn=M-IIUr>DDr*1P1IuP{cS1DV2|9JPhyob`BY}L%mE>Ex4 zdp7ZP{9VyT3vMBg=RdE>$L?|HjrqU%g_fMC*sW;IV=hf=oTe!(-mEom|5?A+t9p8N zbUrmywtaEi=)1J^R+{2^nFR)ry2LHdge zFHKE~KVCg`!rRR-XWpwV;^(9zSH`|fdM9zh*@{3=s{ulTB+=*GX>p$6i)tz!e@9WRk%P#M?-#^3s!HzhYo9>6oa#Tz% zO*ea|JL_n7W7>rWd+I-V6wHX4s{NBsWWVcux!VsyT>f9Hf41fF%g?ckS1fwQa^Cyd zr_H;!Ur?PZ{*mj!_a7SD7E_2$&Ge9_dlPQGSBD|r%n8>$5)EAy02W0nA?{cc4f{IJ>CEP zx0c8IN8j{av%C6hWm;sT&O-NZwK3l|_eEaacINK4bG046J}G+|6|H~tGt=xWs+zO^9W>WVmN)?^>Hl%55u4-QvHh>xx}})i^nR^|Aif zpR1qhO?3^>^w9Ty&6etl*0+Hk%<-BAzsB>eq* zO4fRpy8Wu_kL}8g?H8VsIa|D4XjaZ*KP5PEuy=zJYmaNsUHN3a)gil!b>Ey6acQ&v@2KEX_g7ZgBpZli!GJhJ2 zmZVmnDtu`<1`^wE5r#>-#<0LlSpZC18m%!m&Z=V?Nv3RLxc4U9Z=e61V|6_D} zc5V3k`c&txUl-nHoh$x6vtFB7!_Di?^}d70O1<_9`AySX9LiqrG&lNR%dhQqP0tzR1izr0m(UXNkXy2<<1R@`5ns)2DU9-qkd&@0I%6G0En;_UDCtj$$e&lO2Up9!^TOsHhS>ufKc! zWy85S(?jPzWc4<`^hELer6Y{~AHALy-Kwgv(~VdktG~K@uaEGLnUAvdD&~pzoejR3 zEgQ4fD9hJ7$635=Z}8LUmd}nx|2w0Xm#Y^k=KA%-?k=m8kBb}s6!ATJ?HZPRdh-z> znbWIQX(pQ2c6Lp#51RH)Zo7Mu@*0jEUwc2qEc-m^z=o_zYHyV};= zzSXu;d+M3e?uR8jpC0j5mUzzJTxOGYxMEf4+Ye%x5IcZ1j1{pF75zwAR1q_4#{%+T*q)Rm}2a})r&+V0T zd1+H&wC$4A$A*)4w(eHQzc_pgF>CV}c=8_1T;u{C^kWpraA08D&L{-h+YTD*ba=pd-~rn_O)to}9z!D== Date: Mon, 23 Mar 2020 14:06:20 -0700 Subject: [PATCH 0943/1255] libui: Fix clamping of uint32_t source values It turned out that clamping was not working for conversions from uint32_t values to int32_t values. This adds a test to verify that conversion is handled correctly for that case, along with correcting the logic for implementing the clamping. The tests for the floating point source value case are also extended to verify that source values near INT32_MAX and INT32_MIN are also handled as correctly as possible, despite the seven bits of precision that are lost. Bug: 149495759 Test: atest Size_test Change-Id: Iaa0560184e6c2dd0a9d288fff288fb159ee99f07 --- libs/ui/include/ui/Size.h | 67 ++++++++++++++++++++++++++++--------- libs/ui/tests/Size_test.cpp | 25 ++++++++++++++ 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h index c2cda17a6f..f1e825286e 100644 --- a/libs/ui/include/ui/Size.h +++ b/libs/ui/include/ui/Size.h @@ -109,11 +109,11 @@ struct Size { // Takes a value of type FromType, and ensures it can be represented as a value of type ToType, // clamping the input value to the output range if necessary. template - static Size::remove_cv_reference_t clamp( - typename std::enable_if< - std::numeric_limits>::is_bounded && - std::numeric_limits>::is_bounded, - FromType&&>::type v) { + static Size::remove_cv_reference_t + clamp(typename std::enable_if< + std::numeric_limits>::is_specialized && + std::numeric_limits>::is_specialized, + FromType>::type v) { using BareToType = remove_cv_reference_t; using BareFromType = remove_cv_reference_t; static constexpr auto toHighest = std::numeric_limits::max(); @@ -121,21 +121,58 @@ struct Size { static constexpr auto fromHighest = std::numeric_limits::max(); static constexpr auto fromLowest = std::numeric_limits::lowest(); - // A clamp is needed if the range of FromType is not a subset of the range of ToType - static constexpr bool isClampNeeded = (toLowest > fromLowest) || (toHighest < fromHighest); + // Get the closest representation of [toLowest, toHighest] in type + // FromType to use to clamp the input value before conversion. + + // std::common_type<...> is used to get a value-preserving type for the + // top end of the range. + using CommonHighestType = std::common_type_t; + + // std::make_signed> is used to get a + // value-preserving type for the bottom end of the range, except this is + // a bit trickier for non-integer types like float. + using CommonLowestType = + std::conditional_t::is_integer, + std::make_signed_t::is_integer, + CommonHighestType, int /* not used */>>, + CommonHighestType>; + + // We can then compute the clamp range in a way that can be later + // trivially converted to either the 'from' or 'to' types, and be + // representabile in either. + static constexpr auto commonClampHighest = + std::min(static_cast(fromHighest), + static_cast(toHighest)); + static constexpr auto commonClampLowest = + std::max(static_cast(fromLowest), + static_cast(toLowest)); + + static constexpr auto fromClampHighest = static_cast(commonClampHighest); + static constexpr auto fromClampLowest = static_cast(commonClampLowest); + + // A clamp is needed only if the range we are clamping to is not the + // same as the range of the input. + static constexpr bool isClampNeeded = + (fromLowest != fromClampLowest) || (fromHighest != fromClampHighest); // If a clamp is not needed, the conversion is just a trivial cast. if (!isClampNeeded) { - return static_cast(v); + return static_cast(v); } - // Otherwise we need to carefully compare the limits of ToType (casted - // for the comparisons to be warning free to FromType) while still - // ensuring we return a value clamped to the range of ToType. - return v < static_cast(toLowest) - ? toLowest - : (v > static_cast(toHighest) ? toHighest - : static_cast(v)); + // Note: Clang complains about the value of INT32_MAX not being + // convertible back to int32_t from float if this is made "constexpr", + // when clamping a float value to an int32_t value. This is however + // covered by a test case to ensure the run-time cast works correctly. + const auto toClampHighest = static_cast(commonClampHighest); + const auto toClampLowest = static_cast(commonClampLowest); + + // Otherwise clamping is done by using the already computed endpoints + // for each type. + return (v <= fromClampLowest) + ? toClampLowest + : ((v >= fromClampHighest) ? toClampHighest : static_cast(v)); } }; diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp index 40dc702a8b..38f37ad827 100644 --- a/libs/ui/tests/Size_test.cpp +++ b/libs/ui/tests/Size_test.cpp @@ -186,9 +186,34 @@ TEST(SizeTest, Int8RangeIsNotClamped) { TEST(SizeTest, FloatRangeIsClamped) { ClampTest(std::numeric_limits::max(), std::numeric_limits::max()); + ClampTest(nexttowardf(std::numeric_limits::max(), std::numeric_limits::max()), + std::numeric_limits::max()); + ClampTest(static_cast(std::numeric_limits::max()), + std::numeric_limits::max()); + ClampTest(nexttowardf(std::numeric_limits::max(), 0), + static_cast(nexttowardf(std::numeric_limits::max(), 0))); ClampTest(float(0), int32_t(0)); + ClampTest(nexttowardf(std::numeric_limits::lowest(), 0), + static_cast(nexttowardf(std::numeric_limits::lowest(), 0))); + ClampTest(static_cast(std::numeric_limits::lowest()), + std::numeric_limits::lowest()); + ClampTest(nexttowardf(std::numeric_limits::lowest(), + std::numeric_limits::lowest()), + std::numeric_limits::lowest()); ClampTest(std::numeric_limits::lowest(), std::numeric_limits::lowest()); } +TEST(SizeTest, Uint32RangeIsClamped) { + ClampTest(std::numeric_limits::max(), std::numeric_limits::max()); + ClampTest(std::numeric_limits::max() - 1, std::numeric_limits::max()); + ClampTest(static_cast(std::numeric_limits::max()) + 1, + std::numeric_limits::max()); + ClampTest(static_cast(std::numeric_limits::max()), + std::numeric_limits::max()); + ClampTest(static_cast(std::numeric_limits::max()) - 1, + std::numeric_limits::max() - 1); + ClampTest(uint32_t(0), int32_t(0)); +} + } // namespace ui } // namespace android -- GitLab From 27ddcb559ad4fde529cc9216e1e9381e5a6cb6a2 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Fri, 20 Mar 2020 11:49:10 -0700 Subject: [PATCH 0944/1255] SF: Simplify initialization after a ui::Size fix Removes a TODO about waiting for the bug to be fixed. Bug: 149495759 Test: atest libsurfaceflinger_unittest Change-Id: Iada825d7501bf9bee3d99afb8802413eb6371492 --- .../surfaceflinger/DisplayHardware/FramebufferSurface.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index aeffb0e185..4c3b3e502d 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -183,10 +183,7 @@ void FramebufferSurface::onFrameCommitted() { } ui::Size FramebufferSurface::limitFramebufferSize(uint32_t width, uint32_t height) { - // TODO(b/149495759): Use the ui::Size constructor once it no longer is broken. - ui::Size framebufferSize; - framebufferSize.width = width; - framebufferSize.height = height; + ui::Size framebufferSize(width, height); bool wasLimited = true; if (width > mMaxWidth && mMaxWidth != 0) { float aspectRatio = float(width) / float(height); -- GitLab From 29e7bdfc0a8bb2c9e0165622edc18124e42b0b59 Mon Sep 17 00:00:00 2001 From: Dan Stoza Date: Mon, 23 Mar 2020 14:43:09 -0700 Subject: [PATCH 0945/1255] PowerAdvisor: Wait for boot finished Adds a call to PowerAdvisor so it can gate calls to notifyDisplayUpdateImminent until the boot has finished. This prevents PowerAdvisor from attempting to connect to the Power HAL, which can delay the boot animation if SF comes up first. Bug: 152131148 Test: libsurfaceflinger_unittest Test: libcompositionengine_test Test: Manual, check that boot is not delayed Change-Id: Idf59e9bb62a03360925aa06d95a7b4caea36be83 --- .../CompositionEngine/tests/MockPowerAdvisor.h | 1 + .../surfaceflinger/DisplayHardware/PowerAdvisor.cpp | 10 ++++++++++ services/surfaceflinger/DisplayHardware/PowerAdvisor.h | 3 +++ services/surfaceflinger/SurfaceFlinger.cpp | 1 + .../unittests/mock/DisplayHardware/MockPowerAdvisor.h | 1 + 5 files changed, 16 insertions(+) diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h index e740b13203..b738096479 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h @@ -29,6 +29,7 @@ public: PowerAdvisor(); ~PowerAdvisor() override; + MOCK_METHOD0(onBootFinished, void()); MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected)); MOCK_METHOD0(notifyDisplayUpdateImminent, void()); }; diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index 06e0cbb044..1d8179c9ac 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -72,6 +72,10 @@ PowerAdvisor::PowerAdvisor() } } +void PowerAdvisor::onBootFinished() { + mBootFinished.store(true); +} + void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) { if (expected) { mExpensiveDisplays.insert(displayId); @@ -97,6 +101,12 @@ void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expec } void PowerAdvisor::notifyDisplayUpdateImminent() { + // Only start sending this notification once the system has booted so we don't introduce an + // early-boot dependency on Power HAL + if (!mBootFinished.load()) { + return; + } + if (mSendUpdateImminent.load()) { HalWrapper* const halWrapper = getPowerHal(); if (halWrapper == nullptr) { diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h index 957d28989b..4a90acbdee 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h @@ -35,6 +35,7 @@ class PowerAdvisor { public: virtual ~PowerAdvisor(); + virtual void onBootFinished() = 0; virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0; virtual void notifyDisplayUpdateImminent() = 0; }; @@ -56,12 +57,14 @@ public: PowerAdvisor(); ~PowerAdvisor() override; + void onBootFinished() override; void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override; void notifyDisplayUpdateImminent() override; private: HalWrapper* getPowerHal(); + std::atomic_bool mBootFinished = false; bool mReconnectPowerHal = false; std::unordered_set mExpensiveDisplays; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index cfaabfc78c..6460904d59 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -567,6 +567,7 @@ void SurfaceFlinger::bootFinished() postMessageAsync(new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { readPersistentProperties(); + mPowerAdvisor.onBootFinished(); mBootStage = BootStage::FINISHED; if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) { diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h index fe57c98df8..e22d0cf74c 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h @@ -29,6 +29,7 @@ public: PowerAdvisor(); ~PowerAdvisor() override; + MOCK_METHOD0(onBootFinished, void()); MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected)); MOCK_METHOD0(notifyDisplayUpdateImminent, void()); }; -- GitLab From 34684143dce78c71faa8b2960fb171c6d36c21bb Mon Sep 17 00:00:00 2001 From: Yan Wang Date: Wed, 4 Mar 2020 15:37:55 -0800 Subject: [PATCH 0946/1255] package-manager-native: Add aidl for package change event and observer. Iorapd, a native service to prefetch files during app startup, will register it as an observer via the package manager native service. Bug: 150742983 Test: Make and run on a blueline device and check the observer works. Change-Id: I98624fe563b83f5dd801f607fa2b31ab6f6998e7 --- libs/binder/Android.bp | 2 ++ .../content/pm/IPackageChangeObserver.aidl | 28 ++++++++++++++++ .../content/pm/IPackageManagerNative.aidl | 11 +++++++ .../content/pm/PackageChangeEvent.aidl | 32 +++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl create mode 100644 libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index bc541f4d31..e6cfeb4943 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -158,7 +158,9 @@ cc_library { filegroup { name: "libbinder_aidl", srcs: [ + "aidl/android/content/pm/IPackageChangeObserver.aidl", "aidl/android/content/pm/IPackageManagerNative.aidl", + "aidl/android/content/pm/PackageChangeEvent.aidl", "aidl/android/os/IClientCallback.aidl", "aidl/android/os/IServiceCallback.aidl", "aidl/android/os/IServiceManager.aidl", diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl new file mode 100644 index 0000000000..6929a6cb49 --- /dev/null +++ b/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm; + +import android.content.pm.PackageChangeEvent; + +/** + * This is a non-blocking notification when a package has changed. + * + * @hide + */ +oneway interface IPackageChangeObserver { + void onPackageChanged(in PackageChangeEvent event); +} diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl index 618f88c66d..dc8d74c052 100644 --- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -17,6 +17,8 @@ package android.content.pm; +import android.content.pm.IPackageChangeObserver; + /** * Parallel implementation of certain {@link PackageManager} APIs that need to * be exposed to native code. @@ -90,4 +92,13 @@ interface IPackageManagerNative { /* Returns the names of all packages. */ @utf8InCpp String[] getAllPackages(); + + /** Register an extra package change observer to receive the multi-cast. */ + void registerPackageChangeObserver(in IPackageChangeObserver observer); + + /** + * Unregister an existing package change observer. + * This does nothing if this observer was not already registered. + */ + void unregisterPackageChangeObserver(in IPackageChangeObserver observer); } diff --git a/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl b/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl new file mode 100644 index 0000000000..e30e9072fc --- /dev/null +++ b/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm; + +/** + * This event is designed for notification to native code listener about + * any changes on a package including update, deletion and etc. + * + * @hide + */ +parcelable PackageChangeEvent { + @utf8InCpp String packageName; + long version; + long lastUpdateTimeMillis; + boolean newInstalled; + boolean dataRemoved; + boolean isDeleted; +} -- GitLab From 5e7371cec37711a0a822a7b553a340a4605efc89 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 24 Mar 2020 14:47:24 -0700 Subject: [PATCH 0947/1255] SurfaceFlinger: add debug information when vsync is not generated Print debug information about VsyncReactor internal state when we expect a vsync event but it is not generated. Bug: 151892277 Test: adb shell dumpsys SurfaceFlinger --dispsync Test: simulate a missed vsync and observed logcat Change-Id: Ia98cb884321d0c25610c4d721f422d9cd05c8c5e --- .../Scheduler/DispSyncSource.cpp | 7 +++ .../surfaceflinger/Scheduler/DispSyncSource.h | 4 +- .../surfaceflinger/Scheduler/EventThread.cpp | 7 ++- .../surfaceflinger/Scheduler/EventThread.h | 2 + .../Scheduler/InjectVSyncSource.h | 1 + .../surfaceflinger/Scheduler/VSyncDispatch.h | 2 + .../Scheduler/VSyncDispatchTimerQueue.cpp | 36 +++++++++++++++ .../Scheduler/VSyncDispatchTimerQueue.h | 5 ++- .../Scheduler/VSyncPredictor.cpp | 14 ++++++ .../surfaceflinger/Scheduler/VSyncPredictor.h | 2 + .../surfaceflinger/Scheduler/VSyncReactor.cpp | 44 +++++++++++++++++-- .../surfaceflinger/Scheduler/VSyncReactor.h | 2 +- .../surfaceflinger/Scheduler/VSyncTracker.h | 2 + .../tests/unittests/EventThreadTest.cpp | 1 + .../unittests/VSyncDispatchRealtimeTest.cpp | 2 + .../unittests/VSyncDispatchTimerQueueTest.cpp | 1 + .../tests/unittests/VSyncReactorTest.cpp | 5 +++ 17 files changed, 130 insertions(+), 7 deletions(-) diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 776e98463f..4e3f85f53e 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -30,6 +30,7 @@ #include "EventThread.h" namespace android { +using base::StringAppendF; DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name) @@ -107,6 +108,12 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) { } } +void DispSyncSource::dump(std::string& result) const { + std::lock_guard lock(mVsyncMutex); + StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled"); + mDispSync->dump(result); +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h index 328b8c176f..f278712407 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.h +++ b/services/surfaceflinger/Scheduler/DispSyncSource.h @@ -36,6 +36,8 @@ public: void setCallback(VSyncSource::Callback* callback) override; void setPhaseOffset(nsecs_t phaseOffset) override; + void dump(std::string&) const override; + private: // The following method is the implementation of the DispSync::Callback. virtual void onDispSyncEvent(nsecs_t when); @@ -52,7 +54,7 @@ private: std::mutex mCallbackMutex; VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr; - std::mutex mVsyncMutex; + mutable std::mutex mVsyncMutex; TracedOrdinal mPhaseOffset GUARDED_BY(mVsyncMutex); bool mEnabled GUARDED_BY(mVsyncMutex) = false; }; diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index acab5a6249..0d6a92e08f 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -425,7 +425,12 @@ void EventThread::threadMain(std::unique_lock& lock) { // display is off, keep feeding clients at 60 Hz. const auto timeout = mState == State::SyntheticVSync ? 16ms : 1000ms; if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) { - ALOGW_IF(mState == State::VSync, "Faking VSYNC due to driver stall"); + if (mState == State::VSync) { + ALOGW("Faking VSYNC due to driver stall for thread %s", mThreadName); + std::string debugInfo = "VsyncSource debug info:\n"; + mVSyncSource->dump(debugInfo); + ALOGW("%s", debugInfo.c_str()); + } LOG_FATAL_IF(!mVSyncState); mPendingEvents.push_back(makeVSync(mVSyncState->displayId, diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 466234d3d7..98b1876994 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -66,6 +66,8 @@ public: virtual void setVSyncEnabled(bool enable) = 0; virtual void setCallback(Callback* callback) = 0; virtual void setPhaseOffset(nsecs_t phaseOffset) = 0; + + virtual void dump(std::string& result) const = 0; }; class EventThreadConnection : public BnDisplayEventConnection { diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h index fa46e6f589..31da588b72 100644 --- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h +++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h @@ -45,6 +45,7 @@ public: const char* getName() const override { return "inject"; } void setVSyncEnabled(bool) override {} void setPhaseOffset(nsecs_t) override {} + void dump(std::string&) const override {} private: std::mutex mCallbackMutex; diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h index a6fb3a4df0..2a2d7c5279 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatch.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h @@ -108,6 +108,8 @@ public: */ virtual CancelResult cancel(CallbackToken token) = 0; + virtual void dump(std::string& result) const = 0; + protected: VSyncDispatch() = default; VSyncDispatch(VSyncDispatch const&) = delete; diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp index d0f18abe77..460d4a5c3c 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp @@ -15,6 +15,7 @@ */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include #include #include @@ -23,6 +24,7 @@ #include "VSyncTracker.h" namespace android::scheduler { +using base::StringAppendF; VSyncDispatch::~VSyncDispatch() = default; VSyncTracker::~VSyncTracker() = default; @@ -122,6 +124,28 @@ void VSyncDispatchTimerQueueEntry::ensureNotRunning() { mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; }); } +void VSyncDispatchTimerQueueEntry::dump(std::string& result) const { + std::lock_guard lk(mRunningMutex); + std::string armedInfo; + if (mArmedInfo) { + StringAppendF(&armedInfo, "[wake up in %.2fms for vsync %.2fms from now]", + (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f, + (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f); + } + + StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(), + mRunning ? "(in callback function)" : "", armedInfo.c_str()); + StringAppendF(&result, "\t\t\tmWorkDuration: %.2fms mEarliestVsync: %.2fms relative to now\n", + mWorkDuration / 1e6f, (mEarliestVsync - systemTime()) / 1e6f); + + if (mLastDispatchTime) { + StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n", + (systemTime() - *mLastDispatchTime) / 1e6f); + } else { + StringAppendF(&result, "\t\t\tmLastDispatchTime unknown\n"); + } +} + VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr tk, VSyncTracker& tracker, nsecs_t timerSlack, nsecs_t minVsyncDistance) @@ -296,6 +320,18 @@ CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) { return CancelResult::TooLate; } +void VSyncDispatchTimerQueue::dump(std::string& result) const { + std::lock_guard lk(mMutex); + StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f, + mMinVsyncDistance / 1e6f); + StringAppendF(&result, "\tmIntendedWakeupTime: %.2fms from now\n", + (mIntendedWakeupTime - systemTime()) / 1e6f); + StringAppendF(&result, "\tCallbacks:\n"); + for (const auto& [token, entry] : mCallbacks) { + entry->dump(result); + } +} + VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch, VSyncDispatch::Callback const& callbackFn, std::string const& callbackName) diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h index fd0a034423..390e0c460f 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h @@ -71,6 +71,8 @@ public: // Block calling thread while the callback is executing. void ensureNotRunning(); + void dump(std::string& result) const; + private: std::string const mName; VSyncDispatch::Callback const mCallback; @@ -86,7 +88,7 @@ private: std::optional mArmedInfo; std::optional mLastDispatchTime; - std::mutex mRunningMutex; + mutable std::mutex mRunningMutex; std::condition_variable mCv; bool mRunning GUARDED_BY(mRunningMutex) = false; }; @@ -112,6 +114,7 @@ public: void unregisterCallback(CallbackToken token) final; ScheduleResult schedule(CallbackToken token, nsecs_t workDuration, nsecs_t earliestVsync) final; CancelResult cancel(CallbackToken token) final; + void dump(std::string& result) const final; private: VSyncDispatchTimerQueue(VSyncDispatchTimerQueue const&) = delete; diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index 257b8b16bf..a3cb7725a7 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -22,6 +22,7 @@ //#define LOG_NDEBUG 0 #include "VSyncPredictor.h" #include +#include #include #include #include @@ -31,6 +32,7 @@ #include namespace android::scheduler { +using base::StringAppendF; static auto constexpr kMaxPercent = 100u; @@ -263,6 +265,18 @@ void VSyncPredictor::resetModel() { clearTimestamps(); } +void VSyncPredictor::dump(std::string& result) const { + std::lock_guard lk(mMutex); + StringAppendF(&result, "\tmIdealPeriod=%.2f\n", mIdealPeriod / 1e6f); + StringAppendF(&result, "\tRefresh Rate Map:\n"); + for (const auto& [idealPeriod, periodInterceptTuple] : mRateMap) { + StringAppendF(&result, + "\t\tFor ideal period %.2fms: period = %.2fms, intercept = %" PRId64 "\n", + idealPeriod / 1e6f, std::get<0>(periodInterceptTuple) / 1e6f, + std::get<1>(periodInterceptTuple)); + } +} + } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h index ef1d88ac27..3ca878d77d 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.h +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h @@ -60,6 +60,8 @@ public: std::tuple getVSyncPredictionModel() const; + void dump(std::string& result) const final; + private: VSyncPredictor(VSyncPredictor const&) = delete; VSyncPredictor& operator=(VSyncPredictor const&) = delete; diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index 8987dcdc58..892ae62027 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -28,6 +28,7 @@ #include "VSyncTracker.h" namespace android::scheduler { +using base::StringAppendF; Clock::~Clock() = default; nsecs_t SystemClock::now() const { @@ -73,11 +74,12 @@ class CallbackRepeater { public: CallbackRepeater(VSyncDispatch& dispatch, DispSync::Callback* cb, const char* name, nsecs_t period, nsecs_t offset, nsecs_t notBefore) - : mCallback(cb), + : mName(name), + mCallback(cb), mRegistration(dispatch, std::bind(&CallbackRepeater::callback, this, std::placeholders::_1, std::placeholders::_2), - std::string(name)), + mName), mPeriod(period), mOffset(offset), mLastCallTime(notBefore) {} @@ -112,6 +114,13 @@ public: mRegistration.cancel(); } + void dump(std::string& result) const { + std::lock_guard lk(mMutex); + StringAppendF(&result, "\t%s: mPeriod=%.2f last vsync time %.2fms relative to now (%s)\n", + mName.c_str(), mPeriod / 1e6f, (mLastCallTime - systemTime()) / 1e6f, + mStopped ? "stopped" : "running"); + } + private: void callback(nsecs_t vsynctime, nsecs_t wakeupTime) { { @@ -137,6 +146,7 @@ private: // Note change in sign between the two defnitions. nsecs_t calculateWorkload() REQUIRES(mMutex) { return mPeriod - mOffset; } + const std::string mName; DispSync::Callback* const mCallback; std::mutex mutable mMutex; @@ -349,7 +359,35 @@ status_t VSyncReactor::changePhaseOffset(DispSync::Callback* callback, nsecs_t p } void VSyncReactor::dump(std::string& result) const { - result += "VsyncReactor in use\n"; // TODO (b/144927823): add more information! + std::lock_guard lk(mMutex); + StringAppendF(&result, "VsyncReactor in use\n"); + StringAppendF(&result, "Has %zu unfired fences\n", mUnfiredFences.size()); + StringAppendF(&result, "mInternalIgnoreFences=%d mExternalIgnoreFences=%d\n", + mInternalIgnoreFences, mExternalIgnoreFences); + StringAppendF(&result, "mMoreSamplesNeeded=%d mPeriodConfirmationInProgress=%d\n", + mMoreSamplesNeeded, mPeriodConfirmationInProgress); + if (mPeriodTransitioningTo) { + StringAppendF(&result, "mPeriodTransitioningTo=%" PRId64 "\n", *mPeriodTransitioningTo); + } else { + StringAppendF(&result, "mPeriodTransitioningTo=nullptr\n"); + } + + if (mLastHwVsync) { + StringAppendF(&result, "Last HW vsync was %.2fms ago\n", + (mClock->now() - *mLastHwVsync) / 1e6f); + } else { + StringAppendF(&result, "No Last HW vsync\n"); + } + + StringAppendF(&result, "CallbackRepeaters:\n"); + for (const auto& [callback, repeater] : mCallbacks) { + repeater->dump(result); + } + + StringAppendF(&result, "VSyncTracker:\n"); + mTracker->dump(result); + StringAppendF(&result, "VSyncDispatch:\n"); + mDispatch->dump(result); } void VSyncReactor::reset() {} diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index 7d8a8e3bb0..5ee29f86d4 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -75,7 +75,7 @@ private: std::unique_ptr const mDispatch; size_t const mPendingLimit; - std::mutex mMutex; + mutable std::mutex mMutex; bool mInternalIgnoreFences GUARDED_BY(mMutex) = false; bool mExternalIgnoreFences GUARDED_BY(mMutex) = false; std::vector> mUnfiredFences GUARDED_BY(mMutex); diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h index a25b8a98de..05a6fc3a8d 100644 --- a/services/surfaceflinger/Scheduler/VSyncTracker.h +++ b/services/surfaceflinger/Scheduler/VSyncTracker.h @@ -66,6 +66,8 @@ public: /* Inform the tracker that the samples it has are not accurate for prediction. */ virtual void resetModel() = 0; + virtual void dump(std::string& result) const = 0; + protected: VSyncTracker(VSyncTracker const&) = delete; VSyncTracker& operator=(VSyncTracker const&) = delete; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 65b3e35d32..ba5c0c2988 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -48,6 +48,7 @@ public: MOCK_METHOD1(setCallback, void(VSyncSource::Callback*)); MOCK_METHOD1(setPhaseOffset, void(nsecs_t)); MOCK_METHOD1(pauseVsyncCallback, void(bool)); + MOCK_CONST_METHOD1(dump, void(std::string&)); }; } // namespace diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp index caac61da29..be49ef33f2 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp @@ -51,6 +51,7 @@ public: void setPeriod(nsecs_t) final {} void resetModel() final {} + void dump(std::string&) const final {} private: nsecs_t const mPeriod; @@ -85,6 +86,7 @@ public: void setPeriod(nsecs_t) final {} void resetModel() final {} + void dump(std::string&) const final {} private: std::mutex mutable mMutex; diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index 3ab38e40ef..3543361f7b 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -47,6 +47,7 @@ public: MOCK_CONST_METHOD0(currentPeriod, nsecs_t()); MOCK_METHOD1(setPeriod, void(nsecs_t)); MOCK_METHOD0(resetModel, void()); + MOCK_CONST_METHOD1(dump, void(std::string&)); nsecs_t nextVSyncTime(nsecs_t timePoint) const { if (timePoint % mPeriod == 0) { diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index ac959388c2..4f150ef1e0 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -41,6 +41,7 @@ public: MOCK_CONST_METHOD0(currentPeriod, nsecs_t()); MOCK_METHOD1(setPeriod, void(nsecs_t)); MOCK_METHOD0(resetModel, void()); + MOCK_CONST_METHOD1(dump, void(std::string&)); }; class VSyncTrackerWrapper : public VSyncTracker { @@ -56,6 +57,7 @@ public: nsecs_t currentPeriod() const final { return mTracker->currentPeriod(); } void setPeriod(nsecs_t period) final { mTracker->setPeriod(period); } void resetModel() final { mTracker->resetModel(); } + void dump(std::string& result) const final { mTracker->dump(result); } private: std::shared_ptr const mTracker; @@ -83,6 +85,7 @@ public: MOCK_METHOD1(unregisterCallback, void(CallbackToken)); MOCK_METHOD3(schedule, ScheduleResult(CallbackToken, nsecs_t, nsecs_t)); MOCK_METHOD1(cancel, CancelResult(CallbackToken token)); + MOCK_CONST_METHOD1(dump, void(std::string&)); }; class VSyncDispatchWrapper : public VSyncDispatch { @@ -102,6 +105,8 @@ public: CancelResult cancel(CallbackToken token) final { return mDispatch->cancel(token); } + void dump(std::string& result) const final { return mDispatch->dump(result); } + private: std::shared_ptr const mDispatch; }; -- GitLab From 5b31e5c671773cb5a81e3521204fe8ab0fbaa171 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 24 Mar 2020 17:05:03 -0700 Subject: [PATCH 0948/1255] SurfaceFlinger: remove experimental.sf.force_youtube_vote This was just for development purposes, not needed anymore. Test: compile Bug: 146935143 Change-Id: I404bed7ebc88dfc43ba58baa0a31e30f57ee83ed --- services/surfaceflinger/Scheduler/Scheduler.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 920f0ec331..cd6075f5b4 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -419,20 +419,6 @@ void Scheduler::registerLayer(Layer* layer) { mRefreshRateConfigs.getMaxRefreshRate().fps, scheduler::LayerHistory::LayerVoteType::Heuristic); } - - // TODO(146935143): Simulate youtube app vote. This should be removed once youtube calls the - // API to set desired rate - { - const auto vote = property_get_int32("experimental.sf.force_youtube_vote", 0); - if (vote != 0 && - layer->getName() == - "SurfaceView - " - "com.google.android.youtube/" - "com.google.android.apps.youtube.app.WatchWhileActivity#0") { - layer->setFrameRate( - Layer::FrameRate(vote, Layer::FrameRateCompatibility::ExactOrMultiple)); - } - } } } -- GitLab From 47a72cba40259aae313f8b274a3f785606ed8ddc Mon Sep 17 00:00:00 2001 From: Changyeon Jo Date: Wed, 25 Mar 2020 10:51:09 -0700 Subject: [PATCH 0949/1255] Use manifest fragments Add Automotive Display Proxy service to vintf by using a manifest fragment. Bug: 152367138 Test: build and manually run automotive display service on automotive platform Change-Id: I801f2900f6d46b6991c02e46dc684715a5936241 --- services/automotive/display/Android.bp | 4 ++++ ...fest_android.frameworks.automotive.display@1.0.xml | 11 +++++++++++ 2 files changed, 15 insertions(+) create mode 100644 services/automotive/display/manifest_android.frameworks.automotive.display@1.0.xml diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp index 8ff0711f55..c3da216002 100644 --- a/services/automotive/display/Android.bp +++ b/services/automotive/display/Android.bp @@ -40,4 +40,8 @@ cc_binary { cflags: [ "-DLOG_TAG=\"AutomotiveDisplayService\"" ], + + vintf_fragments: [ + "manifest_android.frameworks.automotive.display@1.0.xml", + ], } diff --git a/services/automotive/display/manifest_android.frameworks.automotive.display@1.0.xml b/services/automotive/display/manifest_android.frameworks.automotive.display@1.0.xml new file mode 100644 index 0000000000..464dcac8bb --- /dev/null +++ b/services/automotive/display/manifest_android.frameworks.automotive.display@1.0.xml @@ -0,0 +1,11 @@ + + + android.frameworks.automotive.display + hwbinder + 1.0 + + IAutomotiveDisplayProxyService + default + + + -- GitLab From ef6532c9d46439e4773435c10624d097a53978df Mon Sep 17 00:00:00 2001 From: Hui Yu Date: Tue, 24 Mar 2020 16:12:07 -0700 Subject: [PATCH 0950/1255] Add isUidActiveOrForeground for camera/audio to use. The new interface isUidActiveOrForeground will call AM.isUidActiveOrForeground() which check isUidActive() first, if flase, then check isUidForeground. Bug: 151185692, 151777097, 109950150 Test: manual test. Change-Id: I51ed1fe780dbead0688e73a37c6c762f84e8bf23 --- libs/binder/ActivityManager.cpp | 9 +++++ libs/binder/IActivityManager.cpp | 12 ++++++ libs/binder/include/binder/ActivityManager.h | 38 +++++++++---------- libs/binder/include/binder/IActivityManager.h | 4 +- 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp index 5e4c98fc7a..4f2709d91a 100644 --- a/libs/binder/ActivityManager.cpp +++ b/libs/binder/ActivityManager.cpp @@ -98,6 +98,15 @@ int32_t ActivityManager::getUidProcessState(const uid_t uid, const String16& cal return PROCESS_STATE_UNKNOWN; } +bool ActivityManager::isUidActiveOrForeground(const uid_t uid, const String16& callingPackage) +{ + sp service = getService(); + if (service != nullptr) { + return service->isUidActiveOrForeground(uid, callingPackage); + } + return false; +} + status_t ActivityManager::linkToDeath(const sp& recipient) { sp service = getService(); if (service != nullptr) { diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp index 1eb5363ae2..9e1249baf4 100644 --- a/libs/binder/IActivityManager.cpp +++ b/libs/binder/IActivityManager.cpp @@ -104,6 +104,18 @@ public: } return reply.readInt32(); } + + virtual bool isUidActiveOrForeground(const uid_t uid, const String16& callingPackage) + { + Parcel data, reply; + data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); + data.writeInt32(uid); + data.writeString16(callingPackage); + remote()->transact(IS_UID_ACTIVE_OR_FOREGROUND_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return false; + return reply.readInt32() == 1; + } }; // ------------------------------------------------------------------------------------ diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h index 9108e31758..0bb6d28da4 100644 --- a/libs/binder/include/binder/ActivityManager.h +++ b/libs/binder/include/binder/ActivityManager.h @@ -46,25 +46,24 @@ public: PROCESS_STATE_PERSISTENT = 0, PROCESS_STATE_PERSISTENT_UI = 1, PROCESS_STATE_TOP = 2, - PROCESS_STATE_FOREGROUND_SERVICE_LOCATION = 3, - PROCESS_STATE_BOUND_TOP = 4, - PROCESS_STATE_FOREGROUND_SERVICE = 5, - PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 6, - PROCESS_STATE_IMPORTANT_FOREGROUND = 7, - PROCESS_STATE_IMPORTANT_BACKGROUND = 8, - PROCESS_STATE_TRANSIENT_BACKGROUND = 9, - PROCESS_STATE_BACKUP = 10, - PROCESS_STATE_SERVICE = 11, - PROCESS_STATE_RECEIVER = 12, - PROCESS_STATE_TOP_SLEEPING = 13, - PROCESS_STATE_HEAVY_WEIGHT = 14, - PROCESS_STATE_HOME = 15, - PROCESS_STATE_LAST_ACTIVITY = 16, - PROCESS_STATE_CACHED_ACTIVITY = 17, - PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 18, - PROCESS_STATE_CACHED_RECENT = 19, - PROCESS_STATE_CACHED_EMPTY = 20, - PROCESS_STATE_NONEXISTENT = 21, + PROCESS_STATE_BOUND_TOP = 3, + PROCESS_STATE_FOREGROUND_SERVICE = 4, + PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 5, + PROCESS_STATE_IMPORTANT_FOREGROUND = 6, + PROCESS_STATE_IMPORTANT_BACKGROUND = 7, + PROCESS_STATE_TRANSIENT_BACKGROUND = 8, + PROCESS_STATE_BACKUP = 9, + PROCESS_STATE_SERVICE = 10, + PROCESS_STATE_RECEIVER = 11, + PROCESS_STATE_TOP_SLEEPING = 12, + PROCESS_STATE_HEAVY_WEIGHT = 13, + PROCESS_STATE_HOME = 14, + PROCESS_STATE_LAST_ACTIVITY = 15, + PROCESS_STATE_CACHED_ACTIVITY = 16, + PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 17, + PROCESS_STATE_CACHED_RECENT = 18, + PROCESS_STATE_CACHED_EMPTY = 19, + PROCESS_STATE_NONEXISTENT = 20, }; ActivityManager(); @@ -77,6 +76,7 @@ public: void unregisterUidObserver(const sp& observer); bool isUidActive(const uid_t uid, const String16& callingPackage); int getUidProcessState(const uid_t uid, const String16& callingPackage); + bool isUidActiveOrForeground(const uid_t uid, const String16& callingPackage); status_t linkToDeath(const sp& recipient); diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h index e0248f6624..1815ecc67f 100644 --- a/libs/binder/include/binder/IActivityManager.h +++ b/libs/binder/include/binder/IActivityManager.h @@ -39,13 +39,15 @@ public: virtual void unregisterUidObserver(const sp& observer) = 0; virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0; virtual int32_t getUidProcessState(const uid_t uid, const String16& callingPackage) = 0; + virtual bool isUidActiveOrForeground(const uid_t uid, const String16& callingPackage) = 0; enum { OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, REGISTER_UID_OBSERVER_TRANSACTION, UNREGISTER_UID_OBSERVER_TRANSACTION, IS_UID_ACTIVE_TRANSACTION, - GET_UID_PROCESS_STATE_TRANSACTION + GET_UID_PROCESS_STATE_TRANSACTION, + IS_UID_ACTIVE_OR_FOREGROUND_TRANSACTION, }; }; -- GitLab From 27800499ab20551a2b2e64d360c5e2130c881dd2 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 25 Mar 2020 15:44:28 -0700 Subject: [PATCH 0951/1255] [Vulkan] Expose device extensions from implicit layers. Previously the vulkan loader only exposes device extensions from the driver implementation when the layer name is not specified. Per vkEnumerateDeviceExtensionProperties spec the loader must also advertise device extensions from implicitly enabled layers. Bug: b/143293104 Test: atest android.gputools.cts.CtsRootlessGpuDebugHostTest Change-Id: Iaf5786ba7e371a290ecd1764af69b5298371cfdd --- vulkan/libvulkan/api.cpp | 100 ++++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 23 deletions(-) diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp index e607b058eb..5b9affd03a 100644 --- a/vulkan/libvulkan/api.cpp +++ b/vulkan/libvulkan/api.cpp @@ -1196,6 +1196,23 @@ bool EnsureInitialized() { return initialized; } +template +void ForEachLayerFromSettings(Functor functor) { + const std::string layersSetting = + android::GraphicsEnv::getInstance().getDebugLayers(); + if (!layersSetting.empty()) { + std::vector layers = + android::base::Split(layersSetting, ":"); + for (uint32_t i = 0; i < layers.size(); i++) { + const Layer* layer = FindLayer(layers[i].c_str()); + if (!layer) { + continue; + } + functor(layer); + } + } +} + } // anonymous namespace VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo, @@ -1291,28 +1308,18 @@ VkResult EnumerateInstanceExtensionProperties( std::unordered_set extensionNames; // Expose extensions from implicitly enabled layers. - const std::string layersSetting = - android::GraphicsEnv::getInstance().getDebugLayers(); - if (!layersSetting.empty()) { - std::vector layers = - android::base::Split(layersSetting, ":"); - for (uint32_t i = 0; i < layers.size(); i++) { - const Layer* layer = FindLayer(layers[i].c_str()); - if (!layer) { - continue; - } - uint32_t count = 0; - const VkExtensionProperties* props = - GetLayerInstanceExtensions(*layer, count); - if (count > 0) { - for (uint32_t i = 0; i < count; ++i) { - if (extensionNames.emplace(props[i].extensionName).second) { - properties.push_back(props[i]); - } + ForEachLayerFromSettings([&](const Layer* layer) { + uint32_t count = 0; + const VkExtensionProperties* props = + GetLayerInstanceExtensions(*layer, count); + if (count > 0) { + for (uint32_t i = 0; i < count; ++i) { + if (extensionNames.emplace(props[i].extensionName).second) { + properties.push_back(props[i]); } } } - } + }); // TODO(b/143293104): Parse debug.vulkan.layers properties @@ -1393,10 +1400,57 @@ VkResult EnumerateDeviceExtensionProperties( return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS; } - // TODO(b/143293104): expose extensions from implicitly enabled layers - const InstanceData& data = GetData(physicalDevice); - return data.dispatch.EnumerateDeviceExtensionProperties( - physicalDevice, nullptr, pPropertyCount, pProperties); + // If the pLayerName is nullptr, we must advertise all device extensions + // from all implicitly enabled layers and the driver implementation. If + // there are duplicates among layers and the driver implementation, always + // only preserve the top layer closest to the application regardless of the + // spec version. + std::vector properties; + std::unordered_set extensionNames; + + // Expose extensions from implicitly enabled layers. + ForEachLayerFromSettings([&](const Layer* layer) { + uint32_t count = 0; + const VkExtensionProperties* props = + GetLayerDeviceExtensions(*layer, count); + if (count > 0) { + for (uint32_t i = 0; i < count; ++i) { + if (extensionNames.emplace(props[i].extensionName).second) { + properties.push_back(props[i]); + } + } + } + }); + + // TODO(b/143293104): Parse debug.vulkan.layers properties + + // Expose extensions from driver implementation. + { + const InstanceData& data = GetData(physicalDevice); + uint32_t count = 0; + VkResult result = data.dispatch.EnumerateDeviceExtensionProperties( + physicalDevice, nullptr, &count, nullptr); + if (result == VK_SUCCESS && count > 0) { + std::vector props(count); + result = data.dispatch.EnumerateDeviceExtensionProperties( + physicalDevice, nullptr, &count, props.data()); + for (auto prop : props) { + if (extensionNames.emplace(prop.extensionName).second) { + properties.push_back(prop); + } + } + } + } + + uint32_t totalCount = properties.size(); + if (!pProperties || *pPropertyCount > totalCount) { + *pPropertyCount = totalCount; + } + if (pProperties) { + std::copy(properties.data(), properties.data() + *pPropertyCount, + pProperties); + } + return *pPropertyCount < totalCount ? VK_INCOMPLETE : VK_SUCCESS; } VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) { -- GitLab From 655ca15dc33535c1a48f2b75948ff9b764bcb041 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 25 Mar 2020 18:59:40 -0700 Subject: [PATCH 0952/1255] Keep screen on when running libgui_test Input tests require the screen to be on. Looking at the recent flakes, the device may have been left in a bad state. This change explicitly turns the screen on before running all tests. Fixes: 152014889 Test: atest libgui_test (with screen turned off) Change-Id: I9c8673ffb11f6db5549911acb789e66444ea82e0 --- libs/gui/tests/AndroidTest.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/gui/tests/AndroidTest.xml b/libs/gui/tests/AndroidTest.xml index c02e020be6..5e09fff6bb 100644 --- a/libs/gui/tests/AndroidTest.xml +++ b/libs/gui/tests/AndroidTest.xml @@ -18,6 +18,10 @@


+ * AHardwareBuffer* buffer;
+ * AHardwareBuffer_allocate(..., &buffer);  // `buffer` has reference count 1
+ * jobject java_result = AHardwareBuffer_toHardwareBuffer(buffer);  // `buffer` has reference count 2.
+ * AHardwareBuffer_release(buffer); // `buffer` has reference count 1
+ * return result;  // The underlying buffer is kept alive by `java_result` and
+ *                 // will be set to 0 when it is closed on the Java side with
+ *                 // HardwareBuffer::close().
+ * 
* * Available since API level 26. */ -- GitLab From 29e1ae6598404ecdaa58b19b8c28ca2145439e31 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 9 Jul 2020 23:37:24 +0000 Subject: [PATCH 1250/1255] Avoid TREBLE_TESTING_OVERRIDE This is moved from an environmental variable to a function since getenv is problematic in multi-threaded testing environments. Bug: 156668058 Bug: 160796914 Test: N/A Change-Id: Ic90258adad95d3b3c2a6a4758c4e1b5efbedc8fd --- services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp index 96a7541919..1cea25a80f 100644 --- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp @@ -29,8 +29,8 @@ #include "SurfaceFlinger.h" // Get the name of the service... #include - #include +#include #include #include @@ -173,7 +173,7 @@ void FakeHwcEnvironment::SetUp() { property_set("debug.sf.hwc_service_name", "mock"); // This allows tests/SF to register/load a HIDL service not listed in manifest files. - setenv("TREBLE_TESTING_OVERRIDE", "true", true); + android::hardware::details::setTrebleTestingOverride(true); property_set("debug.sf.treble_testing_override", "true"); } -- GitLab From a371dfa3b8d368265e6e6d5ced55d5dce6315bee Mon Sep 17 00:00:00 2001 From: Lalit Maganti Date: Wed, 8 Jul 2020 16:37:01 +0100 Subject: [PATCH 1251/1255] sf: only look for graphics frame packets when asserting on traces Asserting on packet counts leads to extremely brittle tests as it prevent the Perfetto team from adding new service-generated packets as needed. Instead, perform all assertions on packets which have already been filtered to contain just packets of relevance to sf - namely GraphicsFrameEvent packets. (this is a cherry-pick of ag/12108746 onto rvc-dev-plus-aosp because the test failure on aosp/1355782 is affecting this branch as well). Change-Id: I0c323761acd35ca4d3b9e21c2a68d1baefdcd13a Merged-In: I0c323761acd35ca4d3b9e21c2a68d1baefdcd13a --- .../tests/unittests/FrameTracerTest.cpp | 93 ++++++++----------- 1 file changed, 37 insertions(+), 56 deletions(-) diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp index 68cb52fe87..a119e27d41 100644 --- a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp @@ -77,6 +77,22 @@ public: return tracingSession; } + std::vector readGraphicsFramePacketsBlocking( + perfetto::TracingSession* tracingSession) { + std::vector raw_trace = tracingSession->ReadTraceBlocking(); + perfetto::protos::Trace trace; + EXPECT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); + + std::vector packets; + for (const auto& packet : trace.packet()) { + if (!packet.has_graphics_frame_event()) { + continue; + } + packets.emplace_back(packet); + } + return packets; + } + std::unique_ptr mFrameTracer; FenceToFenceTimeMap fenceFactory; }; @@ -142,40 +158,29 @@ TEST_F(FrameTracerTest, canTraceAfterAddingLayer) { auto tracingSession = getTracingSessionForTest(); tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); - mFrameTracer->traceTimestamp(layerId, bufferID, frameNumber, timestamp, type, duration); // Create second trace packet to finalize the previous one. mFrameTracer->traceTimestamp(layerId, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); tracingSession->StopBlocking(); - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - EXPECT_EQ(raw_trace.size(), 0); + auto packets = readGraphicsFramePacketsBlocking(tracingSession.get()); + EXPECT_EQ(packets.size(), 0); } { auto tracingSession = getTracingSessionForTest(); tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); - mFrameTracer->traceNewLayer(layerId, layerName); mFrameTracer->traceTimestamp(layerId, bufferID, frameNumber, timestamp, type, duration); // Create second trace packet to finalize the previous one. mFrameTracer->traceTimestamp(layerId, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); tracingSession->StopBlocking(); - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - ASSERT_GT(raw_trace.size(), 0); - - perfetto::protos::Trace trace; - ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); - ASSERT_FALSE(trace.packet().empty()); - EXPECT_EQ(trace.packet().size(), 1); + auto packets = readGraphicsFramePacketsBlocking(tracingSession.get()); + EXPECT_EQ(packets.size(), 1); - const auto& packet = trace.packet().Get(0); + const auto& packet = packets[0]; ASSERT_TRUE(packet.has_timestamp()); EXPECT_EQ(packet.timestamp(), timestamp); ASSERT_TRUE(packet.has_graphics_frame_event()); @@ -205,24 +210,21 @@ TEST_F(FrameTracerTest, traceFenceTriggersOnNextTraceAfterFenceFired) { fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING); auto tracingSession = getTracingSessionForTest(); tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); // Trace. mFrameTracer->traceNewLayer(layerId, layerName); mFrameTracer->traceFence(layerId, bufferID, frameNumber, fenceTime, type); // Create extra trace packet to (hopefully not) trigger and finalize the fence packet. mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); tracingSession->StopBlocking(); - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - EXPECT_EQ(raw_trace.size(), 0); + + auto packets = readGraphicsFramePacketsBlocking(tracingSession.get()); + EXPECT_EQ(packets.size(), 0); } { auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto tracingSession = getTracingSessionForTest(); tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); mFrameTracer->traceNewLayer(layerId, layerName); mFrameTracer->traceFence(layerId, bufferID, frameNumber, fenceTime, type); const nsecs_t timestamp = systemTime(); @@ -231,15 +233,10 @@ TEST_F(FrameTracerTest, traceFenceTriggersOnNextTraceAfterFenceFired) { mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); tracingSession->StopBlocking(); - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - ASSERT_GT(raw_trace.size(), 0); + auto packets = readGraphicsFramePacketsBlocking(tracingSession.get()); + EXPECT_EQ(packets.size(), 2); // Two packets because of the extra trace made above. - perfetto::protos::Trace trace; - ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); - ASSERT_FALSE(trace.packet().empty()); - EXPECT_EQ(trace.packet().size(), 2); // Two packets because of the extra trace made above. - - const auto& packet = trace.packet().Get(1); + const auto& packet = packets[1]; ASSERT_TRUE(packet.has_timestamp()); EXPECT_EQ(packet.timestamp(), timestamp); ASSERT_TRUE(packet.has_graphics_frame_event()); @@ -266,8 +263,6 @@ TEST_F(FrameTracerTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDurat auto tracingSession = getTracingSessionForTest(); tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); mFrameTracer->traceNewLayer(layerId, layerName); // traceFence called after fence signalled. @@ -288,22 +283,17 @@ TEST_F(FrameTracerTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDurat mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); tracingSession->StopBlocking(); - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - ASSERT_GT(raw_trace.size(), 0); + auto packets = readGraphicsFramePacketsBlocking(tracingSession.get()); + EXPECT_EQ(packets.size(), 2); - perfetto::protos::Trace trace; - ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); - ASSERT_FALSE(trace.packet().empty()); - EXPECT_EQ(trace.packet().size(), 2); - - const auto& packet1 = trace.packet().Get(0); + const auto& packet1 = packets[0]; ASSERT_TRUE(packet1.has_timestamp()); EXPECT_EQ(packet1.timestamp(), signalTime1); ASSERT_TRUE(packet1.has_graphics_frame_event()); ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event()); ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns()); - const auto& packet2 = trace.packet().Get(1); + const auto& packet2 = packets[1]; ASSERT_TRUE(packet2.has_timestamp()); EXPECT_EQ(packet2.timestamp(), signalTime2); ASSERT_TRUE(packet2.has_graphics_frame_event()); @@ -323,8 +313,6 @@ TEST_F(FrameTracerTest, traceFenceOlderThanDeadline_ShouldBeIgnored) { auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); mFrameTracer->traceNewLayer(layerId, layerName); mFrameTracer->traceFence(layerId, bufferID, frameNumber, fence, type); fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime); @@ -332,8 +320,8 @@ TEST_F(FrameTracerTest, traceFenceOlderThanDeadline_ShouldBeIgnored) { mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); tracingSession->StopBlocking(); - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - EXPECT_EQ(raw_trace.size(), 0); + auto packets = readGraphicsFramePacketsBlocking(tracingSession.get()); + EXPECT_EQ(packets.size(), 0); } TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) { @@ -347,8 +335,6 @@ TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) auto tracingSession = getTracingSessionForTest(); tracingSession->StartBlocking(); - // Clean up irrelevant traces. - tracingSession->ReadTraceBlocking(); mFrameTracer->traceNewLayer(layerId, layerName); // traceFence called after fence signalled. @@ -369,15 +355,10 @@ TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED); tracingSession->StopBlocking(); - std::vector raw_trace = tracingSession->ReadTraceBlocking(); - ASSERT_GT(raw_trace.size(), 0); - - perfetto::protos::Trace trace; - ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()))); - ASSERT_FALSE(trace.packet().empty()); - EXPECT_EQ(trace.packet().size(), 2); + auto packets = readGraphicsFramePacketsBlocking(tracingSession.get()); + EXPECT_EQ(packets.size(), 2); - const auto& packet1 = trace.packet().Get(0); + const auto& packet1 = packets[0]; ASSERT_TRUE(packet1.has_timestamp()); EXPECT_EQ(packet1.timestamp(), startTime1); ASSERT_TRUE(packet1.has_graphics_frame_event()); @@ -386,7 +367,7 @@ TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event(); EXPECT_EQ(buffer_event1.duration_ns(), duration); - const auto& packet2 = trace.packet().Get(1); + const auto& packet2 = packets[1]; ASSERT_TRUE(packet2.has_timestamp()); EXPECT_EQ(packet2.timestamp(), startTime2); ASSERT_TRUE(packet2.has_graphics_frame_event()); -- GitLab From 3b8e3215a6927724e366702c03be44fffb620b26 Mon Sep 17 00:00:00 2001 From: Victor Khimenko Date: Tue, 16 Jun 2020 01:01:15 +0200 Subject: [PATCH 1252/1255] Make libarect buildable for native_bridge Also make headers available for RenderScript. Bug: http://b/153609531 Test: m libarect.native_bridge Change-Id: Iee387d19d167d8b90f4bf3fae7869ea370025b9a Merged-In: Iee387d19d167d8b90f4bf3fae7869ea370025b9a --- libs/arect/Android.bp | 2 ++ libs/nativebase/Android.bp | 2 ++ libs/nativewindow/Android.bp | 2 ++ 3 files changed, 6 insertions(+) diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp index f66673f6ad..258a4e3748 100644 --- a/libs/arect/Android.bp +++ b/libs/arect/Android.bp @@ -29,6 +29,8 @@ cc_library_static { name: "libarect", host_supported: true, vendor_available: true, + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, export_include_dirs: ["include"], target: { windows: { diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp index 9e7e4a2291..8399e8ce0a 100644 --- a/libs/nativebase/Android.bp +++ b/libs/nativebase/Android.bp @@ -16,6 +16,8 @@ cc_library_headers { name: "libnativebase_headers", vendor_available: true, host_supported: true, + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, export_include_dirs: ["include"], target: { diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp index ee006aaaba..52d73e0a56 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -25,6 +25,8 @@ cc_library_headers { name: "libnativewindow_headers", export_include_dirs: ["include"], vendor_available: true, + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, min_sdk_version: "29", } -- GitLab From 9a12a013eeca75b2a3bf49492ec6557245a6f8fc Mon Sep 17 00:00:00 2001 From: Victor Khimenko Date: Fri, 3 Jul 2020 00:06:50 +0200 Subject: [PATCH 1253/1255] Make libbinder buildable for native_bridge Bug: http://b/153609531 Test: m libbinder.native_bridge Change-Id: I3955d9b54aaea7a6b5b9bde81a336908a849cde6 Merged-In: I3955d9b54aaea7a6b5b9bde81a336908a849cde6 --- libs/binder/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index db4aba8640..b24a577588 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -17,6 +17,8 @@ cc_library_headers { export_include_dirs: ["include"], vendor_available: true, host_supported: true, + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, header_libs: [ "libbase_headers", @@ -62,6 +64,8 @@ cc_library { }, double_loadable: true, host_supported: true, + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, // TODO(b/31559095): get headers from bionic on host include_dirs: [ -- GitLab From 6dd9fd763a385adba96c8de6d8919c5b61991e7d Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan Date: Fri, 19 Jun 2020 14:57:06 -0700 Subject: [PATCH 1254/1255] Trace acquire fence at queue time instead of at latch time For apps that do not use frame pacing, there is a chance that they keep dequeueing and queueing a buffer before the SF wake up. In this case, the older queue item gets dropped by SurfaceFlinger if the expected present time of the later submitted buffer gets satisfied. The GPU work still happens for all the submissions however. The acquire fence gets signalled whenever GPU is done with such work. We currently do not trace this acquirefence and instead, we trace only the one that gets latched by flinger. This behavior can break the new phases UI where the slices are formed based on certain assumptions. This change fixes that by tracing AcquireFence at queue time instead of latch time. Test: Take a trace with blur enabled. Bug: 159472563 Change-Id: I329a11c53dc18eb5d03df096c19dba5c9704ea4a (cherry picked from commit f1e87abccf9b394ab903579c5e0b6ffe3d5da7b4) --- services/surfaceflinger/BufferQueueLayer.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 07be7916ee..6e4235e409 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -324,9 +324,6 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t } uint64_t bufferID = mQueueItems[0].mGraphicBuffer->getId(); - mFlinger->mFrameTracer->traceFence(layerId, bufferID, currentFrameNumber, - mQueueItems[0].mFenceTime, - FrameTracer::FrameEvent::ACQUIRE_FENCE); mFlinger->mTimeStats->setLatchTime(layerId, currentFrameNumber, latchTime); mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, currentFrameNumber, latchTime, FrameTracer::FrameEvent::LATCH); @@ -393,8 +390,12 @@ void BufferQueueLayer::onFrameCancelled(const uint64_t bufferId) { void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { const int32_t layerId = getSequence(); - mFlinger->mFrameTracer->traceTimestamp(layerId, item.mGraphicBuffer->getId(), item.mFrameNumber, - systemTime(), FrameTracer::FrameEvent::QUEUE); + const uint64_t bufferId = item.mGraphicBuffer->getId(); + mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, item.mFrameNumber, systemTime(), + FrameTracer::FrameEvent::QUEUE); + mFlinger->mFrameTracer->traceFence(layerId, bufferId, item.mFrameNumber, + std::make_shared(item.mFence), + FrameTracer::FrameEvent::ACQUIRE_FENCE); ATRACE_CALL(); // Add this buffer from our internal queue tracker @@ -460,8 +461,12 @@ void BufferQueueLayer::onFrameReplaced(const BufferItem& item) { } const int32_t layerId = getSequence(); - mFlinger->mFrameTracer->traceTimestamp(layerId, item.mGraphicBuffer->getId(), item.mFrameNumber, - systemTime(), FrameTracer::FrameEvent::QUEUE); + const uint64_t bufferId = item.mGraphicBuffer->getId(); + mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, item.mFrameNumber, systemTime(), + FrameTracer::FrameEvent::QUEUE); + mFlinger->mFrameTracer->traceFence(layerId, bufferId, item.mFrameNumber, + std::make_shared(item.mFence), + FrameTracer::FrameEvent::ACQUIRE_FENCE); mConsumer->onBufferAvailable(item); } -- GitLab From df8a0739f7ab42ce59e2370867d26ed2793b6228 Mon Sep 17 00:00:00 2001 From: Stan Iliev Date: Thu, 16 Jul 2020 17:09:57 -0400 Subject: [PATCH 1255/1255] Fix TextureView calling eglCreateImage with a destructed buffer Fix an issue with hardware buffer passed from the SurfaceTexture being destroyed before an SkImage is created. This CL is matched by a change in frameworks/base I4d121f087fc842ce317745e7b7e2656f80a52b7d. Test: Ran TextureView CTS tests and a few apps that use TextureView. Test: Fix verified by partner Mediatek Bug: 160930384 Bug: 152781833 Bug: 153045874 Bug: 156047948 Bug: 160514803 Bug: 155545635 Bug: 155171712 Change-Id: I2e025e683052168546f2e271a20a857b1e556b64 (cherry picked from commit 0702f1d077bab79c76a4889d7859abbaabf06b81) --- .../include/surfacetexture/surface_texture_platform.h | 2 ++ libs/nativedisplay/surfacetexture/surface_texture.cpp | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h index e2d036bfb0..f3716674c5 100644 --- a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h +++ b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h @@ -79,6 +79,8 @@ typedef int (*ASurfaceTexture_fenceWait)(int fence, void* fencePassThroughHandle /** * ASurfaceTexture_dequeueBuffer returns the next available AHardwareBuffer. + * The caller gets ownership of the buffer and need to release it with + * AHardwareBuffer_release. */ AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlotid, android_dataspace* outDataspace, diff --git a/libs/nativedisplay/surfacetexture/surface_texture.cpp b/libs/nativedisplay/surfacetexture/surface_texture.cpp index d1bcd8d1b1..ebe4484873 100644 --- a/libs/nativedisplay/surfacetexture/surface_texture.cpp +++ b/libs/nativedisplay/surfacetexture/surface_texture.cpp @@ -208,7 +208,15 @@ AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlot *outNewContent = true; } } while (buffer.get() && (!queueEmpty)); - return reinterpret_cast(buffer.get()); + AHardwareBuffer* result = nullptr; + if (buffer.get()) { + result = buffer->toAHardwareBuffer(); + // add a reference to keep the hardware buffer alive, even if + // BufferQueueProducer is disconnected. This is needed, because + // sp reference is destroyed at the end of this function. + AHardwareBuffer_acquire(result); + } + return result; } } // namespace android -- GitLab