drm_hwcomposer: Reorganize struct DrmHwcLayer
1. Move BlendMode, ColorSpace, SampleRange fields to the struct BufferInfo,
allowing extraction of the data from native_handle using Metadata@4 API.
Use it when data from HWC2 API can't be used (Currently it's a BlendMode
case for CLIENT layer)
2. Rename DrmHwcLayer to LayerData and move it to compositor/ directory.
(I was confused in the past because of similarity of names DrmHwcLayer
vs HwcLayer, so this step should meke it easier for newcomers to
understand the code)
3. Allow clonning of the LayerData to propagate it through the composition
pipeline. Thus LayerData can be used by both HwcLayer to track state
and by the compositor.
Signed-off-by: Roman Stratiienko <roman.o.stratiienko@globallogic.com>
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 7279c02..02df28c 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -90,6 +90,7 @@
: hwc2_(hwc2),
handle_(handle),
type_(type),
+ client_layer_(this),
color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) {
// clang-format off
color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0,
@@ -188,7 +189,7 @@
}
HWC2::Error HwcDisplay::CreateLayer(hwc2_layer_t *layer) {
- layers_.emplace(static_cast<hwc2_layer_t>(layer_idx_), HwcLayer());
+ layers_.emplace(static_cast<hwc2_layer_t>(layer_idx_), HwcLayer(this));
*layer = static_cast<hwc2_layer_t>(layer_idx_);
++layer_idx_;
return HWC2::Error::None;
@@ -478,18 +479,26 @@
if (z_map.empty())
return HWC2::Error::BadLayer;
- std::vector<DrmHwcLayer> composition_layers;
+ std::vector<LayerData> composition_layers;
+
+ /* Import & populate */
+ for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
+ l.second->PopulateLayerData(a_args.test_only);
+ }
// now that they're ordered by z, add them to the composition
for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
- DrmHwcLayer layer;
- l.second->PopulateDrmLayer(&layer);
- int ret = layer.ImportBuffer(GetPipe().device);
- if (ret) {
- ALOGE("Failed to import layer, ret=%d", ret);
- return HWC2::Error::NoResources;
+ if (!l.second->IsLayerUsableAsDevice()) {
+ /* This will be normally triggered on validation of the first frame
+ * containing CLIENT layer. At this moment client buffer is not yet
+ * provided by the CLIENT.
+ * This may be triggered once in HwcLayer lifecycle in case FB can't be
+ * imported. For example when non-contiguous buffer is imported into
+ * contiguous-only DRM/KMS driver.
+ */
+ return HWC2::Error::BadLayer;
}
- composition_layers.emplace_back(std::move(layer));
+ composition_layers.emplace_back(l.second->GetLayerData().Clone());
}
/* Store plan to ensure shared planes won't be stolen by other display
@@ -596,14 +605,13 @@
return HWC2::Error::None;
}
- /* TODO: Do not update source_crop every call.
- * It makes sense to do it once after every hotplug event. */
- auto bi = BufferInfoGetter::GetInstance()->GetBoInfo(target);
-
- if (!bi) {
- return HWC2::Error::BadParameter;
+ client_layer_.PopulateLayerData(/*test = */ true);
+ if (!client_layer_.IsLayerUsableAsDevice()) {
+ ALOGE("Client layer must be always usable by DRM/KMS");
+ return HWC2::Error::BadLayer;
}
+ auto &bi = client_layer_.GetLayerData().bi;
hwc_frect_t source_crop = {.left = 0.0F,
.top = 0.0F,
.right = static_cast<float>(bi->width),
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index cd33ebe..d79efb0 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -22,10 +22,10 @@
#include <optional>
#include "HwcDisplayConfigs.h"
+#include "compositor/LayerData.h"
#include "drm/DrmAtomicStateManager.h"
#include "drm/ResourceManager.h"
#include "drm/VSyncWorker.h"
-#include "drmhwcomposer.h"
#include "hwc2_device/HwcLayer.h"
namespace android {
diff --git a/hwc2_device/HwcLayer.cpp b/hwc2_device/HwcLayer.cpp
index cc535d7..f57ad9b 100644
--- a/hwc2_device/HwcLayer.cpp
+++ b/hwc2_device/HwcLayer.cpp
@@ -18,6 +18,8 @@
#include "HwcLayer.h"
+#include "HwcDisplay.h"
+#include "bufferinfo/BufferInfoGetter.h"
#include "utils/log.h"
namespace android {
@@ -30,17 +32,17 @@
HWC2::Error HwcLayer::SetLayerBlendMode(int32_t mode) {
switch (static_cast<HWC2::BlendMode>(mode)) {
case HWC2::BlendMode::None:
- blending_ = DrmHwcBlending::kNone;
+ blend_mode_ = BufferBlendMode::kNone;
break;
case HWC2::BlendMode::Premultiplied:
- blending_ = DrmHwcBlending::kPreMult;
+ blend_mode_ = BufferBlendMode::kPreMult;
break;
case HWC2::BlendMode::Coverage:
- blending_ = DrmHwcBlending::kCoverage;
+ blend_mode_ = BufferBlendMode::kCoverage;
break;
default:
- ALOGE("Unknown blending mode b=%d", blending_);
- blending_ = DrmHwcBlending::kNone;
+ ALOGE("Unknown blending mode b=%d", blend_mode_);
+ blend_mode_ = BufferBlendMode::kUndefined;
break;
}
return HWC2::Error::None;
@@ -51,8 +53,10 @@
*/
HWC2::Error HwcLayer::SetLayerBuffer(buffer_handle_t buffer,
int32_t acquire_fence) {
- buffer_ = buffer;
acquire_fence_ = UniqueFd(acquire_fence);
+ buffer_handle_ = buffer;
+ buffer_handle_updated_ = true;
+
return HWC2::Error::None;
}
@@ -70,54 +74,54 @@
HWC2::Error HwcLayer::SetLayerDataspace(int32_t dataspace) {
switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
case HAL_DATASPACE_STANDARD_BT709:
- color_space_ = DrmHwcColorSpace::kItuRec709;
+ color_space_ = BufferColorSpace::kItuRec709;
break;
case HAL_DATASPACE_STANDARD_BT601_625:
case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
case HAL_DATASPACE_STANDARD_BT601_525:
case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
- color_space_ = DrmHwcColorSpace::kItuRec601;
+ color_space_ = BufferColorSpace::kItuRec601;
break;
case HAL_DATASPACE_STANDARD_BT2020:
case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
- color_space_ = DrmHwcColorSpace::kItuRec2020;
+ color_space_ = BufferColorSpace::kItuRec2020;
break;
default:
- color_space_ = DrmHwcColorSpace::kUndefined;
+ color_space_ = BufferColorSpace::kUndefined;
}
switch (dataspace & HAL_DATASPACE_RANGE_MASK) {
case HAL_DATASPACE_RANGE_FULL:
- sample_range_ = DrmHwcSampleRange::kFullRange;
+ sample_range_ = BufferSampleRange::kFullRange;
break;
case HAL_DATASPACE_RANGE_LIMITED:
- sample_range_ = DrmHwcSampleRange::kLimitedRange;
+ sample_range_ = BufferSampleRange::kLimitedRange;
break;
default:
- sample_range_ = DrmHwcSampleRange::kUndefined;
+ sample_range_ = BufferSampleRange::kUndefined;
}
return HWC2::Error::None;
}
HWC2::Error HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) {
- display_frame_ = frame;
+ layer_data_.pi.display_frame = frame;
return HWC2::Error::None;
}
HWC2::Error HwcLayer::SetLayerPlaneAlpha(float alpha) {
- alpha_ = alpha;
+ layer_data_.pi.alpha = std::lround(alpha * UINT16_MAX);
return HWC2::Error::None;
}
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
HWC2::Error HwcLayer::SetLayerSidebandStream(
- const native_handle_t * /*stream*/) {
+ const native_handle_t* /*stream*/) {
// TODO(nobody): We don't support sideband
return HWC2::Error::Unsupported;
}
HWC2::Error HwcLayer::SetLayerSourceCrop(hwc_frect_t crop) {
- source_crop_ = crop;
+ layer_data_.pi.source_crop = crop;
return HWC2::Error::None;
}
@@ -135,19 +139,19 @@
// redundant in this case. 90* rotation can be combined with either horizontal
// flip or vertical flip, so treat it differently
if (transform == HWC_TRANSFORM_ROT_270) {
- l_transform = DrmHwcTransform::kRotate270;
+ l_transform = LayerTransform::kRotate270;
} else if (transform == HWC_TRANSFORM_ROT_180) {
- l_transform = DrmHwcTransform::kRotate180;
+ l_transform = LayerTransform::kRotate180;
} else {
if ((transform & HWC_TRANSFORM_FLIP_H) != 0)
- l_transform |= DrmHwcTransform::kFlipH;
+ l_transform |= LayerTransform::kFlipH;
if ((transform & HWC_TRANSFORM_FLIP_V) != 0)
- l_transform |= DrmHwcTransform::kFlipV;
+ l_transform |= LayerTransform::kFlipV;
if ((transform & HWC_TRANSFORM_ROT_90) != 0)
- l_transform |= DrmHwcTransform::kRotate90;
+ l_transform |= LayerTransform::kRotate90;
}
- transform_ = static_cast<DrmHwcTransform>(l_transform);
+ layer_data_.pi.transform = static_cast<LayerTransform>(l_transform);
return HWC2::Error::None;
}
@@ -162,17 +166,49 @@
return HWC2::Error::None;
}
-void HwcLayer::PopulateDrmLayer(DrmHwcLayer *layer) {
- layer->sf_handle = buffer_;
- // TODO(rsglobal): Avoid extra fd duplication
- layer->acquire_fence = UniqueFd::Dup(acquire_fence_.Get());
- layer->display_frame = display_frame_;
- layer->alpha = std::lround(alpha_ * UINT16_MAX);
- layer->blending = blending_;
- layer->source_crop = source_crop_;
- layer->transform = transform_;
- layer->color_space = color_space_;
- layer->sample_range = sample_range_;
+void HwcLayer::ImportFb() {
+ if (!IsLayerUsableAsDevice() || !buffer_handle_updated_) {
+ return;
+ }
+ buffer_handle_updated_ = false;
+
+ layer_data_.fb = {};
+
+ layer_data_.bi = BufferInfoGetter::GetInstance()->GetBoInfo(buffer_handle_);
+ if (!layer_data_.bi) {
+ ALOGW("Unable to get buffer information (0x%p)", buffer_handle_);
+ bi_get_failed_ = true;
+ return;
+ }
+
+ layer_data_
+ .fb = parent_->GetPipe().device->GetDrmFbImporter().GetOrCreateFbId(
+ &layer_data_.bi.value());
+
+ if (!layer_data_.fb) {
+ ALOGV("Unable to create framebuffer object for buffer 0x%p",
+ buffer_handle_);
+ fb_import_failed_ = true;
+ return;
+ }
+}
+
+void HwcLayer::PopulateLayerData(bool test) {
+ ImportFb();
+
+ if (blend_mode_ != BufferBlendMode::kUndefined) {
+ layer_data_.bi->blend_mode = blend_mode_;
+ }
+ if (color_space_ != BufferColorSpace::kUndefined) {
+ layer_data_.bi->color_space = color_space_;
+ }
+ if (sample_range_ != BufferSampleRange::kUndefined) {
+ layer_data_.bi->sample_range = sample_range_;
+ }
+
+ if (!test) {
+ layer_data_.acquire_fence = std::move(acquire_fence_);
+ }
}
} // namespace android
\ No newline at end of file
diff --git a/hwc2_device/HwcLayer.h b/hwc2_device/HwcLayer.h
index ad94129..92e9476 100644
--- a/hwc2_device/HwcLayer.h
+++ b/hwc2_device/HwcLayer.h
@@ -19,14 +19,16 @@
#include <hardware/hwcomposer2.h>
-#include <cmath>
-
-#include "drmhwcomposer.h"
+#include "compositor/LayerData.h"
namespace android {
+class HwcDisplay;
+
class HwcLayer {
public:
+ explicit HwcLayer(HwcDisplay *parent_display) : parent_(parent_display){};
+
HWC2::Composition GetSfType() const {
return sf_type_;
}
@@ -55,27 +57,8 @@
return z_order_;
}
- buffer_handle_t GetBuffer() {
- return buffer_;
- }
-
- hwc_rect_t GetDisplayFrame() {
- return display_frame_;
- }
-
- void PopulateDrmLayer(DrmHwcLayer *layer);
-
- bool RequireScalingOrPhasing() const {
- float src_width = source_crop_.right - source_crop_.left;
- float src_height = source_crop_.bottom - source_crop_.top;
-
- auto dest_width = float(display_frame_.right - display_frame_.left);
- auto dest_height = float(display_frame_.bottom - display_frame_.top);
-
- bool scaling = src_width != dest_width || src_height != dest_height;
- bool phasing = (source_crop_.left - std::floor(source_crop_.left) != 0) ||
- (source_crop_.top - std::floor(source_crop_.top) != 0);
- return scaling || phasing;
+ auto &GetLayerData() {
+ return layer_data_;
}
// Layer hooks
@@ -100,20 +83,41 @@
HWC2::Composition sf_type_ = HWC2::Composition::Invalid;
HWC2::Composition validated_type_ = HWC2::Composition::Invalid;
- buffer_handle_t buffer_ = nullptr;
- hwc_rect_t display_frame_;
- static constexpr float kOpaqueFloat = 1.0F;
- float alpha_ = kOpaqueFloat;
- hwc_frect_t source_crop_;
- DrmHwcTransform transform_ = DrmHwcTransform::kIdentity;
uint32_t z_order_ = 0;
- DrmHwcBlending blending_ = DrmHwcBlending::kNone;
- DrmHwcColorSpace color_space_ = DrmHwcColorSpace::kUndefined;
- DrmHwcSampleRange sample_range_ = DrmHwcSampleRange::kUndefined;
+ LayerData layer_data_;
+
+ /* Should be populated to layer_data_.acquire_fence only before presenting */
+ UniqueFd acquire_fence_;
+
+ /* The following buffer data can have 2 sources:
+ * 1 - Mapper@4 metadata API
+ * 2 - HWC@2 API
+ * We keep ability to have 2 sources in drm_hwc. It may be useful for CLIENT
+ * layer, at this moment HWC@2 API can't specify blending mode for this layer,
+ * but Mapper@4 can do that
+ */
+ BufferColorSpace color_space_{};
+ BufferSampleRange sample_range_{};
+ BufferBlendMode blend_mode_{};
+ buffer_handle_t buffer_handle_{};
+ bool buffer_handle_updated_{};
bool prior_buffer_scanout_flag_{};
- UniqueFd acquire_fence_;
+ HwcDisplay *const parent_;
+
+ /* Layer state */
+ public:
+ void PopulateLayerData(bool test);
+
+ bool IsLayerUsableAsDevice() const {
+ return !bi_get_failed_ && !fb_import_failed_ && buffer_handle_ != nullptr;
+ }
+
+ private:
+ void ImportFb();
+ bool bi_get_failed_{};
+ bool fb_import_failed_{};
};
} // namespace android