diff options
122 files changed, 2599 insertions, 3206 deletions
diff --git a/include/input/InputConsumerNoResampling.h b/include/input/InputConsumerNoResampling.h index 65c2914b3c..358a19158e 100644 --- a/include/input/InputConsumerNoResampling.h +++ b/include/input/InputConsumerNoResampling.h @@ -17,6 +17,7 @@ #pragma once #include <input/InputTransport.h> +#include <input/LooperInterface.h> #include <input/Resampler.h> #include <utils/Looper.h> @@ -66,6 +67,16 @@ public: class InputConsumerNoResampling final { public: /** + * This constructor is exclusively for test code. Any real use of InputConsumerNoResampling must + * use the constructor that takes an sp<Looper> parameter instead of + * std::shared_ptr<LooperInterface>. + */ + explicit InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel, + std::shared_ptr<LooperInterface> looper, + InputConsumerCallbacks& callbacks, + std::unique_ptr<Resampler> resampler); + + /** * @param callbacks are used to interact with InputConsumerNoResampling. They're called whenever * the event is ready to consume. * @param looper needs to be sp and not shared_ptr because it inherits from @@ -108,7 +119,7 @@ public: private: std::shared_ptr<InputChannel> mChannel; - sp<Looper> mLooper; + std::shared_ptr<LooperInterface> mLooper; InputConsumerCallbacks& mCallbacks; std::unique_ptr<Resampler> mResampler; diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index 7d8c19e702..1a482396ee 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -389,6 +389,7 @@ enum class InputDeviceConfigurationFileType : int32_t { CONFIGURATION = 0, /* .idc file */ KEY_LAYOUT = 1, /* .kl file */ KEY_CHARACTER_MAP = 2, /* .kcm file */ + ftl_last = KEY_CHARACTER_MAP, }; /* diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 7d11f76c85..0cd87201fb 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -263,7 +263,7 @@ public: * Return DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ - status_t sendMessage(const InputMessage* msg); + virtual status_t sendMessage(const InputMessage* msg); /* Receive a message sent by the other endpoint. * @@ -275,14 +275,14 @@ public: * Return DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ - android::base::Result<InputMessage> receiveMessage(); + virtual android::base::Result<InputMessage> receiveMessage(); /* Tells whether there is a message in the channel available to be received. * * This is only a performance hint and may return false negative results. Clients should not * rely on availability of the message based on the return value. */ - bool probablyHasInput() const; + virtual bool probablyHasInput() const; /* Wait until there is a message in the channel. * @@ -323,11 +323,12 @@ public: */ sp<IBinder> getConnectionToken() const; +protected: + InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token); + private: static std::unique_ptr<InputChannel> create(const std::string& name, android::base::unique_fd fd, sp<IBinder> token); - - InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token); }; /* diff --git a/include/input/LooperInterface.h b/include/input/LooperInterface.h new file mode 100644 index 0000000000..2d6719c965 --- /dev/null +++ b/include/input/LooperInterface.h @@ -0,0 +1,39 @@ +/** + * Copyright 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 <utils/Looper.h> +#include <utils/StrongPointer.h> + +namespace android { + +/** + * LooperInterface allows the use of TestLooper in InputConsumerNoResampling without reassigning to + * Looper. LooperInterface is needed to control how InputConsumerNoResampling consumes and batches + * InputMessages. + */ +class LooperInterface { +public: + virtual ~LooperInterface() = default; + + virtual int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, + void* data) = 0; + virtual int removeFd(int fd) = 0; + + virtual sp<Looper> getLooper() const = 0; +}; +} // namespace android diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h index 8c356d0140..e5eee340ca 100644 --- a/include/private/performance_hint_private.h +++ b/include/private/performance_hint_private.h @@ -108,6 +108,10 @@ APerformanceHintSession* APerformanceHint_createSessionInternal(APerformanceHint const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos, SessionTag tag); +/** + * Forces FMQ to be enabled or disabled, for testing only. + */ +void APerformanceHint_setUseFMQForTesting(bool enabled); __END_DECLS diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp index 319716ec81..cbba7118b6 100644 --- a/libs/arect/Android.bp +++ b/libs/arect/Android.bp @@ -40,6 +40,7 @@ ndk_headers { cc_library_headers { name: "libarect_headers", + host_supported: true, vendor_available: true, min_sdk_version: "29", // TODO(b/153609531): remove when no longer needed. diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp index 455a4338e5..7263e236fc 100644 --- a/libs/binder/FdTrigger.cpp +++ b/libs/binder/FdTrigger.cpp @@ -82,7 +82,9 @@ status_t FdTrigger::triggerablePoll(const android::RpcTransportFd& transportFd, int ret = TEMP_FAILURE_RETRY(poll(pfd, countof(pfd), -1)); if (ret < 0) { - return -errno; + int saved_errno = errno; + ALOGE("FdTrigger poll returned error: %d, with error: %s", ret, strerror(saved_errno)); + return -saved_errno; } LOG_ALWAYS_FATAL_IF(ret == 0, "poll(%d) returns 0 with infinite timeout", transportFd.fd.get()); @@ -106,6 +108,7 @@ status_t FdTrigger::triggerablePoll(const android::RpcTransportFd& transportFd, // POLLNVAL: invalid FD number, e.g. not opened. if (pfd[0].revents & POLLNVAL) { + LOG_ALWAYS_FATAL("Invalid FD number (%d) in FdTrigger (POLLNVAL)", pfd[0].fd); return BAD_VALUE; } diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h index 62738041ba..af56bf0da1 100644 --- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h +++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h @@ -225,6 +225,8 @@ class BpCInterface : public INTERFACE { SpAIBinder asBinder() override final; + const SpAIBinder& asBinderReference() { return mBinder; } + bool isRemote() override final { return AIBinder_isRemote(mBinder.get()); } binder_status_t dump(int fd, const char** args, uint32_t numArgs) override { diff --git a/libs/bufferstreams/rust/src/stream_config.rs b/libs/bufferstreams/rust/src/stream_config.rs index 454bdf144e..8288f9f3cf 100644 --- a/libs/bufferstreams/rust/src/stream_config.rs +++ b/libs/bufferstreams/rust/src/stream_config.rs @@ -32,10 +32,23 @@ pub struct StreamConfig { pub stride: u32, } +impl From<StreamConfig> for HardwareBufferDescription { + fn from(config: StreamConfig) -> Self { + HardwareBufferDescription::new( + config.width, + config.height, + config.layers, + config.format, + config.usage, + config.stride, + ) + } +} + impl StreamConfig { /// Tries to create a new HardwareBuffer from settings in a [StreamConfig]. pub fn create_hardware_buffer(&self) -> Option<HardwareBuffer> { - HardwareBuffer::new(self.width, self.height, self.layers, self.format, self.usage) + HardwareBuffer::new(&(*self).into()) } } @@ -59,9 +72,10 @@ mod test { assert!(maybe_buffer.is_some()); let buffer = maybe_buffer.unwrap(); - assert_eq!(config.width, buffer.width()); - assert_eq!(config.height, buffer.height()); - assert_eq!(config.format, buffer.format()); - assert_eq!(config.usage, buffer.usage()); + let description = buffer.description(); + assert_eq!(config.width, description.width()); + assert_eq!(config.height, description.height()); + assert_eq!(config.format, description.format()); + assert_eq!(config.usage, description.usage()); } } diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 3c1971fd81..94998e5ab7 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -31,6 +31,7 @@ #include <sys/epoll.h> #include <sys/eventfd.h> +#include <gui/FenceMonitor.h> #include <gui/FrameRateUtils.h> #include <gui/GLConsumer.h> #include <gui/IProducerListener.h> @@ -475,6 +476,16 @@ void BLASTBufferQueue::releaseBufferCallbackLocked( ATRACE_CALL(); BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str()); + if (CC_UNLIKELY(atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS))) { + if (!mFenceMonitor) { + std::string monitorName = "release :"; + monitorName.append(mName.c_str()); + mFenceMonitor.emplace(monitorName.c_str()); + } + + mFenceMonitor->queueFence(releaseFence); + } + // Calculate how many buffers we need to hold before we release them back // to the buffer queue. This will prevent higher latency when we are running // on a lower refresh rate than the max supported. We only do that for EGL diff --git a/libs/gui/FenceMonitor.cpp b/libs/gui/FenceMonitor.cpp index 230c81a0b3..e38f1a8ce6 100644 --- a/libs/gui/FenceMonitor.cpp +++ b/libs/gui/FenceMonitor.cpp @@ -25,9 +25,18 @@ namespace android::gui { FenceMonitor::FenceMonitor(const char* name) : mName(name), mFencesQueued(0), mFencesSignaled(0) { - std::thread thread(&FenceMonitor::loop, this); - pthread_setname_np(thread.native_handle(), mName); - thread.detach(); + mThread = std::thread(&FenceMonitor::loop, this); +} + +FenceMonitor::~FenceMonitor() { + { + std::lock_guard<std::mutex> lock(mMutex); + mStopped = true; + mCondition.notify_one(); + } + if (mThread.joinable()) { + mThread.join(); + } } void FenceMonitor::queueFence(const sp<Fence>& fence) { @@ -35,24 +44,26 @@ void FenceMonitor::queueFence(const sp<Fence>& fence) { std::lock_guard<std::mutex> lock(mMutex); if (fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) { - snprintf(message, sizeof(message), "%s fence %u has signaled", mName, mFencesQueued); + snprintf(message, sizeof(message), "%s fence %u has signaled", mName.c_str(), + mFencesQueued); ATRACE_NAME(message); // Need an increment on both to make the trace number correct. mFencesQueued++; mFencesSignaled++; return; } - snprintf(message, sizeof(message), "Trace %s fence %u", mName, mFencesQueued); + snprintf(message, sizeof(message), "Trace %s fence %u", mName.c_str(), mFencesQueued); ATRACE_NAME(message); mQueue.push_back(fence); mCondition.notify_one(); mFencesQueued++; - ATRACE_INT(mName, int32_t(mQueue.size())); + ATRACE_INT(mName.c_str(), int32_t(mQueue.size())); } void FenceMonitor::loop() { - while (true) { + pthread_setname_np(pthread_self(), mName.c_str()); + while (!mStopped) { threadLoop(); } } @@ -62,15 +73,18 @@ void FenceMonitor::threadLoop() { uint32_t fenceNum; { std::unique_lock<std::mutex> lock(mMutex); - while (mQueue.empty()) { + while (mQueue.empty() && !mStopped) { mCondition.wait(lock); } + if (mStopped) { + return; + } fence = mQueue[0]; fenceNum = mFencesSignaled; } { char message[64]; - snprintf(message, sizeof(message), "waiting for %s %u", mName, fenceNum); + snprintf(message, sizeof(message), "waiting for %s %u", mName.c_str(), fenceNum); ATRACE_NAME(message); status_t result = fence->waitForever(message); @@ -82,8 +96,8 @@ void FenceMonitor::threadLoop() { std::lock_guard<std::mutex> lock(mMutex); mQueue.pop_front(); mFencesSignaled++; - ATRACE_INT(mName, int32_t(mQueue.size())); + ATRACE_INT(mName.c_str(), int32_t(mQueue.size())); } } -} // namespace android::gui
\ No newline at end of file +} // namespace android::gui diff --git a/libs/gui/ScreenCaptureResults.cpp b/libs/gui/ScreenCaptureResults.cpp index 601a5f9b33..2de023e5b2 100644 --- a/libs/gui/ScreenCaptureResults.cpp +++ b/libs/gui/ScreenCaptureResults.cpp @@ -40,6 +40,13 @@ status_t ScreenCaptureResults::writeToParcel(android::Parcel* parcel) const { SAFE_PARCEL(parcel->writeBool, capturedSecureLayers); SAFE_PARCEL(parcel->writeBool, capturedHdrLayers); SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(capturedDataspace)); + if (optionalGainMap != nullptr) { + SAFE_PARCEL(parcel->writeBool, true); + SAFE_PARCEL(parcel->write, *optionalGainMap); + } else { + SAFE_PARCEL(parcel->writeBool, false); + } + SAFE_PARCEL(parcel->writeFloat, hdrSdrRatio); return NO_ERROR; } @@ -68,6 +75,14 @@ status_t ScreenCaptureResults::readFromParcel(const android::Parcel* parcel) { uint32_t dataspace = 0; SAFE_PARCEL(parcel->readUint32, &dataspace); capturedDataspace = static_cast<ui::Dataspace>(dataspace); + + bool hasGainmap; + SAFE_PARCEL(parcel->readBool, &hasGainmap); + if (hasGainmap) { + optionalGainMap = new GraphicBuffer(); + SAFE_PARCEL(parcel->read, *optionalGainMap); + } + SAFE_PARCEL(parcel->readFloat, &hdrSdrRatio); return NO_ERROR; } diff --git a/libs/gui/aidl/android/gui/CaptureArgs.aidl b/libs/gui/aidl/android/gui/CaptureArgs.aidl index 2bbed2b9d6..4920344e0e 100644 --- a/libs/gui/aidl/android/gui/CaptureArgs.aidl +++ b/libs/gui/aidl/android/gui/CaptureArgs.aidl @@ -69,5 +69,10 @@ parcelable CaptureArgs { // exact colorspace is not an appropriate intermediate result. // Note that if the caller is requesting a specific dataspace, this hint does nothing. boolean hintForSeamlessTransition = false; + + // Allows the screenshot to attach a gainmap, which allows for a per-pixel + // transformation of the screenshot to another luminance range, typically + // mapping an SDR base image into HDR. + boolean attachGainmap = false; } diff --git a/libs/gui/aidl/android/gui/ScreenCaptureResults.aidl b/libs/gui/aidl/android/gui/ScreenCaptureResults.aidl index 97a903515b..f4ef16dc71 100644 --- a/libs/gui/aidl/android/gui/ScreenCaptureResults.aidl +++ b/libs/gui/aidl/android/gui/ScreenCaptureResults.aidl @@ -16,4 +16,4 @@ package android.gui; -parcelable ScreenCaptureResults cpp_header "gui/ScreenCaptureResults.h" rust_type "gui_aidl_types_rs::ScreenCaptureResults";
\ No newline at end of file +parcelable ScreenCaptureResults cpp_header "gui/ScreenCaptureResults.h" rust_type "gui_aidl_types_rs::ScreenCaptureResults"; diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index d787d6cc45..868dbd06ec 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -20,6 +20,7 @@ #include <com_android_graphics_libgui_flags.h> #include <gui/BufferItem.h> #include <gui/BufferItemConsumer.h> +#include <gui/FenceMonitor.h> #include <gui/IGraphicBufferConsumer.h> #include <gui/IGraphicBufferProducer.h> #include <gui/SurfaceComposerClient.h> @@ -316,6 +317,8 @@ private: std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex); + std::optional<gui::FenceMonitor> mFenceMonitor GUARDED_BY(mMutex); + #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) class BufferReleaseReader { public: diff --git a/libs/gui/include/gui/FenceMonitor.h b/libs/gui/include/gui/FenceMonitor.h index 62ceddee5f..ac5cc0a574 100644 --- a/libs/gui/include/gui/FenceMonitor.h +++ b/libs/gui/include/gui/FenceMonitor.h @@ -19,6 +19,7 @@ #include <cstdint> #include <deque> #include <mutex> +#include <thread> #include <ui/Fence.h> @@ -28,17 +29,20 @@ class FenceMonitor { public: explicit FenceMonitor(const char* name); void queueFence(const sp<Fence>& fence); + ~FenceMonitor(); private: void loop(); void threadLoop(); - const char* mName; + std::string mName; uint32_t mFencesQueued; uint32_t mFencesSignaled; std::deque<sp<Fence>> mQueue; std::condition_variable mCondition; std::mutex mMutex; + std::thread mThread; + std::atomic_bool mStopped = false; }; -} // namespace android::gui
\ No newline at end of file +} // namespace android::gui diff --git a/libs/gui/include/gui/ScreenCaptureResults.h b/libs/gui/include/gui/ScreenCaptureResults.h index 6e17791a29..f176f48fb4 100644 --- a/libs/gui/include/gui/ScreenCaptureResults.h +++ b/libs/gui/include/gui/ScreenCaptureResults.h @@ -36,6 +36,11 @@ public: bool capturedSecureLayers{false}; bool capturedHdrLayers{false}; ui::Dataspace capturedDataspace{ui::Dataspace::V0_SRGB}; + // A gainmap that can be used to "lift" the screenshot into HDR + sp<GraphicBuffer> optionalGainMap; + // HDR/SDR ratio value that fully applies the gainmap. + // Note that we use 1/64 epsilon offsets to eliminate precision issues + float hdrSdrRatio{1.0f}; }; } // namespace android::gui diff --git a/libs/gui/tests/Choreographer_test.cpp b/libs/gui/tests/Choreographer_test.cpp index 2ac2550f07..8db48d2eb0 100644 --- a/libs/gui/tests/Choreographer_test.cpp +++ b/libs/gui/tests/Choreographer_test.cpp @@ -52,25 +52,23 @@ TEST_F(ChoreographerTest, InputCallbackBeforeAnimation) { sp<Looper> looper = Looper::prepare(0); Choreographer* choreographer = Choreographer::getForThread(); VsyncCallback animationCb; - VsyncCallback inputCb; - choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &animationCb, 0, CALLBACK_ANIMATION); + VsyncCallback inputCb; choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &inputCb, 0, CALLBACK_INPUT); - - nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); - nsecs_t currTime; - int pollResult; + auto startTime = std::chrono::system_clock::now(); do { - pollResult = looper->pollOnce(16); - currTime = systemTime(SYSTEM_TIME_MONOTONIC); - } while (!(inputCb.callbackReceived() && animationCb.callbackReceived()) && - (pollResult != Looper::POLL_TIMEOUT && pollResult != Looper::POLL_ERROR) && - (currTime - startTime < 3000)); - - ASSERT_TRUE(inputCb.callbackReceived()) << "did not receive input callback"; - ASSERT_TRUE(animationCb.callbackReceived()) << "did not receive animation callback"; + static constexpr int32_t timeoutMs = 1000; + int pollResult = looper->pollOnce(timeoutMs); + ASSERT_TRUE((pollResult != Looper::POLL_TIMEOUT) && (pollResult != Looper::POLL_ERROR)) + << "Failed to poll looper. Poll result = " << pollResult; + auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>( + std::chrono::system_clock::now() - startTime); + ASSERT_LE(elapsedMs.count(), timeoutMs) + << "Timed out waiting for callbacks. inputCb=" << inputCb.callbackReceived() + << " animationCb=" << animationCb.callbackReceived(); + } while (!(inputCb.callbackReceived() && animationCb.callbackReceived())); ASSERT_EQ(inputCb.frameTime, animationCb.frameTime) << android::base::StringPrintf("input and animation callback frame times don't match. " diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp index 99ffa683dd..eb419180e7 100644 --- a/libs/input/InputConsumerNoResampling.cpp +++ b/libs/input/InputConsumerNoResampling.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "InputTransport" +#define LOG_TAG "InputConsumerNoResampling" #define ATRACE_TAG ATRACE_TAG_INPUT #include <chrono> @@ -33,8 +33,6 @@ #include <input/PrintTools.h> #include <input/TraceTools.h> -namespace input_flags = com::android::input::flags; - namespace android { namespace { @@ -46,6 +44,27 @@ namespace { const bool DEBUG_TRANSPORT_CONSUMER = __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Consumer", ANDROID_LOG_INFO); +/** + * RealLooper is a wrapper of Looper. All the member functions exclusively call the internal looper. + * This class' behavior is the same as Looper. + */ +class RealLooper final : public LooperInterface { +public: + RealLooper(sp<Looper> looper) : mLooper{looper} {} + + int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, + void* data) override { + return mLooper->addFd(fd, ident, events, callback, data); + } + + int removeFd(int fd) override { return mLooper->removeFd(fd); } + + sp<Looper> getLooper() const override { return mLooper; } + +private: + sp<Looper> mLooper; +}; + std::unique_ptr<KeyEvent> createKeyEvent(const InputMessage& msg) { std::unique_ptr<KeyEvent> event = std::make_unique<KeyEvent>(); event->initialize(msg.body.key.eventId, msg.body.key.deviceId, msg.body.key.source, @@ -173,22 +192,20 @@ InputMessage createTimelineMessage(int32_t inputEventId, nsecs_t gpuCompletedTim bool isPointerEvent(const MotionEvent& motionEvent) { return (motionEvent.getSource() & AINPUT_SOURCE_CLASS_POINTER) == AINPUT_SOURCE_CLASS_POINTER; } - } // namespace using android::base::Result; -using android::base::StringPrintf; // --- InputConsumerNoResampling --- InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel, - sp<Looper> looper, + std::shared_ptr<LooperInterface> looper, InputConsumerCallbacks& callbacks, std::unique_ptr<Resampler> resampler) - : mChannel(channel), - mLooper(looper), + : mChannel{channel}, + mLooper{looper}, mCallbacks(callbacks), - mResampler(std::move(resampler)), + mResampler{std::move(resampler)}, mFdEvents(0) { LOG_ALWAYS_FATAL_IF(mLooper == nullptr); mCallback = sp<LooperEventCallback>::make( @@ -199,6 +216,13 @@ InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<Input setFdEvents(ALOOPER_EVENT_INPUT); } +InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel, + sp<Looper> looper, + InputConsumerCallbacks& callbacks, + std::unique_ptr<Resampler> resampler) + : InputConsumerNoResampling(channel, std::make_shared<RealLooper>(looper), callbacks, + std::move(resampler)) {} + InputConsumerNoResampling::~InputConsumerNoResampling() { ensureCalledOnLooperThread(__func__); consumeBatchedInputEvents(std::nullopt); @@ -513,7 +537,7 @@ bool InputConsumerNoResampling::consumeBatchedInputEvents( void InputConsumerNoResampling::ensureCalledOnLooperThread(const char* func) const { sp<Looper> callingThreadLooper = Looper::getForThread(); - if (callingThreadLooper != mLooper) { + if (callingThreadLooper != mLooper->getLooper()) { LOG(FATAL) << "The function " << func << " can only be called on the looper thread"; } } diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index 9333ab83a6..c9030312f9 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -20,6 +20,7 @@ #include <unistd.h> #include <ctype.h> +#include <android-base/logging.h> #include <android-base/properties.h> #include <android-base/stringprintf.h> #include <ftl/enum.h> @@ -31,6 +32,9 @@ using android::base::StringPrintf; namespace android { +// Set to true to log detailed debugging messages about IDC file probing. +static constexpr bool DEBUG_PROBE = false; + static const char* CONFIGURATION_FILE_DIR[] = { "idc/", "keylayout/", @@ -114,15 +118,18 @@ std::string getInputDeviceConfigurationFilePathByName( for (const auto& prefix : pathPrefixes) { path = prefix; appendInputDeviceConfigurationFileRelativePath(path, name, type); -#if DEBUG_PROBE - ALOGD("Probing for system provided input device configuration file: path='%s'", - path.c_str()); -#endif if (!access(path.c_str(), R_OK)) { -#if DEBUG_PROBE - ALOGD("Found"); -#endif + LOG_IF(INFO, DEBUG_PROBE) + << "Found system-provided input device configuration file at " << path; return path; + } else if (errno != ENOENT) { + LOG(WARNING) << "Couldn't find a system-provided input device configuration file at " + << path << " due to error " << errno << " (" << strerror(errno) + << "); there may be an IDC file there that cannot be loaded."; + } else { + LOG_IF(ERROR, DEBUG_PROBE) + << "Didn't find system-provided input device configuration file at " << path + << ": " << strerror(errno); } } @@ -135,21 +142,22 @@ std::string getInputDeviceConfigurationFilePathByName( } path += "/system/devices/"; appendInputDeviceConfigurationFileRelativePath(path, name, type); -#if DEBUG_PROBE - ALOGD("Probing for system user input device configuration file: path='%s'", path.c_str()); -#endif if (!access(path.c_str(), R_OK)) { -#if DEBUG_PROBE - ALOGD("Found"); -#endif + LOG_IF(INFO, DEBUG_PROBE) << "Found system user input device configuration file at " + << path; return path; + } else if (errno != ENOENT) { + LOG(WARNING) << "Couldn't find a system user input device configuration file at " << path + << " due to error " << errno << " (" << strerror(errno) + << "); there may be an IDC file there that cannot be loaded."; + } else { + LOG_IF(ERROR, DEBUG_PROBE) << "Didn't find system user input device configuration file at " + << path << ": " << strerror(errno); } // Not found. -#if DEBUG_PROBE - ALOGD("Probe failed to find input device configuration file: name='%s', type=%d", - name.c_str(), type); -#endif + LOG_IF(INFO, DEBUG_PROBE) << "Probe failed to find input device configuration file with name '" + << name << "' and type " << ftl::enum_string(type); return ""; } diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index b8a8d76857..f1c4aed7af 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -185,3 +185,10 @@ flag { description: "Collect quality metrics on framework palm rejection." bug: "341717757" } + +flag { + name: "enable_touchpad_no_focus_change" + namespace: "input" + description: "Prevents touchpad gesture changing window focus." + bug: "364460018" +} diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index 132866bd99..3ec167a288 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -16,6 +16,7 @@ cc_test { "BlockingQueue_test.cpp", "IdGenerator_test.cpp", "InputChannel_test.cpp", + "InputConsumer_test.cpp", "InputDevice_test.cpp", "InputEvent_test.cpp", "InputPublisherAndConsumer_test.cpp", @@ -25,6 +26,8 @@ cc_test { "MotionPredictorMetricsManager_test.cpp", "Resampler_test.cpp", "RingBuffer_test.cpp", + "TestInputChannel.cpp", + "TestLooper.cpp", "TfLiteMotionPredictor_test.cpp", "TouchResampling_test.cpp", "TouchVideoFrame_test.cpp", @@ -92,6 +95,7 @@ cc_test { }, }, }, + native_coverage: false, } // NOTE: This is a compile time test, and does not need to be diff --git a/libs/input/tests/InputConsumer_test.cpp b/libs/input/tests/InputConsumer_test.cpp new file mode 100644 index 0000000000..c30f243398 --- /dev/null +++ b/libs/input/tests/InputConsumer_test.cpp @@ -0,0 +1,123 @@ +/** + * Copyright 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. + */ + +#include <input/InputConsumerNoResampling.h> + +#include <memory> +#include <optional> +#include <utility> + +#include <TestInputChannel.h> +#include <TestLooper.h> +#include <android-base/logging.h> +#include <gtest/gtest.h> +#include <input/BlockingQueue.h> +#include <input/InputEventBuilders.h> +#include <utils/StrongPointer.h> + +namespace android { + +class InputConsumerTest : public testing::Test, public InputConsumerCallbacks { +protected: + InputConsumerTest() + : mClientTestChannel{std::make_shared<TestInputChannel>("TestChannel")}, + mTestLooper{std::make_shared<TestLooper>()} { + Looper::setForThread(mTestLooper->getLooper()); + mConsumer = std::make_unique<InputConsumerNoResampling>(mClientTestChannel, mTestLooper, + *this, /*resampler=*/nullptr); + } + + void assertOnBatchedInputEventPendingWasCalled(); + + std::shared_ptr<TestInputChannel> mClientTestChannel; + std::shared_ptr<TestLooper> mTestLooper; + std::unique_ptr<InputConsumerNoResampling> mConsumer; + + BlockingQueue<std::unique_ptr<KeyEvent>> mKeyEvents; + BlockingQueue<std::unique_ptr<MotionEvent>> mMotionEvents; + BlockingQueue<std::unique_ptr<FocusEvent>> mFocusEvents; + BlockingQueue<std::unique_ptr<CaptureEvent>> mCaptureEvents; + BlockingQueue<std::unique_ptr<DragEvent>> mDragEvents; + BlockingQueue<std::unique_ptr<TouchModeEvent>> mTouchModeEvents; + +private: + size_t onBatchedInputEventPendingInvocationCount{0}; + + // InputConsumerCallbacks interface + void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) override { + mKeyEvents.push(std::move(event)); + mConsumer->finishInputEvent(seq, true); + } + void onMotionEvent(std::unique_ptr<MotionEvent> event, uint32_t seq) override { + mMotionEvents.push(std::move(event)); + mConsumer->finishInputEvent(seq, true); + } + void onBatchedInputEventPending(int32_t pendingBatchSource) override { + if (!mConsumer->probablyHasInput()) { + ADD_FAILURE() << "should deterministically have input because there is a batch"; + } + ++onBatchedInputEventPendingInvocationCount; + }; + void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) override { + mFocusEvents.push(std::move(event)); + mConsumer->finishInputEvent(seq, true); + }; + void onCaptureEvent(std::unique_ptr<CaptureEvent> event, uint32_t seq) override { + mCaptureEvents.push(std::move(event)); + mConsumer->finishInputEvent(seq, true); + }; + void onDragEvent(std::unique_ptr<DragEvent> event, uint32_t seq) override { + mDragEvents.push(std::move(event)); + mConsumer->finishInputEvent(seq, true); + } + void onTouchModeEvent(std::unique_ptr<TouchModeEvent> event, uint32_t seq) override { + mTouchModeEvents.push(std::move(event)); + mConsumer->finishInputEvent(seq, true); + }; +}; + +void InputConsumerTest::assertOnBatchedInputEventPendingWasCalled() { + ASSERT_GT(onBatchedInputEventPendingInvocationCount, 0UL) + << "onBatchedInputEventPending has not been called."; + --onBatchedInputEventPendingInvocationCount; +} + +TEST_F(InputConsumerTest, MessageStreamBatchedInMotionEvent) { + mClientTestChannel->enqueueMessage( + InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0}.build()); + mClientTestChannel->enqueueMessage( + InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/1}.build()); + mClientTestChannel->enqueueMessage( + InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/2}.build()); + + mClientTestChannel->assertNoSentMessages(); + + mTestLooper->invokeCallback(mClientTestChannel->getFd(), ALOOPER_EVENT_INPUT); + + assertOnBatchedInputEventPendingWasCalled(); + + mConsumer->consumeBatchedInputEvents(std::nullopt); + + std::unique_ptr<MotionEvent> batchedMotionEvent = mMotionEvents.pop(); + ASSERT_NE(batchedMotionEvent, nullptr); + + mClientTestChannel->assertFinishMessage(/*seq=*/0, /*handled=*/true); + mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true); + mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true); + + EXPECT_EQ(batchedMotionEvent->getHistorySize() + 1, 3UL); +} +} // namespace android diff --git a/libs/input/tests/TestInputChannel.cpp b/libs/input/tests/TestInputChannel.cpp new file mode 100644 index 0000000000..d5f00b699b --- /dev/null +++ b/libs/input/tests/TestInputChannel.cpp @@ -0,0 +1,85 @@ +/** + * Copyright 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. + */ + +#define LOG_TAG "TestInputChannel" +#define ATRACE_TAG ATRACE_TAG_INPUT + +#include <TestInputChannel.h> + +#include <android-base/logging.h> +#include <android-base/unique_fd.h> +#include <binder/IBinder.h> +#include <utils/StrongPointer.h> + +namespace android { + +namespace { +constexpr int FAKE_FD{-1}; +} // namespace + +// --- TestInputChannel --- + +TestInputChannel::TestInputChannel(const std::string& name) + : InputChannel{name, base::unique_fd(FAKE_FD), sp<BBinder>::make()} {} + +void TestInputChannel::enqueueMessage(const InputMessage& message) { + mReceivedMessages.push(message); +} + +status_t TestInputChannel::sendMessage(const InputMessage* message) { + LOG_IF(FATAL, message == nullptr) + << "TestInputChannel " << getName() << ". No message was passed to sendMessage."; + + mSentMessages.push(*message); + return OK; +} + +base::Result<InputMessage> TestInputChannel::receiveMessage() { + if (mReceivedMessages.empty()) { + return base::Error(WOULD_BLOCK); + } + InputMessage message = mReceivedMessages.front(); + mReceivedMessages.pop(); + return message; +} + +bool TestInputChannel::probablyHasInput() const { + return !mReceivedMessages.empty(); +} + +void TestInputChannel::assertFinishMessage(uint32_t seq, bool handled) { + ASSERT_FALSE(mSentMessages.empty()) + << "TestInputChannel " << getName() << ". Cannot assert. mSentMessages is empty."; + + const InputMessage& finishMessage = mSentMessages.front(); + + EXPECT_EQ(finishMessage.header.seq, seq) + << "TestInputChannel " << getName() + << ". Sequence mismatch. Message seq: " << finishMessage.header.seq + << " Expected seq: " << seq; + + EXPECT_EQ(finishMessage.body.finished.handled, handled) + << "TestInputChannel " << getName() + << ". Handled value mismatch. Message val: " << std::boolalpha + << finishMessage.body.finished.handled << "Expected val: " << handled + << std::noboolalpha; + mSentMessages.pop(); +} + +void TestInputChannel::assertNoSentMessages() const { + ASSERT_TRUE(mSentMessages.empty()); +} +} // namespace android
\ No newline at end of file diff --git a/libs/input/tests/TestInputChannel.h b/libs/input/tests/TestInputChannel.h new file mode 100644 index 0000000000..43253ec0ef --- /dev/null +++ b/libs/input/tests/TestInputChannel.h @@ -0,0 +1,66 @@ +/** + * Copyright 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 <queue> +#include <string> + +#include <android-base/result.h> +#include <gtest/gtest.h> +#include <input/InputTransport.h> +#include <utils/Errors.h> + +namespace android { + +class TestInputChannel final : public InputChannel { +public: + explicit TestInputChannel(const std::string& name); + + /** + * Enqueues a message in mReceivedMessages. + */ + void enqueueMessage(const InputMessage& message); + + /** + * Pushes message to mSentMessages. In the default implementation, InputChannel sends messages + * through a file descriptor. TestInputChannel, on the contrary, stores sent messages in + * mSentMessages for assertion reasons. + */ + status_t sendMessage(const InputMessage* message) override; + + /** + * Returns an InputMessage from mReceivedMessages. This is done instead of retrieving data + * directly from fd. + */ + base::Result<InputMessage> receiveMessage() override; + + /** + * Returns if mReceivedMessages is not empty. + */ + bool probablyHasInput() const override; + + void assertFinishMessage(uint32_t seq, bool handled); + + void assertNoSentMessages() const; + +private: + // InputMessages received by the endpoint. + std::queue<InputMessage> mReceivedMessages; + // InputMessages sent by the endpoint. + std::queue<InputMessage> mSentMessages; +}; +} // namespace android diff --git a/libs/input/tests/TestLooper.cpp b/libs/input/tests/TestLooper.cpp new file mode 100644 index 0000000000..e0f01ed25d --- /dev/null +++ b/libs/input/tests/TestLooper.cpp @@ -0,0 +1,51 @@ +/** + * Copyright 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. + */ + +#include <TestLooper.h> + +#include <android-base/logging.h> + +namespace android { + +TestLooper::TestLooper() : mLooper(sp<Looper>::make(/*allowNonCallbacks=*/false)) {} + +int TestLooper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, + void* data) { + mCallbacks[fd] = callback; + constexpr int SUCCESS{1}; + return SUCCESS; +} + +int TestLooper::removeFd(int fd) { + if (auto it = mCallbacks.find(fd); it != mCallbacks.cend()) { + mCallbacks.erase(fd); + constexpr int SUCCESS{1}; + return SUCCESS; + } + constexpr int FAILURE{0}; + return FAILURE; +} + +void TestLooper::invokeCallback(int fd, int events) { + auto it = mCallbacks.find(fd); + LOG_IF(FATAL, it == mCallbacks.cend()) << "Fd does not exist in mCallbacks."; + mCallbacks[fd]->handleEvent(fd, events, /*data=*/nullptr); +} + +sp<Looper> TestLooper::getLooper() const { + return mLooper; +} +} // namespace android
\ No newline at end of file diff --git a/libs/input/tests/TestLooper.h b/libs/input/tests/TestLooper.h new file mode 100644 index 0000000000..3242bc7699 --- /dev/null +++ b/libs/input/tests/TestLooper.h @@ -0,0 +1,56 @@ +/** + * Copyright 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 <map> + +#include <input/LooperInterface.h> + +namespace android { +/** + * TestLooper provides a mechanism to directly trigger Looper's callback. + */ +class TestLooper final : public LooperInterface { +public: + TestLooper(); + + /** + * Adds a file descriptor to mCallbacks. Ident, events, and data parameters are ignored. If + * addFd is called with an existent file descriptor and a different callback, the previous + * callback is overwritten. + */ + int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, + void* data) override; + + /** + * Removes a file descriptor from mCallbacks. If fd is not in mCallbacks, returns FAILURE. + */ + int removeFd(int fd) override; + + /** + * Calls handleEvent of the file descriptor. Fd must be in mCallbacks. Otherwise, invokeCallback + * fatally logs. + */ + void invokeCallback(int fd, int events); + + sp<Looper> getLooper() const override; + +private: + std::map<int /*fd*/, sp<LooperCallback>> mCallbacks; + sp<Looper> mLooper; +}; +} // namespace android
\ No newline at end of file diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp index 97740dbcd8..d68d6ba1af 100644 --- a/libs/nativewindow/rust/Android.bp +++ b/libs/nativewindow/rust/Android.bp @@ -29,6 +29,8 @@ rust_bindgen { "--bitfield-enum=AHardwareBuffer_UsageFlags", "--allowlist-file=.*/nativewindow/include/.*\\.h", + "--allowlist-file=.*/include/cutils/.*\\.h", + "--allowlist-file=.*/include_outside_system/cutils/.*\\.h", "--blocklist-type", "AParcel", "--raw-line", @@ -39,6 +41,7 @@ rust_bindgen { ], shared_libs: [ "libbinder_ndk", + "libcutils", "libnativewindow", ], rustlibs: [ @@ -66,6 +69,7 @@ rust_library { srcs: [":libnativewindow_bindgen_internal"], shared_libs: [ "libbinder_ndk", + "libcutils", "libnativewindow", ], rustlibs: [ diff --git a/libs/nativewindow/rust/src/handle.rs b/libs/nativewindow/rust/src/handle.rs new file mode 100644 index 0000000000..a3a9dc6258 --- /dev/null +++ b/libs/nativewindow/rust/src/handle.rs @@ -0,0 +1,92 @@ +// 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. + +use std::{mem::forget, ptr::NonNull}; + +/// Rust wrapper around `native_handle_t`. +/// +/// This owns the `native_handle_t` and its file descriptors, and will close them and free it when +/// it is dropped. +#[derive(Debug)] +pub struct NativeHandle(NonNull<ffi::native_handle_t>); + +impl NativeHandle { + /// Wraps a raw `native_handle_t` pointer, taking ownership of it. + /// + /// # Safety + /// + /// `native_handle` must be a valid pointer to a `native_handle_t`, and must not be used + /// anywhere else after calling this method. + pub unsafe fn from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Self { + Self(native_handle) + } + + /// Creates a new `NativeHandle` wrapping a clone of the given `native_handle_t` pointer. + /// + /// Unlike [`from_raw`](Self::from_raw) this doesn't take ownership of the pointer passed in, so + /// the caller remains responsible for closing and freeing it. + /// + /// # Safety + /// + /// `native_handle` must be a valid pointer to a `native_handle_t`. + pub unsafe fn clone_from_raw(native_handle: NonNull<ffi::native_handle_t>) -> Option<Self> { + // SAFETY: The caller promised that `native_handle` was valid. + let cloned = unsafe { ffi::native_handle_clone(native_handle.as_ptr()) }; + NonNull::new(cloned).map(Self) + } + + /// Returns a raw pointer to the wrapped `native_handle_t`. + /// + /// This is only valid as long as this `NativeHandle` exists, so shouldn't be stored. It mustn't + /// be closed or deleted. + pub fn as_raw(&self) -> NonNull<ffi::native_handle_t> { + self.0 + } + + /// Turns the `NativeHandle` into a raw `native_handle_t`. + /// + /// The caller takes ownership of the `native_handle_t` and its file descriptors, so is + /// responsible for closing and freeing it. + pub fn into_raw(self) -> NonNull<ffi::native_handle_t> { + let raw = self.0; + forget(self); + raw + } +} + +impl Clone for NativeHandle { + fn clone(&self) -> Self { + // SAFETY: Our wrapped `native_handle_t` pointer is always valid. + unsafe { Self::clone_from_raw(self.0) }.expect("native_handle_clone returned null") + } +} + +impl Drop for NativeHandle { + fn drop(&mut self) { + // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed + // after this because we own it and are being dropped. + unsafe { + assert_eq!(ffi::native_handle_close(self.0.as_ptr()), 0); + assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0); + } + } +} + +// 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 {} + +// SAFETY: A `NativeHandle` can be used from different threads simultaneously, as is is just +// integers and file descriptors. +unsafe impl Sync for NativeHandle {} diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index dc3f51f7fd..931c311e65 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -16,7 +16,10 @@ extern crate nativewindow_bindgen as ffi; +mod handle; mod surface; + +pub use handle::NativeHandle; pub use surface::Surface; pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; @@ -27,31 +30,29 @@ use binder::{ unstable_api::{status_result, AsNative}, StatusCode, }; -use ffi::{AHardwareBuffer, AHardwareBuffer_readFromParcel, AHardwareBuffer_writeToParcel}; +use ffi::{ + AHardwareBuffer, AHardwareBuffer_Desc, AHardwareBuffer_readFromParcel, + AHardwareBuffer_writeToParcel, +}; use std::fmt::{self, Debug, Formatter}; use std::mem::ManuallyDrop; use std::ptr::{self, null_mut, NonNull}; -/// Wrapper around an opaque C `AHardwareBuffer`. -#[derive(PartialEq, Eq)] -pub struct HardwareBuffer(NonNull<AHardwareBuffer>); +/// Wrapper around a C `AHardwareBuffer_Desc`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct HardwareBufferDescription(AHardwareBuffer_Desc); -impl HardwareBuffer { - /// Test whether the given format and usage flag combination is allocatable. If this function - /// returns true, it means that a buffer with the given description can be allocated on this - /// implementation, unless resource exhaustion occurs. If this function returns false, it means - /// that the allocation of the given description will never succeed. - /// - /// Available since API 29 - pub fn is_supported( +impl HardwareBufferDescription { + /// Creates a new `HardwareBufferDescription` with the given parameters. + pub fn new( width: u32, height: u32, layers: u32, format: AHardwareBuffer_Format::Type, usage: AHardwareBuffer_UsageFlags, stride: u32, - ) -> bool { - let buffer_desc = ffi::AHardwareBuffer_Desc { + ) -> Self { + Self(AHardwareBuffer_Desc { width, height, layers, @@ -60,9 +61,69 @@ impl HardwareBuffer { stride, rfu0: 0, rfu1: 0, - }; - // SAFETY: *buffer_desc will never be null. - let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) }; + }) + } + + /// Returns the width from the buffer description. + pub fn width(&self) -> u32 { + self.0.width + } + + /// Returns the height from the buffer description. + pub fn height(&self) -> u32 { + self.0.height + } + + /// Returns the number from layers from the buffer description. + pub fn layers(&self) -> u32 { + self.0.layers + } + + /// Returns the format from the buffer description. + pub fn format(&self) -> AHardwareBuffer_Format::Type { + self.0.format + } + + /// Returns the usage bitvector from the buffer description. + pub fn usage(&self) -> AHardwareBuffer_UsageFlags { + AHardwareBuffer_UsageFlags(self.0.usage) + } + + /// Returns the stride from the buffer description. + pub fn stride(&self) -> u32 { + self.0.stride + } +} + +impl Default for HardwareBufferDescription { + fn default() -> Self { + Self(AHardwareBuffer_Desc { + width: 0, + height: 0, + layers: 0, + format: 0, + usage: 0, + stride: 0, + rfu0: 0, + rfu1: 0, + }) + } +} + +/// Wrapper around an opaque C `AHardwareBuffer`. +#[derive(PartialEq, Eq)] +pub struct HardwareBuffer(NonNull<AHardwareBuffer>); + +impl HardwareBuffer { + /// Test whether the given format and usage flag combination is allocatable. If this function + /// returns true, it means that a buffer with the given description can be allocated on this + /// implementation, unless resource exhaustion occurs. If this function returns false, it means + /// that the allocation of the given description will never succeed. + /// + /// Available since API 29 + pub fn is_supported(buffer_description: &HardwareBufferDescription) -> bool { + // SAFETY: The pointer comes from a reference so must be valid. + let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_description.0) }; status == 1 } @@ -74,27 +135,11 @@ impl HardwareBuffer { /// /// Available since API level 26. #[inline] - pub fn new( - width: u32, - height: u32, - layers: u32, - format: AHardwareBuffer_Format::Type, - usage: AHardwareBuffer_UsageFlags, - ) -> Option<Self> { - let buffer_desc = ffi::AHardwareBuffer_Desc { - width, - height, - layers, - format, - usage: usage.0, - stride: 0, - rfu0: 0, - rfu1: 0, - }; + pub fn new(buffer_description: &HardwareBufferDescription) -> Option<Self> { let mut ptr = ptr::null_mut(); // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail // and return a status, but we check it later. - let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut ptr) }; + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_description.0, &mut ptr) }; if status == 0 { Some(Self(NonNull::new(ptr).expect("Allocated AHardwareBuffer was null"))) @@ -103,6 +148,50 @@ impl HardwareBuffer { } } + /// Creates a `HardwareBuffer` from a native handle. + /// + /// The native handle is cloned, so this doesn't take ownership of the original handle passed + /// in. + pub fn create_from_handle( + handle: &NativeHandle, + buffer_description: &HardwareBufferDescription, + ) -> Result<Self, StatusCode> { + let mut buffer = ptr::null_mut(); + // SAFETY: The caller guarantees that `handle` is valid, and the buffer pointer is valid + // because it comes from a reference. The method we pass means that + // `AHardwareBuffer_createFromHandle` will clone the handle rather than taking ownership of + // it. + let status = unsafe { + ffi::AHardwareBuffer_createFromHandle( + &buffer_description.0, + handle.as_raw().as_ptr(), + ffi::CreateFromHandleMethod_AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE + .try_into() + .unwrap(), + &mut buffer, + ) + }; + status_result(status)?; + Ok(Self(NonNull::new(buffer).expect("Allocated AHardwareBuffer was null"))) + } + + /// Returns a clone of the native handle of the buffer. + /// + /// Returns `None` if the operation fails for any reason. + pub fn cloned_native_handle(&self) -> Option<NativeHandle> { + // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid + // because it must have been allocated by `AHardwareBuffer_allocate`, + // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet + // released it. + let native_handle = unsafe { ffi::AHardwareBuffer_getNativeHandle(self.0.as_ptr()) }; + NonNull::new(native_handle.cast_mut()).and_then(|native_handle| { + // SAFETY: `AHardwareBuffer_getNativeHandle` should have returned a valid pointer which + // is valid at least as long as the buffer is, and `clone_from_raw` clones it rather + // than taking ownership of it so the original `native_handle` isn't stored. + unsafe { NativeHandle::clone_from_raw(native_handle) } + }) + } + /// Adopts the given raw pointer and wraps it in a Rust HardwareBuffer. /// /// # Safety @@ -155,37 +244,8 @@ impl HardwareBuffer { out_id } - /// Get the width of this buffer - pub fn width(&self) -> u32 { - self.description().width - } - - /// Get the height of this buffer - pub fn height(&self) -> u32 { - self.description().height - } - - /// Get the number of layers of this buffer - pub fn layers(&self) -> u32 { - self.description().layers - } - - /// Get the format of this buffer - pub fn format(&self) -> AHardwareBuffer_Format::Type { - self.description().format - } - - /// Get the usage bitvector of this buffer - pub fn usage(&self) -> AHardwareBuffer_UsageFlags { - AHardwareBuffer_UsageFlags(self.description().usage) - } - - /// Get the stride of this buffer - pub fn stride(&self) -> u32 { - self.description().stride - } - - fn description(&self) -> ffi::AHardwareBuffer_Desc { + /// Returns the description of this buffer. + pub fn description(&self) -> HardwareBufferDescription { let mut buffer_desc = ffi::AHardwareBuffer_Desc { width: 0, height: 0, @@ -198,7 +258,7 @@ impl HardwareBuffer { }; // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null. unsafe { ffi::AHardwareBuffer_describe(self.0.as_ref(), &mut buffer_desc) }; - buffer_desc + HardwareBufferDescription(buffer_desc) } } @@ -281,19 +341,27 @@ mod test { #[test] fn create_valid_buffer_returns_ok() { - let buffer = HardwareBuffer::new( + let buffer = HardwareBuffer::new(&HardwareBufferDescription::new( 512, 512, 1, AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, - ); + 0, + )); assert!(buffer.is_some()); } #[test] fn create_invalid_buffer_returns_err() { - let buffer = HardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0)); + let buffer = HardwareBuffer::new(&HardwareBufferDescription::new( + 512, + 512, + 1, + 0, + AHardwareBuffer_UsageFlags(0), + 0, + )); assert!(buffer.is_none()); } @@ -319,39 +387,45 @@ mod test { // SAFETY: The pointer must be valid because it was just allocated successfully, and we // don't use it after calling this. let buffer = unsafe { HardwareBuffer::from_raw(NonNull::new(raw_buffer_ptr).unwrap()) }; - assert_eq!(buffer.width(), 1024); + assert_eq!(buffer.description().width(), 1024); } #[test] fn basic_getters() { - let buffer = HardwareBuffer::new( + let buffer = HardwareBuffer::new(&HardwareBufferDescription::new( 1024, 512, 1, AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, - ) + 0, + )) .expect("Buffer with some basic parameters was not created successfully"); - assert_eq!(buffer.width(), 1024); - assert_eq!(buffer.height(), 512); - assert_eq!(buffer.layers(), 1); - assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM); + let description = buffer.description(); + assert_eq!(description.width(), 1024); + assert_eq!(description.height(), 512); + assert_eq!(description.layers(), 1); + assert_eq!( + description.format(), + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM + ); assert_eq!( - buffer.usage(), + description.usage(), AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN ); } #[test] fn id_getter() { - let buffer = HardwareBuffer::new( + let buffer = HardwareBuffer::new(&HardwareBufferDescription::new( 1024, 512, 1, AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, - ) + 0, + )) .expect("Buffer with some basic parameters was not created successfully"); assert_ne!(0, buffer.id()); @@ -359,13 +433,14 @@ mod test { #[test] fn clone() { - let buffer = HardwareBuffer::new( + let buffer = HardwareBuffer::new(&HardwareBufferDescription::new( 1024, 512, 1, AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, - ) + 0, + )) .expect("Buffer with some basic parameters was not created successfully"); let buffer2 = buffer.clone(); @@ -374,13 +449,14 @@ mod test { #[test] fn into_raw() { - let buffer = HardwareBuffer::new( + let buffer = HardwareBuffer::new(&HardwareBufferDescription::new( 1024, 512, 1, AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, - ) + 0, + )) .expect("Buffer with some basic parameters was not created successfully"); let buffer2 = buffer.clone(); @@ -390,4 +466,26 @@ mod test { assert_eq!(remade_buffer, buffer2); } + + #[test] + fn native_handle_and_back() { + let buffer_description = HardwareBufferDescription::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + 1024, + ); + let buffer = HardwareBuffer::new(&buffer_description) + .expect("Buffer with some basic parameters was not created successfully"); + + let native_handle = + buffer.cloned_native_handle().expect("Failed to get native handle for buffer"); + let buffer2 = HardwareBuffer::create_from_handle(&native_handle, &buffer_description) + .expect("Failed to create buffer from native handle"); + + assert_eq!(buffer.description(), buffer_description); + assert_eq!(buffer2.description(), buffer_description); + } } diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h index 5689f7df94..5046a80095 100644 --- a/libs/nativewindow/rust/sys/nativewindow_bindings.h +++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h @@ -20,3 +20,5 @@ #include <android/hdr_metadata.h> #include <android/native_window.h> #include <android/native_window_aidl.h> +#include <cutils/native_handle.h> +#include <vndk/hardware_buffer.h> diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs index 876f6c8e26..73a7e95149 100644 --- a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs @@ -22,13 +22,14 @@ use nativewindow::*; #[inline] fn create_720p_buffer() -> HardwareBuffer { - HardwareBuffer::new( + HardwareBuffer::new(&HardwareBufferDescription::new( 1280, 720, 1, AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, - ) + 0, + )) .unwrap() } @@ -51,7 +52,7 @@ fn criterion_benchmark(c: &mut Criterion) { // underlying call to AHardwareBuffer_describe. c.bench_with_input(BenchmarkId::new("desc", "buffer"), &buffer, |b, buffer| { b.iter(|| { - buffer.width(); + buffer.description().width(); }) }); } diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 7639fab3a5..d248ea0b84 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -100,6 +100,7 @@ filegroup { "skia/debug/SkiaCapture.cpp", "skia/debug/SkiaMemoryReporter.cpp", "skia/filters/BlurFilter.cpp", + "skia/filters/GainmapFactory.cpp", "skia/filters/GaussianBlurFilter.cpp", "skia/filters/KawaseBlurDualFilter.cpp", "skia/filters/KawaseBlurFilter.cpp", diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index bc3976d9f1..907590a236 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -21,6 +21,7 @@ #include "skia/GraphiteVkRenderEngine.h" #include "skia/SkiaGLRenderEngine.h" #include "threaded/RenderEngineThreaded.h" +#include "ui/GraphicTypes.h" #include <com_android_graphics_surfaceflinger_flags.h> #include <cutils/properties.h> @@ -101,17 +102,34 @@ ftl::Future<FenceResult> RenderEngine::drawLayers(const DisplaySettings& display base::unique_fd&& bufferFence) { const auto resultPromise = std::make_shared<std::promise<FenceResult>>(); std::future<FenceResult> resultFuture = resultPromise->get_future(); - updateProtectedContext(layers, buffer); + updateProtectedContext(layers, {buffer.get()}); drawLayersInternal(std::move(resultPromise), display, layers, buffer, std::move(bufferFence)); return resultFuture; } +ftl::Future<FenceResult> RenderEngine::drawGainmap( + const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) { + const auto resultPromise = std::make_shared<std::promise<FenceResult>>(); + std::future<FenceResult> resultFuture = resultPromise->get_future(); + updateProtectedContext({}, {sdr.get(), hdr.get(), gainmap.get()}); + drawGainmapInternal(std::move(resultPromise), sdr, std::move(sdrFence), hdr, + std::move(hdrFence), hdrSdrRatio, dataspace, gainmap); + return resultFuture; +} + void RenderEngine::updateProtectedContext(const std::vector<LayerSettings>& layers, - const std::shared_ptr<ExternalTexture>& buffer) { + vector<const ExternalTexture*> buffers) { const bool needsProtectedContext = - (buffer && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED)) || - std::any_of(layers.begin(), layers.end(), [](const LayerSettings& layer) { - const std::shared_ptr<ExternalTexture>& buffer = layer.source.buffer.buffer; + std::any_of(layers.begin(), layers.end(), + [](const LayerSettings& layer) { + const std::shared_ptr<ExternalTexture>& buffer = + layer.source.buffer.buffer; + return buffer && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED); + }) || + std::any_of(buffers.begin(), buffers.end(), [](const ExternalTexture* buffer) { return buffer && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED); }); useProtectedContext(needsProtectedContext); diff --git a/libs/renderengine/benchmark/AndroidTest.xml b/libs/renderengine/benchmark/AndroidTest.xml new file mode 100644 index 0000000000..3b923cb3a8 --- /dev/null +++ b/libs/renderengine/benchmark/AndroidTest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 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. +--> +<configuration description="Config for librenderengine_bench."> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-native-metric" /> + + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="librenderengine_bench->/data/local/tmp/librenderengine_bench" /> + </target_preparer> + <test class="com.android.tradefed.testtype.GoogleBenchmarkTest" > + <option name="native-benchmark-device-path" value="/data/local/tmp" /> + <option name="benchmark-module-name" value="librenderengine_bench" /> + <option name="file-exclusion-filter-regex" value=".*\.config$" /> + <option name="file-exclusion-filter-regex" value=".*/resources/.*" /> + </test> +</configuration> diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp index 326d1cec1b..a9264b3914 100644 --- a/libs/renderengine/benchmark/RenderEngineBench.cpp +++ b/libs/renderengine/benchmark/RenderEngineBench.cpp @@ -29,6 +29,16 @@ using namespace android; using namespace android::renderengine; +// To run tests: +/** + * mmm frameworks/native/libs/renderengine/benchmark;\ + * adb push $OUT/data/benchmarktest/librenderengine_bench/librenderengine_bench + * /data/benchmarktest/librenderengine_bench/librenderengine_bench;\ + * adb shell /data/benchmarktest/librenderengine_bench/librenderengine_bench + * + * (64-bit devices: out directory contains benchmarktest64 instead of benchmarktest) + */ + /////////////////////////////////////////////////////////////////////////////// // Helpers for calling drawLayers /////////////////////////////////////////////////////////////////////////////// @@ -173,29 +183,67 @@ static void benchDrawLayers(RenderEngine& re, const std::vector<LayerSettings>& } } +/** + * Return a buffer with the image in the provided path, relative to the executable directory + */ +static std::shared_ptr<ExternalTexture> createTexture(RenderEngine& re, const char* relPathImg) { + // Initially use cpu access so we can decode into it with AImageDecoder. + auto [width, height] = getDisplaySize(); + auto srcBuffer = + allocateBuffer(re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN, "decoded_source"); + std::string fileName = base::GetExecutableDirectory().append(relPathImg); + renderenginebench::decode(fileName.c_str(), srcBuffer->getBuffer()); + // Now copy into GPU-only buffer for more realistic timing. + srcBuffer = copyBuffer(re, srcBuffer, 0, "source"); + return srcBuffer; +} + /////////////////////////////////////////////////////////////////////////////// // Benchmarks /////////////////////////////////////////////////////////////////////////////// +constexpr char kHomescreenPath[] = "/resources/homescreen.png"; + +/** + * Draw a layer with texture and no additional shaders as a baseline to evaluate a shader's impact + * on performance + */ template <class... Args> -void BM_blur(benchmark::State& benchState, Args&&... args) { +void BM_homescreen(benchmark::State& benchState, Args&&... args) { auto args_tuple = std::make_tuple(std::move(args)...); auto re = createRenderEngine(static_cast<RenderEngine::Threaded>(std::get<0>(args_tuple)), - static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple)), - static_cast<RenderEngine::BlurAlgorithm>(std::get<2>(args_tuple))); + static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple))); - // Initially use cpu access so we can decode into it with AImageDecoder. auto [width, height] = getDisplaySize(); - auto srcBuffer = - allocateBuffer(*re, width, height, GRALLOC_USAGE_SW_WRITE_OFTEN, "decoded_source"); - { - std::string srcImage = base::GetExecutableDirectory(); - srcImage.append("/resources/homescreen.png"); - renderenginebench::decode(srcImage.c_str(), srcBuffer->getBuffer()); - - // Now copy into GPU-only buffer for more realistic timing. - srcBuffer = copyBuffer(*re, srcBuffer, 0, "source"); - } + auto srcBuffer = createTexture(*re, kHomescreenPath); + + const FloatRect layerRect(0, 0, width, height); + LayerSettings layer{ + .geometry = + Geometry{ + .boundaries = layerRect, + }, + .source = + PixelSource{ + .buffer = + Buffer{ + .buffer = srcBuffer, + }, + }, + .alpha = half(1.0f), + }; + auto layers = std::vector<LayerSettings>{layer}; + benchDrawLayers(*re, layers, benchState, "homescreen"); +} + +template <class... Args> +void BM_homescreen_blur(benchmark::State& benchState, Args&&... args) { + auto args_tuple = std::make_tuple(std::move(args)...); + auto re = createRenderEngine(static_cast<RenderEngine::Threaded>(std::get<0>(args_tuple)), + static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple))); + + auto [width, height] = getDisplaySize(); + auto srcBuffer = createTexture(*re, kHomescreenPath); const FloatRect layerRect(0, 0, width, height); LayerSettings layer{ @@ -223,14 +271,55 @@ void BM_blur(benchmark::State& benchState, Args&&... args) { }; auto layers = std::vector<LayerSettings>{layer, blurLayer}; - benchDrawLayers(*re, layers, benchState, "blurred"); + benchDrawLayers(*re, layers, benchState, "homescreen_blurred"); +} + +template <class... Args> +void BM_homescreen_edgeExtension(benchmark::State& benchState, Args&&... args) { + auto args_tuple = std::make_tuple(std::move(args)...); + auto re = createRenderEngine(static_cast<RenderEngine::Threaded>(std::get<0>(args_tuple)), + static_cast<RenderEngine::GraphicsApi>(std::get<1>(args_tuple))); + + auto [width, height] = getDisplaySize(); + auto srcBuffer = createTexture(*re, kHomescreenPath); + + LayerSettings layer{ + .geometry = + Geometry{ + .boundaries = FloatRect(0, 0, width, height), + }, + .source = + PixelSource{ + .buffer = + Buffer{ + .buffer = srcBuffer, + // Part of the screen is not covered by the texture but + // will be filled in by the shader + .textureTransform = + mat4(mat3(), + vec3(width * 0.3f, height * 0.3f, 0.0f)), + }, + }, + .alpha = half(1.0f), + .edgeExtensionEffect = + EdgeExtensionEffect(/* left */ true, + /* right */ false, /* top */ true, /* bottom */ false), + }; + auto layers = std::vector<LayerSettings>{layer}; + benchDrawLayers(*re, layers, benchState, "homescreen_edge_extension"); } -BENCHMARK_CAPTURE(BM_blur, gaussian, RenderEngine::Threaded::YES, RenderEngine::GraphicsApi::GL, - RenderEngine::BlurAlgorithm::GAUSSIAN); +BENCHMARK_CAPTURE(BM_homescreen_blur, gaussian, RenderEngine::Threaded::YES, + RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::GAUSSIAN); -BENCHMARK_CAPTURE(BM_blur, kawase, RenderEngine::Threaded::YES, RenderEngine::GraphicsApi::GL, - RenderEngine::BlurAlgorithm::KAWASE); +BENCHMARK_CAPTURE(BM_homescreen_blur, kawase, RenderEngine::Threaded::YES, + RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::KAWASE); -BENCHMARK_CAPTURE(BM_blur, kawase_dual_filter, RenderEngine::Threaded::YES, +BENCHMARK_CAPTURE(BM_homescreen_blur, kawase_dual_filter, RenderEngine::Threaded::YES, RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::KAWASE_DUAL_FILTER); + +BENCHMARK_CAPTURE(BM_homescreen, SkiaGLThreaded, RenderEngine::Threaded::YES, + RenderEngine::GraphicsApi::GL); + +BENCHMARK_CAPTURE(BM_homescreen_edgeExtension, SkiaGLThreaded, RenderEngine::Threaded::YES, + RenderEngine::GraphicsApi::GL); diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index b640983a55..280ec19a4c 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -102,6 +102,9 @@ struct DisplaySettings { Local, }; TonemapStrategy tonemapStrategy = TonemapStrategy::Libtonemap; + + // For now, meaningful primarily when the TonemappingStrategy is Local + float targetHdrSdrRatio = 1.f; }; static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) { diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 9bc2c48a8a..1954fc52e9 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -208,6 +208,13 @@ public: const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence); + virtual ftl::Future<FenceResult> drawGainmap(const std::shared_ptr<ExternalTexture>& sdr, + base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, + base::borrowed_fd&& hdrFence, float hdrSdrRatio, + ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap); + // Clean-up method that should be called on the main thread after the // drawFence returned by drawLayers fires. This method will free up // resources used by the most recently drawn frame. If the frame is still @@ -285,8 +292,7 @@ protected: // Update protectedContext mode depending on whether or not any layer has a protected buffer. void updateProtectedContext(const std::vector<LayerSettings>&, - const std::shared_ptr<ExternalTexture>&); - + std::vector<const ExternalTexture*>); // Attempt to switch RenderEngine into and out of protectedContext mode virtual void useProtectedContext(bool useProtectedContext) = 0; @@ -294,6 +300,13 @@ protected: const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, const DisplaySettings& display, const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) = 0; + + virtual void drawGainmapInternal( + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) = 0; }; struct RenderEngineCreationArgs { diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index a8c242a86f..fb8331d870 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -46,6 +46,17 @@ public: ftl::Future<FenceResult>(const DisplaySettings&, const std::vector<LayerSettings>&, const std::shared_ptr<ExternalTexture>&, base::unique_fd&&)); + MOCK_METHOD7(drawGainmap, + ftl::Future<FenceResult>(const std::shared_ptr<ExternalTexture>&, + base::borrowed_fd&&, + const std::shared_ptr<ExternalTexture>&, + base::borrowed_fd&&, float, ui::Dataspace, + const std::shared_ptr<ExternalTexture>&)); + MOCK_METHOD8(drawGainmapInternal, + void(const std::shared_ptr<std::promise<FenceResult>>&&, + const std::shared_ptr<ExternalTexture>&, base::borrowed_fd&&, + const std::shared_ptr<ExternalTexture>&, base::borrowed_fd&&, float, + ui::Dataspace, const std::shared_ptr<ExternalTexture>&)); MOCK_METHOD5(drawLayersInternal, void(const std::shared_ptr<std::promise<FenceResult>>&&, const DisplaySettings&, const std::vector<LayerSettings>&, const std::shared_ptr<ExternalTexture>&, diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index 056e8fecc3..ec9d3efb88 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -75,6 +75,7 @@ #include "ColorSpaces.h" #include "compat/SkiaGpuContext.h" #include "filters/BlurFilter.h" +#include "filters/GainmapFactory.h" #include "filters/GaussianBlurFilter.h" #include "filters/KawaseBlurDualFilter.h" #include "filters/KawaseBlurFilter.h" @@ -238,12 +239,22 @@ static inline SkM44 getSkM44(const android::mat4& matrix) { static inline SkPoint3 getSkPoint3(const android::vec3& vector) { return SkPoint3::Make(vector.x, vector.y, vector.z); } + } // namespace namespace android { namespace renderengine { namespace skia { +namespace { +void trace(sp<Fence> fence) { + if (SFTRACE_ENABLED()) { + static gui::FenceMonitor sMonitor("RE Completion"); + sMonitor.queueFence(std::move(fence)); + } +} +} // namespace + using base::StringAppendF; std::future<void> SkiaRenderEngine::primeCache(PrimeCacheConfig config) { @@ -544,13 +555,15 @@ sk_sp<SkShader> SkiaRenderEngine::createRuntimeEffectShader( const auto usingLocalTonemap = parameters.display.tonemapStrategy == DisplaySettings::TonemapStrategy::Local && hdrType != HdrRenderType::SDR && - shader->isAImage((SkMatrix*)nullptr, (SkTileMode*)nullptr); - + shader->isAImage((SkMatrix*)nullptr, (SkTileMode*)nullptr) && + (hdrType != HdrRenderType::DISPLAY_HDR || + parameters.display.targetHdrSdrRatio < parameters.layerDimmingRatio); if (usingLocalTonemap) { - static MouriMap kMapper; - const float ratio = + const float inputRatio = hdrType == HdrRenderType::GENERIC_HDR ? 1.0f : parameters.layerDimmingRatio; - shader = kMapper.mouriMap(getActiveContext(), shader, ratio); + static MouriMap kMapper; + shader = kMapper.mouriMap(getActiveContext(), shader, inputRatio, + parameters.display.targetHdrSdrRatio); } // disable tonemapping if we already locally tonemapped @@ -1187,11 +1200,48 @@ void SkiaRenderEngine::drawLayersInternal( LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface); auto drawFence = sp<Fence>::make(flushAndSubmit(context, dstSurface)); + trace(drawFence); + resultPromise->set_value(std::move(drawFence)); +} - if (SFTRACE_ENABLED()) { - static gui::FenceMonitor sMonitor("RE Completion"); - sMonitor.queueFence(drawFence); - } +void SkiaRenderEngine::drawGainmapInternal( + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) { + std::lock_guard<std::mutex> lock(mRenderingMutex); + auto context = getActiveContext(); + auto surfaceTextureRef = getOrCreateBackendTexture(gainmap->getBuffer(), true); + sk_sp<SkSurface> dstSurface = + surfaceTextureRef->getOrCreateSurface(ui::Dataspace::V0_SRGB_LINEAR); + + waitFence(context, sdrFence); + const auto sdrTextureRef = getOrCreateBackendTexture(sdr->getBuffer(), false); + const auto sdrImage = sdrTextureRef->makeImage(dataspace, kPremul_SkAlphaType); + const auto sdrShader = + sdrImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, + SkSamplingOptions({SkFilterMode::kLinear, SkMipmapMode::kNone}), + nullptr); + waitFence(context, hdrFence); + const auto hdrTextureRef = getOrCreateBackendTexture(hdr->getBuffer(), false); + const auto hdrImage = hdrTextureRef->makeImage(dataspace, kPremul_SkAlphaType); + const auto hdrShader = + hdrImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, + SkSamplingOptions({SkFilterMode::kLinear, SkMipmapMode::kNone}), + nullptr); + + static GainmapFactory kGainmapFactory; + const auto gainmapShader = kGainmapFactory.createSkShader(sdrShader, hdrShader, hdrSdrRatio); + + const auto canvas = dstSurface->getCanvas(); + SkPaint paint; + paint.setShader(gainmapShader); + paint.setBlendMode(SkBlendMode::kSrc); + canvas->drawPaint(paint); + + auto drawFence = sp<Fence>::make(flushAndSubmit(context, dstSurface)); + trace(drawFence); resultPromise->set_value(std::move(drawFence)); } diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 721dbce0e8..b5f8898263 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -142,6 +142,13 @@ private: const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) override final; + void drawGainmapInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& sdr, + base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, + base::borrowed_fd&& hdrFence, float hdrSdrRatio, + ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) override final; void dump(std::string& result) override final; diff --git a/libs/renderengine/skia/filters/GainmapFactory.cpp b/libs/renderengine/skia/filters/GainmapFactory.cpp new file mode 100644 index 0000000000..e4d4fe96f8 --- /dev/null +++ b/libs/renderengine/skia/filters/GainmapFactory.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 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. + */ + +#include "GainmapFactory.h" + +#include <log/log.h> + +namespace android { +namespace renderengine { +namespace skia { +namespace { + +sk_sp<SkRuntimeEffect> makeEffect(const SkString& sksl) { + auto [effect, error] = SkRuntimeEffect::MakeForShader(sksl); + LOG_ALWAYS_FATAL_IF(!effect, "RuntimeShader error: %s", error.c_str()); + return effect; +} + +// Please refer to https://developer.android.com/media/platform/hdr-image-format#gain_map-generation +static const SkString kGainmapShader = SkString(R"( + uniform shader sdr; + uniform shader hdr; + uniform float mapMaxLog2; + + const float mapMinLog2 = 0.0; + const float mapGamma = 1.0; + const float offsetSdr = 0.015625; + const float offsetHdr = 0.015625; + + float luminance(vec3 linearColor) { + return 0.2126 * linearColor.r + 0.7152 * linearColor.g + 0.0722 * linearColor.b; + } + + vec4 main(vec2 xy) { + float sdrY = luminance(toLinearSrgb(sdr.eval(xy).rgb)); + float hdrY = luminance(toLinearSrgb(hdr.eval(xy).rgb)); + float pixelGain = (hdrY + offsetHdr) / (sdrY + offsetSdr); + float logRecovery = (log2(pixelGain) - mapMinLog2) / (mapMaxLog2 - mapMinLog2); + return vec4(pow(clamp(logRecovery, 0.0, 1.0), mapGamma)); + } +)"); +} // namespace + +const float INTERPOLATION_STRENGTH_VALUE = 0.7f; + +GainmapFactory::GainmapFactory() : mEffect(makeEffect(kGainmapShader)) {} + +sk_sp<SkShader> GainmapFactory::createSkShader(const sk_sp<SkShader>& sdr, + const sk_sp<SkShader>& hdr, float hdrSdrRatio) { + SkRuntimeShaderBuilder shaderBuilder(mEffect); + shaderBuilder.child("sdr") = sdr; + shaderBuilder.child("hdr") = hdr; + shaderBuilder.uniform("mapMaxLog2") = std::log2(hdrSdrRatio); + return shaderBuilder.makeShader(); +} + +} // namespace skia +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/skia/filters/GainmapFactory.h b/libs/renderengine/skia/filters/GainmapFactory.h new file mode 100644 index 0000000000..7aea5e2195 --- /dev/null +++ b/libs/renderengine/skia/filters/GainmapFactory.h @@ -0,0 +1,44 @@ +/* + * Copyright 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 <SkRuntimeEffect.h> +#include <SkShader.h> + +namespace android { +namespace renderengine { +namespace skia { + +/** + * Generates a shader for computing a gainmap, given an SDR base image and its idealized HDR + * rendition. The shader follows the procedure in the UltraHDR spec: + * https://developer.android.com/media/platform/hdr-image-format#gain_map-generation, but makes some + * simplifying assumptions about metadata typical for RenderEngine's usage. + */ +class GainmapFactory { +public: + GainmapFactory(); + // Generates the gainmap shader. The hdrSdrRatio is the max_content_boost in the UltraHDR + // specification. + sk_sp<SkShader> createSkShader(const sk_sp<SkShader>& sdr, const sk_sp<SkShader>& hdr, + float hdrSdrRatio); + +private: + sk_sp<SkRuntimeEffect> mEffect; +}; +} // namespace skia +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/skia/filters/MouriMap.cpp b/libs/renderengine/skia/filters/MouriMap.cpp index b45893919c..b099bcf3d7 100644 --- a/libs/renderengine/skia/filters/MouriMap.cpp +++ b/libs/renderengine/skia/filters/MouriMap.cpp @@ -67,7 +67,7 @@ const SkString kBlur(R"( float result = 0.0; for (int y = -2; y <= 2; y++) { for (int x = -2; x <= 2; x++) { - result += C[y + 2] * C[x + 2] * bitmap.eval(xy + vec2(x, y)).r; + result += C[y + 2] * C[x + 2] * bitmap.eval(xy + vec2(x, y)).r; } } return float4(float3(exp2(result)), 1.0); @@ -78,18 +78,20 @@ const SkString kTonemap(R"( uniform shader lux; uniform float scaleFactor; uniform float hdrSdrRatio; + uniform float targetHdrSdrRatio; vec4 main(vec2 xy) { float localMax = lux.eval(xy * scaleFactor).r; float4 rgba = image.eval(xy); float3 linear = toLinearSrgb(rgba.rgb) * hdrSdrRatio; - if (localMax <= 1.0) { + if (localMax <= targetHdrSdrRatio) { return float4(fromLinearSrgb(linear), rgba.a); } float maxRGB = max(linear.r, max(linear.g, linear.b)); localMax = max(localMax, maxRGB); - float gain = (1 + maxRGB / (localMax * localMax)) / (1 + maxRGB); + float gain = (1 + maxRGB * (targetHdrSdrRatio / (localMax * localMax))) + / (1 + maxRGB / targetHdrSdrRatio); return float4(fromLinearSrgb(linear * gain), rgba.a); } )"); @@ -114,10 +116,10 @@ MouriMap::MouriMap() mTonemap(makeEffect(kTonemap)) {} sk_sp<SkShader> MouriMap::mouriMap(SkiaGpuContext* context, sk_sp<SkShader> input, - float hdrSdrRatio) { + float hdrSdrRatio, float targetHdrSdrRatio) { auto downchunked = downchunk(context, input, hdrSdrRatio); auto localLux = blur(context, downchunked.get()); - return tonemap(input, localLux.get(), hdrSdrRatio); + return tonemap(input, localLux.get(), hdrSdrRatio, targetHdrSdrRatio); } sk_sp<SkImage> MouriMap::downchunk(SkiaGpuContext* context, sk_sp<SkShader> input, @@ -166,8 +168,8 @@ sk_sp<SkImage> MouriMap::blur(SkiaGpuContext* context, SkImage* input) const { LOG_ALWAYS_FATAL_IF(!blurSurface, "%s: Failed to create surface!", __func__); return makeImage(blurSurface.get(), blurBuilder); } -sk_sp<SkShader> MouriMap::tonemap(sk_sp<SkShader> input, SkImage* localLux, - float hdrSdrRatio) const { +sk_sp<SkShader> MouriMap::tonemap(sk_sp<SkShader> input, SkImage* localLux, float hdrSdrRatio, + float targetHdrSdrRatio) const { static constexpr float kScaleFactor = 1.0f / 128.0f; SkRuntimeShaderBuilder tonemapBuilder(mTonemap); tonemapBuilder.child("image") = input; @@ -176,8 +178,9 @@ sk_sp<SkShader> MouriMap::tonemap(sk_sp<SkShader> input, SkImage* localLux, SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone)); tonemapBuilder.uniform("scaleFactor") = kScaleFactor; tonemapBuilder.uniform("hdrSdrRatio") = hdrSdrRatio; + tonemapBuilder.uniform("targetHdrSdrRatio") = targetHdrSdrRatio; return tonemapBuilder.makeShader(); } } // namespace skia } // namespace renderengine -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/renderengine/skia/filters/MouriMap.h b/libs/renderengine/skia/filters/MouriMap.h index 3c0df8abf0..9ba2b6ff9d 100644 --- a/libs/renderengine/skia/filters/MouriMap.h +++ b/libs/renderengine/skia/filters/MouriMap.h @@ -64,13 +64,16 @@ public: // Apply the MouriMap tonemmaping operator to the input. // The HDR/SDR ratio describes the luminace range of the input. 1.0 means SDR. Anything larger // then 1.0 means that there is headroom above the SDR region. - sk_sp<SkShader> mouriMap(SkiaGpuContext* context, sk_sp<SkShader> input, float hdrSdrRatio); + // Similarly, the target HDR/SDR ratio describes the luminance range of the output. + sk_sp<SkShader> mouriMap(SkiaGpuContext* context, sk_sp<SkShader> input, float inputHdrSdrRatio, + float targetHdrSdrRatio); private: sk_sp<SkImage> downchunk(SkiaGpuContext* context, sk_sp<SkShader> input, float hdrSdrRatio) const; sk_sp<SkImage> blur(SkiaGpuContext* context, SkImage* input) const; - sk_sp<SkShader> tonemap(sk_sp<SkShader> input, SkImage* localLux, float hdrSdrRatio) const; + sk_sp<SkShader> tonemap(sk_sp<SkShader> input, SkImage* localLux, float hdrSdrRatio, + float targetHdrSdrRatio) const; const sk_sp<SkRuntimeEffect> mCrosstalkAndChunk16x16; const sk_sp<SkRuntimeEffect> mChunk8x8; const sk_sp<SkRuntimeEffect> mBlur; @@ -78,4 +81,4 @@ private: }; } // namespace skia } // namespace renderengine -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index f5a90fdcfd..c187f93089 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -249,6 +249,16 @@ void RenderEngineThreaded::drawLayersInternal( return; } +void RenderEngineThreaded::drawGainmapInternal( + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) { + resultPromise->set_value(Fence::NO_FENCE); + return; +} + ftl::Future<FenceResult> RenderEngineThreaded::drawLayers( const DisplaySettings& display, const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) { @@ -262,7 +272,7 @@ ftl::Future<FenceResult> RenderEngineThreaded::drawLayers( mFunctionCalls.push( [resultPromise, display, layers, buffer, fd](renderengine::RenderEngine& instance) { SFTRACE_NAME("REThreaded::drawLayers"); - instance.updateProtectedContext(layers, buffer); + instance.updateProtectedContext(layers, {buffer.get()}); instance.drawLayersInternal(std::move(resultPromise), display, layers, buffer, base::unique_fd(fd)); }); @@ -271,6 +281,30 @@ ftl::Future<FenceResult> RenderEngineThreaded::drawLayers( return resultFuture; } +ftl::Future<FenceResult> RenderEngineThreaded::drawGainmap( + const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) { + SFTRACE_CALL(); + const auto resultPromise = std::make_shared<std::promise<FenceResult>>(); + std::future<FenceResult> resultFuture = resultPromise->get_future(); + { + std::lock_guard lock(mThreadMutex); + mNeedsPostRenderCleanup = true; + mFunctionCalls.push([resultPromise, sdr, sdrFence = std::move(sdrFence), hdr, + hdrFence = std::move(hdrFence), hdrSdrRatio, dataspace, + gainmap](renderengine::RenderEngine& instance) mutable { + SFTRACE_NAME("REThreaded::drawGainmap"); + instance.updateProtectedContext({}, {sdr.get(), hdr.get(), gainmap.get()}); + instance.drawGainmapInternal(std::move(resultPromise), sdr, std::move(sdrFence), hdr, + std::move(hdrFence), hdrSdrRatio, dataspace, gainmap); + }); + } + mCondition.notify_one(); + return resultFuture; +} + int RenderEngineThreaded::getContextPriority() { std::promise<int> resultPromise; std::future<int> resultFuture = resultPromise.get_future(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index d4997d6c93..cb6e924d81 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -55,6 +55,12 @@ public: const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) override; + ftl::Future<FenceResult> drawGainmap(const std::shared_ptr<ExternalTexture>& sdr, + base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, + base::borrowed_fd&& hdrFence, float hdrSdrRatio, + ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) override; int getContextPriority() override; bool supportsBackgroundBlur() override; @@ -71,6 +77,13 @@ protected: const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) override; + void drawGainmapInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& sdr, + base::borrowed_fd&& sdrFence, + const std::shared_ptr<ExternalTexture>& hdr, + base::borrowed_fd&& hdrFence, float hdrSdrRatio, + ui::Dataspace dataspace, + const std::shared_ptr<ExternalTexture>& gainmap) override; private: void threadMain(CreateInstanceFactory factory); diff --git a/libs/ui/DisplayIdentification.cpp b/libs/ui/DisplayIdentification.cpp index e5af7406ed..8b13d78840 100644 --- a/libs/ui/DisplayIdentification.cpp +++ b/libs/ui/DisplayIdentification.cpp @@ -26,6 +26,7 @@ #include <ftl/hash.h> #include <log/log.h> #include <ui/DisplayIdentification.h> +#include <ui/Size.h> namespace android { namespace { @@ -46,6 +47,10 @@ std::optional<uint8_t> getEdidDescriptorType(const byte_view& view) { return view[3]; } +bool isDetailedTimingDescriptor(const byte_view& view) { + return view[0] != 0 && view[1] != 0; +} + std::string_view parseEdidText(const byte_view& view) { std::string_view text(reinterpret_cast<const char*>(view.data()), view.size()); text = text.substr(0, text.find('\n')); @@ -219,6 +224,8 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { std::string_view displayName; std::string_view serialNumber; std::string_view asciiText; + ui::Size preferredDTDPixelSize; + ui::Size preferredDTDPhysicalSize; constexpr size_t kDescriptorCount = 4; constexpr size_t kDescriptorLength = 18; @@ -243,6 +250,35 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { serialNumber = parseEdidText(descriptor); break; } + } else if (isDetailedTimingDescriptor(view)) { + static constexpr size_t kHorizontalPhysicalLsbOffset = 12; + static constexpr size_t kHorizontalPhysicalMsbOffset = 14; + static constexpr size_t kVerticalPhysicalLsbOffset = 13; + static constexpr size_t kVerticalPhysicalMsbOffset = 14; + const uint32_t hSize = + static_cast<uint32_t>(view[kHorizontalPhysicalLsbOffset] | + ((view[kHorizontalPhysicalMsbOffset] >> 4) << 8)); + const uint32_t vSize = + static_cast<uint32_t>(view[kVerticalPhysicalLsbOffset] | + ((view[kVerticalPhysicalMsbOffset] & 0b1111) << 8)); + + static constexpr size_t kHorizontalPixelLsbOffset = 2; + static constexpr size_t kHorizontalPixelMsbOffset = 4; + static constexpr size_t kVerticalPixelLsbOffset = 5; + static constexpr size_t kVerticalPixelMsbOffset = 7; + + const uint8_t hLsb = view[kHorizontalPixelLsbOffset]; + const uint8_t hMsb = view[kHorizontalPixelMsbOffset]; + const int32_t hPixel = hLsb + ((hMsb & 0xF0) << 4); + + const uint8_t vLsb = view[kVerticalPixelLsbOffset]; + const uint8_t vMsb = view[kVerticalPixelMsbOffset]; + const int32_t vPixel = vLsb + ((vMsb & 0xF0) << 4); + + preferredDTDPixelSize.setWidth(hPixel); + preferredDTDPixelSize.setHeight(vPixel); + preferredDTDPhysicalSize.setWidth(hSize); + preferredDTDPhysicalSize.setHeight(vSize); } view = view.subspan(kDescriptorLength); @@ -297,14 +333,22 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { } } - return Edid{.manufacturerId = manufacturerId, - .productId = productId, - .pnpId = *pnpId, - .modelHash = modelHash, - .displayName = displayName, - .manufactureOrModelYear = manufactureOrModelYear, - .manufactureWeek = manufactureWeek, - .cea861Block = cea861Block}; + DetailedTimingDescriptor preferredDetailedTimingDescriptor{ + .pixelSizeCount = preferredDTDPixelSize, + .physicalSizeInMm = preferredDTDPhysicalSize, + }; + + return Edid{ + .manufacturerId = manufacturerId, + .productId = productId, + .pnpId = *pnpId, + .modelHash = modelHash, + .displayName = displayName, + .manufactureOrModelYear = manufactureOrModelYear, + .manufactureWeek = manufactureWeek, + .cea861Block = cea861Block, + .preferredDetailedTimingDescriptor = preferredDetailedTimingDescriptor, + }; } std::optional<PnpId> getPnpId(uint16_t manufacturerId) { @@ -336,9 +380,12 @@ std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData( } const auto displayId = PhysicalDisplayId::fromEdid(port, edid->manufacturerId, edid->modelHash); - return DisplayIdentificationInfo{.id = displayId, - .name = std::string(edid->displayName), - .deviceProductInfo = buildDeviceProductInfo(*edid)}; + return DisplayIdentificationInfo{ + .id = displayId, + .name = std::string(edid->displayName), + .deviceProductInfo = buildDeviceProductInfo(*edid), + .preferredDetailedTimingDescriptor = edid->preferredDetailedTimingDescriptor, + }; } PhysicalDisplayId getVirtualDisplayId(uint32_t id) { diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index ffb6cdb6ef..b0c6e44b2b 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -388,8 +388,8 @@ status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage, uint64_t inConsumerU } } - const uint64_t usage = static_cast<uint64_t>( - android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage)); + const uint64_t usage = static_cast<uint64_t>(ANDROID_NATIVE_UNSIGNED_CAST( + android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage))); auto result = getBufferMapper().lock(handle, usage, rect, base::unique_fd{fenceFd}); diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp index b6ab2f5a47..7b5a27d9e1 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -208,8 +208,10 @@ status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint32_t usage, status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint64_t producerUsage, uint64_t consumerUsage, const Rect& bounds, void** vaddr, int fenceFd) { - return lockAsync(handle, android_convertGralloc1To0Usage(producerUsage, consumerUsage), bounds, - vaddr, fenceFd); + return lockAsync(handle, + ANDROID_NATIVE_UNSIGNED_CAST( + android_convertGralloc1To0Usage(producerUsage, consumerUsage)), + bounds, vaddr, fenceFd); } status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle, uint32_t usage, diff --git a/libs/ui/include/ui/DisplayIdentification.h b/libs/ui/include/ui/DisplayIdentification.h index 8bc2017b55..648e024d86 100644 --- a/libs/ui/include/ui/DisplayIdentification.h +++ b/libs/ui/include/ui/DisplayIdentification.h @@ -25,6 +25,7 @@ #include <ui/DeviceProductInfo.h> #include <ui/DisplayId.h> +#include <ui/Size.h> #define LEGACY_DISPLAY_TYPE_PRIMARY 0 #define LEGACY_DISPLAY_TYPE_EXTERNAL 1 @@ -33,10 +34,16 @@ namespace android { using DisplayIdentificationData = std::vector<uint8_t>; +struct DetailedTimingDescriptor { + ui::Size pixelSizeCount; + ui::Size physicalSizeInMm; +}; + struct DisplayIdentificationInfo { PhysicalDisplayId id; std::string name; std::optional<DeviceProductInfo> deviceProductInfo; + std::optional<DetailedTimingDescriptor> preferredDetailedTimingDescriptor; }; struct ExtensionBlock { @@ -68,6 +75,7 @@ struct Edid { uint8_t manufactureOrModelYear; uint8_t manufactureWeek; std::optional<Cea861ExtensionBlock> cea861Block; + std::optional<DetailedTimingDescriptor> preferredDetailedTimingDescriptor; }; bool isEdid(const DisplayIdentificationData&); diff --git a/libs/ui/tests/DisplayIdentification_test.cpp b/libs/ui/tests/DisplayIdentification_test.cpp index 721b46688e..76e3f66e1b 100644 --- a/libs/ui/tests/DisplayIdentification_test.cpp +++ b/libs/ui/tests/DisplayIdentification_test.cpp @@ -194,6 +194,10 @@ TEST(DisplayIdentificationTest, parseEdid) { EXPECT_EQ(21, edid->manufactureOrModelYear); EXPECT_EQ(0, edid->manufactureWeek); EXPECT_FALSE(edid->cea861Block); + EXPECT_EQ(1280, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width); + EXPECT_EQ(800, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height); + EXPECT_EQ(261, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width); + EXPECT_EQ(163, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height); edid = parseEdid(getExternalEdid()); ASSERT_TRUE(edid); @@ -206,6 +210,10 @@ TEST(DisplayIdentificationTest, parseEdid) { EXPECT_EQ(22, edid->manufactureOrModelYear); EXPECT_EQ(2, edid->manufactureWeek); EXPECT_FALSE(edid->cea861Block); + EXPECT_EQ(1280, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width); + EXPECT_EQ(800, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height); + EXPECT_EQ(641, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width); + EXPECT_EQ(400, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height); edid = parseEdid(getExternalEedid()); ASSERT_TRUE(edid); @@ -224,6 +232,10 @@ TEST(DisplayIdentificationTest, parseEdid) { EXPECT_EQ(0, physicalAddress.b); EXPECT_EQ(0, physicalAddress.c); EXPECT_EQ(0, physicalAddress.d); + EXPECT_EQ(1366, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width); + EXPECT_EQ(768, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height); + EXPECT_EQ(160, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width); + EXPECT_EQ(90, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height); edid = parseEdid(getPanasonicTvEdid()); ASSERT_TRUE(edid); @@ -242,6 +254,10 @@ TEST(DisplayIdentificationTest, parseEdid) { EXPECT_EQ(0, physicalAddress.b); EXPECT_EQ(0, physicalAddress.c); EXPECT_EQ(0, physicalAddress.d); + EXPECT_EQ(1920, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width); + EXPECT_EQ(1080, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height); + EXPECT_EQ(698, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width); + EXPECT_EQ(392, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height); edid = parseEdid(getHisenseTvEdid()); ASSERT_TRUE(edid); @@ -260,6 +276,10 @@ TEST(DisplayIdentificationTest, parseEdid) { EXPECT_EQ(2, physicalAddress.b); EXPECT_EQ(3, physicalAddress.c); EXPECT_EQ(4, physicalAddress.d); + EXPECT_EQ(1920, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width); + EXPECT_EQ(1080, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height); + EXPECT_EQ(575, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width); + EXPECT_EQ(323, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height); edid = parseEdid(getCtlDisplayEdid()); ASSERT_TRUE(edid); @@ -273,6 +293,10 @@ TEST(DisplayIdentificationTest, parseEdid) { EXPECT_EQ(0xff, edid->manufactureWeek); ASSERT_TRUE(edid->cea861Block); EXPECT_FALSE(edid->cea861Block->hdmiVendorDataBlock); + EXPECT_EQ(1360, edid->preferredDetailedTimingDescriptor->pixelSizeCount.width); + EXPECT_EQ(768, edid->preferredDetailedTimingDescriptor->pixelSizeCount.height); + EXPECT_EQ(521, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.width); + EXPECT_EQ(293, edid->preferredDetailedTimingDescriptor->physicalSizeInMm.height); } TEST(DisplayIdentificationTest, parseInvalidEdid) { diff --git a/opengl/OWNERS b/opengl/OWNERS index 3d60a1dad6..645a578c76 100644 --- a/opengl/OWNERS +++ b/opengl/OWNERS @@ -2,5 +2,4 @@ chrisforbes@google.com cnorthrop@google.com ianelliott@google.com jessehall@google.com -lpy@google.com -vantablack@google.com +tomnom@google.com diff --git a/services/gpuservice/gpuwork/GpuWork.cpp b/services/gpuservice/gpuwork/GpuWork.cpp index 00161e6f4c..7628745537 100644 --- a/services/gpuservice/gpuwork/GpuWork.cpp +++ b/services/gpuservice/gpuwork/GpuWork.cpp @@ -44,7 +44,7 @@ #include "gpuwork/gpuWork.h" -#define ONE_MS_IN_NS (10000000) +#define MSEC_PER_NSEC (1000LU * 1000LU) namespace android { namespace gpuwork { @@ -385,10 +385,11 @@ AStatsManager_PullAtomCallbackReturn GpuWork::pullWorkAtoms(AStatsEventList* dat ALOGI("pullWorkAtoms: after random selection: uids.size() == %zu", uids.size()); auto now = std::chrono::steady_clock::now(); - long long duration = - std::chrono::duration_cast<std::chrono::seconds>(now - mPreviousMapClearTimePoint) - .count(); - if (duration > std::numeric_limits<int32_t>::max() || duration < 0) { + int32_t duration = + static_cast<int32_t>( + std::chrono::duration_cast<std::chrono::seconds>(now - mPreviousMapClearTimePoint) + .count()); + if (duration < 0) { // This is essentially impossible. If it does somehow happen, give up, // but still clear the map. clearMap(); @@ -404,13 +405,14 @@ AStatsManager_PullAtomCallbackReturn GpuWork::pullWorkAtoms(AStatsEventList* dat } const UidTrackingInfo& info = it->second; - uint64_t total_active_duration_ms = info.total_active_duration_ns / ONE_MS_IN_NS; - uint64_t total_inactive_duration_ms = info.total_inactive_duration_ns / ONE_MS_IN_NS; + int32_t total_active_duration_ms = + static_cast<int32_t>(info.total_active_duration_ns / MSEC_PER_NSEC); + int32_t total_inactive_duration_ms = + static_cast<int32_t>(info.total_inactive_duration_ns / MSEC_PER_NSEC); // Skip this atom if any numbers are out of range. |duration| is // already checked above. - if (total_active_duration_ms > std::numeric_limits<int32_t>::max() || - total_inactive_duration_ms > std::numeric_limits<int32_t>::max()) { + if (total_active_duration_ms < 0 || total_inactive_duration_ms < 0) { continue; } @@ -421,11 +423,11 @@ AStatsManager_PullAtomCallbackReturn GpuWork::pullWorkAtoms(AStatsEventList* dat // gpu_id bitcast_int32(gpuId), // time_duration_seconds - static_cast<int32_t>(duration), + duration, // total_active_duration_millis - static_cast<int32_t>(total_active_duration_ms), + total_active_duration_ms, // total_inactive_duration_millis - static_cast<int32_t>(total_inactive_duration_ms)); + total_inactive_duration_ms); } } clearMap(); diff --git a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h index e70da540b9..60cd2c703e 100644 --- a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h +++ b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h @@ -125,7 +125,7 @@ private: static constexpr size_t kNumGpusHardLimit = 32; // The minimum GPU time needed to actually log stats for a UID. - static constexpr uint64_t kMinGpuTimeNanoseconds = 30U * 1000000000U; // 30 seconds. + static constexpr uint64_t kMinGpuTimeNanoseconds = 10LLU * 1000000000LLU; // 10 seconds. // The previous time point at which |mGpuWorkMap| was cleared. std::chrono::steady_clock::time_point mPreviousMapClearTimePoint GUARDED_BY(mMutex); diff --git a/services/gpuservice/vts/TEST_MAPPING b/services/gpuservice/vts/TEST_MAPPING index b33e9624e2..a809be18e1 100644 --- a/services/gpuservice/vts/TEST_MAPPING +++ b/services/gpuservice/vts/TEST_MAPPING @@ -1,7 +1,13 @@ { "presubmit": [ { - "name": "GpuServiceVendorTests" + "name": "GpuServiceVendorTests", + "options": [ + { + // Exclude test methods that require a physical device to run. + "exclude-annotation": "android.platform.test.annotations.RequiresDevice" + } + ] } ] } diff --git a/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java b/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java index 6c16335359..5c12323633 100644 --- a/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java +++ b/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java @@ -19,7 +19,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; -import android.platform.test.annotations.RestrictedBuildTest; +import android.platform.test.annotations.RequiresDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; @@ -63,7 +63,7 @@ public class GpuWorkTracepointTest extends BaseHostJUnit4Test { } @VsrTest(requirements={"VSR-3.3-004"}) - @RestrictedBuildTest + @RequiresDevice @Test public void testGpuWorkPeriodTracepointFormat() throws Exception { CommandResult commandResult = getDevice().executeShellV2Command( diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING index af9d2ebeda..10fec7480d 100644 --- a/services/inputflinger/TEST_MAPPING +++ b/services/inputflinger/TEST_MAPPING @@ -298,9 +298,14 @@ "name": "CtsInputRootTestCases" } ], - "staged-platinum-postsubmit": [ + "platinum-postsubmit": [ { "name": "inputflinger_tests" } + ], + "staged-platinum-postsubmit": [ + { + "name": "libinput_tests" + } ] } diff --git a/services/inputflinger/dispatcher/InputEventTimeline.cpp b/services/inputflinger/dispatcher/InputEventTimeline.cpp index 31ceb8d4d3..688196461a 100644 --- a/services/inputflinger/dispatcher/InputEventTimeline.cpp +++ b/services/inputflinger/dispatcher/InputEventTimeline.cpp @@ -66,12 +66,11 @@ bool ConnectionTimeline::operator!=(const ConnectionTimeline& rhs) const { return !operator==(rhs); } -InputEventTimeline::InputEventTimeline(bool isDown, nsecs_t eventTime, nsecs_t readTime, - uint16_t vendorId, uint16_t productId, +InputEventTimeline::InputEventTimeline(nsecs_t eventTime, nsecs_t readTime, uint16_t vendorId, + uint16_t productId, const std::set<InputDeviceUsageSource>& sources, InputEventActionType inputEventActionType) - : isDown(isDown), - eventTime(eventTime), + : eventTime(eventTime), readTime(readTime), vendorId(vendorId), productId(productId), @@ -91,8 +90,8 @@ bool InputEventTimeline::operator==(const InputEventTimeline& rhs) const { return false; } } - return isDown == rhs.isDown && eventTime == rhs.eventTime && readTime == rhs.readTime && - vendorId == rhs.vendorId && productId == rhs.productId && sources == rhs.sources && + return eventTime == rhs.eventTime && readTime == rhs.readTime && vendorId == rhs.vendorId && + productId == rhs.productId && sources == rhs.sources && inputEventActionType == rhs.inputEventActionType; } diff --git a/services/inputflinger/dispatcher/InputEventTimeline.h b/services/inputflinger/dispatcher/InputEventTimeline.h index 6668399af3..951fcc8d0c 100644 --- a/services/inputflinger/dispatcher/InputEventTimeline.h +++ b/services/inputflinger/dispatcher/InputEventTimeline.h @@ -97,10 +97,9 @@ enum class InputEventActionType : int32_t { }; struct InputEventTimeline { - InputEventTimeline(bool isDown, nsecs_t eventTime, nsecs_t readTime, uint16_t vendorId, - uint16_t productId, const std::set<InputDeviceUsageSource>& sources, + InputEventTimeline(nsecs_t eventTime, nsecs_t readTime, uint16_t vendorId, uint16_t productId, + const std::set<InputDeviceUsageSource>& sources, InputEventActionType inputEventActionType); - const bool isDown; // True if this is an ACTION_DOWN event const nsecs_t eventTime; const nsecs_t readTime; const uint16_t vendorId; diff --git a/services/inputflinger/dispatcher/LatencyAggregator.cpp b/services/inputflinger/dispatcher/LatencyAggregator.cpp index e09d97a13b..4ddd2e9e95 100644 --- a/services/inputflinger/dispatcher/LatencyAggregator.cpp +++ b/services/inputflinger/dispatcher/LatencyAggregator.cpp @@ -134,7 +134,9 @@ void LatencyAggregator::processStatistics(const InputEventTimeline& timeline) { mNumSketchEventsProcessed++; std::array<std::unique_ptr<KllQuantile>, SketchIndex::SIZE>& sketches = - timeline.isDown ? mDownSketches : mMoveSketches; + timeline.inputEventActionType == InputEventActionType::MOTION_ACTION_DOWN + ? mDownSketches + : mMoveSketches; // Process common ones first const nsecs_t eventToRead = timeline.readTime - timeline.eventTime; @@ -242,7 +244,9 @@ void LatencyAggregator::processSlowEvent(const InputEventTimeline& timeline) { const nsecs_t consumeToGpuComplete = gpuCompletedTime - connectionTimeline.consumeTime; const nsecs_t gpuCompleteToPresent = presentTime - gpuCompletedTime; - android::util::stats_write(android::util::SLOW_INPUT_EVENT_REPORTED, timeline.isDown, + android::util::stats_write(android::util::SLOW_INPUT_EVENT_REPORTED, + timeline.inputEventActionType == + InputEventActionType::MOTION_ACTION_DOWN, static_cast<int32_t>(ns2us(eventToRead)), static_cast<int32_t>(ns2us(readToDeliver)), static_cast<int32_t>(ns2us(deliverToConsume)), diff --git a/services/inputflinger/dispatcher/LatencyTracker.cpp b/services/inputflinger/dispatcher/LatencyTracker.cpp index 721d009570..69024b326a 100644 --- a/services/inputflinger/dispatcher/LatencyTracker.cpp +++ b/services/inputflinger/dispatcher/LatencyTracker.cpp @@ -70,7 +70,7 @@ LatencyTracker::LatencyTracker(InputEventTimelineProcessor* processor) void LatencyTracker::trackListener(int32_t inputEventId, nsecs_t eventTime, nsecs_t readTime, DeviceId deviceId, const std::set<InputDeviceUsageSource>& sources, - int inputEventAction, InputEventType inputEventType) { + int32_t inputEventAction, InputEventType inputEventType) { reportAndPruneMatureRecords(eventTime); const auto it = mTimelines.find(inputEventId); if (it != mTimelines.end()) { @@ -105,7 +105,7 @@ void LatencyTracker::trackListener(int32_t inputEventId, nsecs_t eventTime, nsec const InputEventActionType inputEventActionType = [&]() { switch (inputEventType) { case InputEventType::MOTION: { - switch (inputEventAction) { + switch (MotionEvent::getActionMasked(inputEventAction)) { case AMOTION_EVENT_ACTION_DOWN: return InputEventActionType::MOTION_ACTION_DOWN; case AMOTION_EVENT_ACTION_MOVE: @@ -134,10 +134,8 @@ void LatencyTracker::trackListener(int32_t inputEventId, nsecs_t eventTime, nsec } }(); - bool isDown = inputEventType == InputEventType::MOTION && - inputEventAction == AMOTION_EVENT_ACTION_DOWN; mTimelines.emplace(inputEventId, - InputEventTimeline(isDown, eventTime, readTime, identifier->vendor, + InputEventTimeline(eventTime, readTime, identifier->vendor, identifier->product, sources, inputEventActionType)); mEventTimes.emplace(eventTime, inputEventId); } diff --git a/services/inputflinger/dispatcher/LatencyTracker.h b/services/inputflinger/dispatcher/LatencyTracker.h index 532f42290a..b4053ba1b3 100644 --- a/services/inputflinger/dispatcher/LatencyTracker.h +++ b/services/inputflinger/dispatcher/LatencyTracker.h @@ -53,7 +53,7 @@ public: * must drop all duplicate data. */ void trackListener(int32_t inputEventId, nsecs_t eventTime, nsecs_t readTime, DeviceId deviceId, - const std::set<InputDeviceUsageSource>& sources, int inputEventActionType, + const std::set<InputDeviceUsageSource>& sources, int32_t inputEventAction, InputEventType inputEventType); void trackFinishedEvent(int32_t inputEventId, const sp<IBinder>& connectionToken, nsecs_t deliveryTime, nsecs_t consumeTime, nsecs_t finishTime); diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 7bec94eea1..69874c90f3 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -466,6 +466,9 @@ public: virtual void notifyTouchpadHardwareState(const SelfContainedHardwareState& schs, int32_t deviceId) = 0; + /* Sends the Info of gestures that happen on the touchpad. */ + virtual void notifyTouchpadGestureInfo(GestureType type, int32_t deviceId) = 0; + /* Gets the keyboard layout for a particular input device. */ virtual std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( const InputDeviceIdentifier& identifier, diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp index dd46bbc543..c8e7790c86 100644 --- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp +++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp @@ -20,19 +20,14 @@ #include <sstream> #include <android-base/stringprintf.h> -#include <com_android_input_flags.h> #include <input/PrintTools.h> #include <linux/input-event-codes.h> #include <log/log_main.h> -namespace input_flags = com::android::input::flags; - namespace android { namespace { -static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD; - int32_t actionWithIndex(int32_t action, int32_t index) { return action | (index << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); } @@ -48,12 +43,6 @@ size_t firstUnmarkedBit(T set) { return i; } -void addRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis, - RawAbsoluteAxisInfo& evdevAxis) { - deviceInfo.addMotionRange(androidAxis, SOURCE, evdevAxis.minValue, evdevAxis.maxValue, - evdevAxis.flat, evdevAxis.fuzz, evdevAxis.resolution); -} - } // namespace CapturedTouchpadEventConverter::CapturedTouchpadEventConverter( @@ -119,15 +108,8 @@ std::string CapturedTouchpadEventConverter::dump() const { } void CapturedTouchpadEventConverter::populateMotionRanges(InputDeviceInfo& info) const { - if (input_flags::include_relative_axis_values_for_captured_touchpads()) { - tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_X, - AMOTION_EVENT_AXIS_RELATIVE_X, ABS_MT_POSITION_X); - tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_Y, - AMOTION_EVENT_AXIS_RELATIVE_Y, ABS_MT_POSITION_Y); - } else { - tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X); - tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y); - } + tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X); + tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y); tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MAJOR, ABS_MT_TOUCH_MAJOR); tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MINOR, ABS_MT_TOUCH_MINOR); tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOOL_MAJOR, ABS_MT_WIDTH_MAJOR); @@ -153,23 +135,8 @@ void CapturedTouchpadEventConverter::tryAddRawMotionRange(InputDeviceInfo& devic int32_t evdevAxis) const { std::optional<RawAbsoluteAxisInfo> info = mDeviceContext.getAbsoluteAxisInfo(evdevAxis); if (info) { - addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *info); - } -} - -void CapturedTouchpadEventConverter::tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo, - int32_t androidAxis, - int32_t androidRelativeAxis, - int32_t evdevAxis) const { - std::optional<RawAbsoluteAxisInfo> axisInfo = mDeviceContext.getAbsoluteAxisInfo(evdevAxis); - if (axisInfo) { - addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *axisInfo); - - // The largest movement we could possibly report on a relative axis is from the minimum to - // the maximum (or vice versa) of the absolute axis. - float range = axisInfo->maxValue - axisInfo->minValue; - deviceInfo.addMotionRange(androidRelativeAxis, SOURCE, -range, range, axisInfo->flat, - axisInfo->fuzz, axisInfo->resolution); + deviceInfo.addMotionRange(androidAxis, SOURCE, info->minValue, info->maxValue, info->flat, + info->fuzz, info->resolution); } } @@ -196,7 +163,7 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t std::list<NotifyArgs> out; std::vector<PointerCoords> coords; std::vector<PointerProperties> properties; - std::map<size_t /*slotNumber*/, size_t /*coordsIndex*/> coordsIndexForSlotNumber; + std::map<size_t, size_t> coordsIndexForSlotNumber; // For all the touches that were already down, send a MOVE event with their updated coordinates. // A convention of the MotionEvent API is that pointer coordinates in UP events match the @@ -208,19 +175,11 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t // to stay perfectly still between frames, and if it does the worst that can happen is // an extra MOVE event, so it's not worth the overhead of checking for changes. coordsIndexForSlotNumber[slotNumber] = coords.size(); - coords.push_back(makePointerCoordsForSlot(slotNumber)); + coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber))); properties.push_back({.id = pointerId, .toolType = ToolType::FINGER}); } out.push_back( makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, coords, properties)); - if (input_flags::include_relative_axis_values_for_captured_touchpads()) { - // For any further events we send from this sync, the pointers won't have moved relative - // to the positions we just reported in this MOVE event, so zero out the relative axes. - for (PointerCoords& pointer : coords) { - pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0); - pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0); - } - } } std::vector<size_t> upSlots, downSlots; @@ -275,9 +234,6 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t /*flags=*/cancel ? AMOTION_EVENT_FLAG_CANCELED : 0)); freePointerIdForSlot(slotNumber); - if (input_flags::include_relative_axis_values_for_captured_touchpads()) { - mPreviousCoordsForSlotNumber.erase(slotNumber); - } coords.erase(coords.begin() + indexToRemove); properties.erase(properties.begin() + indexToRemove); // Now that we've removed some coords and properties, we might have to update the slot @@ -298,7 +254,7 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t : actionWithIndex(AMOTION_EVENT_ACTION_POINTER_DOWN, coordsIndex); coordsIndexForSlotNumber[slotNumber] = coordsIndex; - coords.push_back(makePointerCoordsForSlot(slotNumber)); + coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber))); properties.push_back( {.id = allocatePointerIdToSlot(slotNumber), .toolType = ToolType::FINGER}); @@ -330,22 +286,12 @@ NotifyMotionArgs CapturedTouchpadEventConverter::makeMotionArgs( AMOTION_EVENT_INVALID_CURSOR_POSITION, mDownTime, /*videoFrames=*/{}); } -PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(size_t slotNumber) { - const MultiTouchMotionAccumulator::Slot& slot = mMotionAccumulator.getSlot(slotNumber); +PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot( + const MultiTouchMotionAccumulator::Slot& slot) const { PointerCoords coords; coords.clear(); coords.setAxisValue(AMOTION_EVENT_AXIS_X, slot.getX()); coords.setAxisValue(AMOTION_EVENT_AXIS_Y, slot.getY()); - if (input_flags::include_relative_axis_values_for_captured_touchpads()) { - if (auto it = mPreviousCoordsForSlotNumber.find(slotNumber); - it != mPreviousCoordsForSlotNumber.end()) { - auto [oldX, oldY] = it->second; - coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, slot.getX() - oldX); - coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, slot.getY() - oldY); - } - mPreviousCoordsForSlotNumber[slotNumber] = std::make_pair(slot.getX(), slot.getY()); - } - coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, slot.getTouchMajor()); coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, slot.getTouchMinor()); coords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, slot.getToolMajor()); diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h index d6c0708f4a..9b6df7a222 100644 --- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h +++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h @@ -21,7 +21,6 @@ #include <map> #include <set> #include <string> -#include <utility> #include <vector> #include <android/input.h> @@ -50,14 +49,12 @@ public: private: void tryAddRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis, int32_t evdevAxis) const; - void tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo, int32_t androidAxis, - int32_t androidRelativeAxis, int32_t evdevAxis) const; [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime); [[nodiscard]] NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action, const std::vector<PointerCoords>& coords, const std::vector<PointerProperties>& properties, int32_t actionButton = 0, int32_t flags = 0); - PointerCoords makePointerCoordsForSlot(size_t slotNumber); + PointerCoords makePointerCoordsForSlot(const MultiTouchMotionAccumulator::Slot& slot) const; int32_t allocatePointerIdToSlot(size_t slotNumber); void freePointerIdForSlot(size_t slotNumber); @@ -79,7 +76,8 @@ private: std::bitset<MAX_POINTER_ID + 1> mPointerIdsInUse; std::map<size_t, int32_t> mPointerIdForSlotNumber; - std::map<size_t, std::pair<float, float>> mPreviousCoordsForSlotNumber; + + static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD; }; } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp index dbc28721d1..9a36bfbeaf 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp @@ -425,7 +425,7 @@ std::list<NotifyArgs> TouchpadInputMapper::process(const RawEvent& rawEvent) { std::optional<SelfContainedHardwareState> state = mStateConverter.processRawEvent(rawEvent); if (state) { if (mTouchpadHardwareStateNotificationsEnabled) { - getPolicy()->notifyTouchpadHardwareState(*state, rawEvent.deviceId); + getPolicy()->notifyTouchpadHardwareState(*state, getDeviceId()); } updatePalmDetectionMetrics(); return sendHardwareState(rawEvent.when, rawEvent.readTime, *state); @@ -480,6 +480,9 @@ void TouchpadInputMapper::consumeGesture(const Gesture* gesture) { return; } mGesturesToProcess.push_back(*gesture); + if (mTouchpadHardwareStateNotificationsEnabled) { + getPolicy()->notifyTouchpadGestureInfo(gesture->type, getDeviceId()); + } } std::list<NotifyArgs> TouchpadInputMapper::processGestures(nsecs_t when, nsecs_t readTime) { diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp index 9924d0d491..da2c683d95 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp @@ -60,6 +60,21 @@ uint32_t gesturesButtonToMotionEventButton(uint32_t gesturesButton) { } } +bool isGestureNoFocusChange(MotionClassification classification) { + switch (classification) { + case MotionClassification::TWO_FINGER_SWIPE: + case MotionClassification::MULTI_FINGER_SWIPE: + case MotionClassification::PINCH: + // Most gestures can be performed on an unfocused window, so they should not + // not affect window focus. + return true; + case MotionClassification::NONE: + case MotionClassification::AMBIGUOUS_GESTURE: + case MotionClassification::DEEP_PRESS: + return false; + } +} + } // namespace GestureConverter::GestureConverter(InputReaderContext& readerContext, @@ -67,6 +82,7 @@ GestureConverter::GestureConverter(InputReaderContext& readerContext, : mDeviceId(deviceId), mReaderContext(readerContext), mEnableFlingStop(input_flags::enable_touchpad_fling_stop()), + mEnableNoFocusChange(input_flags::enable_touchpad_no_focus_change()), // We can safely assume that ABS_MT_POSITION_X and _Y axes will be available, as EventHub // won't classify a device as a touchpad if they're not present. mXAxisInfo(deviceContext.getAbsoluteAxisInfo(ABS_MT_POSITION_X).value()), @@ -338,7 +354,6 @@ std::list<NotifyArgs> GestureConverter::handleScroll(nsecs_t when, nsecs_t readT NotifyMotionArgs args = makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN, /* actionButton= */ 0, mButtonState, /* pointerCount= */ 1, mFakeFingerCoords.data()); - args.flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE; out.push_back(args); } float deltaX = gesture.details.scroll.dx; @@ -353,7 +368,6 @@ std::list<NotifyArgs> GestureConverter::handleScroll(nsecs_t when, nsecs_t readT NotifyMotionArgs args = makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, /* actionButton= */ 0, mButtonState, /* pointerCount= */ 1, mFakeFingerCoords.data()); - args.flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE; out.push_back(args); return out; } @@ -427,7 +441,6 @@ std::list<NotifyArgs> GestureConverter::endScroll(nsecs_t when, nsecs_t readTime NotifyMotionArgs args = makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, /* actionButton= */ 0, mButtonState, /* pointerCount= */ 1, mFakeFingerCoords.data()); - args.flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE; out.push_back(args); mCurrentClassification = MotionClassification::NONE; out += enterHover(when, readTime); @@ -624,6 +637,18 @@ NotifyMotionArgs GestureConverter::makeMotionArgs(nsecs_t when, nsecs_t readTime int32_t actionButton, int32_t buttonState, uint32_t pointerCount, const PointerCoords* pointerCoords) { + int32_t flags = 0; + if (action == AMOTION_EVENT_ACTION_CANCEL) { + flags |= AMOTION_EVENT_FLAG_CANCELED; + } + if (mEnableNoFocusChange && isGestureNoFocusChange(mCurrentClassification)) { + flags |= AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE; + } + if (mCurrentClassification == MotionClassification::TWO_FINGER_SWIPE) { + // This helps to make GestureDetector responsive. + flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE; + } + return {mReaderContext.getNextId(), when, readTime, @@ -633,7 +658,7 @@ NotifyMotionArgs GestureConverter::makeMotionArgs(nsecs_t when, nsecs_t readTime /* policyFlags= */ POLICY_FLAG_WAKE, action, /* actionButton= */ actionButton, - /* flags= */ action == AMOTION_EVENT_ACTION_CANCEL ? AMOTION_EVENT_FLAG_CANCELED : 0, + flags, mReaderContext.getGlobalMetaState(), buttonState, mCurrentClassification, diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h index 829fb9289b..c9a35c151f 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h @@ -99,6 +99,7 @@ private: const int32_t mDeviceId; InputReaderContext& mReaderContext; const bool mEnableFlingStop; + const bool mEnableNoFocusChange; std::optional<ui::LogicalDisplayId> mDisplayId; FloatRect mBoundsInLogicalDisplay{}; diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 95283ba6ab..744cf4a514 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -123,4 +123,5 @@ cc_test { "device-tests", "device-platinum-tests", ], + native_coverage: false, } diff --git a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp index d39ad3fd1e..f20c43c523 100644 --- a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp +++ b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp @@ -20,7 +20,6 @@ #include <memory> #include <EventHub.h> -#include <com_android_input_flags.h> #include <gtest/gtest.h> #include <linux/input-event-codes.h> #include <linux/input.h> @@ -33,8 +32,6 @@ #include "TestEventMatchers.h" #include "TestInputListener.h" -namespace input_flags = com::android::input::flags; - namespace android { using testing::AllOf; @@ -50,8 +47,6 @@ public: mReader(mFakeEventHub, mFakePolicy, mFakeListener), mDevice(newDevice()), mDeviceContext(*mDevice, EVENTHUB_ID) { - input_flags::include_relative_axis_values_for_captured_touchpads(true); - const size_t slotCount = 8; mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_SLOT, 0, slotCount - 1, 0, 0, 0); mAccumulator.configure(mDeviceContext, slotCount, /*usingSlotsProtocol=*/true); @@ -131,7 +126,7 @@ protected: TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populatedCorrectly) { mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, 0, 4000, 0, 0, 45); - mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, -500, 2000, 0, 0, 40); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, 0, 2500, 0, 0, 40); mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MAJOR, 0, 1100, 0, 0, 35); mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, 0, 1000, 0, 0, 30); mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, 0, 900, 0, 0, 25); @@ -155,8 +150,8 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populated const InputDeviceInfo::MotionRange* posY = info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD); ASSERT_NE(nullptr, posY); - EXPECT_NEAR(-500, posY->min, EPSILON); - EXPECT_NEAR(2000, posY->max, EPSILON); + EXPECT_NEAR(0, posY->min, EPSILON); + EXPECT_NEAR(2500, posY->max, EPSILON); EXPECT_NEAR(40, posY->resolution, EPSILON); const InputDeviceInfo::MotionRange* touchMajor = @@ -187,22 +182,8 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populated EXPECT_NEAR(800, toolMinor->max, EPSILON); EXPECT_NEAR(20, toolMinor->resolution, EPSILON); - // ...except for the relative motion axes, derived from the corresponding absolute ones: - const InputDeviceInfo::MotionRange* relX = - info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD); - ASSERT_NE(nullptr, relX); - EXPECT_NEAR(-4000, relX->min, EPSILON); - EXPECT_NEAR(4000, relX->max, EPSILON); - EXPECT_NEAR(45, relX->resolution, EPSILON); - - const InputDeviceInfo::MotionRange* relY = - info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD); - ASSERT_NE(nullptr, relY); - EXPECT_NEAR(-2500, relY->min, EPSILON); - EXPECT_NEAR(2500, relY->max, EPSILON); - EXPECT_NEAR(40, relY->resolution, EPSILON); - - // ...orientation and pressure, which get scaled: + // ...except orientation and pressure, which get scaled, and size, which is generated from other + // values. const InputDeviceInfo::MotionRange* orientation = info.getMotionRange(AMOTION_EVENT_AXIS_ORIENTATION, AINPUT_SOURCE_TOUCHPAD); ASSERT_NE(nullptr, orientation); @@ -217,7 +198,6 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populated EXPECT_NEAR(1, pressure->max, EPSILON); EXPECT_NEAR(0, pressure->resolution, EPSILON); - // ... and size, which is generated from other values. const InputDeviceInfo::MotionRange* size = info.getMotionRange(AMOTION_EVENT_AXIS_SIZE, AINPUT_SOURCE_TOUCHPAD); ASSERT_NE(nullptr, size); @@ -239,9 +219,7 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_bareMinimumAxesPresent_p // present, since it's generated from axes that aren't provided by this device). EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHPAD)); EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD)); - EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD)); - EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD)); - EXPECT_EQ(4u, info.getMotionRanges().size()); + EXPECT_EQ(2u, info.getMotionRanges().size()); } TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) { @@ -257,16 +235,14 @@ TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) { EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), - WithCoords(50, 100), WithRelativeMotion(0, 0), - WithToolType(ToolType::FINGER))); + WithCoords(50, 100), WithToolType(ToolType::FINGER))); processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52); processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 99); EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), - WithCoords(52, 99), WithRelativeMotion(2, -1), - WithToolType(ToolType::FINGER))); + WithCoords(52, 99), WithToolType(ToolType::FINGER))); processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); processAxis(conv, EV_KEY, BTN_TOUCH, 0); @@ -279,9 +255,8 @@ TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) { VariantWith<NotifyMotionArgs>( WithMotionAction(AMOTION_EVENT_ACTION_UP)))); EXPECT_THAT(args, - Each(VariantWith<NotifyMotionArgs>( - AllOf(WithCoords(52, 99), WithRelativeMotion(0, 0), WithPointerCount(1u), - WithToolType(ToolType::FINGER))))); + Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(52, 99), WithPointerCount(1u), + WithToolType(ToolType::FINGER))))); } TEST_F(CapturedTouchpadEventConverterTest, OneFinger_touchDimensionsPassedThrough) { @@ -532,13 +507,13 @@ TEST_F(CapturedTouchpadEventConverterTest, PalmTurningIntoFinger_reported) { EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), - WithCoords(51, 100), WithRelativeMotion(0, 0))); + WithCoords(51, 100))); processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52); EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), - WithCoords(52, 100), WithRelativeMotion(1, 0))); + WithCoords(52, 100))); } TEST_F(CapturedTouchpadEventConverterTest, FingerArrivingAfterPalm_onlyFingerReported) { @@ -578,7 +553,7 @@ TEST_F(CapturedTouchpadEventConverterTest, FingerArrivingAfterPalm_onlyFingerRep EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), - WithCoords(98, 148), WithRelativeMotion(-2, -2))); + WithCoords(98, 148))); } TEST_F(CapturedTouchpadEventConverterTest, FingerAndFingerTurningIntoPalm_partiallyCancelled) { @@ -685,8 +660,7 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), - WithCoords(50, 100), WithRelativeMotion(0, 0), - WithToolType(ToolType::FINGER))); + WithCoords(50, 100), WithToolType(ToolType::FINGER))); processAxis(conv, EV_ABS, ABS_MT_SLOT, 0); processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52); @@ -704,16 +678,13 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), WithCoords(52, 99), - WithRelativeMotion(2, -1), WithToolType(ToolType::FINGER))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction( AMOTION_EVENT_ACTION_POINTER_DOWN | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithPointerCount(2u), WithPointerCoords(0, 52, 99), - WithPointerRelativeMotion(0, 0, 0), WithPointerCoords(1, 250, 200), - WithPointerRelativeMotion(1, 0, 0), WithPointerToolType(0, ToolType::FINGER), WithPointerToolType(1, ToolType::FINGER))))); @@ -729,17 +700,14 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { std::list<NotifyArgs> args = processSync(conv); EXPECT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithPointerRelativeMotion(1, 5, 2))), - VariantWith<NotifyMotionArgs>( - AllOf(WithMotionAction( - AMOTION_EVENT_ACTION_POINTER_UP | - 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithPointerRelativeMotion(1, 0, 0))))); + WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), + VariantWith<NotifyMotionArgs>(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT)))); EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>( AllOf(WithPointerCount(2u), WithPointerCoords(0, 52, 99), - WithPointerRelativeMotion(0, 0, 0), WithPointerCoords(1, 255, 202), + WithPointerCoords(1, 255, 202), WithPointerToolType(1, ToolType::FINGER), WithPointerToolType(0, ToolType::FINGER))))); @@ -755,69 +723,9 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { WithMotionAction(AMOTION_EVENT_ACTION_UP)))); EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(AllOf(WithPointerCount(1u), WithCoords(255, 202), - WithPointerRelativeMotion(1, 0, 0), WithToolType(ToolType::FINGER))))); } -TEST_F(CapturedTouchpadEventConverterTest, RelativeMotionAxesClearedForNewFingerInSlot) { - CapturedTouchpadEventConverter conv = createConverter(); - // Put down one finger. - processAxis(conv, EV_ABS, ABS_MT_SLOT, 0); - processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1); - processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50); - processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100); - - processAxis(conv, EV_KEY, BTN_TOUCH, 1); - processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); - - EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), - WithCoords(50, 100), WithRelativeMotion(0, 0))); - - // Move it in negative X and Y directions. - processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 47); - processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 97); - - EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(47, 97), - WithRelativeMotion(-3, -3))); - - // Lift it. - processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); - processAxis(conv, EV_KEY, BTN_TOUCH, 0); - processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0); - - std::list<NotifyArgs> args = processSync(conv); - EXPECT_THAT(args, - ElementsAre(VariantWith<NotifyMotionArgs>( - WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), - VariantWith<NotifyMotionArgs>( - WithMotionAction(AMOTION_EVENT_ACTION_UP)))); - EXPECT_THAT(args, - Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(47, 97), - WithRelativeMotion(0, 0), - WithPointerCount(1u))))); - - // Put down another finger using the same slot. Relative axis values should be cleared. - processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 2); - processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 60); - processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 60); - - processAxis(conv, EV_KEY, BTN_TOUCH, 1); - processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); - - EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), - WithCoords(60, 60), WithRelativeMotion(0, 0))); - - processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 64); - processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 58); - - EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), - WithCoords(64, 58), WithRelativeMotion(4, -2))); -} - // Pointer IDs max out at 31, and so must be reused once a touch is lifted to avoid running out. TEST_F(CapturedTouchpadEventConverterTest, PointerIdsReusedAfterLift) { CapturedTouchpadEventConverter conv = createConverter(); diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp index e1f844c571..f373cac085 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp +++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp @@ -256,6 +256,10 @@ void FakeInputReaderPolicy::notifyTouchpadHardwareState(const SelfContainedHardw mTouchpadHardwareStateNotified.notify_all(); } +void FakeInputReaderPolicy::notifyTouchpadGestureInfo(GestureType type, int32_t deviceId) { + std::scoped_lock lock(mLock); +} + std::shared_ptr<KeyCharacterMap> FakeInputReaderPolicy::getKeyboardLayoutOverlay( const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) { return nullptr; diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h index 61bb9fcb25..3a2b4e9ed9 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.h +++ b/services/inputflinger/tests/FakeInputReaderPolicy.h @@ -85,6 +85,7 @@ private: void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override; void notifyTouchpadHardwareState(const SelfContainedHardwareState& schs, int32_t deviceId) override; + void notifyTouchpadGestureInfo(GestureType type, int32_t deviceId) override; std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) override; std::string getDeviceAlias(const InputDeviceIdentifier&) override; diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp index d0cd677ade..225ae0f67c 100644 --- a/services/inputflinger/tests/GestureConverter_test.cpp +++ b/services/inputflinger/tests/GestureConverter_test.cpp @@ -279,6 +279,8 @@ TEST_F(GestureConverterTest, DragWithButton) { } TEST_F(GestureConverterTest, Scroll) { + input_flags::enable_touchpad_no_focus_change(true); + const nsecs_t downTime = 12345; InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); @@ -300,7 +302,8 @@ TEST_F(GestureConverterTest, Scroll) { ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>( AllOf(WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE | + AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE), WithToolType(ToolType::FINGER), WithDisplayId(ui::LogicalDisplayId::DEFAULT))))); @@ -312,7 +315,8 @@ TEST_F(GestureConverterTest, Scroll) { WithGestureScrollDistance(0, 5, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), WithToolType(ToolType::FINGER), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE | + AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE), WithDisplayId(ui::LogicalDisplayId::DEFAULT))))); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, @@ -325,7 +329,8 @@ TEST_F(GestureConverterTest, Scroll) { WithGestureScrollDistance(0, 0, EPSILON), WithMotionClassification( MotionClassification::TWO_FINGER_SWIPE), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE | + AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), WithCoords(0, 0), @@ -845,6 +850,8 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { } TEST_F(GestureConverterTest, Pinch_Inwards) { + input_flags::enable_touchpad_no_focus_change(true); + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setDisplayId(ui::LogicalDisplayId::DEFAULT); @@ -867,7 +874,8 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { AllOf(WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithToolType(ToolType::FINGER), - WithDisplayId(ui::LogicalDisplayId::DEFAULT))))); + WithDisplayId(ui::LogicalDisplayId::DEFAULT), + WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))))); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 0.8, GESTURES_ZOOM_UPDATE); @@ -879,7 +887,8 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { WithGesturePinchScaleFactor(0.8f, EPSILON), WithPointerCoords(0, -80, 0), WithPointerCoords(1, 80, 0), WithPointerCount(2u), WithToolType(ToolType::FINGER), - WithDisplayId(ui::LogicalDisplayId::DEFAULT))))); + WithDisplayId(ui::LogicalDisplayId::DEFAULT), + WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))))); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_END); @@ -891,12 +900,14 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), - WithPointerCount(2u))), + WithPointerCount(2u), + WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), - WithPointerCount(1u))), + WithPointerCount(1u), + WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), WithCoords(0, 0), @@ -908,6 +919,8 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { } TEST_F(GestureConverterTest, Pinch_Outwards) { + input_flags::enable_touchpad_no_focus_change(true); + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setDisplayId(ui::LogicalDisplayId::DEFAULT); @@ -930,7 +943,8 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { AllOf(WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithToolType(ToolType::FINGER), - WithDisplayId(ui::LogicalDisplayId::DEFAULT))))); + WithDisplayId(ui::LogicalDisplayId::DEFAULT), + WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))))); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1.1, GESTURES_ZOOM_UPDATE); @@ -942,7 +956,8 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { WithGesturePinchScaleFactor(1.1f, EPSILON), WithPointerCoords(0, -110, 0), WithPointerCoords(1, 110, 0), WithPointerCount(2u), WithToolType(ToolType::FINGER), - WithDisplayId(ui::LogicalDisplayId::DEFAULT))))); + WithDisplayId(ui::LogicalDisplayId::DEFAULT), + WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))))); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_END); @@ -954,12 +969,14 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), - WithPointerCount(2u))), + WithPointerCount(2u), + WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), - WithPointerCount(1u))), + WithPointerCount(1u), + WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), WithCoords(0, 0), @@ -1055,6 +1072,8 @@ TEST_F(GestureConverterTest, ResetWithButtonPressed) { } TEST_F(GestureConverterTest, ResetDuringScroll) { + input_flags::enable_touchpad_no_focus_change(true); + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setDisplayId(ui::LogicalDisplayId::DEFAULT); @@ -1070,7 +1089,8 @@ TEST_F(GestureConverterTest, ResetDuringScroll) { WithGestureScrollDistance(0, 0, EPSILON), WithMotionClassification( MotionClassification::TWO_FINGER_SWIPE), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))), + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE | + AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), WithCoords(0, 0), diff --git a/services/inputflinger/tests/InputTracingTest.cpp b/services/inputflinger/tests/InputTracingTest.cpp index 2ccd93ec4c..3cc4bdd79e 100644 --- a/services/inputflinger/tests/InputTracingTest.cpp +++ b/services/inputflinger/tests/InputTracingTest.cpp @@ -133,8 +133,8 @@ protected: mDispatcher->setFocusedWindow(request); } - void tapAndExpect(const std::vector<const sp<FakeWindowHandle>>& windows, - Level inboundTraceLevel, Level dispatchTraceLevel, InputTraceSession& s) { + void tapAndExpect(const std::vector<sp<FakeWindowHandle>>& windows, Level inboundTraceLevel, + Level dispatchTraceLevel, InputTraceSession& s) { const auto down = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(110)) .build(); @@ -156,7 +156,7 @@ protected: } } - void keypressAndExpect(const std::vector<const sp<FakeWindowHandle>>& windows, + void keypressAndExpect(const std::vector<sp<FakeWindowHandle>>& windows, Level inboundTraceLevel, Level dispatchTraceLevel, InputTraceSession& s) { const auto down = KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build(); diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp index 56502861cf..0f92833e64 100644 --- a/services/inputflinger/tests/LatencyTracker_test.cpp +++ b/services/inputflinger/tests/LatencyTracker_test.cpp @@ -61,7 +61,6 @@ const std::chrono::duration ANR_TIMEOUT = std::chrono::milliseconds( InputEventTimeline getTestTimeline() { InputEventTimeline t( - /*isDown=*/false, /*eventTime=*/2, /*readTime=*/3, /*vendorId=*/0, @@ -174,7 +173,7 @@ TEST_F(LatencyTrackerTest, TrackListener_DoesNotTriggerReporting) { AMOTION_EVENT_ACTION_CANCEL, InputEventType::MOTION); triggerEventReporting(/*eventTime=*/2); assertReceivedTimeline( - InputEventTimeline{/*isDown=*/false, /*eventTime=*/2, + InputEventTimeline{/*eventTime=*/2, /*readTime=*/3, /*vendorId=*/0, /*productID=*/0, /*sources=*/{InputDeviceUsageSource::UNKNOWN}, /*inputEventActionType=*/InputEventActionType::UNKNOWN_INPUT_EVENT}); @@ -226,7 +225,6 @@ TEST_F(LatencyTrackerTest, TrackAllParameters_ReportsFullTimeline) { TEST_F(LatencyTrackerTest, WhenDuplicateEventsAreReported_DoesNotCrash) { constexpr nsecs_t inputEventId = 1; constexpr nsecs_t readTime = 3; // does not matter for this test - constexpr bool isDown = false; // does not matter for this test // In the following 2 calls to trackListener, the inputEventId's are the same, but event times // are different. @@ -246,7 +244,6 @@ TEST_F(LatencyTrackerTest, WhenDuplicateEventsAreReported_DoesNotCrash) { TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) { constexpr int32_t inputEventId1 = 1; InputEventTimeline timeline1( - /*isDown*/ false, /*eventTime*/ 2, /*readTime*/ 3, /*vendorId=*/0, @@ -264,7 +261,6 @@ TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) { constexpr int32_t inputEventId2 = 10; InputEventTimeline timeline2( - /*isDown=*/false, /*eventTime=*/20, /*readTime=*/30, /*vendorId=*/0, @@ -317,9 +313,9 @@ TEST_F(LatencyTrackerTest, IncompleteEvents_AreHandledConsistently) { /*deviceId=*/DEVICE_ID, /*sources=*/{InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL, InputEventType::MOTION); - expectedTimelines.push_back(InputEventTimeline{timeline.isDown, timeline.eventTime, - timeline.readTime, timeline.vendorId, - timeline.productId, timeline.sources, + expectedTimelines.push_back(InputEventTimeline{timeline.eventTime, timeline.readTime, + timeline.vendorId, timeline.productId, + timeline.sources, timeline.inputEventActionType}); } // Now, complete the first event that was sent. @@ -350,10 +346,9 @@ TEST_F(LatencyTrackerTest, EventsAreTracked_WhenTrackListenerIsCalledFirst) { {InputDeviceUsageSource::UNKNOWN}, AMOTION_EVENT_ACTION_CANCEL, InputEventType::MOTION); triggerEventReporting(expected.eventTime); - assertReceivedTimeline(InputEventTimeline{expected.isDown, expected.eventTime, - expected.readTime, expected.vendorId, - expected.productId, expected.sources, - expected.inputEventActionType}); + assertReceivedTimeline(InputEventTimeline{expected.eventTime, expected.readTime, + expected.vendorId, expected.productId, + expected.sources, expected.inputEventActionType}); } /** @@ -364,7 +359,7 @@ TEST_F(LatencyTrackerTest, EventsAreTracked_WhenTrackListenerIsCalledFirst) { TEST_F(LatencyTrackerTest, TrackListenerCheck_DeviceInfoFieldsInputEventTimeline) { constexpr int32_t inputEventId = 1; InputEventTimeline timeline( - /*isDown*/ false, /*eventTime*/ 2, /*readTime*/ 3, + /*eventTime*/ 2, /*readTime*/ 3, /*vendorId=*/50, /*productId=*/60, /*sources=*/ {InputDeviceUsageSource::TOUCHSCREEN, InputDeviceUsageSource::STYLUS_DIRECT}, @@ -390,37 +385,37 @@ TEST_F(LatencyTrackerTest, TrackListenerCheck_InputEventActionTypeFieldInputEven constexpr int32_t inputEventId = 1; // Create timelines for different event types (Motion, Key) InputEventTimeline motionDownTimeline( - /*isDown*/ true, /*eventTime*/ 2, /*readTime*/ 3, + /*eventTime*/ 2, /*readTime*/ 3, /*vendorId*/ 0, /*productId*/ 0, /*sources*/ {InputDeviceUsageSource::UNKNOWN}, /*inputEventActionType*/ InputEventActionType::MOTION_ACTION_DOWN); InputEventTimeline motionMoveTimeline( - /*isDown*/ false, /*eventTime*/ 4, /*readTime*/ 5, + /*eventTime*/ 4, /*readTime*/ 5, /*vendorId*/ 0, /*productId*/ 0, /*sources*/ {InputDeviceUsageSource::UNKNOWN}, /*inputEventActionType*/ InputEventActionType::MOTION_ACTION_MOVE); InputEventTimeline motionUpTimeline( - /*isDown*/ false, /*eventTime*/ 6, /*readTime*/ 7, + /*eventTime*/ 6, /*readTime*/ 7, /*vendorId*/ 0, /*productId*/ 0, /*sources*/ {InputDeviceUsageSource::UNKNOWN}, /*inputEventActionType*/ InputEventActionType::MOTION_ACTION_UP); InputEventTimeline keyDownTimeline( - /*isDown*/ false, /*eventTime*/ 8, /*readTime*/ 9, + /*eventTime*/ 8, /*readTime*/ 9, /*vendorId*/ 0, /*productId*/ 0, /*sources*/ {InputDeviceUsageSource::UNKNOWN}, /*inputEventActionType*/ InputEventActionType::KEY); InputEventTimeline keyUpTimeline( - /*isDown*/ false, /*eventTime*/ 10, /*readTime*/ 11, + /*eventTime*/ 10, /*readTime*/ 11, /*vendorId*/ 0, /*productId*/ 0, /*sources*/ {InputDeviceUsageSource::UNKNOWN}, /*inputEventActionType*/ InputEventActionType::KEY); InputEventTimeline unknownTimeline( - /*isDown*/ false, /*eventTime*/ 12, /*readTime*/ 13, + /*eventTime*/ 12, /*readTime*/ 13, /*vendorId*/ 0, /*productId*/ 0, /*sources*/ {InputDeviceUsageSource::UNKNOWN}, /*inputEventActionType*/ InputEventActionType::UNKNOWN_INPUT_EVENT); diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h index f3be04115a..cfedc6eb1a 100644 --- a/services/inputflinger/tests/TestEventMatchers.h +++ b/services/inputflinger/tests/TestEventMatchers.h @@ -654,15 +654,6 @@ MATCHER_P2(WithRelativeMotion, x, y, "InputEvent with specified relative motion" return argX == x && argY == y; } -MATCHER_P3(WithPointerRelativeMotion, pointer, x, y, - "InputEvent with specified relative motion for pointer") { - const auto argX = arg.pointerCoords[pointer].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); - const auto argY = arg.pointerCoords[pointer].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); - *result_listener << "expected pointer " << pointer << " to have relative motion (" << x << ", " - << y << "), but got (" << argX << ", " << argY << ")"; - return argX == x && argY == y; -} - MATCHER_P3(WithGestureOffset, dx, dy, epsilon, "InputEvent with specified touchpad gesture offset") { const auto argGestureX = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET); diff --git a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp index 80c2213482..695eb3c5dd 100644 --- a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp @@ -71,7 +71,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { const DeviceId deviceId = fdp.ConsumeIntegral<int32_t>(); std::set<InputDeviceUsageSource> sources = { fdp.ConsumeEnum<InputDeviceUsageSource>()}; - int32_t inputEventActionType = fdp.ConsumeIntegral<int32_t>(); + const int32_t inputEventActionType = fdp.ConsumeIntegral<int32_t>(); const InputEventType inputEventType = fdp.ConsumeEnum<InputEventType>(); tracker.trackListener(inputEventId, eventTime, readTime, deviceId, sources, inputEventActionType, inputEventType); diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index ddc3310448..7e362f4e35 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -283,6 +283,7 @@ public: void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override {} void notifyTouchpadHardwareState(const SelfContainedHardwareState& schs, int32_t deviceId) override {} + void notifyTouchpadGestureInfo(GestureType type, int32_t deviceId) override {} std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( const InputDeviceIdentifier& identifier, const std::optional<KeyboardLayoutInfo> layoutInfo) override { diff --git a/services/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h index dc9e8215e7..a8a773ad6b 100644 --- a/services/sensorservice/SensorRegistrationInfo.h +++ b/services/sensorservice/SensorRegistrationInfo.h @@ -38,10 +38,11 @@ public: mActivated = false; } - SensorRegistrationInfo(int32_t handle, const String8 &packageName, - int64_t samplingRateNs, int64_t maxReportLatencyNs, bool activate) { + SensorRegistrationInfo(int32_t handle, const String8& packageName, int64_t samplingRateNs, + int64_t maxReportLatencyNs, bool activate, status_t registerStatus) { mSensorHandle = handle; mPackageName = packageName; + mRegisteredStatus = registerStatus; mSamplingRateUs = static_cast<int64_t>(samplingRateNs/1000); mMaxReportLatencyUs = static_cast<int64_t>(maxReportLatencyNs/1000); @@ -60,28 +61,43 @@ public: return (info.mSensorHandle == INT32_MIN && info.mRealtimeSec == 0); } - // Dumpable interface - virtual std::string dump() const override { + std::string dump(SensorService* sensorService) const { struct tm* timeinfo = localtime(&mRealtimeSec); const int8_t hour = static_cast<int8_t>(timeinfo->tm_hour); const int8_t min = static_cast<int8_t>(timeinfo->tm_min); const int8_t sec = static_cast<int8_t>(timeinfo->tm_sec); std::ostringstream ss; - ss << std::setfill('0') << std::setw(2) << static_cast<int>(hour) << ":" - << std::setw(2) << static_cast<int>(min) << ":" - << std::setw(2) << static_cast<int>(sec) - << (mActivated ? " +" : " -") - << " 0x" << std::hex << std::setw(8) << mSensorHandle << std::dec - << std::setfill(' ') << " pid=" << std::setw(5) << mPid - << " uid=" << std::setw(5) << mUid << " package=" << mPackageName; - if (mActivated) { - ss << " samplingPeriod=" << mSamplingRateUs << "us" - << " batchingPeriod=" << mMaxReportLatencyUs << "us"; - }; + ss << std::setfill('0') << std::setw(2) << static_cast<int>(hour) << ":" << std::setw(2) + << static_cast<int>(min) << ":" << std::setw(2) << static_cast<int>(sec) + << (mActivated ? " +" : " -") << " 0x" << std::hex << std::setw(8) << mSensorHandle; + ss << std::dec << std::setfill(' ') << " pid=" << std::setw(5) << mPid + << " uid=" << std::setw(5) << mUid; + + std::string samplingRate = + mActivated ? std::to_string(mSamplingRateUs) : " N/A "; + std::string batchingInterval = + mActivated ? std::to_string(mMaxReportLatencyUs) : " N/A "; + ss << " samplingPeriod=" << std::setfill(' ') << std::setw(8) + << samplingRate << "us" << " batchingPeriod=" << std::setfill(' ') + << std::setw(8) << batchingInterval << "us" + << " result=" << statusToString(mRegisteredStatus) + << " (sensor, package): (" << std::setfill(' ') << std::left + << std::setw(27); + + if (sensorService != nullptr) { + ss << sensorService->getSensorName(mSensorHandle); + } else { + ss << "null"; + } + ss << ", " << mPackageName << ")"; + return ss.str(); } + // Dumpable interface + virtual std::string dump() const override { return dump(static_cast<SensorService*>(nullptr)); } + /** * Dump debugging information as android.service.SensorRegistrationInfoProto protobuf message * using ProtoOutputStream. @@ -110,6 +126,7 @@ private: int64_t mMaxReportLatencyUs; bool mActivated; time_t mRealtimeSec; + status_t mRegisteredStatus; }; } // namespace android; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 57b473bd37..060508ca25 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -708,7 +708,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { SENSOR_REGISTRATIONS_BUF_SIZE; continue; } - result.appendFormat("%s\n", reg_info.dump().c_str()); + result.appendFormat("%s\n", reg_info.dump(this).c_str()); currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % SENSOR_REGISTRATIONS_BUF_SIZE; } while(startIndex != currentIndex); @@ -2167,17 +2167,17 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, sensor->getSensor().getRequiredAppOp() >= 0) { connection->mHandleToAppOp[handle] = sensor->getSensor().getRequiredAppOp(); } - - mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) = - SensorRegistrationInfo(handle, connection->getPackageName(), - samplingPeriodNs, maxBatchReportLatencyNs, true); - mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE; } if (err != NO_ERROR) { // batch/activate has failed, reset our state. cleanupWithoutDisableLocked(connection, handle); } + + mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) = + SensorRegistrationInfo(handle, connection->getPackageName(), samplingPeriodNs, + maxBatchReportLatencyNs, /*activate=*/ true, err); + mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE; return err; } @@ -2190,13 +2190,10 @@ status_t SensorService::disable(const sp<SensorEventConnection>& connection, int if (err == NO_ERROR) { std::shared_ptr<SensorInterface> sensor = getSensorInterfaceFromHandle(handle); err = sensor != nullptr ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE); - - } - if (err == NO_ERROR) { - mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) = - SensorRegistrationInfo(handle, connection->getPackageName(), 0, 0, false); - mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE; } + mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex) = + SensorRegistrationInfo(handle, connection->getPackageName(), 0, 0, /*activate=*/ false, err); + mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE; return err; } diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index 839fb7d7a3..e910c72e2e 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -51,7 +51,8 @@ public: MOCK_CONST_METHOD0(getMaxVirtualDisplayCount, size_t()); MOCK_CONST_METHOD0(getMaxVirtualDisplayDimension, size_t()); MOCK_METHOD3(allocateVirtualDisplay, bool(HalVirtualDisplayId, ui::Size, ui::PixelFormat*)); - MOCK_METHOD2(allocatePhysicalDisplay, void(hal::HWDisplayId, PhysicalDisplayId)); + MOCK_METHOD3(allocatePhysicalDisplay, + void(hal::HWDisplayId, PhysicalDisplayId, std::optional<ui::Size>)); MOCK_METHOD1(createLayer, std::shared_ptr<HWC2::Layer>(HalDisplayId)); MOCK_METHOD(status_t, getDeviceCompositionChanges, diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index 20ae74ab00..66237b9d8a 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -60,6 +60,7 @@ using AidlDisplayCapability = aidl::android::hardware::graphics::composer3::Disp using AidlHdrCapabilities = aidl::android::hardware::graphics::composer3::HdrCapabilities; using AidlHdrConversionCapability = aidl::android::hardware::graphics::common::HdrConversionCapability; +using AidlHdcpLevels = aidl::android::hardware::drm::HdcpLevels; using AidlHdrConversionStrategy = aidl::android::hardware::graphics::common::HdrConversionStrategy; using AidlOverlayProperties = aidl::android::hardware::graphics::composer3::OverlayProperties; using AidlPerFrameMetadata = aidl::android::hardware::graphics::composer3::PerFrameMetadata; @@ -223,6 +224,12 @@ public: return ::ndk::ScopedAStatus::ok(); } + ::ndk::ScopedAStatus onHdcpLevelsChanged(int64_t in_display, + const AidlHdcpLevels& levels) override { + mCallback.onComposerHalHdcpLevelsChanged(translate<Display>(in_display), levels); + return ::ndk::ScopedAStatus::ok(); + } + private: HWC2::ComposerCallback& mCallback; }; diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 8e78af4a09..f1fa9389eb 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -675,6 +675,11 @@ void Display::loadDisplayCapabilities() { } }); } + +void Display::setPhysicalSizeInMm(std::optional<ui::Size> size) { + mPhysicalSize = size; +} + } // namespace impl // Layer methods diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index c2dc94357a..8e2aeaf234 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -67,6 +67,7 @@ class Layer; namespace hal = android::hardware::graphics::composer::hal; +using aidl::android::hardware::drm::HdcpLevels; using aidl::android::hardware::graphics::common::DisplayHotplugEvent; using aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData; @@ -85,6 +86,7 @@ struct ComposerCallback { virtual void onComposerHalSeamlessPossible(hal::HWDisplayId) = 0; virtual void onComposerHalVsyncIdle(hal::HWDisplayId) = 0; virtual void onRefreshRateChangedDebug(const RefreshRateChangedDebugData&) = 0; + virtual void onComposerHalHdcpLevelsChanged(hal::HWDisplayId, const HdcpLevels& levels) = 0; protected: ~ComposerCallback() = default; @@ -103,6 +105,7 @@ public: virtual bool isVsyncPeriodSwitchSupported() const = 0; virtual bool hasDisplayIdleTimerCapability() const = 0; virtual void onLayerDestroyed(hal::HWLayerId layerId) = 0; + virtual std::optional<ui::Size> getPhysicalSizeInMm() const = 0; [[nodiscard]] virtual hal::Error acceptChanges() = 0; [[nodiscard]] virtual base::expected<std::shared_ptr<HWC2::Layer>, hal::Error> @@ -283,6 +286,8 @@ public: bool hasDisplayIdleTimerCapability() const override; void onLayerDestroyed(hal::HWLayerId layerId) override; hal::Error getPhysicalDisplayOrientation(Hwc2::AidlTransform* outTransform) const override; + void setPhysicalSizeInMm(std::optional<ui::Size> size); + std::optional<ui::Size> getPhysicalSizeInMm() const override { return mPhysicalSize; } private: void loadDisplayCapabilities(); @@ -316,6 +321,8 @@ private: std::optional< std::unordered_set<aidl::android::hardware::graphics::composer3::DisplayCapability>> mDisplayCapabilities GUARDED_BY(mDisplayCapabilitiesMutex); + // Physical size in mm. + std::optional<ui::Size> mPhysicalSize; }; } // namespace impl diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index c83e0da99a..bd093f52cf 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -76,6 +76,7 @@ using aidl::android::hardware::graphics::common::HdrConversionCapability; using aidl::android::hardware::graphics::common::HdrConversionStrategy; using aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::DisplayCapability; +using aidl::android::hardware::graphics::composer3::DisplayConfiguration; using namespace std::string_literals; namespace android { @@ -222,8 +223,8 @@ bool HWComposer::allocateVirtualDisplay(HalVirtualDisplayId displayId, ui::Size return true; } -void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId, - PhysicalDisplayId displayId) { +void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId, PhysicalDisplayId displayId, + std::optional<ui::Size> physicalSize) { mPhysicalDisplayIdMap[hwcDisplayId] = displayId; if (!mPrimaryHwcDisplayId) { @@ -235,6 +236,7 @@ void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId, std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities, hwcDisplayId, hal::DisplayType::PHYSICAL); newDisplay->setConnected(true); + newDisplay->setPhysicalSizeInMm(physicalSize); displayData.hwcDisplay = std::move(newDisplay); } @@ -276,6 +278,47 @@ std::vector<HWComposer::HWCDisplayMode> HWComposer::getModes(PhysicalDisplayId d return getModesFromLegacyDisplayConfigs(hwcDisplayId); } +DisplayConfiguration::Dpi HWComposer::getEstimatedDotsPerInchFromSize( + uint64_t hwcDisplayId, const HWCDisplayMode& hwcMode) const { + if (!FlagManager::getInstance().correct_dpi_with_display_size()) { + return {-1, -1}; + } + if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) { + if (const auto it = mDisplayData.find(displayId.value()); + it != mDisplayData.end() && it->second.hwcDisplay->getPhysicalSizeInMm()) { + ui::Size size = it->second.hwcDisplay->getPhysicalSizeInMm().value(); + if (hwcMode.width > 0 && hwcMode.height > 0 && size.width > 0 && size.height > 0) { + static constexpr float kMmPerInch = 25.4f; + return {hwcMode.width * kMmPerInch / size.width, + hwcMode.height * kMmPerInch / size.height}; + } + } + } + return {-1, -1}; +} + +DisplayConfiguration::Dpi HWComposer::correctedDpiIfneeded( + DisplayConfiguration::Dpi dpi, DisplayConfiguration::Dpi estimatedDpi) const { + // hwc can be unreliable when it comes to dpi. A rough estimated dpi may yield better + // results. For instance, libdrm and bad edid may result in a dpi of {350, 290} for a + // 16:9 3840x2160 display, which would match a 4:3 aspect ratio. + // The logic here checks if hwc was able to provide some dpi, and if so if the dpi + // disparity between the axes is more reasonable than a rough estimate, otherwise use + // the estimated dpi as a corrected value. + if (estimatedDpi.x == -1 || estimatedDpi.x == -1) { + return dpi; + } + if (dpi.x == -1 || dpi.y == -1) { + return estimatedDpi; + } + if (std::min(dpi.x, dpi.y) != 0 && std::min(estimatedDpi.x, estimatedDpi.y) != 0 && + abs(dpi.x - dpi.y) / std::min(dpi.x, dpi.y) > + abs(estimatedDpi.x - estimatedDpi.y) / std::min(estimatedDpi.x, estimatedDpi.y)) { + return estimatedDpi; + } + return dpi; +} + std::vector<HWComposer::HWCDisplayMode> HWComposer::getModesFromDisplayConfigurations( uint64_t hwcDisplayId, int32_t maxFrameIntervalNs) const { std::vector<hal::DisplayConfiguration> configs; @@ -294,9 +337,16 @@ std::vector<HWComposer::HWCDisplayMode> HWComposer::getModesFromDisplayConfigura .configGroup = config.configGroup, .vrrConfig = config.vrrConfig}; + const DisplayConfiguration::Dpi estimatedDPI = + getEstimatedDotsPerInchFromSize(hwcDisplayId, hwcMode); if (config.dpi) { - hwcMode.dpiX = config.dpi->x; - hwcMode.dpiY = config.dpi->y; + const DisplayConfiguration::Dpi dpi = + correctedDpiIfneeded(config.dpi.value(), estimatedDPI); + hwcMode.dpiX = dpi.x; + hwcMode.dpiY = dpi.y; + } else if (estimatedDPI.x != -1 && estimatedDPI.y != -1) { + hwcMode.dpiX = estimatedDPI.x; + hwcMode.dpiY = estimatedDPI.y; } if (!mEnableVrrTimeout) { @@ -328,12 +378,14 @@ std::vector<HWComposer::HWCDisplayMode> HWComposer::getModesFromLegacyDisplayCon const int32_t dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X); const int32_t dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y); - if (dpiX != -1) { - hwcMode.dpiX = static_cast<float>(dpiX) / 1000.f; - } - if (dpiY != -1) { - hwcMode.dpiY = static_cast<float>(dpiY) / 1000.f; - } + const DisplayConfiguration::Dpi hwcDpi = + DisplayConfiguration::Dpi{dpiX == -1 ? dpiY : dpiX / 1000.f, + dpiY == -1 ? dpiY : dpiY / 1000.f}; + const DisplayConfiguration::Dpi estimatedDPI = + getEstimatedDotsPerInchFromSize(hwcDisplayId, hwcMode); + const DisplayConfiguration::Dpi dpi = correctedDpiIfneeded(hwcDpi, estimatedDPI); + hwcMode.dpiX = dpi.x; + hwcMode.dpiY = dpi.y; modes.push_back(hwcMode); } @@ -1072,6 +1124,8 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( getDisplayIdentificationData(hwcDisplayId, &port, &data); if (auto newInfo = parseDisplayIdentificationData(port, data)) { info->deviceProductInfo = std::move(newInfo->deviceProductInfo); + info->preferredDetailedTimingDescriptor = + std::move(newInfo->preferredDetailedTimingDescriptor); } else { ALOGE("Failed to parse identification data for display %" PRIu64, hwcDisplayId); } @@ -1114,7 +1168,11 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( } if (!isConnected(info->id)) { - allocatePhysicalDisplay(hwcDisplayId, info->id); + std::optional<ui::Size> size = std::nullopt; + if (info->preferredDetailedTimingDescriptor) { + size = info->preferredDetailedTimingDescriptor->physicalSizeInMm; + } + allocatePhysicalDisplay(hwcDisplayId, info->id, size); } return info; } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index dec4bfed41..b95c619f75 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -134,7 +134,8 @@ public: // supported by the HWC can be queried in advance, but allocation may fail for other reasons. virtual bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*) = 0; - virtual void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) = 0; + virtual void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId, + std::optional<ui::Size> physicalSize) = 0; // Attempts to create a new layer on this display virtual std::shared_ptr<HWC2::Layer> createLayer(HalDisplayId) = 0; @@ -349,7 +350,8 @@ public: bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*) override; // Called from SurfaceFlinger, when the state for a new physical display needs to be recreated. - void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) override; + void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId, + std::optional<ui::Size> physicalSize) override; // Attempts to create a new layer on this display std::shared_ptr<HWC2::Layer> createLayer(HalDisplayId) override; @@ -532,6 +534,13 @@ private: std::optional<DisplayIdentificationInfo> onHotplugDisconnect(hal::HWDisplayId); bool shouldIgnoreHotplugConnect(hal::HWDisplayId, bool hasDisplayIdentificationData) const; + aidl::android::hardware::graphics::composer3::DisplayConfiguration::Dpi + getEstimatedDotsPerInchFromSize(uint64_t hwcDisplayId, const HWCDisplayMode& hwcMode) const; + + aidl::android::hardware::graphics::composer3::DisplayConfiguration::Dpi correctedDpiIfneeded( + aidl::android::hardware::graphics::composer3::DisplayConfiguration::Dpi dpi, + aidl::android::hardware::graphics::composer3::DisplayConfiguration::Dpi estimatedDpi) + const; std::vector<HWCDisplayMode> getModesFromDisplayConfigurations(uint64_t hwcDisplayId, int32_t maxFrameIntervalNs) const; std::vector<HWCDisplayMode> getModesFromLegacyDisplayConfigs(uint64_t hwcDisplayId) const; diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 3736abc79f..47b811b721 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -38,6 +38,8 @@ using base::StringAppendF; using FrameTimelineEvent = perfetto::protos::pbzero::FrameTimelineEvent; using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource; +namespace { + void dumpTable(std::string& result, TimelineItem predictions, TimelineItem actuals, const std::string& indent, PredictionState predictionState, nsecs_t baseTime) { StringAppendF(&result, "%s", indent.c_str()); @@ -319,6 +321,16 @@ nsecs_t getMinTime(PredictionState predictionState, TimelineItem predictions, return minTime; } +bool shouldTraceForDataSource(const FrameTimelineDataSource::TraceContext& ctx, nsecs_t timestamp) { + if (auto ds = ctx.GetDataSourceLocked(); ds && ds->getStartTime() > timestamp) { + return false; + } + + return true; +} + +} // namespace + int64_t TraceCookieCounter::getCookieForTracing() { return ++mTraceCookie; } @@ -726,15 +738,24 @@ void SurfaceFrame::onCommitNotComposited(Fps refreshRate, Fps displayFrameRender classifyJankLocked(JankType::None, refreshRate, displayFrameRenderRate, nullptr); } -void SurfaceFrame::tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset) const { +void SurfaceFrame::tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset, + bool filterFramesBeforeTraceStarts) const { int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing(); + bool traced = false; // Expected timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { + const auto timestamp = mPredictions.startTime; + if (filterFramesBeforeTraceStarts && !shouldTraceForDataSource(ctx, timestamp)) { + // Do not trace packets started before tracing starts. + return; + } + traced = true; + std::scoped_lock lock(mMutex); auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); - packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime + monoBootOffset)); + packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset)); auto* event = packet->set_frame_timeline_event(); auto* expectedSurfaceFrameStartEvent = event->set_expected_surface_frame_start(); @@ -748,42 +769,54 @@ void SurfaceFrame::tracePredictions(int64_t displayFrameToken, nsecs_t monoBootO expectedSurfaceFrameStartEvent->set_layer_name(mDebugName); }); - // Expected timeline end - FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::scoped_lock lock(mMutex); - auto packet = ctx.NewTracePacket(); - packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); - packet->set_timestamp(static_cast<uint64_t>(mPredictions.endTime + monoBootOffset)); + if (traced) { + // Expected timeline end + FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { + std::scoped_lock lock(mMutex); + auto packet = ctx.NewTracePacket(); + packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); + packet->set_timestamp(static_cast<uint64_t>(mPredictions.endTime + monoBootOffset)); - auto* event = packet->set_frame_timeline_event(); - auto* expectedSurfaceFrameEndEvent = event->set_frame_end(); + auto* event = packet->set_frame_timeline_event(); + auto* expectedSurfaceFrameEndEvent = event->set_frame_end(); - expectedSurfaceFrameEndEvent->set_cookie(expectedTimelineCookie); - }); + expectedSurfaceFrameEndEvent->set_cookie(expectedTimelineCookie); + }); + } } -void SurfaceFrame::traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset) const { +void SurfaceFrame::traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset, + bool filterFramesBeforeTraceStarts) const { int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing(); + bool traced = false; // Actual timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { + const auto timestamp = [&]() { + std::scoped_lock lock(mMutex); + // Actual start time is not yet available, so use expected start instead + if (mPredictionState == PredictionState::Expired) { + // If prediction is expired, we can't use the predicted start time. Instead, just + // use a start time a little earlier than the end time so that we have some info + // about this frame in the trace. + nsecs_t endTime = + (mPresentState == PresentState::Dropped ? mDropTime : mActuals.endTime); + return endTime - kPredictionExpiredStartTimeDelta; + } + + return mActuals.startTime == 0 ? mPredictions.startTime : mActuals.startTime; + }(); + + if (filterFramesBeforeTraceStarts && !shouldTraceForDataSource(ctx, timestamp)) { + // Do not trace packets started before tracing starts. + return; + } + traced = true; + std::scoped_lock lock(mMutex); auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); - // Actual start time is not yet available, so use expected start instead - if (mPredictionState == PredictionState::Expired) { - // If prediction is expired, we can't use the predicted start time. Instead, just use a - // start time a little earlier than the end time so that we have some info about this - // frame in the trace. - nsecs_t endTime = - (mPresentState == PresentState::Dropped ? mDropTime : mActuals.endTime); - const auto timestamp = endTime - kPredictionExpiredStartTimeDelta; - packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset)); - } else { - const auto timestamp = - mActuals.startTime == 0 ? mPredictions.startTime : mActuals.startTime; - packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset)); - } + packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset)); auto* event = packet->set_frame_timeline_event(); auto* actualSurfaceFrameStartEvent = event->set_actual_surface_frame_start(); @@ -812,28 +845,31 @@ void SurfaceFrame::traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffse actualSurfaceFrameStartEvent->set_jank_severity_type(toProto(mJankSeverityType)); }); - // Actual timeline end - FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::scoped_lock lock(mMutex); - auto packet = ctx.NewTracePacket(); - packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); - if (mPresentState == PresentState::Dropped) { - packet->set_timestamp(static_cast<uint64_t>(mDropTime + monoBootOffset)); - } else { - packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime + monoBootOffset)); - } + if (traced) { + // Actual timeline end + FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { + std::scoped_lock lock(mMutex); + auto packet = ctx.NewTracePacket(); + packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); + if (mPresentState == PresentState::Dropped) { + packet->set_timestamp(static_cast<uint64_t>(mDropTime + monoBootOffset)); + } else { + packet->set_timestamp(static_cast<uint64_t>(mActuals.endTime + monoBootOffset)); + } - auto* event = packet->set_frame_timeline_event(); - auto* actualSurfaceFrameEndEvent = event->set_frame_end(); + auto* event = packet->set_frame_timeline_event(); + auto* actualSurfaceFrameEndEvent = event->set_frame_end(); - actualSurfaceFrameEndEvent->set_cookie(actualTimelineCookie); - }); + actualSurfaceFrameEndEvent->set_cookie(actualTimelineCookie); + }); + } } /** * TODO(b/178637512): add inputEventId to the perfetto trace. */ -void SurfaceFrame::trace(int64_t displayFrameToken, nsecs_t monoBootOffset) const { +void SurfaceFrame::trace(int64_t displayFrameToken, nsecs_t monoBootOffset, + bool filterFramesBeforeTraceStarts) const { if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID || displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) { // No packets can be traced with a missing token. @@ -842,9 +878,9 @@ void SurfaceFrame::trace(int64_t displayFrameToken, nsecs_t monoBootOffset) cons if (getPredictionState() != PredictionState::Expired) { // Expired predictions have zeroed timestamps. This cannot be used in any meaningful way in // a trace. - tracePredictions(displayFrameToken, monoBootOffset); + tracePredictions(displayFrameToken, monoBootOffset, filterFramesBeforeTraceStarts); } - traceActuals(displayFrameToken, monoBootOffset); + traceActuals(displayFrameToken, monoBootOffset, filterFramesBeforeTraceStarts); } namespace impl { @@ -870,8 +906,12 @@ std::optional<TimelineItem> TokenManager::getPredictionsForToken(int64_t token) } FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid, - JankClassificationThresholds thresholds, bool useBootTimeClock) + JankClassificationThresholds thresholds, bool useBootTimeClock, + bool filterFramesBeforeTraceStarts) : mUseBootTimeClock(useBootTimeClock), + mFilterFramesBeforeTraceStarts( + FlagManager::getInstance().filter_frames_before_trace_starts() && + filterFramesBeforeTraceStarts), mMaxDisplayFrames(kDefaultMaxDisplayFrames), mTimeStats(std::move(timeStats)), mSurfaceFlingerPid(surfaceFlingerPid), @@ -1154,16 +1194,23 @@ void FrameTimeline::DisplayFrame::onCommitNotComposited() { } } -void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid, - nsecs_t monoBootOffset) const { +void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid, nsecs_t monoBootOffset, + bool filterFramesBeforeTraceStarts) const { int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing(); + bool traced = false; // Expected timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { + const auto timestamp = mSurfaceFlingerPredictions.startTime; + if (filterFramesBeforeTraceStarts && !shouldTraceForDataSource(ctx, timestamp)) { + // Do not trace packets started before tracing starts. + return; + } + traced = true; + auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); - packet->set_timestamp( - static_cast<uint64_t>(mSurfaceFlingerPredictions.startTime + monoBootOffset)); + packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset)); auto* event = packet->set_frame_timeline_event(); auto* expectedDisplayFrameStartEvent = event->set_expected_display_frame_start(); @@ -1174,22 +1221,25 @@ void FrameTimeline::DisplayFrame::tracePredictions(pid_t surfaceFlingerPid, expectedDisplayFrameStartEvent->set_pid(surfaceFlingerPid); }); - // Expected timeline end - FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - auto packet = ctx.NewTracePacket(); - packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); - packet->set_timestamp( - static_cast<uint64_t>(mSurfaceFlingerPredictions.endTime + monoBootOffset)); + if (traced) { + // Expected timeline end + FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { + auto packet = ctx.NewTracePacket(); + packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); + packet->set_timestamp( + static_cast<uint64_t>(mSurfaceFlingerPredictions.endTime + monoBootOffset)); - auto* event = packet->set_frame_timeline_event(); - auto* expectedDisplayFrameEndEvent = event->set_frame_end(); + auto* event = packet->set_frame_timeline_event(); + auto* expectedDisplayFrameEndEvent = event->set_frame_end(); - expectedDisplayFrameEndEvent->set_cookie(expectedTimelineCookie); - }); + expectedDisplayFrameEndEvent->set_cookie(expectedTimelineCookie); + }); + } } void FrameTimeline::DisplayFrame::addSkippedFrame(pid_t surfaceFlingerPid, nsecs_t monoBootOffset, - nsecs_t previousPredictionPresentTime) const { + nsecs_t previousPredictionPresentTime, + bool filterFramesBeforeTraceStarts) const { nsecs_t skippedFrameStartTime = 0, skippedFramePresentTime = 0; const constexpr float kThresh = 0.5f; const constexpr float kRange = 1.5f; @@ -1205,7 +1255,7 @@ void FrameTimeline::DisplayFrame::addSkippedFrame(pid_t surfaceFlingerPid, nsecs (static_cast<float>(previousPredictionPresentTime) + kThresh * static_cast<float>(mRenderRate.getPeriodNsecs())) && // sf skipped frame is not considered if app is self janked - !surfaceFrame->isSelfJanky()) { + surfaceFrame->getJankType() != JankType::None && !surfaceFrame->isSelfJanky()) { skippedFrameStartTime = surfaceFrame->getPredictions().endTime; skippedFramePresentTime = surfaceFrame->getPredictions().presentTime; break; @@ -1215,9 +1265,17 @@ void FrameTimeline::DisplayFrame::addSkippedFrame(pid_t surfaceFlingerPid, nsecs // add slice if (skippedFrameStartTime != 0 && skippedFramePresentTime != 0) { int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing(); + bool traced = false; // Actual timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { + if (filterFramesBeforeTraceStarts && + !shouldTraceForDataSource(ctx, skippedFrameStartTime)) { + // Do not trace packets started before tracing starts. + return; + } + traced = true; + auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); packet->set_timestamp(static_cast<uint64_t>(skippedFrameStartTime + monoBootOffset)); @@ -1238,30 +1296,40 @@ void FrameTimeline::DisplayFrame::addSkippedFrame(pid_t surfaceFlingerPid, nsecs actualDisplayFrameStartEvent->set_jank_severity_type(toProto(JankSeverityType::None)); }); - // Actual timeline end - FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - auto packet = ctx.NewTracePacket(); - packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); - packet->set_timestamp(static_cast<uint64_t>(skippedFramePresentTime + monoBootOffset)); + if (traced) { + // Actual timeline end + FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { + auto packet = ctx.NewTracePacket(); + packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); + packet->set_timestamp( + static_cast<uint64_t>(skippedFramePresentTime + monoBootOffset)); - auto* event = packet->set_frame_timeline_event(); - auto* actualDisplayFrameEndEvent = event->set_frame_end(); + auto* event = packet->set_frame_timeline_event(); + auto* actualDisplayFrameEndEvent = event->set_frame_end(); - actualDisplayFrameEndEvent->set_cookie(actualTimelineCookie); - }); + actualDisplayFrameEndEvent->set_cookie(actualTimelineCookie); + }); + } } } -void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid, - nsecs_t monoBootOffset) const { +void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid, nsecs_t monoBootOffset, + bool filterFramesBeforeTraceStarts) const { int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing(); + bool traced = false; // Actual timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { + const auto timestamp = mSurfaceFlingerActuals.startTime; + if (filterFramesBeforeTraceStarts && !shouldTraceForDataSource(ctx, timestamp)) { + // Do not trace packets started before tracing starts. + return; + } + traced = true; + auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); - packet->set_timestamp( - static_cast<uint64_t>(mSurfaceFlingerActuals.startTime + monoBootOffset)); + packet->set_timestamp(static_cast<uint64_t>(timestamp + monoBootOffset)); auto* event = packet->set_frame_timeline_event(); auto* actualDisplayFrameStartEvent = event->set_actual_display_frame_start(); @@ -1280,22 +1348,25 @@ void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid, actualDisplayFrameStartEvent->set_jank_severity_type(toProto(mJankSeverityType)); }); - // Actual timeline end - FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - auto packet = ctx.NewTracePacket(); - packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); - packet->set_timestamp( - static_cast<uint64_t>(mSurfaceFlingerActuals.presentTime + monoBootOffset)); + if (traced) { + // Actual timeline end + FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { + auto packet = ctx.NewTracePacket(); + packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME); + packet->set_timestamp( + static_cast<uint64_t>(mSurfaceFlingerActuals.presentTime + monoBootOffset)); - auto* event = packet->set_frame_timeline_event(); - auto* actualDisplayFrameEndEvent = event->set_frame_end(); + auto* event = packet->set_frame_timeline_event(); + auto* actualDisplayFrameEndEvent = event->set_frame_end(); - actualDisplayFrameEndEvent->set_cookie(actualTimelineCookie); - }); + actualDisplayFrameEndEvent->set_cookie(actualTimelineCookie); + }); + } } nsecs_t FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid, nsecs_t monoBootOffset, - nsecs_t previousPredictionPresentTime) const { + nsecs_t previousPredictionPresentTime, + bool filterFramesBeforeTraceStarts) const { if (mSurfaceFrames.empty()) { // We don't want to trace display frames without any surface frames updates as this cannot // be janky @@ -1311,16 +1382,17 @@ nsecs_t FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid, nsecs_t mono if (mPredictionState == PredictionState::Valid) { // Expired and unknown predictions have zeroed timestamps. This cannot be used in any // meaningful way in a trace. - tracePredictions(surfaceFlingerPid, monoBootOffset); + tracePredictions(surfaceFlingerPid, monoBootOffset, filterFramesBeforeTraceStarts); } - traceActuals(surfaceFlingerPid, monoBootOffset); + traceActuals(surfaceFlingerPid, monoBootOffset, filterFramesBeforeTraceStarts); for (auto& surfaceFrame : mSurfaceFrames) { - surfaceFrame->trace(mToken, monoBootOffset); + surfaceFrame->trace(mToken, monoBootOffset, filterFramesBeforeTraceStarts); } if (FlagManager::getInstance().add_sf_skipped_frames_to_trace()) { - addSkippedFrame(surfaceFlingerPid, monoBootOffset, previousPredictionPresentTime); + addSkippedFrame(surfaceFlingerPid, monoBootOffset, previousPredictionPresentTime, + filterFramesBeforeTraceStarts); } return mSurfaceFlingerPredictions.presentTime; } @@ -1414,8 +1486,9 @@ void FrameTimeline::flushPendingPresentFences() { const nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID; auto& displayFrame = pendingPresentFence.second; displayFrame->onPresent(signalTime, mPreviousActualPresentTime); - mPreviousPredictionPresentTime = displayFrame->trace(mSurfaceFlingerPid, monoBootOffset, - mPreviousPredictionPresentTime); + mPreviousPredictionPresentTime = + displayFrame->trace(mSurfaceFlingerPid, monoBootOffset, + mPreviousPredictionPresentTime, mFilterFramesBeforeTraceStarts); mPendingPresentFences.erase(mPendingPresentFences.begin()); } @@ -1431,8 +1504,9 @@ void FrameTimeline::flushPendingPresentFences() { auto& displayFrame = pendingPresentFence.second; displayFrame->onPresent(signalTime, mPreviousActualPresentTime); - mPreviousPredictionPresentTime = displayFrame->trace(mSurfaceFlingerPid, monoBootOffset, - mPreviousPredictionPresentTime); + mPreviousPredictionPresentTime = + displayFrame->trace(mSurfaceFlingerPid, monoBootOffset, + mPreviousPredictionPresentTime, mFilterFramesBeforeTraceStarts); mPreviousActualPresentTime = signalTime; mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i)); diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index 94cfcb40b9..cffb61ee10 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -214,7 +214,8 @@ public: // enabled. The displayFrameToken is needed to link the SurfaceFrame to the corresponding // DisplayFrame at the trace processor side. monoBootOffset is the difference // between SYSTEM_TIME_BOOTTIME and SYSTEM_TIME_MONOTONIC. - void trace(int64_t displayFrameToken, nsecs_t monoBootOffset) const; + void trace(int64_t displayFrameToken, nsecs_t monoBootOffset, + bool filterFramesBeforeTraceStarts) const; // Getter functions used only by FrameTimelineTests and SurfaceFrame internally TimelineItem getActuals() const; @@ -234,8 +235,10 @@ public: std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count(); private: - void tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset) const; - void traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset) const; + void tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset, + bool filterFramesBeforeTraceStarts) const; + void traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset, + bool filterFramesBeforeTraceStarts) const; void classifyJankLocked(int32_t displayFrameJankType, const Fps& refreshRate, Fps displayFrameRenderRate, nsecs_t* outDeadlineDelta) REQUIRES(mMutex); @@ -367,9 +370,15 @@ private: class FrameTimeline : public android::frametimeline::FrameTimeline { public: class FrameTimelineDataSource : public perfetto::DataSource<FrameTimelineDataSource> { - void OnSetup(const SetupArgs&) override{}; - void OnStart(const StartArgs&) override{}; - void OnStop(const StopArgs&) override{}; + public: + nsecs_t getStartTime() const { return mTraceStartTime; } + + private: + void OnSetup(const SetupArgs&) override {}; + void OnStart(const StartArgs&) override { mTraceStartTime = systemTime(); }; + void OnStop(const StopArgs&) override {}; + + nsecs_t mTraceStartTime = 0; }; /* @@ -390,7 +399,8 @@ public: // is enabled. monoBootOffset is the difference between SYSTEM_TIME_BOOTTIME // and SYSTEM_TIME_MONOTONIC. nsecs_t trace(pid_t surfaceFlingerPid, nsecs_t monoBootOffset, - nsecs_t previousPredictionPresentTime) const; + nsecs_t previousPredictionPresentTime, + bool filterFramesBeforeTraceStarts) const; // Sets the token, vsyncPeriod, predictions and SF start time. void onSfWakeUp(int64_t token, Fps refreshRate, Fps renderRate, std::optional<TimelineItem> predictions, nsecs_t wakeUpTime); @@ -424,10 +434,13 @@ public: private: void dump(std::string& result, nsecs_t baseTime) const; - void tracePredictions(pid_t surfaceFlingerPid, nsecs_t monoBootOffset) const; - void traceActuals(pid_t surfaceFlingerPid, nsecs_t monoBootOffset) const; + void tracePredictions(pid_t surfaceFlingerPid, nsecs_t monoBootOffset, + bool filterFramesBeforeTraceStarts) const; + void traceActuals(pid_t surfaceFlingerPid, nsecs_t monoBootOffset, + bool filterFramesBeforeTraceStarts) const; void addSkippedFrame(pid_t surfaceFlingerPid, nsecs_t monoBootOffset, - nsecs_t previousActualPresentTime) const; + nsecs_t previousActualPresentTime, + bool filterFramesBeforeTraceStarts) const; void classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync, nsecs_t previousPresentTime); @@ -471,7 +484,8 @@ public: }; FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid, - JankClassificationThresholds thresholds = {}, bool useBootTimeClock = true); + JankClassificationThresholds thresholds = {}, bool useBootTimeClock = true, + bool filterFramesBeforeTraceStarts = true); ~FrameTimeline() = default; frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; } @@ -516,6 +530,7 @@ private: TraceCookieCounter mTraceCookieCounter; mutable std::mutex mMutex; const bool mUseBootTimeClock; + const bool mFilterFramesBeforeTraceStarts; uint32_t mMaxDisplayFrames; std::shared_ptr<TimeStats> mTimeStats; const pid_t mSurfaceFlingerPid; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3c8af19015..c17ea3b579 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -60,9 +60,7 @@ #include <utils/StopWatch.h> #include <algorithm> -#include <mutex> #include <optional> -#include <sstream> #include "DisplayDevice.h" #include "DisplayHardware/HWComposer.h" @@ -72,7 +70,6 @@ #include "FrontEnd/LayerHandle.h" #include "Layer.h" #include "LayerProtoHelper.h" -#include "MutexUtils.h" #include "SurfaceFlinger.h" #include "TimeStats/TimeStats.h" #include "TransactionCallbackInvoker.h" @@ -89,18 +86,6 @@ constexpr int kDumpTableRowLength = 159; const ui::Transform kIdentityTransform; -ui::LogicalDisplayId toLogicalDisplayId(const ui::LayerStack& layerStack) { - return ui::LogicalDisplayId{static_cast<int32_t>(layerStack.id)}; -} - -bool assignTransform(ui::Transform* dst, ui::Transform& from) { - if (*dst == from) { - return false; - } - *dst = from; - return true; -} - TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) { using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility; using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness; @@ -149,24 +134,11 @@ Layer::Layer(const surfaceflinger::LayerCreationArgs& args) : sequence(args.sequence), mFlinger(sp<SurfaceFlinger>::fromExisting(args.flinger)), mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)), - mClientRef(args.client), mWindowType(static_cast<WindowInfo::Type>( - args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))), - mLayerCreationFlags(args.flags), - mLegacyLayerFE(args.flinger->getFactory().createLayerFE(mName, this)) { + args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))) { ALOGV("Creating Layer %s", getDebugName()); - uint32_t layerFlags = 0; - if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden; - if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque; - if (args.flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure; - if (args.flags & ISurfaceComposerClient::eSkipScreenshot) - layerFlags |= layer_state_t::eLayerSkipScreenshot; - mDrawingState.flags = layerFlags; mDrawingState.crop.makeInvalid(); - mDrawingState.z = 0; - mDrawingState.color.a = 1.0f; - mDrawingState.layerStack = ui::DEFAULT_LAYER_STACK; mDrawingState.sequence = 0; mDrawingState.transform.set(0, 0); mDrawingState.frameNumber = 0; @@ -179,33 +151,9 @@ Layer::Layer(const surfaceflinger::LayerCreationArgs& args) mDrawingState.acquireFence = sp<Fence>::make(-1); mDrawingState.acquireFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence); mDrawingState.dataspace = ui::Dataspace::V0_SRGB; - mDrawingState.hdrMetadata.validTypes = 0; - mDrawingState.surfaceDamageRegion = Region::INVALID_REGION; - mDrawingState.cornerRadius = 0.0f; - mDrawingState.backgroundBlurRadius = 0; - mDrawingState.api = -1; - mDrawingState.hasColorTransform = false; - mDrawingState.colorSpaceAgnostic = false; - mDrawingState.frameRateSelectionPriority = PRIORITY_UNSET; mDrawingState.metadata = args.metadata; - mDrawingState.shadowRadius = 0.f; - mDrawingState.fixedTransformHint = ui::Transform::ROT_INVALID; mDrawingState.frameTimelineInfo = {}; mDrawingState.postTime = -1; - mDrawingState.destinationFrame.makeInvalid(); - mDrawingState.isTrustedOverlay = false; - mDrawingState.dropInputMode = gui::DropInputMode::NONE; - mDrawingState.dimmingEnabled = true; - mDrawingState.defaultFrameRateCompatibility = FrameRateCompatibility::Default; - mDrawingState.frameRateSelectionStrategy = FrameRateSelectionStrategy::Propagate; - - if (args.flags & ISurfaceComposerClient::eNoColorFill) { - // Set an invalid color so there is no color fill. - mDrawingState.color.r = -1.0_hf; - mDrawingState.color.g = -1.0_hf; - mDrawingState.color.b = -1.0_hf; - } - mFrameTracker.setDisplayRefreshPeriod( args.flinger->mScheduler->getPacesetterVsyncPeriod().ns()); @@ -213,14 +161,9 @@ Layer::Layer(const surfaceflinger::LayerCreationArgs& args) mOwnerPid = args.ownerPid; mOwnerAppId = mOwnerUid % PER_USER_RANGE; - mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied); mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow; - mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp; - - mSnapshot->sequence = sequence; - mSnapshot->name = getDebugName(); - mSnapshot->premultipliedAlpha = mPremultipliedAlpha; - mSnapshot->parentTransform = {}; + mLayerFEs.emplace_back(frontend::LayerHierarchy::TraversalPath{static_cast<uint32_t>(sequence)}, + args.flinger->getFactory().createLayerFE(mName, this)); } void Layer::onFirstRef() { @@ -253,35 +196,8 @@ Layer::~Layer() { } // --------------------------------------------------------------------------- -// callbacks -// --------------------------------------------------------------------------- - -void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) { - if (mDrawingState.zOrderRelativeOf == nullptr) { - return; - } - - sp<Layer> strongRelative = mDrawingState.zOrderRelativeOf.promote(); - if (strongRelative == nullptr) { - setZOrderRelativeOf(nullptr); - return; - } - - if (!std::binary_search(layersInTree.begin(), layersInTree.end(), strongRelative.get())) { - strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this)); - mFlinger->setTransactionFlags(eTraversalNeeded); - setZOrderRelativeOf(nullptr); - } -} - -// --------------------------------------------------------------------------- // set-up // --------------------------------------------------------------------------- - -bool Layer::getPremultipledAlpha() const { - return mPremultipliedAlpha; -} - sp<IBinder> Layer::getHandle() { Mutex::Autolock _l(mLock); if (mGetHandleCalled) { @@ -297,46 +213,6 @@ sp<IBinder> Layer::getHandle() { // h/w composer set-up // --------------------------------------------------------------------------- -static Rect reduce(const Rect& win, const Region& exclude) { - if (CC_LIKELY(exclude.isEmpty())) { - return win; - } - if (exclude.isRect()) { - return win.reduce(exclude.getBounds()); - } - return Region(win).subtract(exclude).getBounds(); -} - -static FloatRect reduce(const FloatRect& win, const Region& exclude) { - if (CC_LIKELY(exclude.isEmpty())) { - return win; - } - // Convert through Rect (by rounding) for lack of FloatRegion - return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect(); -} - -Rect Layer::getScreenBounds(bool reduceTransparentRegion) const { - if (!reduceTransparentRegion) { - return Rect{mScreenBounds}; - } - - FloatRect bounds = getBounds(); - ui::Transform t = getTransform(); - // Transform to screen space. - bounds = t.transform(bounds); - return Rect{bounds}; -} - -FloatRect Layer::getBounds() const { - const State& s(getDrawingState()); - return getBounds(getActiveTransparentRegion(s)); -} - -FloatRect Layer::getBounds(const Region& activeTransparentRegion) const { - // Subtract the transparent region and snap to the bounds. - return reduce(mBounds, activeTransparentRegion); -} - // No early returns. void Layer::updateTrustedPresentationState(const DisplayDevice* display, const frontend::LayerSnapshot* snapshot, @@ -438,57 +314,6 @@ bool Layer::computeTrustedPresentationState(const FloatRect& bounds, const Float return true; } -void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform, - float parentShadowRadius) { - const State& s(getDrawingState()); - - // Calculate effective layer transform - mEffectiveTransform = parentTransform * getActiveTransform(s); - - if (CC_UNLIKELY(!isTransformValid())) { - ALOGW("Stop computing bounds for %s because it has invalid transformation.", - getDebugName()); - return; - } - - // Transform parent bounds to layer space - parentBounds = getActiveTransform(s).inverse().transform(parentBounds); - - // Calculate source bounds - mSourceBounds = computeSourceBounds(parentBounds); - - // Calculate bounds by croping diplay frame with layer crop and parent bounds - FloatRect bounds = mSourceBounds; - const Rect layerCrop = getCrop(s); - if (!layerCrop.isEmpty()) { - bounds = mSourceBounds.intersect(layerCrop.toFloatRect()); - } - bounds = bounds.intersect(parentBounds); - - mBounds = bounds; - mScreenBounds = mEffectiveTransform.transform(mBounds); - - // Use the layer's own shadow radius if set. Otherwise get the radius from - // parent. - if (s.shadowRadius > 0.f) { - mEffectiveShadowRadius = s.shadowRadius; - } else { - mEffectiveShadowRadius = parentShadowRadius; - } - - // Shadow radius is passed down to only one layer so if the layer can draw shadows, - // don't pass it to its children. - const float childShadowRadius = canDrawShadows() ? 0.f : mEffectiveShadowRadius; - - for (const sp<Layer>& child : mDrawingChildren) { - child->computeBounds(mBounds, mEffectiveTransform, childShadowRadius); - } - - if (mPotentialCursor) { - prepareCursorCompositionState(); - } -} - Rect Layer::getCroppedBufferSize(const State& s) const { Rect size = getBufferSize(s); Rect crop = getCrop(s); @@ -500,180 +325,6 @@ Rect Layer::getCroppedBufferSize(const State& s) const { return size; } -void Layer::setupRoundedCornersCropCoordinates(Rect win, - const FloatRect& roundedCornersCrop) const { - // Translate win by the rounded corners rect coordinates, to have all values in - // layer coordinate space. - win.left -= roundedCornersCrop.left; - win.right -= roundedCornersCrop.left; - win.top -= roundedCornersCrop.top; - win.bottom -= roundedCornersCrop.top; -} - -void Layer::prepareBasicGeometryCompositionState() { - const auto& drawingState{getDrawingState()}; - const auto alpha = static_cast<float>(getAlpha()); - const bool opaque = isOpaque(drawingState); - const bool usesRoundedCorners = hasRoundedCorners(); - - auto blendMode = Hwc2::IComposerClient::BlendMode::NONE; - if (!opaque || alpha != 1.0f) { - blendMode = mPremultipliedAlpha ? Hwc2::IComposerClient::BlendMode::PREMULTIPLIED - : Hwc2::IComposerClient::BlendMode::COVERAGE; - } - - // Please keep in sync with LayerSnapshotBuilder - auto* snapshot = editLayerSnapshot(); - snapshot->outputFilter = getOutputFilter(); - snapshot->isVisible = isVisible(); - snapshot->isOpaque = opaque && !usesRoundedCorners && alpha == 1.f; - snapshot->shadowSettings.length = mEffectiveShadowRadius; - - snapshot->contentDirty = contentDirty; - contentDirty = false; - - snapshot->geomLayerBounds = mBounds; - snapshot->geomLayerTransform = getTransform(); - snapshot->geomInverseLayerTransform = snapshot->geomLayerTransform.inverse(); - snapshot->transparentRegionHint = getActiveTransparentRegion(drawingState); - snapshot->localTransform = getActiveTransform(drawingState); - snapshot->localTransformInverse = snapshot->localTransform.inverse(); - snapshot->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode); - snapshot->alpha = alpha; - snapshot->backgroundBlurRadius = getBackgroundBlurRadius(); - snapshot->blurRegions = getBlurRegions(); -} - -void Layer::prepareGeometryCompositionState() { - const auto& drawingState{getDrawingState()}; - auto* snapshot = editLayerSnapshot(); - - // Please keep in sync with LayerSnapshotBuilder - snapshot->geomBufferSize = getBufferSize(drawingState); - snapshot->geomContentCrop = getBufferCrop(); - snapshot->geomCrop = getCrop(drawingState); - snapshot->geomBufferTransform = getBufferTransform(); - snapshot->geomBufferUsesDisplayInverseTransform = getTransformToDisplayInverse(); - snapshot->geomUsesSourceCrop = usesSourceCrop(); - snapshot->isSecure = isSecure(); - - snapshot->metadata.clear(); - const auto& supportedMetadata = mFlinger->getHwComposer().getSupportedLayerGenericMetadata(); - for (const auto& [key, mandatory] : supportedMetadata) { - const auto& genericLayerMetadataCompatibilityMap = - mFlinger->getGenericLayerMetadataKeyMap(); - auto compatIter = genericLayerMetadataCompatibilityMap.find(key); - if (compatIter == std::end(genericLayerMetadataCompatibilityMap)) { - continue; - } - const uint32_t id = compatIter->second; - - auto it = drawingState.metadata.mMap.find(id); - if (it == std::end(drawingState.metadata.mMap)) { - continue; - } - - snapshot->metadata.emplace(key, - compositionengine::GenericLayerMetadataEntry{mandatory, - it->second}); - } -} - -void Layer::preparePerFrameCompositionState() { - const auto& drawingState{getDrawingState()}; - // Please keep in sync with LayerSnapshotBuilder - auto* snapshot = editLayerSnapshot(); - - snapshot->forceClientComposition = false; - - snapshot->isColorspaceAgnostic = isColorSpaceAgnostic(); - snapshot->dataspace = getDataSpace(); - snapshot->colorTransform = getColorTransform(); - snapshot->colorTransformIsIdentity = !hasColorTransform(); - snapshot->surfaceDamage = surfaceDamageRegion; - snapshot->hasProtectedContent = isProtected(); - snapshot->dimmingEnabled = isDimmingEnabled(); - snapshot->currentHdrSdrRatio = getCurrentHdrSdrRatio(); - snapshot->desiredHdrSdrRatio = getDesiredHdrSdrRatio(); - snapshot->cachingHint = getCachingHint(); - - const bool usesRoundedCorners = hasRoundedCorners(); - - snapshot->isOpaque = isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf; - - // Force client composition for special cases known only to the front-end. - // Rounded corners no longer force client composition, since we may use a - // hole punch so that the layer will appear to have rounded corners. - if (drawShadows() || snapshot->stretchEffect.hasEffect()) { - snapshot->forceClientComposition = true; - } - // If there are no visible region changes, we still need to update blur parameters. - snapshot->blurRegions = getBlurRegions(); - snapshot->backgroundBlurRadius = getBackgroundBlurRadius(); - - // Layer framerate is used in caching decisions. - // Retrieve it from the scheduler which maintains an instance of LayerHistory, and store it in - // LayerFECompositionState where it would be visible to Flattener. - snapshot->fps = mFlinger->getLayerFramerate(systemTime(), getSequence()); - - if (hasBufferOrSidebandStream()) { - preparePerFrameBufferCompositionState(); - } else { - preparePerFrameEffectsCompositionState(); - } -} - -void Layer::preparePerFrameBufferCompositionState() { - // Please keep in sync with LayerSnapshotBuilder - auto* snapshot = editLayerSnapshot(); - // Sideband layers - if (snapshot->sidebandStream.get() && !snapshot->sidebandStreamHasFrame) { - snapshot->compositionType = - aidl::android::hardware::graphics::composer3::Composition::SIDEBAND; - return; - } else if ((mDrawingState.flags & layer_state_t::eLayerIsDisplayDecoration) != 0) { - snapshot->compositionType = - aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION; - } else if ((mDrawingState.flags & layer_state_t::eLayerIsRefreshRateIndicator) != 0) { - snapshot->compositionType = - aidl::android::hardware::graphics::composer3::Composition::REFRESH_RATE_INDICATOR; - } else { - // Normal buffer layers - snapshot->hdrMetadata = mBufferInfo.mHdrMetadata; - snapshot->compositionType = mPotentialCursor - ? aidl::android::hardware::graphics::composer3::Composition::CURSOR - : aidl::android::hardware::graphics::composer3::Composition::DEVICE; - } - - snapshot->buffer = getBuffer(); - snapshot->acquireFence = mBufferInfo.mFence; - snapshot->frameNumber = mBufferInfo.mFrameNumber; - snapshot->sidebandStreamHasFrame = false; -} - -void Layer::preparePerFrameEffectsCompositionState() { - // Please keep in sync with LayerSnapshotBuilder - auto* snapshot = editLayerSnapshot(); - snapshot->color = getColor(); - snapshot->compositionType = - aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR; -} - -void Layer::prepareCursorCompositionState() { - const State& drawingState{getDrawingState()}; - // Please keep in sync with LayerSnapshotBuilder - auto* snapshot = editLayerSnapshot(); - - // Apply the layer's transform, followed by the display's global transform - // Here we're guaranteed that the layer's transform preserves rects - Rect win = getCroppedBufferSize(drawingState); - // Subtract the transparent region and snap to the bounds - Rect bounds = reduce(win, getActiveTransparentRegion(drawingState)); - Rect frame(getTransform().transform(bounds)); - - snapshot->cursorFrame = frame; -} - const char* Layer::getDebugName() const { return mName.c_str(); } @@ -701,45 +352,18 @@ aidl::android::hardware::graphics::composer3::Composition Layer::getCompositionT } // ---------------------------------------------------------------------------- -// local state -// ---------------------------------------------------------------------------- - -bool Layer::isSecure() const { - const State& s(mDrawingState); - if (s.flags & layer_state_t::eLayerSecure) { - return true; - } - - const auto p = mDrawingParent.promote(); - return (p != nullptr) ? p->isSecure() : false; -} - -// ---------------------------------------------------------------------------- // transaction // ---------------------------------------------------------------------------- uint32_t Layer::doTransaction(uint32_t flags) { SFTRACE_CALL(); - // TODO: This is unfortunate. - mDrawingStateModified = mDrawingState.modified; - mDrawingState.modified = false; - const State& s(getDrawingState()); - if (updateGeometry()) { - // invalidate and recompute the visible regions if needed - flags |= Layer::eVisibleRegion; - } - if (s.sequence != mLastCommittedTxSequence) { // invalidate and recompute the visible regions if needed mLastCommittedTxSequence = s.sequence; flags |= eVisibleRegion; - this->contentDirty = true; - - // we may use linear filtering, if the matrix scales us - mNeedsFiltering = getActiveTransform(s).needsBilinearFiltering(); } if (!mPotentialCursor && (flags & Layer::eVisibleRegion)) { @@ -775,208 +399,11 @@ void Layer::setTransactionFlags(uint32_t mask) { mTransactionFlags |= mask; } -bool Layer::setLayer(int32_t z) { - if (mDrawingState.z == z && !usingRelativeZ(LayerVector::StateSet::Current)) return false; - mDrawingState.sequence++; - mDrawingState.z = z; - mDrawingState.modified = true; - - mFlinger->mSomeChildrenChanged = true; - - // Discard all relative layering. - if (mDrawingState.zOrderRelativeOf != nullptr) { - sp<Layer> strongRelative = mDrawingState.zOrderRelativeOf.promote(); - if (strongRelative != nullptr) { - strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this)); - } - setZOrderRelativeOf(nullptr); - } - setTransactionFlags(eTransactionNeeded); - return true; -} - -void Layer::removeZOrderRelative(const wp<Layer>& relative) { - mDrawingState.zOrderRelatives.remove(relative); - mDrawingState.sequence++; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); -} - -void Layer::addZOrderRelative(const wp<Layer>& relative) { - mDrawingState.zOrderRelatives.add(relative); - mDrawingState.modified = true; - mDrawingState.sequence++; - setTransactionFlags(eTransactionNeeded); -} - -void Layer::setZOrderRelativeOf(const wp<Layer>& relativeOf) { - mDrawingState.zOrderRelativeOf = relativeOf; - mDrawingState.sequence++; - mDrawingState.modified = true; - mDrawingState.isRelativeOf = relativeOf != nullptr; - - setTransactionFlags(eTransactionNeeded); -} - -bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ) { - sp<Layer> relative = LayerHandle::getLayer(relativeToHandle); - if (relative == nullptr) { - return false; - } - - if (mDrawingState.z == relativeZ && usingRelativeZ(LayerVector::StateSet::Current) && - mDrawingState.zOrderRelativeOf == relative) { - return false; - } - - if (CC_UNLIKELY(relative->usingRelativeZ(LayerVector::StateSet::Drawing)) && - (relative->mDrawingState.zOrderRelativeOf == this)) { - ALOGE("Detected relative layer loop between %s and %s", - mName.c_str(), relative->mName.c_str()); - ALOGE("Ignoring new call to set relative layer"); - return false; - } - - mFlinger->mSomeChildrenChanged = true; - - mDrawingState.sequence++; - mDrawingState.modified = true; - mDrawingState.z = relativeZ; - - auto oldZOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote(); - if (oldZOrderRelativeOf != nullptr) { - oldZOrderRelativeOf->removeZOrderRelative(wp<Layer>::fromExisting(this)); - } - setZOrderRelativeOf(relative); - relative->addZOrderRelative(wp<Layer>::fromExisting(this)); - - setTransactionFlags(eTransactionNeeded); - - return true; -} - -bool Layer::setTrustedOverlay(bool isTrustedOverlay) { - if (mDrawingState.isTrustedOverlay == isTrustedOverlay) return false; - mDrawingState.isTrustedOverlay = isTrustedOverlay; - mDrawingState.modified = true; - mFlinger->mUpdateInputInfo = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::isTrustedOverlay() const { - if (getDrawingState().isTrustedOverlay) { - return true; - } - const auto& p = mDrawingParent.promote(); - return (p != nullptr) && p->isTrustedOverlay(); -} - -bool Layer::setAlpha(float alpha) { - if (mDrawingState.color.a == alpha) return false; - mDrawingState.sequence++; - mDrawingState.color.a = alpha; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setCornerRadius(float cornerRadius) { - if (mDrawingState.cornerRadius == cornerRadius) return false; - - mDrawingState.sequence++; - mDrawingState.cornerRadius = cornerRadius; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) { - if (mDrawingState.backgroundBlurRadius == backgroundBlurRadius) return false; - // If we start or stop drawing blur then the layer's visibility state may change so increment - // the magic sequence number. - if (mDrawingState.backgroundBlurRadius == 0 || backgroundBlurRadius == 0) { - mDrawingState.sequence++; - } - mDrawingState.backgroundBlurRadius = backgroundBlurRadius; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setTransparentRegionHint(const Region& transparent) { - mDrawingState.sequence++; - mDrawingState.transparentRegionHint = transparent; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setBlurRegions(const std::vector<BlurRegion>& blurRegions) { - // If we start or stop drawing blur then the layer's visibility state may change so increment - // the magic sequence number. - if (mDrawingState.blurRegions.size() == 0 || blurRegions.size() == 0) { - mDrawingState.sequence++; - } - mDrawingState.blurRegions = blurRegions; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setFlags(uint32_t flags, uint32_t mask) { - const uint32_t newFlags = (mDrawingState.flags & ~mask) | (flags & mask); - if (mDrawingState.flags == newFlags) return false; - mDrawingState.sequence++; - mDrawingState.flags = newFlags; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - bool Layer::setCrop(const Rect& crop) { if (mDrawingState.crop == crop) return false; mDrawingState.sequence++; mDrawingState.crop = crop; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setMetadata(const LayerMetadata& data) { - if (!mDrawingState.metadata.merge(data, true /* eraseEmpty */)) return false; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setLayerStack(ui::LayerStack layerStack) { - if (mDrawingState.layerStack == layerStack) return false; - mDrawingState.sequence++; - mDrawingState.layerStack = layerStack; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setColorSpaceAgnostic(const bool agnostic) { - if (mDrawingState.colorSpaceAgnostic == agnostic) { - return false; - } - mDrawingState.sequence++; - mDrawingState.colorSpaceAgnostic = agnostic; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setDimmingEnabled(const bool dimmingEnabled) { - if (mDrawingState.dimmingEnabled == dimmingEnabled) return false; - - mDrawingState.sequence++; - mDrawingState.dimmingEnabled = dimmingEnabled; - mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } @@ -985,52 +412,6 @@ bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) { return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE; }; -ui::LayerStack Layer::getLayerStack(LayerVector::StateSet state) const { - bool useDrawing = state == LayerVector::StateSet::Drawing; - const auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote(); - if (parent) { - return parent->getLayerStack(); - } - return getDrawingState().layerStack; -} - -bool Layer::setShadowRadius(float shadowRadius) { - if (mDrawingState.shadowRadius == shadowRadius) { - return false; - } - - mDrawingState.sequence++; - mDrawingState.shadowRadius = shadowRadius; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint) { - if (mDrawingState.fixedTransformHint == fixedTransformHint) { - return false; - } - - mDrawingState.sequence++; - mDrawingState.fixedTransformHint = fixedTransformHint; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setStretchEffect(const StretchEffect& effect) { - StretchEffect temp = effect; - temp.sanitize(); - if (mDrawingState.stretchEffect == temp) { - return false; - } - mDrawingState.sequence++; - mDrawingState.stretchEffect = temp; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime, gui::GameMode gameMode) { mDrawingState.postTime = postTime; @@ -1059,7 +440,6 @@ void Layer::setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInf gui::GameMode gameMode) { mDrawingState.frameTimelineInfo = info; mDrawingState.postTime = postTime; - mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); if (const auto& bufferSurfaceFrameTX = mDrawingState.bufferSurfaceFrameTX; @@ -1181,40 +561,6 @@ Layer::FrameRate Layer::getFrameRateForLayerTree() const { return getDrawingState().frameRateForLayerTree; } -bool Layer::isHiddenByPolicy() const { - const State& s(mDrawingState); - const auto& parent = mDrawingParent.promote(); - if (parent != nullptr && parent->isHiddenByPolicy()) { - return true; - } - if (usingRelativeZ(LayerVector::StateSet::Drawing)) { - auto zOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote(); - if (zOrderRelativeOf != nullptr) { - if (zOrderRelativeOf->isHiddenByPolicy()) { - return true; - } - } - } - if (CC_UNLIKELY(!isTransformValid())) { - ALOGW("Hide layer %s because it has invalid transformation.", getDebugName()); - return true; - } - return s.flags & layer_state_t::eLayerHidden; -} - -uint32_t Layer::getEffectiveUsage(uint32_t usage) const { - // TODO: should we do something special if mSecure is set? - if (mProtectedByApp) { - // need a hardware-protected path to external video sink - usage |= GraphicBuffer::USAGE_PROTECTED; - } - if (mPotentialCursor) { - usage |= GraphicBuffer::USAGE_CURSOR; - } - usage |= GraphicBuffer::USAGE_HW_COMPOSER; - return usage; -} - // ---------------------------------------------------------------------------- // debugging // ---------------------------------------------------------------------------- @@ -1293,248 +639,12 @@ void Layer::getFrameStats(FrameStats* outStats) const { mFrameTracker.getStats(outStats); } -void Layer::dumpOffscreenDebugInfo(std::string& result) const { - std::string hasBuffer = hasBufferOrSidebandStream() ? " (contains buffer)" : ""; - StringAppendF(&result, "Layer %s%s pid:%d uid:%d%s\n", getName().c_str(), hasBuffer.c_str(), - mOwnerPid, mOwnerUid, isHandleAlive() ? " handleAlive" : ""); -} - void Layer::onDisconnect() { const int32_t layerId = getSequence(); mFlinger->mTimeStats->onDestroy(layerId); mFlinger->mFrameTracer->onDestroy(layerId); } -void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) { - for (const sp<Layer>& child : mDrawingChildren) { - child->mDrawingParent = newParent; - const float parentShadowRadius = - newParent->canDrawShadows() ? 0.f : newParent->mEffectiveShadowRadius; - child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform, - parentShadowRadius); - } -} - -bool Layer::setColorTransform(const mat4& matrix) { - static const mat4 identityMatrix = mat4(); - - if (mDrawingState.colorTransform == matrix) { - return false; - } - ++mDrawingState.sequence; - mDrawingState.colorTransform = matrix; - mDrawingState.hasColorTransform = matrix != identityMatrix; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -mat4 Layer::getColorTransform() const { - mat4 colorTransform = mat4(getDrawingState().colorTransform); - if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) { - colorTransform = parent->getColorTransform() * colorTransform; - } - return colorTransform; -} - -bool Layer::hasColorTransform() const { - bool hasColorTransform = getDrawingState().hasColorTransform; - if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) { - hasColorTransform = hasColorTransform || parent->hasColorTransform(); - } - return hasColorTransform; -} - -bool Layer::isLegacyDataSpace() const { - // return true when no higher bits are set - return !(getDataSpace() & - (ui::Dataspace::STANDARD_MASK | ui::Dataspace::TRANSFER_MASK | - ui::Dataspace::RANGE_MASK)); -} - -void Layer::setParent(const sp<Layer>& layer) { - mCurrentParent = layer; -} - -int32_t Layer::getZ(LayerVector::StateSet) const { - return mDrawingState.z; -} - -bool Layer::usingRelativeZ(LayerVector::StateSet stateSet) const { - const bool useDrawing = stateSet == LayerVector::StateSet::Drawing; - const State& state = useDrawing ? mDrawingState : mDrawingState; - return state.isRelativeOf; -} - -__attribute__((no_sanitize("unsigned-integer-overflow"))) LayerVector Layer::makeTraversalList( - LayerVector::StateSet stateSet, bool* outSkipRelativeZUsers) { - LOG_ALWAYS_FATAL_IF(stateSet == LayerVector::StateSet::Invalid, - "makeTraversalList received invalid stateSet"); - const bool useDrawing = stateSet == LayerVector::StateSet::Drawing; - const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren; - const State& state = useDrawing ? mDrawingState : mDrawingState; - - if (state.zOrderRelatives.size() == 0) { - *outSkipRelativeZUsers = true; - return children; - } - - LayerVector traverse(stateSet); - for (const wp<Layer>& weakRelative : state.zOrderRelatives) { - sp<Layer> strongRelative = weakRelative.promote(); - if (strongRelative != nullptr) { - traverse.add(strongRelative); - } - } - - for (const sp<Layer>& child : children) { - if (child->usingRelativeZ(stateSet)) { - continue; - } - traverse.add(child); - } - - return traverse; -} - -ui::Transform Layer::getTransform() const { - return mEffectiveTransform; -} - -bool Layer::isTransformValid() const { - float transformDet = getTransform().det(); - return transformDet != 0 && !isinf(transformDet) && !isnan(transformDet); -} - -half Layer::getAlpha() const { - const auto& p = mDrawingParent.promote(); - - half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf; - return parentAlpha * getDrawingState().color.a; -} - -ui::Transform::RotationFlags Layer::getFixedTransformHint() const { - ui::Transform::RotationFlags fixedTransformHint = mDrawingState.fixedTransformHint; - if (fixedTransformHint != ui::Transform::ROT_INVALID) { - return fixedTransformHint; - } - const auto& p = mCurrentParent.promote(); - if (!p) return fixedTransformHint; - return p->getFixedTransformHint(); -} - -half4 Layer::getColor() const { - const half4 color(getDrawingState().color); - return half4(color.r, color.g, color.b, getAlpha()); -} - -int32_t Layer::getBackgroundBlurRadius() const { - if (getDrawingState().backgroundBlurRadius == 0) { - return 0; - } - - const auto& p = mDrawingParent.promote(); - half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf; - return parentAlpha * getDrawingState().backgroundBlurRadius; -} - -const std::vector<BlurRegion> Layer::getBlurRegions() const { - auto regionsCopy(getDrawingState().blurRegions); - float layerAlpha = getAlpha(); - for (auto& region : regionsCopy) { - region.alpha = region.alpha * layerAlpha; - } - return regionsCopy; -} - -RoundedCornerState Layer::getRoundedCornerState() const { - // Today's DPUs cannot do rounded corners. If RenderEngine cannot render - // protected content, remove rounded corners from protected content so it - // can be rendered by the DPU. - if (isProtected() && !mFlinger->getRenderEngine().supportsProtectedContent()) { - return {}; - } - - // Get parent settings - RoundedCornerState parentSettings; - const auto& parent = mDrawingParent.promote(); - if (parent != nullptr) { - parentSettings = parent->getRoundedCornerState(); - if (parentSettings.hasRoundedCorners()) { - ui::Transform t = getActiveTransform(getDrawingState()); - t = t.inverse(); - parentSettings.cropRect = t.transform(parentSettings.cropRect); - parentSettings.radius.x *= t.getScaleX(); - parentSettings.radius.y *= t.getScaleY(); - } - } - - // Get layer settings - Rect layerCropRect = getCroppedBufferSize(getDrawingState()); - const vec2 radius(getDrawingState().cornerRadius, getDrawingState().cornerRadius); - RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius); - const bool layerSettingsValid = layerSettings.hasRoundedCorners() && layerCropRect.isValid(); - - if (layerSettingsValid && parentSettings.hasRoundedCorners()) { - // If the parent and the layer have rounded corner settings, use the parent settings if the - // parent crop is entirely inside the layer crop. - // This has limitations and cause rendering artifacts. See b/200300845 for correct fix. - if (parentSettings.cropRect.left > layerCropRect.left && - parentSettings.cropRect.top > layerCropRect.top && - parentSettings.cropRect.right < layerCropRect.right && - parentSettings.cropRect.bottom < layerCropRect.bottom) { - return parentSettings; - } else { - return layerSettings; - } - } else if (layerSettingsValid) { - return layerSettings; - } else if (parentSettings.hasRoundedCorners()) { - return parentSettings; - } - return {}; -} - -bool Layer::findInHierarchy(const sp<Layer>& l) { - if (l == this) { - return true; - } - for (auto& child : mDrawingChildren) { - if (child->findInHierarchy(l)) { - return true; - } - } - return false; -} - -void Layer::setInputInfo(const WindowInfo& info) { - mDrawingState.inputInfo = info; - mDrawingState.touchableRegionCrop = - LayerHandle::getLayer(info.touchableRegionCropHandle.promote()); - mDrawingState.modified = true; - mFlinger->mUpdateInputInfo = true; - setTransactionFlags(eTransactionNeeded); -} - -perfetto::protos::LayerProto* Layer::writeToProto(perfetto::protos::LayersProto& layersProto, - uint32_t traceFlags) { - perfetto::protos::LayerProto* layerProto = layersProto.add_layers(); - writeToProtoDrawingState(layerProto); - writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags); - - if (traceFlags & LayerTracing::TRACE_COMPOSITION) { - ui::LayerStack layerStack = - (mSnapshot) ? mSnapshot->outputFilter.layerStack : ui::INVALID_LAYER_STACK; - writeCompositionStateToProto(layerProto, layerStack); - } - - for (const sp<Layer>& layer : mDrawingChildren) { - layer->writeToProto(layersProto, traceFlags); - } - - return layerProto; -} - void Layer::writeCompositionStateToProto(perfetto::protos::LayerProto* layerProto, ui::LayerStack layerStack) { ftl::FakeGuard guard(mFlinger->mStateLock); // Called from the main thread. @@ -1550,352 +660,6 @@ void Layer::writeCompositionStateToProto(perfetto::protos::LayerProto* layerProt } } -void Layer::writeToProtoDrawingState(perfetto::protos::LayerProto* layerInfo) { - const ui::Transform transform = getTransform(); - auto buffer = getExternalTexture(); - if (buffer != nullptr) { - LayerProtoHelper::writeToProto(*buffer, - [&]() { return layerInfo->mutable_active_buffer(); }); - LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()), - layerInfo->mutable_buffer_transform()); - } - layerInfo->set_invalidate(contentDirty); - layerInfo->set_is_protected(isProtected()); - layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(getDataSpace()))); - layerInfo->set_queued_frames(getQueuedFrameCount()); - layerInfo->set_curr_frame(mCurrentFrameNumber); - layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius); - layerInfo->set_corner_radius( - (getRoundedCornerState().radius.x + getRoundedCornerState().radius.y) / 2.0); - layerInfo->set_background_blur_radius(getBackgroundBlurRadius()); - layerInfo->set_is_trusted_overlay(isTrustedOverlay()); - LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform()); - LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), - [&]() { return layerInfo->mutable_position(); }); - LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); - LayerProtoHelper::writeToProto(surfaceDamageRegion, - [&]() { return layerInfo->mutable_damage_region(); }); - - if (hasColorTransform()) { - LayerProtoHelper::writeToProto(getColorTransform(), layerInfo->mutable_color_transform()); - } - - LayerProtoHelper::writeToProto(mSourceBounds, - [&]() { return layerInfo->mutable_source_bounds(); }); - LayerProtoHelper::writeToProto(mScreenBounds, - [&]() { return layerInfo->mutable_screen_bounds(); }); - LayerProtoHelper::writeToProto(getRoundedCornerState().cropRect, - [&]() { return layerInfo->mutable_corner_radius_crop(); }); - layerInfo->set_shadow_radius(mEffectiveShadowRadius); -} - -void Layer::writeToProtoCommonState(perfetto::protos::LayerProto* layerInfo, - LayerVector::StateSet stateSet, uint32_t traceFlags) { - const bool useDrawing = stateSet == LayerVector::StateSet::Drawing; - const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren; - const State& state = useDrawing ? mDrawingState : mDrawingState; - - ui::Transform requestedTransform = state.transform; - - layerInfo->set_id(sequence); - layerInfo->set_name(getName().c_str()); - layerInfo->set_type(getType()); - - for (const auto& child : children) { - layerInfo->add_children(child->sequence); - } - - for (const wp<Layer>& weakRelative : state.zOrderRelatives) { - sp<Layer> strongRelative = weakRelative.promote(); - if (strongRelative != nullptr) { - layerInfo->add_relatives(strongRelative->sequence); - } - } - - LayerProtoHelper::writeToProto(state.transparentRegionHint, - [&]() { return layerInfo->mutable_transparent_region(); }); - - layerInfo->set_layer_stack(getLayerStack().id); - layerInfo->set_z(state.z); - - LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() { - return layerInfo->mutable_requested_position(); - }); - - LayerProtoHelper::writeToProto(state.crop, [&]() { return layerInfo->mutable_crop(); }); - - layerInfo->set_is_opaque(isOpaque(state)); - - layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat())); - LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); }); - LayerProtoHelper::writeToProto(state.color, - [&]() { return layerInfo->mutable_requested_color(); }); - layerInfo->set_flags(state.flags); - - LayerProtoHelper::writeToProtoDeprecated(requestedTransform, - layerInfo->mutable_requested_transform()); - - auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote(); - if (parent != nullptr) { - layerInfo->set_parent(parent->sequence); - } - - auto zOrderRelativeOf = state.zOrderRelativeOf.promote(); - if (zOrderRelativeOf != nullptr) { - layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence); - } - - layerInfo->set_is_relative_of(state.isRelativeOf); - - layerInfo->set_owner_uid(mOwnerUid); - - if ((traceFlags & LayerTracing::TRACE_INPUT) && needsInputInfo()) { - WindowInfo info; - if (useDrawing) { - info = fillInputInfo( - InputDisplayArgs{.transform = &kIdentityTransform, .isSecure = true}); - } else { - info = state.inputInfo; - } - - LayerProtoHelper::writeToProto(info, state.touchableRegionCrop, - [&]() { return layerInfo->mutable_input_window_info(); }); - } - - if (traceFlags & LayerTracing::TRACE_EXTRA) { - auto protoMap = layerInfo->mutable_metadata(); - for (const auto& entry : state.metadata.mMap) { - (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend()); - } - } - - LayerProtoHelper::writeToProto(state.destinationFrame, - [&]() { return layerInfo->mutable_destination_frame(); }); -} - -// Applies the given transform to the region, while protecting against overflows caused by any -// offsets. If applying the offset in the transform to any of the Rects in the region would result -// in an overflow, they are not added to the output Region. -static Region transformTouchableRegionSafely(const ui::Transform& t, const Region& r, - const std::string& debugWindowName) { - // Round the translation using the same rounding strategy used by ui::Transform. - const auto tx = static_cast<int32_t>(t.tx() + 0.5); - const auto ty = static_cast<int32_t>(t.ty() + 0.5); - - ui::Transform transformWithoutOffset = t; - transformWithoutOffset.set(0.f, 0.f); - - const Region transformed = transformWithoutOffset.transform(r); - - // Apply the translation to each of the Rects in the region while discarding any that overflow. - Region ret; - for (const auto& rect : transformed) { - Rect newRect; - if (__builtin_add_overflow(rect.left, tx, &newRect.left) || - __builtin_add_overflow(rect.top, ty, &newRect.top) || - __builtin_add_overflow(rect.right, tx, &newRect.right) || - __builtin_add_overflow(rect.bottom, ty, &newRect.bottom)) { - ALOGE("Applying transform to touchable region of window '%s' resulted in an overflow.", - debugWindowName.c_str()); - continue; - } - ret.orSelf(newRect); - } - return ret; -} - -void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) { - auto [inputBounds, inputBoundsValid] = getInputBounds(/*fillParentBounds=*/false); - if (!inputBoundsValid) { - info.touchableRegion.clear(); - } - - info.frame = getInputBoundsInDisplaySpace(inputBounds, screenToDisplay); - - ui::Transform inputToLayer; - inputToLayer.set(inputBounds.left, inputBounds.top); - const ui::Transform layerToScreen = getInputTransform(); - const ui::Transform inputToDisplay = screenToDisplay * layerToScreen * inputToLayer; - - // InputDispatcher expects a display-to-input transform. - info.transform = inputToDisplay.inverse(); - - // The touchable region is specified in the input coordinate space. Change it to display space. - info.touchableRegion = - transformTouchableRegionSafely(inputToDisplay, info.touchableRegion, mName); -} - -void Layer::fillTouchOcclusionMode(WindowInfo& info) { - sp<Layer> p = sp<Layer>::fromExisting(this); - while (p != nullptr && !p->hasInputInfo()) { - p = p->mDrawingParent.promote(); - } - if (p != nullptr) { - info.touchOcclusionMode = p->mDrawingState.inputInfo.touchOcclusionMode; - } -} - -gui::DropInputMode Layer::getDropInputMode() const { - gui::DropInputMode mode = mDrawingState.dropInputMode; - if (mode == gui::DropInputMode::ALL) { - return mode; - } - sp<Layer> parent = mDrawingParent.promote(); - if (parent) { - gui::DropInputMode parentMode = parent->getDropInputMode(); - if (parentMode != gui::DropInputMode::NONE) { - return parentMode; - } - } - return mode; -} - -void Layer::handleDropInputMode(gui::WindowInfo& info) const { - if (mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) { - return; - } - - // Check if we need to drop input unconditionally - gui::DropInputMode dropInputMode = getDropInputMode(); - if (dropInputMode == gui::DropInputMode::ALL) { - info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT; - ALOGV("Dropping input for %s as requested by policy.", getDebugName()); - return; - } - - // Check if we need to check if the window is obscured by parent - if (dropInputMode != gui::DropInputMode::OBSCURED) { - return; - } - - // Check if the parent has set an alpha on the layer - sp<Layer> parent = mDrawingParent.promote(); - if (parent && parent->getAlpha() != 1.0_hf) { - info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT; - ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(), - static_cast<float>(getAlpha())); - } - - // Check if the parent has cropped the buffer - Rect bufferSize = getCroppedBufferSize(getDrawingState()); - if (!bufferSize.isValid()) { - info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED; - return; - } - - // Screenbounds are the layer bounds cropped by parents, transformed to screenspace. - // To check if the layer has been cropped, we take the buffer bounds, apply the local - // layer crop and apply the same set of transforms to move to screenspace. If the bounds - // match then the layer has not been cropped by its parents. - Rect bufferInScreenSpace(getTransform().transform(bufferSize)); - bool croppedByParent = bufferInScreenSpace != Rect{mScreenBounds}; - - if (croppedByParent) { - info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT; - ALOGV("Dropping input for %s as requested by policy because buffer is cropped by parent", - getDebugName()); - } else { - // If the layer is not obscured by its parents (by setting an alpha or crop), then only drop - // input if the window is obscured. This check should be done in surfaceflinger but the - // logic currently resides in inputflinger. So pass the if_obscured check to input to only - // drop input events if the window is obscured. - info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED; - } -} - -WindowInfo Layer::fillInputInfo(const InputDisplayArgs& displayArgs) { - if (!hasInputInfo()) { - mDrawingState.inputInfo.name = getName(); - mDrawingState.inputInfo.ownerUid = gui::Uid{mOwnerUid}; - mDrawingState.inputInfo.ownerPid = gui::Pid{mOwnerPid}; - mDrawingState.inputInfo.inputConfig |= WindowInfo::InputConfig::NO_INPUT_CHANNEL; - mDrawingState.inputInfo.displayId = toLogicalDisplayId(getLayerStack()); - } - - const ui::Transform& displayTransform = - displayArgs.transform != nullptr ? *displayArgs.transform : kIdentityTransform; - - WindowInfo info = mDrawingState.inputInfo; - info.id = sequence; - info.displayId = toLogicalDisplayId(getLayerStack()); - - fillInputFrameInfo(info, displayTransform); - - if (displayArgs.transform == nullptr) { - // Do not let the window receive touches if it is not associated with a valid display - // transform. We still allow the window to receive keys and prevent ANRs. - info.inputConfig |= WindowInfo::InputConfig::NOT_TOUCHABLE; - } - - info.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !isVisibleForInput()); - - info.alpha = getAlpha(); - fillTouchOcclusionMode(info); - handleDropInputMode(info); - - // If the window will be blacked out on a display because the display does not have the secure - // flag and the layer has the secure flag set, then drop input. - if (!displayArgs.isSecure && isSecure()) { - info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT; - } - - sp<Layer> cropLayer = mDrawingState.touchableRegionCrop.promote(); - if (info.replaceTouchableRegionWithCrop) { - Rect inputBoundsInDisplaySpace; - if (!cropLayer) { - FloatRect inputBounds = getInputBounds(/*fillParentBounds=*/true).first; - inputBoundsInDisplaySpace = getInputBoundsInDisplaySpace(inputBounds, displayTransform); - } else { - FloatRect inputBounds = cropLayer->getInputBounds(/*fillParentBounds=*/true).first; - inputBoundsInDisplaySpace = - cropLayer->getInputBoundsInDisplaySpace(inputBounds, displayTransform); - } - info.touchableRegion = Region(inputBoundsInDisplaySpace); - } else if (cropLayer != nullptr) { - FloatRect inputBounds = cropLayer->getInputBounds(/*fillParentBounds=*/true).first; - Rect inputBoundsInDisplaySpace = - cropLayer->getInputBoundsInDisplaySpace(inputBounds, displayTransform); - info.touchableRegion = info.touchableRegion.intersect(inputBoundsInDisplaySpace); - } - - // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state - // if it was set by WM for a known system overlay - if (isTrustedOverlay()) { - info.inputConfig |= WindowInfo::InputConfig::TRUSTED_OVERLAY; - } - - Rect bufferSize = getBufferSize(getDrawingState()); - info.contentSize = Size(bufferSize.width(), bufferSize.height()); - - return info; -} - -Rect Layer::getInputBoundsInDisplaySpace(const FloatRect& inputBounds, - const ui::Transform& screenToDisplay) { - // InputDispatcher works in the display device's coordinate space. Here, we calculate the - // frame and transform used for the layer, which determines the bounds and the coordinate space - // within which the layer will receive input. - - // Coordinate space definitions: - // - display: The display device's coordinate space. Correlates to pixels on the display. - // - screen: The post-rotation coordinate space for the display, a.k.a. logical display space. - // - layer: The coordinate space of this layer. - // - input: The coordinate space in which this layer will receive input events. This could be - // different than layer space if a surfaceInset is used, which changes the origin - // of the input space. - - // Crop the input bounds to ensure it is within the parent's bounds. - const FloatRect croppedInputBounds = mBounds.intersect(inputBounds); - const ui::Transform layerToScreen = getInputTransform(); - const ui::Transform layerToDisplay = screenToDisplay * layerToScreen; - return Rect{layerToDisplay.transform(croppedInputBounds)}; -} - -bool Layer::hasInputInfo() const { - return mDrawingState.inputInfo.token != nullptr || - mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL); -} - compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( const DisplayDevice* display) const { if (!display) return nullptr; @@ -1930,24 +694,6 @@ Region Layer::getVisibleRegion(const DisplayDevice* display) const { return outputLayer ? outputLayer->getState().visibleRegion : Region(); } -bool Layer::isInternalDisplayOverlay() const { - const State& s(mDrawingState); - if (s.flags & layer_state_t::eLayerSkipScreenshot) { - return true; - } - - sp<Layer> parent = mDrawingParent.promote(); - return parent && parent->isInternalDisplayOverlay(); -} - -bool Layer::setDropInputMode(gui::DropInputMode mode) { - if (mDrawingState.dropInputMode == mode) { - return false; - } - mDrawingState.dropInputMode = mode; - return true; -} - void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, const sp<GraphicBuffer>& buffer, uint64_t framenumber, const sp<Fence>& releaseFence) { @@ -2023,6 +769,10 @@ void Layer::prepareReleaseCallbacks(ftl::Future<FenceResult> futureFenceResult, // Older fences for the same layer stack can be dropped when a new fence arrives. // An assumption here is that RenderEngine performs work sequentially, so an // incoming fence will not fire before an existing fence. + SFTRACE_NAME( + ftl::Concat("Adding additional fence for: ", ftl::truncated<20>(mName.c_str()), + ", Replacing?: ", mAdditionalPreviousReleaseFences.contains(layerStack)) + .c_str()); mAdditionalPreviousReleaseFences.emplace_or_replace(layerStack, std::move(futureFenceResult)); } @@ -2106,17 +856,9 @@ void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) { mDrawingState.callbackHandles = {}; } -bool Layer::willPresentCurrentTransaction() const { - // Returns true if the most recent Transaction applied to CurrentState will be presented. - return (getSidebandStreamChanged() || getAutoRefresh() || - (mDrawingState.modified && - (mDrawingState.buffer != nullptr || mDrawingState.bgColorLayer != nullptr))); -} - bool Layer::setTransform(uint32_t transform) { if (mDrawingState.bufferTransform == transform) return false; mDrawingState.bufferTransform = transform; - mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } @@ -2125,7 +867,6 @@ bool Layer::setTransformToDisplayInverse(bool transformToDisplayInverse) { if (mDrawingState.transformToDisplayInverse == transformToDisplayInverse) return false; mDrawingState.sequence++; mDrawingState.transformToDisplayInverse = transformToDisplayInverse; - mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } @@ -2136,100 +877,10 @@ bool Layer::setBufferCrop(const Rect& bufferCrop) { mDrawingState.sequence++; mDrawingState.bufferCrop = bufferCrop; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setDestinationFrame(const Rect& destinationFrame) { - if (mDrawingState.destinationFrame == destinationFrame) return false; - - mDrawingState.sequence++; - mDrawingState.destinationFrame = destinationFrame; - - mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } -// Translate destination frame into scale and position. If a destination frame is not set, use the -// provided scale and position -bool Layer::updateGeometry() { - if ((mDrawingState.flags & layer_state_t::eIgnoreDestinationFrame) || - mDrawingState.destinationFrame.isEmpty()) { - // If destination frame is not set, use the requested transform set via - // Layer::setPosition and Layer::setMatrix. - return assignTransform(&mDrawingState.transform, mRequestedTransform); - } - - Rect destRect = mDrawingState.destinationFrame; - int32_t destW = destRect.width(); - int32_t destH = destRect.height(); - if (destRect.left < 0) { - destRect.left = 0; - destRect.right = destW; - } - if (destRect.top < 0) { - destRect.top = 0; - destRect.bottom = destH; - } - - if (!mDrawingState.buffer) { - ui::Transform t; - t.set(destRect.left, destRect.top); - return assignTransform(&mDrawingState.transform, t); - } - - uint32_t bufferWidth = mDrawingState.buffer->getWidth(); - uint32_t bufferHeight = mDrawingState.buffer->getHeight(); - // Undo any transformations on the buffer. - if (mDrawingState.bufferTransform & ui::Transform::ROT_90) { - std::swap(bufferWidth, bufferHeight); - } - uint32_t invTransform = SurfaceFlinger::getActiveDisplayRotationFlags(); - if (mDrawingState.transformToDisplayInverse) { - if (invTransform & ui::Transform::ROT_90) { - std::swap(bufferWidth, bufferHeight); - } - } - - float sx = destW / static_cast<float>(bufferWidth); - float sy = destH / static_cast<float>(bufferHeight); - ui::Transform t; - t.set(sx, 0, 0, sy); - t.set(destRect.left, destRect.top); - return assignTransform(&mDrawingState.transform, t); -} - -bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) { - if (mRequestedTransform.dsdx() == matrix.dsdx && mRequestedTransform.dtdy() == matrix.dtdy && - mRequestedTransform.dtdx() == matrix.dtdx && mRequestedTransform.dsdy() == matrix.dsdy) { - return false; - } - - mRequestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); - - mDrawingState.sequence++; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - - return true; -} - -bool Layer::setPosition(float x, float y) { - if (mRequestedTransform.tx() == x && mRequestedTransform.ty() == y) { - return false; - } - - mRequestedTransform.set(x, y); - - mDrawingState.sequence++; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - - return true; -} - void Layer::releasePreviousBuffer() { mReleasePreviousBuffer = true; if (!mBufferInfo.mBuffer || @@ -2293,7 +944,6 @@ bool Layer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer, mDrawingState.isAutoTimestamp = isAutoTimestamp; mDrawingState.latchedVsyncId = info.vsyncId; mDrawingState.useVsyncIdForRefreshRateSelection = info.useForRefreshRateSelection; - mDrawingState.modified = true; if (!buffer) { resetDrawingStateBufferInfo(); setTransactionFlags(eTransactionNeeded); @@ -2441,7 +1091,6 @@ void Layer::recordLayerHistoryAnimationTx(const scheduler::LayerProps& layerProp bool Layer::setDataspace(ui::Dataspace dataspace) { if (mDrawingState.dataspace == dataspace) return false; mDrawingState.dataspace = dataspace; - mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } @@ -2452,7 +1101,6 @@ bool Layer::setExtendedRangeBrightness(float currentBufferRatio, float desiredRa return false; mDrawingState.currentHdrSdrRatio = currentBufferRatio; mDrawingState.desiredHdrSdrRatio = desiredRatio; - mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } @@ -2460,40 +1108,6 @@ bool Layer::setExtendedRangeBrightness(float currentBufferRatio, float desiredRa bool Layer::setDesiredHdrHeadroom(float desiredRatio) { if (mDrawingState.desiredHdrSdrRatio == desiredRatio) return false; mDrawingState.desiredHdrSdrRatio = desiredRatio; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setCachingHint(gui::CachingHint cachingHint) { - if (mDrawingState.cachingHint == cachingHint) return false; - mDrawingState.cachingHint = cachingHint; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setHdrMetadata(const HdrMetadata& hdrMetadata) { - if (mDrawingState.hdrMetadata == hdrMetadata) return false; - mDrawingState.hdrMetadata = hdrMetadata; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::setSurfaceDamageRegion(const Region& surfaceDamage) { - if (mDrawingState.surfaceDamageRegion.hasSameRects(surfaceDamage)) return false; - mDrawingState.surfaceDamageRegion = surfaceDamage; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - setIsSmallDirty(surfaceDamage, getTransform()); - return true; -} - -bool Layer::setApi(int32_t api) { - if (mDrawingState.api == api) return false; - mDrawingState.api = api; - mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); return true; } @@ -2509,7 +1123,6 @@ bool Layer::setSidebandStream(const sp<NativeHandle>& sidebandStream, const Fram } mDrawingState.sidebandStream = sidebandStream; - mDrawingState.modified = true; if (sidebandStream != nullptr && mDrawingState.buffer != nullptr) { releasePreviousBuffer(); resetDrawingStateBufferInfo(); @@ -2606,14 +1219,6 @@ Rect Layer::getBufferSize(const State& /*s*/) const { return Rect(0, 0, static_cast<int32_t>(bufWidth), static_cast<int32_t>(bufHeight)); } -FloatRect Layer::computeSourceBounds(const FloatRect& parentBounds) const { - if (mBufferInfo.mBuffer == nullptr) { - return parentBounds; - } - - return getBufferSize(getDrawingState()).toFloatRect(); -} - bool Layer::fenceHasSignaled() const { if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { return true; @@ -2635,37 +1240,21 @@ void Layer::onPreComposition(nsecs_t refreshStartTime) { } } -void Layer::setAutoRefresh(bool autoRefresh) { - mDrawingState.autoRefresh = autoRefresh; -} - bool Layer::latchSidebandStream(bool& recomputeVisibleRegions) { - // We need to update the sideband stream if the layer has both a buffer and a sideband stream. - auto* snapshot = editLayerSnapshot(); - snapshot->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get(); - if (mSidebandStreamChanged.exchange(false)) { const State& s(getDrawingState()); // mSidebandStreamChanged was true mSidebandStream = s.sidebandStream; - snapshot->sidebandStream = mSidebandStream; if (mSidebandStream != nullptr) { setTransactionFlags(eTransactionNeeded); mFlinger->setTransactionFlags(eTraversalNeeded); } recomputeVisibleRegions = true; - return true; } return false; } -bool Layer::hasFrameUpdate() const { - const State& c(getDrawingState()); - return (mDrawingStateModified || mDrawingState.modified) && - (c.buffer != nullptr || c.bgColorLayer != nullptr); -} - void Layer::updateTexImage(nsecs_t latchTime, bool bgColorOnly) { const State& s(getDrawingState()); @@ -2712,8 +1301,6 @@ void Layer::updateTexImage(nsecs_t latchTime, bool bgColorOnly) { mFlinger->getTransactionCallbackInvoker() .addOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles); mDrawingState.callbackHandles = remainingHandles; - - mDrawingStateModified = false; } void Layer::gatherBufferInfo() { @@ -2737,7 +1324,6 @@ void Layer::gatherBufferInfo() { mBufferInfo.mFrameLatencyNeeded = true; mBufferInfo.mDesiredPresentTime = mDrawingState.desiredPresentTime; mBufferInfo.mFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence); - mBufferInfo.mFence = mDrawingState.acquireFence; mBufferInfo.mTransform = mDrawingState.bufferTransform; auto lastDataspace = mBufferInfo.mDataspace; mBufferInfo.mDataspace = translateDataspace(mDrawingState.dataspace); @@ -2785,10 +1371,6 @@ void Layer::gatherBufferInfo() { mFlinger->mHdrLayerInfoChanged = true; } mBufferInfo.mCrop = computeBufferCrop(mDrawingState); - mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; - mBufferInfo.mSurfaceDamage = mDrawingState.surfaceDamageRegion; - mBufferInfo.mHdrMetadata = mDrawingState.hdrMetadata; - mBufferInfo.mApi = mDrawingState.api; mBufferInfo.mTransformToDisplayInverse = mDrawingState.transformToDisplayInverse; } @@ -2813,294 +1395,6 @@ void Layer::tracePendingBufferCount(int32_t pendingBuffers) { SFTRACE_INT(mBlastTransactionName.c_str(), pendingBuffers); } -/* - * We don't want to send the layer's transform to input, but rather the - * parent's transform. This is because Layer's transform is - * information about how the buffer is placed on screen. The parent's - * transform makes more sense to send since it's information about how the - * layer is placed on screen. This transform is used by input to determine - * how to go from screen space back to window space. - */ -ui::Transform Layer::getInputTransform() const { - if (!hasBufferOrSidebandStream()) { - return getTransform(); - } - sp<Layer> parent = mDrawingParent.promote(); - if (parent == nullptr) { - return ui::Transform(); - } - - return parent->getTransform(); -} - -/** - * Returns the bounds used to fill the input frame and the touchable region. - * - * Similar to getInputTransform, we need to update the bounds to include the transform. - * This is because bounds don't include the buffer transform, where the input assumes - * that's already included. - */ -std::pair<FloatRect, bool> Layer::getInputBounds(bool fillParentBounds) const { - Rect croppedBufferSize = getCroppedBufferSize(getDrawingState()); - FloatRect inputBounds = croppedBufferSize.toFloatRect(); - if (hasBufferOrSidebandStream() && croppedBufferSize.isValid() && - mDrawingState.transform.getType() != ui::Transform::IDENTITY) { - inputBounds = mDrawingState.transform.transform(inputBounds); - } - - bool inputBoundsValid = croppedBufferSize.isValid(); - if (!inputBoundsValid) { - /** - * Input bounds are based on the layer crop or buffer size. But if we are using - * the layer bounds as the input bounds (replaceTouchableRegionWithCrop flag) then - * we can use the parent bounds as the input bounds if the layer does not have buffer - * or a crop. We want to unify this logic but because of compat reasons we cannot always - * use the parent bounds. A layer without a buffer can get input. So when a window is - * initially added, its touchable region can fill its parent layer bounds and that can - * have negative consequences. - */ - inputBounds = fillParentBounds ? mBounds : FloatRect{}; - } - - // Clamp surface inset to the input bounds. - const float inset = static_cast<float>(mDrawingState.inputInfo.surfaceInset); - const float xSurfaceInset = std::clamp(inset, 0.f, inputBounds.getWidth() / 2.f); - const float ySurfaceInset = std::clamp(inset, 0.f, inputBounds.getHeight() / 2.f); - - // Apply the insets to the input bounds. - inputBounds.left += xSurfaceInset; - inputBounds.top += ySurfaceInset; - inputBounds.right -= xSurfaceInset; - inputBounds.bottom -= ySurfaceInset; - - return {inputBounds, inputBoundsValid}; -} - -bool Layer::isSimpleBufferUpdate(const layer_state_t& s) const { - const uint64_t requiredFlags = layer_state_t::eBufferChanged; - - const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged | - layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged | - layer_state_t::eFlagsChanged | layer_state_t::eBlurRegionsChanged | - layer_state_t::eLayerStackChanged | layer_state_t::eReparent | - (FlagManager::getInstance().latch_unsignaled_with_auto_refresh_changed() - ? 0 - : layer_state_t::eAutoRefreshChanged); - - if ((s.what & requiredFlags) != requiredFlags) { - SFTRACE_FORMAT_INSTANT("%s: false [missing required flags 0x%" PRIx64 "]", __func__, - (s.what | requiredFlags) & ~s.what); - return false; - } - - if (s.what & deniedFlags) { - SFTRACE_FORMAT_INSTANT("%s: false [has denied flags 0x%" PRIx64 "]", __func__, - s.what & deniedFlags); - return false; - } - - if (s.what & layer_state_t::ePositionChanged) { - if (mRequestedTransform.tx() != s.x || mRequestedTransform.ty() != s.y) { - SFTRACE_FORMAT_INSTANT("%s: false [ePositionChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eAlphaChanged) { - if (mDrawingState.color.a != s.color.a) { - SFTRACE_FORMAT_INSTANT("%s: false [eAlphaChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eColorTransformChanged) { - if (mDrawingState.colorTransform != s.colorTransform) { - SFTRACE_FORMAT_INSTANT("%s: false [eColorTransformChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eBackgroundColorChanged) { - if (mDrawingState.bgColorLayer || s.bgColor.a != 0) { - SFTRACE_FORMAT_INSTANT("%s: false [eBackgroundColorChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eMatrixChanged) { - if (mRequestedTransform.dsdx() != s.matrix.dsdx || - mRequestedTransform.dtdy() != s.matrix.dtdy || - mRequestedTransform.dtdx() != s.matrix.dtdx || - mRequestedTransform.dsdy() != s.matrix.dsdy) { - SFTRACE_FORMAT_INSTANT("%s: false [eMatrixChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eCornerRadiusChanged) { - if (mDrawingState.cornerRadius != s.cornerRadius) { - SFTRACE_FORMAT_INSTANT("%s: false [eCornerRadiusChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eBackgroundBlurRadiusChanged) { - if (mDrawingState.backgroundBlurRadius != static_cast<int>(s.backgroundBlurRadius)) { - SFTRACE_FORMAT_INSTANT("%s: false [eBackgroundBlurRadiusChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eBufferTransformChanged) { - if (mDrawingState.bufferTransform != s.bufferTransform) { - SFTRACE_FORMAT_INSTANT("%s: false [eBufferTransformChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eTransformToDisplayInverseChanged) { - if (mDrawingState.transformToDisplayInverse != s.transformToDisplayInverse) { - SFTRACE_FORMAT_INSTANT("%s: false [eTransformToDisplayInverseChanged changed]", - __func__); - return false; - } - } - - if (s.what & layer_state_t::eCropChanged) { - if (mDrawingState.crop != s.crop) { - SFTRACE_FORMAT_INSTANT("%s: false [eCropChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eDataspaceChanged) { - if (mDrawingState.dataspace != s.dataspace) { - SFTRACE_FORMAT_INSTANT("%s: false [eDataspaceChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eHdrMetadataChanged) { - if (mDrawingState.hdrMetadata != s.hdrMetadata) { - SFTRACE_FORMAT_INSTANT("%s: false [eHdrMetadataChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eSidebandStreamChanged) { - if (mDrawingState.sidebandStream != s.sidebandStream) { - SFTRACE_FORMAT_INSTANT("%s: false [eSidebandStreamChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eColorSpaceAgnosticChanged) { - if (mDrawingState.colorSpaceAgnostic != s.colorSpaceAgnostic) { - SFTRACE_FORMAT_INSTANT("%s: false [eColorSpaceAgnosticChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eShadowRadiusChanged) { - if (mDrawingState.shadowRadius != s.shadowRadius) { - SFTRACE_FORMAT_INSTANT("%s: false [eShadowRadiusChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eFixedTransformHintChanged) { - if (mDrawingState.fixedTransformHint != s.fixedTransformHint) { - SFTRACE_FORMAT_INSTANT("%s: false [eFixedTransformHintChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eTrustedOverlayChanged) { - if (mDrawingState.isTrustedOverlay != (s.trustedOverlay == gui::TrustedOverlay::ENABLED)) { - SFTRACE_FORMAT_INSTANT("%s: false [eTrustedOverlayChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eStretchChanged) { - StretchEffect temp = s.stretchEffect; - temp.sanitize(); - if (mDrawingState.stretchEffect != temp) { - SFTRACE_FORMAT_INSTANT("%s: false [eStretchChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eBufferCropChanged) { - if (mDrawingState.bufferCrop != s.bufferCrop) { - SFTRACE_FORMAT_INSTANT("%s: false [eBufferCropChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eDestinationFrameChanged) { - if (mDrawingState.destinationFrame != s.destinationFrame) { - SFTRACE_FORMAT_INSTANT("%s: false [eDestinationFrameChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eDimmingEnabledChanged) { - if (mDrawingState.dimmingEnabled != s.dimmingEnabled) { - SFTRACE_FORMAT_INSTANT("%s: false [eDimmingEnabledChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eExtendedRangeBrightnessChanged) { - if (mDrawingState.currentHdrSdrRatio != s.currentHdrSdrRatio || - mDrawingState.desiredHdrSdrRatio != s.desiredHdrSdrRatio) { - SFTRACE_FORMAT_INSTANT("%s: false [eExtendedRangeBrightnessChanged changed]", __func__); - return false; - } - } - - if (s.what & layer_state_t::eDesiredHdrHeadroomChanged) { - if (mDrawingState.desiredHdrSdrRatio != s.desiredHdrSdrRatio) { - SFTRACE_FORMAT_INSTANT("%s: false [eDesiredHdrHeadroomChanged changed]", __func__); - return false; - } - } - - return true; -} - -sp<LayerFE> Layer::getCompositionEngineLayerFE() const { - // There's no need to get a CE Layer if the layer isn't going to draw anything. - return hasSomethingToDraw() ? mLegacyLayerFE : nullptr; -} - -const LayerSnapshot* Layer::getLayerSnapshot() const { - return mSnapshot.get(); -} - -LayerSnapshot* Layer::editLayerSnapshot() { - return mSnapshot.get(); -} - -std::unique_ptr<frontend::LayerSnapshot> Layer::stealLayerSnapshot() { - return std::move(mSnapshot); -} - -void Layer::updateLayerSnapshot(std::unique_ptr<frontend::LayerSnapshot> snapshot) { - mSnapshot = std::move(snapshot); -} - -const compositionengine::LayerFECompositionState* Layer::getCompositionState() const { - return mSnapshot.get(); -} - -sp<LayerFE> Layer::copyCompositionEngineLayerFE() const { - auto result = mFlinger->getFactory().createLayerFE(mName, this); - result->mSnapshot = std::make_unique<LayerSnapshot>(*mSnapshot); - return result; -} - sp<LayerFE> Layer::getCompositionEngineLayerFE( const frontend::LayerHierarchy::TraversalPath& path) { for (auto& [p, layerFE] : mLayerFEs) { @@ -3113,55 +1407,6 @@ sp<LayerFE> Layer::getCompositionEngineLayerFE( return layerFE; } -void Layer::useSurfaceDamage() { - if (mFlinger->mForceFullDamage) { - surfaceDamageRegion = Region::INVALID_REGION; - } else { - surfaceDamageRegion = mBufferInfo.mSurfaceDamage; - } -} - -void Layer::useEmptyDamage() { - surfaceDamageRegion.clear(); -} - -bool Layer::isOpaque(const Layer::State& s) const { - // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the - // layer's opaque flag. - if (!hasSomethingToDraw()) { - return false; - } - - // if the layer has the opaque flag, then we're always opaque - if ((s.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque) { - return true; - } - - // If the buffer has no alpha channel, then we are opaque - if (hasBufferOrSidebandStream() && LayerSnapshot::isOpaqueFormat(getPixelFormat())) { - return true; - } - - // Lastly consider the layer opaque if drawing a color with alpha == 1.0 - return fillsColor() && getAlpha() == 1.0_hf; -} - -bool Layer::canReceiveInput() const { - return !isHiddenByPolicy() && (mBufferInfo.mBuffer == nullptr || getAlpha() > 0.0f); -} - -bool Layer::isVisible() const { - if (!hasSomethingToDraw()) { - return false; - } - - if (isHiddenByPolicy()) { - return false; - } - - return getAlpha() > 0.0f || hasBlur(); -} - void Layer::onCompositionPresented(const DisplayDevice* display, const std::shared_ptr<FenceTime>& glDoneFence, const std::shared_ptr<FenceTime>& presentFence, @@ -3254,11 +1499,6 @@ bool Layer::willReleaseBufferOnLatch() const { return !mDrawingState.buffer && mBufferInfo.mBuffer; } -bool Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) { - const bool bgColorOnly = mDrawingState.bgColorLayer != nullptr; - return latchBufferImpl(recomputeVisibleRegions, latchTime, bgColorOnly); -} - bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bool bgColorOnly) { SFTRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(), getDrawingState().frameNumber); @@ -3280,7 +1520,6 @@ bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bo // Capture the old state of the layer for comparisons later BufferInfo oldBufferInfo = mBufferInfo; - const bool oldOpacity = isOpaque(mDrawingState); mPreviousFrameNumber = mCurrentFrameNumber; mCurrentFrameNumber = mDrawingState.frameNumber; gatherBufferInfo(); @@ -3305,7 +1544,6 @@ bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bo if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) || (mBufferInfo.mTransform != oldBufferInfo.mTransform) || - (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) || (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) { recomputeVisibleRegions = true; } @@ -3318,35 +1556,14 @@ bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bo recomputeVisibleRegions = true; } } - - if (oldOpacity != isOpaque(mDrawingState)) { - recomputeVisibleRegions = true; - } - return true; } -bool Layer::hasReadyFrame() const { - return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh(); -} - bool Layer::isProtected() const { return (mBufferInfo.mBuffer != nullptr) && (mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED); } -void Layer::latchAndReleaseBuffer() { - if (hasReadyFrame()) { - bool ignored = false; - latchBuffer(ignored, systemTime()); - } - releasePendingBuffer(systemTime()); -} - -PixelFormat Layer::getPixelFormat() const { - return mBufferInfo.mPixelFormat; -} - bool Layer::getTransformToDisplayInverse() const { return mBufferInfo.mTransformToDisplayInverse; } @@ -3370,18 +1587,6 @@ uint32_t Layer::getBufferTransform() const { return mBufferInfo.mTransform; } -ui::Dataspace Layer::getDataSpace() const { - return hasBufferOrSidebandStream() ? mBufferInfo.mDataspace : mDrawingState.dataspace; -} - -bool Layer::isFrontBuffered() const { - if (mBufferInfo.mBuffer == nullptr) { - return false; - } - - return mBufferInfo.mBuffer->getUsage() & AHARDWAREBUFFER_USAGE_FRONT_BUFFER; -} - ui::Dataspace Layer::translateDataspace(ui::Dataspace dataspace) { ui::Dataspace updatedDataspace = dataspace; // translate legacy dataspaces to modern dataspaces @@ -3417,84 +1622,6 @@ sp<GraphicBuffer> Layer::getBuffer() const { return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr; } -const std::shared_ptr<renderengine::ExternalTexture>& Layer::getExternalTexture() const { - return mBufferInfo.mBuffer; -} - -bool Layer::setColor(const half3& color) { - if (mDrawingState.color.rgb == color) { - return false; - } - - mDrawingState.sequence++; - mDrawingState.color.rgb = color; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool Layer::fillsColor() const { - return !hasBufferOrSidebandStream() && mDrawingState.color.r >= 0.0_hf && - mDrawingState.color.g >= 0.0_hf && mDrawingState.color.b >= 0.0_hf; -} - -bool Layer::hasBlur() const { - return getBackgroundBlurRadius() > 0 || getDrawingState().blurRegions.size() > 0; -} - -void Layer::updateSnapshot(bool updateGeometry) { - if (!getCompositionEngineLayerFE()) { - return; - } - - auto* snapshot = editLayerSnapshot(); - if (updateGeometry) { - prepareBasicGeometryCompositionState(); - prepareGeometryCompositionState(); - snapshot->roundedCorner = getRoundedCornerState(); - snapshot->transformedBounds = mScreenBounds; - if (mEffectiveShadowRadius > 0.f) { - snapshot->shadowSettings = mFlinger->mDrawingState.globalShadowSettings; - - // Note: this preserves existing behavior of shadowing the entire layer and not cropping - // it if transparent regions are present. This may not be necessary since shadows are - // typically cast by layers without transparent regions. - snapshot->shadowSettings.boundaries = mBounds; - - const float casterAlpha = snapshot->alpha; - const bool casterIsOpaque = - ((mBufferInfo.mBuffer != nullptr) && isOpaque(mDrawingState)); - - // If the casting layer is translucent, we need to fill in the shadow underneath the - // layer. Otherwise the generated shadow will only be shown around the casting layer. - snapshot->shadowSettings.casterIsTranslucent = !casterIsOpaque || (casterAlpha < 1.0f); - snapshot->shadowSettings.ambientColor *= casterAlpha; - snapshot->shadowSettings.spotColor *= casterAlpha; - } - snapshot->shadowSettings.length = mEffectiveShadowRadius; - } - snapshot->contentOpaque = isOpaque(mDrawingState); - snapshot->layerOpaqueFlagSet = - (mDrawingState.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque; - sp<Layer> p = mDrawingParent.promote(); - if (p != nullptr) { - snapshot->parentTransform = p->getTransform(); - } else { - snapshot->parentTransform.reset(); - } - snapshot->bufferSize = getBufferSize(mDrawingState); - snapshot->externalTexture = mBufferInfo.mBuffer; - snapshot->hasReadyFrame = hasReadyFrame(); - preparePerFrameCompositionState(); -} - -void Layer::updateChildrenSnapshots(bool updateGeometry) { - for (const sp<Layer>& child : mDrawingChildren) { - child->updateSnapshot(updateGeometry); - child->updateChildrenSnapshots(updateGeometry); - } -} - bool Layer::setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds, TrustedPresentationListener const& listener) { bool hadTrustedPresentationListener = hasTrustedPresentationListener(); @@ -3527,35 +1654,32 @@ void Layer::updateLastLatchTime(nsecs_t latchTime) { mLastLatchTime = latchTime; } -void Layer::setIsSmallDirty(const Region& damageRegion, - const ui::Transform& layerToDisplayTransform) { - mSmallDirty = false; +void Layer::setIsSmallDirty(frontend::LayerSnapshot* snapshot) { if (!mFlinger->mScheduler->supportSmallDirtyDetection(mOwnerAppId)) { + snapshot->isSmallDirty = false; return; } if (mWindowType != WindowInfo::Type::APPLICATION && mWindowType != WindowInfo::Type::BASE_APPLICATION) { + snapshot->isSmallDirty = false; return; } - Rect bounds = damageRegion.getBounds(); + Rect bounds = snapshot->surfaceDamage.getBounds(); if (!bounds.isValid()) { + snapshot->isSmallDirty = false; return; } // Transform to screen space. - bounds = layerToDisplayTransform.transform(bounds); + bounds = snapshot->localTransform.transform(bounds); // If the damage region is a small dirty, this could give the hint for the layer history that // it could suppress the heuristic rate when calculating. - mSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(mOwnerAppId, - bounds.getWidth() * bounds.getHeight()); -} - -void Layer::setIsSmallDirty(frontend::LayerSnapshot* snapshot) { - setIsSmallDirty(snapshot->surfaceDamage, snapshot->localTransform); - snapshot->isSmallDirty = mSmallDirty; + snapshot->isSmallDirty = + mFlinger->mScheduler->isSmallDirtyArea(mOwnerAppId, + bounds.getWidth() * bounds.getHeight()); } } // namespace android diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 1e4f2dc296..9caa20cfb8 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -43,9 +43,7 @@ #include <scheduler/Fps.h> #include <scheduler/Seamlessness.h> -#include <chrono> #include <cstdint> -#include <list> #include <optional> #include <vector> @@ -56,7 +54,6 @@ #include "LayerVector.h" #include "Scheduler/LayerInfo.h" #include "SurfaceFlinger.h" -#include "Tracing/LayerTracing.h" #include "TransactionCallbackInvoker.h" using namespace android::surfaceflinger; @@ -97,42 +94,15 @@ public: eInputInfoChanged = 0x00000004 }; - struct Geometry { - uint32_t w; - uint32_t h; - ui::Transform transform; - - inline bool operator==(const Geometry& rhs) const { - return (w == rhs.w && h == rhs.h) && (transform.tx() == rhs.transform.tx()) && - (transform.ty() == rhs.transform.ty()); - } - inline bool operator!=(const Geometry& rhs) const { return !operator==(rhs); } - }; - using FrameRate = scheduler::LayerInfo::FrameRate; using FrameRateCompatibility = scheduler::FrameRateCompatibility; using FrameRateSelectionStrategy = scheduler::LayerInfo::FrameRateSelectionStrategy; struct State { - int32_t z; - ui::LayerStack layerStack; - uint32_t flags; int32_t sequence; // changes when visible regions can change - bool modified; // Crop is expressed in layer space coordinate. Rect crop; LayerMetadata metadata; - // If non-null, a Surface this Surface's Z-order is interpreted relative to. - wp<Layer> zOrderRelativeOf; - bool isRelativeOf{false}; - - // A list of surfaces whose Z-order is interpreted relative to ours. - SortedVector<wp<Layer>> zOrderRelatives; - half4 color; - float cornerRadius; - int backgroundBlurRadius; - gui::WindowInfo inputInfo; - wp<Layer> touchableRegionCrop; ui::Dataspace dataspace; @@ -154,52 +124,18 @@ public: std::shared_ptr<renderengine::ExternalTexture> buffer; sp<Fence> acquireFence; std::shared_ptr<FenceTime> acquireFenceTime; - HdrMetadata hdrMetadata; - Region surfaceDamageRegion; - int32_t api; sp<NativeHandle> sidebandStream; mat4 colorTransform; - bool hasColorTransform; - // pointer to background color layer that, if set, appears below the buffer state layer - // and the buffer state layer's children. Z order will be set to - // INT_MIN - sp<Layer> bgColorLayer; // The deque of callback handles for this frame. The back of the deque contains the most // recent callback handle. std::deque<sp<CallbackHandle>> callbackHandles; - bool colorSpaceAgnostic; nsecs_t desiredPresentTime = 0; bool isAutoTimestamp = true; - // Length of the cast shadow. If the radius is > 0, a shadow of length shadowRadius will - // be rendered around the layer. - float shadowRadius; - - // Layer regions that are made of custom materials, like frosted glass - std::vector<BlurRegion> blurRegions; - - // Priority of the layer assigned by Window Manager. - int32_t frameRateSelectionPriority; - - // Default frame rate compatibility used to set the layer refresh rate votetype. - FrameRateCompatibility defaultFrameRateCompatibility; - FrameRate frameRate; - // The combined frame rate of parents / children of this layer FrameRate frameRateForLayerTree; - FrameRateSelectionStrategy frameRateSelectionStrategy; - - // Set by window manager indicating the layer and all its children are - // in a different orientation than the display. The hint suggests that - // the graphic producers should receive a transform hint as if the - // display was in this orientation. When the display changes to match - // the layer orientation, the graphic producer may not need to allocate - // a buffer of a different size. ui::Transform::ROT_INVALID means the - // a fixed transform hint is not set. - ui::Transform::RotationFlags fixedTransformHint; - // The vsync info that was used to start the transaction FrameTimelineInfo frameTimelineInfo; @@ -219,21 +155,12 @@ public: // An arbitrary threshold for the number of BufferlessSurfaceFrames in the state. Used to // trigger a warning if the number of SurfaceFrames crosses the threshold. static constexpr uint32_t kStateSurfaceFramesThreshold = 25; - - // Stretch effect to apply to this layer - StretchEffect stretchEffect; - - // Whether or not this layer is a trusted overlay for input - bool isTrustedOverlay; Rect bufferCrop; Rect destinationFrame; sp<IBinder> releaseBufferEndpoint; - gui::DropInputMode dropInputMode; bool autoRefresh = false; - bool dimmingEnabled = true; float currentHdrSdrRatio = 1.f; float desiredHdrSdrRatio = -1.f; - gui::CachingHint cachingHint = gui::CachingHint::Enabled; int64_t latchedVsyncId = 0; bool useVsyncIdForRefreshRateSelection = false; }; @@ -245,15 +172,7 @@ public: static void miniDumpHeader(std::string& result); // Provide unique string for each class type in the Layer hierarchy - virtual const char* getType() const { return "Layer"; } - - // true if this layer is visible, false otherwise - virtual bool isVisible() const; - - // Set a 2x2 transformation matrix on the layer. This transform - // will be applied after parent transforms, but before any final - // producer specified transform. - bool setMatrix(const layer_state_t::matrix22_t& matrix); + const char* getType() const { return "Layer"; } // This second set of geometry attributes are controlled by // setGeometryAppliesWithResize, and their default mode is to be @@ -261,49 +180,9 @@ public: // while a resize is pending, then update of these attributes will // be delayed until the resize completes. - // setPosition operates in parent buffer space (pre parent-transform) or display - // space for top-level layers. - bool setPosition(float x, float y); // Buffer space bool setCrop(const Rect& crop); - // TODO(b/38182121): Could we eliminate the various latching modes by - // using the layer hierarchy? - // ----------------------------------------------------------------------- - virtual bool setLayer(int32_t z); - virtual bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ); - - virtual bool setAlpha(float alpha); - bool setColor(const half3& /*color*/); - - // Set rounded corner radius for this layer and its children. - // - // We only support 1 radius per layer in the hierarchy, where parent layers have precedence. - // The shape of the rounded corner rectangle is specified by the crop rectangle of the layer - // from which we inferred the rounded corner radius. - virtual bool setCornerRadius(float cornerRadius); - // When non-zero, everything below this layer will be blurred by backgroundBlurRadius, which - // is specified in pixels. - virtual bool setBackgroundBlurRadius(int backgroundBlurRadius); - virtual bool setBlurRegions(const std::vector<BlurRegion>& effectRegions); - bool setTransparentRegionHint(const Region& transparent); - virtual bool setTrustedOverlay(bool); - virtual bool setFlags(uint32_t flags, uint32_t mask); - virtual bool setLayerStack(ui::LayerStack); - virtual ui::LayerStack getLayerStack( - LayerVector::StateSet state = LayerVector::StateSet::Drawing) const; - - virtual bool setMetadata(const LayerMetadata& data); - virtual void setChildrenDrawingParent(const sp<Layer>&); - virtual bool setColorTransform(const mat4& matrix); - virtual mat4 getColorTransform() const; - virtual bool hasColorTransform() const; - virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; } - virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; } - float getDesiredHdrSdrRatio() const { return getDrawingState().desiredHdrSdrRatio; } - float getCurrentHdrSdrRatio() const { return getDrawingState().currentHdrSdrRatio; } - gui::CachingHint getCachingHint() const { return getDrawingState().cachingHint; } - bool setTransform(uint32_t /*transform*/); bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/); bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */, @@ -314,111 +193,34 @@ public: bool setDataspace(ui::Dataspace /*dataspace*/); bool setExtendedRangeBrightness(float currentBufferRatio, float desiredRatio); bool setDesiredHdrHeadroom(float desiredRatio); - bool setCachingHint(gui::CachingHint cachingHint); - bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/); - bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/); - bool setApi(int32_t /*api*/); bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/, const FrameTimelineInfo& /* info*/, nsecs_t /* postTime */, gui::GameMode gameMode); bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& /*handles*/, bool willPresent); - virtual bool setColorSpaceAgnostic(const bool agnostic); - virtual bool setDimmingEnabled(const bool dimmingEnabled); - virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint); - void setAutoRefresh(bool /* autoRefresh */); - bool setDropInputMode(gui::DropInputMode); - - ui::Dataspace getDataSpace() const; - virtual bool isFrontBuffered() const; - - virtual sp<LayerFE> getCompositionEngineLayerFE() const; - virtual sp<LayerFE> copyCompositionEngineLayerFE() const; sp<LayerFE> getCompositionEngineLayerFE(const frontend::LayerHierarchy::TraversalPath&); sp<LayerFE> getOrCreateCompositionEngineLayerFE(const frontend::LayerHierarchy::TraversalPath&); - const frontend::LayerSnapshot* getLayerSnapshot() const; - frontend::LayerSnapshot* editLayerSnapshot(); - std::unique_ptr<frontend::LayerSnapshot> stealLayerSnapshot(); - void updateLayerSnapshot(std::unique_ptr<frontend::LayerSnapshot> snapshot); - // If we have received a new buffer this frame, we will pass its surface // damage down to hardware composer. Otherwise, we must send a region with // one empty rect. - void useSurfaceDamage(); - void useEmptyDamage(); Region getVisibleRegion(const DisplayDevice*) const; void updateLastLatchTime(nsecs_t latchtime); /* - * isOpaque - true if this surface is opaque - * - * This takes into account the buffer format (i.e. whether or not the - * pixel format includes an alpha channel) and the "opaque" flag set - * on the layer. It does not examine the current plane alpha value. - */ - bool isOpaque(const Layer::State&) const; - - /* - * Returns whether this layer can receive input. - */ - bool canReceiveInput() const; - - /* - * Whether or not the layer should be considered visible for input calculations. - */ - virtual bool isVisibleForInput() const { - // For compatibility reasons we let layers which can receive input - // receive input before they have actually submitted a buffer. Because - // of this we use canReceiveInput instead of isVisible to check the - // policy-visibility, ignoring the buffer state. However for layers with - // hasInputInfo()==false we can use the real visibility state. - // We are just using these layers for occlusion detection in - // InputDispatcher, and obviously if they aren't visible they can't occlude - // anything. - return hasInputInfo() ? canReceiveInput() : isVisible(); - } - - /* * isProtected - true if the layer may contain protected contents in the * GRALLOC_USAGE_PROTECTED sense. */ bool isProtected() const; - - /* - * isFixedSize - true if content has a fixed size - */ - virtual bool isFixedSize() const { return true; } - /* * usesSourceCrop - true if content should use a source crop */ bool usesSourceCrop() const { return hasBufferOrSidebandStream(); } - // Most layers aren't created from the main thread, and therefore need to - // grab the SF state lock to access HWC, but ContainerLayer does, so we need - // to avoid grabbing the lock again to avoid deadlock - virtual bool isCreatedFromMainThread() const { return false; } - - ui::Transform getActiveTransform(const Layer::State& s) const { return s.transform; } - Region getActiveTransparentRegion(const Layer::State& s) const { - return s.transparentRegionHint; - } Rect getCrop(const Layer::State& s) const { return s.crop; } bool needsFiltering(const DisplayDevice*) const; - // True if this layer requires filtering - // This method is distinct from needsFiltering() in how the filter - // requirement is computed. needsFiltering() compares displayFrame and crop, - // where as this method transforms the displayFrame to layer-stack space - // first. This method should be used if there is no physical display to - // project onto when taking screenshots, as the filtering requirements are - // different. - // If the parent transform needs to be undone when capturing the layer, then - // the inverse parent transform is also required. - bool needsFilteringForScreenshots(const DisplayDevice*, const ui::Transform&) const; - // from graphics API static ui::Dataspace translateDataspace(ui::Dataspace dataspace); uint64_t mPreviousFrameNumber = 0; @@ -437,8 +239,6 @@ public: * operation, so this should be set only if needed). Typically this is used * to figure out if the content or size of a surface has changed. */ - bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/); - bool latchBufferImpl(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/, bool bgColorOnly); @@ -449,14 +249,6 @@ public: bool willReleaseBufferOnLatch() const; /* - * Calls latchBuffer if the buffer has a frame queued and then releases the buffer. - * This is used if the buffer is just latched and releases to free up the buffer - * and will not be shown on screen. - * Should only be called on the main thread. - */ - void latchAndReleaseBuffer(); - - /* * returns the rectangle that crops the content of the layer and scales it * to the layer's size. */ @@ -468,15 +260,6 @@ public: uint32_t getBufferTransform() const; sp<GraphicBuffer> getBuffer() const; - const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const; - - /* - * Returns if a frame is ready - */ - bool hasReadyFrame() const; - - virtual int32_t getQueuedFrameCount() const { return 0; } - /** * Returns active buffer size in the correct orientation. Buffer size is determined by undoing * any buffer transformations. Returns Rect::INVALID_RECT if the layer has no buffer or the @@ -484,33 +267,10 @@ public: */ Rect getBufferSize(const Layer::State&) const; - /** - * Returns the source bounds. If the bounds are not defined, it is inferred from the - * buffer size. Failing that, the bounds are determined from the passed in parent bounds. - * For the root layer, this is the display viewport size. - */ - FloatRect computeSourceBounds(const FloatRect& parentBounds) const; - virtual FrameRate getFrameRateForLayerTree() const; + FrameRate getFrameRateForLayerTree() const; bool getTransformToDisplayInverse() const; - // Returns how rounded corners should be drawn for this layer. - // A layer can override its parent's rounded corner settings if the parent's rounded - // corner crop does not intersect with its own rounded corner crop. - virtual frontend::RoundedCornerState getRoundedCornerState() const; - - bool hasRoundedCorners() const { return getRoundedCornerState().hasRoundedCorners(); } - - PixelFormat getPixelFormat() const; - /** - * Return whether this layer needs an input info. We generate InputWindowHandles for all - * non-cursor buffered layers regardless of whether they have an InputChannel. This is to enable - * the InputDispatcher to do PID based occlusion detection. - */ - bool needsInputInfo() const { - return (hasInputInfo() || hasBufferOrSidebandStream()) && !mPotentialCursor; - } - // Implements RefBase. void onFirstRef() override; @@ -521,17 +281,11 @@ public: uint32_t mTransform{0}; ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN}; Rect mCrop; - uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE}; - Region mSurfaceDamage; - HdrMetadata mHdrMetadata; - int mApi; PixelFormat mPixelFormat{PIXEL_FORMAT_NONE}; bool mTransformToDisplayInverse{false}; - std::shared_ptr<renderengine::ExternalTexture> mBuffer; uint64_t mFrameNumber; sp<IBinder> mReleaseBufferEndpoint; - bool mFrameLatencyNeeded{false}; float mDesiredHdrSdrRatio = -1.f; }; @@ -539,8 +293,6 @@ public: BufferInfo mBufferInfo; std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseChannel; - // implements compositionengine::LayerFE - const compositionengine::LayerFECompositionState* getCompositionState() const; bool fenceHasSignaled() const; void onPreComposition(nsecs_t refreshStartTime); void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack, @@ -561,15 +313,6 @@ public: const char* getDebugName() const; - bool setShadowRadius(float shadowRadius); - - // Before color management is introduced, contents on Android have to be - // desaturated in order to match what they appears like visually. - // With color management, these contents will appear desaturated, thus - // needed to be saturated so that they match what they are designed for - // visually. - bool isLegacyDataSpace() const; - uint32_t getTransactionFlags() const { return mTransactionFlags; } static bool computeTrustedPresentationState(const FloatRect& bounds, @@ -592,14 +335,6 @@ public: // Clears and returns the masked bits. uint32_t clearTransactionFlags(uint32_t mask); - FloatRect getBounds(const Region& activeTransparentRegion) const; - FloatRect getBounds() const; - Rect getInputBoundsInDisplaySpace(const FloatRect& insetBounds, - const ui::Transform& displayTransform); - - // Compute bounds for the layer and cache the results. - void computeBounds(FloatRect parentBounds, ui::Transform parentTransform, float shadowRadius); - int32_t getSequence() const { return sequence; } // For tracing. @@ -610,90 +345,35 @@ public: // only used within a single layer. uint64_t getCurrentBufferId() const { return getBuffer() ? getBuffer()->getId() : 0; } - /* - * isSecure - true if this surface is secure, that is if it prevents - * screenshots or VNC servers. A surface can be set to be secure by the - * application, being secure doesn't mean the surface has DRM contents. - */ - bool isSecure() const; - - /* - * isHiddenByPolicy - true if this layer has been forced invisible. - * just because this is false, doesn't mean isVisible() is true. - * For example if this layer has no active buffer, it may not be hidden by - * policy, but it still can not be visible. - */ - bool isHiddenByPolicy() const; - - // True if the layer should be skipped in screenshots, screen recordings, - // and mirroring to external or virtual displays. - bool isInternalDisplayOverlay() const; - - ui::LayerFilter getOutputFilter() const { - return {getLayerStack(), isInternalDisplayOverlay()}; - } - - perfetto::protos::LayerProto* writeToProto(perfetto::protos::LayersProto& layersProto, - uint32_t traceFlags); void writeCompositionStateToProto(perfetto::protos::LayerProto* layerProto, ui::LayerStack layerStack); - // Write states that are modified by the main thread. This includes drawing - // state as well as buffer data. This should be called in the main or tracing - // thread. - void writeToProtoDrawingState(perfetto::protos::LayerProto* layerInfo); - // Write drawing or current state. If writing current state, the caller should hold the - // external mStateLock. If writing drawing state, this function should be called on the - // main or tracing thread. - void writeToProtoCommonState(perfetto::protos::LayerProto* layerInfo, LayerVector::StateSet, - uint32_t traceFlags = LayerTracing::TRACE_ALL); - gui::WindowInfo::Type getWindowType() const { return mWindowType; } /* * doTransaction - process the transaction. This is a good place to figure * out which attributes of the surface have changed. */ - virtual uint32_t doTransaction(uint32_t transactionFlags); - - /* - * Remove relative z for the layer if its relative parent is not part of the - * provided layer tree. - */ - void removeRelativeZ(const std::vector<Layer*>& layersInTree); + uint32_t doTransaction(uint32_t transactionFlags); inline const State& getDrawingState() const { return mDrawingState; } inline State& getDrawingState() { return mDrawingState; } void miniDump(std::string& result, const frontend::LayerSnapshot&, const DisplayDevice&) const; void dumpFrameStats(std::string& result) const; - void dumpOffscreenDebugInfo(std::string& result) const; void clearFrameStats(); void logFrameStats(); void getFrameStats(FrameStats* outStats) const; void onDisconnect(); ui::Transform getTransform() const; - bool isTransformValid() const; - // Returns the Alpha of the Surface, accounting for the Alpha - // of parent Surfaces in the hierarchy (alpha's will be multiplied - // down the hierarchy). - half getAlpha() const; half4 getColor() const; int32_t getBackgroundBlurRadius() const; bool drawShadows() const { return mEffectiveShadowRadius > 0.f; }; - // Returns the transform hint set by Window Manager on the layer or one of its parents. - // This traverses the current state because the data is needed when creating - // the layer(off drawing thread) and the hint should be available before the producer - // is ready to acquire a buffer. - ui::Transform::RotationFlags getFixedTransformHint() const; - bool isHandleAlive() const { return mHandleAlive; } bool onHandleDestroyed() { return mHandleAlive = false; } - Rect getScreenBounds(bool reduceTransparentRegion = true) const; - int32_t getZ(LayerVector::StateSet) const; /** * Returns the cropped buffer size or the layer crop if the layer has no buffer. Return @@ -703,7 +383,7 @@ public: */ Rect getCroppedBufferSize(const Layer::State& s) const; - virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {} + void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {} void setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime, gui::GameMode gameMode); void setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info, @@ -732,31 +412,14 @@ public: // this to be called once. sp<IBinder> getHandle(); const std::string& getName() const { return mName; } - bool getPremultipledAlpha() const; void setInputInfo(const gui::WindowInfo& info); - struct InputDisplayArgs { - const ui::Transform* transform = nullptr; - bool isSecure = false; - }; - gui::WindowInfo fillInputInfo(const InputDisplayArgs& displayArgs); - - /** - * Returns whether this layer has an explicitly set input-info. - */ - bool hasInputInfo() const; - virtual uid_t getOwnerUid() const { return mOwnerUid; } pid_t getOwnerPid() { return mOwnerPid; } int32_t getOwnerAppId() { return mOwnerAppId; } - mutable bool contentDirty{false}; - Region surfaceDamageRegion; - - // True when the surfaceDamageRegion is recognized as a small area update. - bool mSmallDirty{false}; // Used to check if mUsedVsyncIdForRefreshRateSelection should be expired when it stop updating. nsecs_t mMaxTimeForUseVsyncId = 0; // True when DrawState.useVsyncIdForRefreshRateSelection previously set to true during updating @@ -770,35 +433,11 @@ public: bool mPendingHWCDestroy{false}; - bool backpressureEnabled() const { - return mDrawingState.flags & layer_state_t::eEnableBackpressure; - } - - bool setStretchEffect(const StretchEffect& effect); - bool setBufferCrop(const Rect& /* bufferCrop */); - bool setDestinationFrame(const Rect& /* destinationFrame */); // See mPendingBufferTransactions void decrementPendingBufferCount(); std::atomic<int32_t>* getPendingBufferCounter() { return &mPendingBufferTransactions; } std::string getPendingBufferCounterName() { return mBlastTransactionName; } - bool updateGeometry(); - - bool isSimpleBufferUpdate(const layer_state_t& s) const; - - static bool isOpaqueFormat(PixelFormat format); - - // Updates the LayerSnapshot. This must be called prior to sending layer data to - // CompositionEngine or RenderEngine (i.e. before calling CompositionEngine::present or - // LayerFE::prepareClientComposition). - // - // TODO(b/238781169) Remove direct calls to RenderEngine::drawLayers that don't go through - // CompositionEngine to create a single path for composing layers. - void updateSnapshot(bool updateGeometry); - void updateChildrenSnapshots(bool updateGeometry); - - bool willPresentCurrentTransaction() const; - void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, const sp<GraphicBuffer>& buffer, uint64_t framenumber, const sp<Fence>& releaseFence); @@ -844,7 +483,6 @@ public: const sp<SurfaceFlinger> mFlinger; // Check if the damage region is a small dirty. - void setIsSmallDirty(const Region& damageRegion, const ui::Transform& layerToDisplayTransform); void setIsSmallDirty(frontend::LayerSnapshot* snapshot); protected: @@ -856,52 +494,16 @@ protected: friend class TransactionFrameTracerTest; friend class TransactionSurfaceFrameTest; - void preparePerFrameCompositionState(); - void preparePerFrameBufferCompositionState(); - void preparePerFrameEffectsCompositionState(); void gatherBufferInfo(); - void prepareBasicGeometryCompositionState(); - void prepareGeometryCompositionState(); - void prepareCursorCompositionState(); - - uint32_t getEffectiveUsage(uint32_t usage) const; - - /** - * Setup rounded corners coordinates of this layer, taking into account the layer bounds and - * crop coordinates, transforming them into layer space. - */ - void setupRoundedCornersCropCoordinates(Rect win, const FloatRect& roundedCornersCrop) const; - void setParent(const sp<Layer>&); - LayerVector makeTraversalList(LayerVector::StateSet, bool* outSkipRelativeZUsers); - void addZOrderRelative(const wp<Layer>& relative); - void removeZOrderRelative(const wp<Layer>& relative); compositionengine::OutputLayer* findOutputLayerForDisplay(const DisplayDevice*) const; compositionengine::OutputLayer* findOutputLayerForDisplay( const DisplayDevice*, const frontend::LayerHierarchy::TraversalPath& path) const; - bool usingRelativeZ(LayerVector::StateSet) const; - - virtual ui::Transform getInputTransform() const; - /** - * Get the bounds in layer space within which this layer can receive input. - * - * These bounds are used to: - * - Determine the input frame for the layer to be used for occlusion detection; and - * - Determine the coordinate space within which the layer will receive input. The top-left of - * this rect will be the origin of the coordinate space that the input events sent to the - * layer will be in (prior to accounting for surface insets). - * - * The layer can still receive touch input if these bounds are invalid if - * "replaceTouchableRegionWithCrop" is specified. In this case, the layer will receive input - * in this layer's space, regardless of the specified crop layer. - */ - std::pair<FloatRect, bool> getInputBounds(bool fillParentBounds) const; - bool mPremultipliedAlpha{true}; const std::string mName; const std::string mTransactionName{"TX - " + mName}; - // These are only accessed by the main thread or the tracing thread. + // These are only accessed by the main thread. State mDrawingState; TrustedPresentationThresholds mTrustedPresentationThresholds; @@ -921,34 +523,16 @@ protected: // main thread sp<NativeHandle> mSidebandStream; - // False if the buffer and its contents have been previously used for GPU - // composition, true otherwise. - bool mIsActiveBufferUpdatedForGpu = true; // We encode unset as -1. std::atomic<uint64_t> mCurrentFrameNumber{0}; - // Whether filtering is needed b/c of the drawingstate - bool mNeedsFiltering{false}; - - std::atomic<bool> mRemovedFromDrawingState{false}; - - // page-flip thread (currently main thread) - bool mProtectedByApp{false}; // application requires protected path to external sink // protected by mLock mutable Mutex mLock; - const wp<Client> mClientRef; - // This layer can be a cursor on some displays. bool mPotentialCursor{false}; - LayerVector mCurrentChildren{LayerVector::StateSet::Current}; - LayerVector mDrawingChildren{LayerVector::StateSet::Drawing}; - - wp<Layer> mCurrentParent; - wp<Layer> mDrawingParent; - // Window types from WindowManager.LayoutParams const gui::WindowInfo::Type mWindowType; @@ -966,8 +550,6 @@ protected: // Used in buffer stuffing analysis in FrameTimeline. nsecs_t mLastLatchTime = 0; - mutable bool mDrawingStateModified = false; - sp<Fence> mLastClientCompositionFence; bool mClearClientCompositionFenceOnLayerDisplayed = false; private: @@ -979,44 +561,20 @@ private: friend class TransactionFrameTracerTest; friend class TransactionSurfaceFrameTest; - bool getAutoRefresh() const { return mDrawingState.autoRefresh; } bool getSidebandStreamChanged() const { return mSidebandStreamChanged; } std::atomic<bool> mSidebandStreamChanged{false}; - // Returns true if the layer can draw shadows on its border. - virtual bool canDrawShadows() const { return true; } - aidl::android::hardware::graphics::composer3::Composition getCompositionType( const DisplayDevice&) const; aidl::android::hardware::graphics::composer3::Composition getCompositionType( const compositionengine::OutputLayer*) const; - bool propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool overrideChildren, - bool* transactionNeeded); - void setZOrderRelativeOf(const wp<Layer>& relativeOf); - bool isTrustedOverlay() const; - gui::DropInputMode getDropInputMode() const; - void handleDropInputMode(gui::WindowInfo& info) const; - - // Finds the top most layer in the hierarchy. This will find the root Layer where the parent is - // null. - sp<Layer> getRootLayer(); - - // Fills in the touch occlusion mode of the first parent (including this layer) that - // hasInputInfo() or no-op if no such parent is found. - void fillTouchOcclusionMode(gui::WindowInfo& info); - - // Fills in the frame and transform info for the gui::WindowInfo. - void fillInputFrameInfo(gui::WindowInfo&, const ui::Transform& screenToDisplay); - inline void tracePendingBufferCount(int32_t pendingBuffers); // Latch sideband stream and returns true if the dirty region should be updated. bool latchSidebandStream(bool& recomputeVisibleRegions); - bool hasFrameUpdate() const; - void updateTexImage(nsecs_t latchTime, bool bgColorOnly = false); // Crop that applies to the buffer @@ -1027,15 +585,6 @@ private: const sp<Fence>& releaseFence, uint32_t currentMaxAcquiredBufferCount); - // Returns true if the transformed buffer size does not match the layer size and we need - // to apply filtering. - bool bufferNeedsFiltering() const; - - // Returns true if there is a valid color to fill. - bool fillsColor() const; - // Returns true if this layer has a blur value. - bool hasBlur() const; - bool hasEffect() const { return fillsColor() || drawShadows() || hasBlur(); } bool hasBufferOrSidebandStream() const { return ((mSidebandStream != nullptr) || (mBufferInfo.mBuffer != nullptr)); } @@ -1044,33 +593,6 @@ private: return ((mDrawingState.sidebandStream != nullptr) || (mDrawingState.buffer != nullptr)); } - bool hasSomethingToDraw() const { return hasEffect() || hasBufferOrSidebandStream(); } - - bool shouldOverrideChildrenFrameRate() const { - return getDrawingState().frameRateSelectionStrategy == - FrameRateSelectionStrategy::OverrideChildren; - } - - bool shouldPropagateFrameRate() const { - return getDrawingState().frameRateSelectionStrategy != FrameRateSelectionStrategy::Self; - } - - // Cached properties computed from drawing state - // Effective transform taking into account parent transforms and any parent scaling, which is - // a transform from the current layer coordinate space to display(screen) coordinate space. - ui::Transform mEffectiveTransform; - - // Bounds of the layer before any transformation is applied and before it has been cropped - // by its parents. - FloatRect mSourceBounds; - - // Bounds of the layer in layer space. This is the mSourceBounds cropped by its layer crop and - // its parent bounds. - FloatRect mBounds; - - // Layer bounds in screen space. - FloatRect mScreenBounds; - bool mGetHandleCalled = false; // The inherited shadow radius after taking into account the layer hierarchy. This is the @@ -1081,15 +603,10 @@ private: // Game mode for the layer. Set by WindowManagerShell and recorded by SurfaceFlingerStats. gui::GameMode mGameMode = gui::GameMode::Unsupported; - // A list of regions on this layer that should have blurs. - const std::vector<BlurRegion> getBlurRegions() const; - bool mIsAtRoot = false; uint32_t mLayerCreationFlags; - bool findInHierarchy(const sp<Layer>&); - void releasePreviousBuffer(); void resetDrawingStateBufferInfo(); @@ -1122,10 +639,7 @@ private: // not specify a destination frame. ui::Transform mRequestedTransform; - sp<LayerFE> mLegacyLayerFE; std::vector<std::pair<frontend::LayerHierarchy::TraversalPath, sp<LayerFE>>> mLayerFEs; - std::unique_ptr<frontend::LayerSnapshot> mSnapshot = - std::make_unique<frontend::LayerSnapshot>(); bool mHandleAlive = false; }; diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index 885c3d3460..5eea45b436 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -178,7 +178,7 @@ void LayerProtoHelper::writeToProto( } void LayerProtoHelper::writeToProto( - const WindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds, + const WindowInfo& inputInfo, std::function<perfetto::protos::InputWindowInfoProto*()> getInputWindowInfoProto) { if (inputInfo.token == nullptr) { return; @@ -208,13 +208,6 @@ void LayerProtoHelper::writeToProto( proto->set_global_scale_factor(inputInfo.globalScaleFactor); LayerProtoHelper::writeToProtoDeprecated(inputInfo.transform, proto->mutable_transform()); proto->set_replace_touchable_region_with_crop(inputInfo.replaceTouchableRegionWithCrop); - auto cropLayer = touchableRegionBounds.promote(); - if (cropLayer != nullptr) { - proto->set_crop_layer_id(cropLayer->sequence); - LayerProtoHelper::writeToProto(cropLayer->getScreenBounds( - false /* reduceTransparentRegion */), - [&]() { return proto->mutable_touchable_region_crop(); }); - } } void LayerProtoHelper::writeToProto(const mat4 matrix, @@ -482,7 +475,7 @@ void LayerProtoHelper::writeSnapshotToProto(perfetto::protos::LayerProto* layerI layerInfo->set_owner_uid(requestedState.ownerUid.val()); if ((traceFlags & LayerTracing::TRACE_INPUT) && snapshot.hasInputInfo()) { - LayerProtoHelper::writeToProto(snapshot.inputInfo, {}, + LayerProtoHelper::writeToProto(snapshot.inputInfo, [&]() { return layerInfo->mutable_input_window_info(); }); } diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h index c0198b62ec..41ea68420f 100644 --- a/services/surfaceflinger/LayerProtoHelper.h +++ b/services/surfaceflinger/LayerProtoHelper.h @@ -62,7 +62,7 @@ public: const renderengine::ExternalTexture& buffer, std::function<perfetto::protos::ActiveBufferProto*()> getActiveBufferProto); static void writeToProto( - const gui::WindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds, + const gui::WindowInfo& inputInfo, std::function<perfetto::protos::InputWindowInfoProto*()> getInputWindowInfoProto); static void writeToProto(const mat4 matrix, perfetto::protos::ColorTransformProto* colorTransformProto); diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp index ff0a955ad6..13e054e249 100644 --- a/services/surfaceflinger/LayerVector.cpp +++ b/services/surfaceflinger/LayerVector.cpp @@ -45,16 +45,6 @@ int LayerVector::do_compare(const void* lhs, const void* rhs) const const auto& lState = l->getDrawingState(); const auto& rState = r->getDrawingState(); - const auto ls = lState.layerStack; - const auto rs = rState.layerStack; - if (ls != rs) - return (ls > rs) ? 1 : -1; - - int32_t lz = lState.z; - int32_t rz = rState.z; - if (lz != rz) - return (lz > rz) ? 1 : -1; - if (l->sequence == r->sequence) return 0; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 7712d38f43..06c2f26a6d 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -346,6 +346,7 @@ void RegionSamplingThread::captureSample() { constexpr bool kRegionSampling = true; constexpr bool kGrayscale = false; constexpr bool kIsProtected = false; + constexpr bool kAttachGainmap = false; SurfaceFlinger::RenderAreaBuilderVariant renderAreaBuilder(std::in_place_type<DisplayRenderAreaBuilder>, sampledBounds, @@ -358,15 +359,15 @@ void RegionSamplingThread::captureSample() { std::vector<sp<LayerFE>> layerFEs; auto displayState = mFlinger.getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layerFEs); - fenceResult = - mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, kGrayscale, - kIsProtected, nullptr, displayState, layerFEs) - .get(); + fenceResult = mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, + kGrayscale, kIsProtected, kAttachGainmap, nullptr, + displayState, layerFEs) + .get(); } else { - fenceResult = - mFlinger.captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, buffer, - kRegionSampling, kGrayscale, kIsProtected, nullptr) - .get(); + fenceResult = mFlinger.captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, + buffer, kRegionSampling, kGrayscale, + kIsProtected, kAttachGainmap, nullptr) + .get(); } if (fenceResult.ok()) { fenceResult.value()->waitForever(LOG_TAG); diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h index 034e467be9..aa66ccf172 100644 --- a/services/surfaceflinger/RenderArea.h +++ b/services/surfaceflinger/RenderArea.h @@ -39,21 +39,6 @@ public: mReqDataSpace(reqDataSpace), mCaptureFill(captureFill) {} - static std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()> fromTraverseLayersLambda( - std::function<void(const LayerVector::Visitor&)> traverseLayers) { - return [traverseLayers = std::move(traverseLayers)]() { - std::vector<std::pair<Layer*, sp<LayerFE>>> layers; - traverseLayers([&](Layer* layer) { - // Layer::prepareClientComposition uses the layer's snapshot to populate the - // resulting LayerSettings. Calling Layer::updateSnapshot ensures that LayerSettings - // are generated with the layer's current buffer and geometry. - layer->updateSnapshot(true /* updateGeometry */); - layers.emplace_back(layer, layer->copyCompositionEngineLayerFE()); - }); - return layers; - }; - } - virtual ~RenderArea() = default; // Returns true if the render area is secure. A secure layer should be diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index dbc458cb7f..ff1926e03f 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -595,8 +595,7 @@ bool LayerInfo::FrameRate::isVoteValidForMrr(bool isVrrDevice) const { return true; } - if (FlagManager::getInstance().view_set_requested_frame_rate_mrr() && - category == FrameRateCategory::NoPreference && vote.rate.isValid() && + if (category == FrameRateCategory::NoPreference && vote.rate.isValid() && vote.type == FrameRateCompatibility::ExactOrMultiple) { return true; } diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index 9f6eab288b..ab9014e418 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -841,7 +841,8 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi return score.overallScore == 0; }); - if (policy->primaryRangeIsSingleRate()) { + // TODO(b/364651864): Evaluate correctness of primaryRangeIsSingleRate. + if (!mIsVrrDevice.load() && policy->primaryRangeIsSingleRate()) { // If we never scored any layers, then choose the rate from the primary // range instead of picking a random score from the app range. if (noLayerScore) { @@ -887,8 +888,8 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi const auto touchRefreshRates = rankFrameRates(anchorGroup, RefreshRateOrder::Descending); using fps_approx_ops::operator<; - if (scores.front().frameRateMode.fps < touchRefreshRates.front().frameRateMode.fps) { - ALOGV("Touch Boost"); + if (scores.front().frameRateMode.fps <= touchRefreshRates.front().frameRateMode.fps) { + ALOGV("Touch Boost [late]"); SFTRACE_FORMAT_INSTANT("%s (Touch Boost [late])", to_string(touchRefreshRates.front().frameRateMode.fps).c_str()); return {touchRefreshRates, GlobalSignals{.touch = true}}; @@ -1394,13 +1395,14 @@ auto RefreshRateSelector::setPolicy(const PolicyVariant& policy) -> SetPolicyRes const auto& idleScreenConfigOpt = getCurrentPolicyLocked()->idleScreenConfigOpt; if (idleScreenConfigOpt != oldPolicy.idleScreenConfigOpt) { if (!idleScreenConfigOpt.has_value()) { - // fallback to legacy timer if existed, otherwise pause the old timer - LOG_ALWAYS_FATAL_IF(!mIdleTimer); - if (mConfig.legacyIdleTimerTimeout > 0ms) { - mIdleTimer->setInterval(mConfig.legacyIdleTimerTimeout); - mIdleTimer->resume(); - } else { - mIdleTimer->pause(); + if (mIdleTimer) { + // fallback to legacy timer if existed, otherwise pause the old timer + if (mConfig.legacyIdleTimerTimeout > 0ms) { + mIdleTimer->setInterval(mConfig.legacyIdleTimerTimeout); + mIdleTimer->resume(); + } else { + mIdleTimer->pause(); + } } } else if (idleScreenConfigOpt->timeoutMillis > 0) { // create a new timer or reconfigure diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp index fa377e9323..3c5f68c4c2 100644 --- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp +++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp @@ -21,7 +21,6 @@ #include "VsyncModulator.h" -#include <android-base/properties.h> #include <common/trace.h> #include <log/log.h> @@ -37,8 +36,7 @@ const std::chrono::nanoseconds VsyncModulator::MIN_EARLY_TRANSACTION_TIME = 1ms; VsyncModulator::VsyncModulator(const VsyncConfigSet& config, Now now) : mVsyncConfigSet(config), - mNow(now), - mTraceDetailedInfo(base::GetBoolProperty("debug.sf.vsync_trace_detailed_info", false)) {} + mNow(now) {} VsyncConfig VsyncModulator::setVsyncConfigSet(const VsyncConfigSet& config) { std::lock_guard<std::mutex> lock(mMutex); @@ -71,10 +69,6 @@ VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(Transactio break; } - if (mTraceDetailedInfo) { - SFTRACE_INT("mEarlyWakeup", static_cast<int>(mEarlyWakeupRequests.size())); - } - if (mEarlyWakeupRequests.empty() && schedule == Schedule::EarlyEnd) { mEarlyTransactionFrames = MIN_EARLY_TRANSACTION_FRAMES; mEarlyTransactionStartTime = mNow(); @@ -167,15 +161,19 @@ VsyncConfig VsyncModulator::updateVsyncConfigLocked() { const VsyncConfig& offsets = getNextVsyncConfig(); mVsyncConfig = offsets; - if (mTraceDetailedInfo) { - const bool isEarly = &offsets == &mVsyncConfigSet.early; - const bool isEarlyGpu = &offsets == &mVsyncConfigSet.earlyGpu; - const bool isLate = &offsets == &mVsyncConfigSet.late; + // Trace config type + SFTRACE_INT("Vsync-Early", &mVsyncConfig == &mVsyncConfigSet.early); + SFTRACE_INT("Vsync-EarlyGpu", &mVsyncConfig == &mVsyncConfigSet.earlyGpu); + SFTRACE_INT("Vsync-Late", &mVsyncConfig == &mVsyncConfigSet.late); - SFTRACE_INT("Vsync-EarlyOffsetsOn", isEarly); - SFTRACE_INT("Vsync-EarlyGpuOffsetsOn", isEarlyGpu); - SFTRACE_INT("Vsync-LateOffsetsOn", isLate); - } + // Trace early vsync conditions + SFTRACE_INT("EarlyWakeupRequests", + static_cast<int>(mEarlyWakeupRequests.size())); + SFTRACE_INT("EarlyTransactionFrames", mEarlyTransactionFrames); + SFTRACE_INT("RefreshRateChangePending", mRefreshRateChangePending); + + // Trace early gpu conditions + SFTRACE_INT("EarlyGpuFrames", mEarlyGpuFrames); return offsets; } @@ -183,7 +181,6 @@ VsyncConfig VsyncModulator::updateVsyncConfigLocked() { void VsyncModulator::binderDied(const wp<IBinder>& who) { std::lock_guard<std::mutex> lock(mMutex); mEarlyWakeupRequests.erase(who); - static_cast<void>(updateVsyncConfigLocked()); } diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h index be0d3348b5..d0a793535c 100644 --- a/services/surfaceflinger/Scheduler/VsyncModulator.h +++ b/services/surfaceflinger/Scheduler/VsyncModulator.h @@ -105,7 +105,6 @@ private: std::atomic<TimePoint> mLastTransactionCommitTime = TimePoint(); const Now mNow; - const bool mTraceDetailedInfo; }; } // namespace android::scheduler diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp index 8bb72b8470..41a9a1bb22 100644 --- a/services/surfaceflinger/ScreenCaptureOutput.cpp +++ b/services/surfaceflinger/ScreenCaptureOutput.cpp @@ -93,6 +93,12 @@ renderengine::DisplaySettings ScreenCaptureOutput::generateClientCompositionDisp if (mEnableLocalTonemapping) { clientCompositionDisplay.tonemapStrategy = renderengine::DisplaySettings::TonemapStrategy::Local; + if (static_cast<ui::PixelFormat>(buffer->getPixelFormat()) == ui::PixelFormat::RGBA_FP16) { + clientCompositionDisplay.targetHdrSdrRatio = + getState().displayBrightnessNits / getState().sdrWhitePointNits; + } else { + clientCompositionDisplay.targetHdrSdrRatio = 1.f; + } } return clientCompositionDisplay; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e13c74fe69..c794a7ba43 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -532,9 +532,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false); // These are set by the HWC implementation to indicate that they will use the workarounds. - mIsHotplugErrViaNegVsync = - base::GetBoolProperty("debug.sf.hwc_hotplug_error_via_neg_vsync"s, false); - mIsHdcpViaNegVsync = base::GetBoolProperty("debug.sf.hwc_hdcp_via_neg_vsync"s, false); } @@ -2172,21 +2169,13 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t std::optional<hal::VsyncPeriodNanos> vsyncPeriod) { if (FlagManager::getInstance().connected_display() && timestamp < 0 && vsyncPeriod.has_value()) { - // use ~0 instead of -1 as AidlComposerHal.cpp passes the param as unsigned int32 - if (mIsHotplugErrViaNegVsync && vsyncPeriod.value() == ~0) { - const auto errorCode = static_cast<int32_t>(-timestamp); - ALOGD("%s: Hotplug error %d for display %" PRIu64, __func__, errorCode, hwcDisplayId); - mScheduler->dispatchHotplugError(errorCode); - return; - } - if (mIsHdcpViaNegVsync && vsyncPeriod.value() == ~1) { const int32_t value = static_cast<int32_t>(-timestamp); // one byte is good enough to encode android.hardware.drm.HdcpLevel const int32_t maxLevel = (value >> 8) & 0xFF; const int32_t connectedLevel = value & 0xFF; - ALOGD("%s: HDCP levels changed (connected=%d, max=%d) for display %" PRIu64, __func__, - connectedLevel, maxLevel, hwcDisplayId); + ALOGD("%s: HDCP levels changed (connected=%d, max=%d) for hwcDisplayId %" PRIu64, + __func__, connectedLevel, maxLevel, hwcDisplayId); updateHdcpLevels(hwcDisplayId, connectedLevel, maxLevel); return; } @@ -2226,7 +2215,7 @@ void SurfaceFlinger::onComposerHalHotplugEvent(hal::HWDisplayId hwcDisplayId, if (FlagManager::getInstance().hotplug2()) { // TODO(b/311403559): use enum type instead of int const auto errorCode = static_cast<int32_t>(event); - ALOGD("%s: Hotplug error %d for display %" PRIu64, __func__, errorCode, hwcDisplayId); + ALOGD("%s: Hotplug error %d for hwcDisplayId %" PRIu64, __func__, errorCode, hwcDisplayId); mScheduler->dispatchHotplugError(errorCode); } } @@ -2276,6 +2265,18 @@ void SurfaceFlinger::onRefreshRateChangedDebug(const RefreshRateChangedDebugData })); } +void SurfaceFlinger::onComposerHalHdcpLevelsChanged(hal::HWDisplayId hwcDisplayId, + const HdcpLevels& levels) { + if (FlagManager::getInstance().hdcp_level_hal()) { + // TODO(b/362270040): propagate enum constants + const int32_t maxLevel = static_cast<int32_t>(levels.maxLevel); + const int32_t connectedLevel = static_cast<int32_t>(levels.connectedLevel); + ALOGD("%s: HDCP levels changed (connected=%d, max=%d) for hwcDisplayId %" PRIu64, __func__, + connectedLevel, maxLevel, hwcDisplayId); + updateHdcpLevels(hwcDisplayId, connectedLevel, maxLevel); + } +} + void SurfaceFlinger::configure() { Mutex::Autolock lock(mStateLock); if (configureLocked()) { @@ -2448,7 +2449,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, bool newDataLatched = false; SFTRACE_NAME("DisplayCallbackAndStatsUpdates"); - mustComposite |= applyTransactionsLocked(update.transactions, vsyncId); + mustComposite |= applyTransactionsLocked(update.transactions); traverseLegacyLayers([&](Layer* layer) { layer->commitTransaction(); }); const nsecs_t latchTime = systemTime(); bool unused = false; @@ -2738,7 +2739,8 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( if (!FlagManager::getInstance().ce_fence_promise()) { refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size()); for (auto& [layer, _] : mLayersWithQueuedFrames) { - if (const auto& layerFE = layer->getCompositionEngineLayerFE()) + if (const auto& layerFE = layer->getCompositionEngineLayerFE( + {static_cast<uint32_t>(layer->sequence)})) refreshArgs.layersWithQueuedFrames.push_back(layerFE); } } @@ -2814,7 +2816,8 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size()); for (auto& [layer, _] : mLayersWithQueuedFrames) { - if (const auto& layerFE = layer->getCompositionEngineLayerFE()) { + if (const auto& layerFE = layer->getCompositionEngineLayerFE( + {static_cast<uint32_t>(layer->sequence)})) { refreshArgs.layersWithQueuedFrames.push_back(layerFE); // Some layers are not displayed and do not yet have a future release fence if (layerFE->getReleaseFencePromiseStatus() == @@ -3814,7 +3817,8 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, mDisplays.erase(displayToken); if (const auto& physical = currentState.physical) { - getHwComposer().allocatePhysicalDisplay(physical->hwcDisplayId, physical->id); + getHwComposer().allocatePhysicalDisplay(physical->hwcDisplayId, physical->id, + /*physicalSize=*/std::nullopt); } processDisplayAdded(displayToken, currentState); @@ -3910,7 +3914,6 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { // Commit display transactions. const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded; mFrontEndDisplayInfosChanged = displayTransactionNeeded; - mForceTransactionDisplayChange = displayTransactionNeeded; if (mSomeChildrenChanged) { mVisibleRegionsDirty = true; @@ -4572,20 +4575,18 @@ void SurfaceFlinger::addTransactionReadyFilters() { } // For tests only -bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) { +bool SurfaceFlinger::flushTransactionQueues() { mTransactionHandler.collectTransactions(); std::vector<TransactionState> transactions = mTransactionHandler.flushTransactions(); - return applyTransactions(transactions, vsyncId); + return applyTransactions(transactions); } -bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions, - VsyncId vsyncId) { +bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions) { Mutex::Autolock lock(mStateLock); - return applyTransactionsLocked(transactions, vsyncId); + return applyTransactionsLocked(transactions); } -bool SurfaceFlinger::applyTransactionsLocked(std::vector<TransactionState>& transactions, - VsyncId vsyncId) { +bool SurfaceFlinger::applyTransactionsLocked(std::vector<TransactionState>& transactions) { bool needsTraversal = false; // Now apply all transactions. for (auto& transaction : transactions) { @@ -6963,7 +6964,8 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, displayWeak, options), getLayerSnapshotsFn, reqSize, static_cast<ui::PixelFormat>(captureArgs.pixelFormat), - captureArgs.allowProtected, captureArgs.grayscale, captureListener); + captureArgs.allowProtected, captureArgs.grayscale, + captureArgs.attachGainmap, captureListener); } void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args, @@ -7020,7 +7022,7 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args static_cast<ui::Dataspace>(args.dataspace), displayWeak, options), getLayerSnapshotsFn, size, static_cast<ui::PixelFormat>(args.pixelFormat), - kAllowProtected, kGrayscale, captureListener); + kAllowProtected, kGrayscale, args.attachGainmap, captureListener); } ScreenCaptureResults SurfaceFlinger::captureLayersSync(const LayerCaptureArgs& args) { @@ -7131,7 +7133,8 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, options), getLayerSnapshotsFn, reqSize, static_cast<ui::PixelFormat>(captureArgs.pixelFormat), - captureArgs.allowProtected, captureArgs.grayscale, captureListener); + captureArgs.allowProtected, captureArgs.grayscale, + captureArgs.attachGainmap, captureListener); } // Creates a Future release fence for a layer and keeps track of it in a list to @@ -7182,7 +7185,7 @@ std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getSnapsho void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, - bool allowProtected, bool grayscale, + bool allowProtected, bool grayscale, bool attachGainmap, const sp<IScreenCaptureListener>& captureListener) { SFTRACE_CALL(); @@ -7228,9 +7231,9 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil renderengine::impl::ExternalTexture>(buffer, getRenderEngine(), renderengine::impl::ExternalTexture::Usage:: WRITEABLE); - auto futureFence = - captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, grayscale, - isProtected, captureListener, displayState, layerFEs); + auto futureFence = captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, + grayscale, isProtected, attachGainmap, captureListener, + displayState, layerFEs); futureFence.get(); } else { @@ -7265,7 +7268,7 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil WRITEABLE); auto futureFence = captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, texture, false /* regionSampling */, grayscale, - isProtected, captureListener); + isProtected, attachGainmap, captureListener); futureFence.get(); } } @@ -7319,7 +7322,8 @@ std::vector<sp<LayerFE>> SurfaceFlinger::extractLayerFEs( ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, + bool grayscale, bool isProtected, bool attachGainmap, + const sp<IScreenCaptureListener>& captureListener, std::optional<OutputCompositionState>& displayState, std::vector<sp<LayerFE>>& layerFEs) { SFTRACE_CALL(); @@ -7336,19 +7340,87 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( } return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); } + float displayBrightnessNits = displayState.value().displayBrightnessNits; + float sdrWhitePointNits = displayState.value().sdrWhitePointNits; // Empty vector needed to pass into renderScreenImpl for legacy path std::vector<std::pair<Layer*, sp<android::LayerFE>>> layers; ftl::SharedFuture<FenceResult> renderFuture = - renderScreenImpl(std::move(renderArea), buffer, regionSampling, grayscale, isProtected, - captureResults, displayState, layers, layerFEs); + renderScreenImpl(renderArea.get(), buffer, regionSampling, grayscale, isProtected, + attachGainmap, captureResults, displayState, layers, layerFEs); + + if (captureResults.capturedHdrLayers && attachGainmap && + FlagManager::getInstance().true_hdr_screenshots()) { + sp<GraphicBuffer> hdrBuffer = + getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(), + HAL_PIXEL_FORMAT_RGBA_FP16, 1 /* layerCount */, + buffer->getUsage(), "screenshot-hdr"); + sp<GraphicBuffer> gainmapBuffer = + getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(), + buffer->getPixelFormat(), 1 /* layerCount */, + buffer->getUsage(), "screenshot-gainmap"); + + const status_t bufferStatus = hdrBuffer->initCheck(); + const status_t gainmapBufferStatus = gainmapBuffer->initCheck(); + + if (bufferStatus != OK) { + ALOGW("%s: Buffer failed to allocate for hdr: %d. Screenshoting SDR instead.", __func__, + bufferStatus); + } else if (gainmapBufferStatus != OK) { + ALOGW("%s: Buffer failed to allocate for gainmap: %d. Screenshoting SDR instead.", + __func__, gainmapBufferStatus); + } else { + captureResults.optionalGainMap = gainmapBuffer; + const auto hdrTexture = std::make_shared< + renderengine::impl::ExternalTexture>(hdrBuffer, getRenderEngine(), + renderengine::impl::ExternalTexture:: + Usage::WRITEABLE); + const auto gainmapTexture = std::make_shared< + renderengine::impl::ExternalTexture>(gainmapBuffer, getRenderEngine(), + renderengine::impl::ExternalTexture:: + Usage::WRITEABLE); + ScreenCaptureResults unusedResults; + ftl::SharedFuture<FenceResult> hdrRenderFuture = + renderScreenImpl(renderArea.get(), hdrTexture, regionSampling, grayscale, + isProtected, attachGainmap, unusedResults, displayState, + layers, layerFEs); + + renderFuture = + ftl::Future(std::move(renderFuture)) + .then([&, hdrRenderFuture = std::move(hdrRenderFuture), + displayBrightnessNits, sdrWhitePointNits, + dataspace = captureResults.capturedDataspace, buffer, hdrTexture, + gainmapTexture](FenceResult fenceResult) -> FenceResult { + if (!fenceResult.ok()) { + return fenceResult; + } + + auto hdrFenceResult = hdrRenderFuture.get(); + + if (!hdrFenceResult.ok()) { + return hdrFenceResult; + } + + return getRenderEngine() + .drawGainmap(buffer, fenceResult.value()->get(), hdrTexture, + hdrFenceResult.value()->get(), + displayBrightnessNits / sdrWhitePointNits, + static_cast<ui::Dataspace>(dataspace), + gainmapTexture) + .get(); + }) + .share(); + }; + } if (captureListener) { // Defer blocking on renderFuture back to the Binder thread. return ftl::Future(std::move(renderFuture)) - .then([captureListener, captureResults = std::move(captureResults)]( - FenceResult fenceResult) mutable -> FenceResult { + .then([captureListener, captureResults = std::move(captureResults), + displayBrightnessNits, + sdrWhitePointNits](FenceResult fenceResult) mutable -> FenceResult { captureResults.fenceResult = std::move(fenceResult); + captureResults.hdrSdrRatio = displayBrightnessNits / sdrWhitePointNits; captureListener->onScreenCaptureCompleted(captureResults); return base::unexpected(NO_ERROR); }) @@ -7360,7 +7432,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshotLegacy( RenderAreaBuilderVariant renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener) { + bool grayscale, bool isProtected, bool attachGainmap, + const sp<IScreenCaptureListener>& captureListener) { SFTRACE_CALL(); auto takeScreenshotFn = [=, this, renderAreaBuilder = std::move(renderAreaBuilder)]() REQUIRES( @@ -7389,8 +7462,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshotLegacy( auto layerFEs = extractLayerFEs(layers); ftl::SharedFuture<FenceResult> renderFuture = - renderScreenImpl(std::move(renderArea), buffer, regionSampling, grayscale, - isProtected, captureResults, displayState, layers, layerFEs); + renderScreenImpl(renderArea.get(), buffer, regionSampling, grayscale, isProtected, + attachGainmap, captureResults, displayState, layers, layerFEs); if (captureListener) { // Defer blocking on renderFuture back to the Binder thread. @@ -7420,10 +7493,9 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshotLegacy( } ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( - std::unique_ptr<const RenderArea> renderArea, - const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, ScreenCaptureResults& captureResults, - std::optional<OutputCompositionState>& displayState, + const RenderArea* renderArea, const std::shared_ptr<renderengine::ExternalTexture>& buffer, + bool regionSampling, bool grayscale, bool isProtected, bool attachGainmap, + ScreenCaptureResults& captureResults, std::optional<OutputCompositionState>& displayState, std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, std::vector<sp<LayerFE>>& layerFEs) { SFTRACE_CALL(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 414088e316..3eb72cc4c0 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -135,6 +135,7 @@ class FrameTracer; class ScreenCapturer; class WindowInfosListenerInvoker; +using ::aidl::android::hardware::drm::HdcpLevels; using ::aidl::android::hardware::graphics::common::DisplayHotplugEvent; using ::aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData; using frontend::TransactionHandler; @@ -671,6 +672,7 @@ private: void onComposerHalSeamlessPossible(hal::HWDisplayId) override; void onComposerHalVsyncIdle(hal::HWDisplayId) override; void onRefreshRateChangedDebug(const RefreshRateChangedDebugData&) override; + void onComposerHalHdcpLevelsChanged(hal::HWDisplayId, const HdcpLevels& levels) override; // ICompositor overrides: void configure() override REQUIRES(kMainThreadContext); @@ -783,9 +785,9 @@ private: REQUIRES(mStateLock, kMainThreadContext); // Flush pending transactions that were presented after desiredPresentTime. // For test only - bool flushTransactionQueues(VsyncId) REQUIRES(kMainThreadContext); + bool flushTransactionQueues() REQUIRES(kMainThreadContext); - bool applyTransactions(std::vector<TransactionState>&, VsyncId) REQUIRES(kMainThreadContext); + bool applyTransactions(std::vector<TransactionState>&) REQUIRES(kMainThreadContext); bool applyAndCommitDisplayTransactionStatesLocked(std::vector<TransactionState>& transactions) REQUIRES(kMainThreadContext, mStateLock); @@ -815,7 +817,7 @@ private: static LatchUnsignaledConfig getLatchUnsignaledConfig(); bool shouldLatchUnsignaled(const layer_state_t&, size_t numStates, bool firstTransaction) const; - bool applyTransactionsLocked(std::vector<TransactionState>& transactions, VsyncId) + bool applyTransactionsLocked(std::vector<TransactionState>& transactions) REQUIRES(mStateLock, kMainThreadContext); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands) @@ -859,7 +861,7 @@ private: void captureScreenCommon(RenderAreaBuilderVariant, GetLayerSnapshotsFunction, ui::Size bufferSize, ui::PixelFormat, bool allowProtected, - bool grayscale, const sp<IScreenCaptureListener>&); + bool grayscale, bool attachGainmap, const sp<IScreenCaptureListener>&); std::optional<OutputCompositionState> getDisplayStateFromRenderAreaBuilder( RenderAreaBuilderVariant& renderAreaBuilder) REQUIRES(kMainThreadContext); @@ -873,20 +875,21 @@ private: ftl::SharedFuture<FenceResult> captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, + bool grayscale, bool isProtected, bool attachGainmap, + const sp<IScreenCaptureListener>& captureListener, std::optional<OutputCompositionState>& displayState, std::vector<sp<LayerFE>>& layerFEs); ftl::SharedFuture<FenceResult> captureScreenshotLegacy( RenderAreaBuilderVariant, GetLayerSnapshotsFunction, const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling, - bool grayscale, bool isProtected, const sp<IScreenCaptureListener>&); + bool grayscale, bool isProtected, bool attachGainmap, + const sp<IScreenCaptureListener>&); ftl::SharedFuture<FenceResult> renderScreenImpl( - std::unique_ptr<const RenderArea>, - const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling, - bool grayscale, bool isProtected, ScreenCaptureResults&, - std::optional<OutputCompositionState>& displayState, + const RenderArea*, const std::shared_ptr<renderengine::ExternalTexture>&, + bool regionSampling, bool grayscale, bool isProtected, bool attachGainmap, + ScreenCaptureResults&, std::optional<OutputCompositionState>& displayState, std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, std::vector<sp<LayerFE>>& layerFEs); @@ -1228,7 +1231,6 @@ private: // TODO: Also move visibleRegions over to a boolean system. bool mUpdateInputInfo = false; bool mSomeChildrenChanged; - bool mForceTransactionDisplayChange = false; bool mUpdateAttachedChoreographer = false; struct LayerIntHash { @@ -1259,7 +1261,6 @@ private: }; bool mIsHdcpViaNegVsync = false; - bool mIsHotplugErrViaNegVsync = false; std::mutex mHotplugMutex; std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mHotplugMutex); diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index c6856aea75..2b20648e42 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -30,6 +30,7 @@ #include <binder/IInterface.h> #include <common/FlagManager.h> #include <common/trace.h> +#include <ftl/concat.h> #include <utils/RefBase.h> namespace android { @@ -129,6 +130,9 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>& if (FlagManager::getInstance().ce_fence_promise()) { for (auto& future : handle->previousReleaseFences) { + SFTRACE_NAME(ftl::Concat("Merging fence for layer: ", + ftl::truncated<20>(handle->name.c_str())) + .c_str()); mergeFence(handle->name.c_str(), future.get().value_or(Fence::NO_FENCE), prevFence); } } else { diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp index 8ec908fffd..12d6138675 100644 --- a/services/surfaceflinger/common/FlagManager.cpp +++ b/services/surfaceflinger/common/FlagManager.cpp @@ -119,7 +119,6 @@ void FlagManager::dump(std::string& result) const { DUMP_READ_ONLY_FLAG(connected_display); DUMP_READ_ONLY_FLAG(enable_small_area_detection); DUMP_READ_ONLY_FLAG(frame_rate_category_mrr); - DUMP_READ_ONLY_FLAG(view_set_requested_frame_rate_mrr); DUMP_READ_ONLY_FLAG(misc1); DUMP_READ_ONLY_FLAG(vrr_config); DUMP_READ_ONLY_FLAG(hotplug2); @@ -144,11 +143,13 @@ void FlagManager::dump(std::string& result) const { DUMP_READ_ONLY_FLAG(ce_fence_promise); DUMP_READ_ONLY_FLAG(idle_screen_refresh_rate_timeout); DUMP_READ_ONLY_FLAG(graphite_renderengine); + DUMP_READ_ONLY_FLAG(filter_frames_before_trace_starts); DUMP_READ_ONLY_FLAG(latch_unsignaled_with_auto_refresh_changed); DUMP_READ_ONLY_FLAG(deprecate_vsync_sf); DUMP_READ_ONLY_FLAG(allow_n_vsyncs_in_targeter); DUMP_READ_ONLY_FLAG(detached_mirror); DUMP_READ_ONLY_FLAG(commit_not_composited); + DUMP_READ_ONLY_FLAG(correct_dpi_with_display_size); DUMP_READ_ONLY_FLAG(local_tonemap_screenshots); DUMP_READ_ONLY_FLAG(override_trusted_overlay); DUMP_READ_ONLY_FLAG(flush_buffer_slots_to_uncache); @@ -224,8 +225,6 @@ FLAG_MANAGER_LEGACY_SERVER_FLAG(use_skia_tracing, PROPERTY_SKIA_ATRACE_ENABLED, 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") -FLAG_MANAGER_READ_ONLY_FLAG(view_set_requested_frame_rate_mrr, - "debug.sf.view_set_requested_frame_rate_mrr") FLAG_MANAGER_READ_ONLY_FLAG(misc1, "") FLAG_MANAGER_READ_ONLY_FLAG(vrr_config, "debug.sf.enable_vrr_config") FLAG_MANAGER_READ_ONLY_FLAG(hotplug2, "") @@ -250,11 +249,13 @@ FLAG_MANAGER_READ_ONLY_FLAG(vrr_bugfix_24q4, ""); FLAG_MANAGER_READ_ONLY_FLAG(vrr_bugfix_dropped_frame, "") FLAG_MANAGER_READ_ONLY_FLAG(ce_fence_promise, ""); FLAG_MANAGER_READ_ONLY_FLAG(graphite_renderengine, "debug.renderengine.graphite") +FLAG_MANAGER_READ_ONLY_FLAG(filter_frames_before_trace_starts, "") FLAG_MANAGER_READ_ONLY_FLAG(latch_unsignaled_with_auto_refresh_changed, ""); FLAG_MANAGER_READ_ONLY_FLAG(deprecate_vsync_sf, ""); FLAG_MANAGER_READ_ONLY_FLAG(allow_n_vsyncs_in_targeter, ""); FLAG_MANAGER_READ_ONLY_FLAG(detached_mirror, ""); FLAG_MANAGER_READ_ONLY_FLAG(commit_not_composited, ""); +FLAG_MANAGER_READ_ONLY_FLAG(correct_dpi_with_display_size, ""); FLAG_MANAGER_READ_ONLY_FLAG(local_tonemap_screenshots, "debug.sf.local_tonemap_screenshots"); FLAG_MANAGER_READ_ONLY_FLAG(override_trusted_overlay, ""); FLAG_MANAGER_READ_ONLY_FLAG(flush_buffer_slots_to_uncache, ""); diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h index 473e564903..a1be19421b 100644 --- a/services/surfaceflinger/common/include/common/FlagManager.h +++ b/services/surfaceflinger/common/include/common/FlagManager.h @@ -56,7 +56,6 @@ public: /// Trunk stable readonly flags /// bool connected_display() const; bool frame_rate_category_mrr() const; - bool view_set_requested_frame_rate_mrr() const; bool enable_small_area_detection() const; bool misc1() const; bool vrr_config() const; @@ -82,11 +81,13 @@ public: bool ce_fence_promise() const; bool idle_screen_refresh_rate_timeout() const; bool graphite_renderengine() const; + bool filter_frames_before_trace_starts() const; bool latch_unsignaled_with_auto_refresh_changed() const; bool deprecate_vsync_sf() const; bool allow_n_vsyncs_in_targeter() const; bool detached_mirror() const; bool commit_not_composited() const; + bool correct_dpi_with_display_size() const; bool local_tonemap_screenshots() const; bool override_trusted_overlay() const; bool flush_buffer_slots_to_uncache() const; diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig index 0ff846e744..102e2b643c 100644 --- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig @@ -4,10 +4,10 @@ package: "com.android.graphics.surfaceflinger.flags" container: "system" 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" - bug: "284324521" + name: "adpf_gpu_sf" + namespace: "game" + description: "Guards use of the sending ADPF GPU duration hint and load hints from SurfaceFlinger to Power HAL" + bug: "284324521" } # adpf_gpu_sf flag { @@ -21,18 +21,29 @@ flag { } } # ce_fence_promise - flag { - name: "commit_not_composited" - namespace: "core_graphics" - description: "mark frames as non janky if the transaction resulted in no composition" - bug: "340633280" - is_fixed_read_only: true - metadata { - purpose: PURPOSE_BUGFIX - } - } # commit_not_composited +flag { + name: "commit_not_composited" + namespace: "core_graphics" + description: "mark frames as non janky if the transaction resulted in no composition" + bug: "340633280" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} # commit_not_composited - flag { +flag { + name: "correct_dpi_with_display_size" + namespace: "core_graphics" + description: "indicate whether missing or likely incorrect dpi should be corrected using the display size." + bug: "328425848" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} # correct_dpi_with_display_size + +flag { name: "deprecate_vsync_sf" namespace: "core_graphics" description: "Depracate eVsyncSourceSurfaceFlinger and use vsync_app everywhere" @@ -43,7 +54,7 @@ flag { } } # deprecate_vsync_sf - flag { +flag { name: "detached_mirror" namespace: "window_surfaces" description: "Ignore local transform when mirroring a partial hierarchy" @@ -55,6 +66,17 @@ flag { } # detached_mirror flag { + name: "filter_frames_before_trace_starts" + namespace: "core_graphics" + description: "Do not trace FrameTimeline events for frames started before the trace started" + bug: "364194637" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} # filter_frames_before_trace_starts + +flag { name: "flush_buffer_slots_to_uncache" namespace: "core_graphics" description: "Flush DisplayCommands for disabled displays in order to uncache requested buffers." @@ -96,11 +118,11 @@ flag { } # latch_unsignaled_with_auto_refresh_changed flag { - name: "local_tonemap_screenshots" - namespace: "core_graphics" - description: "Enables local tonemapping when capturing screenshots" - bug: "329464641" - is_fixed_read_only: true + name: "local_tonemap_screenshots" + namespace: "core_graphics" + description: "Enables local tonemapping when capturing screenshots" + bug: "329464641" + is_fixed_read_only: true } # local_tonemap_screenshots flag { @@ -115,11 +137,11 @@ flag { } # single_hop_screenshot flag { - name: "true_hdr_screenshots" - namespace: "core_graphics" - description: "Enables screenshotting display content in HDR, sans tone mapping" - bug: "329470026" - is_fixed_read_only: true + name: "true_hdr_screenshots" + namespace: "core_graphics" + description: "Enables screenshotting display content in HDR, sans tone mapping" + bug: "329470026" + is_fixed_read_only: true } # true_hdr_screenshots flag { @@ -134,11 +156,11 @@ flag { } # override_trusted_overlay flag { - name: "view_set_requested_frame_rate_mrr" - namespace: "core_graphics" - description: "Enable to use frame rate category NoPreference with fixed frame rate vote on MRR devices" - bug: "352206100" - is_fixed_read_only: true + name: "view_set_requested_frame_rate_mrr" + namespace: "core_graphics" + description: "Enable to use frame rate category NoPreference with fixed frame rate vote on MRR devices" + bug: "352206100" + is_fixed_read_only: true } # view_set_requested_frame_rate_mrr flag { diff --git a/services/surfaceflinger/tests/OWNERS b/services/surfaceflinger/tests/OWNERS index 56f2f1b07a..7857961ce4 100644 --- a/services/surfaceflinger/tests/OWNERS +++ b/services/surfaceflinger/tests/OWNERS @@ -4,5 +4,5 @@ per-file HdrSdrRatioOverlay_test.cpp = alecmouri@google.com, sallyqi@google.com, per-file Layer* = set noparent per-file Layer* = pdwilliams@google.com, vishnun@google.com, melodymhsu@google.com -per-file LayerHistoryTest.cpp = file:/services/surfaceflinger/OWNERS +per-file LayerHistoryIntegrationTest.cpp = file:/services/surfaceflinger/OWNERS per-file LayerInfoTest.cpp = file:/services/surfaceflinger/OWNERS
\ No newline at end of file diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h index 3104dd4720..ae380ad459 100644 --- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h +++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h @@ -515,6 +515,23 @@ public: mLifecycleManager.applyTransactions(transactions); } + void setEdgeExtensionEffect(uint32_t id, int edge) { + std::vector<TransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.what |= layer_state_t::eEdgeExtensionChanged; + transactions.back().states.front().state.edgeExtensionParameters = + gui::EdgeExtensionParameters(); + transactions.back().states.front().state.edgeExtensionParameters.extendLeft = edge & LEFT; + transactions.back().states.front().state.edgeExtensionParameters.extendRight = edge & RIGHT; + transactions.back().states.front().state.edgeExtensionParameters.extendTop = edge & TOP; + transactions.back().states.front().state.edgeExtensionParameters.extendBottom = + edge & BOTTOM; + mLifecycleManager.applyTransactions(transactions); + } + private: LayerLifecycleManager& mLifecycleManager; }; diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index 9be0fc38b3..0dfbd6185e 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -84,9 +84,11 @@ public: void SetUp() override { constexpr bool kUseBootTimeClock = true; + constexpr bool kFilterFramesBeforeTraceStarts = false; mTimeStats = std::make_shared<mock::TimeStats>(); mFrameTimeline = std::make_unique<impl::FrameTimeline>(mTimeStats, kSurfaceFlingerPid, - kTestThresholds, !kUseBootTimeClock); + kTestThresholds, !kUseBootTimeClock, + kFilterFramesBeforeTraceStarts); mFrameTimeline->registerDataSource(); mTokenManager = &mFrameTimeline->mTokenManager; mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter; diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index 2cff2f2929..e0753a3cfb 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -58,6 +58,7 @@ using namespace std::chrono_literals; using Hwc2::Config; +using ::aidl::android::hardware::drm::HdcpLevels; using ::aidl::android::hardware::graphics::common::DisplayHotplugEvent; using ::aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData; using hal::IComposerClient; @@ -165,6 +166,7 @@ TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { expectHotplugConnect(kHwcDisplayId); const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); ASSERT_TRUE(info); + ASSERT_TRUE(info->preferredDetailedTimingDescriptor.has_value()); EXPECT_CALL(*mHal, isVrrSupported()).WillRepeatedly(Return(false)); @@ -178,6 +180,10 @@ TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { constexpr int32_t kHeight = 720; constexpr int32_t kConfigGroup = 1; constexpr int32_t kVsyncPeriod = 16666667; + constexpr float kMmPerInch = 25.4f; + const ui::Size size = info->preferredDetailedTimingDescriptor->physicalSizeInMm; + const float expectedDpiX = (kWidth * kMmPerInch / size.width); + const float expectedDpiY = (kHeight * kMmPerInch / size.height); EXPECT_CALL(*mHal, getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::WIDTH, @@ -217,8 +223,13 @@ TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { EXPECT_EQ(modes.front().height, kHeight); EXPECT_EQ(modes.front().configGroup, kConfigGroup); EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); - EXPECT_EQ(modes.front().dpiX, -1); - EXPECT_EQ(modes.front().dpiY, -1); + if (!FlagManager::getInstance().correct_dpi_with_display_size()) { + EXPECT_EQ(modes.front().dpiX, -1); + EXPECT_EQ(modes.front().dpiY, -1); + } else { + EXPECT_EQ(modes.front().dpiX, expectedDpiX); + EXPECT_EQ(modes.front().dpiY, expectedDpiY); + } // Optional parameters are supported constexpr int32_t kDpi = 320; @@ -270,6 +281,10 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_OFF) { constexpr int32_t kHeight = 720; constexpr int32_t kConfigGroup = 1; constexpr int32_t kVsyncPeriod = 16666667; + constexpr float kMmPerInch = 25.4f; + const ui::Size size = info->preferredDetailedTimingDescriptor->physicalSizeInMm; + const float expectedDpiX = (kWidth * kMmPerInch / size.width); + const float expectedDpiY = (kHeight * kMmPerInch / size.height); EXPECT_CALL(*mHal, getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::WIDTH, @@ -309,8 +324,13 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_OFF) { EXPECT_EQ(modes.front().height, kHeight); EXPECT_EQ(modes.front().configGroup, kConfigGroup); EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); - EXPECT_EQ(modes.front().dpiX, -1); - EXPECT_EQ(modes.front().dpiY, -1); + if (!FlagManager::getInstance().correct_dpi_with_display_size()) { + EXPECT_EQ(modes.front().dpiX, -1); + EXPECT_EQ(modes.front().dpiY, -1); + } else { + EXPECT_EQ(modes.front().dpiX, expectedDpiX); + EXPECT_EQ(modes.front().dpiY, expectedDpiY); + } // Optional parameters are supported constexpr int32_t kDpi = 320; @@ -360,6 +380,10 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_ON) { constexpr int32_t kHeight = 720; constexpr int32_t kConfigGroup = 1; constexpr int32_t kVsyncPeriod = 16666667; + constexpr float kMmPerInch = 25.4f; + const ui::Size size = info->preferredDetailedTimingDescriptor->physicalSizeInMm; + const float expectedDpiX = (kWidth * kMmPerInch / size.width); + const float expectedDpiY = (kHeight * kMmPerInch / size.height); const hal::VrrConfig vrrConfig = hal::VrrConfig{.minFrameIntervalNs = static_cast<Fps>(120_Hz).getPeriodNsecs(), .notifyExpectedPresentConfig = hal::VrrConfig:: @@ -386,8 +410,13 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_ON) { EXPECT_EQ(modes.front().configGroup, kConfigGroup); EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); EXPECT_EQ(modes.front().vrrConfig, vrrConfig); - EXPECT_EQ(modes.front().dpiX, -1); - EXPECT_EQ(modes.front().dpiY, -1); + if (!FlagManager::getInstance().correct_dpi_with_display_size()) { + EXPECT_EQ(modes.front().dpiX, -1); + EXPECT_EQ(modes.front().dpiY, -1); + } else { + EXPECT_EQ(modes.front().dpiX, expectedDpiX); + EXPECT_EQ(modes.front().dpiY, expectedDpiY); + } // Supports optional dpi parameter constexpr int32_t kDpi = 320; @@ -454,6 +483,8 @@ struct MockHWC2ComposerCallback final : StrictMock<HWC2::ComposerCallback> { MOCK_METHOD1(onComposerHalSeamlessPossible, void(hal::HWDisplayId)); MOCK_METHOD1(onComposerHalVsyncIdle, void(hal::HWDisplayId)); MOCK_METHOD(void, onRefreshRateChangedDebug, (const RefreshRateChangedDebugData&), (override)); + MOCK_METHOD(void, onComposerHalHdcpLevelsChanged, (hal::HWDisplayId, const HdcpLevels&), + (override)); }; struct HWComposerSetCallbackTest : HWComposerTest { diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp index 7e84408f7d..de37b6342c 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp @@ -894,7 +894,6 @@ TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitCategory) { TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVoteWithFixedSourceAndNoPreferenceCategory) { SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); - SET_FLAG_FOR_TEST(flags::view_set_requested_frame_rate_mrr, true); auto layer = createLegacyAndFrontedEndLayer(1); setFrameRate(1, (45.6_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 2860345538..90207232b0 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -27,6 +27,7 @@ #include "LayerHierarchyTest.h" #include "ui/GraphicTypes.h" +#include <com_android_graphics_libgui_flags.h> #include <com_android_graphics_surfaceflinger_flags.h> #define UPDATE_AND_VERIFY(BUILDER, ...) \ @@ -1761,4 +1762,162 @@ TEST_F(LayerSnapshotTest, hideLayerWithNanMatrix) { UPDATE_AND_VERIFY(mSnapshotBuilder, {2}); EXPECT_TRUE(getSnapshot(1)->isHiddenByPolicy()); } +TEST_F(LayerSnapshotTest, edgeExtensionPropagatesInHierarchy) { + if (!com::android::graphics::libgui::flags::edge_extension_shader()) { + GTEST_SKIP() << "Skipping test because edge_extension_shader is off"; + } + setCrop(1, Rect(0, 0, 20, 20)); + setBuffer(1221, + std::make_shared<renderengine::mock::FakeExternalTexture>(20 /* width */, + 20 /* height */, + 42ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0 /*usage*/)); + setEdgeExtensionEffect(12, LEFT); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + + EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(LEFT)); + EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(LEFT)); + EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(LEFT)); + + setEdgeExtensionEffect(12, RIGHT); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + + EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(RIGHT)); + EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(RIGHT)); + EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(RIGHT)); + + setEdgeExtensionEffect(12, TOP); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + + EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(TOP)); + EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(TOP)); + EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(TOP)); + + setEdgeExtensionEffect(12, BOTTOM); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + + EXPECT_TRUE(getSnapshot({.id = 12})->edgeExtensionEffect.extendsEdge(BOTTOM)); + EXPECT_TRUE(getSnapshot({.id = 121})->edgeExtensionEffect.extendsEdge(BOTTOM)); + EXPECT_TRUE(getSnapshot({.id = 1221})->edgeExtensionEffect.extendsEdge(BOTTOM)); +} + +TEST_F(LayerSnapshotTest, leftEdgeExtensionIncreaseBoundSizeWithinCrop) { + // The left bound is extended when shifting to the right + if (!com::android::graphics::libgui::flags::edge_extension_shader()) { + GTEST_SKIP() << "Skipping test because edge_extension_shader is off"; + } + setCrop(1, Rect(0, 0, 20, 20)); + const int texSize = 10; + setBuffer(1221, + std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */, + texSize /* height*/, + 42ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0 /*usage*/)); + const float translation = 5.0; + setPosition(12, translation, 0); + setEdgeExtensionEffect(12, LEFT); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.right, texSize + translation); + EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.left, translation); + EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.left, 0.0); +} + +TEST_F(LayerSnapshotTest, rightEdgeExtensionIncreaseBoundSizeWithinCrop) { + // The right bound is extended when shifting to the left + if (!com::android::graphics::libgui::flags::edge_extension_shader()) { + GTEST_SKIP() << "Skipping test because edge_extension_shader is off"; + } + const int crop = 20; + setCrop(1, Rect(0, 0, crop, crop)); + const int texSize = 10; + setBuffer(1221, + std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */, + texSize /* height*/, + 42ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0 /*usage*/)); + const float translation = -5.0; + setPosition(12, translation, 0); + setEdgeExtensionEffect(12, RIGHT); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.left, 0); + EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.right, texSize + translation); + EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.right, (float)crop); +} + +TEST_F(LayerSnapshotTest, topEdgeExtensionIncreaseBoundSizeWithinCrop) { + // The top bound is extended when shifting to the bottom + if (!com::android::graphics::libgui::flags::edge_extension_shader()) { + GTEST_SKIP() << "Skipping test because edge_extension_shader is off"; + } + setCrop(1, Rect(0, 0, 20, 20)); + const int texSize = 10; + setBuffer(1221, + std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */, + texSize /* height*/, + 42ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0 /*usage*/)); + const float translation = 5.0; + setPosition(12, 0, translation); + setEdgeExtensionEffect(12, TOP); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.bottom, texSize + translation); + EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.top, translation); + EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.top, 0.0); +} + +TEST_F(LayerSnapshotTest, bottomEdgeExtensionIncreaseBoundSizeWithinCrop) { + // The bottom bound is extended when shifting to the top + if (!com::android::graphics::libgui::flags::edge_extension_shader()) { + GTEST_SKIP() << "Skipping test because edge_extension_shader is off"; + } + const int crop = 20; + setCrop(1, Rect(0, 0, crop, crop)); + const int texSize = 10; + setBuffer(1221, + std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */, + texSize /* height*/, + 42ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0 /*usage*/)); + const float translation = -5.0; + setPosition(12, 0, translation); + setEdgeExtensionEffect(12, BOTTOM); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot({.id = 1221})->transformedBounds.top, 0); + EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.bottom, texSize - translation); + EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.bottom, (float)crop); +} + +TEST_F(LayerSnapshotTest, multipleEdgeExtensionIncreaseBoundSizeWithinCrop) { + // The left bound is extended when shifting to the right + if (!com::android::graphics::libgui::flags::edge_extension_shader()) { + GTEST_SKIP() << "Skipping test because edge_extension_shader is off"; + } + const int crop = 20; + setCrop(1, Rect(0, 0, crop, crop)); + const int texSize = 10; + setBuffer(1221, + std::make_shared<renderengine::mock::FakeExternalTexture>(texSize /* width */, + texSize /* height*/, + 42ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0 /*usage*/)); + const float translation = 5.0; + setPosition(12, translation, translation); + setEdgeExtensionEffect(12, LEFT | RIGHT | TOP | BOTTOM); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.right, texSize + translation); + EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.right, (float)crop); + EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.left, translation); + EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.left, 0.0); + EXPECT_GT(getSnapshot({.id = 1221})->transformedBounds.bottom, texSize + translation); + EXPECT_LE(getSnapshot({.id = 1221})->transformedBounds.bottom, (float)crop); + EXPECT_LT(getSnapshot({.id = 1221})->transformedBounds.top, translation); + EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.top, 0); +} + } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index 06c4e30989..9efe73d450 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -1837,6 +1837,43 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_60_12 } } +TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_vrrHighHintTouch_primaryRangeIsSingleRate) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + SET_FLAG_FOR_TEST(flags::vrr_config, true); + + auto selector = createSelector(kVrrMode_120, kModeId120); + selector.setActiveMode(kModeId120, 60_Hz); + + // Change primary physical range to be single rate, which on VRR device should not affect + // fps scoring. + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId120, {120_Hz, 120_Hz}})); + + std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}}; + layers[0].vote = LayerVoteType::ExplicitCategory; + layers[0].frameRateCategory = FrameRateCategory::HighHint; + layers[0].name = "ExplicitCategory HighHint"; + + auto actualRankedFrameRates = selector.getRankedFrameRates(layers); + // Expect late touch boost from HighHint. + EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps); + EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId()); + EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch); + + layers[1].vote = LayerVoteType::ExplicitExactOrMultiple; + layers[1].desiredRefreshRate = 30_Hz; + layers[1].name = "ExplicitExactOrMultiple 30Hz"; + + actualRankedFrameRates = selector.getRankedFrameRates(layers); + // Expect late touch boost from HighHint. + EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps); + EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId()); + EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch); +} + TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_HighHint) { auto selector = createSelector(makeModes(kMode24, kMode30, kMode60, kMode120), kModeId60); @@ -1955,7 +1992,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_HighH // Gets touch boost EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps); EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId()); - EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch); + EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_TouchBoost) { @@ -2049,7 +2086,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_Touch lr2.name = "Max"; actualRankedFrameRates = selector.getRankedFrameRates(layers, {.touch = true}); EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, actualRankedFrameRates.ranking.front().frameRateMode); - EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch); + EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch); lr1.vote = LayerVoteType::ExplicitCategory; lr1.frameRateCategory = FrameRateCategory::Normal; diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp index 933d03dac1..352000ef9a 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp @@ -239,7 +239,7 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { ASSERT_TRUE(displayId); const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value; ASSERT_TRUE(hwcDisplayId); - mFlinger.getHwComposer().allocatePhysicalDisplay(*hwcDisplayId, *displayId); + mFlinger.getHwComposer().allocatePhysicalDisplay(*hwcDisplayId, *displayId, std::nullopt); DisplayModePtr activeMode = DisplayMode::Builder(Case::Display::HWC_ACTIVE_CONFIG_ID) .setResolution(Case::Display::RESOLUTION) .setVsyncPeriod(DEFAULT_VSYNC_PERIOD) diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 710b5cc623..725354b845 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -335,13 +335,6 @@ public: return mFlinger->mLegacyLayers[layerId]->findOutputLayerForDisplay(display.get()); } - static void setLayerSidebandStream(const sp<Layer>& layer, - const sp<NativeHandle>& sidebandStream) { - layer->mDrawingState.sidebandStream = sidebandStream; - layer->mSidebandStream = sidebandStream; - layer->editLayerSnapshot()->sidebandStream = sidebandStream; - } - void setLayerCompositionType(const sp<Layer>& layer, aidl::android::hardware::graphics::composer3::Composition type) { auto outputLayer = findOutputLayerForDisplay(static_cast<uint32_t>(layer->sequence), @@ -352,10 +345,6 @@ public: (*state.hwc).hwcCompositionType = type; } - static void setLayerDrawingParent(const sp<Layer>& layer, const sp<Layer>& drawingParent) { - layer->mDrawingParent = drawingParent; - } - /* ------------------------------------------------------------------------ * Forwarding for functions being tested */ @@ -501,9 +490,10 @@ public: auto layers = getLayerSnapshotsFn(); auto layerFEs = mFlinger->extractLayerFEs(layers); - return mFlinger->renderScreenImpl(std::move(renderArea), buffer, regionSampling, + return mFlinger->renderScreenImpl(renderArea.get(), buffer, regionSampling, false /* grayscale */, false /* isProtected */, - captureResults, displayState, layers, layerFEs); + false /* attachGainmap */, captureResults, displayState, + layers, layerFEs); } auto getLayerSnapshotsForScreenshotsFn(ui::LayerStack layerStack, uint32_t uid) { @@ -547,7 +537,7 @@ public: } auto flushTransactionQueues() { - return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues(kVsyncId)); + return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues()); } auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h index 2cc19873f5..5edd2cd9e3 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -35,6 +35,7 @@ public: (const, override)); MOCK_METHOD(bool, isVsyncPeriodSwitchSupported, (), (const, override)); MOCK_METHOD(void, onLayerDestroyed, (hal::HWLayerId), (override)); + MOCK_METHOD(std::optional<ui::Size>, getPhysicalSizeInMm, (), (const override)); MOCK_METHOD(hal::Error, acceptChanges, (), (override)); MOCK_METHOD((base::expected<std::shared_ptr<HWC2::Layer>, hal::Error>), createLayer, (), diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h index fdb6f4dafe..45f86fa1a8 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -31,15 +31,11 @@ public: explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {} - MOCK_CONST_METHOD0(getType, const char*()); MOCK_METHOD0(getFrameSelectionPriority, int32_t()); - MOCK_CONST_METHOD0(isVisible, bool()); MOCK_METHOD0(createClone, sp<Layer>()); MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate()); MOCK_CONST_METHOD0(getDefaultFrameRateCompatibility, scheduler::FrameRateCompatibility()); MOCK_CONST_METHOD0(getOwnerUid, uid_t()); - MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace()); - MOCK_METHOD(bool, isFrontBuffered, (), (const, override)); }; } // namespace android::mock diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp index 3d8124b81b..4ac16188fa 100644 --- a/services/vibratorservice/VibratorHalWrapper.cpp +++ b/services/vibratorservice/VibratorHalWrapper.cpp @@ -96,6 +96,17 @@ Info HalWrapper::getInfo() { if (mInfoCache.mMaxAmplitudes.isFailed()) { mInfoCache.mMaxAmplitudes = getMaxAmplitudesInternal(); } + if (mInfoCache.mMaxEnvelopeEffectSize.isFailed()) { + mInfoCache.mMaxEnvelopeEffectSize = getMaxEnvelopeEffectSizeInternal(); + } + if (mInfoCache.mMinEnvelopeEffectControlPointDuration.isFailed()) { + mInfoCache.mMinEnvelopeEffectControlPointDuration = + getMinEnvelopeEffectControlPointDurationInternal(); + } + if (mInfoCache.mMaxEnvelopeEffectControlPointDuration.isFailed()) { + mInfoCache.mMaxEnvelopeEffectControlPointDuration = + getMaxEnvelopeEffectControlPointDurationInternal(); + } return mInfoCache.get(); } @@ -210,6 +221,23 @@ HalResult<std::vector<float>> HalWrapper::getMaxAmplitudesInternal() { ALOGV("Skipped getMaxAmplitudes because it's not available in Vibrator HAL"); return HalResult<std::vector<float>>::unsupported(); } +HalResult<int32_t> HalWrapper::getMaxEnvelopeEffectSizeInternal() { + ALOGV("Skipped getMaxEnvelopeEffectSizeInternal because it's not available " + "in Vibrator HAL"); + return HalResult<int32_t>::unsupported(); +} + +HalResult<milliseconds> HalWrapper::getMinEnvelopeEffectControlPointDurationInternal() { + ALOGV("Skipped getMinEnvelopeEffectControlPointDurationInternal because it's not " + "available in Vibrator HAL"); + return HalResult<milliseconds>::unsupported(); +} + +HalResult<milliseconds> HalWrapper::getMaxEnvelopeEffectControlPointDurationInternal() { + ALOGV("Skipped getMaxEnvelopeEffectControlPointDurationInternal because it's not " + "available in Vibrator HAL"); + return HalResult<milliseconds>::unsupported(); +} // ------------------------------------------------------------------------------------------------- @@ -441,6 +469,24 @@ HalResult<std::vector<float>> AidlHalWrapper::getMaxAmplitudesInternal() { return HalResultFactory::fromStatus<std::vector<float>>(std::move(status), amplitudes); } +HalResult<int32_t> AidlHalWrapper::getMaxEnvelopeEffectSizeInternal() { + int32_t size = 0; + auto status = getHal()->getPwleV2CompositionSizeMax(&size); + return HalResultFactory::fromStatus<int32_t>(std::move(status), size); +} + +HalResult<milliseconds> AidlHalWrapper::getMinEnvelopeEffectControlPointDurationInternal() { + int32_t durationMs = 0; + auto status = getHal()->getPwleV2PrimitiveDurationMinMillis(&durationMs); + return HalResultFactory::fromStatus<milliseconds>(std::move(status), milliseconds(durationMs)); +} + +HalResult<milliseconds> AidlHalWrapper::getMaxEnvelopeEffectControlPointDurationInternal() { + int32_t durationMs = 0; + auto status = getHal()->getPwleV2PrimitiveDurationMaxMillis(&durationMs); + return HalResultFactory::fromStatus<milliseconds>(std::move(status), milliseconds(durationMs)); +} + std::shared_ptr<Aidl::IVibrator> AidlHalWrapper::getHal() { std::lock_guard<std::mutex> lock(mHandleMutex); return mHandle; diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h index ae0d9ab411..4938b156e7 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h +++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h @@ -258,6 +258,9 @@ public: const HalResult<float> frequencyResolution; const HalResult<float> qFactor; const HalResult<std::vector<float>> maxAmplitudes; + const HalResult<int32_t> maxEnvelopeEffectSize; + const HalResult<std::chrono::milliseconds> minEnvelopeEffectControlPointDuration; + const HalResult<std::chrono::milliseconds> maxEnvelopeEffectControlPointDuration; void logFailures() const { logFailure<Capabilities>(capabilities, "getCapabilities"); @@ -276,6 +279,11 @@ public: logFailure<float>(frequencyResolution, "getFrequencyResolution"); logFailure<float>(qFactor, "getQFactor"); logFailure<std::vector<float>>(maxAmplitudes, "getMaxAmplitudes"); + logFailure<int32_t>(maxEnvelopeEffectSize, "getMaxEnvelopeEffectSize"); + logFailure<std::chrono::milliseconds>(minEnvelopeEffectControlPointDuration, + "getMinEnvelopeEffectControlPointDuration"); + logFailure<std::chrono::milliseconds>(maxEnvelopeEffectControlPointDuration, + "getMaxEnvelopeEffectControlPointDuration"); } bool shouldRetry() const { @@ -285,7 +293,10 @@ public: pwlePrimitiveDurationMax.shouldRetry() || compositionSizeMax.shouldRetry() || pwleSizeMax.shouldRetry() || minFrequency.shouldRetry() || resonantFrequency.shouldRetry() || frequencyResolution.shouldRetry() || - qFactor.shouldRetry() || maxAmplitudes.shouldRetry(); + qFactor.shouldRetry() || maxAmplitudes.shouldRetry() || + maxEnvelopeEffectSize.shouldRetry() || + minEnvelopeEffectControlPointDuration.shouldRetry() || + maxEnvelopeEffectControlPointDuration.shouldRetry(); } private: @@ -313,7 +324,10 @@ public: mResonantFrequency, mFrequencyResolution, mQFactor, - mMaxAmplitudes}; + mMaxAmplitudes, + mMaxEnvelopeEffectSize, + mMinEnvelopeEffectControlPointDuration, + mMaxEnvelopeEffectControlPointDuration}; } private: @@ -340,6 +354,11 @@ private: HalResult<float> mQFactor = HalResult<float>::transactionFailed(MSG); HalResult<std::vector<float>> mMaxAmplitudes = HalResult<std::vector<float>>::transactionFailed(MSG); + HalResult<int32_t> mMaxEnvelopeEffectSize = HalResult<int>::transactionFailed(MSG); + HalResult<std::chrono::milliseconds> mMinEnvelopeEffectControlPointDuration = + HalResult<std::chrono::milliseconds>::transactionFailed(MSG); + HalResult<std::chrono::milliseconds> mMaxEnvelopeEffectControlPointDuration = + HalResult<std::chrono::milliseconds>::transactionFailed(MSG); friend class HalWrapper; }; @@ -420,6 +439,9 @@ protected: virtual HalResult<float> getFrequencyResolutionInternal(); virtual HalResult<float> getQFactorInternal(); virtual HalResult<std::vector<float>> getMaxAmplitudesInternal(); + virtual HalResult<int32_t> getMaxEnvelopeEffectSizeInternal(); + virtual HalResult<std::chrono::milliseconds> getMinEnvelopeEffectControlPointDurationInternal(); + virtual HalResult<std::chrono::milliseconds> getMaxEnvelopeEffectControlPointDurationInternal(); private: std::mutex mInfoMutex; @@ -495,6 +517,13 @@ protected: HalResult<float> getFrequencyResolutionInternal() override final; HalResult<float> getQFactorInternal() override final; HalResult<std::vector<float>> getMaxAmplitudesInternal() override final; + HalResult<int32_t> getMaxEnvelopeEffectSizeInternal() override final; + + HalResult<std::chrono::milliseconds> getMinEnvelopeEffectControlPointDurationInternal() + override final; + + HalResult<std::chrono::milliseconds> getMaxEnvelopeEffectControlPointDurationInternal() + override final; private: const reconnect_fn mReconnectFn; diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp index ba7e1f07bf..17f384d320 100644 --- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp +++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp @@ -235,6 +235,9 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) { constexpr int32_t PWLE_SIZE_MAX = 20; constexpr int32_t PRIMITIVE_DELAY_MAX = 100; constexpr int32_t PWLE_DURATION_MAX = 200; + constexpr int32_t PWLE_V2_COMPOSITION_SIZE_MAX = 16; + constexpr int32_t PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS = 20; + constexpr int32_t PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS = 1000; std::vector<Effect> supportedEffects = {Effect::CLICK, Effect::TICK}; std::vector<CompositePrimitive> supportedPrimitives = {CompositePrimitive::CLICK}; std::vector<Braking> supportedBraking = {Braking::CLAB}; @@ -305,6 +308,21 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) { .Times(Exactly(2)) .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) .WillOnce(DoAll(SetArgPointee<0>(amplitudes), Return(ndk::ScopedAStatus::ok()))); + EXPECT_CALL(*mMockHal.get(), getPwleV2CompositionSizeMax(_)) + .Times(Exactly(2)) + .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) + .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_COMPOSITION_SIZE_MAX), + Return(ndk::ScopedAStatus::ok()))); + EXPECT_CALL(*mMockHal.get(), getPwleV2PrimitiveDurationMinMillis(_)) + .Times(Exactly(2)) + .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) + .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS), + Return(ndk::ScopedAStatus::ok()))); + EXPECT_CALL(*mMockHal.get(), getPwleV2PrimitiveDurationMaxMillis(_)) + .Times(Exactly(2)) + .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) + .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS), + Return(ndk::ScopedAStatus::ok()))); vibrator::Info failed = mWrapper->getInfo(); ASSERT_TRUE(failed.capabilities.isFailed()); @@ -321,6 +339,9 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) { ASSERT_TRUE(failed.frequencyResolution.isFailed()); ASSERT_TRUE(failed.qFactor.isFailed()); ASSERT_TRUE(failed.maxAmplitudes.isFailed()); + ASSERT_TRUE(failed.maxEnvelopeEffectSize.isFailed()); + ASSERT_TRUE(failed.minEnvelopeEffectControlPointDuration.isFailed()); + ASSERT_TRUE(failed.maxEnvelopeEffectControlPointDuration.isFailed()); vibrator::Info successful = mWrapper->getInfo(); ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, successful.capabilities.value()); @@ -338,6 +359,11 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) { ASSERT_EQ(F_RESOLUTION, successful.frequencyResolution.value()); ASSERT_EQ(Q_FACTOR, successful.qFactor.value()); ASSERT_EQ(amplitudes, successful.maxAmplitudes.value()); + ASSERT_EQ(PWLE_V2_COMPOSITION_SIZE_MAX, successful.maxEnvelopeEffectSize.value()); + ASSERT_EQ(std::chrono::milliseconds(PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS), + successful.minEnvelopeEffectControlPointDuration.value()); + ASSERT_EQ(std::chrono::milliseconds(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS), + successful.maxEnvelopeEffectControlPointDuration.value()); } TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) { @@ -347,6 +373,9 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) { constexpr int32_t PWLE_SIZE_MAX = 20; constexpr int32_t PRIMITIVE_DELAY_MAX = 100; constexpr int32_t PWLE_DURATION_MAX = 200; + constexpr int32_t PWLE_V2_COMPOSITION_SIZE_MAX = 16; + constexpr int32_t PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS = 20; + constexpr int32_t PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS = 1000; std::vector<Effect> supportedEffects = {Effect::CLICK, Effect::TICK}; EXPECT_CALL(*mMockHal.get(), getCapabilities(_)) @@ -391,6 +420,18 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) { EXPECT_CALL(*mMockHal.get(), getSupportedBraking(_)) .Times(Exactly(1)) .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))); + EXPECT_CALL(*mMockHal.get(), getPwleV2CompositionSizeMax(_)) + .Times(Exactly(1)) + .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_COMPOSITION_SIZE_MAX), + Return(ndk::ScopedAStatus::ok()))); + EXPECT_CALL(*mMockHal.get(), getPwleV2PrimitiveDurationMinMillis(_)) + .Times(Exactly(1)) + .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS), + Return(ndk::ScopedAStatus::ok()))); + EXPECT_CALL(*mMockHal.get(), getPwleV2PrimitiveDurationMaxMillis(_)) + .Times(Exactly(1)) + .WillOnce(DoAll(SetArgPointee<0>(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS), + Return(ndk::ScopedAStatus::ok()))); std::vector<std::thread> threads; for (int i = 0; i < 10; i++) { @@ -414,6 +455,11 @@ TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) { ASSERT_TRUE(info.frequencyResolution.isUnsupported()); ASSERT_TRUE(info.qFactor.isUnsupported()); ASSERT_TRUE(info.maxAmplitudes.isUnsupported()); + ASSERT_EQ(PWLE_V2_COMPOSITION_SIZE_MAX, info.maxEnvelopeEffectSize.value()); + ASSERT_EQ(std::chrono::milliseconds(PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS), + info.minEnvelopeEffectControlPointDuration.value()); + ASSERT_EQ(std::chrono::milliseconds(PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS), + info.maxEnvelopeEffectControlPointDuration.value()); } TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithCallbackSupport) { diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp index 83430d79a5..a09ddecf91 100644 --- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp +++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp @@ -220,6 +220,9 @@ TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoDoesNotCacheFailedResult) { ASSERT_TRUE(info.frequencyResolution.isUnsupported()); ASSERT_TRUE(info.qFactor.isUnsupported()); ASSERT_TRUE(info.maxAmplitudes.isUnsupported()); + ASSERT_TRUE(info.maxEnvelopeEffectSize.isUnsupported()); + ASSERT_TRUE(info.minEnvelopeEffectControlPointDuration.isUnsupported()); + ASSERT_TRUE(info.maxEnvelopeEffectControlPointDuration.isUnsupported()); } TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoWithoutAmplitudeControl) { @@ -253,6 +256,9 @@ TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoCachesResult) { ASSERT_TRUE(info.frequencyResolution.isUnsupported()); ASSERT_TRUE(info.qFactor.isUnsupported()); ASSERT_TRUE(info.maxAmplitudes.isUnsupported()); + ASSERT_TRUE(info.maxEnvelopeEffectSize.isUnsupported()); + ASSERT_TRUE(info.minEnvelopeEffectControlPointDuration.isUnsupported()); + ASSERT_TRUE(info.maxEnvelopeEffectControlPointDuration.isUnsupported()); } TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformEffect) { |