Commit d0c035b4 authored by Roman Stratiienko's avatar Roman Stratiienko
Browse files

drm_hwcomposer: Implement SetActiveConfigWithConstraints

Enough to get 100% passes in Composer 2.4 VTS.
Some SOCs require a VTS fix to pass [1]

[1]: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1954544


Signed-off-by: default avatarRoman Stratiienko <roman.o.stratiienko@globallogic.com>
parent 099c3115
Pipeline #500939 passed with stages
in 13 minutes and 35 seconds
......@@ -21,6 +21,7 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <ctime>
#include <sstream>
#include "bufferinfo/BufferInfoGetter.h"
......@@ -114,6 +115,13 @@ int ResourceManager::AddDrmDevice(const std::string &path) {
return ret;
}
auto ResourceManager::GetTimeMonotonicNs() -> int64_t {
struct timespec ts {};
clock_gettime(CLOCK_MONOTONIC, &ts);
constexpr int64_t kNsInSec = 1000000000LL;
return int64_t(ts.tv_sec) * kNsInSec + int64_t(ts.tv_nsec);
}
void ResourceManager::UpdateFrontendDisplays() {
auto ordered_connectors = GetOrderedConnectors();
......
......@@ -56,6 +56,8 @@ class ResourceManager {
return main_lock_;
}
static auto GetTimeMonotonicNs() -> int64_t;
private:
auto AddDrmDevice(std::string const &path) -> int;
auto GetOrderedConnectors() -> std::vector<DrmConnector *>;
......
......@@ -174,6 +174,11 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data);
break;
}
case HWC2::Callback::VsyncPeriodTimingChanged: {
period_timing_changed_callback_ = std::
make_pair(HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED(function), data);
break;
}
#endif
default:
break;
......@@ -220,4 +225,21 @@ void DrmHwcTwo::SendVsyncEventToClient(
}
}
void DrmHwcTwo::SendVsyncPeriodTimingChangedEventToClient(
[[maybe_unused]] hwc2_display_t displayid,
[[maybe_unused]] int64_t timestamp) const {
#if PLATFORM_SDK_VERSION > 29
hwc_vsync_period_change_timeline_t timeline = {
.newVsyncAppliedTimeNanos = timestamp,
.refreshRequired = false,
.refreshTimeNanos = 0,
};
if (period_timing_changed_callback_.first != nullptr &&
period_timing_changed_callback_.second != nullptr) {
period_timing_changed_callback_
.first(period_timing_changed_callback_.second, displayid, &timeline);
}
#endif
}
} // namespace android
......@@ -33,6 +33,8 @@ class DrmHwcTwo : public PipelineToFrontendBindingInterface {
std::pair<HWC2_PFN_VSYNC, hwc2_callback_data_t> vsync_callback_{};
#if PLATFORM_SDK_VERSION > 29
std::pair<HWC2_PFN_VSYNC_2_4, hwc2_callback_data_t> vsync_2_4_callback_{};
std::pair<HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED, hwc2_callback_data_t>
period_timing_changed_callback_{};
#endif
std::pair<HWC2_PFN_REFRESH, hwc2_callback_data_t> refresh_callback_{};
......@@ -66,6 +68,8 @@ class DrmHwcTwo : public PipelineToFrontendBindingInterface {
void SendVsyncEventToClient(hwc2_display_t displayid, int64_t timestamp,
uint32_t vsync_period) const;
void SendVsyncPeriodTimingChangedEventToClient(hwc2_display_t displayid,
int64_t timestamp) const;
private:
void SendHotplugEventToClient(hwc2_display_t displayid, bool connected);
......
......@@ -141,7 +141,10 @@ HWC2::Error HwcDisplay::Init() {
if (vsync_flattening_en_) {
ProcessFlatenningVsyncInternal();
}
if (!vsync_event_en_ && !vsync_flattening_en_) {
if (vsync_tracking_en_) {
last_vsync_ts_ = timestamp;
}
if (!vsync_event_en_ && !vsync_flattening_en_ && !vsync_tracking_en_) {
vsync_worker_.VSyncControl(false);
}
});
......@@ -215,10 +218,10 @@ HWC2::Error HwcDisplay::DestroyLayer(hwc2_layer_t layer) {
}
HWC2::Error HwcDisplay::GetActiveConfig(hwc2_config_t *config) const {
if (configs_.hwc_configs.count(configs_.active_config_id) == 0)
if (configs_.hwc_configs.count(staged_mode_config_id_) == 0)
return HWC2::Error::BadConfig;
*config = configs_.active_config_id;
*config = staged_mode_config_id_;
return HWC2::Error::None;
}
......@@ -321,7 +324,7 @@ HWC2::Error HwcDisplay::GetDisplayAttribute(hwc2_config_t config,
case HWC2::Attribute::ConfigGroup:
/* Dispite ConfigGroup is a part of HWC2.4 API, framework
* able to request it even if service @2.1 is used */
*value = hwc_config.group_id;
*value = int(hwc_config.group_id);
break;
#endif
default:
......@@ -436,6 +439,26 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
return HWC2::Error::None;
}
int PrevModeVsyncPeriodNs = static_cast<int>(
1E9 / GetPipe().connector->Get()->GetActiveMode().v_refresh());
auto mode_update_commited_ = false;
if (staged_mode_ &&
staged_mode_change_time_ <= ResourceManager::GetTimeMonotonicNs()) {
client_layer_.SetLayerDisplayFrame(
(hwc_rect_t){.left = 0,
.top = 0,
.right = static_cast<int>(staged_mode_->h_display()),
.bottom = static_cast<int>(staged_mode_->v_display())});
configs_.active_config_id = staged_mode_config_id_;
a_args.display_mode = *staged_mode_;
if (!a_args.test_only) {
mode_update_commited_ = true;
}
}
// order the layers by z-order
bool use_client_layer = false;
uint32_t client_z_order = UINT32_MAX;
......@@ -498,9 +521,6 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
}
a_args.composition = composition;
if (staged_mode) {
a_args.display_mode = *staged_mode;
}
ret = GetPipe().compositor->ExecuteAtomicCommit(a_args);
if (ret) {
......@@ -509,8 +529,13 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
return HWC2::Error::BadParameter;
}
if (!a_args.test_only) {
staged_mode.reset();
if (mode_update_commited_) {
staged_mode_.reset();
vsync_tracking_en_ = false;
if (last_vsync_ts_ != 0) {
hwc2_->SendVsyncPeriodTimingChangedEventToClient(
handle_, last_vsync_ts_ + PrevModeVsyncPeriodNs);
}
}
return HWC2::Error::None;
......@@ -548,30 +573,24 @@ HWC2::Error HwcDisplay::PresentDisplay(int32_t *present_fence) {
return HWC2::Error::None;
}
HWC2::Error HwcDisplay::SetActiveConfig(hwc2_config_t config) {
int conf = static_cast<int>(config);
if (configs_.hwc_configs.count(conf) == 0) {
ALOGE("Could not find active mode for %d", conf);
HWC2::Error HwcDisplay::SetActiveConfigInternal(uint32_t config,
int64_t change_time) {
if (configs_.hwc_configs.count(config) == 0) {
ALOGE("Could not find active mode for %u", config);
return HWC2::Error::BadConfig;
}
auto &mode = configs_.hwc_configs[conf].mode;
staged_mode = mode;
configs_.active_config_id = conf;
// Setup the client layer's dimensions
hwc_rect_t display_frame = {.left = 0,
.top = 0,
.right = static_cast<int>(mode.h_display()),
.bottom = static_cast<int>(mode.v_display())};
client_layer_.SetLayerDisplayFrame(display_frame);
staged_mode_ = configs_.hwc_configs[config].mode;
staged_mode_change_time_ = change_time;
staged_mode_config_id_ = config;
return HWC2::Error::None;
}
HWC2::Error HwcDisplay::SetActiveConfig(hwc2_config_t config) {
return SetActiveConfigInternal(config, ResourceManager::GetTimeMonotonicNs());
}
/* Find API details at:
* https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1861
*/
......@@ -736,14 +755,37 @@ HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
}
HWC2::Error HwcDisplay::SetActiveConfigWithConstraints(
hwc2_config_t /*config*/,
hwc2_config_t config,
hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints,
hwc_vsync_period_change_timeline_t *outTimeline) {
if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) {
return HWC2::Error::BadParameter;
}
return HWC2::Error::BadConfig;
uint32_t current_vsync_period{};
GetDisplayVsyncPeriod(&current_vsync_period);
if (vsyncPeriodChangeConstraints->seamlessRequired) {
return HWC2::Error::SeamlessNotAllowed;
}
outTimeline->refreshTimeNanos = vsyncPeriodChangeConstraints
->desiredTimeNanos -
current_vsync_period;
auto ret = SetActiveConfigInternal(config, outTimeline->refreshTimeNanos);
if (ret != HWC2::Error::None) {
return ret;
}
outTimeline->refreshRequired = true;
outTimeline->newVsyncAppliedTimeNanos = vsyncPeriodChangeConstraints
->desiredTimeNanos;
last_vsync_ts_ = 0;
vsync_tracking_en_ = true;
vsync_worker_.VSyncControl(true);
return HWC2::Error::None;
}
HWC2::Error HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) {
......
......@@ -195,7 +195,9 @@ class HwcDisplay {
DrmHwcTwo *const hwc2_;
std::optional<DrmMode> staged_mode;
std::optional<DrmMode> staged_mode_;
int64_t staged_mode_change_time_{};
uint32_t staged_mode_config_id_{};
DrmDisplayPipeline *const pipeline_;
......@@ -204,6 +206,8 @@ class HwcDisplay {
VSyncWorker vsync_worker_;
bool vsync_event_en_{};
bool vsync_flattening_en_{};
bool vsync_tracking_en_{};
int64_t last_vsync_ts_{};
const hwc2_display_t handle_;
HWC2::DisplayType type_;
......@@ -223,6 +227,8 @@ class HwcDisplay {
std::string DumpDelta(HwcDisplay::Stats delta);
HWC2::Error Init();
HWC2::Error SetActiveConfigInternal(uint32_t config, int64_t change_time);
};
} // namespace android
......
......@@ -32,7 +32,7 @@ constexpr uint32_t kHeadlessModeDisplayVRefresh = 60;
namespace android {
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
int HwcDisplayConfigs::last_config_id = 1;
uint32_t HwcDisplayConfigs::last_config_id = 1;
void HwcDisplayConfigs::FillHeadless() {
hwc_configs.clear();
......@@ -77,15 +77,15 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
mm_height = connector.GetMmHeight();
preferred_config_id = 0;
int preferred_config_group_id = 0;
uint32_t preferred_config_group_id = 0;
int first_config_id = last_config_id;
int last_group_id = 1;
uint32_t first_config_id = last_config_id;
uint32_t last_group_id = 1;
/* Group modes */
for (const auto &mode : connector.GetModes()) {
/* Find group for the new mode or create new group */
int group_found = 0;
uint32_t group_found = 0;
for (auto &hwc_config : hwc_configs) {
if (mode.h_display() == hwc_config.second.mode.h_display() &&
mode.v_display() == hwc_config.second.mode.v_display()) {
......@@ -128,7 +128,7 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
preferred_config_group_id = 1;
}
for (int group = 1; group < last_group_id; group++) {
for (uint32_t group = 1; group < last_group_id; group++) {
bool has_interlaced = false;
bool has_progressive = false;
for (auto &hwc_config : hwc_configs) {
......@@ -179,8 +179,8 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
* otherwise android.graphics.cts.SetFrameRateTest CTS will fail
*/
constexpr float kMinFpsDelta = 1.0; // FPS
for (int m1 = first_config_id; m1 < last_config_id; m1++) {
for (int m2 = first_config_id; m2 < last_config_id; m2++) {
for (uint32_t m1 = first_config_id; m1 < last_config_id; m1++) {
for (uint32_t m2 = first_config_id; m2 < last_config_id; m2++) {
if (m1 != m2 && hwc_configs[m1].group_id == hwc_configs[m2].group_id &&
!hwc_configs[m1].disabled && !hwc_configs[m2].disabled &&
fabsf(hwc_configs[m1].mode.v_refresh() -
......
......@@ -28,8 +28,8 @@ namespace android {
class DrmConnector;
struct HwcDisplayConfig {
int id{};
int group_id{};
uint32_t id{};
uint32_t group_id{};
DrmMode mode;
bool disabled{};
......@@ -42,13 +42,13 @@ struct HwcDisplayConfigs {
HWC2::Error Update(DrmConnector &conn);
void FillHeadless();
std::map<int /*config_id*/, struct HwcDisplayConfig> hwc_configs;
std::map<uint32_t /*config_id*/, struct HwcDisplayConfig> hwc_configs;
int active_config_id = 0;
int preferred_config_id = 0;
uint32_t active_config_id = 0;
uint32_t preferred_config_id = 0;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static int last_config_id;
static uint32_t last_config_id;
uint32_t mm_width = 0;
uint32_t mm_height = 0;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment