1
0
Fork 0

Merge remote-tracking branch 'freedesktop/main' into android-16.0

This commit is contained in:
Konsta 2025-11-12 22:01:44 +02:00
commit 22ba81cf61
14 changed files with 436 additions and 1 deletions

View file

@ -103,6 +103,8 @@ SKIP_FILES := \
drm/DrmDisplayPipelineTest.cpp \
stats/CompositionStatsTest.cpp \
stats/CompositionStatsAtomReporterDesktop.cpp \
stats/DisplayHotplugConnectModeDetectedAtomReporterDesktop.cpp \
stats/DisplayRefreshRatesChangedAtomReporterDesktop.cpp \
BUILD_FILES_AUTO := $(shell find -L $(SRC_DIR) -not -path '*/\.*' -not -path '*/tests/test_include/*' -path '*.cpp')
SKIP_FILES_path := $(foreach file,$(SKIP_FILES),$(SRC_DIR)/$(file))

View file

@ -345,6 +345,8 @@ drm_hwcomposer_atom_reporter_library {
srcs: [
"compositor/FlatteningEventAtomReporterDesktop.cpp",
"stats/CompositionStatsAtomReporterDesktop.cpp",
"stats/DisplayHotplugConnectModeDetectedAtomReporterDesktop.cpp",
"stats/DisplayRefreshRatesChangedAtomReporterDesktop.cpp",
],
shared_libs: [
"android.frameworks.stats-V2-ndk",
@ -356,6 +358,8 @@ drm_hwcomposer_atom_reporter_library {
srcs: [
"compositor/FlatteningEventAtomReporter.cpp",
"stats/CompositionStatsAtomReporter.cpp",
"stats/DisplayHotplugConnectModeDetectedAtomReporter.cpp",
"stats/DisplayRefreshRatesChangedAtomReporter.cpp",
],
},
},

View file

@ -72,7 +72,11 @@ std::string DumpDisplayStats(const HwcDisplay *display,
}
} // namespace
DrmHwc::DrmHwc() : resource_manager_(this), dump_stats_tracker_(this) {};
DrmHwc::DrmHwc()
: resource_manager_(this),
dump_stats_tracker_(this),
refresh_rates_reporter_(
DisplayRefreshRatesChangedAtomReporter::Create()) {};
/* Must be called after every display attach/detach cycle */
void DrmHwc::FinalizeDisplayBinding() {
@ -274,4 +278,18 @@ void DrmHwc::DeinitDisplays() {
}
}
void DrmHwc::LogRefreshRateChanges() {
std::vector<int32_t> refresh_rates;
refresh_rates.reserve(displays_.size());
for (const auto &[_, display] : displays_) {
if (const HwcDisplayConfig *config = display->GetCurrentConfig(); config) {
refresh_rates.push_back(
static_cast<int32_t>(lround(config->mode.GetVRefresh())));
}
}
if (refresh_rates_reporter_)
refresh_rates_reporter_->UpdateRefreshRates(refresh_rates);
}
} // namespace android::drm_hwcomposer

View file

@ -19,6 +19,7 @@
#include "drm/ResourceManager.h"
#include "hwc/HwcDisplay.h"
#include "stats/CompositionStats.h"
#include "stats/DisplayRefreshRatesChangedAtomReporter.h"
namespace android::drm_hwcomposer {
@ -85,6 +86,9 @@ class DrmHwc : public PipelineToFrontendBindingInterface,
void NotifyDisplayLinkStatus(
std::shared_ptr<DrmDisplayPipeline> pipeline) override;
// Should be done for all successful modesets (full and seamless).
void LogRefreshRateChanges();
protected:
auto &Displays() {
return displays_;
@ -100,6 +104,9 @@ class DrmHwc : public PipelineToFrontendBindingInterface,
DisplayHandle last_display_handle_ = kPrimaryDisplay;
CompositionStatsTracker dump_stats_tracker_;
std::unique_ptr<DisplayRefreshRatesChangedAtomReporter>
refresh_rates_reporter_;
};
} // namespace android::drm_hwcomposer

View file

@ -40,6 +40,7 @@
#include "drm/VSyncWorker.h"
#include "hwc/HwcLayer.h"
#include "stats/CompositionStats.h"
#include "stats/DisplayHotplugConnectModeDetectedAtomReporter.h"
#include "utils/EdidWrapper.h"
#include "utils/log.h"
#include "utils/properties.h"
@ -144,6 +145,9 @@ HwcDisplay::HwcDisplay(DisplayHandle handle, bool is_virtual, DrmHwc *hwc)
writeback_layer_ = std::make_unique<HwcLayer>(this);
identity_color_matrix_ = ToColorTransform(kIdentityMatrix);
display_mode_reporter_ = DisplayHotplugConnectModeDetectedAtomReporter::
Create();
}
void HwcDisplay::SetColorTransformMatrix(
@ -640,6 +644,9 @@ void HwcDisplay::SetPipeline(std::shared_ptr<DrmDisplayPipeline> pipeline) {
bool success = Init();
ALOGE_IF(!success, "Failed to init HwcDisplay after setting pipeline.");
hwc_->ScheduleHotplugEvent(handle_, DrmHwc::kConnected);
if (pipeline_) {
LogModesOnHotplug();
}
} else {
hwc_->ScheduleHotplugEvent(handle_, DrmHwc::kDisconnected);
}
@ -1390,4 +1397,60 @@ std::pair<uint32_t, uint32_t> HwcDisplay::GetSize() const {
config->mode.GetRawMode().vdisplay);
}
void HwcDisplay::LogModesOnHotplug() {
if (!display_mode_reporter_) {
return;
}
const HwcDisplay::DisplayType display_type = GetDisplayType();
if (display_type != HwcDisplay::DisplayType::kInternal &&
display_type != HwcDisplay::DisplayType::kExternal) {
return;
}
using ModeAtom = DisplayHotplugConnectModeDetectedAtomReporter::Atom;
std::vector<ModeAtom> submitted_atoms;
for (const auto &[id, hwc_mode] : configs_.hwc_configs) {
const DrmMode &mode = hwc_mode.mode;
const drmModeModeInfo &raw_mode = mode.GetRawMode();
const bool is_preferred = (raw_mode.type & DRM_MODE_TYPE_PREFERRED) != 0;
constexpr float kMmPerInch = 25.4;
const auto [width_mm, height_mm] = GetDisplayBoundsMm();
int32_t dpi_x = -1;
if (width_mm > 0) {
dpi_x = static_cast<int32_t>(
lround((static_cast<float>(raw_mode.hdisplay) * kMmPerInch) /
static_cast<float>(width_mm)));
}
int32_t dpi_y = dpi_x;
if (height_mm > 0) {
dpi_y = static_cast<int32_t>(
lround((static_cast<float>(raw_mode.vdisplay) * kMmPerInch) /
static_cast<float>(height_mm)));
}
using AtomDisplayType = DisplayHotplugConnectModeDetectedAtomReporter::
DisplayType;
const ModeAtom atom =
{.display_handle = handle_,
.resolution_x = raw_mode.hdisplay,
.resolution_y = raw_mode.vdisplay,
.refresh_rate = static_cast<int32_t>(lround(mode.GetVRefresh())),
.dpi_x = dpi_x,
.dpi_y = dpi_y,
.display_type = display_type == HwcDisplay::DisplayType::kInternal
? AtomDisplayType::kInternal
: AtomDisplayType::kExternal,
.is_preferred = is_preferred};
if (std::find(submitted_atoms.begin(), submitted_atoms.end(), atom) !=
submitted_atoms.end()) {
continue;
}
display_mode_reporter_->PushAtom(atom);
submitted_atoms.push_back(atom);
}
}
} // namespace android::drm_hwcomposer

View file

@ -35,6 +35,7 @@ using aidl::android::hardware::graphics::common::Hdr;
namespace android::drm_hwcomposer {
class ChangedLayer;
class DisplayHotplugConnectModeDetectedAtomReporter;
class DrmHwc;
class EdidWrapper;
class FlatteningController;
@ -299,6 +300,8 @@ class HwcDisplay {
return edid_wrapper_;
}
void LogModesOnHotplug();
HwcDisplayConfigs configs_;
DrmHwc *const hwc_;
@ -344,6 +347,9 @@ class HwcDisplay {
HwcDisplay::HdcpState hdcp_state_ = HdcpState::kUndesired;
std::shared_ptr<FrontendDisplayBase> frontend_private_data_;
std::unique_ptr<DisplayHotplugConnectModeDetectedAtomReporter>
display_mode_reporter_;
};
} // namespace android::drm_hwcomposer

View file

@ -1318,6 +1318,7 @@ ndk::ScopedAStatus ComposerClient::setActiveConfigWithConstraints(
return ToBinderStatus(hwc3::Error::kBadConfig);
#endif
case HwcDisplay::ConfigError::kNone:
hwc_->LogRefreshRateChanges();
return ndk::ScopedAStatus::ok();
}
}

View file

@ -24,6 +24,8 @@ src_common = files(
'stats/CompositionStats.cpp',
'stats/CompositionStatsAtomReporter.cpp',
'stats/CompositionStatsPoller.cpp',
'stats/DisplayHotplugConnectModeDetectedAtomReporter.cpp',
'stats/DisplayRefreshRatesChangedAtomReporter.cpp',
'utils/fd.cpp',
'utils/LibdisplayEdidWrapper.cpp',
'utils/properties.cpp',

View file

@ -0,0 +1,31 @@
/*
* Copyright (C) 2025 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 "drmhwc"
#include "DisplayHotplugConnectModeDetectedAtomReporter.h"
#include "utils/log.h"
namespace android::drm_hwcomposer {
std::unique_ptr<DisplayHotplugConnectModeDetectedAtomReporter>
DisplayHotplugConnectModeDetectedAtomReporter::Create() {
ALOGI("Atom reporting is not enabled.");
return {};
}
} // namespace android::drm_hwcomposer

View file

@ -0,0 +1,58 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <memory>
namespace android::drm_hwcomposer {
class DisplayHotplugConnectModeDetectedAtomReporter {
public:
static std::unique_ptr<DisplayHotplugConnectModeDetectedAtomReporter>
Create();
enum class DisplayType {
kUnspecified = 0,
kInternal,
kExternal,
};
struct Atom {
int64_t display_handle = 0;
int32_t resolution_x = 0;
int32_t resolution_y = 0;
int32_t refresh_rate = 0;
int32_t dpi_x = 0;
int32_t dpi_y = 0;
DisplayType display_type = DisplayType::kUnspecified;
bool is_preferred = false;
bool operator==(const Atom& other) const {
return display_handle == other.display_handle &&
resolution_x == other.resolution_x &&
resolution_y == other.resolution_y &&
refresh_rate == other.refresh_rate && dpi_x == other.dpi_x &&
dpi_y == other.dpi_y && display_type == other.display_type &&
is_preferred == other.is_preferred;
};
};
// Pushes a Vendor Atom to IStats::reportVendorAtom.
virtual void PushAtom(Atom atom) = 0;
virtual ~DisplayHotplugConnectModeDetectedAtomReporter() = default;
};
} // namespace android::drm_hwcomposer

View file

@ -0,0 +1,98 @@
/*
* Copyright (C) 2025 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 "drmhwc"
// #define NLOG_DEBUG 0
#include "DisplayHotplugConnectModeDetectedAtomReporter.h"
#include <cinttypes>
#include <thread>
#include <aidl/android/frameworks/stats/IStats.h>
#include <android/binder_manager.h>
#include "desktopatoms.h"
#include "utils/log.h"
using aidl::android::frameworks::stats::IStats;
using aidl::android::frameworks::stats::VendorAtom;
namespace DesktopAtoms = android::vendor::google::desktop::stats::DesktopAtoms;
namespace android::drm_hwcomposer {
namespace {
DesktopAtoms::DisplayHotplugConnectModeDetected::DisplayType ToProtoEnum(
DisplayHotplugConnectModeDetectedAtomReporter::DisplayType type) {
switch (type) {
case DisplayHotplugConnectModeDetectedAtomReporter::DisplayType::
kUnspecified:
return DesktopAtoms::DisplayHotplugConnectModeDetected::
DISPLAY_TYPE_UNSPECIFIED;
case DisplayHotplugConnectModeDetectedAtomReporter::DisplayType::kInternal:
return DesktopAtoms::DisplayHotplugConnectModeDetected::
DISPLAY_TYPE_INTERNAL;
case DisplayHotplugConnectModeDetectedAtomReporter::DisplayType::kExternal:
return DesktopAtoms::DisplayHotplugConnectModeDetected::
DISPLAY_TYPE_EXTERNAL;
}
}
const std::string kStatsServiceName = std::string(IStats::descriptor)
.append("/default");
// Use a private implementation of DisplayHotplugConnectModeDetectedAtomReporter
// to avoid leaking the IStats interface through the public api.
class DisplayHotplugConnectModeDetectedAtomReporterDesktop
: public DisplayHotplugConnectModeDetectedAtomReporter {
public:
void PushAtom(Atom atom) override {
ALOGE("zzzz DisplayHotplugConnectModeDetected");
// The order of the arguments to createVendorAtom is determined by the
// proto definition in libdesktopatoms.
const char* deprecated_reverse_domain_name = "";
const VendorAtom vendor_atom = DesktopAtoms::
createVendorAtom(DesktopAtoms::DISPLAY_HOTPLUG_CONNECT_MODE_DETECTED,
deprecated_reverse_domain_name, atom.display_handle,
atom.resolution_x, atom.resolution_y,
atom.refresh_rate, atom.dpi_x, atom.dpi_y,
ToProtoEnum(atom.display_type), atom.is_preferred);
auto stats_service = IStats::fromBinder(ndk::SpAIBinder(
AServiceManager_checkService(kStatsServiceName.c_str())));
ALOGE_IF(stats_service == nullptr, "Failed to get IStats service");
if (stats_service) {
const ndk::ScopedAStatus ret = stats_service->reportVendorAtom(
vendor_atom);
ALOGE_IF(!ret.isOk(), "Failed to report stats: %s",
ret.getDescription().c_str());
}
}
};
} // namespace
std::unique_ptr<DisplayHotplugConnectModeDetectedAtomReporter>
DisplayHotplugConnectModeDetectedAtomReporter::Create() {
if (!AServiceManager_isDeclared(kStatsServiceName.c_str())) {
ALOGW("Stats service is not declared.");
return nullptr;
}
return std::make_unique<
DisplayHotplugConnectModeDetectedAtomReporterDesktop>();
}
} // namespace android::drm_hwcomposer

View file

@ -0,0 +1,31 @@
/*
* Copyright (C) 2025 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 "drmhwc"
#include "DisplayRefreshRatesChangedAtomReporter.h"
#include "utils/log.h"
namespace android::drm_hwcomposer {
std::unique_ptr<DisplayRefreshRatesChangedAtomReporter>
DisplayRefreshRatesChangedAtomReporter::Create() {
ALOGI("Atom reporting is not enabled.");
return {};
}
} // namespace android::drm_hwcomposer

View file

@ -0,0 +1,31 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <memory>
#include <vector>
namespace android::drm_hwcomposer {
class DisplayRefreshRatesChangedAtomReporter {
public:
static std::unique_ptr<DisplayRefreshRatesChangedAtomReporter> Create();
virtual void UpdateRefreshRates(std::vector<int32_t> refresh_rates) = 0;
virtual ~DisplayRefreshRatesChangedAtomReporter() = default;
};
} // namespace android::drm_hwcomposer

View file

@ -0,0 +1,83 @@
/*
* Copyright (C) 2025 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 "drmhwc"
// #define NLOG_DEBUG 0
#include "DisplayRefreshRatesChangedAtomReporter.h"
#include <cinttypes>
#include <thread>
#include <aidl/android/frameworks/stats/IStats.h>
#include <android/binder_manager.h>
#include "desktopatoms.h"
#include "utils/log.h"
using aidl::android::frameworks::stats::IStats;
using aidl::android::frameworks::stats::VendorAtom;
namespace DesktopAtoms = android::vendor::google::desktop::stats::DesktopAtoms;
namespace android::drm_hwcomposer {
namespace {
const std::string kStatsServiceName = std::string(IStats::descriptor)
.append("/default");
// Use a private implementation of DisplayRefreshRatesChangedAtomReporter to
// avoid leaking the IStats interface through the public api.
class DisplayRefreshRatesChangedAtomReporterDesktop
: public DisplayRefreshRatesChangedAtomReporter {
public:
void UpdateRefreshRates(std::vector<int32_t> refresh_rates) override {
if (refresh_rates == last_refresh_rates_) {
return;
}
last_refresh_rates_ = refresh_rates;
// The order of the arguments to createVendorAtom is determined by the
// proto definition in libdesktopatoms.
const char* deprecated_reverse_domain_name = "";
const VendorAtom vendor_atom = DesktopAtoms::
createVendorAtom(DesktopAtoms::DISPLAY_REFRESH_RATES_CHANGED,
deprecated_reverse_domain_name, refresh_rates);
auto stats_service = IStats::fromBinder(ndk::SpAIBinder(
AServiceManager_checkService(kStatsServiceName.c_str())));
ALOGE_IF(stats_service == nullptr, "Failed to get IStats service");
if (stats_service) {
const ndk::ScopedAStatus ret = stats_service->reportVendorAtom(
vendor_atom);
}
}
private:
std::vector<int32_t> last_refresh_rates_;
};
} // namespace
std::unique_ptr<DisplayRefreshRatesChangedAtomReporter>
DisplayRefreshRatesChangedAtomReporter::Create() {
if (!AServiceManager_isDeclared(kStatsServiceName.c_str())) {
ALOGW("Stats service is not declared.");
return nullptr;
}
return std::make_unique<DisplayRefreshRatesChangedAtomReporterDesktop>();
}
} // namespace android::drm_hwcomposer