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