1From 2d28f635b01ec5921c26fdab63da5f535f7dbfbd Mon Sep 17 00:00:00 2001 2From: Jeffy Chen <jeffy.chen@rock-chips.com> 3Date: Wed, 21 Apr 2021 04:44:38 +0800 4Subject: [PATCH 25/41] kmssink: Support NV12_10LE40 and NV12|NV12_10LE40|NV16 5 (AFBC) 6 7Support using NV12_10LE40 and ARM AFBC compressed format. 8 9NOTE: 10Those formats only supported on a few planes of a few chips. 11 12Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> 13--- 14 sys/kms/gstkmsallocator.c | 49 +++++++++++++- 15 sys/kms/gstkmssink.c | 137 +++++++++++++++++++++++++++++++++++++- 16 sys/kms/gstkmsutils.c | 6 ++ 17 sys/kms/gstkmsutils.h | 46 +++++++++++++ 18 4 files changed, 234 insertions(+), 4 deletions(-) 19 20diff --git a/sys/kms/gstkmsallocator.c b/sys/kms/gstkmsallocator.c 21index 6687f3b..ad56a17 100644 22--- a/sys/kms/gstkmsallocator.c 23+++ b/sys/kms/gstkmsallocator.c 24@@ -36,6 +36,7 @@ 25 26 /* it needs to be below because is internal to libdrm */ 27 #include <drm.h> 28+#include <drm_fourcc.h> 29 30 #include <gst/allocators/gstdmabuf.h> 31 32@@ -416,7 +417,7 @@ static gboolean 33 gst_kms_allocator_add_fb (GstKMSAllocator * alloc, GstKMSMemory * kmsmem, 34 gsize in_offsets[GST_VIDEO_MAX_PLANES], GstVideoInfo * vinfo) 35 { 36- gint i, ret; 37+ gint i, ret = -1; 38 gint num_planes = GST_VIDEO_INFO_N_PLANES (vinfo); 39 guint32 w, h, fmt, bo_handles[4] = { 0, }; 40 guint32 pitches[4] = { 0, }; 41@@ -442,8 +443,50 @@ gst_kms_allocator_add_fb (GstKMSAllocator * alloc, GstKMSMemory * kmsmem, 42 GST_DEBUG_OBJECT (alloc, "bo handles: %d, %d, %d, %d", bo_handles[0], 43 bo_handles[1], bo_handles[2], bo_handles[3]); 44 45- ret = drmModeAddFB2 (alloc->priv->fd, w, h, fmt, bo_handles, pitches, 46- offsets, &kmsmem->fb_id, 0); 47+ if (GST_VIDEO_INFO_IS_AFBC (vinfo)) { 48+ guint64 modifiers[4] = { 0 }; 49+ 50+ for (i = 0; i < num_planes; i++) 51+ modifiers[i] = DRM_AFBC_MODIFIER; 52+ 53+ if (fmt == DRM_FORMAT_NV12 || fmt == DRM_FORMAT_NV12_10 || 54+ fmt == DRM_FORMAT_NV16) { 55+ /* The newer kernel might use new formats instead */ 56+ guint32 _handles[4] = { bo_handles[0], 0, }; 57+ guint32 _pitches[4] = { pitches[0], 0, }; 58+ guint32 _offsets[4] = { offsets[0], 0, }; 59+ guint64 _modifiers[4] = { modifiers[0], 0, }; 60+ guint32 _fmt; 61+ 62+ if (fmt == DRM_FORMAT_NV12) { 63+ _fmt = DRM_FORMAT_YUV420_8BIT; 64+ /* The bpp of YUV420_8BIT is 12 */ 65+ _pitches[0] *= 1.5; 66+ } else if (fmt == DRM_FORMAT_NV12_10) { 67+ _fmt = DRM_FORMAT_YUV420_10BIT; 68+ /* The bpp of YUV420_10BIT is 15 */ 69+ _pitches[0] *= 1.5; 70+ } else { 71+ _fmt = DRM_FORMAT_YUYV; 72+ /* The bpp of YUYV (AFBC) is 16 */ 73+ _pitches[0] *= 2; 74+ } 75+ 76+ ret = drmModeAddFB2WithModifiers (alloc->priv->fd, w, h, _fmt, _handles, 77+ _pitches, _offsets, _modifiers, &kmsmem->fb_id, 78+ DRM_MODE_FB_MODIFIERS); 79+ } 80+ 81+ if (ret) 82+ ret = drmModeAddFB2WithModifiers (alloc->priv->fd, w, h, fmt, bo_handles, 83+ pitches, offsets, modifiers, &kmsmem->fb_id, DRM_MODE_FB_MODIFIERS); 84+ } else { 85+ ret = drmModeAddFB2 (alloc->priv->fd, w, h, fmt, bo_handles, pitches, 86+ offsets, &kmsmem->fb_id, 0); 87+ if (ret && fmt == DRM_FORMAT_NV12_10) 88+ ret = drmModeAddFB2 (alloc->priv->fd, w, h, DRM_FORMAT_NV15, bo_handles, 89+ pitches, offsets, &kmsmem->fb_id, 0); 90+ } 91 if (ret) { 92 GST_ERROR_OBJECT (alloc, "Failed to bind to framebuffer: %s (%d)", 93 g_strerror (errno), errno); 94diff --git a/sys/kms/gstkmssink.c b/sys/kms/gstkmssink.c 95index c10a374..8335963 100644 96--- a/sys/kms/gstkmssink.c 97+++ b/sys/kms/gstkmssink.c 98@@ -826,6 +826,84 @@ modesetting_failed: 99 } 100 } 101 102+static void 103+check_afbc (GstKMSSink * self, drmModePlane * plane, guint32 drmfmt, 104+ gboolean * linear, gboolean * afbc) 105+{ 106+ drmModeObjectPropertiesPtr props; 107+ drmModePropertyBlobPtr blob; 108+ drmModePropertyPtr prop; 109+ drmModeResPtr res; 110+ struct drm_format_modifier_blob *header; 111+ struct drm_format_modifier *modifiers; 112+ guint32 *formats; 113+ guint64 value = 0; 114+ gint i, j; 115+ 116+ *linear = *afbc = FALSE; 117+ 118+ res = drmModeGetResources (self->fd); 119+ if (!res) 120+ return; 121+ 122+ props = drmModeObjectGetProperties (self->fd, plane->plane_id, 123+ DRM_MODE_OBJECT_PLANE); 124+ if (!props) { 125+ drmModeFreeResources (res); 126+ return; 127+ } 128+ 129+ for (i = 0; i < props->count_props && !value; i++) { 130+ prop = drmModeGetProperty (self->fd, props->props[i]); 131+ if (!prop) 132+ continue; 133+ 134+ if (!strcmp (prop->name, "IN_FORMATS")) 135+ value = props->prop_values[i]; 136+ 137+ drmModeFreeProperty (prop); 138+ } 139+ 140+ drmModeFreeObjectProperties (props); 141+ drmModeFreeResources (res); 142+ 143+ /* No modifiers */ 144+ if (!value) { 145+ *linear = TRUE; 146+ return; 147+ } 148+ 149+ blob = drmModeGetPropertyBlob (self->fd, value); 150+ if (!blob) 151+ return; 152+ 153+ header = blob->data; 154+ modifiers = (struct drm_format_modifier *) 155+ ((gchar *) header + header->modifiers_offset); 156+ formats = (guint32 *) ((gchar *) header + header->formats_offset); 157+ 158+ for (i = 0; i < header->count_formats; i++) { 159+ if (formats[i] != drmfmt) 160+ continue; 161+ 162+ for (j = 0; j < header->count_modifiers; j++) { 163+ struct drm_format_modifier *mod = &modifiers[j]; 164+ 165+ if ((i < mod->offset) || (i > mod->offset + 63)) 166+ continue; 167+ if (!(mod->formats & (1 << (i - mod->offset)))) 168+ continue; 169+ 170+ if (mod->modifier == DRM_AFBC_MODIFIER) 171+ *afbc = TRUE; 172+ else if (mod->modifier == DRM_FORMAT_MOD_LINEAR) 173+ *linear = TRUE; 174+ } 175+ } 176+ 177+ drmModeFreePropertyBlob (blob); 178+} 179+ 180 static gboolean 181 ensure_allowed_caps (GstKMSSink * self, drmModeConnector * conn, 182 drmModePlane * plane, drmModeRes * res) 183@@ -859,7 +937,19 @@ ensure_allowed_caps (GstKMSSink * self, drmModeConnector * conn, 184 mode = &conn->modes[i]; 185 186 for (j = 0; j < plane->count_formats; j++) { 187- fmt = gst_video_format_from_drm (plane->formats[j]); 188+ gboolean linear = FALSE, afbc = FALSE; 189+ 190+ check_afbc (self, plane, plane->formats[j], &linear, &afbc); 191+ 192+ if (plane->formats[j] == DRM_FORMAT_YUV420_8BIT) 193+ fmt = GST_VIDEO_FORMAT_NV12; 194+ else if (plane->formats[j] == DRM_FORMAT_YUV420_10BIT) 195+ fmt = GST_VIDEO_FORMAT_NV12_10LE40; 196+ else if (afbc && plane->formats[j] == DRM_FORMAT_YUYV) 197+ fmt = GST_VIDEO_FORMAT_NV16; 198+ else 199+ fmt = gst_video_format_from_drm (plane->formats[j]); 200+ 201 if (fmt == GST_VIDEO_FORMAT_UNKNOWN) { 202 GST_INFO_OBJECT (self, "ignoring format %" GST_FOURCC_FORMAT, 203 GST_FOURCC_ARGS (plane->formats[j])); 204@@ -884,6 +974,16 @@ ensure_allowed_caps (GstKMSSink * self, drmModeConnector * conn, 205 if (!caps) 206 continue; 207 208+ if (afbc) { 209+ GstCaps *afbc_caps = gst_caps_copy (caps); 210+ gst_caps_set_simple (afbc_caps, "arm-afbc", G_TYPE_INT, 1, NULL); 211+ 212+ if (linear) 213+ gst_caps_append (caps, afbc_caps); 214+ else 215+ gst_caps_replace (&caps, afbc_caps); 216+ } 217+ 218 tmp_caps = gst_caps_merge (tmp_caps, caps); 219 } 220 221@@ -1532,11 +1632,23 @@ gst_kms_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) 222 { 223 GstKMSSink *self; 224 GstVideoInfo vinfo; 225+ GstStructure *s; 226+ gint value; 227 228 self = GST_KMS_SINK (bsink); 229 230 if (!gst_video_info_from_caps (&vinfo, caps)) 231 goto invalid_format; 232+ 233+ /* parse AFBC from caps */ 234+ s = gst_caps_get_structure (caps, 0); 235+ if (gst_structure_get_int (s, "arm-afbc", &value)) { 236+ if (value) 237+ GST_VIDEO_INFO_SET_AFBC (&vinfo); 238+ else 239+ GST_VIDEO_INFO_UNSET_AFBC (&vinfo); 240+ } 241+ 242 self->vinfo = vinfo; 243 244 if (!gst_kms_sink_calculate_display_ratio (self, &vinfo, 245@@ -1611,7 +1723,9 @@ gst_kms_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) 246 gboolean need_pool; 247 GstVideoInfo vinfo; 248 GstBufferPool *pool; 249+ GstStructure *s; 250 gsize size; 251+ gint value; 252 253 self = GST_KMS_SINK (bsink); 254 255@@ -1623,6 +1737,10 @@ gst_kms_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) 256 if (!gst_video_info_from_caps (&vinfo, caps)) 257 goto invalid_caps; 258 259+ s = gst_caps_get_structure (caps, 0); 260+ if (gst_structure_get_int (s, "arm-afbc", &value) && value) 261+ goto afbc_caps; 262+ 263 size = GST_VIDEO_INFO_SIZE (&vinfo); 264 265 pool = NULL; 266@@ -1661,6 +1779,11 @@ invalid_caps: 267 GST_DEBUG_OBJECT (bsink, "invalid caps specified"); 268 return FALSE; 269 } 270+afbc_caps: 271+ { 272+ GST_DEBUG_OBJECT (bsink, "no allocation for AFBC"); 273+ return FALSE; 274+ } 275 no_pool: 276 { 277 /* Already warned in create_pool */ 278@@ -1893,6 +2016,11 @@ gst_kms_sink_copy_to_dumb_buffer (GstKMSSink * self, GstVideoInfo * vinfo, 279 gboolean success; 280 GstBuffer *buf = NULL; 281 282+ if (GST_VIDEO_INFO_IS_AFBC (vinfo)) { 283+ GST_ERROR_OBJECT (self, "unable to copy AFBC"); 284+ return NULL; 285+ } 286+ 287 if (!ensure_internal_pool (self, vinfo, inbuf)) 288 goto bail; 289 290@@ -2081,6 +2209,10 @@ retry_set_plane: 291 gst_kms_push_hdr_infoframe (self, FALSE); 292 #endif 293 294+ if (GST_VIDEO_INFO_IS_AFBC (vinfo)) 295+ /* The AFBC's width should align to 4 */ 296+ src.w &= ~3; 297+ 298 GST_TRACE_OBJECT (self, 299 "drmModeSetPlane at (%i,%i) %ix%i sourcing at (%i,%i) %ix%i", 300 result.x, result.y, result.w, result.h, src.x, src.y, src.w, src.h); 301@@ -2170,6 +2302,9 @@ gst_kms_sink_drain (GstKMSSink * self) 302 303 dumb_buf = gst_kms_sink_copy_to_dumb_buffer (self, &self->last_vinfo, 304 parent_meta->buffer); 305+ if (!dumb_buf) 306+ dumb_buf = gst_buffer_ref (self->last_buffer); 307+ 308 last_buf = self->last_buffer; 309 self->last_buffer = dumb_buf; 310 311diff --git a/sys/kms/gstkmsutils.c b/sys/kms/gstkmsutils.c 312index cc719fc..23f04da 100644 313--- a/sys/kms/gstkmsutils.c 314+++ b/sys/kms/gstkmsutils.c 315@@ -68,6 +68,8 @@ static const struct 316 DEF_FMT (YUV422, Y42B), 317 DEF_FMT (NV61, NV61), 318 DEF_FMT (NV16, NV16), 319+ DEF_FMT (NV12_10, NV12_10LE40), 320+ DEF_FMT (NV15, NV12_10LE40), 321 DEF_FMT (UYVY, UYVY), 322 DEF_FMT (YVYU, YVYU), 323 DEF_FMT (YUYV, YUY2), 324@@ -129,6 +131,8 @@ gst_drm_bpp_from_drm (guint32 drmfmt) 325 bpp = 8; 326 break; 327 case DRM_FORMAT_P010: 328+ case DRM_FORMAT_NV12_10: 329+ case DRM_FORMAT_NV15: 330 bpp = 10; 331 break; 332 case DRM_FORMAT_UYVY: 333@@ -161,6 +165,8 @@ gst_drm_height_from_drm (guint32 drmfmt, guint32 height) 334 case DRM_FORMAT_YVU420: 335 case DRM_FORMAT_YUV422: 336 case DRM_FORMAT_NV12: 337+ case DRM_FORMAT_NV12_10: 338+ case DRM_FORMAT_NV15: 339 case DRM_FORMAT_NV21: 340 case DRM_FORMAT_P010: 341 case DRM_FORMAT_P016: 342diff --git a/sys/kms/gstkmsutils.h b/sys/kms/gstkmsutils.h 343index 6570070..742372a 100644 344--- a/sys/kms/gstkmsutils.h 345+++ b/sys/kms/gstkmsutils.h 346@@ -30,6 +30,52 @@ 347 348 G_BEGIN_DECLS 349 350+#ifndef DRM_FORMAT_NV12_10 351+#define DRM_FORMAT_NV12_10 fourcc_code('N', 'A', '1', '2') 352+#endif 353+ 354+#ifndef DRM_FORMAT_NV15 355+#define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') 356+#endif 357+ 358+#ifndef DRM_FORMAT_YUV420_8BIT 359+#define DRM_FORMAT_YUV420_8BIT fourcc_code('Y', 'U', '0', '8') 360+#endif 361+ 362+#ifndef DRM_FORMAT_YUV420_10BIT 363+#define DRM_FORMAT_YUV420_10BIT fourcc_code('Y', 'U', '1', '0') 364+#endif 365+ 366+#ifndef DRM_FORMAT_MOD_VENDOR_ARM 367+#define DRM_FORMAT_MOD_VENDOR_ARM 0x08 368+#endif 369+ 370+#ifndef DRM_FORMAT_MOD_ARM_AFBC 371+#define DRM_FORMAT_MOD_ARM_AFBC(__afbc_mode) fourcc_mod_code(ARM, __afbc_mode) 372+#endif 373+ 374+#ifndef AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 375+#define AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 (1ULL) 376+#endif 377+ 378+#ifndef AFBC_FORMAT_MOD_SPARSE 379+#define AFBC_FORMAT_MOD_SPARSE (((__u64)1) << 6) 380+#endif 381+ 382+#define DRM_AFBC_MODIFIER \ 383+ (DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_SPARSE) | \ 384+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)) 385+ 386+#ifndef GST_VIDEO_FLAG_ARM_AFBC 387+#define GST_VIDEO_FLAG_ARM_AFBC (1UL << 31) 388+#define GST_VIDEO_INFO_SET_AFBC(i) \ 389+ GST_VIDEO_INFO_FLAG_SET (i, GST_VIDEO_FLAG_ARM_AFBC) 390+#define GST_VIDEO_INFO_UNSET_AFBC(i) \ 391+ GST_VIDEO_INFO_FLAG_UNSET (i, GST_VIDEO_FLAG_ARM_AFBC) 392+#define GST_VIDEO_INFO_IS_AFBC(i) \ 393+ GST_VIDEO_INFO_FLAG_IS_SET (i, GST_VIDEO_FLAG_ARM_AFBC) 394+#endif 395+ 396 GstVideoFormat gst_video_format_from_drm (guint32 drmfmt); 397 guint32 gst_drm_format_from_video (GstVideoFormat fmt); 398 guint32 gst_drm_bpp_from_drm (guint32 drmfmt); 399-- 4002.20.1 401 402