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

drm_hwcomposer: Support relaxed requirements for the most bottom plane



1. Some of DRM/KMS drivers has no planes with formats which Android does require,
   but in some cases it's possible to modify the format of the buffer,
   making such planes usable without any drawbacks.

2. Another use-case is blend mode support. Android does require premultiplied
   blending mode support for all planes, but such requirement can be made
   optional for the most bottom plane without any drawbacks.
Signed-off-by: default avatarRoman Stratiienko <roman.o.stratiienko@globallogic.com>
parent 5ef1d9c5
Pipeline #573200 passed with stages
in 11 minutes and 49 seconds
......@@ -42,7 +42,7 @@ auto DrmKmsPlan::CreateDrmKmsPlan(DrmDisplayPipeline &pipe,
plane = *avail_planes.begin();
avail_planes.erase(avail_planes.begin());
} while (!plane->Get()->IsValidForLayer(&dhl));
} while (!plane->Get()->IsValidForLayer(&dhl, z_pos == 0));
LayerToPlaneJoining joining = {
.layer = std::move(dhl),
......
## Feature
Support relaxed requirements for the most bottom plane
## Description:
1. Some of DRM/KMS drivers has no planes with formats which Android does require,
but in some cases it's possible to modify the format of the buffer,
making such planes usable without any drawbacks.
2. Another use-case is blend mode support. Android does require premultiplied blending mode support for all planes,
but such requirement can be made optional for the most bottom plane without any drawbacks.
## Known use-cases:
### 1. sun4i/drm mainline driver kernel 5.4+
DE2.0 SUN4I-VI-0 plane has no format with alpha channel due to hardware limitations
|Layer|Plane# [int. name]|Buffer format|Resolved format|ZPOS|
|---|---|---|---|---|
|DEVICE|0 [SUN4I-UI-0]|DRM_FORMAT_ABGR8888| - |1|
|DEVICE|1 [SUN4I-VI-0]|DRM_FORMAT_ABGR8888|DRM_FORMAT_XBGR8888|0|
|DEVICE|2 [SUN4I-UI-1]|DRM_FORMAT_ABGR8888| - |2|
|DEVICE|3 [SUN4I-UI-2]|DRM_FORMAT_ABGR8888| - |3|
With this feature we are able to use SUN4I-VI-0 as most bottom plane (zpos=0)
## Test
1. Modify kernel driver and remove all alpha-enabled formats from drm/kms driver.
2. Ensure android boots with UI in CLIENT mode
Kernel must not support DRM_FORMAT_ABGR8888 after changes made.
|Layer|Plane|Buffer format|Resolved format|
|---|---|---|---|
|CLIENT|0|DRM_FORMAT_ABGR8888|DRM_FORMAT_XBGR8888|
......@@ -106,6 +106,8 @@ auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
new_frame_state.used_framebuffers.clear();
new_frame_state.used_planes.clear();
bool most_bottom = true;
for (auto &joining : args.composition->plan) {
DrmPlane *plane = joining.plane->Get();
DrmHwcLayer &layer = joining.layer;
......@@ -117,10 +119,11 @@ auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
auto &v = unused_planes;
v.erase(std::remove(v.begin(), v.end(), joining.plane), v.end());
if (plane->AtomicSetState(*pset, layer, joining.z_pos, crtc->GetId()) !=
0) {
if (plane->AtomicSetState(*pset, layer, joining.z_pos, crtc->GetId(),
most_bottom) != 0) {
return -EINVAL;
}
most_bottom = false;
}
}
......
......@@ -35,7 +35,7 @@ auto DrmFbIdHandle::CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
DrmDevice &drm)
-> std::shared_ptr<DrmFbIdHandle> {
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory): priv. constructor usage
std::shared_ptr<DrmFbIdHandle> local(new DrmFbIdHandle(drm));
std::shared_ptr<DrmFbIdHandle> local(new DrmFbIdHandle(drm, *bo));
local->gem_handles_[0] = first_gem_handle;
int32_t err = 0;
......@@ -62,44 +62,53 @@ auto DrmFbIdHandle::CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
if (!drm.HasAddFb2ModifiersSupport() && has_modifiers) {
ALOGE("No ADDFB2 with modifier support. Can't import modifier %" PRIu64,
bo->modifiers[0]);
local.reset();
return local;
return {};
}
/* Create framebuffer object */
if (!has_modifiers) {
err = drmModeAddFB2(drm.GetFd(), bo->width, bo->height, bo->format,
local->gem_handles_.data(), &bo->pitches[0],
&bo->offsets[0], &local->fb_id_, 0);
} else {
err = drmModeAddFB2WithModifiers(drm.GetFd(), bo->width, bo->height,
bo->format, local->gem_handles_.data(),
&bo->pitches[0], &bo->offsets[0],
&bo->modifiers[0], &local->fb_id_,
DRM_MODE_FB_MODIFIERS);
}
err = local->CreateFb(bo->format, &local->fb_id_);
if (err != 0) {
ALOGE("could not create drm fb %d", err);
local.reset();
return {};
}
return local;
}
/* Creates framebuffer object */
auto DrmFbIdHandle::CreateFb(uint32_t fourcc, uint32_t *out_fb_id) -> int {
bool has_modifiers = bo_.modifiers[0] != DRM_FORMAT_MOD_NONE &&
bo_.modifiers[0] != DRM_FORMAT_MOD_INVALID;
/* Create framebuffer object */
if (!has_modifiers) {
return drmModeAddFB2(drm_->GetFd(), bo_.width, bo_.height, fourcc,
gem_handles_.data(), &bo_.pitches[0], &bo_.offsets[0],
out_fb_id, 0);
}
return drmModeAddFB2WithModifiers(drm_->GetFd(), bo_.width, bo_.height,
fourcc, gem_handles_.data(),
&bo_.pitches[0], &bo_.offsets[0],
&bo_.modifiers[0], out_fb_id,
DRM_MODE_FB_MODIFIERS);
}
DrmFbIdHandle::~DrmFbIdHandle() {
/* Destroy framebuffer object */
if (drmModeRmFB(drm_->GetFd(), fb_id_) != 0) {
ALOGE("Failed to rm fb");
ALOGE("Failed to remove framebuffer fb_id=%i", fb_id_);
}
/* Close GEM handles.
*
* WARNING: TODO(nobody):
* From Linux side libweston relies on libgbm to get KMS handle and never
* closes it (handle is closed by libgbm on buffer destruction)
* Probably we should offer similar approach to users (at least on user
* request via system properties)
/* Destroy framebuffer created for resolved formats
* Feature: docs/features/drmhwc-feature-001.md
*/
for (auto &rf : fb_id_resolved_format_) {
if (drmModeRmFB(drm_->GetFd(), rf.second) != 0) {
ALOGE("Failed to remove framebuffer fb_id=%i", rf.second);
}
}
/* Close GEM handles */
struct drm_gem_close gem_close {};
for (size_t i = 0; i < gem_handles_.size(); i++) {
/* Don't close invalid handle. Close handle only once in cases
......
......@@ -49,12 +49,32 @@ class DrmFbIdHandle {
return fb_id_;
}
/* Feature: docs/features/drmhwc-feature-001.md */
auto GetFbIdForFormat [[nodiscard]] (uint32_t fourcc) -> uint32_t {
if (fb_id_resolved_format_.count(fourcc) == 0) {
uint32_t fb_id{};
int err = CreateFb(fourcc, &fb_id);
if (err == 0) {
fb_id_resolved_format_[fourcc] = fb_id;
} else {
return 0;
}
}
return fb_id_resolved_format_[fourcc];
}
private:
explicit DrmFbIdHandle(DrmDevice &drm) : drm_(&drm){};
explicit DrmFbIdHandle(DrmDevice &drm, hwc_drm_bo_t &bo)
: drm_(&drm), bo_(bo){};
DrmDevice *const drm_;
const hwc_drm_bo_t bo_;
auto CreateFb(uint32_t fourcc, uint32_t *out_fb_id) -> int;
uint32_t fb_id_{};
std::map<uint32_t /*fourcc*/, uint32_t /*fb_id*/> fb_id_resolved_format_{};
std::array<GemHandle, kHwcDrmBoMaxPlanes> gem_handles_{};
};
......
......@@ -144,6 +144,12 @@ int DrmPlane::Init() {
}
}
/* Feature: docs/features/drmhwc-feature-001.md */
AddToFormatResolutionTable(DRM_FORMAT_ABGR8888, DRM_FORMAT_XBGR8888);
AddToFormatResolutionTable(DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888);
AddToFormatResolutionTable(DRM_FORMAT_RGBA8888, DRM_FORMAT_RGBX8888);
AddToFormatResolutionTable(DRM_FORMAT_BGRA8888, DRM_FORMAT_BGRX8888);
return 0;
}
......@@ -151,7 +157,7 @@ bool DrmPlane::IsCrtcSupported(const DrmCrtc &crtc) const {
return ((1 << crtc.GetIndexInResArray()) & plane_->possible_crtcs) != 0;
}
bool DrmPlane::IsValidForLayer(DrmHwcLayer *layer) {
bool DrmPlane::IsValidForLayer(DrmHwcLayer *layer, bool most_bottom) {
if (!rotation_property_) {
if (layer->transform != DrmHwcTransform::kIdentity) {
ALOGV("No rotation property on plane %d", GetId());
......@@ -169,14 +175,17 @@ bool DrmPlane::IsValidForLayer(DrmHwcLayer *layer) {
return false;
}
if (blending_enum_map_.count(layer->blending) == 0 &&
layer->blending != DrmHwcBlending::kNone &&
layer->blending != DrmHwcBlending::kPreMult) {
if (blending_enum_map_.count(layer->blending) == 0 && !most_bottom) {
ALOGV("Blending is not supported on plane %d", GetId());
return false;
}
/* Feature: docs/features/drmhwc-feature-001.md */
uint32_t format = layer->buffer_info.format;
if (most_bottom && BottomLayerFormatResolutionTable_.count(format) != 0) {
format = BottomLayerFormatResolutionTable_[format];
}
if (!IsFormatSupported(format)) {
ALOGV("Plane %d does not supports %c%c%c%c format", GetId(), format,
format >> 8, format >> 16, format >> 24);
......@@ -191,6 +200,14 @@ bool DrmPlane::IsFormatSupported(uint32_t format) const {
std::end(formats_);
}
/* Feature: docs/features/drmhwc-feature-001.md */
void DrmPlane::AddToFormatResolutionTable(uint32_t original_fourcc,
uint32_t resolved_fourcc) {
if (!IsFormatSupported(original_fourcc)) {
BottomLayerFormatResolutionTable_[original_fourcc] = resolved_fourcc;
}
}
bool DrmPlane::HasNonRgbFormat() const {
return std::find_if_not(std::begin(formats_), std::end(formats_),
[](uint32_t format) {
......@@ -223,7 +240,8 @@ static int To1616FixPt(float in) {
}
auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer,
uint32_t zpos, uint32_t crtc_id) -> int {
uint32_t zpos, uint32_t crtc_id, bool most_bottom)
-> int {
if (!layer.fb_id_handle) {
ALOGE("Expected a valid framebuffer for pset");
return -EINVAL;
......@@ -245,8 +263,17 @@ auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer,
return -EINVAL;
}
uint32_t fb_id = layer.fb_id_handle->GetFbId();
/* Feature: docs/features/drmhwc-feature-001.md */
if (most_bottom &&
BottomLayerFormatResolutionTable_.count(layer.buffer_info.format) != 0) {
fb_id = layer.fb_id_handle->GetFbIdForFormat(
BottomLayerFormatResolutionTable_[layer.buffer_info.format]);
}
if (!crtc_property_.AtomicSet(pset, crtc_id) ||
!fb_property_.AtomicSet(pset, layer.fb_id_handle->GetFbId()) ||
!fb_property_.AtomicSet(pset, fb_id) ||
!crtc_x_property_.AtomicSet(pset, layer.display_frame.left) ||
!crtc_y_property_.AtomicSet(pset, layer.display_frame.top) ||
!crtc_w_property_.AtomicSet(pset, layer.display_frame.right -
......
......@@ -33,24 +33,23 @@ struct DrmHwcLayer;
class DrmPlane : public PipelineBindable<DrmPlane> {
public:
DrmPlane(const DrmPlane &) = delete;
DrmPlane &operator=(const DrmPlane &) = delete;
static auto CreateInstance(DrmDevice &dev, uint32_t plane_id)
-> std::unique_ptr<DrmPlane>;
DrmPlane(const DrmPlane &) = delete;
DrmPlane &operator=(const DrmPlane &) = delete;
bool IsCrtcSupported(const DrmCrtc &crtc) const;
bool IsValidForLayer(DrmHwcLayer *layer);
bool IsValidForLayer(DrmHwcLayer *layer, bool most_bottom);
auto GetType() const {
return type_;
}
bool IsFormatSupported(uint32_t format) const;
bool HasNonRgbFormat() const;
auto AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer, uint32_t zpos,
uint32_t crtc_id) -> int;
uint32_t crtc_id, bool most_bottom) -> int;
auto AtomicDisablePlane(drmModeAtomicReq &pset) -> int;
auto &GetZPosProperty() const {
return zpos_property_;
......@@ -72,8 +71,16 @@ class DrmPlane : public PipelineBindable<DrmPlane> {
auto GetPlaneProperty(const char *prop_name, DrmProperty &property,
Presence presence = Presence::kMandatory) -> bool;
bool IsFormatSupported(uint32_t format) const;
uint32_t type_{};
/* Feature: docs/features/drmhwc-feature-001.md */
std::map<uint32_t /*ReqDrmFormat*/, uint32_t /*ResolvedDrmFormat*/>
BottomLayerFormatResolutionTable_;
void AddToFormatResolutionTable(uint32_t original_fourcc,
uint32_t resolved_fourcc);
std::vector<uint32_t> formats_;
DrmProperty crtc_property_;
......
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