Commit ef3c797d authored by Matvii Zorin's avatar Matvii Zorin
Browse files

drm_hwcomposer: Add backend-dependent validation for HwcDisplay class



Different DRM/KMS backends have a variable set of limitations, which is
not always exposed via DRM ioctls.

This implementation of backend-dependent validation provides a register
of platform-specific inherited backend class to the map by BackendManager
class. ValidateDisplay function is moved to generic backend
implementantion and separated into 2 additional methods.

The map key is a string that contains the corresponding DRM driver name.
During DrmHwcTwo class initialization the vendor.hwc.backend_override
system property and driver name will be checked and a backend will be set
for the appropriate display. If the map does not have any backend for the
named driver, the generic backend will be used.
Signed-off-by: Matvii Zorin's avatarMatvii Zorin <matvii.zorin@globallogic.com>
parent 373de710
......@@ -94,6 +94,9 @@ cc_library_static {
"utils/autolock.cpp",
"utils/hwcutils.cpp",
"backend/backendmanager.cpp",
"backend/backend.cpp",
],
}
......
/*
* Copyright (C) 2020 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 "backend.h"
#include "backendmanager.h"
#include "drmhwctwo.h"
namespace android {
HWC2::Error Backend::ValidateDisplay(DrmHwcTwo::HwcDisplay *display,
uint32_t *num_types,
uint32_t *num_requests) {
*num_types = 0;
*num_requests = 0;
size_t avail_planes = display->primary_planes().size() +
display->overlay_planes().size();
/*
* If more layers then planes, save one plane
* for client composited layers
*/
if (avail_planes < display->layers().size())
avail_planes--;
std::map<uint32_t, DrmHwcTwo::HwcLayer *> z_map, z_map_tmp;
uint32_t z_index = 0;
// First create a map of layers and z_order values
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l :
display->layers())
z_map_tmp.emplace(std::make_pair(l.second.z_order(), &l.second));
// normalise the map so that the lowest z_order layer has key 0
for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map_tmp)
z_map.emplace(std::make_pair(z_index++, l.second));
uint32_t total_pixops = display->CalcPixOps(z_map, 0, z_map.size());
uint32_t gpu_pixops = 0;
int client_start = -1, client_size = 0;
if (display->compositor().ShouldFlattenOnClient()) {
client_start = 0;
client_size = z_map.size();
display->MarkValidated(z_map, client_start, client_size);
} else {
std::tie(client_start, client_size) = GetClientLayers(display, z_map);
int extra_client = (z_map.size() - client_size) - avail_planes;
if (extra_client > 0) {
int start = 0, steps;
if (client_size != 0) {
int prepend = std::min(client_start, extra_client);
int append = std::min(int(z_map.size() - (client_start + client_size)),
extra_client);
start = client_start - prepend;
client_size += extra_client;
steps = 1 + std::min(std::min(append, prepend),
int(z_map.size()) - (start + client_size));
} else {
client_size = extra_client;
steps = 1 + z_map.size() - extra_client;
}
gpu_pixops = INT_MAX;
for (int i = 0; i < steps; i++) {
uint32_t po = display->CalcPixOps(z_map, start + i, client_size);
if (po < gpu_pixops) {
gpu_pixops = po;
client_start = start + i;
}
}
}
display->MarkValidated(z_map, client_start, client_size);
bool testing_needed = !(client_start == 0 && client_size == z_map.size());
if (testing_needed &&
display->CreateComposition(true) != HWC2::Error::None) {
++display->total_stats().failed_kms_validate_;
gpu_pixops = total_pixops;
client_size = z_map.size();
display->MarkValidated(z_map, 0, client_size);
}
}
*num_types = client_size;
display->total_stats().frames_flattened_ = display->compositor()
.GetFlattenedFramesCount();
display->total_stats().gpu_pixops_ += gpu_pixops;
display->total_stats().total_pixops_ += total_pixops;
return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None;
}
std::tuple<int, int> Backend::GetClientLayers(
DrmHwcTwo::HwcDisplay *display,
const std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map) {
int client_start = -1, client_size = 0;
for (auto & [ z_order, layer ] : z_map) {
if (IsClientLayer(display, layer)) {
if (client_start < 0)
client_start = z_order;
client_size = (z_order - client_start) + 1;
}
}
return std::make_tuple(client_start, client_size);
}
bool Backend::IsClientLayer(DrmHwcTwo::HwcDisplay *display,
DrmHwcTwo::HwcLayer *layer) {
return !display->HardwareSupportsLayerType(layer->sf_type()) ||
!display->importer()->CanImportBuffer(layer->buffer()) ||
display->color_transform_hint() != HAL_COLOR_TRANSFORM_IDENTITY ||
(layer->RequireScalingOrPhasing() &&
display->resource_manager()->ForcedScalingWithGpu());
}
REGISTER_BACKEND("generic", Backend);
} // namespace android
/*
* Copyright (C) 2020 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 "hwc-backend"
#include "backendmanager.h"
#include "backend.h"
#include "drmhwctwo.h"
#include <cutils/properties.h>
#include <log/log.h>
namespace android {
const std::vector<std::string> BackendManager::client_devices_ = {
"kirin",
};
BackendManager &BackendManager::GetInstance() {
static BackendManager backend_manager;
return backend_manager;
}
int BackendManager::RegisterBackend(const std::string &name,
backend_constructor_t backend_constructor) {
available_backends_[name] = std::move(backend_constructor);
return 0;
}
int BackendManager::SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display) {
std::string driver_name(display->drm()->GetName());
char backend_override[PROPERTY_VALUE_MAX];
property_get("vendor.hwc.backend_override", backend_override,
driver_name.c_str());
std::string backend_name(std::move(backend_override));
display->set_backend(GetBackendByName(backend_name));
if (!display->backend()) {
ALOGE("Failed to set backend '%s' for '%s' and driver '%s'",
backend_name.c_str(), display->connector()->name().c_str(),
driver_name.c_str());
return -EINVAL;
}
ALOGI("Backend '%s' for '%s' and driver '%s' was successfully set",
backend_name.c_str(), display->connector()->name().c_str(),
driver_name.c_str());
return 0;
}
std::unique_ptr<Backend> BackendManager::GetBackendByName(std::string &name) {
if (!available_backends_.size()) {
ALOGE("No backends are specified");
return nullptr;
}
auto it = available_backends_.find(name);
if (it == available_backends_.end()) {
auto it = std::find(client_devices_.begin(), client_devices_.end(), name);
name = it == client_devices_.end() ? "generic" : "client";
}
return available_backends_[name]();
}
} // namespace android
......@@ -570,4 +570,16 @@ int DrmDevice::GetConnectorProperty(const DrmConnector &connector,
return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name,
property);
}
const std::string DrmDevice::GetName() const {
auto ver = drmGetVersion(fd_.get());
if (!ver) {
ALOGW("Failed to get drm version for fd=%d", fd_.get());
return "generic";
}
std::string name(ver->name);
drmFreeVersion(ver);
return name;
}
} // namespace android
......@@ -18,6 +18,7 @@
#define LOG_TAG "hwc-drm-two"
#include "drmhwctwo.h"
#include "backendmanager.h"
#include "drmdisplaycomposition.h"
#include "drmhwcomposer.h"
#include "platform.h"
......@@ -299,6 +300,12 @@ HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
return HWC2::Error::BadDisplay;
}
ret = BackendManager::GetInstance().SetBackendForDisplay(this);
if (ret) {
ALOGE("Failed to set backend for d=%d %d\n", display, ret);
return HWC2::Error::BadDisplay;
}
return ChosePreferredConfig();
}
......@@ -900,92 +907,8 @@ void DrmHwcTwo::HwcDisplay::MarkValidated(
HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types,
uint32_t *num_requests) {
supported(__func__);
*num_types = 0;
*num_requests = 0;
size_t avail_planes = primary_planes_.size() + overlay_planes_.size();
/*
* If more layers then planes, save one plane
* for client composited layers
*/
if (avail_planes < layers_.size())
avail_planes--;
std::map<uint32_t, DrmHwcTwo::HwcLayer *> z_map, z_map_tmp;
uint32_t z_index = 0;
// First create a map of layers and z_order values
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_)
z_map_tmp.emplace(std::make_pair(l.second.z_order(), &l.second));
// normalise the map so that the lowest z_order layer has key 0
for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map_tmp)
z_map.emplace(std::make_pair(z_index++, l.second));
uint32_t total_pixops = CalcPixOps(z_map, 0, z_map.size()), gpu_pixops = 0;
int client_start = -1, client_size = 0;
if (compositor_.ShouldFlattenOnClient()) {
client_start = 0;
client_size = z_map.size();
MarkValidated(z_map, client_start, client_size);
} else {
for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) {
if (!HardwareSupportsLayerType(l.second->sf_type()) ||
!importer_->CanImportBuffer(l.second->buffer()) ||
color_transform_hint_ != HAL_COLOR_TRANSFORM_IDENTITY ||
(l.second->RequireScalingOrPhasing() &&
resource_manager_->ForcedScalingWithGpu())) {
if (client_start < 0)
client_start = l.first;
client_size = (l.first - client_start) + 1;
}
}
int extra_client = (z_map.size() - client_size) - avail_planes;
if (extra_client > 0) {
int start = 0, steps;
if (client_size != 0) {
int prepend = std::min(client_start, extra_client);
int append = std::min(int(z_map.size() - (client_start + client_size)),
extra_client);
start = client_start - prepend;
client_size += extra_client;
steps = 1 + std::min(std::min(append, prepend),
int(z_map.size()) - (start + client_size));
} else {
client_size = extra_client;
steps = 1 + z_map.size() - extra_client;
}
gpu_pixops = INT_MAX;
for (int i = 0; i < steps; i++) {
uint32_t po = CalcPixOps(z_map, start + i, client_size);
if (po < gpu_pixops) {
gpu_pixops = po;
client_start = start + i;
}
}
}
MarkValidated(z_map, client_start, client_size);
bool testing_needed = !(client_start == 0 && client_size == z_map.size());
if (testing_needed && CreateComposition(true) != HWC2::Error::None) {
++total_stats_.failed_kms_validate_;
gpu_pixops = total_pixops;
client_size = z_map.size();
MarkValidated(z_map, 0, client_size);
}
}
*num_types = client_size;
total_stats_.frames_flattened_ = compositor_.GetFlattenedFramesCount();
total_stats_.gpu_pixops_ += gpu_pixops;
total_stats_.total_pixops_ += total_pixops;
return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None;
return backend_->ValidateDisplay(this, num_types, num_requests);
}
#if PLATFORM_SDK_VERSION > 28
......
/*
* Copyright (C) 2020 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.
*/
#ifndef ANDROID_BACKEND_H
#define ANDROID_BACKEND_H
#include "drmhwctwo.h"
namespace android {
class Backend {
public:
virtual ~Backend() = default;
virtual HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display,
uint32_t *num_types,
uint32_t *num_requests);
virtual std::tuple<int, int> GetClientLayers(
DrmHwcTwo::HwcDisplay *display,
const std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map);
virtual bool IsClientLayer(DrmHwcTwo::HwcDisplay *display,
DrmHwcTwo::HwcLayer *layer);
};
} // namespace android
#endif
/*
* Copyright (C) 2020 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.
*/
#ifndef ANDROID_BACKEND_MANAGER_H
#define ANDROID_BACKEND_MANAGER_H
#include "backend.h"
#include "drmhwctwo.h"
#include <functional>
#include <map>
#include <string>
#include <vector>
#define REGISTER_BACKEND(name_str_, backend_) \
static int \
backend = BackendManager::GetInstance() \
.RegisterBackend(name_str_, \
[]() -> std::unique_ptr<Backend> { \
return std::make_unique<backend_>(); \
});
namespace android {
class BackendManager {
public:
using backend_constructor_t = std::function<std::unique_ptr<Backend>()>;
static BackendManager &GetInstance();
int RegisterBackend(const std::string &name,
backend_constructor_t backend_constructor);
int SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display);
std::unique_ptr<Backend> GetBackendByName(std::string &name);
HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display,
uint32_t *num_types, uint32_t *num_requests);
private:
BackendManager() = default;
static const std::vector<std::string> client_devices_;
std::map<std::string, backend_constructor_t> available_backends_;
};
} // namespace android
#endif
......@@ -70,6 +70,8 @@ class DrmDevice {
int GetConnectorProperty(const DrmConnector &connector, const char *prop_name,
DrmProperty *property);
const std::string GetName() const;
const std::vector<std::unique_ptr<DrmCrtc>> &crtcs() const;
uint32_t next_mode_id();
......
......@@ -31,6 +31,8 @@
namespace android {
class Backend;
class DrmHwcTwo : public hwc2_device_t {
public:
static int HookDevOpen(const struct hw_module_t *module, const char *name,
......@@ -256,6 +258,13 @@ class DrmHwcTwo : public hwc2_device_t {
uint32_t frames_flattened_ = 0;
};
const Backend *backend() const {
return backend_.get();
}
void set_backend(std::unique_ptr<Backend> backend) {
backend_ = std::move(backend);
}
const std::vector<DrmPlane *> &primary_planes() const {
return primary_planes_;
}
......@@ -310,6 +319,8 @@ class DrmHwcTwo : public hwc2_device_t {
std::vector<DrmPlane *> primary_planes_;
std::vector<DrmPlane *> overlay_planes_;
std::unique_ptr<Backend> backend_;
VSyncWorker vsync_worker_;
DrmConnector *connector_ = NULL;
DrmCrtc *crtc_ = NULL;
......
Markdown is supported
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