Merge "Add config for librenderengine_bench" into main
diff --git a/include/input/InputConsumerNoResampling.h b/include/input/InputConsumerNoResampling.h
index 65c2914..358a191 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 @@
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 @@
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 7d8c19e..1a48239 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -389,6 +389,7 @@
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 7d11f76..0cd8720 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -263,7 +263,7 @@
* 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 @@
* 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 @@
*/
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 0000000..2d6719c
--- /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 8c356d0..e5eee34 100644
--- a/include/private/performance_hint_private.h
+++ b/include/private/performance_hint_private.h
@@ -108,6 +108,10 @@
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/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
index 455a433..7263e23 100644
--- a/libs/binder/FdTrigger.cpp
+++ b/libs/binder/FdTrigger.cpp
@@ -82,7 +82,9 @@
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 @@
// 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 6273804..af56bf0 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 @@
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 454bdf1..8288f9f 100644
--- a/libs/bufferstreams/rust/src/stream_config.rs
+++ b/libs/bufferstreams/rust/src/stream_config.rs
@@ -32,10 +32,23 @@
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 @@
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/ScreenCaptureResults.cpp b/libs/gui/ScreenCaptureResults.cpp
index 601a5f9..2de023e 100644
--- a/libs/gui/ScreenCaptureResults.cpp
+++ b/libs/gui/ScreenCaptureResults.cpp
@@ -40,6 +40,13 @@
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 @@
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 2bbed2b..4920344 100644
--- a/libs/gui/aidl/android/gui/CaptureArgs.aidl
+++ b/libs/gui/aidl/android/gui/CaptureArgs.aidl
@@ -69,5 +69,10 @@
// 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 97a9035..f4ef16d 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/ScreenCaptureResults.h b/libs/gui/include/gui/ScreenCaptureResults.h
index 6e17791..f176f48 100644
--- a/libs/gui/include/gui/ScreenCaptureResults.h
+++ b/libs/gui/include/gui/ScreenCaptureResults.h
@@ -36,6 +36,11 @@
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 2ac2550..8db48d2 100644
--- a/libs/gui/tests/Choreographer_test.cpp
+++ b/libs/gui/tests/Choreographer_test.cpp
@@ -52,25 +52,23 @@
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 99ffa68..eb41918 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 @@
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 @@
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 @@
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 @@
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 9333ab8..c903031 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 @@
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 @@
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 @@
}
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 b8a8d76..f1c4aed 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -185,3 +185,10 @@
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 132866b..43bc894 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -16,6 +16,7 @@
"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 @@
"MotionPredictorMetricsManager_test.cpp",
"Resampler_test.cpp",
"RingBuffer_test.cpp",
+ "TestInputChannel.cpp",
+ "TestLooper.cpp",
"TfLiteMotionPredictor_test.cpp",
"TouchResampling_test.cpp",
"TouchVideoFrame_test.cpp",
diff --git a/libs/input/tests/InputConsumer_test.cpp b/libs/input/tests/InputConsumer_test.cpp
new file mode 100644
index 0000000..c30f243
--- /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 0000000..d5f00b6
--- /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 0000000..43253ec
--- /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 0000000..e0f01ed
--- /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 0000000..3242bc7
--- /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 97740db..d68d6ba 100644
--- a/libs/nativewindow/rust/Android.bp
+++ b/libs/nativewindow/rust/Android.bp
@@ -29,6 +29,8 @@
"--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 @@
],
shared_libs: [
"libbinder_ndk",
+ "libcutils",
"libnativewindow",
],
rustlibs: [
@@ -66,6 +69,7 @@
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 0000000..a3a9dc6
--- /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 dc3f51f..931c311 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,11 +30,86 @@
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 a C `AHardwareBuffer_Desc`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct HardwareBufferDescription(AHardwareBuffer_Desc);
+
+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,
+ ) -> Self {
+ Self(AHardwareBuffer_Desc {
+ width,
+ height,
+ layers,
+ format,
+ usage: usage.0,
+ stride,
+ rfu0: 0,
+ rfu1: 0,
+ })
+ }
+
+ /// 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>);
@@ -43,26 +121,9 @@
/// that the allocation of the given description will never succeed.
///
/// Available since API 29
- pub fn is_supported(
- width: u32,
- height: u32,
- layers: u32,
- format: AHardwareBuffer_Format::Type,
- usage: AHardwareBuffer_UsageFlags,
- stride: u32,
- ) -> bool {
- let buffer_desc = ffi::AHardwareBuffer_Desc {
- width,
- height,
- layers,
- format,
- usage: usage.0,
- stride,
- rfu0: 0,
- rfu1: 0,
- };
- // SAFETY: *buffer_desc will never be null.
- let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) };
+ 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 @@
///
/// 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 @@
}
}
+ /// 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 @@
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 @@
};
// 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 @@
#[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 @@
// 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!(
- buffer.usage(),
+ description.format(),
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM
+ );
+ assert_eq!(
+ 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 @@
#[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 @@
#[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 @@
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 5689f7d..5046a80 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 876f6c8..73a7e95 100644
--- a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
+++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
@@ -22,13 +22,14 @@
#[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 @@
// 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 7639fab..d248ea0 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -100,6 +100,7 @@
"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 bc3976d..907590a 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 @@
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/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index 326d1ce..a9264b3 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 @@
}
}
+/**
+ * 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());
+ auto srcBuffer = createTexture(*re, kHomescreenPath);
- // Now copy into GPU-only buffer for more realistic timing.
- srcBuffer = copyBuffer(*re, srcBuffer, 0, "source");
- }
+ 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 @@
};
auto layers = std::vector<LayerSettings>{layer, blurLayer};
- benchDrawLayers(*re, layers, benchState, "blurred");
+ benchDrawLayers(*re, layers, benchState, "homescreen_blurred");
}
-BENCHMARK_CAPTURE(BM_blur, gaussian, RenderEngine::Threaded::YES, RenderEngine::GraphicsApi::GL,
- RenderEngine::BlurAlgorithm::GAUSSIAN);
+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)));
-BENCHMARK_CAPTURE(BM_blur, kawase, RenderEngine::Threaded::YES, RenderEngine::GraphicsApi::GL,
- RenderEngine::BlurAlgorithm::KAWASE);
+ auto [width, height] = getDisplaySize();
+ auto srcBuffer = createTexture(*re, kHomescreenPath);
-BENCHMARK_CAPTURE(BM_blur, kawase_dual_filter, RenderEngine::Threaded::YES,
+ 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_homescreen_blur, gaussian, RenderEngine::Threaded::YES,
+ RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::GAUSSIAN);
+
+BENCHMARK_CAPTURE(BM_homescreen_blur, kawase, RenderEngine::Threaded::YES,
+ RenderEngine::GraphicsApi::GL, RenderEngine::BlurAlgorithm::KAWASE);
+
+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 b640983..280ec19 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -102,6 +102,9 @@
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 9bc2c48..1954fc5 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -208,6 +208,13 @@
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 @@
// 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 @@
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 a8c242a..fb8331d 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -46,6 +46,17 @@
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 056e8fe..ec9d3ef 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 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 @@
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 @@
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 721dbce..b5f8898 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -142,6 +142,13 @@
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 0000000..e4d4fe9
--- /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 0000000..7aea5e2
--- /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 b458939..b099bcf 100644
--- a/libs/renderengine/skia/filters/MouriMap.cpp
+++ b/libs/renderengine/skia/filters/MouriMap.cpp
@@ -67,7 +67,7 @@
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 @@
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 @@
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 @@
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 @@
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 3c0df8a..9ba2b6f 100644
--- a/libs/renderengine/skia/filters/MouriMap.h
+++ b/libs/renderengine/skia/filters/MouriMap.h
@@ -64,13 +64,16 @@
// 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 @@
};
} // 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 f5a90fd..c187f93 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -249,6 +249,16 @@
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 @@
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 @@
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 d4997d6..cb6e924 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -55,6 +55,12 @@
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 @@
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 e5af740..8b13d78 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 @@
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::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 @@
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 @@
}
}
- 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 @@
}
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 ffb6cdb..b0c6e44 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -388,8 +388,8 @@
}
}
- 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 b6ab2f5..7b5a27d 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -208,8 +208,10 @@
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 8bc2017..648e024 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 @@
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 @@
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 721b466..76e3f66 100644
--- a/libs/ui/tests/DisplayIdentification_test.cpp
+++ b/libs/ui/tests/DisplayIdentification_test.cpp
@@ -194,6 +194,10 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 3d60a1d..645a578 100644
--- a/opengl/OWNERS
+++ b/opengl/OWNERS
@@ -2,5 +2,4 @@
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 00161e6..7628745 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 @@
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 @@
}
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 @@
// 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 e70da54..60cd2c7 100644
--- a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
+++ b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
@@ -125,7 +125,7 @@
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/inputflinger/dispatcher/InputEventTimeline.cpp b/services/inputflinger/dispatcher/InputEventTimeline.cpp
index 31ceb8d..6881964 100644
--- a/services/inputflinger/dispatcher/InputEventTimeline.cpp
+++ b/services/inputflinger/dispatcher/InputEventTimeline.cpp
@@ -66,12 +66,11 @@
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 @@
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 6668399..951fcc8 100644
--- a/services/inputflinger/dispatcher/InputEventTimeline.h
+++ b/services/inputflinger/dispatcher/InputEventTimeline.h
@@ -97,10 +97,9 @@
};
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 e09d97a..4ddd2e9 100644
--- a/services/inputflinger/dispatcher/LatencyAggregator.cpp
+++ b/services/inputflinger/dispatcher/LatencyAggregator.cpp
@@ -134,7 +134,9 @@
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 @@
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 721d009..69024b3 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.cpp
+++ b/services/inputflinger/dispatcher/LatencyTracker.cpp
@@ -70,7 +70,7 @@
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 @@
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 @@
}
}();
- 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 532f422..b4053ba 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.h
+++ b/services/inputflinger/dispatcher/LatencyTracker.h
@@ -53,7 +53,7 @@
* 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/reader/mapper/CapturedTouchpadEventConverter.cpp b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
index dd46bbc..c8e7790 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 @@
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 @@
}
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 @@
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> 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 @@
// 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 @@
/*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 @@
: 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 @@
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 d6c0708..9b6df7a 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 @@
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 @@
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 dbc2872..b17e79a 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -425,7 +425,7 @@
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);
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index 9924d0d..da2c683 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -60,6 +60,21 @@
}
}
+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 @@
: 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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 829fb92..c9a35c1 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
@@ -99,6 +99,7 @@
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/CapturedTouchpadEventConverter_test.cpp b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
index d39ad3f..f20c43c 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index d0cd677..225ae0f 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -279,6 +279,8 @@
}
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 @@
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 @@
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 @@
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, 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 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
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, 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 @@
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 2ccd93e..3cc4bdd 100644
--- a/services/inputflinger/tests/InputTracingTest.cpp
+++ b/services/inputflinger/tests/InputTracingTest.cpp
@@ -133,8 +133,8 @@
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 @@
}
}
- 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 5650286..0f92833 100644
--- a/services/inputflinger/tests/LatencyTracker_test.cpp
+++ b/services/inputflinger/tests/LatencyTracker_test.cpp
@@ -61,7 +61,6 @@
InputEventTimeline getTestTimeline() {
InputEventTimeline t(
- /*isDown=*/false,
/*eventTime=*/2,
/*readTime=*/3,
/*vendorId=*/0,
@@ -174,7 +173,7 @@
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, 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, MultipleEvents_AreReportedConsistently) {
constexpr int32_t inputEventId1 = 1;
InputEventTimeline timeline1(
- /*isDown*/ false,
/*eventTime*/ 2,
/*readTime*/ 3,
/*vendorId=*/0,
@@ -264,7 +261,6 @@
constexpr int32_t inputEventId2 = 10;
InputEventTimeline timeline2(
- /*isDown=*/false,
/*eventTime=*/20,
/*readTime=*/30,
/*vendorId=*/0,
@@ -317,9 +313,9 @@
/*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 @@
{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, 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 @@
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 f3be041..cfedc6e 100644
--- a/services/inputflinger/tests/TestEventMatchers.h
+++ b/services/inputflinger/tests/TestEventMatchers.h
@@ -654,15 +654,6 @@
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 80c2213..695eb3c 100644
--- a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
@@ -71,7 +71,7 @@
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/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h
index dc9e821..a8a773a 100644
--- a/services/sensorservice/SensorRegistrationInfo.h
+++ b/services/sensorservice/SensorRegistrationInfo.h
@@ -38,10 +38,11 @@
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 @@
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 @@
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 57b473b..060508c 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -708,7 +708,7 @@
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 @@
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 @@
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 839fb7d..e910c72 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -51,7 +51,8 @@
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 20ae74a..66237b9 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -60,6 +60,7 @@
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 @@
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 8e78af4..f1fa938 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -675,6 +675,11 @@
}
});
}
+
+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 c2dc943..8e2aeaf 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -67,6 +67,7 @@
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 @@
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 @@
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 @@
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 @@
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 c83e0da..bd093f5 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -76,6 +76,7 @@
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 @@
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 @@
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 @@
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 @@
.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 @@
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 @@
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 @@
}
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 dec4bfe..b95c619 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -134,7 +134,8 @@
// 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 @@
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 @@
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 3736abc..47b811b 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -38,6 +38,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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::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 @@
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 @@
(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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 94cfcb4..cffb61e 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -214,7 +214,8 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
};
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 @@
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 3c8af19..c8bb068 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 @@
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 @@
: 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 @@
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 @@
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 @@
}
// ---------------------------------------------------------------------------
-// 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 @@
// 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 @@
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 @@
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 @@
}
// ----------------------------------------------------------------------------
-// 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 @@
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 @@
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 @@
gui::GameMode gameMode) {
mDrawingState.frameTimelineInfo = info;
mDrawingState.postTime = postTime;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
if (const auto& bufferSurfaceFrameTX = mDrawingState.bufferSurfaceFrameTX;
@@ -1181,40 +561,6 @@
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 @@
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::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 @@
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) {
@@ -2106,17 +852,9 @@
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 +863,6 @@
if (mDrawingState.transformToDisplayInverse == transformToDisplayInverse) return false;
mDrawingState.sequence++;
mDrawingState.transformToDisplayInverse = transformToDisplayInverse;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -2136,100 +873,10 @@
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 +940,6 @@
mDrawingState.isAutoTimestamp = isAutoTimestamp;
mDrawingState.latchedVsyncId = info.vsyncId;
mDrawingState.useVsyncIdForRefreshRateSelection = info.useForRefreshRateSelection;
- mDrawingState.modified = true;
if (!buffer) {
resetDrawingStateBufferInfo();
setTransactionFlags(eTransactionNeeded);
@@ -2441,7 +1087,6 @@
bool Layer::setDataspace(ui::Dataspace dataspace) {
if (mDrawingState.dataspace == dataspace) return false;
mDrawingState.dataspace = dataspace;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -2452,7 +1097,6 @@
return false;
mDrawingState.currentHdrSdrRatio = currentBufferRatio;
mDrawingState.desiredHdrSdrRatio = desiredRatio;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -2460,40 +1104,6 @@
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 +1119,6 @@
}
mDrawingState.sidebandStream = sidebandStream;
- mDrawingState.modified = true;
if (sidebandStream != nullptr && mDrawingState.buffer != nullptr) {
releasePreviousBuffer();
resetDrawingStateBufferInfo();
@@ -2606,14 +1215,6 @@
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 +1236,21 @@
}
}
-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 +1297,6 @@
mFlinger->getTransactionCallbackInvoker()
.addOnCommitCallbackHandles(mDrawingState.callbackHandles, remainingHandles);
mDrawingState.callbackHandles = remainingHandles;
-
- mDrawingStateModified = false;
}
void Layer::gatherBufferInfo() {
@@ -2737,7 +1320,6 @@
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 +1367,6 @@
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 +1391,6 @@
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 +1403,6 @@
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 +1495,6 @@
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 +1516,6 @@
// 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 +1540,6 @@
if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) ||
(mBufferInfo.mTransform != oldBufferInfo.mTransform) ||
- (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) ||
(mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) {
recomputeVisibleRegions = true;
}
@@ -3318,35 +1552,14 @@
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 +1583,6 @@
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 +1618,6 @@
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 +1650,32 @@
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 1e4f2dc..9caa20c 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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 @@
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 @@
* 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 @@
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 @@
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 @@
*/
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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
*/
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 @@
// 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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 885c3d3..5eea45b 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -178,7 +178,7 @@
}
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 @@
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 @@
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 c0198b6..41ea684 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -62,7 +62,7 @@
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 ff0a955..13e054e 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -45,16 +45,6 @@
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 7712d38..06c2f26 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -346,6 +346,7 @@
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 @@
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 034e467..aa66ccf 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -39,21 +39,6 @@
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 dbc458c..ff1926e 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -595,8 +595,7 @@
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 9f6eab2..ab9014e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -841,7 +841,8 @@
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 @@
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 @@
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/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp
index 8bb72b8..41a9a1b 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.cpp
+++ b/services/surfaceflinger/ScreenCaptureOutput.cpp
@@ -93,6 +93,12 @@
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 e13c74f..c794a7b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -532,9 +532,6 @@
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 @@
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 @@
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::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 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 @@
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 @@
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 @@
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 @@
// Commit display transactions.
const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded;
mFrontEndDisplayInfosChanged = displayTransactionNeeded;
- mForceTransactionDisplayChange = displayTransactionNeeded;
if (mSomeChildrenChanged) {
mVisibleRegionsDirty = true;
@@ -4572,20 +4575,18 @@
}
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
WRITEABLE);
auto futureFence = captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, texture,
false /* regionSampling */, grayscale,
- isProtected, captureListener);
+ isProtected, attachGainmap, captureListener);
futureFence.get();
}
}
@@ -7319,7 +7322,8 @@
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 @@
}
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::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 @@
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::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 414088e..3eb72cc 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -135,6 +135,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
};
bool mIsHdcpViaNegVsync = false;
- bool mIsHotplugErrViaNegVsync = false;
std::mutex mHotplugMutex;
std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mHotplugMutex);
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index 8ec908f..12d6138 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -119,7 +119,6 @@
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 @@
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_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_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 473e564..a1be194 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -56,7 +56,6 @@
/// 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 @@
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 0ff846e7..102e2b6 100644
--- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
@@ -4,10 +4,10 @@
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 @@
}
} # 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 @@
}
} # deprecate_vsync_sf
- flag {
+flag {
name: "detached_mirror"
namespace: "window_surfaces"
description: "Ignore local transform when mirroring a partial hierarchy"
@@ -55,6 +66,17 @@
} # 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 @@
} # 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 @@
} # 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 @@
} # 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 56f2f1b..7857961 100644
--- a/services/surfaceflinger/tests/OWNERS
+++ b/services/surfaceflinger/tests/OWNERS
@@ -4,5 +4,5 @@
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 3104dd4..ae380ad 100644
--- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
+++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
@@ -515,6 +515,23 @@
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 9be0fc3..0dfbd61 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -84,9 +84,11 @@
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 2cff2f2..e0753a3 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -58,6 +58,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 7e84408..de37b63 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
@@ -894,7 +894,6 @@
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 2860345..9020723 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 @@
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 06c4e30..9efe73d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -1837,6 +1837,43 @@
}
}
+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 @@
// 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 @@
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 933d03d..352000e 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -239,7 +239,7 @@
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 710b5cc..725354b 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -335,13 +335,6 @@
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 @@
(*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 @@
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 @@
}
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 2cc1987..5edd2cd 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -35,6 +35,7 @@
(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 fdb6f4d..45f86fa 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -31,15 +31,11 @@
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 3d8124b..4ac1618 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -96,6 +96,17 @@
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 @@
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 @@
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 ae0d9ab..4938b15 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -258,6 +258,9 @@
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 @@
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 @@
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 @@
mResonantFrequency,
mFrequencyResolution,
mQFactor,
- mMaxAmplitudes};
+ mMaxAmplitudes,
+ mMaxEnvelopeEffectSize,
+ mMinEnvelopeEffectControlPointDuration,
+ mMaxEnvelopeEffectControlPointDuration};
}
private:
@@ -340,6 +354,11 @@
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 @@
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 @@
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 ba7e1f0..17f384d 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -235,6 +235,9 @@
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 @@
.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 @@
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 @@
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 @@
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 @@
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 @@
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 83430d7..a09ddec 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
@@ -220,6 +220,9 @@
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 @@
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) {