Upgrade drm_hwcomposer to 75855a6ab877011a2e26ae95da7ddf06dd3a04b2
This project was upgraded with external_updater.
Usage: tools/external_updater/updater.sh update external/drm_hwcomposer
For more info, check https://cs.android.com/android/platform/superproject/main/+/main:tools/external_updater/README.md
Test: TreeHugger
Change-Id: I33ab547cfa3133dc20fedda280232a2a479b28e6
diff --git a/.ci/.gitlab-ci-checkcommit.sh b/.ci/.gitlab-ci-checkcommit.sh
index 1ca2876..5649475 100755
--- a/.ci/.gitlab-ci-checkcommit.sh
+++ b/.ci/.gitlab-ci-checkcommit.sh
@@ -61,7 +61,7 @@
exit 1
fi
- git show -U0 "$h" -- | clang-format-diff-19 -p 1 -style=file > /tmp/format-fixup.patch
+ git diff -U0 "$h" -- | clang-format-diff-19 -p 1 -style=file > /tmp/format-fixup.patch
if [ -s /tmp/format-fixup.patch ]; then
cat /tmp/format-fixup.patch >&2
exit 1
diff --git a/Android.bp b/Android.bp
index 3951949..47b2cd8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,8 +42,6 @@
name: "hwcomposer.drm_defaults",
shared_libs: [
- "android.hardware.graphics.composer@2.1-resources",
- "android.hardware.graphics.composer@2.2-resources",
"libcutils",
"libdrm",
"libhardware",
@@ -130,7 +128,6 @@
srcs: [
"hwc3/Composer.cpp",
"hwc3/ComposerClient.cpp",
- "hwc3/ComposerResources.cpp",
"hwc3/DrmHwcThree.cpp",
"hwc3/Utils.cpp",
],
diff --git a/METADATA b/METADATA
index dacef3a..afe2045 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@
last_upgrade_date {
year: 2025
month: 2
- day: 4
+ day: 18
}
identifier {
type: "Git"
value: "https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer"
- version: "851ea4dc268c4da612c65a5dfedbd3ed85960405"
+ version: "75855a6ab877011a2e26ae95da7ddf06dd3a04b2"
}
}
diff --git a/backend/Backend.cpp b/backend/Backend.cpp
index 91cb84d..bf45c08 100644
--- a/backend/Backend.cpp
+++ b/backend/Backend.cpp
@@ -108,7 +108,10 @@
for (size_t z_order = 0; z_order < layers.size(); ++z_order) {
if (z_order >= first_z && z_order < first_z + size) {
auto &df = layers[z_order]->GetLayerData().pi.display_frame;
- pixops += (df.right - df.left) * (df.bottom - df.top);
+ if (df.i_rect) {
+ pixops += (df.i_rect->right - df.i_rect->left) *
+ (df.i_rect->bottom - df.i_rect->top);
+ }
}
}
return pixops;
diff --git a/bufferinfo/BufferInfo.h b/bufferinfo/BufferInfo.h
index b2297f9..db4c53e 100644
--- a/bufferinfo/BufferInfo.h
+++ b/bufferinfo/BufferInfo.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include <memory>
constexpr int kBufferMaxPlanes = 4;
@@ -40,6 +41,11 @@
kCoverage,
};
+class PrimeFdsSharedBase {
+ public:
+ virtual ~PrimeFdsSharedBase() = default;
+};
+
struct BufferInfo {
uint32_t width;
uint32_t height;
@@ -54,4 +60,9 @@
BufferColorSpace color_space;
BufferSampleRange sample_range;
BufferBlendMode blend_mode;
+
+ /* prime_fds field require valid file descriptors. While their lifecycle is
+ * managed elsewhere. The shared_ptr is used to ensure that the fds are not
+ * closed while the BufferInfo is still in use. */
+ std::shared_ptr<PrimeFdsSharedBase> fds_shared;
};
diff --git a/compositor/LayerData.h b/compositor/LayerData.h
index 7eb6cba..962141f 100644
--- a/compositor/LayerData.h
+++ b/compositor/LayerData.h
@@ -16,9 +16,6 @@
#pragma once
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-
#include <cmath>
#include <cstdbool>
#include <cstdint>
@@ -41,22 +38,53 @@
bool rotate90;
};
+struct SrcRectInfo {
+ struct FRect {
+ float left;
+ float top;
+ float right;
+ float bottom;
+ };
+ /* nullopt means the whole buffer */
+ std::optional<FRect> f_rect;
+};
+
+struct DstRectInfo {
+ struct IRect {
+ int32_t left;
+ int32_t top;
+ int32_t right;
+ int32_t bottom;
+ };
+ /* nullopt means the whole display */
+ std::optional<IRect> i_rect;
+};
+
+constexpr float kAlphaOpaque = 1.0F;
+
struct PresentInfo {
LayerTransform transform{};
- uint16_t alpha = UINT16_MAX;
- hwc_frect_t source_crop{};
- hwc_rect_t display_frame{};
+ float alpha = kAlphaOpaque;
+ SrcRectInfo source_crop{};
+ DstRectInfo display_frame{};
bool RequireScalingOrPhasing() const {
- const float src_width = source_crop.right - source_crop.left;
- const float src_height = source_crop.bottom - source_crop.top;
+ if (!source_crop.f_rect || !display_frame.i_rect) {
+ return false;
+ }
- auto dest_width = float(display_frame.right - display_frame.left);
- auto dest_height = float(display_frame.bottom - display_frame.top);
+ const auto &src = *source_crop.f_rect;
+ const auto &dst = *display_frame.i_rect;
+
+ const float src_width = src.right - src.left;
+ const float src_height = src.bottom - src.top;
+
+ auto dest_width = float(dst.right - dst.left);
+ auto dest_height = float(dst.bottom - dst.top);
auto scaling = src_width != dest_width || src_height != dest_height;
- auto phasing = (source_crop.left - std::floor(source_crop.left) != 0) ||
- (source_crop.top - std::floor(source_crop.top) != 0);
+ auto phasing = (src.left - std::floor(src.left) != 0) ||
+ (src.top - std::floor(src.top) != 0);
return scaling || phasing;
}
};
diff --git a/drm/DrmAtomicStateManager.cpp b/drm/DrmAtomicStateManager.cpp
index 9ce9a93..299d30c 100644
--- a/drm/DrmAtomicStateManager.cpp
+++ b/drm/DrmAtomicStateManager.cpp
@@ -120,6 +120,9 @@
return -EINVAL;
}
+ auto raw_mode = args.display_mode.value().GetRawMode();
+ whole_display_rect_.i_rect = {0, 0, raw_mode.hdisplay, raw_mode.vdisplay};
+
if (!crtc->GetModeProperty().AtomicSet(*pset, *new_frame_state.mode_blob)) {
return -EINVAL;
}
@@ -141,12 +144,14 @@
if (args.colorspace && connector->GetColorspaceProperty()) {
if (!connector->GetColorspaceProperty()
- .AtomicSet(*pset, connector->GetColorspacePropertyValue(*args.colorspace)))
+ .AtomicSet(*pset, connector->GetColorspacePropertyValue(
+ *args.colorspace)))
return -EINVAL;
}
if (args.content_type && connector->GetContentTypeProperty()) {
- if (!connector->GetContentTypeProperty().AtomicSet(*pset, *args.content_type))
+ if (!connector->GetContentTypeProperty().AtomicSet(*pset,
+ *args.content_type))
return -EINVAL;
}
@@ -181,8 +186,8 @@
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(),
+ whole_display_rect_) != 0) {
return -EINVAL;
}
}
diff --git a/drm/DrmAtomicStateManager.h b/drm/DrmAtomicStateManager.h
index 4af04d1..f97a488 100644
--- a/drm/DrmAtomicStateManager.h
+++ b/drm/DrmAtomicStateManager.h
@@ -110,6 +110,8 @@
int frames_staged_{};
int frames_tracked_{};
+ DstRectInfo whole_display_rect_{};
+
void ThreadFn(const std::shared_ptr<DrmAtomicStateManager> &dasm);
std::condition_variable cv_;
std::mutex mutex_;
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index 4534104..6fd5c0c 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -18,6 +18,7 @@
#include "DrmDevice.h"
+#include <sys/mman.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
@@ -34,13 +35,13 @@
namespace android {
auto DrmDevice::CreateInstance(std::string const &path,
- ResourceManager *res_man)
+ ResourceManager *res_man, uint32_t index)
-> std::unique_ptr<DrmDevice> {
if (!IsKMSDev(path.c_str())) {
return {};
}
- auto device = std::unique_ptr<DrmDevice>(new DrmDevice(res_man));
+ auto device = std::unique_ptr<DrmDevice>(new DrmDevice(res_man, index));
if (device->Init(path.c_str()) != 0) {
return {};
@@ -49,7 +50,8 @@
return device;
}
-DrmDevice::DrmDevice(ResourceManager *res_man) : res_man_(res_man) {
+DrmDevice::DrmDevice(ResourceManager *res_man, uint32_t index)
+ : index_in_dev_array_(index), res_man_(res_man) {
drm_fb_importer_ = std::make_unique<DrmFbImporter>(*this);
}
@@ -260,4 +262,93 @@
return encoders_;
}
+class DumbBufferFd : public PrimeFdsSharedBase {
+ public:
+ SharedFd fd;
+};
+
+// NOLINTBEGIN(cppcoreguidelines-avoid-goto)
+auto DrmDevice::CreateBufferForModeset(uint32_t width, uint32_t height)
+ -> std::optional<BufferInfo> {
+ constexpr uint32_t kDumbBufferFormat = DRM_FORMAT_XRGB8888;
+ constexpr uint32_t kDumbBufferBpp = 32;
+
+ std::optional<BufferInfo> result;
+ void *ptr = MAP_FAILED;
+ struct drm_mode_create_dumb create = {
+ .height = height,
+ .width = width,
+ .bpp = kDumbBufferBpp,
+ .flags = 0,
+ };
+
+ int ret = drmIoctl(*fd_, DRM_IOCTL_MODE_CREATE_DUMB, &create);
+ if (ret != 0) {
+ ALOGE("Failed to DRM_IOCTL_MODE_CREATE_DUMB %d", errno);
+ return {};
+ }
+
+ struct drm_mode_map_dumb map = {
+ .handle = create.handle,
+ };
+
+ auto dumb_buffer_fd = std::make_shared<DumbBufferFd>();
+
+ BufferInfo buffer_info = {
+ .width = width,
+ .height = height,
+
+ .format = kDumbBufferFormat,
+ .pitches = {create.pitch},
+ .prime_fds = {-1, -1, -1, -1},
+ .modifiers = {DRM_FORMAT_MOD_NONE},
+
+ .color_space = BufferColorSpace::kUndefined,
+ .sample_range = BufferSampleRange::kUndefined,
+ .blend_mode = BufferBlendMode::kNone,
+
+ .fds_shared = dumb_buffer_fd,
+ };
+
+ ret = drmIoctl(*fd_, DRM_IOCTL_MODE_MAP_DUMB, &map);
+ if (ret != 0) {
+ ALOGE("Failed to DRM_IOCTL_MODE_MAP_DUMB %d", errno);
+ goto done;
+ }
+
+ ptr = mmap(nullptr, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd_,
+ (off_t)map.offset);
+ if (ptr == MAP_FAILED) {
+ ALOGE("Failed to mmap dumb buffer %d", errno);
+ goto done;
+ }
+
+ memset(ptr, 0, create.size);
+
+ if (munmap(ptr, create.size) != 0) {
+ ALOGE("Failed to unmap dumb buffer: %d", errno);
+ }
+
+ ret = drmPrimeHandleToFD(*fd_, create.handle, 0, &buffer_info.prime_fds[0]);
+ if (ret != 0) {
+ ALOGE("Failed to export dumb buffer as FD: %d", errno);
+ goto done;
+ }
+
+ dumb_buffer_fd->fd = MakeSharedFd(buffer_info.prime_fds[0]);
+
+ result = buffer_info;
+
+done:
+ if (create.handle > 0) {
+ struct drm_mode_destroy_dumb destroy = {
+ .handle = create.handle,
+ };
+ drmIoctl(*fd_, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
+ }
+
+ return result;
+}
+// NOLINTEND(cppcoreguidelines-avoid-goto)
+
} // namespace android
diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h
index cbaa536..baa719d 100644
--- a/drm/DrmDevice.h
+++ b/drm/DrmDevice.h
@@ -18,11 +18,13 @@
#include <cstdint>
#include <map>
+#include <optional>
#include <tuple>
#include "DrmConnector.h"
#include "DrmCrtc.h"
#include "DrmEncoder.h"
+#include "bufferinfo/BufferInfo.h"
#include "utils/fd.h"
namespace android {
@@ -35,13 +37,17 @@
public:
~DrmDevice() = default;
- static auto CreateInstance(std::string const &path, ResourceManager *res_man)
- -> std::unique_ptr<DrmDevice>;
+ static auto CreateInstance(std::string const &path, ResourceManager *res_man,
+ uint32_t index) -> std::unique_ptr<DrmDevice>;
auto &GetFd() const {
return fd_;
}
+ auto GetIndexInDevArray() const {
+ return index_in_dev_array_;
+ }
+
auto &GetResMan() {
return *res_man_;
}
@@ -70,6 +76,9 @@
return HasAddFb2ModifiersSupport_;
}
+ auto CreateBufferForModeset(uint32_t width, uint32_t height)
+ -> std::optional<BufferInfo>;
+
auto &GetDrmFbImporter() {
return *drm_fb_importer_;
}
@@ -98,12 +107,13 @@
DrmProperty *property) const;
private:
- explicit DrmDevice(ResourceManager *res_man);
+ explicit DrmDevice(ResourceManager *res_man, uint32_t index);
auto Init(const char *path) -> int;
static auto IsKMSDev(const char *path) -> bool;
SharedFd fd_;
+ const uint32_t index_in_dev_array_;
std::vector<std::unique_ptr<DrmConnector>> connectors_;
std::vector<std::unique_ptr<DrmConnector>> writeback_connectors_;
diff --git a/drm/DrmMode.cpp b/drm/DrmMode.cpp
index 7cbea44..d9fdb37 100644
--- a/drm/DrmMode.cpp
+++ b/drm/DrmMode.cpp
@@ -28,6 +28,11 @@
return memcmp(&m, &mode_, offsetof(drmModeModeInfo, name)) == 0;
}
+bool DrmMode::SameSize(const DrmMode &mode) const {
+ return (mode_.vdisplay == mode.mode_.vdisplay) &&
+ (mode_.hdisplay == mode.mode_.hdisplay);
+}
+
auto DrmMode::CreateModeBlob(const DrmDevice &drm)
-> DrmModeUserPropertyBlobUnique {
struct drm_mode_modeinfo drm_mode = {};
diff --git a/drm/DrmMode.h b/drm/DrmMode.h
index 5450daf..7520824 100644
--- a/drm/DrmMode.h
+++ b/drm/DrmMode.h
@@ -35,6 +35,8 @@
bool operator==(const drmModeModeInfo &m) const;
+ bool SameSize(const DrmMode &mode) const;
+
auto &GetRawMode() const {
return mode_;
}
diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp
index 0010742..68887dd 100644
--- a/drm/DrmPlane.cpp
+++ b/drm/DrmPlane.cpp
@@ -25,6 +25,7 @@
#include "DrmDevice.h"
#include "bufferinfo/BufferInfoGetter.h"
+#include "compositor/LayerData.h"
#include "utils/log.h"
namespace android {
@@ -107,17 +108,17 @@
GetPlaneProperty("IN_FENCE_FD", in_fence_fd_property_, Presence::kOptional);
if (HasNonRgbFormat()) {
- if (GetPlaneProperty("COLOR_ENCODING", color_encoding_propery_,
+ if (GetPlaneProperty("COLOR_ENCODING", color_encoding_property_,
Presence::kOptional)) {
- color_encoding_propery_.AddEnumToMap("ITU-R BT.709 YCbCr",
- BufferColorSpace::kItuRec709,
- color_encoding_enum_map_);
- color_encoding_propery_.AddEnumToMap("ITU-R BT.601 YCbCr",
- BufferColorSpace::kItuRec601,
- color_encoding_enum_map_);
- color_encoding_propery_.AddEnumToMap("ITU-R BT.2020 YCbCr",
- BufferColorSpace::kItuRec2020,
- color_encoding_enum_map_);
+ color_encoding_property_.AddEnumToMap("ITU-R BT.709 YCbCr",
+ BufferColorSpace::kItuRec709,
+ color_encoding_enum_map_);
+ color_encoding_property_.AddEnumToMap("ITU-R BT.601 YCbCr",
+ BufferColorSpace::kItuRec601,
+ color_encoding_enum_map_);
+ color_encoding_property_.AddEnumToMap("ITU-R BT.2020 YCbCr",
+ BufferColorSpace::kItuRec2020,
+ color_encoding_enum_map_);
}
if (GetPlaneProperty("COLOR_RANGE", color_range_property_,
@@ -145,7 +146,7 @@
// any CRTC already, which is protected by the plane_switching_crtc function
// in the kernel drivers/gpu/drm/drm_atomic.c file.
// The current drm_hwc design is not ready to support such scenario yet,
- // so adding the CRTC status check here to workaorund for now.
+ // so adding the CRTC status check here to workaround for now.
return false;
}
@@ -188,7 +189,7 @@
return false;
}
- if (!alpha_property_ && layer->pi.alpha != UINT16_MAX) {
+ if (!alpha_property_ && layer->pi.alpha != kAlphaOpaque) {
ALOGV("Alpha is not supported on plane %d", GetId());
return false;
}
@@ -229,7 +230,8 @@
}
auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, LayerData &layer,
- uint32_t zpos, uint32_t crtc_id) -> int {
+ uint32_t zpos, uint32_t crtc_id,
+ DstRectInfo &whole_display_rect) -> int {
if (!layer.fb || !layer.bi) {
ALOGE("%s: Invalid arguments", __func__);
return -EINVAL;
@@ -251,8 +253,24 @@
return -EINVAL;
}
- auto &disp = layer.pi.display_frame;
- auto &src = layer.pi.source_crop;
+ auto opt_disp = layer.pi.display_frame.i_rect;
+ if (!layer.pi.display_frame.i_rect) {
+ opt_disp = whole_display_rect.i_rect;
+ }
+
+ auto opt_src = layer.pi.source_crop.f_rect;
+ if (!layer.pi.source_crop.f_rect) {
+ opt_src = {0.0F, 0.0F, float(layer.bi->width), float(layer.bi->height)};
+ }
+
+ if (!opt_disp || !opt_src) {
+ ALOGE("%s: Invalid display frame or source crop", __func__);
+ return -EINVAL;
+ }
+
+ auto disp = opt_disp.value();
+ auto src = opt_src.value();
+
if (!crtc_property_.AtomicSet(pset, crtc_id) ||
!fb_property_.AtomicSet(pset, layer.fb->GetFbId()) ||
!crtc_x_property_.AtomicSet(pset, disp.left) ||
@@ -271,7 +289,9 @@
return -EINVAL;
}
- if (alpha_property_ && !alpha_property_.AtomicSet(pset, layer.pi.alpha)) {
+ if (alpha_property_ &&
+ !alpha_property_.AtomicSet(pset,
+ std::lround(layer.pi.alpha * UINT16_MAX))) {
return -EINVAL;
}
@@ -282,7 +302,7 @@
}
if (color_encoding_enum_map_.count(layer.bi->color_space) != 0 &&
- !color_encoding_propery_
+ !color_encoding_property_
.AtomicSet(pset, color_encoding_enum_map_[layer.bi->color_space])) {
return -EINVAL;
}
diff --git a/drm/DrmPlane.h b/drm/DrmPlane.h
index 24d21c8..81306d9 100644
--- a/drm/DrmPlane.h
+++ b/drm/DrmPlane.h
@@ -49,7 +49,7 @@
bool HasNonRgbFormat() const;
auto AtomicSetState(drmModeAtomicReq &pset, LayerData &layer, uint32_t zpos,
- uint32_t crtc_id) -> int;
+ uint32_t crtc_id, DstRectInfo &whole_display_rect) -> int;
auto AtomicDisablePlane(drmModeAtomicReq &pset) -> int;
auto &GetZPosProperty() const {
return zpos_property_;
@@ -90,7 +90,7 @@
DrmProperty alpha_property_;
DrmProperty blend_property_;
DrmProperty in_fence_fd_property_;
- DrmProperty color_encoding_propery_;
+ DrmProperty color_encoding_property_;
DrmProperty color_range_property_;
std::map<BufferBlendMode, uint64_t> blending_enum_map_;
diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp
index c866263..fee251e 100644
--- a/drm/ResourceManager.cpp
+++ b/drm/ResourceManager.cpp
@@ -55,7 +55,7 @@
auto path_len = property_get("vendor.hwc.drm.device", path_pattern,
"/dev/dri/card%");
if (path_pattern[path_len - 1] != '%') {
- auto dev = DrmDevice::CreateInstance(path_pattern, this);
+ auto dev = DrmDevice::CreateInstance(path_pattern, this, 0);
if (dev) {
drms_.emplace_back(std::move(dev));
}
@@ -69,7 +69,7 @@
if (stat(path.str().c_str(), &buf) != 0)
break;
- auto dev = DrmDevice::CreateInstance(path.str(), this);
+ auto dev = DrmDevice::CreateInstance(path.str(), this, idx);
if (dev) {
drms_.emplace_back(std::move(dev));
}
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 16d8bac..42ebd63 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -21,13 +21,7 @@
#include <cinttypes>
-#include <xf86drmMode.h>
-
-#include <hardware/gralloc.h>
#include <ui/ColorSpace.h>
-#include <ui/GraphicBufferAllocator.h>
-#include <ui/GraphicBufferMapper.h>
-#include <ui/PixelFormat.h>
#include "backend/Backend.h"
#include "backend/BackendManager.h"
@@ -95,98 +89,8 @@
return color_matrix;
}
-// Allocate a black buffer that can be used for an initial modeset when there.
-// is no appropriate client buffer available to be used.
-// Caller must free the returned buffer with GraphicBufferAllocator::free.
-auto GetModesetBuffer(uint32_t width, uint32_t height) -> buffer_handle_t {
- constexpr PixelFormat format = PIXEL_FORMAT_RGBA_8888;
- constexpr uint64_t usage = GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
-
- constexpr uint32_t layer_count = 1;
- const std::string name = "drm-hwcomposer";
-
- buffer_handle_t handle = nullptr;
- uint32_t stride = 0;
- status_t status = GraphicBufferAllocator::get().allocate(width, height,
- format, layer_count,
- usage, &handle,
- &stride, name);
- if (status != OK) {
- ALOGE("Failed to allocate modeset buffer.");
- return nullptr;
- }
-
- void *data = nullptr;
- Rect bounds = {0, 0, static_cast<int32_t>(width),
- static_cast<int32_t>(height)};
- status = GraphicBufferMapper::get().lock(handle, usage, bounds, &data);
- if (status != OK) {
- ALOGE("Failed to map modeset buffer.");
- GraphicBufferAllocator::get().free(handle);
- return nullptr;
- }
-
- // Cast one of the multiplicands to ensure that the multiplication happens
- // in a wider type (size_t).
- const size_t buffer_size = static_cast<size_t>(height) * stride *
- bytesPerPixel(format);
- memset(data, 0, buffer_size);
- status = GraphicBufferMapper::get().unlock(handle);
- ALOGW_IF(status != OK, "Failed to unmap buffer.");
- return handle;
-}
-
-auto GetModesetLayerProperties(buffer_handle_t buffer, uint32_t width,
- uint32_t height) -> HwcLayer::LayerProperties {
- HwcLayer::LayerProperties properties;
- properties.buffer = {.buffer_handle = buffer, .acquire_fence = {}};
- properties.display_frame = {
- .left = 0,
- .top = 0,
- .right = int(width),
- .bottom = int(height),
- };
- properties.source_crop = (hwc_frect_t){
- .left = 0.0F,
- .top = 0.0F,
- .right = static_cast<float>(width),
- .bottom = static_cast<float>(height),
- };
- properties.blend_mode = BufferBlendMode::kNone;
- return properties;
-}
} // namespace
-static BufferColorSpace Hwc2ToColorSpace(int32_t dataspace) {
- switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
- case HAL_DATASPACE_STANDARD_BT709:
- return BufferColorSpace::kItuRec709;
- 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:
- return BufferColorSpace::kItuRec601;
- case HAL_DATASPACE_STANDARD_BT2020:
- case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
- return BufferColorSpace::kItuRec2020;
- default:
- return BufferColorSpace::kUndefined;
- }
-}
-
-static BufferSampleRange Hwc2ToSampleRange(int32_t dataspace) {
- switch (dataspace & HAL_DATASPACE_RANGE_MASK) {
- case HAL_DATASPACE_RANGE_FULL:
- return BufferSampleRange::kFullRange;
- case HAL_DATASPACE_RANGE_LIMITED:
- return BufferSampleRange::kLimitedRange;
- default:
- return BufferSampleRange::kUndefined;
- }
-}
-
std::string HwcDisplay::DumpDelta(HwcDisplay::Stats delta) {
if (delta.total_pixops_ == 0)
return "No stats yet";
@@ -305,14 +209,23 @@
modeset_layer_data = client_layer_.GetLayerData();
} else {
ALOGV("Allocate modeset buffer.");
- buffer_handle_t modeset_buffer = GetModesetBuffer(width, height);
- if (modeset_buffer != nullptr) {
+ auto modeset_buffer = //
+ GetPipe().device->CreateBufferForModeset(width, height);
+ if (modeset_buffer) {
auto modeset_layer = std::make_unique<HwcLayer>(this);
- modeset_layer->SetLayerProperties(
- GetModesetLayerProperties(modeset_buffer, width, height));
+ HwcLayer::LayerProperties properties;
+ properties.slot_buffer = {
+ .slot_id = 0,
+ .bi = modeset_buffer,
+ };
+ properties.active_slot = {
+ .slot_id = 0,
+ .fence = {},
+ };
+ properties.blend_mode = BufferBlendMode::kNone;
+ modeset_layer->SetLayerProperties(properties);
modeset_layer->PopulateLayerData();
modeset_layer_data = modeset_layer->GetLayerData();
- GraphicBufferAllocator::get().free(modeset_buffer);
}
}
@@ -412,12 +325,32 @@
auto HwcDisplay::PresentStagedComposition(
SharedFd &out_present_fence, std::vector<ReleaseFence> &out_release_fences)
-> bool {
- int out_fd = -1;
- auto error = PresentDisplay(&out_fd);
- out_present_fence = MakeSharedFd(out_fd);
- if (error != HWC2::Error::None) {
- return false;
+ if (IsInHeadlessMode()) {
+ return true;
}
+ HWC2::Error ret{};
+
+ ++total_stats_.total_frames_;
+
+ AtomicCommitArgs a_args{};
+ ret = CreateComposition(a_args);
+
+ if (ret != HWC2::Error::None)
+ ++total_stats_.failed_kms_present_;
+
+ if (ret == HWC2::Error::BadLayer) {
+ // Can we really have no client or device layers?
+ return true;
+ }
+ if (ret != HWC2::Error::None)
+ return false;
+
+ out_present_fence = a_args.out_fence;
+
+ // Reset the color matrix so we don't apply it over and over again.
+ color_matrix_ = {};
+
+ ++frame_no_;
if (!out_present_fence) {
return true;
@@ -467,7 +400,7 @@
vsync_worker_ = {};
}
- SetClientTarget(nullptr, -1, 0, {});
+ client_layer_.ClearSlots();
}
HWC2::Error HwcDisplay::Init() {
@@ -534,12 +467,6 @@
return SetActiveConfig(configs_.preferred_config_id);
}
-HWC2::Error HwcDisplay::AcceptDisplayChanges() {
- for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_)
- l.second.AcceptTypeChange();
- return HWC2::Error::None;
-}
-
HWC2::Error HwcDisplay::CreateLayer(hwc2_layer_t *layer) {
layers_.emplace(static_cast<hwc2_layer_t>(layer_idx_), HwcLayer(this));
*layer = static_cast<hwc2_layer_t>(layer_idx_);
@@ -566,53 +493,14 @@
return HWC2::Error::None;
}
-HWC2::Error HwcDisplay::GetChangedCompositionTypes(uint32_t *num_elements,
- hwc2_layer_t *layers,
- int32_t *types) {
- if (IsInHeadlessMode()) {
- *num_elements = 0;
- return HWC2::Error::None;
- }
-
- uint32_t num_changes = 0;
- for (auto &l : layers_) {
- if (l.second.IsTypeChanged()) {
- if (layers && num_changes < *num_elements)
- layers[num_changes] = l.first;
- if (types && num_changes < *num_elements)
- types[num_changes] = static_cast<int32_t>(l.second.GetValidatedType());
- ++num_changes;
- }
- }
- if (!layers && !types)
- *num_elements = num_changes;
- return HWC2::Error::None;
-}
-
-HWC2::Error HwcDisplay::GetClientTargetSupport(uint32_t width, uint32_t height,
- int32_t /*format*/,
- int32_t dataspace) {
- if (IsInHeadlessMode()) {
- return HWC2::Error::None;
- }
-
- auto min = pipeline_->device->GetMinResolution();
- auto max = pipeline_->device->GetMaxResolution();
-
- if (width < min.first || height < min.second)
- return HWC2::Error::Unsupported;
-
- if (width > max.first || height > max.second)
- return HWC2::Error::Unsupported;
-
- if (dataspace != HAL_DATASPACE_UNKNOWN)
- return HWC2::Error::Unsupported;
-
- // TODO(nobody): Validate format can be handled by either GL or planes
- return HWC2::Error::None;
-}
-
HWC2::Error HwcDisplay::GetColorModes(uint32_t *num_modes, int32_t *modes) {
+ if (IsInHeadlessMode()) {
+ *num_modes = 1;
+ if (modes)
+ modes[0] = HAL_COLOR_MODE_NATIVE;
+ return HWC2::Error::None;
+ }
+
if (!modes) {
std::vector<Colormode> temp_modes;
GetEdid()->GetColorModes(temp_modes);
@@ -725,30 +613,20 @@
return HWC2::Error::None;
}
-HWC2::Error HwcDisplay::GetDisplayRequests(int32_t * /*display_requests*/,
- uint32_t *num_elements,
- hwc2_layer_t * /*layers*/,
- int32_t * /*layer_requests*/) {
- // TODO(nobody): I think virtual display should request
- // HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here
- *num_elements = 0;
- return HWC2::Error::None;
-}
-
HWC2::Error HwcDisplay::GetDisplayType(int32_t *type) {
*type = static_cast<int32_t>(type_);
return HWC2::Error::None;
}
-HWC2::Error HwcDisplay::GetDozeSupport(int32_t *support) {
- *support = 0;
- return HWC2::Error::None;
-}
-
HWC2::Error HwcDisplay::GetHdrCapabilities(uint32_t *num_types, int32_t *types,
float *max_luminance,
float *max_average_luminance,
float *min_luminance) {
+ if (IsInHeadlessMode()) {
+ *num_types = 0;
+ return HWC2::Error::None;
+ }
+
if (!types) {
std::vector<ui::Hdr> temp_types;
float lums[3] = {0.F};
@@ -777,45 +655,6 @@
return HWC2::Error::None;
}
-/* Find API details at:
- * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1767
- *
- * Called after PresentDisplay(), CLIENT is expecting release fence for the
- * prior buffer (not the one assigned to the layer at the moment).
- */
-HWC2::Error HwcDisplay::GetReleaseFences(uint32_t *num_elements,
- hwc2_layer_t *layers,
- int32_t *fences) {
- if (IsInHeadlessMode()) {
- *num_elements = 0;
- return HWC2::Error::None;
- }
-
- uint32_t num_layers = 0;
-
- for (auto &l : layers_) {
- if (!l.second.GetPriorBufferScanOutFlag() || !present_fence_) {
- continue;
- }
-
- ++num_layers;
-
- if (layers == nullptr || fences == nullptr)
- continue;
-
- if (num_layers > *num_elements) {
- ALOGW("Overflow num_elements %d/%d", num_layers, *num_elements);
- return HWC2::Error::None;
- }
-
- layers[num_layers - 1] = l.first;
- fences[num_layers - 1] = DupFd(present_fence_);
- }
- *num_elements = num_layers;
-
- return HWC2::Error::None;
-}
-
AtomicCommitArgs HwcDisplay::CreateModesetCommit(
const HwcDisplayConfig *config,
const std::optional<LayerData> &modeset_layer) {
@@ -845,6 +684,7 @@
return args;
}
+// NOLINTNEXTLINE(readability-function-cognitive-complexity)
HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
if (IsInHeadlessMode()) {
ALOGE("%s: Display is in headless mode, should never reach here", __func__);
@@ -867,14 +707,6 @@
if (staged_config == nullptr) {
return HWC2::Error::BadConfig;
}
- HwcLayer::LayerProperties lp;
- lp.display_frame = {
- .left = 0,
- .top = 0,
- .right = int(staged_config->mode.GetRawMode().hdisplay),
- .bottom = int(staged_config->mode.GetRawMode().vdisplay),
- };
- client_layer_.SetLayerProperties(lp);
configs_.active_config_id = staged_mode_config_id_.value();
a_args.display_mode = staged_config->mode;
@@ -901,9 +733,24 @@
continue;
}
}
- if (use_client_layer)
+ if (use_client_layer) {
z_map.emplace(client_z_order, &client_layer_);
+ client_layer_.PopulateLayerData();
+ if (!client_layer_.IsLayerUsableAsDevice()) {
+ ALOGE_IF(!a_args.test_only,
+ "Client layer must be always usable by DRM/KMS");
+ /* This may 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;
+ }
+ }
+
if (z_map.empty())
return HWC2::Error::BadLayer;
@@ -917,13 +764,6 @@
// now that they're ordered by z, add them to the composition
for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
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(l.second->GetLayerData());
@@ -936,6 +776,11 @@
std::move(composition_layers));
if (type_ == HWC2::DisplayType::Virtual) {
+ writeback_layer_->PopulateLayerData();
+ if (!writeback_layer_->IsLayerUsableAsDevice()) {
+ ALOGE("Output layer must be always usable by DRM/KMS");
+ return HWC2::Error::BadLayer;
+ }
a_args.writeback_fb = writeback_layer_->GetLayerData().fb;
a_args.writeback_release_fence = writeback_layer_->GetLayerData()
.acquire_fence;
@@ -971,43 +816,6 @@
return HWC2::Error::None;
}
-/* Find API details at:
- * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1805
- */
-HWC2::Error HwcDisplay::PresentDisplay(int32_t *out_present_fence) {
- if (IsInHeadlessMode()) {
- *out_present_fence = -1;
- return HWC2::Error::None;
- }
- HWC2::Error ret{};
-
- ++total_stats_.total_frames_;
-
- AtomicCommitArgs a_args{};
- ret = CreateComposition(a_args);
-
- if (ret != HWC2::Error::None)
- ++total_stats_.failed_kms_present_;
-
- if (ret == HWC2::Error::BadLayer) {
- // Can we really have no client or device layers?
- *out_present_fence = -1;
- return HWC2::Error::None;
- }
- if (ret != HWC2::Error::None)
- return ret;
-
- this->present_fence_ = a_args.out_fence;
- *out_present_fence = DupFd(a_args.out_fence);
-
- // Reset the color matrix so we don't apply it over and over again.
- color_matrix_ = {};
-
- ++frame_no_;
-
- return HWC2::Error::None;
-}
-
HWC2::Error HwcDisplay::SetActiveConfigInternal(uint32_t config,
int64_t change_time) {
if (configs_.hwc_configs.count(config) == 0) {
@@ -1025,56 +833,6 @@
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
- */
-HWC2::Error HwcDisplay::SetClientTarget(buffer_handle_t target,
- int32_t acquire_fence,
- int32_t dataspace,
- hwc_region_t /*damage*/) {
- HwcLayer::LayerProperties lp;
- lp.buffer = {.buffer_handle = target,
- .acquire_fence = MakeSharedFd(acquire_fence)};
- lp.color_space = Hwc2ToColorSpace(dataspace);
- lp.sample_range = Hwc2ToSampleRange(dataspace);
- client_layer_.SetLayerProperties(lp);
-
- /*
- * target can be nullptr, this does mean the Composer Service is calling
- * cleanDisplayResources() on after receiving HOTPLUG event. See more at:
- * https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h;l=350;drc=944b68180b008456ed2eb4d4d329e33b19bd5166
- */
- if (target == nullptr) {
- client_layer_.SwChainClearCache();
- return HWC2::Error::None;
- }
-
- if (IsInHeadlessMode()) {
- return HWC2::Error::None;
- }
-
- client_layer_.PopulateLayerData();
- if (!client_layer_.IsLayerUsableAsDevice()) {
- ALOGE("Client layer must be always usable by DRM/KMS");
- return HWC2::Error::BadLayer;
- }
-
- auto &bi = client_layer_.GetLayerData().bi;
- if (!bi) {
- ALOGE("%s: Invalid state", __func__);
- return HWC2::Error::BadLayer;
- }
-
- lp = {};
- lp.source_crop = {.left = 0.0F,
- .top = 0.0F,
- .right = float(bi->width),
- .bottom = float(bi->height)};
- client_layer_.SetLayerProperties(lp);
-
- return HWC2::Error::None;
-}
-
HWC2::Error HwcDisplay::SetColorMode(int32_t mode) {
/* Maps to the Colorspace DRM connector property:
* https://elixir.bootlin.com/linux/v6.11/source/include/drm/drm_connector.h#L538
@@ -1180,21 +938,6 @@
return true;
}
-HWC2::Error HwcDisplay::SetOutputBuffer(buffer_handle_t buffer,
- int32_t release_fence) {
- HwcLayer::LayerProperties lp;
- lp.buffer = {.buffer_handle = buffer,
- .acquire_fence = MakeSharedFd(release_fence)};
- writeback_layer_->SetLayerProperties(lp);
- writeback_layer_->PopulateLayerData();
- if (!writeback_layer_->IsLayerUsableAsDevice()) {
- ALOGE("Output layer must be always usable by DRM/KMS");
- return HWC2::Error::BadLayer;
- }
- /* TODO: Check if format is supported by writeback connector */
- return HWC2::Error::None;
-}
-
HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
auto mode = static_cast<HWC2::PowerMode>(mode_in);
@@ -1261,25 +1004,6 @@
return HWC2::Error::None;
}
-HWC2::Error HwcDisplay::ValidateDisplay(uint32_t *num_types,
- uint32_t *num_requests) {
- if (IsInHeadlessMode()) {
- *num_types = *num_requests = 0;
- return HWC2::Error::None;
- }
-
- /* In current drm_hwc design in case previous frame layer was not validated as
- * a CLIENT, it is used by display controller (Front buffer). We have to store
- * this state to provide the CLIENT with the release fences for such buffers.
- */
- for (auto &l : layers_) {
- l.second.SetPriorBufferScanOutFlag(l.second.GetValidatedType() !=
- HWC2::Composition::Client);
- }
-
- return backend_->ValidateDisplay(this, num_types, num_requests);
-}
-
std::vector<HwcLayer *> HwcDisplay::GetOrderLayersByZPos() {
std::vector<HwcLayer *> ordered_layers;
ordered_layers.reserve(layers_.size());
@@ -1413,19 +1137,6 @@
return HWC2::Error::None;
}
-HWC2::Error HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) {
- return HWC2::Error::Unsupported;
-}
-
-HWC2::Error HwcDisplay::GetSupportedContentTypes(
- uint32_t *outNumSupportedContentTypes,
- const uint32_t *outSupportedContentTypes) {
- if (outSupportedContentTypes == nullptr)
- *outNumSupportedContentTypes = 0;
-
- return HWC2::Error::None;
-}
-
HWC2::Error HwcDisplay::SetContentType(int32_t contentType) {
/* Maps exactly to the content_type DRM connector property:
* https://elixir.bootlin.com/linux/v6.11/source/include/uapi/drm/drm_mode.h#L107
@@ -1447,12 +1158,21 @@
return HWC2::Error::Unsupported;
}
- auto blob = GetPipe().connector->Get()->GetEdidBlob();
+ auto *connector = GetPipe().connector->Get();
+ auto blob = connector->GetEdidBlob();
if (!blob) {
return HWC2::Error::Unsupported;
}
- *outPort = handle_; /* TDOD(nobody): What should be here? */
+ constexpr uint8_t kDrmDeviceBitShift = 5U;
+ constexpr uint8_t kDrmDeviceBitMask = 0xE0;
+ constexpr uint8_t kConnectorBitMask = 0x1F;
+ const auto kDrmIdx = static_cast<uint8_t>(
+ connector->GetDev().GetIndexInDevArray());
+ const auto kConnectorIdx = static_cast<uint8_t>(
+ connector->GetIndexInResArray());
+ *outPort = (((kDrmIdx << kDrmDeviceBitShift) & kDrmDeviceBitMask) |
+ (kConnectorIdx & kConnectorBitMask));
if (outData) {
*outDataSize = std::min(*outDataSize, blob->length);
@@ -1494,15 +1214,6 @@
return HWC2::Error::None;
}
-HWC2::Error HwcDisplay::GetDisplayBrightnessSupport(bool *supported) {
- *supported = false;
- return HWC2::Error::None;
-}
-
-HWC2::Error HwcDisplay::SetDisplayBrightness(float /* brightness */) {
- return HWC2::Error::Unsupported;
-}
-
#endif /* __ANDROID_API__ > 28 */
#if __ANDROID_API__ > 27
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index 7522c8d..7391785 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -38,6 +38,11 @@
class Backend;
class DrmHwc;
+class FrontendDisplayBase {
+ public:
+ virtual ~FrontendDisplayBase() = default;
+};
+
inline constexpr uint32_t kPrimaryDisplay = 0;
// NOLINTNEXTLINE
@@ -108,24 +113,24 @@
std::vector<ReleaseFence> &out_release_fences)
-> bool;
+ auto GetFrontendPrivateData() -> std::shared_ptr<FrontendDisplayBase> {
+ return frontend_private_data_;
+ }
+
+ auto SetFrontendPrivateData(std::shared_ptr<FrontendDisplayBase> data) {
+ frontend_private_data_ = std::move(data);
+ }
+
// HWC2 Hooks - these should not be used outside of the hwc2 device.
- HWC2::Error AcceptDisplayChanges();
HWC2::Error CreateLayer(hwc2_layer_t *layer);
HWC2::Error DestroyLayer(hwc2_layer_t layer);
HWC2::Error GetActiveConfig(hwc2_config_t *config) const;
- HWC2::Error GetChangedCompositionTypes(uint32_t *num_elements,
- hwc2_layer_t *layers, int32_t *types);
- HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height,
- int32_t format, int32_t dataspace);
HWC2::Error GetColorModes(uint32_t *num_modes, int32_t *modes);
HWC2::Error GetDisplayAttribute(hwc2_config_t config, int32_t attribute,
int32_t *value);
HWC2::Error LegacyGetDisplayConfigs(uint32_t *num_configs,
hwc2_config_t *configs);
HWC2::Error GetDisplayName(uint32_t *size, char *name);
- HWC2::Error GetDisplayRequests(int32_t *display_requests,
- uint32_t *num_elements, hwc2_layer_t *layers,
- int32_t *layer_requests);
HWC2::Error GetDisplayType(int32_t *type);
#if __ANDROID_API__ > 27
HWC2::Error GetRenderIntents(int32_t mode, uint32_t *outNumIntents,
@@ -138,8 +143,6 @@
uint8_t *outData);
HWC2::Error GetDisplayCapabilities(uint32_t *outNumCapabilities,
uint32_t *outCapabilities);
- HWC2::Error GetDisplayBrightnessSupport(bool *supported);
- HWC2::Error SetDisplayBrightness(float);
#endif
#if __ANDROID_API__ > 29
HWC2::Error GetDisplayConnectionType(uint32_t *outType);
@@ -148,33 +151,21 @@
hwc2_config_t config,
hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints,
hwc_vsync_period_change_timeline_t *outTimeline);
- HWC2::Error SetAutoLowLatencyMode(bool on);
- HWC2::Error GetSupportedContentTypes(
- uint32_t *outNumSupportedContentTypes,
- const uint32_t *outSupportedContentTypes);
HWC2::Error SetContentType(int32_t contentType);
#endif
HWC2::Error GetDisplayVsyncPeriod(uint32_t *outVsyncPeriod);
- HWC2::Error GetDozeSupport(int32_t *support);
HWC2::Error GetHdrCapabilities(uint32_t *num_types, int32_t *types,
float *max_luminance,
float *max_average_luminance,
float *min_luminance);
- HWC2::Error GetReleaseFences(uint32_t *num_elements, hwc2_layer_t *layers,
- int32_t *fences);
- HWC2::Error PresentDisplay(int32_t *out_present_fence);
HWC2::Error SetActiveConfig(hwc2_config_t config);
HWC2::Error ChosePreferredConfig();
- HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence,
- int32_t dataspace, hwc_region_t damage);
HWC2::Error SetColorMode(int32_t mode);
HWC2::Error SetColorTransform(const float *matrix, int32_t hint);
- HWC2::Error SetOutputBuffer(buffer_handle_t buffer, int32_t release_fence);
HWC2::Error SetPowerMode(int32_t mode);
HWC2::Error SetVsyncEnabled(int32_t enabled);
- HWC2::Error ValidateDisplay(uint32_t *num_types, uint32_t *num_requests);
HwcLayer *get_layer(hwc2_layer_t layer) {
auto it = layers_.find(layer);
if (it == layers_.end())
@@ -238,6 +229,10 @@
return flatcon_;
}
+ auto GetClientLayer() -> HwcLayer & {
+ return client_layer_;
+ }
+
auto &GetWritebackLayer() {
return writeback_layer_;
}
@@ -258,8 +253,6 @@
DrmHwc *const hwc_;
- SharedFd present_fence_;
-
int64_t staged_mode_change_time_{};
std::optional<uint32_t> staged_mode_config_id_{};
@@ -304,6 +297,8 @@
auto GetEdid() -> EdidWrapperUnique & {
return GetPipe().connector->Get()->GetParsedEdid();
}
+
+ std::shared_ptr<FrontendDisplayBase> frontend_private_data_;
};
} // namespace android
diff --git a/hwc2_device/HwcLayer.cpp b/hwc2_device/HwcLayer.cpp
index 1d1e118..d0ff216 100644
--- a/hwc2_device/HwcLayer.cpp
+++ b/hwc2_device/HwcLayer.cpp
@@ -25,10 +25,21 @@
namespace android {
void HwcLayer::SetLayerProperties(const LayerProperties& layer_properties) {
- if (layer_properties.buffer) {
- layer_data_.acquire_fence = layer_properties.buffer->acquire_fence;
- buffer_handle_ = layer_properties.buffer->buffer_handle;
- buffer_handle_updated_ = true;
+ if (layer_properties.slot_buffer) {
+ auto slot_id = layer_properties.slot_buffer->slot_id;
+ if (!layer_properties.slot_buffer->bi) {
+ slots_.erase(slot_id);
+ } else {
+ slots_[slot_id] = {
+ .bi = layer_properties.slot_buffer->bi.value(),
+ .fb = {},
+ };
+ }
+ }
+ if (layer_properties.active_slot) {
+ active_slot_id_ = layer_properties.active_slot->slot_id;
+ layer_data_.acquire_fence = layer_properties.active_slot->fence;
+ buffer_updated_ = true;
}
if (layer_properties.blend_mode) {
blend_mode_ = layer_properties.blend_mode.value();
@@ -46,8 +57,7 @@
layer_data_.pi.display_frame = layer_properties.display_frame.value();
}
if (layer_properties.alpha) {
- layer_data_.pi.alpha = std::lround(layer_properties.alpha.value() *
- UINT16_MAX);
+ layer_data_.pi.alpha = layer_properties.alpha.value();
}
if (layer_properties.source_crop) {
layer_data_.pi.source_crop = layer_properties.source_crop.value();
@@ -61,49 +71,39 @@
}
void HwcLayer::ImportFb() {
- if (!IsLayerUsableAsDevice() || !buffer_handle_updated_) {
+ if (!IsLayerUsableAsDevice() || !buffer_updated_ ||
+ !active_slot_id_.has_value()) {
return;
}
- buffer_handle_updated_ = false;
+ buffer_updated_ = false;
- layer_data_.fb = {};
-
- auto unique_id = BufferInfoGetter::GetInstance()->GetUniqueId(buffer_handle_);
- if (unique_id && SwChainGetBufferFromCache(*unique_id)) {
+ if (slots_[*active_slot_id_].fb) {
return;
}
- 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;
- }
+ auto& fb_importer = parent_->GetPipe().device->GetDrmFbImporter();
+ auto fb = fb_importer.GetOrCreateFbId(&slots_[*active_slot_id_].bi);
- 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_);
+ if (!fb) {
+ ALOGE("Unable to create framebuffer object for layer %p", this);
fb_import_failed_ = true;
return;
}
- if (unique_id) {
- SwChainAddCurrentBuffer(*unique_id);
- }
+ slots_[*active_slot_id_].fb = fb;
}
void HwcLayer::PopulateLayerData() {
ImportFb();
- if (!layer_data_.bi) {
- ALOGE("%s: Invalid state", __func__);
+ if (!active_slot_id_.has_value()) {
+ ALOGE("Internal error: populate layer data called without active slot");
return;
}
+ layer_data_.bi = slots_[*active_slot_id_].bi;
+ layer_data_.fb = slots_[*active_slot_id_].fb;
+
if (blend_mode_ != BufferBlendMode::kUndefined) {
layer_data_.bi->blend_mode = blend_mode_;
}
@@ -115,75 +115,9 @@
}
}
-/* SwapChain Cache */
-
-bool HwcLayer::SwChainGetBufferFromCache(BufferUniqueId unique_id) {
- if (swchain_lookup_table_.count(unique_id) == 0) {
- return false;
- }
-
- auto seq = swchain_lookup_table_[unique_id];
-
- if (swchain_cache_.count(seq) == 0) {
- return false;
- }
-
- auto& el = swchain_cache_[seq];
- if (!el.bi) {
- return false;
- }
-
- layer_data_.bi = el.bi;
- layer_data_.fb = el.fb;
-
- return true;
-}
-
-void HwcLayer::SwChainReassemble(BufferUniqueId unique_id) {
- if (swchain_lookup_table_.count(unique_id) != 0) {
- if (swchain_lookup_table_[unique_id] ==
- int(swchain_lookup_table_.size()) - 1) {
- /* Skip same buffer */
- return;
- }
- if (swchain_lookup_table_[unique_id] == 0) {
- swchain_reassembled_ = true;
- return;
- }
- /* Tracking error */
- SwChainClearCache();
- return;
- }
-
- swchain_lookup_table_[unique_id] = int(swchain_lookup_table_.size());
-}
-
-void HwcLayer::SwChainAddCurrentBuffer(BufferUniqueId unique_id) {
- if (!swchain_reassembled_) {
- SwChainReassemble(unique_id);
- }
-
- if (swchain_reassembled_) {
- if (swchain_lookup_table_.count(unique_id) == 0) {
- SwChainClearCache();
- return;
- }
-
- auto seq = swchain_lookup_table_[unique_id];
-
- if (swchain_cache_.count(seq) == 0) {
- swchain_cache_[seq] = {};
- }
-
- swchain_cache_[seq].bi = layer_data_.bi;
- swchain_cache_[seq].fb = layer_data_.fb;
- }
-}
-
-void HwcLayer::SwChainClearCache() {
- swchain_cache_.clear();
- swchain_lookup_table_.clear();
- swchain_reassembled_ = false;
+void HwcLayer::ClearSlots() {
+ slots_.clear();
+ active_slot_id_.reset();
}
} // namespace android
\ No newline at end of file
diff --git a/hwc2_device/HwcLayer.h b/hwc2_device/HwcLayer.h
index 93fd18f..c335d88 100644
--- a/hwc2_device/HwcLayer.h
+++ b/hwc2_device/HwcLayer.h
@@ -18,30 +18,43 @@
#include <aidl/android/hardware/graphics/common/Transform.h>
#include <hardware/hwcomposer2.h>
+#include <memory>
+#include "bufferinfo/BufferInfo.h"
#include "bufferinfo/BufferInfoGetter.h"
#include "compositor/LayerData.h"
+#include "utils/fd.h"
namespace android {
class HwcDisplay;
+class FrontendLayerBase {
+ public:
+ virtual ~FrontendLayerBase() = default;
+};
+
class HwcLayer {
public:
struct Buffer {
- buffer_handle_t buffer_handle;
- SharedFd acquire_fence;
+ int32_t slot_id;
+ std::optional<BufferInfo> bi;
+ };
+ struct Slot {
+ int32_t slot_id;
+ SharedFd fence;
};
// A set of properties to be validated.
struct LayerProperties {
- std::optional<Buffer> buffer;
+ std::optional<Buffer> slot_buffer;
+ std::optional<Slot> active_slot;
std::optional<BufferBlendMode> blend_mode;
std::optional<BufferColorSpace> color_space;
std::optional<BufferSampleRange> sample_range;
std::optional<HWC2::Composition> composition_type;
- std::optional<hwc_rect_t> display_frame;
+ std::optional<DstRectInfo> display_frame;
std::optional<float> alpha;
- std::optional<hwc_frect_t> source_crop;
+ std::optional<SrcRectInfo> source_crop;
std::optional<LayerTransform> transform;
std::optional<uint32_t> z_order;
};
@@ -82,6 +95,14 @@
void SetLayerProperties(const LayerProperties &layer_properties);
+ auto GetFrontendPrivateData() -> std::shared_ptr<FrontendLayerBase> {
+ return frontend_private_data_;
+ }
+
+ auto SetFrontendPrivateData(std::shared_ptr<FrontendLayerBase> data) {
+ frontend_private_data_ = std::move(data);
+ }
+
private:
// sf_type_ stores the initial type given to us by surfaceflinger,
// validated_type_ stores the type after running ValidateDisplay
@@ -101,43 +122,32 @@
BufferColorSpace color_space_{};
BufferSampleRange sample_range_{};
BufferBlendMode blend_mode_{};
- buffer_handle_t buffer_handle_{};
- bool buffer_handle_updated_{};
+ bool buffer_updated_{};
bool prior_buffer_scanout_flag_{};
HwcDisplay *const parent_;
- /* Layer state */
- public:
- void PopulateLayerData();
+ std::shared_ptr<FrontendLayerBase> frontend_private_data_;
- bool IsLayerUsableAsDevice() const {
- return !bi_get_failed_ && !fb_import_failed_ && buffer_handle_ != nullptr;
- }
-
- private:
- void ImportFb();
- bool bi_get_failed_{};
- bool fb_import_failed_{};
-
- /* SwapChain Cache */
- public:
- void SwChainClearCache();
-
- private:
- struct SwapChainElement {
- std::optional<BufferInfo> bi;
+ std::optional<int32_t> active_slot_id_;
+ struct BufferSlot {
+ BufferInfo bi;
std::shared_ptr<DrmFbIdHandle> fb;
};
+ std::map<int32_t /*slot*/, BufferSlot> slots_;
- bool SwChainGetBufferFromCache(BufferUniqueId unique_id);
- void SwChainReassemble(BufferUniqueId unique_id);
- void SwChainAddCurrentBuffer(BufferUniqueId unique_id);
+ void ImportFb();
+ bool fb_import_failed_{};
- std::map<int /*seq_no*/, SwapChainElement> swchain_cache_;
- std::map<BufferUniqueId, int /*seq_no*/> swchain_lookup_table_;
- bool swchain_reassembled_{};
+ public:
+ void PopulateLayerData();
+ void ClearSlots();
+
+ bool IsLayerUsableAsDevice() const {
+ return !fb_import_failed_ && active_slot_id_.has_value() &&
+ slots_.count(*active_slot_id_) > 0;
+ }
};
} // namespace android
diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp
index 842dd9d..72d0aa9 100644
--- a/hwc2_device/hwc2_device.cpp
+++ b/hwc2_device/hwc2_device.cpp
@@ -19,10 +19,16 @@
#define LOG_TAG "drmhwc"
+#include <cassert>
#include <cinttypes>
+#include <memory>
+#include <optional>
+
+#include <cutils/native_handle.h>
#include "DrmHwcTwo.h"
#include "backend/Backend.h"
+#include "hwc2_device/HwcLayer.h"
#include "utils/log.h"
namespace android {
@@ -43,6 +49,126 @@
return str.substr(p1, p2 - p1);
}
+class Hwc2DeviceDisplay : public FrontendDisplayBase {
+ public:
+ std::vector<HwcDisplay::ReleaseFence> release_fences;
+ std::vector<HwcDisplay::ChangedLayer> changed_layers;
+};
+
+static auto GetHwc2DeviceDisplay(HwcDisplay &display)
+ -> std::shared_ptr<Hwc2DeviceDisplay> {
+ auto frontend_private_data = display.GetFrontendPrivateData();
+ if (!frontend_private_data) {
+ frontend_private_data = std::make_shared<Hwc2DeviceDisplay>();
+ display.SetFrontendPrivateData(frontend_private_data);
+ }
+ return std::static_pointer_cast<Hwc2DeviceDisplay>(frontend_private_data);
+}
+
+class Hwc2DeviceLayer : public FrontendLayerBase {
+ public:
+ auto HandleNextBuffer(buffer_handle_t buffer_handle, int32_t fence_fd)
+ -> std::pair<std::optional<HwcLayer::LayerProperties>,
+ bool /* not a swapchain */> {
+ auto slot = GetSlotNumber(buffer_handle);
+
+ if (invalid_) {
+ return std::make_pair(std::nullopt, true);
+ }
+
+ bool buffer_provided = false;
+ bool not_a_swapchain = true;
+ int32_t slot_id = 0;
+
+ if (slot.has_value()) {
+ buffer_provided = swchain_slots_[slot.value()];
+ slot_id = slot.value();
+ not_a_swapchain = true;
+ }
+
+ HwcLayer::LayerProperties lp;
+ if (!buffer_provided) {
+ auto bo_info = BufferInfoGetter::GetInstance()->GetBoInfo(buffer_handle);
+ if (!bo_info) {
+ invalid_ = true;
+ return std::make_pair(std::nullopt, true);
+ }
+
+ lp.slot_buffer = {
+ .slot_id = slot_id,
+ .bi = bo_info,
+ };
+ }
+ lp.active_slot = {
+ .slot_id = slot_id,
+ .fence = MakeSharedFd(fence_fd),
+ };
+
+ return std::make_pair(lp, not_a_swapchain);
+ }
+
+ void SwChainClearCache() {
+ swchain_lookup_table_.clear();
+ swchain_slots_.clear();
+ swchain_reassembled_ = false;
+ }
+
+ private:
+ auto GetSlotNumber(buffer_handle_t buffer_handle) -> std::optional<int32_t> {
+ auto unique_id = BufferInfoGetter::GetInstance()->GetUniqueId(
+ buffer_handle);
+ if (!unique_id) {
+ ALOGE("Failed to get unique id for buffer handle %p", buffer_handle);
+ return std::nullopt;
+ }
+
+ if (swchain_lookup_table_.count(*unique_id) == 0) {
+ SwChainReassemble(*unique_id);
+ return std::nullopt;
+ }
+
+ if (!swchain_reassembled_) {
+ return std::nullopt;
+ }
+
+ return swchain_lookup_table_[*unique_id];
+ }
+
+ void SwChainReassemble(BufferUniqueId unique_id) {
+ if (swchain_lookup_table_.count(unique_id) != 0) {
+ if (swchain_lookup_table_[unique_id] ==
+ int(swchain_lookup_table_.size()) - 1) {
+ /* Skip same buffer */
+ return;
+ }
+ if (swchain_lookup_table_[unique_id] == 0) {
+ swchain_reassembled_ = true;
+ return;
+ }
+ /* Tracking error */
+ SwChainClearCache();
+ return;
+ }
+
+ swchain_lookup_table_[unique_id] = int(swchain_lookup_table_.size());
+ }
+
+ bool invalid_{}; /* Layer is invalid and should be skipped */
+ std::map<BufferUniqueId, int /*slot*/> swchain_lookup_table_;
+ std::map<int /*slot*/, bool /*buffer_provided*/> swchain_slots_;
+ bool swchain_reassembled_{};
+};
+
+static auto GetHwc2DeviceLayer(HwcLayer &layer)
+ -> std::shared_ptr<Hwc2DeviceLayer> {
+ auto frontend_private_data = layer.GetFrontendPrivateData();
+ if (!frontend_private_data) {
+ frontend_private_data = std::make_shared<Hwc2DeviceLayer>();
+ layer.SetFrontendPrivateData(frontend_private_data);
+ }
+ return std::static_pointer_cast<Hwc2DeviceLayer>(frontend_private_data);
+}
+
struct Drmhwc2Device : hwc2_device {
DrmHwcTwo drmhwctwo;
};
@@ -140,6 +266,257 @@
}
}
+/* Display functions */
+static int32_t GetDisplayRequests(hwc2_device_t * /*device*/,
+ hwc2_display_t /*display*/,
+ int32_t * /* out_display_requests */,
+ uint32_t *out_num_elements,
+ hwc2_layer_t * /*out_layers*/,
+ int32_t * /*out_layer_requests*/) {
+ ALOGV("GetDisplayRequests");
+
+ *out_num_elements = 0;
+ return 0;
+}
+
+static int32_t GetDozeSupport(hwc2_device_t * /*device*/,
+ hwc2_display_t /*display*/,
+ int32_t *out_support) {
+ ALOGV("GetDozeSupport");
+ *out_support = 0; // Doze support is not available
+ return 0;
+}
+
+static int32_t GetClientTargetSupport(hwc2_device_t * /*device*/,
+ hwc2_display_t /*display*/,
+ uint32_t /*width*/, uint32_t /*height*/,
+ int32_t /*format*/, int32_t dataspace) {
+ ALOGV("GetClientTargetSupport");
+
+ if (dataspace != HAL_DATASPACE_UNKNOWN)
+ return static_cast<int32_t>(HWC2::Error::Unsupported);
+
+ return 0;
+}
+
+static int32_t SetClientTarget(hwc2_device_t *device, hwc2_display_t display,
+ buffer_handle_t target, int32_t acquire_fence,
+ int32_t dataspace, hwc_region_t /*damage*/) {
+ ALOGV("SetClientTarget");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+
+ auto &client_layer = idisplay->GetClientLayer();
+ auto h2l = GetHwc2DeviceLayer(client_layer);
+ if (!h2l) {
+ client_layer.SetFrontendPrivateData(std::make_shared<Hwc2DeviceLayer>());
+ }
+
+ if (target == nullptr) {
+ client_layer.ClearSlots();
+ h2l->SwChainClearCache();
+
+ return 0;
+ }
+
+ auto [lp, not_a_swapchain] = h2l->HandleNextBuffer(target, acquire_fence);
+ if (!lp) {
+ ALOGE("Failed to process client target");
+ return static_cast<int32_t>(HWC2::Error::BadLayer);
+ }
+
+ if (not_a_swapchain) {
+ client_layer.ClearSlots();
+ }
+
+ lp->color_space = Hwc2ToColorSpace(dataspace);
+ lp->sample_range = Hwc2ToSampleRange(dataspace);
+
+ idisplay->GetClientLayer().SetLayerProperties(lp.value());
+
+ return 0;
+}
+
+static int32_t SetOutputBuffer(hwc2_device_t *device, hwc2_display_t display,
+ buffer_handle_t buffer, int32_t release_fence) {
+ ALOGV("SetOutputBuffer");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+
+ auto &writeback_layer = idisplay->GetWritebackLayer();
+ if (!writeback_layer) {
+ ALOGE("Writeback layer is not available");
+ return static_cast<int32_t>(HWC2::Error::BadLayer);
+ }
+
+ auto h2l = GetHwc2DeviceLayer(*writeback_layer);
+ if (!h2l) {
+ writeback_layer->SetFrontendPrivateData(
+ std::make_shared<Hwc2DeviceLayer>());
+ }
+
+ auto [lp, not_a_swapchain] = h2l->HandleNextBuffer(buffer, release_fence);
+ if (!lp) {
+ ALOGE("Failed to process output buffer");
+ return static_cast<int32_t>(HWC2::Error::BadLayer);
+ }
+
+ if (not_a_swapchain) {
+ writeback_layer->ClearSlots();
+ }
+
+ writeback_layer->SetLayerProperties(lp.value());
+
+ return 0;
+}
+
+static int32_t AcceptDisplayChanges(hwc2_device_t *device,
+ hwc2_display_t display) {
+ ALOGV("AcceptDisplayChanges");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+
+ idisplay->AcceptValidatedComposition();
+
+ return 0;
+}
+
+static int32_t GetReleaseFences(hwc2_device_t *device, hwc2_display_t display,
+ uint32_t *out_num_elements,
+ hwc2_layer_t *out_layers, int32_t *out_fences) {
+ ALOGV("GetReleaseFences");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+
+ auto hwc2display = GetHwc2DeviceDisplay(*idisplay);
+
+ if (*out_num_elements < hwc2display->release_fences.size()) {
+ ALOGW("Overflow num_elements %d/%zu", *out_num_elements,
+ hwc2display->release_fences.size());
+ return static_cast<int32_t>(HWC2::Error::NoResources);
+ }
+
+ for (size_t i = 0; i < hwc2display->release_fences.size(); ++i) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic):
+ out_layers[i] = hwc2display->release_fences[i].first;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic):
+ out_fences[i] = DupFd(hwc2display->release_fences[i].second);
+ }
+
+ *out_num_elements = hwc2display->release_fences.size();
+ hwc2display->release_fences.clear();
+
+ return static_cast<int32_t>(HWC2::Error::None);
+}
+
+static int32_t ValidateDisplay(hwc2_device_t *device, hwc2_display_t display,
+ uint32_t *out_num_types,
+ uint32_t *out_num_requests) {
+ ALOGV("ValidateDisplay");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+
+ auto hwc2display = GetHwc2DeviceDisplay(*idisplay);
+
+ hwc2display->changed_layers = idisplay->ValidateStagedComposition();
+
+ *out_num_types = hwc2display->changed_layers.size();
+ *out_num_requests = 0;
+
+ return 0;
+}
+
+static int32_t GetChangedCompositionTypes(hwc2_device_t *device,
+ hwc2_display_t display,
+ uint32_t *out_num_elements,
+ hwc2_layer_t *out_layers,
+ int32_t *out_types) {
+ ALOGV("GetChangedCompositionTypes");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+
+ auto hwc2display = GetHwc2DeviceDisplay(*idisplay);
+
+ if (*out_num_elements < hwc2display->changed_layers.size()) {
+ ALOGW("Overflow num_elements %d/%zu", *out_num_elements,
+ hwc2display->changed_layers.size());
+ return static_cast<int32_t>(HWC2::Error::NoResources);
+ }
+
+ for (size_t i = 0; i < hwc2display->changed_layers.size(); ++i) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic):
+ out_layers[i] = hwc2display->changed_layers[i].first;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic):
+ out_types[i] = static_cast<int32_t>(hwc2display->changed_layers[i].second);
+ }
+
+ *out_num_elements = hwc2display->changed_layers.size();
+ hwc2display->changed_layers.clear();
+
+ return static_cast<int32_t>(HWC2::Error::None);
+}
+
+static int32_t PresentDisplay(hwc2_device_t *device, hwc2_display_t display,
+ int32_t *out_release_fence) {
+ ALOGV("PresentDisplay");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+
+ auto hwc2display = GetHwc2DeviceDisplay(*idisplay);
+
+ SharedFd out_fence;
+
+ hwc2display->release_fences.clear();
+
+ if (!idisplay->PresentStagedComposition(out_fence,
+ hwc2display->release_fences)) {
+ ALOGE("Failed to present display");
+ return static_cast<int32_t>(HWC2::Error::BadDisplay);
+ }
+
+ *out_release_fence = DupFd(out_fence);
+
+ return 0;
+}
+
+#if __ANDROID_API__ >= 28
+
+static int32_t GetDisplayBrightnessSupport(hwc2_device_t * /*device*/,
+ hwc2_display_t /*display*/,
+ bool *out_support) {
+ ALOGV("GetDisplayBrightnessSupport");
+ *out_support = false; // Brightness support is not available
+ return static_cast<int32_t>(HWC2::Error::None);
+}
+
+static int32_t SetDisplayBrightness(hwc2_device_t * /*device*/,
+ hwc2_display_t /*display*/,
+ float /*brightness*/) {
+ ALOGV("SetDisplayBrightness");
+ return static_cast<int32_t>(HWC2::Error::Unsupported);
+}
+
+#endif
+
+#if __ANDROID_API__ >= 29
+static int32_t SetAutoLowLatencyMode(hwc2_device_t * /*device*/,
+ hwc2_display_t /*display*/, bool /*on*/) {
+ ALOGV("SetAutoLowLatencyMode");
+ return static_cast<int32_t>(HWC2::Error::Unsupported);
+}
+
+static int32_t GetSupportedContentTypes(
+ hwc2_device_t * /*device*/, hwc2_display_t /*display*/,
+ uint32_t *out_num_supported_content_types,
+ uint32_t * /*out_supported_content_types*/) {
+ ALOGV("GetSupportedContentTypes");
+ *out_num_supported_content_types = 0;
+ return static_cast<int32_t>(HWC2::Error::None);
+}
+#endif
+
+/* Layer functions */
+
static int32_t SetLayerBlendMode(hwc2_device_t *device, hwc2_display_t display,
hwc2_layer_t layer,
int32_t /*hwc2_blend_mode_t*/ mode) {
@@ -181,10 +558,19 @@
GET_DISPLAY(display);
GET_LAYER(layer);
- HwcLayer::LayerProperties layer_properties;
- layer_properties.buffer = {.buffer_handle = buffer,
- .acquire_fence = MakeSharedFd(acquire_fence)};
- ilayer->SetLayerProperties(layer_properties);
+ auto h2l = GetHwc2DeviceLayer(*ilayer);
+
+ auto [lp, not_a_swapchain] = h2l->HandleNextBuffer(buffer, acquire_fence);
+ if (!lp) {
+ ALOGV("Failed to process layer buffer");
+ return static_cast<int32_t>(HWC2::Error::BadLayer);
+ }
+
+ if (not_a_swapchain) {
+ ilayer->ClearSlots();
+ }
+
+ ilayer->SetLayerProperties(lp.value());
return 0;
}
@@ -244,7 +630,11 @@
GET_LAYER(layer);
HwcLayer::LayerProperties layer_properties;
- layer_properties.display_frame = frame;
+ layer_properties.display_frame = {
+ .i_rect = DstRectInfo::IRect{.left = frame.left,
+ .top = frame.top,
+ .right = frame.right,
+ .bottom = frame.bottom}};
ilayer->SetLayerProperties(layer_properties);
return 0;
@@ -280,7 +670,11 @@
GET_LAYER(layer);
HwcLayer::LayerProperties layer_properties;
- layer_properties.source_crop = crop;
+ layer_properties.source_crop = {
+ .f_rect = SrcRectInfo::FRect{.left = crop.left,
+ .top = crop.top,
+ .right = crop.right,
+ .bottom = crop.bottom}};
ilayer->SetLayerProperties(layer_properties);
return 0;
@@ -367,9 +761,7 @@
// Display functions
case HWC2::FunctionDescriptor::AcceptDisplayChanges:
- return ToHook<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
- DisplayHook<decltype(&HwcDisplay::AcceptDisplayChanges),
- &HwcDisplay::AcceptDisplayChanges>);
+ return (hwc2_function_pointer_t)AcceptDisplayChanges;
case HWC2::FunctionDescriptor::CreateLayer:
return ToHook<HWC2_PFN_CREATE_LAYER>(
DisplayHook<decltype(&HwcDisplay::CreateLayer),
@@ -383,15 +775,9 @@
DisplayHook<decltype(&HwcDisplay::GetActiveConfig),
&HwcDisplay::GetActiveConfig, hwc2_config_t *>);
case HWC2::FunctionDescriptor::GetChangedCompositionTypes:
- return ToHook<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
- DisplayHook<decltype(&HwcDisplay::GetChangedCompositionTypes),
- &HwcDisplay::GetChangedCompositionTypes, uint32_t *,
- hwc2_layer_t *, int32_t *>);
+ return (hwc2_function_pointer_t)GetChangedCompositionTypes;
case HWC2::FunctionDescriptor::GetClientTargetSupport:
- return ToHook<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
- DisplayHook<decltype(&HwcDisplay::GetClientTargetSupport),
- &HwcDisplay::GetClientTargetSupport, uint32_t, uint32_t,
- int32_t, int32_t>);
+ return (hwc2_function_pointer_t)GetClientTargetSupport;
case HWC2::FunctionDescriptor::GetColorModes:
return ToHook<HWC2_PFN_GET_COLOR_MODES>(
DisplayHook<decltype(&HwcDisplay::GetColorModes),
@@ -411,41 +797,28 @@
DisplayHook<decltype(&HwcDisplay::GetDisplayName),
&HwcDisplay::GetDisplayName, uint32_t *, char *>);
case HWC2::FunctionDescriptor::GetDisplayRequests:
- return ToHook<HWC2_PFN_GET_DISPLAY_REQUESTS>(
- DisplayHook<decltype(&HwcDisplay::GetDisplayRequests),
- &HwcDisplay::GetDisplayRequests, int32_t *, uint32_t *,
- hwc2_layer_t *, int32_t *>);
+ return (hwc2_function_pointer_t)GetDisplayRequests;
case HWC2::FunctionDescriptor::GetDisplayType:
return ToHook<HWC2_PFN_GET_DISPLAY_TYPE>(
DisplayHook<decltype(&HwcDisplay::GetDisplayType),
&HwcDisplay::GetDisplayType, int32_t *>);
case HWC2::FunctionDescriptor::GetDozeSupport:
- return ToHook<HWC2_PFN_GET_DOZE_SUPPORT>(
- DisplayHook<decltype(&HwcDisplay::GetDozeSupport),
- &HwcDisplay::GetDozeSupport, int32_t *>);
+ return (hwc2_function_pointer_t)GetDozeSupport;
case HWC2::FunctionDescriptor::GetHdrCapabilities:
return ToHook<HWC2_PFN_GET_HDR_CAPABILITIES>(
DisplayHook<decltype(&HwcDisplay::GetHdrCapabilities),
&HwcDisplay::GetHdrCapabilities, uint32_t *, int32_t *,
float *, float *, float *>);
case HWC2::FunctionDescriptor::GetReleaseFences:
- return ToHook<HWC2_PFN_GET_RELEASE_FENCES>(
- DisplayHook<decltype(&HwcDisplay::GetReleaseFences),
- &HwcDisplay::GetReleaseFences, uint32_t *, hwc2_layer_t *,
- int32_t *>);
+ return (hwc2_function_pointer_t)GetReleaseFences;
case HWC2::FunctionDescriptor::PresentDisplay:
- return ToHook<HWC2_PFN_PRESENT_DISPLAY>(
- DisplayHook<decltype(&HwcDisplay::PresentDisplay),
- &HwcDisplay::PresentDisplay, int32_t *>);
+ return (hwc2_function_pointer_t)PresentDisplay;
case HWC2::FunctionDescriptor::SetActiveConfig:
return ToHook<HWC2_PFN_SET_ACTIVE_CONFIG>(
DisplayHook<decltype(&HwcDisplay::SetActiveConfig),
&HwcDisplay::SetActiveConfig, hwc2_config_t>);
case HWC2::FunctionDescriptor::SetClientTarget:
- return ToHook<HWC2_PFN_SET_CLIENT_TARGET>(
- DisplayHook<decltype(&HwcDisplay::SetClientTarget),
- &HwcDisplay::SetClientTarget, buffer_handle_t, int32_t,
- int32_t, hwc_region_t>);
+ return (hwc2_function_pointer_t)SetClientTarget;
case HWC2::FunctionDescriptor::SetColorMode:
return ToHook<HWC2_PFN_SET_COLOR_MODE>(
DisplayHook<decltype(&HwcDisplay::SetColorMode),
@@ -455,9 +828,7 @@
DisplayHook<decltype(&HwcDisplay::SetColorTransform),
&HwcDisplay::SetColorTransform, const float *, int32_t>);
case HWC2::FunctionDescriptor::SetOutputBuffer:
- return ToHook<HWC2_PFN_SET_OUTPUT_BUFFER>(
- DisplayHook<decltype(&HwcDisplay::SetOutputBuffer),
- &HwcDisplay::SetOutputBuffer, buffer_handle_t, int32_t>);
+ return (hwc2_function_pointer_t)SetOutputBuffer;
case HWC2::FunctionDescriptor::SetPowerMode:
return ToHook<HWC2_PFN_SET_POWER_MODE>(
DisplayHook<decltype(&HwcDisplay::SetPowerMode),
@@ -467,9 +838,7 @@
DisplayHook<decltype(&HwcDisplay::SetVsyncEnabled),
&HwcDisplay::SetVsyncEnabled, int32_t>);
case HWC2::FunctionDescriptor::ValidateDisplay:
- return ToHook<HWC2_PFN_VALIDATE_DISPLAY>(
- DisplayHook<decltype(&HwcDisplay::ValidateDisplay),
- &HwcDisplay::ValidateDisplay, uint32_t *, uint32_t *>);
+ return (hwc2_function_pointer_t)ValidateDisplay;
#if __ANDROID_API__ > 27
case HWC2::FunctionDescriptor::GetRenderIntents:
return ToHook<HWC2_PFN_GET_RENDER_INTENTS>(
@@ -493,13 +862,9 @@
&HwcDisplay::GetDisplayCapabilities, uint32_t *,
uint32_t *>);
case HWC2::FunctionDescriptor::GetDisplayBrightnessSupport:
- return ToHook<HWC2_PFN_GET_DISPLAY_BRIGHTNESS_SUPPORT>(
- DisplayHook<decltype(&HwcDisplay::GetDisplayBrightnessSupport),
- &HwcDisplay::GetDisplayBrightnessSupport, bool *>);
+ return (hwc2_function_pointer_t)GetDisplayBrightnessSupport;
case HWC2::FunctionDescriptor::SetDisplayBrightness:
- return ToHook<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>(
- DisplayHook<decltype(&HwcDisplay::SetDisplayBrightness),
- &HwcDisplay::SetDisplayBrightness, float>);
+ return (hwc2_function_pointer_t)SetDisplayBrightness;
#endif /* __ANDROID_API__ > 28 */
#if __ANDROID_API__ > 29
case HWC2::FunctionDescriptor::GetDisplayConnectionType:
@@ -518,14 +883,9 @@
hwc2_config_t, hwc_vsync_period_change_constraints_t *,
hwc_vsync_period_change_timeline_t *>);
case HWC2::FunctionDescriptor::SetAutoLowLatencyMode:
- return ToHook<HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE>(
- DisplayHook<decltype(&HwcDisplay::SetAutoLowLatencyMode),
- &HwcDisplay::SetAutoLowLatencyMode, bool>);
+ return (hwc2_function_pointer_t)SetAutoLowLatencyMode;
case HWC2::FunctionDescriptor::GetSupportedContentTypes:
- return ToHook<HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES>(
- DisplayHook<decltype(&HwcDisplay::GetSupportedContentTypes),
- &HwcDisplay::GetSupportedContentTypes, uint32_t *,
- uint32_t *>);
+ return (hwc2_function_pointer_t)GetSupportedContentTypes;
case HWC2::FunctionDescriptor::SetContentType:
return ToHook<HWC2_PFN_SET_CONTENT_TYPE>(
DisplayHook<decltype(&HwcDisplay::SetContentType),
diff --git a/hwc3/Composer.cpp b/hwc3/Composer.cpp
index 124380d..28d096c 100644
--- a/hwc3/Composer.cpp
+++ b/hwc3/Composer.cpp
@@ -38,11 +38,13 @@
}
auto client = ndk::SharedRefBase::make<ComposerClient>();
- if (!client || !client->Init()) {
+ if (!client) {
*out_client = nullptr;
return ToBinderStatus(hwc3::Error::kNoResources);
}
+ client->Init();
+
*out_client = client;
client_ = client;
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp
index ff3d42e..50d8ce6 100644
--- a/hwc3/ComposerClient.cpp
+++ b/hwc3/ComposerClient.cpp
@@ -40,6 +40,7 @@
#include <cutils/native_handle.h>
#include <hardware/hwcomposer2.h>
#include <hardware/hwcomposer_defs.h>
+#include <ui/GraphicBufferMapper.h>
#include "bufferinfo/BufferInfo.h"
#include "compositor/DisplayInfo.h"
@@ -49,11 +50,13 @@
#include "hwc3/DrmHwcThree.h"
#include "hwc3/Utils.h"
+using ::android::DstRectInfo;
using ::android::HwcDisplay;
using ::android::HwcDisplayConfig;
using ::android::HwcDisplayConfigs;
using ::android::HwcLayer;
using ::android::LayerTransform;
+using ::android::SrcRectInfo;
#include "utils/log.h"
@@ -290,18 +293,29 @@
return aidl_configuration;
}
-std::optional<hwc_rect> AidlToRect(const std::optional<common::Rect>& rect) {
+std::optional<DstRectInfo> AidlToRect(const std::optional<common::Rect>& rect) {
if (!rect) {
return std::nullopt;
}
- return hwc_rect{rect->left, rect->top, rect->right, rect->bottom};
+ DstRectInfo dst_rec;
+ dst_rec.i_rect = {.left = rect->left,
+ .top = rect->top,
+ .right = rect->right,
+ .bottom = rect->bottom};
+ return dst_rec;
}
-std::optional<hwc_frect> AidlToFRect(const std::optional<common::FRect>& rect) {
+std::optional<SrcRectInfo> AidlToFRect(
+ const std::optional<common::FRect>& rect) {
if (!rect) {
return std::nullopt;
}
- return hwc_frect{rect->left, rect->top, rect->right, rect->bottom};
+ SrcRectInfo src_rect;
+ src_rect.f_rect = {.left = rect->left,
+ .top = rect->top,
+ .right = rect->right,
+ .bottom = rect->bottom};
+ return src_rect;
}
std::optional<float> AidlToAlpha(const std::optional<PlaneAlpha>& alpha) {
@@ -338,17 +352,121 @@
} // namespace
+class Hwc3BufferHandle : public PrimeFdsSharedBase {
+ public:
+ static auto Create(buffer_handle_t handle)
+ -> std::shared_ptr<Hwc3BufferHandle> {
+ auto hwc3 = std::shared_ptr<Hwc3BufferHandle>(new Hwc3BufferHandle());
+
+ ::android::GraphicBufferMapper::get()
+ .importBufferNoValidate(handle, &hwc3->imported_handle_);
+
+ return hwc3;
+ }
+
+ auto GetHandle() const -> buffer_handle_t {
+ return imported_handle_;
+ }
+
+ ~Hwc3BufferHandle() override {
+ ::android::GraphicBufferMapper::get().freeBuffer(imported_handle_);
+ }
+
+ private:
+ Hwc3BufferHandle() = default;
+ buffer_handle_t imported_handle_{};
+};
+
+class Hwc3Layer : public ::android::FrontendLayerBase {
+ public:
+ auto HandleNextBuffer(std::optional<buffer_handle_t> raw_handle,
+ ::android::SharedFd fence_fd, int32_t slot_id)
+ -> std::optional<HwcLayer::LayerProperties> {
+ HwcLayer::LayerProperties lp;
+ if (!raw_handle && slots_.count(slot_id) != 0) {
+ lp.active_slot = {
+ .slot_id = slot_id,
+ .fence = std::move(fence_fd),
+ };
+
+ return lp;
+ }
+
+ if (!raw_handle) {
+ ALOGE("Buffer handle is nullopt but slot was not cached.");
+ return std::nullopt;
+ }
+
+ auto hwc3 = Hwc3BufferHandle::Create(*raw_handle);
+ if (!hwc3) {
+ return std::nullopt;
+ }
+
+ auto bi = ::android::BufferInfoGetter::GetInstance()->GetBoInfo(
+ hwc3->GetHandle());
+ if (!bi) {
+ return std::nullopt;
+ }
+
+ bi->fds_shared = hwc3;
+
+ lp.slot_buffer = {
+ .slot_id = slot_id,
+ .bi = bi,
+ };
+
+ lp.active_slot = {
+ .slot_id = slot_id,
+ .fence = std::move(fence_fd),
+ };
+
+ slots_[slot_id] = hwc3;
+
+ return lp;
+ }
+
+ [[maybe_unused]]
+ auto HandleClearSlot(int32_t slot_id)
+ -> std::optional<HwcLayer::LayerProperties> {
+ if (slots_.count(slot_id) == 0) {
+ return std::nullopt;
+ }
+
+ slots_.erase(slot_id);
+
+ auto lp = HwcLayer::LayerProperties{};
+ lp.slot_buffer = {
+ .slot_id = slot_id,
+ .bi = std::nullopt,
+ };
+
+ return lp;
+ }
+
+ void ClearSlots() {
+ slots_.clear();
+ }
+
+ private:
+ std::map<int32_t /*slot*/, std::shared_ptr<Hwc3BufferHandle>> slots_;
+};
+
+static auto GetHwc3Layer(HwcLayer& layer) -> std::shared_ptr<Hwc3Layer> {
+ auto frontend_private_data = layer.GetFrontendPrivateData();
+ if (!frontend_private_data) {
+ frontend_private_data = std::make_shared<Hwc3Layer>();
+ layer.SetFrontendPrivateData(frontend_private_data);
+ }
+ return std::static_pointer_cast<Hwc3Layer>(frontend_private_data);
+}
+
ComposerClient::ComposerClient() {
DEBUG_FUNC();
}
-bool ComposerClient::Init() {
+void ComposerClient::Init() {
DEBUG_FUNC();
- composer_resources_ = ComposerResources::Create();
- if (composer_resources_) {
- hwc_ = std::make_unique<DrmHwcThree>(composer_resources_.get());
- }
- return composer_resources_ != nullptr;
+ hwc_ = std::make_unique<DrmHwcThree>();
}
ComposerClient::~ComposerClient() {
@@ -362,7 +480,7 @@
}
ndk::ScopedAStatus ComposerClient::createLayer(int64_t display_id,
- int32_t buffer_slot_count,
+ int32_t /*buffer_slot_count*/,
int64_t* layer_id) {
DEBUG_FUNC();
const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
@@ -378,21 +496,13 @@
return ToBinderStatus(err);
}
- const int64_t created_layer_id = Hwc2LayerToHwc3(hwc2_layer_id);
- err = composer_resources_->AddLayer(display_id, created_layer_id,
- buffer_slot_count);
- if (err != hwc3::Error::kNone) {
- destroyLayer(display_id, created_layer_id);
- return ToBinderStatus(err);
- }
-
- *layer_id = created_layer_id;
+ *layer_id = Hwc2LayerToHwc3(hwc2_layer_id);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ComposerClient::createVirtualDisplay(
int32_t width, int32_t height, AidlPixelFormat format_hint,
- int32_t output_buffer_slot_count, VirtualDisplay* out_display) {
+ int32_t /*output_buffer_slot_count*/, VirtualDisplay* out_display) {
DEBUG_FUNC();
const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
@@ -406,15 +516,7 @@
return ToBinderStatus(err);
}
- const int64_t created_display_id = Hwc2DisplayToHwc3(hwc2_display_id);
- err = composer_resources_->AddVirtualDisplay(hwc2_display_id,
- output_buffer_slot_count);
- if (err != hwc3::Error::kNone) {
- hwc_->DestroyVirtualDisplay(hwc2_display_id);
- return ToBinderStatus(err);
- }
-
- out_display->display = created_display_id;
+ out_display->display = Hwc2DisplayToHwc3(hwc2_display_id);
out_display->format = format_hint;
return ndk::ScopedAStatus::ok();
}
@@ -433,7 +535,6 @@
return ToBinderStatus(err);
}
- err = composer_resources_->RemoveLayer(display_id, layer_id);
return ToBinderStatus(err);
}
@@ -476,16 +577,44 @@
return;
}
+#if __ANDROID_API__ >= 34
+ /* https://source.android.com/docs/core/graphics/reduce-consumption */
+ if (command.bufferSlotsToClear) {
+ auto hwc3_layer = GetHwc3Layer(*layer);
+ for (const auto& slot : *command.bufferSlotsToClear) {
+ auto lp = hwc3_layer->HandleClearSlot(slot);
+ if (!lp) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadLayer);
+ return;
+ }
+
+ layer->SetLayerProperties(lp.value());
+ }
+ }
+#endif
+
HwcLayer::LayerProperties properties;
if (command.buffer) {
- HwcLayer::Buffer buffer;
- auto err = ImportLayerBuffer(display_id, command.layer, *command.buffer,
- &buffer);
- if (err != hwc3::Error::kNone) {
- cmd_result_writer_->AddError(err);
+ auto hwc3_layer = GetHwc3Layer(*layer);
+ std::optional<buffer_handle_t> buffer_handle = std::nullopt;
+ if (command.buffer->handle) {
+ buffer_handle = ::android::makeFromAidl(*command.buffer->handle);
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
+ auto fence = const_cast<::ndk::ScopedFileDescriptor&>(command.buffer->fence)
+ .release();
+
+ auto lp = hwc3_layer->HandleNextBuffer(buffer_handle,
+ ::android::MakeSharedFd(fence),
+ command.buffer->slot);
+
+ if (!lp) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadLayer);
return;
}
- properties.buffer.emplace(buffer);
+
+ properties = lp.value();
}
properties.blend_mode = AidlToBlendMode(command.blendMode);
@@ -571,7 +700,8 @@
composition_type));
}
cmd_result_writer_->AddChanges(changes);
- composer_resources_->SetDisplayMustValidateState(display_id, false);
+ auto hwc3_display = DrmHwcThree::GetHwc3Display(*display);
+ hwc3_display->must_validate = false;
// TODO: DisplayRequests are not implemented.
@@ -585,11 +715,12 @@
}
if (command.acceptDisplayChanges) {
- display->AcceptDisplayChanges();
+ display->AcceptValidatedComposition();
}
if (command.presentDisplay) {
- if (composer_resources_->MustValidateDisplay(display_id)) {
+ auto hwc3_display = DrmHwcThree::GetHwc3Display(*display);
+ if (hwc3_display->must_validate) {
cmd_result_writer_->AddError(hwc3::Error::kNotValidated);
return;
}
@@ -1089,6 +1220,20 @@
next_config != nullptr &&
current_config->group_id ==
next_config->group_id;
+ const bool same_resolution = current_config != nullptr &&
+ next_config != nullptr &&
+ current_config->mode.SameSize(next_config->mode);
+
+ /* Client framebuffer management:
+ * https://source.android.com/docs/core/graphics/framebuffer-mgmt
+ */
+ if (!same_resolution && !future_config) {
+ auto& client_layer = display->GetClientLayer();
+ auto hwc3_layer = GetHwc3Layer(client_layer);
+ hwc3_layer->ClearSlots();
+ client_layer.ClearSlots();
+ }
+
// If the contraints dictate that this is to be applied in the future, it
// must be queued. If the new config is in the same config group as the
// current one, then queue it to reduce jank.
@@ -1139,7 +1284,7 @@
}
ndk::ScopedAStatus ComposerClient::setAutoLowLatencyMode(int64_t display_id,
- bool on) {
+ bool /*on*/) {
DEBUG_FUNC();
const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
HwcDisplay* display = GetDisplay(display_id);
@@ -1147,15 +1292,13 @@
return ToBinderStatus(hwc3::Error::kBadDisplay);
}
- auto error = Hwc2toHwc3Error(display->SetAutoLowLatencyMode(on));
- return ToBinderStatus(error);
+ return ToBinderStatus(hwc3::Error::kUnsupported);
}
-ndk::ScopedAStatus ComposerClient::setClientTargetSlotCount(int64_t display_id,
- int32_t count) {
+ndk::ScopedAStatus ComposerClient::setClientTargetSlotCount(
+ int64_t /*display_id*/, int32_t /*count*/) {
DEBUG_FUNC();
- return ToBinderStatus(
- composer_resources_->SetDisplayClientTargetCacheSize(display_id, count));
+ return ToBinderStatus(hwc3::Error::kNone);
}
ndk::ScopedAStatus ComposerClient::setColorMode(int64_t display_id,
@@ -1284,7 +1427,8 @@
}
ndk::ScopedAStatus ComposerClient::notifyExpectedPresent(
- int64_t /*display*/, const ClockMonotonicTimestamp& /*expected_present_time*/,
+ int64_t /*display*/,
+ const ClockMonotonicTimestamp& /*expected_present_time*/,
int32_t /*frame_interval_ns*/) {
return ToBinderStatus(hwc3::Error::kUnsupported);
}
@@ -1306,19 +1450,6 @@
return binder;
}
-hwc3::Error ComposerClient::ImportLayerBuffer(int64_t display_id,
- int64_t layer_id,
- const Buffer& buffer,
- HwcLayer::Buffer* out_buffer) {
- auto releaser = ComposerResources::CreateResourceReleaser(true);
- auto err = composer_resources_->GetLayerBuffer(display_id, layer_id, buffer,
- &out_buffer->buffer_handle,
- releaser.get());
- out_buffer->acquire_fence = ::android::MakeSharedFd(
- buffer.fence.dup().release());
- return err;
-}
-
void ComposerClient::ExecuteSetDisplayClientTarget(
uint64_t display_id, const ClientTarget& command) {
auto* display = GetDisplay(display_id);
@@ -1327,37 +1458,35 @@
return;
}
- hwc_region_t damage_regions;
- damage_regions.numRects = command.damage.size();
+ auto& client_layer = display->GetClientLayer();
+ auto hwc3layer = GetHwc3Layer(client_layer);
- std::vector<hwc_rect_t> regions(command.damage.size());
- for (const auto& region : command.damage) {
- regions.push_back({region.left, region.top, region.right, region.bottom});
- }
- damage_regions.rects = regions.data();
-
- buffer_handle_t imported_buffer = nullptr;
- auto buf_releaser = ComposerResources::CreateResourceReleaser(true);
-
- auto error = composer_resources_->GetDisplayClientTarget(display_id,
- command.buffer,
- &imported_buffer,
- buf_releaser.get());
- if (error != hwc3::Error::kNone) {
- cmd_result_writer_->AddError(error);
- return;
+ std::optional<buffer_handle_t> raw_buffer = std::nullopt;
+ if (command.buffer.handle) {
+ raw_buffer = ::android::makeFromAidl(*command.buffer.handle);
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
auto fence = const_cast<::ndk::ScopedFileDescriptor&>(command.buffer.fence)
.release();
- error = Hwc2toHwc3Error(
- display->SetClientTarget(imported_buffer, fence,
- Hwc3DataspaceToHwc2(command.dataspace),
- damage_regions));
- if (error != hwc3::Error::kNone) {
- cmd_result_writer_->AddError(error);
+
+ auto properties = hwc3layer->HandleNextBuffer(raw_buffer,
+ ::android::MakeSharedFd(fence),
+ command.buffer.slot);
+
+ if (!properties) {
+ ALOGE("Failed to import client target buffer.");
+ /* Here, sending an error would be the natural way to do the thing.
+ * But VTS checks for no error. Is it the VTS issue?
+ * https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp;l=1892;drc=2647200f4c535ca6567b452695b7d13f2aaf3f2a
+ */
+ return;
}
+
+ properties->color_space = AidlToColorSpace(command.dataspace);
+ properties->sample_range = AidlToSampleRange(command.dataspace);
+
+ client_layer.SetLayerProperties(properties.value());
}
void ComposerClient::ExecuteSetDisplayOutputBuffer(uint64_t display_id,
@@ -1368,24 +1497,32 @@
return;
}
- buffer_handle_t imported_buffer = nullptr;
- auto buf_releaser = ComposerResources::CreateResourceReleaser(true);
-
- auto error = composer_resources_->GetDisplayOutputBuffer(display_id, buffer,
- &imported_buffer,
- buf_releaser.get());
- if (error != hwc3::Error::kNone) {
- cmd_result_writer_->AddError(error);
+ auto& writeback_layer = display->GetWritebackLayer();
+ if (!writeback_layer) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadLayer);
return;
}
+ auto hwc3layer = GetHwc3Layer(*writeback_layer);
+
+ std::optional<buffer_handle_t> raw_buffer = std::nullopt;
+ if (buffer.handle) {
+ raw_buffer = ::android::makeFromAidl(*buffer.handle);
+ }
+
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
auto fence = const_cast<::ndk::ScopedFileDescriptor&>(buffer.fence).release();
- error = Hwc2toHwc3Error(display->SetOutputBuffer(imported_buffer, fence));
- if (error != hwc3::Error::kNone) {
- cmd_result_writer_->AddError(error);
+
+ auto properties = hwc3layer->HandleNextBuffer(raw_buffer,
+ ::android::MakeSharedFd(fence),
+ buffer.slot);
+
+ if (!properties) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadLayer);
return;
}
+
+ writeback_layer->SetLayerProperties(properties.value());
}
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/ComposerClient.h b/hwc3/ComposerClient.h
index 37cb8ab..25dc0ca 100644
--- a/hwc3/ComposerClient.h
+++ b/hwc3/ComposerClient.h
@@ -22,7 +22,6 @@
#include "aidl/android/hardware/graphics/composer3/LayerCommand.h"
#include "hwc2_device/HwcLayer.h"
#include "hwc3/CommandResultWriter.h"
-#include "hwc3/ComposerResources.h"
#include "hwc3/Utils.h"
#include "utils/Mutex.h"
@@ -42,7 +41,7 @@
ComposerClient();
~ComposerClient() override;
- bool Init();
+ void Init();
std::string Dump();
// composer3 interface
@@ -176,9 +175,6 @@
std::unique_ptr<CommandResultWriter> cmd_result_writer_;
- // Manages importing and caching gralloc buffers for displays and layers.
- std::unique_ptr<ComposerResources> composer_resources_;
-
std::unique_ptr<DrmHwcThree> hwc_;
};
diff --git a/hwc3/ComposerResources.cpp b/hwc3/ComposerResources.cpp
deleted file mode 100644
index 5e19082..0000000
--- a/hwc3/ComposerResources.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-
-/*
- * Copyright (C) 2024 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 ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
-
-#include "ComposerResources.h"
-
-#include <aidlcommonsupport/NativeHandle.h>
-
-#include "hardware/hwcomposer2.h"
-#include "hwc3/Utils.h"
-
-namespace {
-using Hwc2Display = ::android::hardware::graphics::composer::V2_1::Display;
-using Hwc2Layer = ::android::hardware::graphics::composer::V2_1::Layer;
-
-auto ToHwc2Display(uint64_t display_id) -> Hwc2Display {
- return static_cast<Hwc2Display>(display_id);
-}
-
-auto ToHwc2Layer(int64_t layer_id) -> Hwc2Layer {
- return static_cast<Hwc2Layer>(layer_id);
-}
-} // namespace
-
-namespace aidl::android::hardware::graphics::composer3::impl {
-
-std::unique_ptr<ComposerResourceReleaser>
-ComposerResources::CreateResourceReleaser(bool is_buffer) {
- return std::make_unique<ComposerResourceReleaser>(is_buffer);
-}
-
-std::unique_ptr<ComposerResources> ComposerResources::Create() {
- auto instance = std::unique_ptr<ComposerResources>(new ComposerResources);
- if (instance->resources_ == nullptr) {
- ALOGE("%s: Failed to initialise ComposerResources", __func__);
- return nullptr;
- }
-
- return instance;
-}
-
-hwc3::Error ComposerResources::GetLayerBuffer(
- uint64_t display_id, int64_t layer_id, const Buffer& buffer,
- buffer_handle_t* out_buffer_handle,
- ComposerResourceReleaser* buf_releaser) {
- auto display = ToHwc2Display(display_id);
- auto layer = ToHwc2Layer(layer_id);
-
- const bool use_cache = !buffer.handle.has_value();
- buffer_handle_t buffer_handle = nullptr;
- if (buffer.handle.has_value()) {
- buffer_handle = ::android::makeFromAidl(*buffer.handle);
- }
-
- auto err = resources_->getLayerBuffer(display, layer, buffer.slot, use_cache,
- buffer_handle, out_buffer_handle,
- buf_releaser->GetReplacedHandle());
-
- return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
-}
-
-hwc3::Error ComposerResources::GetLayerSidebandStream(
- uint64_t display_id, int64_t layer_id,
- const aidl::android::hardware::common::NativeHandle& handle,
- buffer_handle_t* out_handle, ComposerResourceReleaser* releaser) {
- auto display = ToHwc2Display(display_id);
- auto layer = ToHwc2Layer(layer_id);
-
- auto err = resources_->getLayerSidebandStream(display, layer,
- ::android::makeFromAidl(handle),
- out_handle,
- releaser->GetReplacedHandle());
-
- return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
-}
-
-hwc3::Error ComposerResources::AddLayer(uint64_t display_id, int64_t layer_id,
- uint32_t buffer_cache_size) {
- auto display = ToHwc2Display(display_id);
- auto layer = ToHwc2Layer(layer_id);
-
- auto err = resources_->addLayer(display, layer, buffer_cache_size);
- return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
-}
-
-hwc3::Error ComposerResources::RemoveLayer(uint64_t display_id,
- int64_t layer_id) {
- auto display = ToHwc2Display(display_id);
- auto layer = ToHwc2Layer(layer_id);
-
- auto err = resources_->removeLayer(display, layer);
- return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
-}
-
-bool ComposerResources::HasDisplay(uint64_t display_id) {
- auto display = ToHwc2Display(display_id);
- return resources_->hasDisplay(display);
-}
-
-hwc3::Error ComposerResources::AddPhysicalDisplay(uint64_t display_id) {
- auto display = ToHwc2Display(display_id);
- auto err = resources_->addPhysicalDisplay(display);
- return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
-}
-
-hwc3::Error ComposerResources::AddVirtualDisplay(
- uint64_t display, uint32_t output_buffer_cache_size) {
- auto err = resources_->addVirtualDisplay(display, output_buffer_cache_size);
- return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
-}
-
-hwc3::Error ComposerResources::RemoveDisplay(uint64_t display_id) {
- auto display = ToHwc2Display(display_id);
- auto err = resources_->removeDisplay(display);
- return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
-}
-
-void ComposerResources::SetDisplayMustValidateState(uint64_t display_id,
- bool must_validate) {
- auto display = ToHwc2Display(display_id);
- resources_->setDisplayMustValidateState(display, must_validate);
-}
-
-bool ComposerResources::MustValidateDisplay(uint64_t display_id) {
- auto display = ToHwc2Display(display_id);
- return resources_->mustValidateDisplay(display);
-}
-
-hwc3::Error ComposerResources::GetDisplayClientTarget(
- uint64_t display_id, const Buffer& buffer, buffer_handle_t* out_handle,
- ComposerResourceReleaser* releaser) {
- auto display = ToHwc2Display(display_id);
-
- const bool use_cache = !buffer.handle.has_value();
- buffer_handle_t buffer_handle = nullptr;
- if (buffer.handle.has_value()) {
- buffer_handle = ::android::makeFromAidl(*buffer.handle);
- }
-
- auto err = resources_->getDisplayClientTarget(display, buffer.slot, use_cache,
- buffer_handle, out_handle,
- releaser->GetReplacedHandle());
- return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
-}
-
-hwc3::Error ComposerResources::SetDisplayClientTargetCacheSize(
- uint64_t display_id, uint32_t client_target_cache_size) {
- auto display = ToHwc2Display(display_id);
- auto err = resources_
- ->setDisplayClientTargetCacheSize(display,
- client_target_cache_size);
- return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
-}
-
-hwc3::Error ComposerResources::GetDisplayClientTargetCacheSize(
- uint64_t display_id, size_t* out_cache_size) {
- auto display = ToHwc2Display(display_id);
- auto err = resources_->getDisplayClientTargetCacheSize(display,
- out_cache_size);
- return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
-}
-
-hwc3::Error ComposerResources::GetDisplayOutputBufferCacheSize(
- uint64_t display_id, size_t* out_cache_size) {
- auto display = ToHwc2Display(display_id);
- auto err = resources_->getDisplayOutputBufferCacheSize(display,
- out_cache_size);
- return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
-}
-
-hwc3::Error ComposerResources::GetDisplayOutputBuffer(
- uint64_t display_id, const Buffer& buffer, buffer_handle_t* out_handle,
- ComposerResourceReleaser* releaser) {
- auto display = ToHwc2Display(display_id);
- const bool use_cache = !buffer.handle.has_value();
-
- buffer_handle_t buffer_handle = nullptr;
- if (buffer.handle.has_value()) {
- buffer_handle = ::android::makeFromAidl(*buffer.handle);
- }
-
- auto err = resources_->getDisplayOutputBuffer(display, buffer.slot, use_cache,
- buffer_handle, out_handle,
- releaser->GetReplacedHandle());
- return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
-}
-} // namespace aidl::android::hardware::graphics::composer3::impl
\ No newline at end of file
diff --git a/hwc3/ComposerResources.h b/hwc3/ComposerResources.h
deleted file mode 100644
index 6f4eee7..0000000
--- a/hwc3/ComposerResources.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2024 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 "aidl/android/hardware/graphics/composer3/IComposerClient.h"
-#include "composer-resources/2.2/ComposerResources.h"
-#include "cutils/native_handle.h"
-#include "hwc3/Utils.h"
-
-namespace aidl::android::hardware::graphics::composer3::impl {
-
-class ComposerResourceReleaser {
- public:
- explicit ComposerResourceReleaser(bool is_buffer)
- : replaced_handle_(is_buffer) {
- }
- virtual ~ComposerResourceReleaser() = default;
-
- ::android::hardware::graphics::composer::V2_2::hal::ComposerResources::
- ReplacedHandle*
- GetReplacedHandle() {
- return &replaced_handle_;
- }
-
- private:
- ::android::hardware::graphics::composer::V2_2::hal::ComposerResources::
- ReplacedHandle replaced_handle_;
-};
-
-class ComposerResources {
- public:
- static std::unique_ptr<ComposerResources> Create();
- ~ComposerResources() = default;
-
- hwc3::Error GetLayerBuffer(uint64_t display_id, int64_t layer_id,
- const Buffer& buffer,
- buffer_handle_t* out_buffer_handle,
- ComposerResourceReleaser* releaser);
- hwc3::Error GetLayerSidebandStream(
- uint64_t display_id, int64_t layer_id,
- const aidl::android::hardware::common::NativeHandle& handle,
- buffer_handle_t* out_handle, ComposerResourceReleaser* releaser);
-
- hwc3::Error AddLayer(uint64_t display, int64_t layer,
- uint32_t buffer_cache_size);
- hwc3::Error RemoveLayer(uint64_t display, int64_t layer);
-
- bool HasDisplay(uint64_t display);
- hwc3::Error AddPhysicalDisplay(uint64_t display);
- hwc3::Error AddVirtualDisplay(uint64_t display,
- uint32_t output_buffer_cache_size);
- hwc3::Error RemoveDisplay(uint64_t display);
-
- void SetDisplayMustValidateState(uint64_t display_id, bool must_validate);
- bool MustValidateDisplay(uint64_t display_id);
-
- hwc3::Error GetDisplayClientTarget(uint64_t display_id, const Buffer& buffer,
- buffer_handle_t* out_handle,
- ComposerResourceReleaser* releaser);
-
- hwc3::Error SetDisplayClientTargetCacheSize(
- uint64_t display_id, uint32_t client_target_cache_size);
- hwc3::Error GetDisplayClientTargetCacheSize(uint64_t display_id,
- size_t* out_cache_size);
- hwc3::Error GetDisplayOutputBufferCacheSize(uint64_t display,
- size_t* out_cache_size);
- hwc3::Error GetDisplayOutputBuffer(uint64_t display_id, const Buffer& buffer,
- buffer_handle_t* out_handle,
- ComposerResourceReleaser* releaser);
-
- static std::unique_ptr<ComposerResourceReleaser> CreateResourceReleaser(
- bool is_buffer);
-
- private:
- ComposerResources() = default;
-
- std::unique_ptr<
- ::android::hardware::graphics::composer::V2_2::hal::ComposerResources>
- resources_ = ::android::hardware::graphics::composer::V2_2::hal::
- ComposerResources::create();
-};
-
-} // namespace aidl::android::hardware::graphics::composer3::impl
\ No newline at end of file
diff --git a/hwc3/DrmHwcThree.cpp b/hwc3/DrmHwcThree.cpp
index 9b4ba86..6df3022 100644
--- a/hwc3/DrmHwcThree.cpp
+++ b/hwc3/DrmHwcThree.cpp
@@ -28,6 +28,16 @@
namespace aidl::android::hardware::graphics::composer3::impl {
+auto DrmHwcThree::GetHwc3Display(::android::HwcDisplay& display)
+ -> std::shared_ptr<Hwc3Display> {
+ auto frontend_private_data = display.GetFrontendPrivateData();
+ if (!frontend_private_data) {
+ frontend_private_data = std::make_shared<Hwc3Display>();
+ display.SetFrontendPrivateData(frontend_private_data);
+ }
+ return std::static_pointer_cast<Hwc3Display>(frontend_private_data);
+}
+
DrmHwcThree::~DrmHwcThree() {
/* Display deinit routine is handled by resource manager */
GetResMan().DeInit();
@@ -51,7 +61,16 @@
}
void DrmHwcThree::SendRefreshEventToClient(uint64_t display_id) {
- composer_resources_->SetDisplayMustValidateState(display_id, true);
+ {
+ const std::unique_lock lock(GetResMan().GetMainLock());
+ auto* idisplay = GetDisplay(display_id);
+ if (idisplay == nullptr) {
+ ALOGE("Failed to get display %" PRIu64, display_id);
+ return;
+ }
+ auto hwc3_display = GetHwc3Display(*idisplay);
+ hwc3_display->must_validate = true;
+ }
composer_callback_->onRefresh(static_cast<int64_t>(display_id));
}
@@ -69,11 +88,9 @@
switch (display_status) {
case DrmHwc::kDisconnected:
event = common::DisplayHotplugEvent::DISCONNECTED;
- HandleDisplayHotplugEvent(static_cast<uint64_t>(display_id), false);
break;
case DrmHwc::kConnected:
event = common::DisplayHotplugEvent::CONNECTED;
- HandleDisplayHotplugEvent(static_cast<uint64_t>(display_id), true);
break;
case DrmHwc::kLinkTrainingFailed:
event = common::DisplayHotplugEvent::ERROR_INCOMPATIBLE_CABLE;
@@ -87,28 +104,9 @@
void DrmHwcThree::SendHotplugEventToClient(
hwc2_display_t display_id, DrmHwc::DisplayStatus display_status) {
bool connected = display_status != DrmHwc::kDisconnected;
- HandleDisplayHotplugEvent(static_cast<uint64_t>(display_id), connected);
composer_callback_->onHotplug(static_cast<int64_t>(display_id), connected);
}
#endif
-void DrmHwcThree::HandleDisplayHotplugEvent(uint64_t display_id,
- bool connected) {
- DEBUG_FUNC();
- if (!connected) {
- composer_resources_->RemoveDisplay(display_id);
- return;
- }
-
- /* The second or any subsequent hotplug event with connected status enabled is
- * a special way to inform the client (SF) that the display has changed its
- * dimensions. In this case, the client removes all layers and re-creates
- * them. In this case, we keep the display resources.
- */
- if (!composer_resources_->HasDisplay(display_id)) {
- composer_resources_->AddPhysicalDisplay(display_id);
- }
-}
-
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/DrmHwcThree.h b/hwc3/DrmHwcThree.h
index 3a9a6db..44168aa 100644
--- a/hwc3/DrmHwcThree.h
+++ b/hwc3/DrmHwcThree.h
@@ -19,15 +19,18 @@
#include <aidl/android/hardware/graphics/composer3/IComposerCallback.h>
#include "drm/DrmHwc.h"
-#include "hwc3/ComposerResources.h"
+#include "hwc2_device/HwcDisplay.h"
namespace aidl::android::hardware::graphics::composer3::impl {
+class Hwc3Display : public ::android::FrontendDisplayBase {
+ public:
+ bool must_validate = false;
+};
+
class DrmHwcThree : public ::android::DrmHwc {
public:
- explicit DrmHwcThree(ComposerResources* composer_resources)
- : composer_resources_(composer_resources) {
- }
+ explicit DrmHwcThree() = default;
~DrmHwcThree() override;
void Init(std::shared_ptr<IComposerCallback> callback);
@@ -41,10 +44,10 @@
void SendHotplugEventToClient(hwc2_display_t display_id,
DrmHwc::DisplayStatus display_status) override;
- private:
- void HandleDisplayHotplugEvent(uint64_t display_id, bool connected);
+ static auto GetHwc3Display(::android::HwcDisplay& display)
+ -> std::shared_ptr<Hwc3Display>;
+ private:
std::shared_ptr<IComposerCallback> composer_callback_;
- ComposerResources* composer_resources_;
};
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/meson.build b/hwc3/meson.build
index 291c71a..c525308 100644
--- a/hwc3/meson.build
+++ b/hwc3/meson.build
@@ -4,7 +4,6 @@
'Composer.cpp',
'DrmHwcThree.cpp',
'service.cpp',
- 'ComposerResources.cpp',
'Utils.cpp',
)
diff --git a/utils/properties.cpp b/utils/properties.cpp
index 5ba109b..a975822 100644
--- a/utils/properties.cpp
+++ b/utils/properties.cpp
@@ -27,7 +27,7 @@
}
auto Properties::UseConfigGroups() -> bool {
- return (property_get_bool("ro.vendor.hwc.drm.use_config_groups", 1) != 0);
+ return (property_get_bool("ro.vendor.hwc.drm.use_config_groups", 0) != 0);
}
auto Properties::UseOverlayPlanes() -> bool {