drm_hwcomposer: Virtual display acceleration support
Some platforms like RaspberryPI-4 can benefit from Display Blender IP Core's
ability to write back the composition into RAM, offloading the GPU in cases
where the display content needs to be used (screen record, remote display,
etc.).
To enable this feature the following system property must be enabled:
PRODUCT_VENDOR_PROPERTIES += debug.sf.enable_hwc_vds=1
The feature was requested by the Tesla Android project to improve UI
performance.
Closes: https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/-/issues/4
Change-Id: I643f94551408bf218a0b889f1a031598646242f1
Signed-off-by: Roman Stratiienko <r.stratiienko@gmail.com>
diff --git a/hwc2_device/HwcDisplayConfigs.cpp b/hwc2_device/HwcDisplayConfigs.cpp
index 9727989..f6bf4a1 100644
--- a/hwc2_device/HwcDisplayConfigs.cpp
+++ b/hwc2_device/HwcDisplayConfigs.cpp
@@ -19,6 +19,7 @@
#include "HwcDisplayConfigs.h"
#include <cmath>
+#include <cstring>
#include "drm/DrmConnector.h"
#include "utils/log.h"
@@ -28,23 +29,53 @@
constexpr uint32_t kHeadlessModeDisplayWidthPx = 1024;
constexpr uint32_t kHeadlessModeDisplayHeightPx = 768;
constexpr uint32_t kHeadlessModeDisplayVRefresh = 60;
+constexpr uint32_t kSyncLen = 10;
+constexpr uint32_t kBackPorch = 10;
+constexpr uint32_t kFrontPorch = 10;
+constexpr uint32_t kHzInKHz = 1000;
namespace android {
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
uint32_t HwcDisplayConfigs::last_config_id = 1;
-void HwcDisplayConfigs::FillHeadless() {
+void HwcDisplayConfigs::GenFakeMode(uint16_t width, uint16_t height) {
hwc_configs.clear();
last_config_id++;
preferred_config_id = active_config_id = last_config_id;
auto headless_drm_mode_info = (drmModeModeInfo){
- .hdisplay = kHeadlessModeDisplayWidthPx,
- .vdisplay = kHeadlessModeDisplayHeightPx,
+ .hdisplay = width,
+ .vdisplay = height,
.vrefresh = kHeadlessModeDisplayVRefresh,
- .name = "HEADLESS-MODE",
+ .name = "VIRTUAL-MODE",
};
+
+ if (width == 0 || height == 0) {
+ strcpy(headless_drm_mode_info.name, "HEADLESS-MODE");
+ headless_drm_mode_info.hdisplay = kHeadlessModeDisplayWidthPx;
+ headless_drm_mode_info.vdisplay = kHeadlessModeDisplayHeightPx;
+ }
+
+ /* We need a valid mode to pass the kernel validation */
+
+ headless_drm_mode_info.hsync_start = headless_drm_mode_info.hdisplay +
+ kFrontPorch;
+ headless_drm_mode_info.hsync_end = headless_drm_mode_info.hsync_start +
+ kSyncLen;
+ headless_drm_mode_info.htotal = headless_drm_mode_info.hsync_end + kBackPorch;
+
+ headless_drm_mode_info.vsync_start = headless_drm_mode_info.vdisplay +
+ kFrontPorch;
+ headless_drm_mode_info.vsync_end = headless_drm_mode_info.vsync_start +
+ kSyncLen;
+ headless_drm_mode_info.vtotal = headless_drm_mode_info.vsync_end + kBackPorch;
+
+ headless_drm_mode_info.clock = (headless_drm_mode_info.htotal *
+ headless_drm_mode_info.vtotal *
+ headless_drm_mode_info.vrefresh) /
+ kHzInKHz;
+
hwc_configs[active_config_id] = (HwcDisplayConfig){
.id = active_config_id,
.group_id = 1,
@@ -58,8 +89,9 @@
// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
/* In case UpdateModes will fail we will still have one mode for headless
- * mode*/
- FillHeadless();
+ * mode
+ */
+ GenFakeMode(0, 0);
/* Read real configs */
auto ret = connector.UpdateModes();
if (ret != 0) {