diff options
83 files changed, 1425 insertions, 636 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING index 9c0116957d..07d16f7a4d 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -4,9 +4,6 @@ "name": "SurfaceFlinger_test", "options": [ { - "include-filter": "*" - }, - { // TODO(b/305717998): Deflake and re-enable "exclude-filter": "*ChildLayerTest*" } @@ -23,12 +20,7 @@ ], "hwasan-postsubmit": [ { - "name": "SurfaceFlinger_test", - "options": [ - { - "include-filter": "*" - } - ] + "name": "SurfaceFlinger_test" } ] } diff --git a/data/etc/android.hardware.xr.input.controller.xml b/data/etc/android.hardware.xr.input.controller.xml new file mode 100644 index 0000000000..1fb8b41004 --- /dev/null +++ b/data/etc/android.hardware.xr.input.controller.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard feature to indicate the device supports + input from XR controllers. --> +<permissions> + <feature name="android.hardware.xr.input.controller" /> +</permissions> diff --git a/data/etc/android.hardware.xr.input.eye_tracking.xml b/data/etc/android.hardware.xr.input.eye_tracking.xml new file mode 100644 index 0000000000..8c6c2ed7a6 --- /dev/null +++ b/data/etc/android.hardware.xr.input.eye_tracking.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard feature to indicate the device supports + input from an XR user's eyes. --> +<permissions> + <feature name="android.hardware.xr.input.eye_tracking" /> +</permissions> diff --git a/data/etc/android.hardware.xr.input.hand_tracking.xml b/data/etc/android.hardware.xr.input.hand_tracking.xml new file mode 100644 index 0000000000..6de3bee033 --- /dev/null +++ b/data/etc/android.hardware.xr.input.hand_tracking.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard feature to indicate the device supports + input from an XR user's hands. --> +<permissions> + <feature name="android.hardware.xr.input.hand_tracking" /> +</permissions> diff --git a/data/etc/android.software.xr.api.openxr-1_0.xml b/data/etc/android.software.xr.api.openxr-1_0.xml new file mode 100644 index 0000000000..71c4a94980 --- /dev/null +++ b/data/etc/android.software.xr.api.openxr-1_0.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard feature to indicate the device has a runtime + that supports OpenXR 1.0 (0x00010000). --> +<permissions> + <feature name="android.software.xr.api.openxr" version="65536" /> +</permissions> diff --git a/data/etc/android.software.xr.api.openxr-1_1.xml b/data/etc/android.software.xr.api.openxr-1_1.xml new file mode 100644 index 0000000000..45c106523d --- /dev/null +++ b/data/etc/android.software.xr.api.openxr-1_1.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard feature to indicate the device has a runtime + that supports OpenXR 1.1 (0x00010001). --> +<permissions> + <feature name="android.software.xr.api.openxr" version="65537" /> +</permissions> diff --git a/data/etc/android.software.xr.api.openxr-1_2.xml b/data/etc/android.software.xr.api.openxr-1_2.xml new file mode 100644 index 0000000000..ba11b8d498 --- /dev/null +++ b/data/etc/android.software.xr.api.openxr-1_2.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard feature to indicate the device has a runtime + that supports OpenXR 1.2 (0x00010002). --> +<permissions> + <feature name="android.software.xr.api.openxr" version="65538" /> +</permissions> diff --git a/data/etc/android.software.xr.api.spatial-1.xml b/data/etc/android.software.xr.api.spatial-1.xml new file mode 100644 index 0000000000..ce425aa526 --- /dev/null +++ b/data/etc/android.software.xr.api.spatial-1.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard feature to indicate the device has a runtime + that supports Android XR Spatial APIs, version 1. --> +<permissions> + <feature name="android.software.xr.api.spatial" version="1" /> +</permissions> diff --git a/include/input/Resampler.h b/include/input/Resampler.h index 47519c2cfd..6d95ca7e86 100644 --- a/include/input/Resampler.h +++ b/include/input/Resampler.h @@ -16,10 +16,14 @@ #pragma once +#include <array> #include <chrono> +#include <iterator> #include <optional> #include <vector> +#include <android-base/logging.h> +#include <ftl/mixins.h> #include <input/Input.h> #include <input/InputTransport.h> #include <input/RingBuffer.h> @@ -79,13 +83,127 @@ private: PointerCoords coords; }; + /** + * Container that stores pointers as an associative array, supporting O(1) lookup by pointer id, + * as well as forward iteration in the order in which the pointer or pointers were inserted in + * the container. PointerMap has a maximum capacity equal to MAX_POINTERS. + */ + class PointerMap { + public: + struct PointerId : ftl::DefaultConstructible<PointerId, int32_t>, + ftl::Equatable<PointerId> { + using DefaultConstructible::DefaultConstructible; + }; + + /** + * Custom iterator to enable use of range-based for loops. + */ + template <typename T> + class iterator { + public: + using iterator_category = std::forward_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = T*; + using reference = T&; + + explicit iterator(pointer element) : mElement{element} {} + + friend bool operator==(const iterator& lhs, const iterator& rhs) { + return lhs.mElement == rhs.mElement; + } + + friend bool operator!=(const iterator& lhs, const iterator& rhs) { + return !(lhs == rhs); + } + + iterator operator++() { + ++mElement; + return *this; + } + + reference operator*() const { return *mElement; } + + private: + pointer mElement; + }; + + PointerMap() { + idToIndex.fill(std::nullopt); + for (Pointer& pointer : pointers) { + pointer.properties.clear(); + pointer.coords.clear(); + } + } + + /** + * Forward iterators to traverse the pointers in `pointers`. The order of the pointers is + * determined by the order in which they were inserted (not by id). + */ + iterator<Pointer> begin() { return iterator<Pointer>{&pointers[0]}; } + + iterator<const Pointer> begin() const { return iterator<const Pointer>{&pointers[0]}; } + + iterator<Pointer> end() { return iterator<Pointer>{&pointers[nextPointerIndex]}; } + + iterator<const Pointer> end() const { + return iterator<const Pointer>{&pointers[nextPointerIndex]}; + } + + /** + * Inserts the given pointer into the PointerMap. Precondition: The current number of + * contained pointers must be less than MAX_POINTERS when this function is called. It + * fatally logs if the user tries to insert more than MAX_POINTERS, or if pointer id is out + * of bounds. + */ + void insert(const Pointer& pointer) { + LOG_IF(FATAL, nextPointerIndex >= pointers.size()) + << "Cannot insert more than " << MAX_POINTERS << " in PointerMap."; + LOG_IF(FATAL, (pointer.properties.id < 0) || (pointer.properties.id > MAX_POINTER_ID)) + << "Invalid pointer id."; + idToIndex[pointer.properties.id] = std::optional<size_t>{nextPointerIndex}; + pointers[nextPointerIndex] = pointer; + ++nextPointerIndex; + } + + /** + * Returns the pointer associated with the provided id if it exists. + * Otherwise, std::nullopt is returned. + */ + std::optional<Pointer> find(PointerId id) const { + const int32_t idValue = ftl::to_underlying(id); + LOG_IF(FATAL, (idValue < 0) || (idValue > MAX_POINTER_ID)) << "Invalid pointer id."; + const std::optional<size_t> index = idToIndex[idValue]; + return index.has_value() ? std::optional{pointers[*index]} : std::nullopt; + } + + private: + /** + * The index at which a pointer is inserted in `pointers`. Likewise, it represents the + * number of pointers in PointerMap. + */ + size_t nextPointerIndex{0}; + + /** + * Sequentially stores pointers. Each pointer's position is determined by the value of + * nextPointerIndex at insertion time. + */ + std::array<Pointer, MAX_POINTERS + 1> pointers; + + /** + * Maps each pointer id to its associated index in pointers. If no pointer with the id + * exists in pointers, the mapped value is std::nullopt. + */ + std::array<std::optional<size_t>, MAX_POINTER_ID + 1> idToIndex; + }; + struct Sample { std::chrono::nanoseconds eventTime; - std::vector<Pointer> pointers; + PointerMap pointerMap; std::vector<PointerCoords> asPointerCoords() const { std::vector<PointerCoords> pointersCoords; - for (const Pointer& pointer : pointers) { + for (const Pointer& pointer : pointerMap) { pointersCoords.push_back(pointer.coords); } return pointersCoords; @@ -100,13 +218,12 @@ private: RingBuffer<Sample> mLatestSamples{/*capacity=*/2}; /** - * Latest sample in mLatestSamples after resampling motion event. Used to compare if a pointer - * does not move between samples. + * Latest sample in mLatestSamples after resampling motion event. */ std::optional<Sample> mLastRealSample; /** - * Latest prediction. Used to overwrite motion event samples if a set of conditions is met. + * Latest prediction. That is, the latest extrapolated sample. */ std::optional<Sample> mPreviousPrediction; @@ -134,12 +251,12 @@ private: bool canInterpolate(const InputMessage& futureSample) const; /** - * Returns a sample interpolated between the latest sample of mLatestSamples and futureSample, + * Returns a sample interpolated between the latest sample of mLatestSamples and futureMessage, * if the conditions from canInterpolate are satisfied. Otherwise, returns nullopt. * mLatestSamples must have at least one sample when attemptInterpolation is called. */ std::optional<Sample> attemptInterpolation(std::chrono::nanoseconds resampleTime, - const InputMessage& futureSample) const; + const InputMessage& futureMessage) const; /** * Checks if there are necessary conditions to extrapolate. That is, there are at least two @@ -156,7 +273,8 @@ private: std::optional<Sample> attemptExtrapolation(std::chrono::nanoseconds resampleTime) const; /** - * Iterates through motion event samples, and calls overwriteStillPointers on each sample. + * Iterates through motion event samples, and replaces real coordinates with resampled + * coordinates to avoid jerkiness in certain conditions. */ void overwriteMotionEventSamples(MotionEvent& motionEvent) const; @@ -174,4 +292,5 @@ private: inline static void addSampleToMotionEvent(const Sample& sample, MotionEvent& motionEvent); }; + } // namespace android diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 422c57bc87..4b531345b0 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -664,6 +664,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eShadowRadiusChanged; shadowRadius = other.shadowRadius; } + if (other.what & eLutsChanged) { + what |= eLutsChanged; + luts = other.luts; + } if (other.what & eDefaultFrameRateCompatibilityChanged) { what |= eDefaultFrameRateCompatibilityChanged; defaultFrameRateCompatibility = other.defaultFrameRateCompatibility; @@ -821,6 +825,8 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eColorSpaceAgnosticChanged, other, colorSpaceAgnostic); CHECK_DIFF(diff, eDimmingEnabledChanged, other, dimmingEnabled); if (other.what & eBufferReleaseChannelChanged) diff |= eBufferReleaseChannelChanged; + if (other.what & eLutsChanged) diff |= eLutsChanged; + return diff; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index eeea80fa82..a93fc926c2 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -29,6 +29,7 @@ #include <android/gui/IWindowInfosListener.h> #include <android/gui/TrustedPresentationThresholds.h> #include <android/os/IInputConstants.h> +#include <gui/DisplayLuts.h> #include <gui/FrameRateUtils.h> #include <gui/TraceUtils.h> #include <utils/Errors.h> @@ -1940,15 +1941,19 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesir } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLuts( - const sp<SurfaceControl>& sc, const base::unique_fd& /*lutFd*/, - const std::vector<int32_t>& /*offsets*/, const std::vector<int32_t>& /*dimensions*/, - const std::vector<int32_t>& /*sizes*/, const std::vector<int32_t>& /*samplingKeys*/) { + const sp<SurfaceControl>& sc, const base::unique_fd& lutFd, + const std::vector<int32_t>& offsets, const std::vector<int32_t>& dimensions, + const std::vector<int32_t>& sizes, const std::vector<int32_t>& samplingKeys) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } - // TODO (b/329472856): update layer_state_t for lut(s) + + s->luts = std::make_shared<gui::DisplayLuts>(base::unique_fd(dup(lutFd.get())), offsets, + dimensions, sizes, samplingKeys); + s->what |= layer_state_t::eLutsChanged; + registerSurfaceControlForCallback(sc); return *this; } diff --git a/libs/gui/aidl/android/gui/Lut.aidl b/libs/gui/aidl/android/gui/Lut.aidl deleted file mode 100644 index a06e521789..0000000000 --- a/libs/gui/aidl/android/gui/Lut.aidl +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2024 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.gui; - -import android.gui.LutProperties; -import android.os.ParcelFileDescriptor; - -/** - * This mirrors aidl::android::hardware::graphics::composer3::Lut definition - * @hide - */ -parcelable Lut { - @nullable ParcelFileDescriptor pfd; - - LutProperties lutProperties; -}
\ No newline at end of file diff --git a/libs/gui/aidl/android/gui/LutProperties.aidl b/libs/gui/aidl/android/gui/LutProperties.aidl index 561e0c069c..87b878c1ca 100644 --- a/libs/gui/aidl/android/gui/LutProperties.aidl +++ b/libs/gui/aidl/android/gui/LutProperties.aidl @@ -25,7 +25,7 @@ parcelable LutProperties { enum Dimension { ONE_D = 1, THREE_D = 3 } Dimension dimension; - long size; + int size; @Backing(type="int") enum SamplingKey { RGB, MAX_RGB } SamplingKey[] samplingKeys; diff --git a/libs/gui/include/gui/DisplayLuts.h b/libs/gui/include/gui/DisplayLuts.h new file mode 100644 index 0000000000..16a360dcee --- /dev/null +++ b/libs/gui/include/gui/DisplayLuts.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 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 <android-base/unique_fd.h> +#include <vector> + +namespace android::gui { + +struct DisplayLuts { +public: + struct Entry { + int32_t dimension; + int32_t size; + int32_t samplingKey; + }; + + DisplayLuts() {} + + DisplayLuts(base::unique_fd lutfd, std::vector<int32_t> lutoffsets, + std::vector<int32_t> lutdimensions, std::vector<int32_t> lutsizes, + std::vector<int32_t> lutsamplingKeys) { + fd = std::move(lutfd); + offsets = lutoffsets; + lutProperties.reserve(offsets.size()); + for (size_t i = 0; i < lutoffsets.size(); i++) { + Entry entry{lutdimensions[i], lutsizes[i], lutsamplingKeys[i]}; + lutProperties.emplace_back(entry); + } + } + + base::unique_fd& getLutFileDescriptor() { return fd; } + + std::vector<Entry> lutProperties; + std::vector<int32_t> offsets; + +private: + base::unique_fd fd; +}; // struct DisplayLuts + +} // namespace android::gui
\ No newline at end of file diff --git a/libs/gui/include/gui/Flags.h b/libs/gui/include/gui/Flags.h index 735375a1e7..34350d2c91 100644 --- a/libs/gui/include/gui/Flags.h +++ b/libs/gui/include/gui/Flags.h @@ -17,8 +17,20 @@ #pragma once #include <com_android_graphics_libgui_flags.h> +#include <gui/IGraphicBufferProducer.h> +#include <gui/Surface.h> #define WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES \ (COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CAMERA3_AND_PROCESSORS) && \ COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) && \ - COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS))
\ No newline at end of file + COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)) + +#define WB_LIBCAMERASERVICE_WITH_DEPENDENCIES \ + (WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES && \ + COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_LIBCAMERASERVICE)) + +#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES +typedef android::Surface SurfaceType; +#else +typedef android::IGraphicBufferProducer SurfaceType; +#endif
\ No newline at end of file diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 00065c81d8..6bfeaec26a 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -26,6 +26,7 @@ #include <android/gui/LayerCaptureArgs.h> #include <android/gui/TrustedPresentationThresholds.h> #include <android/native_window.h> +#include <gui/DisplayLuts.h> #include <gui/IGraphicBufferProducer.h> #include <gui/ITransactionCompletedListener.h> #include <math/mat4.h> @@ -184,6 +185,7 @@ struct layer_state_t { eCachingHintChanged = 0x00000200, eDimmingEnabledChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, + eLutsChanged = 0x00001000, eBufferCropChanged = 0x00002000, eRelativeLayerChanged = 0x00004000, eReparent = 0x00008000, @@ -255,7 +257,7 @@ struct layer_state_t { layer_state_t::eTransformToDisplayInverseChanged | layer_state_t::eTransparentRegionChanged | layer_state_t::eExtendedRangeBrightnessChanged | - layer_state_t::eDesiredHdrHeadroomChanged; + layer_state_t::eDesiredHdrHeadroomChanged | layer_state_t::eLutsChanged; // Content updates. static constexpr uint64_t CONTENT_CHANGES = layer_state_t::BUFFER_CHANGES | @@ -416,6 +418,8 @@ struct layer_state_t { TrustedPresentationListener trustedPresentationListener; std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> bufferReleaseChannel; + + std::shared_ptr<gui::DisplayLuts> luts; }; class ComposerState { diff --git a/libs/gui/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h index 7ddac8139a..7c762d3869 100644 --- a/libs/gui/include/gui/view/Surface.h +++ b/libs/gui/include/gui/view/Surface.h @@ -24,7 +24,9 @@ #include <binder/IBinder.h> #include <binder/Parcelable.h> +#include <gui/Flags.h> #include <gui/IGraphicBufferProducer.h> +#include <gui/Surface.h> namespace android { @@ -46,6 +48,14 @@ class Surface : public Parcelable { sp<IGraphicBufferProducer> graphicBufferProducer; sp<IBinder> surfaceControlHandle; +#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES + // functions used to convert to a parcelable Surface so it can be passed over binder. + static Surface fromSurface(const sp<android::Surface>& surface); + sp<android::Surface> toSurface() const; + + status_t getUniqueId(/* out */ uint64_t* id) const; +#endif + virtual status_t writeToParcel(Parcel* parcel) const override; virtual status_t readFromParcel(const Parcel* parcel) override; diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp index 84c2a6ac71..9f57923886 100644 --- a/libs/gui/view/Surface.cpp +++ b/libs/gui/view/Surface.cpp @@ -121,6 +121,38 @@ String16 Surface::readMaybeEmptyString16(const Parcel* parcel) { return str.value_or(String16()); } +#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES +Surface Surface::fromSurface(const sp<android::Surface>& surface) { + if (surface == nullptr) { + ALOGE("%s: Error: view::Surface::fromSurface failed due to null surface.", __FUNCTION__); + return Surface(); + } + Surface s; + s.name = String16(surface->getConsumerName()); + s.graphicBufferProducer = surface->getIGraphicBufferProducer(); + s.surfaceControlHandle = surface->getSurfaceControlHandle(); + return s; +} + +sp<android::Surface> Surface::toSurface() const { + if (graphicBufferProducer == nullptr) return nullptr; + return new android::Surface(graphicBufferProducer, false, surfaceControlHandle); +} + +status_t Surface::getUniqueId(uint64_t* out_id) const { + if (graphicBufferProducer == nullptr) { + ALOGE("android::viewSurface::getUniqueId() failed because it's not initialized."); + return UNEXPECTED_NULL; + } + status_t status = graphicBufferProducer->getUniqueId(out_id); + if (status != OK) { + ALOGE("android::viewSurface::getUniqueId() failed."); + return status; + } + return OK; +} +#endif + std::string Surface::toString() const { std::stringstream out; out << name; diff --git a/libs/input/Resampler.cpp b/libs/input/Resampler.cpp index e2cc6fb174..056db093d1 100644 --- a/libs/input/Resampler.cpp +++ b/libs/input/Resampler.cpp @@ -18,6 +18,7 @@ #include <algorithm> #include <chrono> +#include <iomanip> #include <ostream> #include <android-base/logging.h> @@ -37,6 +38,11 @@ const bool IS_DEBUGGABLE_BUILD = true; #endif +/** + * Log debug messages about timestamp and coordinates of event resampling. + * Enable this via "adb shell setprop log.tag.LegacyResamplerResampling DEBUG" + * (requires restart) + */ bool debugResampling() { if (!IS_DEBUGGABLE_BUILD) { static const bool DEBUG_TRANSPORT_RESAMPLING = @@ -107,46 +113,44 @@ void LegacyResampler::updateLatestSamples(const MotionEvent& motionEvent) { const size_t latestIndex = numSamples - 1; const size_t secondToLatestIndex = (latestIndex > 0) ? (latestIndex - 1) : 0; for (size_t sampleIndex = secondToLatestIndex; sampleIndex < numSamples; ++sampleIndex) { - std::vector<Pointer> pointers; - const size_t numPointers = motionEvent.getPointerCount(); - for (size_t pointerIndex = 0; pointerIndex < numPointers; ++pointerIndex) { - pointers.push_back(Pointer{*(motionEvent.getPointerProperties(pointerIndex)), - *(motionEvent.getHistoricalRawPointerCoords(pointerIndex, - sampleIndex))}); + PointerMap pointerMap; + for (size_t pointerIndex = 0; pointerIndex < motionEvent.getPointerCount(); + ++pointerIndex) { + pointerMap.insert(Pointer{*(motionEvent.getPointerProperties(pointerIndex)), + *(motionEvent.getHistoricalRawPointerCoords(pointerIndex, + sampleIndex))}); } mLatestSamples.pushBack( - Sample{nanoseconds{motionEvent.getHistoricalEventTime(sampleIndex)}, pointers}); + Sample{nanoseconds{motionEvent.getHistoricalEventTime(sampleIndex)}, pointerMap}); } } LegacyResampler::Sample LegacyResampler::messageToSample(const InputMessage& message) { - std::vector<Pointer> pointers; + PointerMap pointerMap; for (uint32_t i = 0; i < message.body.motion.pointerCount; ++i) { - pointers.push_back(Pointer{message.body.motion.pointers[i].properties, - message.body.motion.pointers[i].coords}); + pointerMap.insert(Pointer{message.body.motion.pointers[i].properties, + message.body.motion.pointers[i].coords}); } - return Sample{nanoseconds{message.body.motion.eventTime}, pointers}; + return Sample{nanoseconds{message.body.motion.eventTime}, pointerMap}; } bool LegacyResampler::pointerPropertiesResampleable(const Sample& target, const Sample& auxiliary) { - if (target.pointers.size() > auxiliary.pointers.size()) { - LOG_IF(INFO, debugResampling()) - << "Not resampled. Auxiliary sample has fewer pointers than target sample."; - return false; - } - for (size_t i = 0; i < target.pointers.size(); ++i) { - if (target.pointers[i].properties.id != auxiliary.pointers[i].properties.id) { - LOG_IF(INFO, debugResampling()) << "Not resampled. Pointer ID mismatch."; + for (const Pointer& pointer : target.pointerMap) { + const std::optional<Pointer> auxiliaryPointer = + auxiliary.pointerMap.find(PointerMap::PointerId{pointer.properties.id}); + if (!auxiliaryPointer.has_value()) { + LOG_IF(INFO, debugResampling()) + << "Not resampled. Auxiliary sample does not contain all pointers from target."; return false; } - if (target.pointers[i].properties.toolType != auxiliary.pointers[i].properties.toolType) { + if (pointer.properties.toolType != auxiliaryPointer->properties.toolType) { LOG_IF(INFO, debugResampling()) << "Not resampled. Pointer ToolType mismatch."; return false; } - if (!canResampleTool(target.pointers[i].properties.toolType)) { + if (!canResampleTool(pointer.properties.toolType)) { LOG_IF(INFO, debugResampling()) << "Not resampled. Cannot resample " - << ftl::enum_string(target.pointers[i].properties.toolType) << " ToolType."; + << ftl::enum_string(pointer.properties.toolType) << " ToolType."; return false; } } @@ -166,35 +170,40 @@ bool LegacyResampler::canInterpolate(const InputMessage& message) const { const nanoseconds delta = futureSample.eventTime - pastSample.eventTime; if (delta < RESAMPLE_MIN_DELTA) { - LOG_IF(INFO, debugResampling()) << "Not resampled. Delta is too small: " << delta << "ns."; + LOG_IF(INFO, debugResampling()) + << "Not resampled. Delta is too small: " << std::setprecision(3) + << std::chrono::duration<double, std::milli>{delta}.count() << "ms"; return false; } return true; } std::optional<LegacyResampler::Sample> LegacyResampler::attemptInterpolation( - nanoseconds resampleTime, const InputMessage& futureSample) const { - if (!canInterpolate(futureSample)) { + nanoseconds resampleTime, const InputMessage& futureMessage) const { + if (!canInterpolate(futureMessage)) { return std::nullopt; } LOG_IF(FATAL, mLatestSamples.empty()) << "Not resampled. mLatestSamples must not be empty to interpolate."; const Sample& pastSample = *(mLatestSamples.end() - 1); + const Sample& futureSample = messageToSample(futureMessage); - const nanoseconds delta = - nanoseconds{futureSample.body.motion.eventTime} - pastSample.eventTime; + const nanoseconds delta = nanoseconds{futureSample.eventTime} - pastSample.eventTime; const float alpha = - std::chrono::duration<float, std::milli>(resampleTime - pastSample.eventTime) / delta; - - std::vector<Pointer> resampledPointers; - for (size_t i = 0; i < pastSample.pointers.size(); ++i) { - const PointerCoords& resampledCoords = - calculateResampledCoords(pastSample.pointers[i].coords, - futureSample.body.motion.pointers[i].coords, alpha); - resampledPointers.push_back(Pointer{pastSample.pointers[i].properties, resampledCoords}); + std::chrono::duration<float, std::nano>(resampleTime - pastSample.eventTime) / delta; + + PointerMap resampledPointerMap; + for (const Pointer& pointer : pastSample.pointerMap) { + if (std::optional<Pointer> futureSamplePointer = + futureSample.pointerMap.find(PointerMap::PointerId{pointer.properties.id}); + futureSamplePointer.has_value()) { + const PointerCoords& resampledCoords = + calculateResampledCoords(pointer.coords, futureSamplePointer->coords, alpha); + resampledPointerMap.insert(Pointer{pointer.properties, resampledCoords}); + } } - return Sample{resampleTime, resampledPointers}; + return Sample{resampleTime, resampledPointerMap}; } bool LegacyResampler::canExtrapolate() const { @@ -212,10 +221,14 @@ bool LegacyResampler::canExtrapolate() const { const nanoseconds delta = presentSample.eventTime - pastSample.eventTime; if (delta < RESAMPLE_MIN_DELTA) { - LOG_IF(INFO, debugResampling()) << "Not resampled. Delta is too small: " << delta << "ns."; + LOG_IF(INFO, debugResampling()) + << "Not resampled. Delta is too small: " << std::setprecision(3) + << std::chrono::duration<double, std::milli>{delta}.count() << "ms"; return false; } else if (delta > RESAMPLE_MAX_DELTA) { - LOG_IF(INFO, debugResampling()) << "Not resampled. Delta is too large: " << delta << "ns."; + LOG_IF(INFO, debugResampling()) + << "Not resampled. Delta is too large: " << std::setprecision(3) + << std::chrono::duration<double, std::milli>{delta}.count() << "ms"; return false; } return true; @@ -241,20 +254,28 @@ std::optional<LegacyResampler::Sample> LegacyResampler::attemptExtrapolation( (resampleTime > farthestPrediction) ? (farthestPrediction) : (resampleTime); LOG_IF(INFO, debugResampling() && newResampleTime == farthestPrediction) << "Resample time is too far in the future. Adjusting prediction from " - << (resampleTime - presentSample.eventTime) << " to " - << (farthestPrediction - presentSample.eventTime) << "ns."; + << std::setprecision(3) + << std::chrono::duration<double, std::milli>{resampleTime - presentSample.eventTime} + .count() + << "ms to " + << std::chrono::duration<double, std::milli>{farthestPrediction - + presentSample.eventTime} + .count() + << "ms"; const float alpha = - std::chrono::duration<float, std::milli>(newResampleTime - pastSample.eventTime) / - delta; - - std::vector<Pointer> resampledPointers; - for (size_t i = 0; i < presentSample.pointers.size(); ++i) { - const PointerCoords& resampledCoords = - calculateResampledCoords(pastSample.pointers[i].coords, - presentSample.pointers[i].coords, alpha); - resampledPointers.push_back(Pointer{presentSample.pointers[i].properties, resampledCoords}); + std::chrono::duration<float, std::nano>(newResampleTime - pastSample.eventTime) / delta; + + PointerMap resampledPointerMap; + for (const Pointer& pointer : presentSample.pointerMap) { + if (std::optional<Pointer> pastSamplePointer = + pastSample.pointerMap.find(PointerMap::PointerId{pointer.properties.id}); + pastSamplePointer.has_value()) { + const PointerCoords& resampledCoords = + calculateResampledCoords(pastSamplePointer->coords, pointer.coords, alpha); + resampledPointerMap.insert(Pointer{pointer.properties, resampledCoords}); + } } - return Sample{newResampleTime, resampledPointers}; + return Sample{newResampleTime, resampledPointerMap}; } inline void LegacyResampler::addSampleToMotionEvent(const Sample& sample, @@ -267,6 +288,12 @@ nanoseconds LegacyResampler::getResampleLatency() const { return RESAMPLE_LATENCY; } +/** + * The resampler is unaware of ACTION_DOWN. Thus, it needs to constantly check for pointer IDs + * occurrences. This problem could be fixed if the resampler has access to the entire stream of + * MotionEvent actions. That way, both ACTION_DOWN and ACTION_UP will be visible; therefore, + * facilitating pointer tracking between samples. + */ void LegacyResampler::overwriteMotionEventSamples(MotionEvent& motionEvent) const { const size_t numSamples = motionEvent.getHistorySize() + 1; for (size_t sampleIndex = 0; sampleIndex < numSamples; ++sampleIndex) { @@ -276,34 +303,59 @@ void LegacyResampler::overwriteMotionEventSamples(MotionEvent& motionEvent) cons } void LegacyResampler::overwriteStillPointers(MotionEvent& motionEvent, size_t sampleIndex) const { + if (!mLastRealSample.has_value() || !mPreviousPrediction.has_value()) { + LOG_IF(INFO, debugResampling()) << "Still pointers not overwritten. Not enough data."; + return; + } for (size_t pointerIndex = 0; pointerIndex < motionEvent.getPointerCount(); ++pointerIndex) { + const std::optional<Pointer> lastRealPointer = mLastRealSample->pointerMap.find( + PointerMap::PointerId{motionEvent.getPointerId(pointerIndex)}); + const std::optional<Pointer> previousPointer = mPreviousPrediction->pointerMap.find( + PointerMap::PointerId{motionEvent.getPointerId(pointerIndex)}); + // This could happen because resampler only receives ACTION_MOVE events. + if (!lastRealPointer.has_value() || !previousPointer.has_value()) { + continue; + } const PointerCoords& pointerCoords = *(motionEvent.getHistoricalRawPointerCoords(pointerIndex, sampleIndex)); - if (equalXY(mLastRealSample->pointers[pointerIndex].coords, pointerCoords)) { + if (equalXY(pointerCoords, lastRealPointer->coords)) { LOG_IF(INFO, debugResampling()) << "Pointer ID: " << motionEvent.getPointerId(pointerIndex) << " did not move. Overwriting its coordinates from " << pointerCoords << " to " - << mLastRealSample->pointers[pointerIndex].coords; + << previousPointer->coords; setMotionEventPointerCoords(motionEvent, sampleIndex, pointerIndex, - mPreviousPrediction->pointers[pointerIndex].coords); + previousPointer->coords); } } } void LegacyResampler::overwriteOldPointers(MotionEvent& motionEvent, size_t sampleIndex) const { if (!mPreviousPrediction.has_value()) { + LOG_IF(INFO, debugResampling()) << "Old sample not overwritten. Not enough data."; return; } if (nanoseconds{motionEvent.getHistoricalEventTime(sampleIndex)} < mPreviousPrediction->eventTime) { LOG_IF(INFO, debugResampling()) << "Motion event sample older than predicted sample. Overwriting event time from " - << motionEvent.getHistoricalEventTime(sampleIndex) << "ns to " - << mPreviousPrediction->eventTime.count() << "ns."; + << std::setprecision(3) + << std::chrono::duration<double, + std::milli>{nanoseconds{motionEvent.getHistoricalEventTime( + sampleIndex)}} + .count() + << "ms to " + << std::chrono::duration<double, std::milli>{mPreviousPrediction->eventTime}.count() + << "ms"; for (size_t pointerIndex = 0; pointerIndex < motionEvent.getPointerCount(); ++pointerIndex) { + const std::optional<Pointer> previousPointer = mPreviousPrediction->pointerMap.find( + PointerMap::PointerId{motionEvent.getPointerId(pointerIndex)}); + // This could happen because resampler only receives ACTION_MOVE events. + if (!previousPointer.has_value()) { + continue; + } setMotionEventPointerCoords(motionEvent, sampleIndex, pointerIndex, - mPreviousPrediction->pointers[pointerIndex].coords); + previousPointer->coords); } } } @@ -333,6 +385,7 @@ void LegacyResampler::resampleMotionEvent(nanoseconds frameTime, MotionEvent& mo mPreviousPrediction = sample; } } + LOG_IF(FATAL, mLatestSamples.empty()) << "mLatestSamples must contain at least one sample."; mLastRealSample = *(mLatestSamples.end() - 1); } diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index 701fb43c1f..7acfafb29d 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -94,13 +94,6 @@ flag { } flag { - name: "enable_new_mouse_pointer_ballistics" - namespace: "input" - description: "Change the acceleration curves for mouse pointer movements to match the touchpad ones" - bug: "315313622" -} - -flag { name: "rate_limit_user_activity_poke_in_dispatcher" namespace: "input" description: "Move user-activity poke rate-limiting from PowerManagerService to InputDispatcher." @@ -214,3 +207,10 @@ flag { description: "Enable telemetry for rotary input" bug: "370353565" } + +flag { + name: "set_input_device_kernel_wake" + namespace: "input" + description: "Set input device's power/wakeup sysfs node" + bug: "372812925" +} diff --git a/libs/input/tests/Resampler_test.cpp b/libs/input/tests/Resampler_test.cpp index fae8518e87..3162b77c85 100644 --- a/libs/input/tests/Resampler_test.cpp +++ b/libs/input/tests/Resampler_test.cpp @@ -648,7 +648,15 @@ TEST_F(ResamplerTest, MultiplePointerDifferentIdOrderInterpolation) { mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample); - assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); + assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, + {Pointer{.id = 0, + .x = 1.4f, + .y = 1.4f, + .isResampled = true}, + Pointer{.id = 1, + .x = 2.4f, + .y = 2.4f, + .isResampled = true}}); } TEST_F(ResamplerTest, MultiplePointerDifferentIdOrderExtrapolation) { @@ -670,7 +678,15 @@ TEST_F(ResamplerTest, MultiplePointerDifferentIdOrderExtrapolation) { mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr); - assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent); + assertMotionEventIsResampledAndCoordsNear(secondOriginalMotionEvent, secondMotionEvent, + {Pointer{.id = 1, + .x = 4.4f, + .y = 4.4f, + .isResampled = true}, + Pointer{.id = 0, + .x = 3.4f, + .y = 3.4f, + .isResampled = true}}); } TEST_F(ResamplerTest, MultiplePointerDifferentIdsInterpolation) { diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index d05ff3457a..5a78a5c82c 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -175,6 +175,14 @@ enum AHardwareBuffer_Format { AHARDWAREBUFFER_FORMAT_YCbCr_P010 = 0x36, /** + * YUV P210 format. + * Must have an even width and height. Can be accessed in OpenGL + * shaders through an external sampler. Does not support mip-maps + * cube-maps or multi-layered textures. + */ + AHARDWAREBUFFER_FORMAT_YCbCr_P210 = 0x3c, + + /** * Corresponding formats: * Vulkan: VK_FORMAT_R8_UNORM * OpenGL ES: GR_GL_R8 diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp index c572ee7811..faab48b1ce 100644 --- a/libs/nativewindow/rust/Android.bp +++ b/libs/nativewindow/rust/Android.bp @@ -110,6 +110,7 @@ rust_defaults { name: "libnativewindow_defaults", srcs: ["src/lib.rs"], rustlibs: [ + "android.hardware.common-V2-rust", "libbinder_rs", "libbitflags", "libnativewindow_bindgen", diff --git a/libs/nativewindow/rust/src/handle.rs b/libs/nativewindow/rust/src/handle.rs index c41ab8d1b8..2b08c1bcb9 100644 --- a/libs/nativewindow/rust/src/handle.rs +++ b/libs/nativewindow/rust/src/handle.rs @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +use android_hardware_common::{ + aidl::android::hardware::common::NativeHandle::NativeHandle as AidlNativeHandle, + binder::ParcelFileDescriptor, +}; use std::{ ffi::c_int, mem::forget, @@ -81,6 +85,12 @@ impl NativeHandle { /// Destroys the `NativeHandle`, taking ownership of the file descriptors it contained. pub fn into_fds(self) -> Vec<OwnedFd> { + // Unset FDSan tag since this `native_handle_t` is no longer the owner of the file + // descriptors after this function. + // SAFETY: Our wrapped `native_handle_t` pointer is always valid. + unsafe { + ffi::native_handle_unset_fdsan_tag(self.as_ref()); + } let fds = self.data()[..self.fd_count()] .iter() .map(|fd| { @@ -190,6 +200,21 @@ impl Drop for NativeHandle { } } +impl From<AidlNativeHandle> for NativeHandle { + fn from(aidl_native_handle: AidlNativeHandle) -> Self { + let fds = aidl_native_handle.fds.into_iter().map(OwnedFd::from).collect(); + Self::new(fds, &aidl_native_handle.ints).unwrap() + } +} + +impl From<NativeHandle> for AidlNativeHandle { + fn from(native_handle: NativeHandle) -> Self { + let ints = native_handle.ints().to_owned(); + let fds = native_handle.into_fds().into_iter().map(ParcelFileDescriptor::new).collect(); + Self { ints, fds } + } +} + // SAFETY: `NativeHandle` owns the `native_handle_t`, which just contains some integers and file // descriptors, which aren't tied to any particular thread. unsafe impl Send for NativeHandle {} @@ -240,4 +265,43 @@ mod test { drop(cloned); } + + #[test] + fn to_fds() { + let file = File::open("/dev/null").unwrap(); + let original = NativeHandle::new(vec![file.into()], &[42]).unwrap(); + assert_eq!(original.ints(), &[42]); + assert_eq!(original.fds().len(), 1); + + let fds = original.into_fds(); + assert_eq!(fds.len(), 1); + } + + #[test] + fn to_aidl() { + let file = File::open("/dev/null").unwrap(); + let original = NativeHandle::new(vec![file.into()], &[42]).unwrap(); + assert_eq!(original.ints(), &[42]); + assert_eq!(original.fds().len(), 1); + + let aidl = AidlNativeHandle::from(original); + assert_eq!(&aidl.ints, &[42]); + assert_eq!(aidl.fds.len(), 1); + } + + #[test] + fn to_from_aidl() { + let file = File::open("/dev/null").unwrap(); + let original = NativeHandle::new(vec![file.into()], &[42]).unwrap(); + assert_eq!(original.ints(), &[42]); + assert_eq!(original.fds().len(), 1); + + let aidl = AidlNativeHandle::from(original); + assert_eq!(&aidl.ints, &[42]); + assert_eq!(aidl.fds.len(), 1); + + let converted_back = NativeHandle::from(aidl); + assert_eq!(converted_back.ints(), &[42]); + assert_eq!(converted_back.fds().len(), 1); + } } diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index f19b908074..a1d986ed2b 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -220,7 +220,13 @@ impl HardwareBuffer { Self(buffer) } - /// Get the internal |AHardwareBuffer| pointer without decrementing the refcount. This can + /// Get the internal `AHardwareBuffer` pointer that is only valid when this `HardwareBuffer` + /// exists. This can be used to provide a pointer to the AHB for a C/C++ API over the FFI. + pub fn as_raw(&self) -> NonNull<AHardwareBuffer> { + self.0 + } + + /// Get the internal `AHardwareBuffer` pointer without decrementing the refcount. This can /// be used to provide a pointer to the AHB for a C/C++ API over the FFI. pub fn into_raw(self) -> NonNull<AHardwareBuffer> { let buffer = ManuallyDrop::new(self); diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index 859ae8b6e2..ac43da8dcf 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -16,6 +16,7 @@ #pragma once +#include <gui/DisplayLuts.h> #include <math/mat4.h> #include <math/vec3.h> #include <renderengine/ExternalTexture.h> @@ -145,6 +146,8 @@ struct LayerSettings { // If white point nits are unknown, then this layer is assumed to have the // same luminance as the brightest layer in the scene. float whitePointNits = -1.f; + + std::shared_ptr<gui::DisplayLuts> luts; }; // Keep in sync with custom comparison function in @@ -187,7 +190,7 @@ static inline bool operator==(const LayerSettings& lhs, const LayerSettings& rhs lhs.blurRegionTransform == rhs.blurRegionTransform && lhs.stretchEffect == rhs.stretchEffect && lhs.edgeExtensionEffect == rhs.edgeExtensionEffect && - lhs.whitePointNits == rhs.whitePointNits; + lhs.whitePointNits == rhs.whitePointNits && lhs.luts == rhs.luts; } static inline void PrintTo(const Buffer& settings, ::std::ostream* os) { diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 5159ffe86b..b19a862b6c 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -135,6 +135,9 @@ cc_library_static { "EGL/MultifileBlobCache.cpp", ], export_include_dirs: ["EGL"], + shared_libs: [ + "libz", + ], } cc_library_shared { @@ -169,6 +172,7 @@ cc_library_shared { "libutils", "libSurfaceFlingerProp", "libunwindstack", + "libz", ], static_libs: [ "libEGL_getProcAddress", @@ -199,6 +203,7 @@ cc_test { ], shared_libs: [ "libutils", + "libz", ], } diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp index 4a0fac4ce5..573ca5411a 100644 --- a/opengl/libs/EGL/FileBlobCache.cpp +++ b/opengl/libs/EGL/FileBlobCache.cpp @@ -27,6 +27,7 @@ #include <log/log.h> #include <utils/Trace.h> +#include <zlib.h> // Cache file header static const char* cacheFileMagic = "EGL$"; @@ -34,20 +35,10 @@ static const size_t cacheFileHeaderSize = 8; namespace android { -uint32_t crc32c(const uint8_t* buf, size_t len) { - const uint32_t polyBits = 0x82F63B78; - uint32_t r = 0; - for (size_t i = 0; i < len; i++) { - r ^= buf[i]; - for (int j = 0; j < 8; j++) { - if (r & 1) { - r = (r >> 1) ^ polyBits; - } else { - r >>= 1; - } - } - } - return r; +uint32_t GenerateCRC32(const uint8_t *data, size_t size) +{ + const unsigned long initialValue = crc32_z(0u, nullptr, 0u); + return static_cast<uint32_t>(crc32_z(initialValue, data, size)); } FileBlobCache::FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize, @@ -101,7 +92,7 @@ FileBlobCache::FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxT return; } uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); - if (crc32c(buf + headerSize, cacheSize) != *crc) { + if (GenerateCRC32(buf + headerSize, cacheSize) != *crc) { ALOGE("cache file failed CRC check"); close(fd); return; @@ -175,7 +166,7 @@ void FileBlobCache::writeToFile() { // Write the file magic and CRC memcpy(buf, cacheFileMagic, 4); uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); - *crc = crc32c(buf + headerSize, cacheSize); + *crc = GenerateCRC32(buf + headerSize, cacheSize); if (write(fd, buf, fileSize) == -1) { ALOGE("error writing cache file: %s (%d)", strerror(errno), diff --git a/opengl/libs/EGL/FileBlobCache.h b/opengl/libs/EGL/FileBlobCache.h index f083b0d6ca..224444da65 100644 --- a/opengl/libs/EGL/FileBlobCache.h +++ b/opengl/libs/EGL/FileBlobCache.h @@ -22,7 +22,7 @@ namespace android { -uint32_t crc32c(const uint8_t* buf, size_t len); +uint32_t GenerateCRC32(const uint8_t *data, size_t size); class FileBlobCache : public BlobCache { public: diff --git a/opengl/libs/EGL/MultifileBlobCache.cpp b/opengl/libs/EGL/MultifileBlobCache.cpp index 9905210014..f7e33b383f 100644 --- a/opengl/libs/EGL/MultifileBlobCache.cpp +++ b/opengl/libs/EGL/MultifileBlobCache.cpp @@ -214,9 +214,8 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s } // Ensure we have a good CRC - if (header.crc != - crc32c(mappedEntry + sizeof(MultifileHeader), - fileSize - sizeof(MultifileHeader))) { + if (header.crc != GenerateCRC32(mappedEntry + sizeof(MultifileHeader), + fileSize - sizeof(MultifileHeader))) { ALOGV("INIT: Entry %u failed CRC check! Removing.", entryHash); if (remove(fullPath.c_str()) != 0) { ALOGE("Error removing %s: %s", fullPath.c_str(), std::strerror(errno)); @@ -532,9 +531,9 @@ bool MultifileBlobCache::createStatus(const std::string& baseDir) { mBuildId.length() > PROP_VALUE_MAX ? PROP_VALUE_MAX : mBuildId.length()); // Finally update the crc, using cacheVersion and everything the follows - status.crc = - crc32c(reinterpret_cast<uint8_t*>(&status) + offsetof(MultifileStatus, cacheVersion), - sizeof(status) - offsetof(MultifileStatus, cacheVersion)); + status.crc = GenerateCRC32( + reinterpret_cast<uint8_t *>(&status) + offsetof(MultifileStatus, cacheVersion), + sizeof(status) - offsetof(MultifileStatus, cacheVersion)); // Create the status file std::string cacheStatus = baseDir + "/" + kMultifileBlobCacheStatusFile; @@ -599,9 +598,9 @@ bool MultifileBlobCache::checkStatus(const std::string& baseDir) { } // Ensure we have a good CRC - if (status.crc != - crc32c(reinterpret_cast<uint8_t*>(&status) + offsetof(MultifileStatus, cacheVersion), - sizeof(status) - offsetof(MultifileStatus, cacheVersion))) { + if (status.crc != GenerateCRC32(reinterpret_cast<uint8_t *>(&status) + + offsetof(MultifileStatus, cacheVersion), + sizeof(status) - offsetof(MultifileStatus, cacheVersion))) { ALOGE("STATUS(CHECK): Cache status failed CRC check!"); return false; } @@ -840,8 +839,8 @@ void MultifileBlobCache::processTask(DeferredTask& task) { // Add CRC check to the header (always do this last!) MultifileHeader* header = reinterpret_cast<MultifileHeader*>(buffer); - header->crc = - crc32c(buffer + sizeof(MultifileHeader), bufferSize - sizeof(MultifileHeader)); + header->crc = GenerateCRC32(buffer + sizeof(MultifileHeader), + bufferSize - sizeof(MultifileHeader)); ssize_t result = write(fd, buffer, bufferSize); if (result != bufferSize) { diff --git a/opengl/libs/EGL/MultifileBlobCache.h b/opengl/libs/EGL/MultifileBlobCache.h index 18566c2892..65aa2db344 100644 --- a/opengl/libs/EGL/MultifileBlobCache.h +++ b/opengl/libs/EGL/MultifileBlobCache.h @@ -34,7 +34,7 @@ namespace android { -constexpr uint32_t kMultifileBlobCacheVersion = 1; +constexpr uint32_t kMultifileBlobCacheVersion = 2; constexpr char kMultifileBlobCacheStatusFile[] = "cache.status"; struct MultifileHeader { diff --git a/opengl/libs/EGL/fuzzer/Android.bp b/opengl/libs/EGL/fuzzer/Android.bp index 022a2a3f06..4947e5ff6c 100644 --- a/opengl/libs/EGL/fuzzer/Android.bp +++ b/opengl/libs/EGL/fuzzer/Android.bp @@ -36,6 +36,10 @@ cc_fuzz { "libutils", ], + shared_libs: [ + "libz", + ], + srcs: [ "MultifileBlobCache_fuzzer.cpp", ], diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp index 503d7dffdb..839a5cab2f 100644 --- a/opengl/tests/EGLTest/EGL_test.cpp +++ b/opengl/tests/EGLTest/EGL_test.cpp @@ -765,6 +765,30 @@ TEST_F(EGLTest, EGLNoConfigContext) { } } +// Verify that eglCreateContext works when EGL_TELEMETRY_HINT_ANDROID is used with +// NO_HINT = 0, SKIP_TELEMETRY = 1 and an invalid of value of 2 +TEST_F(EGLTest, EGLContextTelemetryHintExt) { + for (int i = 0; i < 3; i++) { + EGLConfig config; + get8BitConfig(config); + std::vector<EGLint> contextAttributes; + contextAttributes.reserve(4); + contextAttributes.push_back(EGL_TELEMETRY_HINT_ANDROID); + contextAttributes.push_back(i); + contextAttributes.push_back(EGL_NONE); + contextAttributes.push_back(EGL_NONE); + + EGLContext eglContext = eglCreateContext(mEglDisplay, config, EGL_NO_CONTEXT, + contextAttributes.data()); + EXPECT_NE(EGL_NO_CONTEXT, eglContext); + EXPECT_EQ(EGL_SUCCESS, eglGetError()); + + if (eglContext != EGL_NO_CONTEXT) { + eglDestroyContext(mEglDisplay, eglContext); + } + } +} + // Emulate what a native application would do to create a // 10:10:10:2 surface. TEST_F(EGLTest, EGLConfig1010102) { diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 756a29b754..6ef4a3d6af 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -137,19 +137,18 @@ struct InputReaderConfiguration { ui::LogicalDisplayId defaultPointerDisplayId; // The mouse pointer speed, as a number from -7 (slowest) to 7 (fastest). - // - // Currently only used when the enable_new_mouse_pointer_ballistics flag is enabled. int32_t mousePointerSpeed; // Displays on which an acceleration curve shouldn't be applied for pointer movements from mice. - // - // Currently only used when the enable_new_mouse_pointer_ballistics flag is enabled. std::set<ui::LogicalDisplayId> displaysWithMousePointerAccelerationDisabled; - // Velocity control parameters for mouse pointer movements. + // Velocity control parameters for touchpad pointer movements on the old touchpad stack (based + // on TouchInputMapper). + // + // For mice, these are ignored and the values of mousePointerSpeed and + // mousePointerAccelerationEnabled used instead. // - // If the enable_new_mouse_pointer_ballistics flag is enabled, these are ignored and the values - // of mousePointerSpeed and mousePointerAccelerationEnabled used instead. + // TODO(b/281840344): remove this. VelocityControlParameters pointerVelocityControlParameters; // Velocity control parameters for mouse wheel movements. @@ -426,6 +425,16 @@ public: /* Notifies that mouse cursor faded due to typing. */ virtual void notifyMouseCursorFadedOnTyping() = 0; + + /* Set whether the given input device can wake up the kernel from sleep + * when it generates input events. By default, usually only internal (built-in) + * input devices can wake the kernel from sleep. For an external input device + * that supports remote wakeup to be able to wake the kernel, this must be called + * after each time the device is connected/added. + * + * Returns true if setting power wakeup was successful. + */ + virtual bool setKernelWakeEnabled(int32_t deviceId, bool enabled) = 0; }; // --- TouchAffineTransformation --- diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index f8cd9733b0..35ba48f137 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -43,6 +43,7 @@ #include <android-base/strings.h> #include <cutils/properties.h> #include <ftl/enum.h> +#include <input/InputEventLabels.h> #include <input/KeyCharacterMap.h> #include <input/KeyLayoutMap.h> #include <input/PrintTools.h> @@ -1021,6 +1022,8 @@ std::optional<RawAbsoluteAxisInfo> EventHub::getAbsoluteAxisInfo(int32_t deviceI std::scoped_lock _l(mLock); const Device* device = getDeviceLocked(deviceId); if (device == nullptr) { + ALOGE("Couldn't find device with ID %d, so returning null axis info for axis %s", deviceId, + InputEventLookup::getLinuxEvdevLabel(EV_ABS, axis, 0).code.c_str()); return std::nullopt; } // We can read the RawAbsoluteAxisInfo even if the device is disabled and doesn't have a valid @@ -2848,6 +2851,35 @@ void EventHub::requestReopenDevices() { mNeedToReopenDevices = true; } +bool EventHub::setKernelWakeEnabled(int32_t deviceId, bool enabled) { + std::scoped_lock _l(mLock); + std::string enabledStr = enabled ? "enabled" : "disabled"; + Device* device = getDeviceLocked(deviceId); + if (device == nullptr) { + ALOGE("Device Id %d does not exist for setting power wakeup", deviceId); + return false; + } + if (device->associatedDevice == nullptr) { + return false; + } + std::filesystem::path currentPath = device->associatedDevice->sysfsRootPath; + while (!currentPath.empty() && currentPath != "/") { + std::string nodePath = currentPath / "power/wakeup"; + if (std::filesystem::exists(nodePath)) { + if (base::WriteStringToFile(enabledStr, nodePath)) { + return true; + + } + // No need to continue searching in parent directories as power/wakeup nodes + // higher up may control other subdevices. + ALOGW("Failed to set power/wakeup node at %s", nodePath.c_str()); + return false; + } + currentPath = currentPath.parent_path(); + } + return false; +} + void EventHub::dump(std::string& dump) const { dump += "Event Hub State:\n"; diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 02eeb0a8de..5e42d57f06 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -745,6 +745,14 @@ void InputDevice::setKeyboardType(KeyboardType keyboardType) { } } +bool InputDevice::setKernelWakeEnabled(bool enabled) { + bool success = false; + for_each_subdevice([&enabled, &success](InputDeviceContext& context) { + success |= context.setKernelWakeEnabled(enabled); + }); + return success; +} + InputDeviceContext::InputDeviceContext(InputDevice& device, int32_t eventHubId) : mDevice(device), mContext(device.getContext()), diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index ab2704237f..a2b7e82154 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -901,6 +901,16 @@ void InputReader::notifyMouseCursorFadedOnTyping() { mPreventingTouchpadTaps = true; } +bool InputReader::setKernelWakeEnabled(int32_t deviceId, bool enabled) { + std::scoped_lock _l(mLock); + + InputDevice* device = findInputDeviceLocked(deviceId); + if (device) { + return device->setKernelWakeEnabled(enabled); + } + return false; +} + void InputReader::dump(std::string& dump) { std::scoped_lock _l(mLock); diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index dffd8e3c7a..4336945e96 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -396,6 +396,13 @@ public: /* Sysfs node changed. Reopen the Eventhub device if any new Peripheral like Light, Battery, * etc. is detected. */ virtual void sysfsNodeChanged(const std::string& sysfsNodePath) = 0; + + /* Set whether the given input device can wake up the kernel from sleep + * when it generates input events. By default, usually only internal (built-in) + * input devices can wake the kernel from sleep. For an external input device + * that supports remote wakeup to be able to wake the kernel, this must be called + * after each time the device is connected/added. */ + virtual bool setKernelWakeEnabled(int32_t deviceId, bool enabled) = 0; }; template <std::size_t BITS> @@ -603,6 +610,8 @@ public: void sysfsNodeChanged(const std::string& sysfsNodePath) override final; + bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override final; + ~EventHub() override; private: diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 8958d9ec0b..abe7a5fa6e 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -139,6 +139,8 @@ public: std::optional<HardwareProperties> getTouchpadHardwareProperties(); + bool setKernelWakeEnabled(bool enabled); + // construct and add a mapper to the input device template <class T, typename... Args> T& addMapper(int32_t eventHubId, Args... args) { @@ -469,6 +471,9 @@ public: inline void setKeyboardType(KeyboardType keyboardType) { return mDevice.setKeyboardType(keyboardType); } + inline bool setKernelWakeEnabled(bool enabled) { + return mEventHub->setKernelWakeEnabled(mId, enabled); + } private: InputDevice& mDevice; diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index 100387195a..7614a05470 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -120,6 +120,8 @@ public: void notifyMouseCursorFadedOnTyping() override; + bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override; + protected: // These members are protected so they can be instrumented by test cases. virtual std::shared_ptr<InputDevice> createDeviceLocked(nsecs_t when, int32_t deviceId, diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 630bd9bcd8..b33659cae1 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -33,8 +33,6 @@ #include "input/PrintTools.h" -namespace input_flags = com::android::input::flags; - namespace android { // The default velocity control parameters that has no effect. @@ -77,8 +75,7 @@ void CursorMotionAccumulator::finishSync() { CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig) : InputMapper(deviceContext, readerConfig), - mLastEventTime(std::numeric_limits<nsecs_t>::min()), - mEnableNewMousePointerBallistics(input_flags::enable_new_mouse_pointer_ballistics()) {} + mLastEventTime(std::numeric_limits<nsecs_t>::min()) {} uint32_t CursorInputMapper::getSources() const { return mSource; @@ -207,8 +204,7 @@ std::list<NotifyArgs> CursorInputMapper::reset(nsecs_t when) { mDownTime = 0; mLastEventTime = std::numeric_limits<nsecs_t>::min(); - mOldPointerVelocityControl.reset(); - mNewPointerVelocityControl.reset(); + mPointerVelocityControl.reset(); mWheelXVelocityControl.reset(); mWheelYVelocityControl.reset(); @@ -291,11 +287,7 @@ std::list<NotifyArgs> CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { mWheelYVelocityControl.move(when, nullptr, &vscroll); mWheelXVelocityControl.move(when, &hscroll, nullptr); - if (mEnableNewMousePointerBallistics) { - mNewPointerVelocityControl.move(when, &deltaX, &deltaY); - } else { - mOldPointerVelocityControl.move(when, &deltaX, &deltaY); - } + mPointerVelocityControl.move(when, &deltaX, &deltaY); float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; @@ -486,27 +478,15 @@ void CursorInputMapper::configureOnPointerCapture(const InputReaderConfiguration void CursorInputMapper::configureOnChangePointerSpeed(const InputReaderConfiguration& config) { if (mParameters.mode == Parameters::Mode::POINTER_RELATIVE) { // Disable any acceleration or scaling for the pointer when Pointer Capture is enabled. - if (mEnableNewMousePointerBallistics) { - mNewPointerVelocityControl.setAccelerationEnabled(false); - } else { - mOldPointerVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS); - } + mPointerVelocityControl.setAccelerationEnabled(false); mWheelXVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS); mWheelYVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS); } else { - if (mEnableNewMousePointerBallistics) { - mNewPointerVelocityControl.setAccelerationEnabled( - config.displaysWithMousePointerAccelerationDisabled.count( - mDisplayId.value_or(ui::LogicalDisplayId::INVALID)) == 0); - mNewPointerVelocityControl.setCurve( - createAccelerationCurveForPointerSensitivity(config.mousePointerSpeed)); - } else { - mOldPointerVelocityControl.setParameters( - (config.displaysWithMousePointerAccelerationDisabled.count( - mDisplayId.value_or(ui::LogicalDisplayId::INVALID)) == 0) - ? config.pointerVelocityControlParameters - : FLAT_VELOCITY_CONTROL_PARAMS); - } + mPointerVelocityControl.setAccelerationEnabled( + config.displaysWithMousePointerAccelerationDisabled.count( + mDisplayId.value_or(ui::LogicalDisplayId::INVALID)) == 0); + mPointerVelocityControl.setCurve( + createAccelerationCurveForPointerSensitivity(config.mousePointerSpeed)); mWheelXVelocityControl.setParameters(config.wheelVelocityControlParameters); mWheelYVelocityControl.setParameters(config.wheelVelocityControlParameters); } diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index 403e96d758..83199227b1 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -104,8 +104,7 @@ private: // Velocity controls for mouse pointer and wheel movements. // The controls for X and Y wheel movements are separate to keep them decoupled. - SimpleVelocityControl mOldPointerVelocityControl; - CurvedVelocityControl mNewPointerVelocityControl; + CurvedVelocityControl mPointerVelocityControl; SimpleVelocityControl mWheelXVelocityControl; SimpleVelocityControl mWheelYVelocityControl; @@ -120,7 +119,6 @@ private: nsecs_t mDownTime; nsecs_t mLastEventTime; - const bool mEnableNewMousePointerBallistics; bool mMouseReverseVerticalScrolling = false; explicit CursorInputMapper(InputDeviceContext& deviceContext, diff --git a/services/inputflinger/tests/CursorInputMapper_test.cpp b/services/inputflinger/tests/CursorInputMapper_test.cpp index 1762a455ce..d4e8fdfdc5 100644 --- a/services/inputflinger/tests/CursorInputMapper_test.cpp +++ b/services/inputflinger/tests/CursorInputMapper_test.cpp @@ -25,8 +25,10 @@ #include <android-base/logging.h> #include <android_companion_virtualdevice_flags.h> #include <com_android_input_flags.h> +#include <gmock/gmock.h> #include <gtest/gtest.h> #include <input/DisplayViewport.h> +#include <input/InputEventLabels.h> #include <linux/input-event-codes.h> #include <linux/input.h> #include <utils/Timers.h> @@ -52,6 +54,8 @@ constexpr auto BUTTON_PRESS = AMOTION_EVENT_ACTION_BUTTON_PRESS; constexpr auto BUTTON_RELEASE = AMOTION_EVENT_ACTION_BUTTON_RELEASE; constexpr auto HOVER_MOVE = AMOTION_EVENT_ACTION_HOVER_MOVE; constexpr auto INVALID_CURSOR_POSITION = AMOTION_EVENT_INVALID_CURSOR_POSITION; +constexpr auto AXIS_X = AMOTION_EVENT_AXIS_X; +constexpr auto AXIS_Y = AMOTION_EVENT_AXIS_Y; constexpr ui::LogicalDisplayId DISPLAY_ID = ui::LogicalDisplayId::DEFAULT; constexpr ui::LogicalDisplayId SECONDARY_DISPLAY_ID = ui::LogicalDisplayId{DISPLAY_ID.val() + 1}; constexpr int32_t DISPLAY_WIDTH = 480; @@ -94,9 +98,35 @@ DisplayViewport createSecondaryViewport() { return v; } +// In a number of these tests, we want to check that some pointer motion is reported without +// specifying an exact value, as that would require updating the tests every time the pointer +// ballistics was changed. To do this, we make some matchers that only check the sign of a +// particular axis. +MATCHER_P(WithPositiveAxis, axis, "MotionEvent with a positive axis value") { + *result_listener << "expected 1 pointer with a positive " + << InputEventLookup::getAxisLabel(axis) << " axis but got " + << arg.pointerCoords.size() << " pointers, with axis value " + << arg.pointerCoords[0].getAxisValue(axis); + return arg.pointerCoords.size() == 1 && arg.pointerCoords[0].getAxisValue(axis) > 0; +} + +MATCHER_P(WithZeroAxis, axis, "MotionEvent with a zero axis value") { + *result_listener << "expected 1 pointer with a zero " << InputEventLookup::getAxisLabel(axis) + << " axis but got " << arg.pointerCoords.size() + << " pointers, with axis value " << arg.pointerCoords[0].getAxisValue(axis); + return arg.pointerCoords.size() == 1 && arg.pointerCoords[0].getAxisValue(axis) == 0; +} + +MATCHER_P(WithNegativeAxis, axis, "MotionEvent with a negative axis value") { + *result_listener << "expected 1 pointer with a negative " + << InputEventLookup::getAxisLabel(axis) << " axis but got " + << arg.pointerCoords.size() << " pointers, with axis value " + << arg.pointerCoords[0].getAxisValue(axis); + return arg.pointerCoords.size() == 1 && arg.pointerCoords[0].getAxisValue(axis) < 0; +} + } // namespace -namespace input_flags = com::android::input::flags; namespace vd_flags = android::companion::virtualdevice::flags; /** @@ -150,24 +180,21 @@ protected: ASSERT_GT(mDevice->getGeneration(), generation); } - void testMotionRotation(int32_t originalX, int32_t originalY, int32_t rotatedX, - int32_t rotatedY) { + void testRotation(int32_t originalX, int32_t originalY, + const testing::Matcher<NotifyMotionArgs>& coordsMatcher) { std::list<NotifyArgs> args; args += process(ARBITRARY_TIME, EV_REL, REL_X, originalX); args += process(ARBITRARY_TIME, EV_REL, REL_Y, originalY); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(ACTION_MOVE), - WithCoords(float(rotatedX) / TRACKBALL_MOVEMENT_THRESHOLD, - float(rotatedY) / TRACKBALL_MOVEMENT_THRESHOLD))))); + AllOf(WithMotionAction(ACTION_MOVE), coordsMatcher)))); } }; class CursorInputMapperUnitTest : public CursorInputMapperUnitTestBase { protected: void SetUp() override { - input_flags::enable_new_mouse_pointer_ballistics(false); vd_flags::high_resolution_scroll(false); CursorInputMapperUnitTestBase::SetUp(); } @@ -344,14 +371,12 @@ TEST_F(CursorInputMapperUnitTest, ProcessPointerCapture) { args += process(EV_KEY, BTN_MOUSE, 0); args += process(EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(BUTTON_RELEASE), - WithSource(AINPUT_SOURCE_MOUSE_RELATIVE), - WithCoords(0.0f, 0.0f), WithPressure(0.0f))), - VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(ACTION_UP), - WithSource(AINPUT_SOURCE_MOUSE_RELATIVE), - WithCoords(0.0f, 0.0f), WithPressure(0.0f))))); + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)), + VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)))); + ASSERT_THAT(args, + Each(VariantWith<NotifyMotionArgs>(AllOf(WithSource(AINPUT_SOURCE_MOUSE_RELATIVE), + WithCoords(0.0f, 0.0f), + WithPressure(0.0f))))); // Another move. args.clear(); @@ -377,7 +402,8 @@ TEST_F(CursorInputMapperUnitTest, ProcessPointerCapture) { ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE), expectedCoords, expectedCursorPosition, - WithRelativeMotion(10.0f, 20.0f))))); + WithPositiveAxis(AMOTION_EVENT_AXIS_RELATIVE_X), + WithPositiveAxis(AMOTION_EVENT_AXIS_RELATIVE_Y))))); } TEST_F(CursorInputMapperUnitTest, PopulateDeviceInfoReturnsScaledRangeInNavigationMode) { @@ -411,64 +437,40 @@ TEST_F(CursorInputMapperUnitTest, ProcessShouldSetAllFieldsAndIncludeGlobalMetaS args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 1); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithEventTime(ARBITRARY_TIME), WithDeviceId(DEVICE_ID), - WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0), - WithEdgeFlags(0), WithPolicyFlags(0), - WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), - WithPointerCount(1), WithPointerId(0, 0), - WithToolType(ToolType::MOUSE), WithCoords(0.0f, 0.0f), - WithPressure(1.0f), - WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD, - TRACKBALL_MOVEMENT_THRESHOLD), - WithDownTime(ARBITRARY_TIME))), - VariantWith<NotifyMotionArgs>( - AllOf(WithEventTime(ARBITRARY_TIME), WithDeviceId(DEVICE_ID), - WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0), - WithEdgeFlags(0), WithPolicyFlags(0), - WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), - WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), - WithPointerCount(1), WithPointerId(0, 0), - WithToolType(ToolType::MOUSE), WithCoords(0.0f, 0.0f), - WithPressure(1.0f), - WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD, - TRACKBALL_MOVEMENT_THRESHOLD), - WithDownTime(ARBITRARY_TIME))))); + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)), + VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>( + AllOf(WithEventTime(ARBITRARY_TIME), WithDeviceId(DEVICE_ID), + WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0), WithEdgeFlags(0), + WithPolicyFlags(0), + WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPointerCount(1), + WithPointerId(0, 0), WithToolType(ToolType::MOUSE), + WithCoords(0.0f, 0.0f), WithPressure(1.0f), + WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD, + TRACKBALL_MOVEMENT_THRESHOLD), + WithDownTime(ARBITRARY_TIME))))); args.clear(); // Button release. Should have same down time. args += process(ARBITRARY_TIME + 1, EV_KEY, BTN_MOUSE, 0); args += process(ARBITRARY_TIME + 1, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithEventTime(ARBITRARY_TIME + 1), - WithDeviceId(DEVICE_ID), - WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0), - WithEdgeFlags(0), WithPolicyFlags(0), - WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON), - WithButtonState(0), WithPointerCount(1), - WithPointerId(0, 0), WithToolType(ToolType::MOUSE), - WithCoords(0.0f, 0.0f), WithPressure(0.0f), - WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD, - TRACKBALL_MOVEMENT_THRESHOLD), - WithDownTime(ARBITRARY_TIME))), - VariantWith<NotifyMotionArgs>( - AllOf(WithEventTime(ARBITRARY_TIME + 1), - WithDeviceId(DEVICE_ID), - WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0), - WithEdgeFlags(0), WithPolicyFlags(0), - WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON), - WithButtonState(0), WithPointerCount(1), - WithPointerId(0, 0), WithToolType(ToolType::MOUSE), - WithCoords(0.0f, 0.0f), WithPressure(0.0f), - WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD, - TRACKBALL_MOVEMENT_THRESHOLD), - WithDownTime(ARBITRARY_TIME))))); + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)), + VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>( + AllOf(WithEventTime(ARBITRARY_TIME + 1), WithDeviceId(DEVICE_ID), + WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0), WithEdgeFlags(0), + WithPolicyFlags(0), + WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON), + WithButtonState(0), WithPointerCount(1), WithPointerId(0, 0), + WithToolType(ToolType::MOUSE), WithCoords(0.0f, 0.0f), + WithPressure(0.0f), + WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD, + TRACKBALL_MOVEMENT_THRESHOLD), + WithDownTime(ARBITRARY_TIME))))); } TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleIndependentXYUpdates) { @@ -482,9 +484,8 @@ TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleIndependentXYUpdates) { args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithCoords(1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f), - WithPressure(0.0f))))); + AllOf(WithMotionAction(ACTION_MOVE), WithPressure(0.0f), + WithPositiveAxis(AXIS_X), WithZeroAxis(AXIS_Y))))); args.clear(); // Motion in Y but not X. @@ -492,9 +493,8 @@ TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleIndependentXYUpdates) { args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithCoords(0.0f, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD), - WithPressure(0.0f))))); + AllOf(WithMotionAction(ACTION_MOVE), WithPressure(0.0f), + WithZeroAxis(AXIS_X), WithNegativeAxis(AXIS_Y))))); args.clear(); } @@ -508,24 +508,22 @@ TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleIndependentButtonUpdates) { args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 1); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithCoords(0.0f, 0.0f), WithPressure(1.0f))), - VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), - WithCoords(0.0f, 0.0f), WithPressure(1.0f))))); + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)), + VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>( + AllOf(WithCoords(0.0f, 0.0f), WithPressure(1.0f))))); args.clear(); // Button release. args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 0); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithCoords(0.0f, 0.0f), WithPressure(0.0f))), - VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithCoords(0.0f, 0.0f), WithPressure(0.0f))))); + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)), + VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>( + AllOf(WithCoords(0.0f, 0.0f), WithPressure(0.0f))))); } TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleCombinedXYAndButtonUpdates) { @@ -540,16 +538,12 @@ TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleCombinedXYAndButtonUpdates) args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 1); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithCoords(1.0f / TRACKBALL_MOVEMENT_THRESHOLD, - -2.0f / TRACKBALL_MOVEMENT_THRESHOLD), - WithPressure(1.0f))), - VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), - WithCoords(1.0f / TRACKBALL_MOVEMENT_THRESHOLD, - -2.0f / TRACKBALL_MOVEMENT_THRESHOLD), - WithPressure(1.0f))))); + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)), + VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>(AllOf(WithPositiveAxis(AXIS_X), + WithNegativeAxis(AXIS_Y), + WithPressure(1.0f))))); args.clear(); // Move X, Y a bit while pressed. @@ -558,22 +552,19 @@ TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleCombinedXYAndButtonUpdates) args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithCoords(2.0f / TRACKBALL_MOVEMENT_THRESHOLD, - 1.0f / TRACKBALL_MOVEMENT_THRESHOLD), - WithPressure(1.0f))))); + AllOf(WithMotionAction(ACTION_MOVE), WithPressure(1.0f), + WithPositiveAxis(AXIS_X), WithPositiveAxis(AXIS_Y))))); args.clear(); // Release Button. args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 0); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithCoords(0.0f, 0.0f), WithPressure(0.0f))), - VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithCoords(0.0f, 0.0f), WithPressure(0.0f))))); + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)), + VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>( + AllOf(WithCoords(0.0f, 0.0f), WithPressure(0.0f))))); args.clear(); } @@ -586,14 +577,16 @@ TEST_F(CursorInputMapperUnitTest, ProcessShouldNotRotateMotionsWhenOrientationAw .WillRepeatedly(Return(createPrimaryViewport(ui::Rotation::Rotation90))); mMapper = createInputMapper<CursorInputMapper>(*mDeviceContext, mReaderConfiguration); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, 1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, -1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, -1, 1)); + constexpr auto X = AXIS_X; + constexpr auto Y = AXIS_Y; + ASSERT_NO_FATAL_FAILURE(testRotation( 0, 1, AllOf(WithZeroAxis(X), WithPositiveAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, 1, AllOf(WithPositiveAxis(X), WithPositiveAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, 0, AllOf(WithPositiveAxis(X), WithZeroAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, -1, AllOf(WithPositiveAxis(X), WithNegativeAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 0, -1, AllOf(WithZeroAxis(X), WithNegativeAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, -1, AllOf(WithNegativeAxis(X), WithNegativeAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, 0, AllOf(WithNegativeAxis(X), WithZeroAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, 1, AllOf(WithNegativeAxis(X), WithPositiveAxis(Y)))); } TEST_F(CursorInputMapperUnitTest, ProcessShouldRotateMotionsWhenNotOrientationAware) { @@ -604,54 +597,56 @@ TEST_F(CursorInputMapperUnitTest, ProcessShouldRotateMotionsWhenNotOrientationAw .WillRepeatedly(Return(createPrimaryViewport(ui::Rotation::Rotation0))); mMapper = createInputMapper<CursorInputMapper>(*mDeviceContext, mReaderConfiguration); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, 1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, -1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, -1, 1)); + constexpr auto X = AXIS_X; + constexpr auto Y = AXIS_Y; + ASSERT_NO_FATAL_FAILURE(testRotation( 0, 1, AllOf(WithZeroAxis(X), WithPositiveAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, 1, AllOf(WithPositiveAxis(X), WithPositiveAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, 0, AllOf(WithPositiveAxis(X), WithZeroAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, -1, AllOf(WithPositiveAxis(X), WithNegativeAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 0, -1, AllOf(WithZeroAxis(X), WithNegativeAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, -1, AllOf(WithNegativeAxis(X), WithNegativeAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, 0, AllOf(WithNegativeAxis(X), WithZeroAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, 1, AllOf(WithNegativeAxis(X), WithPositiveAxis(Y)))); EXPECT_CALL((*mDevice), getAssociatedViewport) .WillRepeatedly(Return(createPrimaryViewport(ui::Rotation::Rotation90))); std::list<NotifyArgs> args = mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration, InputReaderConfiguration::Change::DISPLAY_INFO); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, -1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, 1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, -1, -1)); + ASSERT_NO_FATAL_FAILURE(testRotation( 0, 1, AllOf(WithNegativeAxis(X), WithZeroAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, 1, AllOf(WithNegativeAxis(X), WithPositiveAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, 0, AllOf(WithZeroAxis(X), WithPositiveAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, -1, AllOf(WithPositiveAxis(X), WithPositiveAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 0, -1, AllOf(WithPositiveAxis(X), WithZeroAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, -1, AllOf(WithPositiveAxis(X), WithNegativeAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, 0, AllOf(WithZeroAxis(X), WithNegativeAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, 1, AllOf(WithNegativeAxis(X), WithNegativeAxis(Y)))); EXPECT_CALL((*mDevice), getAssociatedViewport) .WillRepeatedly(Return(createPrimaryViewport(ui::Rotation::Rotation180))); args = mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration, InputReaderConfiguration::Change::DISPLAY_INFO); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, -1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, -1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, 1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, 1, -1)); + ASSERT_NO_FATAL_FAILURE(testRotation( 0, 1, AllOf(WithZeroAxis(X), WithNegativeAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, 1, AllOf(WithNegativeAxis(X), WithNegativeAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, 0, AllOf(WithNegativeAxis(X), WithZeroAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, -1, AllOf(WithNegativeAxis(X), WithPositiveAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 0, -1, AllOf(WithZeroAxis(X), WithPositiveAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, -1, AllOf(WithPositiveAxis(X), WithPositiveAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, 0, AllOf(WithPositiveAxis(X), WithZeroAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, 1, AllOf(WithPositiveAxis(X), WithNegativeAxis(Y)))); EXPECT_CALL((*mDevice), getAssociatedViewport) .WillRepeatedly(Return(createPrimaryViewport(ui::Rotation::Rotation270))); args = mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration, InputReaderConfiguration::Change::DISPLAY_INFO); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, 1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, 1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, 0, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, -1, -1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, -1, 0)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, -1, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, 0, 1)); - ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, 1, 1)); + ASSERT_NO_FATAL_FAILURE(testRotation( 0, 1, AllOf(WithPositiveAxis(X), WithZeroAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, 1, AllOf(WithPositiveAxis(X), WithNegativeAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, 0, AllOf(WithZeroAxis(X), WithNegativeAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 1, -1, AllOf(WithNegativeAxis(X), WithNegativeAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation( 0, -1, AllOf(WithNegativeAxis(X), WithZeroAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, -1, AllOf(WithNegativeAxis(X), WithPositiveAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, 0, AllOf(WithZeroAxis(X), WithPositiveAxis(Y)))); + ASSERT_NO_FATAL_FAILURE(testRotation(-1, 1, AllOf(WithPositiveAxis(X), WithPositiveAxis(Y)))); } TEST_F(CursorInputMapperUnitTest, PopulateDeviceInfoReturnsRangeFromPolicy) { @@ -742,30 +737,22 @@ TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleAllButtonsWithZeroCoords) { args += process(ARBITRARY_TIME, EV_KEY, BTN_LEFT, 1); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), - WithCoords(0.0f, 0.0f), WithPressure(1.0f))), - VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), - WithCoords(0.0f, 0.0f), WithPressure(1.0f))))); + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)), + VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>( + AllOf(WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithCoords(0.0f, 0.0f), + WithPressure(1.0f))))); args.clear(); args += process(ARBITRARY_TIME, EV_KEY, BTN_LEFT, 0); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithButtonState(0), WithCoords(0.0f, 0.0f), - WithPressure(0.0f))), - VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithButtonState(0), WithCoords(0.0f, 0.0f), - WithPressure(0.0f))), - VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), - WithButtonState(0), WithCoords(0.0f, 0.0f), - WithPressure(0.0f))))); + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)), + VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)), + VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>( + AllOf(WithButtonState(0), WithCoords(0.0f, 0.0f), WithPressure(0.0f))))); args.clear(); // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE @@ -774,49 +761,41 @@ TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleAllButtonsWithZeroCoords) { args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + AllOf(WithMotionAction(ACTION_DOWN), WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY | - AMOTION_EVENT_BUTTON_TERTIARY), - WithCoords(0.0f, 0.0f), WithPressure(1.0f))), + AMOTION_EVENT_BUTTON_TERTIARY))), VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), - WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY), - WithCoords(0.0f, 0.0f), WithPressure(1.0f))), + AllOf(WithMotionAction(BUTTON_PRESS), + WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY))), VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + AllOf(WithMotionAction(BUTTON_PRESS), WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY | - AMOTION_EVENT_BUTTON_TERTIARY), - WithCoords(0.0f, 0.0f), WithPressure(1.0f))))); + AMOTION_EVENT_BUTTON_TERTIARY))))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>( + AllOf(WithCoords(0.0f, 0.0f), WithPressure(1.0f))))); args.clear(); args += process(ARBITRARY_TIME, EV_KEY, BTN_RIGHT, 0); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY), - WithCoords(0.0f, 0.0f), WithPressure(1.0f))), - VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY), - WithCoords(0.0f, 0.0f), WithPressure(1.0f))))); + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)), + VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_MOVE)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>( + AllOf(WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY), + WithCoords(0.0f, 0.0f), WithPressure(1.0f))))); args.clear(); args += process(ARBITRARY_TIME, EV_KEY, BTN_MIDDLE, 0); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithButtonState(0), WithCoords(0.0f, 0.0f), - WithPressure(0.0f))), - VariantWith<NotifyMotionArgs>( - AllOf(WithButtonState(0), - WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithCoords(0.0f, 0.0f), WithPressure(0.0f))), - VariantWith<NotifyMotionArgs>( - AllOf(WithButtonState(0), - WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), - WithCoords(0.0f, 0.0f), WithPressure(0.0f))))); + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)), + VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)), + VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>( + AllOf(WithButtonState(0), WithCoords(0.0f, 0.0f), WithPressure(0.0f))))); } class CursorInputMapperButtonKeyTest @@ -838,11 +817,11 @@ TEST_P(CursorInputMapperButtonKeyTest, ProcessShouldHandleButtonKeyWithZeroCoord ElementsAre(VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithKeyCode(expectedKeyCode))), VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + AllOf(WithMotionAction(HOVER_MOVE), WithButtonState(expectedButtonState), WithCoords(0.0f, 0.0f), WithPressure(0.0f))), VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + AllOf(WithMotionAction(BUTTON_PRESS), WithButtonState(expectedButtonState), WithCoords(0.0f, 0.0f), WithPressure(0.0f))))); args.clear(); @@ -851,13 +830,11 @@ TEST_P(CursorInputMapperButtonKeyTest, ProcessShouldHandleButtonKeyWithZeroCoord args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithButtonState(0), WithCoords(0.0f, 0.0f), - WithPressure(0.0f))), + AllOf(WithMotionAction(BUTTON_RELEASE), WithButtonState(0), + WithCoords(0.0f, 0.0f), WithPressure(0.0f))), VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), - WithButtonState(0), WithCoords(0.0f, 0.0f), - WithPressure(0.0f))), + AllOf(WithMotionAction(HOVER_MOVE), WithButtonState(0), + WithCoords(0.0f, 0.0f), WithPressure(0.0f))), VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP), WithKeyCode(expectedKeyCode))))); } @@ -881,8 +858,7 @@ TEST_F(CursorInputMapperUnitTest, ProcessWhenModeIsPointerShouldKeepZeroCoords) args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + AllOf(WithSource(AINPUT_SOURCE_MOUSE), WithMotionAction(HOVER_MOVE), WithCoords(0.0f, 0.0f), WithPressure(0.0f), WithSize(0.0f), WithTouchDimensions(0.0f, 0.0f), WithToolDimensions(0.0f, 0.0f), WithOrientation(0.0f), WithDistance(0.0f))))); @@ -897,13 +873,11 @@ TEST_F(CursorInputMapperUnitTest, ProcessRegularScroll) { args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))), + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)), VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(1.0f, 1.0f))))); + EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithSource(AINPUT_SOURCE_MOUSE)))); } TEST_F(CursorInputMapperUnitTest, ProcessHighResScroll) { @@ -920,13 +894,11 @@ TEST_F(CursorInputMapperUnitTest, ProcessHighResScroll) { args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))), + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)), VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(0.5f, 0.5f))))); + EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithSource(AINPUT_SOURCE_MOUSE)))); } TEST_F(CursorInputMapperUnitTest, HighResScrollIgnoresRegularScroll) { @@ -945,13 +917,11 @@ TEST_F(CursorInputMapperUnitTest, HighResScrollIgnoresRegularScroll) { args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))), + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)), VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(0.5f, 0.5f))))); + EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithSource(AINPUT_SOURCE_MOUSE)))); } TEST_F(CursorInputMapperUnitTest, ProcessReversedVerticalScroll) { @@ -966,13 +936,11 @@ TEST_F(CursorInputMapperUnitTest, ProcessReversedVerticalScroll) { // Reversed vertical scrolling only affects the y-axis, expect it to be -1.0f to indicate the // inverted scroll direction. EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))), + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)), VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(1.0f, -1.0f))))); + EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithSource(AINPUT_SOURCE_MOUSE)))); } TEST_F(CursorInputMapperUnitTest, ProcessHighResReversedVerticalScroll) { @@ -990,13 +958,11 @@ TEST_F(CursorInputMapperUnitTest, ProcessHighResReversedVerticalScroll) { args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))), + ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)), VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(0.5f, -0.5f))))); + EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithSource(AINPUT_SOURCE_MOUSE)))); } /** @@ -1005,10 +971,6 @@ TEST_F(CursorInputMapperUnitTest, ProcessHighResReversedVerticalScroll) { */ TEST_F(CursorInputMapperUnitTest, PointerCaptureDisablesVelocityProcessing) { mPropertyMap.addProperty("cursor.mode", "pointer"); - const VelocityControlParameters testParams(/*scale=*/5.f, /*lowThreshold=*/0.f, - /*highThreshold=*/100.f, /*acceleration=*/10.f); - mReaderConfiguration.pointerVelocityControlParameters = testParams; - mFakePolicy->setVelocityControlParams(testParams); createMapper(); NotifyMotionArgs motionArgs; @@ -1020,8 +982,7 @@ TEST_F(CursorInputMapperUnitTest, PointerCaptureDisablesVelocityProcessing) { args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))))); + AllOf(WithSource(AINPUT_SOURCE_MOUSE), WithMotionAction(HOVER_MOVE))))); motionArgs = std::get<NotifyMotionArgs>(args.front()); const float relX = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); const float relY = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); @@ -1039,12 +1000,7 @@ TEST_F(CursorInputMapperUnitTest, PointerCaptureDisablesVelocityProcessing) { EXPECT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithSource(AINPUT_SOURCE_MOUSE_RELATIVE), - WithMotionAction(AMOTION_EVENT_ACTION_MOVE))))); - motionArgs = std::get<NotifyMotionArgs>(args.front()); - const float relX2 = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); - const float relY2 = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); - ASSERT_EQ(10, relX2); - ASSERT_EQ(20, relY2); + WithMotionAction(ACTION_MOVE), WithRelativeMotion(10, 20))))); } TEST_F(CursorInputMapperUnitTest, ConfigureDisplayIdNoAssociatedViewport) { @@ -1067,54 +1023,12 @@ TEST_F(CursorInputMapperUnitTest, ConfigureDisplayIdNoAssociatedViewport) { args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), - WithSource(AINPUT_SOURCE_MOUSE), + AllOf(WithMotionAction(HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE), WithDisplayId(ui::LogicalDisplayId::INVALID), WithCoords(0.0f, 0.0f))))); } -// TODO(b/320433834): De-duplicate the test cases once the flag is removed. -class CursorInputMapperUnitTestWithNewBallistics : public CursorInputMapperUnitTestBase { -protected: - void SetUp() override { - input_flags::enable_new_mouse_pointer_ballistics(true); - CursorInputMapperUnitTestBase::SetUp(); - } -}; - -TEST_F(CursorInputMapperUnitTestWithNewBallistics, PointerCaptureDisablesVelocityProcessing) { - mPropertyMap.addProperty("cursor.mode", "pointer"); - createMapper(); - - NotifyMotionArgs motionArgs; - std::list<NotifyArgs> args; - - // Move and verify scale is applied. - args += process(ARBITRARY_TIME, EV_REL, REL_X, 10); - args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20); - args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); - motionArgs = std::get<NotifyMotionArgs>(args.front()); - const float relX = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); - const float relY = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); - ASSERT_GT(relX, 10); - ASSERT_GT(relY, 20); - args.clear(); - - // Enable Pointer Capture - setPointerCapture(true); - - // Move and verify scale is not applied. - args += process(ARBITRARY_TIME, EV_REL, REL_X, 10); - args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20); - args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); - motionArgs = std::get<NotifyMotionArgs>(args.front()); - const float relX2 = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); - const float relY2 = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); - ASSERT_EQ(10, relX2); - ASSERT_EQ(20, relY2); -} - -TEST_F(CursorInputMapperUnitTestWithNewBallistics, ConfigureAccelerationWithAssociatedViewport) { +TEST_F(CursorInputMapperUnitTest, ConfigureAccelerationWithAssociatedViewport) { mPropertyMap.addProperty("cursor.mode", "pointer"); DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation0); mReaderConfiguration.setDisplayViewports({primaryViewport}); @@ -1149,7 +1063,7 @@ TEST_F(CursorInputMapperUnitTestWithNewBallistics, ConfigureAccelerationWithAsso WithRelativeMotion(10, 20))))); } -TEST_F(CursorInputMapperUnitTestWithNewBallistics, ConfigureAccelerationOnDisplayChange) { +TEST_F(CursorInputMapperUnitTest, ConfigureAccelerationOnDisplayChange) { mPropertyMap.addProperty("cursor.mode", "pointer"); DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation0); mReaderConfiguration.setDisplayViewports({primaryViewport}); @@ -1186,72 +1100,6 @@ TEST_F(CursorInputMapperUnitTestWithNewBallistics, ConfigureAccelerationOnDispla WithRelativeMotion(10, 20))))); } -TEST_F(CursorInputMapperUnitTestWithNewBallistics, ProcessRegularScroll) { - createMapper(); - - std::list<NotifyArgs> args; - args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1); - args += process(ARBITRARY_TIME, EV_REL, REL_HWHEEL, 1); - args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); - - EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))), - VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), - WithScroll(1.0f, 1.0f))))); -} - -TEST_F(CursorInputMapperUnitTestWithNewBallistics, ProcessHighResScroll) { - vd_flags::high_resolution_scroll(true); - EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL_HI_RES)) - .WillRepeatedly(Return(true)); - EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_HWHEEL_HI_RES)) - .WillRepeatedly(Return(true)); - createMapper(); - - std::list<NotifyArgs> args; - args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL_HI_RES, 60); - args += process(ARBITRARY_TIME, EV_REL, REL_HWHEEL_HI_RES, 60); - args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); - - EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))), - VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), - WithScroll(0.5f, 0.5f))))); -} - -TEST_F(CursorInputMapperUnitTestWithNewBallistics, HighResScrollIgnoresRegularScroll) { - vd_flags::high_resolution_scroll(true); - EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL_HI_RES)) - .WillRepeatedly(Return(true)); - EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_HWHEEL_HI_RES)) - .WillRepeatedly(Return(true)); - createMapper(); - - std::list<NotifyArgs> args; - args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL_HI_RES, 60); - args += process(ARBITRARY_TIME, EV_REL, REL_HWHEEL_HI_RES, 60); - args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1); - args += process(ARBITRARY_TIME, EV_REL, REL_HWHEEL, 1); - args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); - - EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))), - VariantWith<NotifyMotionArgs>( - AllOf(WithSource(AINPUT_SOURCE_MOUSE), - WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), - WithScroll(0.5f, 0.5f))))); -} - namespace { // Minimum timestamp separation between subsequent input events from a Bluetooth device. @@ -1279,8 +1127,7 @@ TEST_F(BluetoothCursorInputMapperUnitTest, TimestampSmoothening) { argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), - WithEventTime(expectedEventTime))))); + AllOf(WithMotionAction(HOVER_MOVE), WithEventTime(expectedEventTime))))); argsList.clear(); // Process several events that come in quick succession, according to their timestamps. @@ -1294,7 +1141,7 @@ TEST_F(BluetoothCursorInputMapperUnitTest, TimestampSmoothening) { argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + AllOf(WithMotionAction(HOVER_MOVE), WithEventTime(expectedEventTime))))); argsList.clear(); } @@ -1310,8 +1157,7 @@ TEST_F(BluetoothCursorInputMapperUnitTest, TimestampSmootheningIsCapped) { argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), - WithEventTime(expectedEventTime))))); + AllOf(WithMotionAction(HOVER_MOVE), WithEventTime(expectedEventTime))))); argsList.clear(); // Process several events with the same timestamp from the kernel. @@ -1325,7 +1171,7 @@ TEST_F(BluetoothCursorInputMapperUnitTest, TimestampSmootheningIsCapped) { argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), + AllOf(WithMotionAction(HOVER_MOVE), WithEventTime(expectedEventTime))))); argsList.clear(); } @@ -1338,8 +1184,7 @@ TEST_F(BluetoothCursorInputMapperUnitTest, TimestampSmootheningIsCapped) { argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), - WithEventTime(cappedEventTime))))); + AllOf(WithMotionAction(HOVER_MOVE), WithEventTime(cappedEventTime))))); argsList.clear(); } } @@ -1355,8 +1200,7 @@ TEST_F(BluetoothCursorInputMapperUnitTest, TimestampSmootheningNotUsed) { argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), - WithEventTime(expectedEventTime))))); + AllOf(WithMotionAction(HOVER_MOVE), WithEventTime(expectedEventTime))))); argsList.clear(); // If the next event has a timestamp that is sufficiently spaced out so that Bluetooth timestamp @@ -1368,8 +1212,7 @@ TEST_F(BluetoothCursorInputMapperUnitTest, TimestampSmootheningNotUsed) { argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0); EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), - WithEventTime(expectedEventTime))))); + AllOf(WithMotionAction(HOVER_MOVE), WithEventTime(expectedEventTime))))); argsList.clear(); } diff --git a/services/inputflinger/tests/FakeEventHub.cpp b/services/inputflinger/tests/FakeEventHub.cpp index 943de6e3cf..e72c440480 100644 --- a/services/inputflinger/tests/FakeEventHub.cpp +++ b/services/inputflinger/tests/FakeEventHub.cpp @@ -650,4 +650,25 @@ void FakeEventHub::sysfsNodeChanged(const std::string& sysfsNodePath) { } } +bool FakeEventHub::setKernelWakeEnabled(int32_t deviceId, bool enabled) { + Device* device = getDevice(deviceId); + if (device == nullptr) { + return false; + } + mKernelWakeup.emplace(deviceId, enabled); + return true; +} + +bool FakeEventHub::fakeReadKernelWakeup(int32_t deviceId) const { + Device* device = getDevice(deviceId); + if (device == nullptr) { + return false; + } + auto it = mKernelWakeup.find(deviceId); + if (it == mKernelWakeup.end()) { + return false; + } + return it->second; +} + } // namespace android diff --git a/services/inputflinger/tests/FakeEventHub.h b/services/inputflinger/tests/FakeEventHub.h index 2dfbb2388a..143b93b245 100644 --- a/services/inputflinger/tests/FakeEventHub.h +++ b/services/inputflinger/tests/FakeEventHub.h @@ -94,6 +94,8 @@ class FakeEventHub : public EventHubInterface { // Simulates a device light intensities, from light id to light intensities map. std::unordered_map<int32_t /* lightId */, std::unordered_map<LightColor, int32_t>> mLightIntensities; + // fake sysfs node path and value. + std::unordered_map<int32_t /*deviceId*/, bool /* wakeupNode*/> mKernelWakeup; public: static constexpr int32_t DEFAULT_BATTERY = 1; @@ -158,6 +160,8 @@ public: void setMtSlotValues(int32_t deviceId, int32_t axis, const std::vector<int32_t>& values); base::Result<std::vector<int32_t>> getMtSlotValues(int32_t deviceId, int32_t axis, size_t slotCount) const override; + bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override; + bool fakeReadKernelWakeup(int32_t deviceId) const; private: Device* getDevice(int32_t deviceId) const; diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp index f373cac085..7c5f350c0e 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp +++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp @@ -217,7 +217,6 @@ float FakeInputReaderPolicy::getPointerGestureZoomSpeedRatio() { } void FakeInputReaderPolicy::setVelocityControlParams(const VelocityControlParameters& params) { - mConfig.pointerVelocityControlParameters = params; mConfig.wheelVelocityControlParameters = params; } diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 6c8b65c018..19b738ea9d 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1392,6 +1392,20 @@ TEST_F(InputReaderTest, LightGetColor) { ASSERT_EQ(mReader->getLightColor(deviceId, /*lightId=*/1), LIGHT_BRIGHTNESS); } +TEST_F(InputReaderTest, SetPowerWakeUp) { + ASSERT_NO_FATAL_FAILURE(addDevice(1, "1st", InputDeviceClass::KEYBOARD, nullptr)); + ASSERT_NO_FATAL_FAILURE(addDevice(2, "2nd", InputDeviceClass::KEYBOARD, nullptr)); + ASSERT_NO_FATAL_FAILURE(addDevice(3, "3rd", InputDeviceClass::KEYBOARD, nullptr)); + + ASSERT_EQ(mFakeEventHub->fakeReadKernelWakeup(1), false); + + ASSERT_TRUE(mFakeEventHub->setKernelWakeEnabled(2, true)); + ASSERT_EQ(mFakeEventHub->fakeReadKernelWakeup(2), true); + + ASSERT_TRUE(mFakeEventHub->setKernelWakeEnabled(3, false)); + ASSERT_EQ(mFakeEventHub->fakeReadKernelWakeup(3), false); +} + // --- InputReaderIntegrationTest --- // These tests create and interact with the InputReader only through its interface. diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h index a43e4e4d80..25e2b4557e 100644 --- a/services/inputflinger/tests/InterfaceMocks.h +++ b/services/inputflinger/tests/InterfaceMocks.h @@ -180,6 +180,7 @@ public: MOCK_METHOD(status_t, enableDevice, (int32_t deviceId), (override)); MOCK_METHOD(status_t, disableDevice, (int32_t deviceId), (override)); MOCK_METHOD(void, sysfsNodeChanged, (const std::string& sysfsNodePath), (override)); + MOCK_METHOD(bool, setKernelWakeEnabled, (int32_t deviceId, bool enabled), (override)); }; class MockPointerChoreographerPolicyInterface : public PointerChoreographerPolicyInterface { diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp index 5442a65f2f..64f3c279a6 100644 --- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp @@ -171,6 +171,10 @@ public: void notifyMouseCursorFadedOnTyping() override { reader->notifyMouseCursorFadedOnTyping(); } + bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override { + return reader->setKernelWakeEnabled(deviceId, enabled); + } + private: std::unique_ptr<InputReaderInterface> reader; }; diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index fa8270a3d9..60c676da58 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -269,6 +269,9 @@ public: status_t enableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); } status_t disableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); } void sysfsNodeChanged(const std::string& sysfsNodePath) override {} + bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override { + return mFdp->ConsumeBool(); + } }; class FuzzInputReaderPolicy : public InputReaderPolicyInterface { diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 14a8fd6ad7..8a91a07115 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -19,6 +19,7 @@ #include <cstdint> #include <android/gui/CachingHint.h> +#include <gui/DisplayLuts.h> #include <gui/HdrMetadata.h> #include <math/mat4.h> #include <ui/BlurRegion.h> @@ -219,6 +220,9 @@ struct LayerFECompositionState { float desiredHdrSdrRatio = 1.f; gui::CachingHint cachingHint = gui::CachingHint::Enabled; + + std::shared_ptr<gui::DisplayLuts> luts; + virtual ~LayerFECompositionState(); // Debugging diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 191d475e5d..556aa249a3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -329,6 +329,8 @@ protected: virtual bool isPowerHintSessionGpuReportingEnabled() = 0; virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0; virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0; + virtual const aidl::android::hardware::graphics::composer3::OverlayProperties* + getOverlaySupport() = 0; }; } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index dcfe21a849..80c5124c76 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -93,7 +93,10 @@ public: // transform, if needed. virtual void updateCompositionState( bool includeGeometry, bool forceClientComposition, - ui::Transform::RotationFlags internalDisplayRotationFlags) = 0; + ui::Transform::RotationFlags internalDisplayRotationFlags, + const std::optional<std::vector< + std::optional<aidl::android::hardware::graphics::composer3::LutProperties>>> + properties) = 0; // 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 @@ -129,8 +132,10 @@ public: virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0; // Applies a HWC device layer lut - virtual void applyDeviceLayerLut(aidl::android::hardware::graphics::composer3::LutProperties, - ndk::ScopedFileDescriptor) = 0; + virtual void applyDeviceLayerLut( + ndk::ScopedFileDescriptor, + std::vector<std::pair< + int, aidl::android::hardware::graphics::composer3::LutProperties>>) = 0; // Returns true if the composition settings scale pixels virtual bool needsFiltering() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index a39abb40d2..d8466ffdff 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -103,6 +103,8 @@ private: DisplayId mId; bool mIsDisconnected = false; Hwc2::PowerAdvisor* mPowerAdvisor = nullptr; + const aidl::android::hardware::graphics::composer3::OverlayProperties* getOverlaySupport() + override; }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 9990a742db..69e1efc4a7 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -164,6 +164,8 @@ protected: bool mustRecompose() const; const std::string& getNamePlusId() const { return mNamePlusId; } + const aidl::android::hardware::graphics::composer3::OverlayProperties* getOverlaySupport() + override; private: void dirtyEntireOutput(); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index 354a4416f2..0c7e4dd071 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -31,6 +31,8 @@ #include <aidl/android/hardware/graphics/composer3/Composition.h> +using aidl::android::hardware::graphics::composer3::LutProperties; + namespace android::compositionengine { struct LayerFECompositionState; @@ -48,7 +50,9 @@ public: void uncacheBuffers(const std::vector<uint64_t>& bufferIdsToUncache) override; void updateCompositionState(bool includeGeometry, bool forceClientComposition, - ui::Transform::RotationFlags) override; + ui::Transform::RotationFlags, + const std::optional<std::vector<std::optional<LutProperties>>> + properties = std::nullopt) override; void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, bool zIsOverridden, bool isPeekingThrough) override; void writeCursorPositionToHWC() const override; @@ -60,8 +64,8 @@ public: aidl::android::hardware::graphics::composer3::Composition) override; void prepareForDeviceLayerRequests() override; void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override; - void applyDeviceLayerLut(aidl::android::hardware::graphics::composer3::LutProperties, - ndk::ScopedFileDescriptor) override; + void applyDeviceLayerLut(ndk::ScopedFileDescriptor, + std::vector<std::pair<int, LutProperties>>) override; bool needsFiltering() const override; std::optional<LayerFE::LayerSettings> getOverrideCompositionSettings() const override; @@ -92,10 +96,13 @@ private: void writeCompositionTypeToHWC(HWC2::Layer*, aidl::android::hardware::graphics::composer3::Composition, bool isPeekingThrough, bool skipLayer); + void writeLutToHWC(HWC2::Layer*, const LayerFECompositionState&); void detectDisallowedCompositionTypeChange( aidl::android::hardware::graphics::composer3::Composition from, aidl::android::hardware::graphics::composer3::Composition to) const; bool isClientCompositionForced(bool isPeekingThrough) const; + void updateLuts(std::shared_ptr<gui::DisplayLuts> luts, + const std::optional<std::vector<std::optional<LutProperties>>>& properties); }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index 6c419da716..28216a475c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -18,6 +18,7 @@ #include <compositionengine/ProjectionSpace.h> #include <compositionengine/impl/HwcBufferCache.h> +#include <gui/DisplayLuts.h> #include <renderengine/ExternalTexture.h> #include <ui/FloatRect.h> #include <ui/GraphicTypes.h> @@ -151,6 +152,9 @@ struct OutputLayerCompositionState { // True when this layer was skipped as part of SF-side layer caching. bool layerSkipped = false; + + // lut information + std::shared_ptr<gui::DisplayLuts> luts; }; // The HWC state is optional, and is only set up if there is any potential diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index d5bf2b5090..33cdc54b90 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -140,6 +140,8 @@ public: MOCK_METHOD(void, setHintSessionRequiresRenderEngine, (bool requiresRenderEngine)); MOCK_METHOD(bool, isPowerHintSessionEnabled, ()); MOCK_METHOD(bool, isPowerHintSessionGpuReportingEnabled, ()); + MOCK_METHOD((const aidl::android::hardware::graphics::composer3::OverlayProperties*), + getOverlaySupport, ()); }; } // 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 48c2f9c483..12f20942cb 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -43,7 +43,10 @@ public: MOCK_CONST_METHOD0(getState, const impl::OutputLayerCompositionState&()); MOCK_METHOD0(editState, impl::OutputLayerCompositionState&()); - MOCK_METHOD3(updateCompositionState, void(bool, bool, ui::Transform::RotationFlags)); + MOCK_METHOD(void, updateCompositionState, + (bool, bool, ui::Transform::RotationFlags, + (const std::optional<std::vector<std::optional< + aidl::android::hardware::graphics::composer3::LutProperties>>>))); MOCK_METHOD5(writeStateToHWC, void(bool, bool, uint32_t, bool, bool)); MOCK_CONST_METHOD0(writeCursorPositionToHWC, void()); @@ -57,8 +60,9 @@ public: MOCK_CONST_METHOD0(needsFiltering, bool()); MOCK_CONST_METHOD0(getOverrideCompositionSettings, std::optional<LayerFE::LayerSettings>()); MOCK_METHOD(void, applyDeviceLayerLut, - (aidl::android::hardware::graphics::composer3::LutProperties, - ndk::ScopedFileDescriptor)); + (ndk::ScopedFileDescriptor, + (std::vector<std::pair< + int, aidl::android::hardware::graphics::composer3::LutProperties>>))); MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index b0164b7c33..1825065c8f 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -370,8 +370,8 @@ void Display::applyLayerLutsToLayers(const LayerLuts& layerLuts) { if (auto lutsIt = layerLuts.find(hwcLayer); lutsIt != layerLuts.end()) { if (auto mapperIt = mapper.find(hwcLayer); mapperIt != mapper.end()) { - layer->applyDeviceLayerLut(lutsIt->second, - ndk::ScopedFileDescriptor(mapperIt->second.release())); + layer->applyDeviceLayerLut(ndk::ScopedFileDescriptor(mapperIt->second.release()), + lutsIt->second); } } } @@ -457,6 +457,11 @@ void Display::setHintSessionRequiresRenderEngine(bool requiresRenderEngine) { mPowerAdvisor->setRequiresRenderEngine(mId, requiresRenderEngine); } +const aidl::android::hardware::graphics::composer3::OverlayProperties* +Display::getOverlaySupport() { + return &getCompositionEngine().getHwComposer().getOverlaySupport(); +} + void Display::finishFrame(GpuCompositionResult&& result) { // We only need to actually compose the display if: // 1) It is being handled by hardware composer, which may need this to diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 22ab3d953b..bb456138d6 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -813,11 +813,14 @@ void Output::updateCompositionState(const compositionengine::CompositionRefreshA mLayerRequestingBackgroundBlur = findLayerRequestingBackgroundComposition(); bool forceClientComposition = mLayerRequestingBackgroundBlur != nullptr; + auto* properties = getOverlaySupport(); + for (auto* layer : getOutputLayersOrderedByZ()) { layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame, refreshArgs.devOptForceClientComposition || forceClientComposition, - refreshArgs.internalDisplayRotationFlags); + refreshArgs.internalDisplayRotationFlags, + properties ? properties->lutProperties : std::nullopt); if (mLayerRequestingBackgroundBlur == layer) { forceClientComposition = false; @@ -1678,6 +1681,10 @@ void Output::setTreat170mAsSrgb(bool enable) { editState().treat170mAsSrgb = enable; } +const aidl::android::hardware::graphics::composer3::OverlayProperties* Output::getOverlaySupport() { + return nullptr; +} + bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) { uint64_t lastOutputLayerHash = getState().lastOutputLayerHash; uint64_t outputLayerHash = getState().outputLayerHash; diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 2d46dc0702..934909d066 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -38,7 +38,7 @@ #pragma clang diagnostic pop // ignored "-Wconversion" using aidl::android::hardware::graphics::composer3::Composition; -using aidl::android::hardware::graphics::composer3::LutProperties; +using aidl::android::hardware::graphics::composer3::Luts; namespace android::compositionengine { @@ -285,9 +285,50 @@ uint32_t OutputLayer::calculateOutputRelativeBufferTransform( return transform.getOrientation(); } +void OutputLayer::updateLuts( + std::shared_ptr<gui::DisplayLuts> layerFEStateLut, + const std::optional<std::vector<std::optional<LutProperties>>>& properties) { + auto& state = editState(); + + if (!properties) { + // GPU composition if no Hwc Luts + state.forceClientComposition = true; + return; + } + + std::vector<LutProperties> hwcLutProperties; + for (auto& p : *properties) { + if (p) { + hwcLutProperties.emplace_back(*p); + } + } + + for (const auto& inputLut : layerFEStateLut->lutProperties) { + bool foundInHwcLuts = false; + for (const auto& hwcLut : hwcLutProperties) { + if (static_cast<int32_t>(hwcLut.dimension) == + static_cast<int32_t>(inputLut.dimension) && + hwcLut.size == inputLut.size && + std::find(hwcLut.samplingKeys.begin(), hwcLut.samplingKeys.end(), + static_cast<LutProperties::SamplingKey>(inputLut.samplingKey)) != + hwcLut.samplingKeys.end()) { + foundInHwcLuts = true; + break; + } + } + // if any lut properties of layerFEStateLut can not be found in hwcLutProperties, + // GPU composition instead + if (!foundInHwcLuts) { + state.forceClientComposition = true; + return; + } + } +} + void OutputLayer::updateCompositionState( bool includeGeometry, bool forceClientComposition, - ui::Transform::RotationFlags internalDisplayRotationFlags) { + ui::Transform::RotationFlags internalDisplayRotationFlags, + const std::optional<std::vector<std::optional<LutProperties>>> properties) { const auto* layerFEState = getLayerFE().getCompositionState(); if (!layerFEState) { return; @@ -368,6 +409,11 @@ void OutputLayer::updateCompositionState( state.whitePointNits = layerBrightnessNits; } + const auto& layerFEStateLut = layerFEState->luts; + if (layerFEStateLut) { + updateLuts(layerFEStateLut, properties); + } + // These are evaluated every frame as they can potentially change at any // time. if (layerFEState->forceClientComposition || !profile.isDataspaceSupported(state.dataspace) || @@ -420,6 +466,8 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough, skipLayer); + writeLutToHWC(hwcLayer.get(), *outputIndependentState); + if (requestedCompositionType == Composition::SOLID_COLOR) { writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState); } @@ -513,6 +561,40 @@ void OutputLayer::writeOutputIndependentGeometryStateToHWC( } } +void OutputLayer::writeLutToHWC(HWC2::Layer* hwcLayer, + const LayerFECompositionState& outputIndependentState) { + if (!outputIndependentState.luts) { + return; + } + auto& lutFileDescriptor = outputIndependentState.luts->getLutFileDescriptor(); + auto lutOffsets = outputIndependentState.luts->offsets; + auto& lutProperties = outputIndependentState.luts->lutProperties; + + std::vector<LutProperties> aidlProperties; + aidlProperties.reserve(lutProperties.size()); + for (size_t i = 0; i < lutOffsets.size(); i++) { + LutProperties properties; + properties.dimension = static_cast<LutProperties::Dimension>(lutProperties[i].dimension); + properties.size = lutProperties[i].size; + properties.samplingKeys = { + static_cast<LutProperties::SamplingKey>(lutProperties[i].samplingKey)}; + aidlProperties.emplace_back(properties); + } + + Luts luts; + luts.pfd = ndk::ScopedFileDescriptor(dup(lutFileDescriptor.get())); + luts.offsets = lutOffsets; + luts.lutProperties = std::move(aidlProperties); + + switch (auto error = hwcLayer->setLuts(luts)) { + case hal::Error::NONE: + break; + default: + ALOGE("[%s] Failed to set Luts: %s (%d)", getLayerFE().getDebugName(), + to_string(error).c_str(), static_cast<int32_t>(error)); + } +} + void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) { const auto& outputDependentState = getState(); @@ -849,10 +931,29 @@ void OutputLayer::applyDeviceLayerRequest(hal::LayerRequest request) { } } -void OutputLayer::applyDeviceLayerLut(LutProperties /*lutProperties*/, - ndk::ScopedFileDescriptor /*lutPfd*/) { - // TODO(b/329472856): decode the shared memory of the pfd, and store the lut data into - // OutputLayerCompositionState#hwc struct +void OutputLayer::applyDeviceLayerLut( + ndk::ScopedFileDescriptor lutFileDescriptor, + std::vector<std::pair<int, LutProperties>> lutOffsetsAndProperties) { + auto& state = editState(); + LOG_FATAL_IF(!state.hwc); + auto& hwcState = *state.hwc; + std::vector<int32_t> offsets; + std::vector<int32_t> dimensions; + std::vector<int32_t> sizes; + std::vector<int32_t> samplingKeys; + for (const auto& [offset, properties] : lutOffsetsAndProperties) { + // The Lut(s) that comes back through CommandResultPayload should be + // only one sampling key. + if (properties.samplingKeys.size() == 1) { + offsets.emplace_back(offset); + dimensions.emplace_back(static_cast<int32_t>(properties.dimension)); + sizes.emplace_back(static_cast<int32_t>(properties.size)); + samplingKeys.emplace_back(static_cast<int32_t>(properties.samplingKeys[0])); + } + } + hwcState.luts = std::make_shared<gui::DisplayLuts>(base::unique_fd(lutFileDescriptor.release()), + std::move(offsets), std::move(dimensions), + std::move(sizes), std::move(samplingKeys)); } bool OutputLayer::needsFiltering() const { diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h index eb6e677117..26b5f4aaed 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h @@ -33,7 +33,7 @@ #include "DisplayHardware/HWC2.h" #include <aidl/android/hardware/graphics/composer3/Composition.h> -#include <aidl/android/hardware/graphics/composer3/Lut.h> +#include <aidl/android/hardware/graphics/composer3/Luts.h> // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" @@ -78,7 +78,7 @@ public: Error(const std::string&, bool, const std::vector<uint8_t>&)); MOCK_METHOD1(setBrightness, Error(float)); MOCK_METHOD1(setBlockingRegion, Error(const android::Region&)); - MOCK_METHOD(Error, setLuts, (std::vector<aidl::android::hardware::graphics::composer3::Lut>&)); + MOCK_METHOD(Error, setLuts, (aidl::android::hardware::graphics::composer3::Luts&)); }; } // namespace mock diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 1c18cd28c5..74ff12407b 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -785,17 +785,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerContentForAllLayers InjectedLayer layer3; uint32_t z = 0; - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); + EXPECT_CALL(*layer1.outputLayer, + updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); + EXPECT_CALL(*layer2.outputLayer, + updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); + EXPECT_CALL(*layer3.outputLayer, + updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -822,17 +825,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerGeometryAndContentF InjectedLayer layer3; uint32_t z = 0; - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -858,17 +861,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, forcesClientCompositionForAllLa InjectedLayer layer3; uint32_t z = 0; - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -896,11 +899,11 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) { InjectedLayer layer3; InSequence seq; - EXPECT_CALL(*layer0.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer0.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); uint32_t z = 0; EXPECT_CALL(*layer0.outputLayer, @@ -4932,12 +4935,12 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, noBackgroundBlurWhenOpaque) { uint32_t z = 0; // Layer requesting blur, or below, should request client composition, unless opaque. - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -4966,17 +4969,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) uint32_t z = 0; // Layer requesting blur, or below, should request client composition. - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -5006,17 +5009,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) { uint32_t z = 0; // Layer requesting blur, or below, should request client composition. - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index 77bd8040c5..5814aa4354 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -44,7 +44,7 @@ using hardware::Return; using aidl::android::hardware::graphics::composer3::BnComposerCallback; using aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness; -using aidl::android::hardware::graphics::composer3::Lut; +using aidl::android::hardware::graphics::composer3::Luts; using aidl::android::hardware::graphics::composer3::PowerMode; using aidl::android::hardware::graphics::composer3::VirtualDisplay; @@ -1565,7 +1565,7 @@ Error AidlComposer::getRequestedLuts(Display display, std::vector<Layer>* outLay return error; } -Error AidlComposer::setLayerLuts(Display display, Layer layer, std::vector<Lut>& luts) { +Error AidlComposer::setLayerLuts(Display display, Layer layer, Luts& luts) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index cdb67e4e5c..d724b218c0 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -53,6 +53,7 @@ using aidl::android::hardware::graphics::common::HdrConversionCapability; using aidl::android::hardware::graphics::common::HdrConversionStrategy; using aidl::android::hardware::graphics::composer3::ComposerClientReader; using aidl::android::hardware::graphics::composer3::ComposerClientWriter; +using aidl::android::hardware::graphics::composer3::Luts; using aidl::android::hardware::graphics::composer3::OverlayProperties; class AidlIComposerCallbackWrapper; @@ -248,9 +249,7 @@ public: Display display, std::vector<Layer>* outLayers, std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>* outLuts) override; - Error setLayerLuts( - Display display, Layer layer, - std::vector<aidl::android::hardware::graphics::composer3::Lut>& luts) override; + Error setLayerLuts(Display display, Layer layer, Luts& luts) override; private: // Many public functions above simply write a command into the command diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 09056631d0..42ddcd18c8 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -42,7 +42,6 @@ #include <aidl/android/hardware/graphics/composer3/DisplayConfiguration.h> #include <aidl/android/hardware/graphics/composer3/DisplayLuts.h> #include <aidl/android/hardware/graphics/composer3/IComposerCallback.h> -#include <aidl/android/hardware/graphics/composer3/Lut.h> #include <aidl/android/hardware/graphics/composer3/OverlayProperties.h> #include <aidl/android/hardware/graphics/common/Transform.h> @@ -307,7 +306,7 @@ public: int32_t frameIntervalNs) = 0; virtual Error getRequestedLuts(Display display, std::vector<Layer>* outLayers, std::vector<V3_0::DisplayLuts::LayerLut>* outLuts) = 0; - virtual Error setLayerLuts(Display display, Layer layer, std::vector<V3_0::Lut>& luts) = 0; + virtual Error setLayerLuts(Display display, Layer layer, V3_0::Luts& luts) = 0; }; } // namespace Hwc2 diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 1df2ab12ce..5355a12cda 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -42,7 +42,8 @@ using aidl::android::hardware::graphics::composer3::Composition; using AidlCapability = aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::DisplayCapability; using aidl::android::hardware::graphics::composer3::DisplayLuts; -using aidl::android::hardware::graphics::composer3::Lut; +using aidl::android::hardware::graphics::composer3::LutProperties; +using aidl::android::hardware::graphics::composer3::Luts; using aidl::android::hardware::graphics::composer3::OverlayProperties; namespace android { @@ -624,10 +625,18 @@ Error Display::getRequestedLuts(LayerLuts* outLuts, auto layer = getLayerById(layerIds[i]); if (layer) { auto& layerLut = tmpLuts[i]; - outLuts->emplace_or_replace(layer.get(), layerLut.lut.lutProperties); - lutFileDescriptorMapper.emplace_or_replace(layer.get(), - ndk::ScopedFileDescriptor( - layerLut.lut.pfd.release())); + if (layerLut.luts.pfd.get() > 0 && layerLut.luts.offsets.has_value()) { + const auto& offsets = layerLut.luts.offsets.value(); + std::vector<std::pair<int32_t, LutProperties>> lutOffsetsAndProperties; + lutOffsetsAndProperties.reserve(offsets.size()); + std::transform(offsets.begin(), offsets.end(), layerLut.luts.lutProperties.begin(), + std::back_inserter(lutOffsetsAndProperties), + [](int32_t i, LutProperties j) { return std::make_pair(i, j); }); + outLuts->emplace_or_replace(layer.get(), lutOffsetsAndProperties); + lutFileDescriptorMapper.emplace_or_replace(layer.get(), + ndk::ScopedFileDescriptor( + layerLut.luts.pfd.release())); + } } } @@ -1069,7 +1078,7 @@ Error Layer::setBlockingRegion(const Region& region) { return static_cast<Error>(intError); } -Error Layer::setLuts(std::vector<Lut>& luts) { +Error Layer::setLuts(aidl::android::hardware::graphics::composer3::Luts& luts) { if (CC_UNLIKELY(!mDisplay)) { return Error::BAD_DISPLAY; } diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 61f92f4d74..799fd02586 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -46,7 +46,7 @@ #include <aidl/android/hardware/graphics/composer3/Color.h> #include <aidl/android/hardware/graphics/composer3/Composition.h> #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h> -#include <aidl/android/hardware/graphics/composer3/Lut.h> +#include <aidl/android/hardware/graphics/composer3/Luts.h> #include <aidl/android/hardware/graphics/composer3/OverlayProperties.h> #include <aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.h> @@ -109,9 +109,10 @@ public: virtual std::optional<ui::Size> getPhysicalSizeInMm() const = 0; static const int kLutFileDescriptorMapperSize = 20; + using LutOffsetAndProperties = std::vector< + std::pair<int32_t, aidl::android::hardware::graphics::composer3::LutProperties>>; using LayerLuts = - ftl::SmallMap<HWC2::Layer*, aidl::android::hardware::graphics::composer3::LutProperties, - kLutFileDescriptorMapperSize>; + ftl::SmallMap<HWC2::Layer*, LutOffsetAndProperties, kLutFileDescriptorMapperSize>; using LutFileDescriptorMapper = ftl::SmallMap<HWC2::Layer*, ndk::ScopedFileDescriptor, kLutFileDescriptorMapperSize>; @@ -375,7 +376,7 @@ public: [[nodiscard]] virtual hal::Error setBrightness(float brightness) = 0; [[nodiscard]] virtual hal::Error setBlockingRegion(const android::Region& region) = 0; [[nodiscard]] virtual hal::Error setLuts( - std::vector<aidl::android::hardware::graphics::composer3::Lut>& luts) = 0; + aidl::android::hardware::graphics::composer3::Luts& luts) = 0; }; namespace impl { @@ -426,8 +427,7 @@ public: // AIDL HAL hal::Error setBrightness(float brightness) override; hal::Error setBlockingRegion(const android::Region& region) override; - hal::Error setLuts( - std::vector<aidl::android::hardware::graphics::composer3::Lut>& luts) override; + hal::Error setLuts(aidl::android::hardware::graphics::composer3::Luts&) override; private: // These are references to data owned by HWComposer, which will outlive diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index 056ecd78f4..6a7a09b5ae 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -47,7 +47,7 @@ using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrig using aidl::android::hardware::graphics::composer3::DimmingStage; using aidl::android::hardware::graphics::composer3::DisplayCapability; using aidl::android::hardware::graphics::composer3::DisplayLuts; -using aidl::android::hardware::graphics::composer3::Lut; +using aidl::android::hardware::graphics::composer3::Luts; using aidl::android::hardware::graphics::composer3::OverlayProperties; namespace android { @@ -1415,7 +1415,7 @@ Error HidlComposer::getRequestedLuts(Display, std::vector<Layer>*, return Error::NONE; } -Error HidlComposer::setLayerLuts(Display, Layer, std::vector<Lut>&) { +Error HidlComposer::setLayerLuts(Display, Layer, Luts&) { return Error::NONE; } diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index 1cc23d1409..a3d1f7f291 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -356,7 +356,7 @@ public: std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*) override; Error setLayerLuts(Display, Layer, - std::vector<aidl::android::hardware::graphics::composer3::Lut>&) override; + aidl::android::hardware::graphics::composer3::Luts&) override; private: class CommandWriter : public CommandWriterBase { diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index 334c104faf..c914ec3066 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -240,7 +240,8 @@ bool PowerAdvisor::ensurePowerHintSessionRunning() { &mSessionConfig); if (ret.isOk()) { mHintSession = ret.value(); - if (FlagManager::getInstance().adpf_use_fmq_channel_fixed()) { + if (FlagManager::getInstance().adpf_use_fmq_channel_fixed() && + FlagManager::getInstance().adpf_fmq_sf()) { setUpFmq(); } } diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index e5f6b7bcd1..11b674b846 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -513,6 +513,10 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate isOpaque = contentOpaque && !roundedCorner.hasRoundedCorners() && color.a == 1.f; blendMode = getBlendMode(requested); } + + if (forceUpdate || requested.what & layer_state_t::eLutsChanged) { + luts = requested.luts; + } } } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index f64ba9e900..a346981ae6 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -174,6 +174,7 @@ std::optional<compositionengine::LayerFE::LayerSettings> LayerFE::prepareClientC layerSettings.edgeExtensionEffect = mSnapshot->edgeExtensionEffect; // Record the name of the layer for debugging further down the stack. layerSettings.name = mSnapshot->name; + layerSettings.luts = mSnapshot->luts; if (hasEffect() && !hasBufferOrSidebandStream()) { prepareEffectsClientComposition(layerSettings, targetSettings); diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index ab9014e418..eca8df27d6 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -722,13 +722,17 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi const bool inPrimaryPhysicalRange = policy->primaryRanges.physical.includes(modePtr->getPeakFps()); const bool inPrimaryRenderRange = policy->primaryRanges.render.includes(fps); - if (((policy->primaryRangeIsSingleRate() && !inPrimaryPhysicalRange) || + if (!mIsVrrDevice.load() && + ((policy->primaryRangeIsSingleRate() && !inPrimaryPhysicalRange) || !inPrimaryRenderRange) && !(layer.focused && (layer.vote == LayerVoteType::ExplicitDefault || layer.vote == LayerVoteType::ExplicitExact))) { // Only focused layers with ExplicitDefault frame rate settings are allowed to score // refresh rates outside the primary range. + ALOGV("%s ignores %s (primaryRangeIsSingleRate). Current mode = %s", + formatLayerInfo(layer, weight).c_str(), to_string(*modePtr).c_str(), + to_string(activeMode).c_str()); continue; } @@ -852,7 +856,8 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi to_string(descending.front().frameRateMode.fps).c_str()); return {descending, kNoSignals}; } else { - ALOGV("primaryRangeIsSingleRate"); + ALOGV("%s (primaryRangeIsSingleRate)", + to_string(ranking.front().frameRateMode.fps).c_str()); SFTRACE_FORMAT_INSTANT("%s (primaryRangeIsSingleRate)", to_string(ranking.front().frameRateMode.fps).c_str()); return {ranking, kNoSignals}; @@ -932,6 +937,8 @@ PerUidLayerRequirements groupLayersByUid( using LayerVoteType = RefreshRateSelector::LayerVoteType; if (layer->vote == LayerVoteType::Max || layer->vote == LayerVoteType::Heuristic) { + ALOGV("%s: %s skips uid=%d due to the vote", __func__, + formatLayerInfo(*layer, layer->weight).c_str(), layer->ownerUid); skipUid = true; break; } @@ -1014,12 +1021,14 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme // Layers with ExplicitExactOrMultiple expect touch boost if (globalSignals.touch && hasExplicitExactOrMultiple) { + ALOGV("%s: Skipping for touch (input signal): uid=%d", __func__, uid); continue; } // Mirrors getRankedFrameRates. If there is no ExplicitDefault, expect touch boost and // skip frame rate override. if (hasHighHint && !hasExplicitDefault) { + ALOGV("%s: Skipping for touch (HighHint): uid=%d", __func__, uid); continue; } @@ -1043,6 +1052,9 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme constexpr bool isSeamlessSwitch = true; const auto layerScore = calculateLayerScoreLocked(*layer, fps, isSeamlessSwitch); score += layer->weight * layerScore; + ALOGV("%s: %s gives %s fps score of %.4f", __func__, + formatLayerInfo(*layer, layer->weight).c_str(), to_string(fps).c_str(), + layerScore); } } @@ -1297,6 +1309,8 @@ void RefreshRateSelector::updateDisplayModes(DisplayModes modes, DisplayModeId a LOG_ALWAYS_FATAL_IF(!activeModeOpt); mActiveModeOpt = FrameRateMode{activeModeOpt->get()->getPeakFps(), ftl::as_non_null(activeModeOpt->get())}; + mIsVrrDevice = FlagManager::getInstance().vrr_config() && + activeModeOpt->get()->getVrrConfig().has_value(); const auto sortedModes = sortByRefreshRate(mDisplayModes); mMinRefreshRateModeIt = sortedModes.front(); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 09dbc59c69..d35a76ad4b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1656,19 +1656,22 @@ status_t SurfaceFlinger::getOverlaySupport(gui::OverlayProperties* outProperties outProperties->combinations.emplace_back(outCombination); } outProperties->supportMixedColorSpaces = aidlProperties.supportMixedColorSpaces; - if (aidlProperties.lutProperties.has_value()) { + if (aidlProperties.lutProperties) { std::vector<gui::LutProperties> outLutProperties; - for (const auto& properties : aidlProperties.lutProperties.value()) { - gui::LutProperties currentProperties; - currentProperties.dimension = - static_cast<gui::LutProperties::Dimension>(properties->dimension); - currentProperties.size = properties->size; - currentProperties.samplingKeys.reserve(properties->samplingKeys.size()); - std::transform(properties->samplingKeys.cbegin(), properties->samplingKeys.cend(), - std::back_inserter(currentProperties.samplingKeys), [](const auto& val) { - return static_cast<gui::LutProperties::SamplingKey>(val); - }); - outLutProperties.push_back(std::move(currentProperties)); + for (auto properties : *aidlProperties.lutProperties) { + if (!properties) { + gui::LutProperties currentProperties; + currentProperties.dimension = + static_cast<gui::LutProperties::Dimension>(properties->dimension); + currentProperties.size = properties->size; + currentProperties.samplingKeys.reserve(properties->samplingKeys.size()); + std::transform(properties->samplingKeys.cbegin(), properties->samplingKeys.cend(), + std::back_inserter(currentProperties.samplingKeys), + [](const auto& val) { + return static_cast<gui::LutProperties::SamplingKey>(val); + }); + outLutProperties.push_back(std::move(currentProperties)); + } } outProperties->lutProperties.emplace(outLutProperties.begin(), outLutProperties.end()); } diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp index e35346a0f6..658bca6f31 100644 --- a/services/surfaceflinger/common/FlagManager.cpp +++ b/services/surfaceflinger/common/FlagManager.cpp @@ -116,6 +116,7 @@ void FlagManager::dump(std::string& result) const { DUMP_SERVER_FLAG(adpf_use_fmq_channel); /// Trunk stable readonly flags /// + DUMP_READ_ONLY_FLAG(adpf_fmq_sf); DUMP_READ_ONLY_FLAG(connected_display); DUMP_READ_ONLY_FLAG(enable_small_area_detection); DUMP_READ_ONLY_FLAG(frame_rate_category_mrr); @@ -221,6 +222,7 @@ FLAG_MANAGER_LEGACY_SERVER_FLAG(use_skia_tracing, PROPERTY_SKIA_ATRACE_ENABLED, "SkiaTracingFeature__use_skia_tracing") /// Trunk stable readonly flags /// +FLAG_MANAGER_READ_ONLY_FLAG(adpf_fmq_sf, "") FLAG_MANAGER_READ_ONLY_FLAG(connected_display, "") FLAG_MANAGER_READ_ONLY_FLAG(enable_small_area_detection, "") FLAG_MANAGER_READ_ONLY_FLAG(frame_rate_category_mrr, "debug.sf.frame_rate_category_mrr") diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h index 5268ffad65..4f34718f4e 100644 --- a/services/surfaceflinger/common/include/common/FlagManager.h +++ b/services/surfaceflinger/common/include/common/FlagManager.h @@ -54,6 +54,7 @@ public: bool adpf_use_fmq_channel_fixed() const; /// Trunk stable readonly flags /// + bool adpf_fmq_sf() const; bool connected_display() const; bool frame_rate_category_mrr() const; bool enable_small_area_detection() const; diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig index 245bc2a35d..f758879687 100644 --- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig @@ -4,6 +4,14 @@ package: "com.android.graphics.surfaceflinger.flags" container: "system" flag { + name: "adpf_fmq_sf" + namespace: "game" + description: "Guards use of the ADPF FMQ system specifically for SurfaceFlinger" + bug: "315894228" + is_fixed_read_only: true +} # adpf_fmq_sf + +flag { name: "adpf_gpu_sf" namespace: "game" description: "Guards use of the sending ADPF GPU duration hint and load hints from SurfaceFlinger to Power HAL" diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp index c879280e57..8375bb9a56 100644 --- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp +++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp @@ -85,6 +85,7 @@ protected: int64_t mSessionId = 123; SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel, true); SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, false); + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, false); }; bool PowerAdvisorTest::sessionExists() { @@ -184,6 +185,7 @@ void PowerAdvisorTest::testGpuScenario(GpuTestConfig& config, WorkDuration& ret) SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_gpu_sf, config.adpfGpuFlagOn); SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, config.usesFmq); + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, config.usesFmq); mPowerAdvisor->onBootFinished(); bool expectsFmqSuccess = config.usesSharedFmqFlag && !config.fmqFull; if (config.usesFmq) { @@ -789,6 +791,7 @@ TEST_F(PowerAdvisorTest, fmq_sendTargetAndActualDuration_queueFull) { TEST_F(PowerAdvisorTest, fmq_sendHint) { SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true); + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, true); mPowerAdvisor->onBootFinished(); SetUpFmq(true, false); auto startTime = uptimeNanos(); @@ -807,6 +810,7 @@ TEST_F(PowerAdvisorTest, fmq_sendHint) { TEST_F(PowerAdvisorTest, fmq_sendHint_noSharedFlag) { SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true); + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, true); mPowerAdvisor->onBootFinished(); SetUpFmq(false, false); SessionHint hint; @@ -821,6 +825,7 @@ TEST_F(PowerAdvisorTest, fmq_sendHint_noSharedFlag) { TEST_F(PowerAdvisorTest, fmq_sendHint_queueFull) { SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true); + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, true); mPowerAdvisor->onBootFinished(); SetUpFmq(true, true); ASSERT_EQ(mBackendFmq->availableToRead(), 2uL); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index adbd868a28..29e1c21878 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -308,6 +308,42 @@ protected: << " category=" << ftl::enum_string(testCase.frameRateCategory); } } + + template <class T> + std::vector<LayerRequirement> createLayers(const std::initializer_list<T>& surfaceVotes) { + std::vector<LayerRequirement> layers; + for (auto surfaceVote : surfaceVotes) { + ALOGI("**** %s: Adding layers for %s: (desiredFrameRate=%s, voteType=%s), " + "(frameRateCategory=%s)", + __func__, surfaceVote.name.c_str(), + to_string(surfaceVote.desiredFrameRate).c_str(), + ftl::enum_string(surfaceVote.voteType).c_str(), + ftl::enum_string(surfaceVote.frameRateCategory).c_str()); + + if (surfaceVote.desiredFrameRate.isValid()) { + std::stringstream ss; + ss << surfaceVote.name << " (" << surfaceVote.weight << "): ExplicitDefault (" + << to_string(surfaceVote.desiredFrameRate) << ")"; + LayerRequirement layer = {.name = ss.str(), + .vote = surfaceVote.voteType, + .desiredRefreshRate = surfaceVote.desiredFrameRate, + .weight = surfaceVote.weight}; + layers.push_back(layer); + } + + if (surfaceVote.frameRateCategory != FrameRateCategory::Default) { + std::stringstream ss; + ss << surfaceVote.name << " (" << surfaceVote.weight << "): ExplicitCategory (" + << ftl::enum_string(surfaceVote.frameRateCategory) << ")"; + LayerRequirement layer = {.name = ss.str(), + .vote = LayerVoteType::ExplicitCategory, + .frameRateCategory = surfaceVote.frameRateCategory, + .weight = surfaceVote.weight}; + layers.push_back(layer); + } + } + return layers; + } }; RefreshRateSelectorTest::RefreshRateSelectorTest() { @@ -1776,6 +1812,98 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategoryMultiL selector); } +TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_multiSurface_arr) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + SET_FLAG_FOR_TEST(flags::vrr_config, true); + + auto selector = createSelector(kVrrMode_120, kModeId120); + + // Switch the policy to be more like an ARR device (primary range is a single rate). + constexpr FpsRange k120_120Hz = {120_Hz, 120_Hz}; + constexpr FpsRange k0_120Hz = {0_Hz, 120_Hz}; + constexpr FpsRanges kPrimaryRanges = {/*physical*/ k120_120Hz, + /*render*/ k120_120Hz}; + constexpr FpsRanges kAppRequestRanges = {/*physical*/ k120_120Hz, + /*render*/ k0_120Hz}; + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy( + {/*defaultMode*/ kModeId120, kPrimaryRanges, kAppRequestRanges})); + + // Surface can translate to multiple layers in SF scheduler due to category and frame rate + // value. + struct SurfaceVote { + // Params + std::string name = ""; + Fps desiredFrameRate = 0_Hz; + LayerVoteType voteType = LayerVoteType::ExplicitDefault; + FrameRateCategory frameRateCategory = FrameRateCategory::Default; + float weight = 1.f; + }; + + auto layers = createLayers( + std::initializer_list<SurfaceVote>{{.name = "60 fixed source", + .desiredFrameRate = 60_Hz, + .voteType = LayerVoteType::ExplicitExactOrMultiple, + .weight = 0.27f}, + {.name = "1 fixed source + NoPreference", + .desiredFrameRate = 1_Hz, + .voteType = LayerVoteType::ExplicitExactOrMultiple, + .frameRateCategory = + FrameRateCategory::NoPreference}}); + auto actualRankedFrameRates = selector.getRankedFrameRates(layers); + EXPECT_EQ(60_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps); + + layers = createLayers( + std::initializer_list<SurfaceVote>{{.name = "60 fixed source", + .desiredFrameRate = 60_Hz, + .voteType = LayerVoteType::ExplicitExactOrMultiple, + .weight = 0.27f}, + {.name = "1 fixed source + Normal", + .desiredFrameRate = 1_Hz, + .voteType = LayerVoteType::ExplicitExactOrMultiple, + .frameRateCategory = FrameRateCategory::Normal}}); + actualRankedFrameRates = selector.getRankedFrameRates(layers); + EXPECT_EQ(60_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps); + + layers = createLayers(std::initializer_list<SurfaceVote>{ + {.name = "30 fixed source + NoPreference", + .desiredFrameRate = 30_Hz, + .voteType = LayerVoteType::ExplicitExactOrMultiple, + .frameRateCategory = FrameRateCategory::NoPreference}}); + actualRankedFrameRates = selector.getRankedFrameRates(layers); + EXPECT_EQ(30_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps); + + layers = createLayers(std::initializer_list<SurfaceVote>{ + {.name = "1 fixed source + NoPreference", + .desiredFrameRate = 1_Hz, + .voteType = LayerVoteType::ExplicitExactOrMultiple, + .frameRateCategory = FrameRateCategory::NoPreference}}); + actualRankedFrameRates = selector.getRankedFrameRates(layers); + // Result affected by RefreshRateSelector.kMinSupportedFrameRate. + EXPECT_EQ(20_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps); + + layers = createLayers(std::initializer_list<SurfaceVote>{ + {.name = "24 fixed source + NoPreference", + .desiredFrameRate = 24_Hz, + .voteType = LayerVoteType::ExplicitExactOrMultiple, + .frameRateCategory = FrameRateCategory::NoPreference}}); + actualRankedFrameRates = selector.getRankedFrameRates(layers); + EXPECT_EQ(24_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps); + + layers = createLayers(std::initializer_list<SurfaceVote>{ + {.name = "23.976 fixed source + NoPreference", + .desiredFrameRate = 23.976_Hz, + .voteType = LayerVoteType::ExplicitExactOrMultiple, + .frameRateCategory = FrameRateCategory::NoPreference}}); + actualRankedFrameRates = selector.getRankedFrameRates(layers); + // Chooses 120 unless certain threshold is set, see tests test23976Chooses120 and + // test23976Chooses60IfThresholdIs120. + EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps); +} + TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_60_120) { auto selector = createSelector(makeModes(kMode60, kMode120), kModeId60); diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index 615cc948ed..3e6a768db8 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -185,7 +185,7 @@ public: (Display, std::vector<Layer>*, std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*)); MOCK_METHOD(Error, setLayerLuts, - (Display, Layer, std::vector<aidl::android::hardware::graphics::composer3::Lut>&)); + (Display, Layer, aidl::android::hardware::graphics::composer3::Luts&)); }; } // namespace Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h index 53ed2e1f20..384b908624 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -147,8 +147,8 @@ public: (const std::string &, bool, const std::vector<uint8_t> &), (override)); MOCK_METHOD(hal::Error, setBrightness, (float), (override)); MOCK_METHOD(hal::Error, setBlockingRegion, (const android::Region &), (override)); - MOCK_METHOD(hal::Error, setLuts, - (std::vector<aidl::android::hardware::graphics::composer3::Lut>&), (override)); + MOCK_METHOD(hal::Error, setLuts, (aidl::android::hardware::graphics::composer3::Luts&), + (override)); }; } // namespace android::HWC2::mock |