c50e5ba7a5
Cherry-pick from http://192.168.110.45/sdk/buildroot/-/commit/ed70e2b79cbc7a504792899e2cd3577777fd54bd
373 lines
13 KiB
Diff
373 lines
13 KiB
Diff
From ac19d1d06ea2433fed707210f4433133a58a12dc Mon Sep 17 00:00:00 2001
|
|
From: Luigi Santivetti <luigi.santivetti@imgtec.com>
|
|
Date: Thu, 26 Sep 2019 13:32:15 +0100
|
|
Subject: [PATCH 43/50] dri2: add support for image modifiers
|
|
|
|
This change introduces support for image modifiers to platform_null. In
|
|
order for it to create an image with modifiers, it relies on libdrm to
|
|
populate all formats with associated modifiers supported by the display
|
|
for the primary drm plane in use.
|
|
|
|
drmModePopulateFormats() is added to the DRM api in a different change
|
|
and it is not upstream at present.
|
|
|
|
NOTES:
|
|
[1] IN_FORMATS blobs are available since kernel 4.14:
|
|
- db1689aa61bd1efb5ce9b896e7aa860a85b7f1b6
|
|
- https://patchwork.freedesktop.org/patch/168543
|
|
|
|
[2] for the record, in order to test this change, it was needed to:
|
|
- edit pvrdri_impl.c, as fbc relies on the BVNC for selecting which
|
|
algorithm and fourcc code are to be used. To sidestep this, include
|
|
img_drm_fourcc_internal.h instead of powervr/img_drm_fourcc.h and
|
|
manually add the list of g_auiAll_mods[]
|
|
- edit null_disp_drv.h, by removing DRM_FORMAT_MOD_LINEAR
|
|
- edit pvrrem_conv_sw_fbdc.c, log from decompress_fb() by building
|
|
with RFB_DEBUG=1, the log file is under /var/log
|
|
|
|
[3] the dri image->base.version threshold is 14.
|
|
- Unlike for platform_wayland, where no details were found regarding
|
|
why it's using 15
|
|
- dri_interface.h makes createImageWithModifiers available since
|
|
version 14
|
|
- dri/gbm_dri.c as an example checks for minimum version 14.
|
|
|
|
Change-Id: I0f7b030f6e1943690692674bf18daabfc153208a
|
|
Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
|
|
---
|
|
src/egl/drivers/dri2/egl_dri2.h | 6 +
|
|
src/egl/drivers/dri2/platform_null.c | 174 +++++++++++++++++++++++----
|
|
2 files changed, 159 insertions(+), 21 deletions(-)
|
|
|
|
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
|
|
index 3d5c9adb4f3..6ec9ee01885 100644
|
|
--- a/src/egl/drivers/dri2/egl_dri2.h
|
|
+++ b/src/egl/drivers/dri2/egl_dri2.h
|
|
@@ -110,6 +110,7 @@ struct display_output {
|
|
drmModeModeInfo mode;
|
|
uint32_t mode_blob_id;
|
|
unsigned formats;
|
|
+ drmModeFormats *in_formats;
|
|
drmModeAtomicReq *atomic_state;
|
|
};
|
|
#endif
|
|
@@ -274,6 +275,7 @@ struct dri2_egl_display
|
|
|
|
#ifdef HAVE_NULL_PLATFORM
|
|
bool atomic_enabled;
|
|
+ bool in_formats_enabled;
|
|
struct display_output output;
|
|
#endif
|
|
|
|
@@ -373,6 +375,10 @@ struct dri2_egl_surface
|
|
#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_NULL_PLATFORM)
|
|
int format;
|
|
#endif
|
|
+#if defined(HAVE_NULL_PLATFORM)
|
|
+ uint64_t *modifiers;
|
|
+ uint32_t count_modifiers;
|
|
+#endif
|
|
|
|
#ifdef HAVE_DRM_PLATFORM
|
|
struct gbm_dri_surface *gbm_surf;
|
|
diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c
|
|
index c25ae0b2a04..701460dde4e 100644
|
|
--- a/src/egl/drivers/dri2/platform_null.c
|
|
+++ b/src/egl/drivers/dri2/platform_null.c
|
|
@@ -156,6 +156,18 @@ format_idx_get_from_drm_format(uint32_t drm_format)
|
|
return -1;
|
|
}
|
|
|
|
+static inline uint32_t
|
|
+blob_id_from_property_value(uint64_t prop_value)
|
|
+{
|
|
+ /* The KMS properties documetation, 01.org/linuxgraphics, says:
|
|
+ *
|
|
+ * For all property types except blob properties the value is a 64-bit
|
|
+ * unsigned integer.
|
|
+ */
|
|
+ assert(!(prop_value >> 32));
|
|
+ return (uint32_t) prop_value;
|
|
+}
|
|
+
|
|
static int
|
|
atomic_state_add_object_properties(drmModeAtomicReq *atomic_state,
|
|
const struct object_property *props,
|
|
@@ -644,14 +656,45 @@ drm_event_process(int fd)
|
|
return 0;
|
|
}
|
|
|
|
+static drmModeFormatsPtr
|
|
+plane_get_in_formats(int fd, drmModePlane *plane)
|
|
+{
|
|
+ drmModeFormatsPtr drm_mode_fmt = NULL;
|
|
+ drmModePropertyBlobRes *blob;
|
|
+ uint64_t prop_value;
|
|
+ uint32_t blob_id;
|
|
+ int err;
|
|
+
|
|
+ if (!plane)
|
|
+ return NULL;
|
|
+
|
|
+ err = !object_property_value_for_name(fd, plane->plane_id, DRM_MODE_OBJECT_PLANE,
|
|
+ "IN_FORMATS", &prop_value);
|
|
+ if (err)
|
|
+ return NULL;
|
|
+
|
|
+ blob_id = blob_id_from_property_value(prop_value);
|
|
+ blob = drmModeGetPropertyBlob(fd, blob_id);
|
|
+
|
|
+ err = drmModePopulateFormats(blob, &drm_mode_fmt);
|
|
+ if (err)
|
|
+ _eglLog(_EGL_WARNING,"failed to populate in_formats (%d)", err);
|
|
+
|
|
+ drmModeFreePropertyBlob(blob);
|
|
+
|
|
+ return drm_mode_fmt;
|
|
+}
|
|
+
|
|
static bool
|
|
-display_output_init(int fd, struct display_output *output, bool use_atomic)
|
|
+display_output_init(int fd, struct display_output *output, bool use_atomic,
|
|
+ bool prefer_in_formats, bool *in_formats_enabled_out)
|
|
{
|
|
drmModeRes *resources;
|
|
drmModeConnector *connector;
|
|
drmModeCrtc *crtc;
|
|
drmModePlane *plane;
|
|
unsigned mode_idx;
|
|
+ uint32_t drm_format;
|
|
|
|
resources = drmModeGetResources(fd);
|
|
if (!resources)
|
|
@@ -674,18 +717,41 @@ display_output_init(int fd, struct display_output *output, bool use_atomic)
|
|
goto err_free_plane;
|
|
output->mode = connector->modes[mode_idx];
|
|
|
|
+ assert(in_formats_enabled_out && !(*in_formats_enabled_out));
|
|
+
|
|
+ /* can in_formats be enabled for this display? */
|
|
+ if (prefer_in_formats) {
|
|
+ output->in_formats = plane_get_in_formats(fd, plane);
|
|
+ if (!output->in_formats) {
|
|
+ _eglLog(_EGL_WARNING,
|
|
+ "fallback to plane formats, no in_formats found");
|
|
+ } else if (output->in_formats->count != plane->count_formats) {
|
|
+ /* exit the process with generic failure 1 */
|
|
+ _eglLog(_EGL_FATAL,
|
|
+ "kernel bug: formats count mismatch, exit");
|
|
+ } else {
|
|
+ *in_formats_enabled_out = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
/* Record the display supported formats */
|
|
for (unsigned i = 0; i < plane->count_formats; i++) {
|
|
int format_idx;
|
|
|
|
- format_idx = format_idx_get_from_drm_format(plane->formats[i]);
|
|
+ drm_format = *in_formats_enabled_out ?
|
|
+ output->in_formats->formats[i].format : plane->formats[i];
|
|
+ format_idx = format_idx_get_from_drm_format(drm_format);
|
|
if (format_idx == -1)
|
|
continue;
|
|
|
|
output->formats |= (1 << format_idx);
|
|
}
|
|
+
|
|
+ /* At this point we can only shut down if the look up failed and
|
|
+ * it is safe to pass NULL to drmModeFreeFormats().
|
|
+ */
|
|
if (!output->formats)
|
|
- goto err_free_plane;
|
|
+ goto err_free_formats;
|
|
|
|
output->connector_id = connector->connector_id;
|
|
output->crtc_id = crtc->crtc_id;
|
|
@@ -705,6 +771,8 @@ display_output_init(int fd, struct display_output *output, bool use_atomic)
|
|
|
|
return true;
|
|
|
|
+err_free_formats:
|
|
+ drmModeFreeFormats(output->in_formats);
|
|
err_free_plane:
|
|
drmModeFreePlane(plane);
|
|
err_free_crtc:
|
|
@@ -983,10 +1051,12 @@ static bool
|
|
add_fb_for_dri_image(struct dri2_egl_display *dri2_dpy, __DRIimage *image,
|
|
uint32_t *fb_id_out)
|
|
{
|
|
+ uint64_t modifiers[4] = {0};
|
|
uint32_t handles[4] = {0};
|
|
uint32_t pitches[4] = {0};
|
|
uint32_t offsets[4] = {0};
|
|
- int handle, stride, width, height, format;
|
|
+ uint32_t flags = 0;
|
|
+ int handle, stride, width, height, format, l_mod, h_mod;
|
|
int format_idx;
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE, &handle);
|
|
@@ -1001,9 +1071,41 @@ add_fb_for_dri_image(struct dri2_egl_display *dri2_dpy, __DRIimage *image,
|
|
format_idx = format_idx_get_from_dri_image_format(format);
|
|
assert(format_idx != -1);
|
|
|
|
- return !drmModeAddFB2(dri2_dpy->fd, width, height,
|
|
- dri2_null_formats[format_idx].drm_format,
|
|
- handles, pitches, offsets, fb_id_out, 0);
|
|
+ if (dri2_dpy->in_formats_enabled) {
|
|
+ dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_MODIFIER_UPPER, &h_mod);
|
|
+ dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_MODIFIER_LOWER, &l_mod);
|
|
+
|
|
+ modifiers[0] = combine_u32_into_u64((uint32_t) h_mod, (uint32_t) l_mod);
|
|
+ flags |= DRM_MODE_FB_MODIFIERS;
|
|
+ }
|
|
+
|
|
+ return !drmModeAddFB2WithModifiers(dri2_dpy->fd, width, height,
|
|
+ dri2_null_formats[format_idx].drm_format,
|
|
+ handles, pitches, offsets, modifiers,
|
|
+ fb_id_out, flags);
|
|
+}
|
|
+
|
|
+static __DRIimage *
|
|
+create_image(struct dri2_egl_surface *dri2_surf, uint32_t flags)
|
|
+{
|
|
+ struct dri2_egl_display *dri2_dpy =
|
|
+ dri2_egl_display(dri2_surf->base.Resource.Display);
|
|
+
|
|
+ if (dri2_dpy->in_formats_enabled)
|
|
+ return dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen,
|
|
+ dri2_surf->base.Width,
|
|
+ dri2_surf->base.Height,
|
|
+ dri2_surf->format,
|
|
+ dri2_surf->modifiers,
|
|
+ dri2_surf->count_modifiers,
|
|
+ NULL);
|
|
+
|
|
+ return dri2_dpy->image->createImage(dri2_dpy->dri_screen,
|
|
+ dri2_surf->base.Width,
|
|
+ dri2_surf->base.Height,
|
|
+ dri2_surf->format,
|
|
+ flags,
|
|
+ NULL);
|
|
}
|
|
|
|
static bool
|
|
@@ -1016,12 +1118,7 @@ get_front_bo(struct dri2_egl_surface *dri2_surf)
|
|
if (dri2_surf->base.Type == EGL_WINDOW_BIT)
|
|
use |= __DRI_IMAGE_USE_SCANOUT;
|
|
|
|
- dri2_surf->front = dri2_dpy->image->createImage(dri2_dpy->dri_screen,
|
|
- dri2_surf->base.Width,
|
|
- dri2_surf->base.Height,
|
|
- dri2_surf->format,
|
|
- use,
|
|
- NULL);
|
|
+ dri2_surf->front = create_image(dri2_surf, use);
|
|
if (!dri2_surf->front)
|
|
return false;
|
|
|
|
@@ -1058,13 +1155,8 @@ get_back_bo(struct dri2_egl_surface *dri2_surf)
|
|
}
|
|
|
|
if (!dri2_surf->back->dri_image) {
|
|
- dri2_surf->back->dri_image =
|
|
- dri2_dpy->image->createImage(dri2_dpy->dri_screen,
|
|
- dri2_surf->base.Width,
|
|
- dri2_surf->base.Height,
|
|
- dri2_surf->format,
|
|
- __DRI_IMAGE_USE_SCANOUT,
|
|
- NULL);
|
|
+ dri2_surf->back->dri_image = create_image(dri2_surf,
|
|
+ __DRI_IMAGE_USE_SCANOUT);
|
|
if (!dri2_surf->back->dri_image)
|
|
goto err_unlock;
|
|
}
|
|
@@ -1094,6 +1186,26 @@ static void surface_swap_queue_init(struct dri2_egl_surface *dri2_surf)
|
|
swap_queue[i].kms_in_fence_fd = -1;
|
|
}
|
|
|
|
+static bool
|
|
+in_formats_get_modifiers(drmModeFormats *in_formats, int drm_format,
|
|
+ uint64_t **out_modifiers, uint32_t *out_count)
|
|
+{
|
|
+ unsigned i;
|
|
+
|
|
+ if (!in_formats)
|
|
+ return false;
|
|
+
|
|
+ for (i = 0; i < in_formats->count; i++) {
|
|
+ if (in_formats->formats[i].format == drm_format) {
|
|
+ *out_modifiers = in_formats->formats[i].modifiers;
|
|
+ *out_count = in_formats->formats[i].count_modifiers;
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
static _EGLSurface *
|
|
create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type,
|
|
const EGLint *attrib_list)
|
|
@@ -1105,6 +1217,7 @@ create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type,
|
|
const __DRIconfig *dri_config;
|
|
_EGLSurface *surf;
|
|
int format_idx;
|
|
+ bool ret;
|
|
|
|
dri2_surf = calloc(1, sizeof(*dri2_surf));
|
|
if (!dri2_surf) {
|
|
@@ -1137,6 +1250,15 @@ create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type,
|
|
|
|
dri2_surf->format = dri2_null_formats[format_idx].dri_image_format;
|
|
|
|
+ if (dri2_dpy->in_formats_enabled) {
|
|
+ ret = in_formats_get_modifiers(dri2_dpy->output.in_formats,
|
|
+ dri2_null_formats[format_idx].drm_format,
|
|
+ &dri2_surf->modifiers,
|
|
+ &dri2_surf->count_modifiers);
|
|
+ if (!ret || dri2_surf->count_modifiers <= 0)
|
|
+ goto err_free_surface;
|
|
+ }
|
|
+
|
|
surface_swap_queue_init(dri2_surf);
|
|
|
|
return surf;
|
|
@@ -1533,6 +1655,7 @@ EGLBoolean
|
|
dri2_initialize_null(_EGLDisplay *disp)
|
|
{
|
|
struct dri2_egl_display *dri2_dpy;
|
|
+ bool prefer_in_formats;
|
|
int err;
|
|
|
|
dri2_dpy = calloc(1, sizeof(*dri2_dpy));
|
|
@@ -1586,8 +1709,16 @@ dri2_initialize_null(_EGLDisplay *disp)
|
|
goto cleanup;
|
|
}
|
|
|
|
+ /* in_formats could be supported by the platform, however not being
|
|
+ * actually enabled, i.e. in_formats init can still fail.
|
|
+ */
|
|
+ prefer_in_formats = dri2_dpy->image->base.version >= 14 &&
|
|
+ dri2_dpy->image->createImageWithModifiers;
|
|
+
|
|
if (!display_output_init(dri2_dpy->fd, &dri2_dpy->output,
|
|
- dri2_dpy->atomic_enabled)) {
|
|
+ dri2_dpy->atomic_enabled,
|
|
+ prefer_in_formats,
|
|
+ &dri2_dpy->in_formats_enabled)) {
|
|
_eglError(EGL_NOT_INITIALIZED, "failed to create output");
|
|
goto cleanup;
|
|
}
|
|
@@ -1616,6 +1747,7 @@ void
|
|
dri2_teardown_null(struct dri2_egl_display *dri2_dpy)
|
|
{
|
|
drmModeAtomicFree(dri2_dpy->output.atomic_state);
|
|
+ drmModeFreeFormats(dri2_dpy->output.in_formats);
|
|
|
|
if (dri2_dpy->output.mode_blob_id)
|
|
drmModeDestroyPropertyBlob(dri2_dpy->fd, dri2_dpy->output.mode_blob_id);
|
|
--
|
|
2.17.1
|
|
|