0002-reset-drm-in-atomic-api.patch 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027
  1. Reset DRM to initial state on each playing.
  2. Signed-off-by: Windsome Zeng <windsome.zeng@starfivetech.com>
  3. diff -purN a/sys/kms/gstkmsallocator.c b/sys/kms/gstkmsallocator.c
  4. --- a/sys/kms/gstkmsallocator.c 2022-09-06 11:07:01.464180909 +0800
  5. +++ b/sys/kms/gstkmsallocator.c 2022-09-06 11:03:57.761729431 +0800
  6. @@ -384,6 +384,9 @@ gst_kms_memory_map (GstMemory * mem, gsi
  7. }
  8. kmsmem->bo->ptr = out;
  9. + /* clear the framebuffer to 0 */
  10. + memset(out, 0, kmsmem->bo->size);
  11. +
  12. out:
  13. g_atomic_int_inc (&kmsmem->bo->refs);
  14. return kmsmem->bo->ptr;
  15. diff -purN a/sys/kms/gstkmssink.c b/sys/kms/gstkmssink.c
  16. --- a/sys/kms/gstkmssink.c 2022-09-06 11:07:01.464180909 +0800
  17. +++ b/sys/kms/gstkmssink.c 2022-09-06 11:03:57.761729431 +0800
  18. @@ -74,6 +74,8 @@ static GstFlowReturn gst_kms_sink_show_f
  19. static void gst_kms_sink_video_overlay_init (GstVideoOverlayInterface * iface);
  20. static void gst_kms_sink_drain (GstKMSSink * self);
  21. +int gst_kms_sink_reset_drm(GstKMSSink * self);
  22. +
  23. #define parent_class gst_kms_sink_parent_class
  24. G_DEFINE_TYPE_WITH_CODE (GstKMSSink, gst_kms_sink, GST_TYPE_VIDEO_SINK,
  25. GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, GST_PLUGIN_NAME, 0,
  26. @@ -818,6 +820,9 @@ retry_find_plane:
  27. g_object_notify_by_pspec (G_OBJECT (self), g_properties[PROP_DISPLAY_WIDTH]);
  28. g_object_notify_by_pspec (G_OBJECT (self), g_properties[PROP_DISPLAY_HEIGHT]);
  29. + GST_INFO_OBJECT (self, "Reset DRM to initial state using atomic API.");
  30. + gst_kms_sink_reset_drm (self);
  31. +
  32. gst_kms_sink_update_connector_properties (self);
  33. gst_kms_sink_update_plane_properties (self);
  34. diff -purN a/sys/kms/meson.build b/sys/kms/meson.build
  35. --- a/sys/kms/meson.build 2022-09-06 11:07:01.464180909 +0800
  36. +++ b/sys/kms/meson.build 2022-09-06 11:03:57.761729431 +0800
  37. @@ -3,6 +3,7 @@ kmssink_sources = [
  38. 'gstkmsbufferpool.c',
  39. 'gstkmssink.c',
  40. 'gstkmsutils.c',
  41. + 'mymodetest.c',
  42. ]
  43. if host_system != 'linux'
  44. diff -purN a/sys/kms/mymodetest.c b/sys/kms/mymodetest.c
  45. --- a/sys/kms/mymodetest.c 1970-01-01 08:00:00.000000000 +0800
  46. +++ b/sys/kms/mymodetest.c 2022-09-06 11:03:57.761729431 +0800
  47. @@ -0,0 +1,973 @@
  48. +/*
  49. + * SPDX-License-Identifier: GPL-2.0
  50. + *
  51. + * Copyright (C) 2022 StarFive Technology Co., Ltd.
  52. + *
  53. + * Description: Reset drm to initial state in atomic API.
  54. + * This code is modified from libdrm/modetest. Instead of command line, all
  55. + * its info comes from GstKMSSink, such as crtc/plane/connector etc.
  56. + * Windsome Zeng <windsome.zeng@starfivetech.com>
  57. + */
  58. +
  59. +/*
  60. + * DRM based mode setting test program
  61. + * Copyright 2008 Tungsten Graphics
  62. + * Jakob Bornecrantz <jakob@tungstengraphics.com>
  63. + * Copyright 2008 Intel Corporation
  64. + * Jesse Barnes <jesse.barnes@intel.com>
  65. + *
  66. + * Permission is hereby granted, free of charge, to any person obtaining a
  67. + * copy of this software and associated documentation files (the "Software"),
  68. + * to deal in the Software without restriction, including without limitation
  69. + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  70. + * and/or sell copies of the Software, and to permit persons to whom the
  71. + * Software is furnished to do so, subject to the following conditions:
  72. + *
  73. + * The above copyright notice and this permission notice shall be included in
  74. + * all copies or substantial portions of the Software.
  75. + *
  76. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  77. + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  78. + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  79. + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  80. + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  81. + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  82. + * IN THE SOFTWARE.
  83. + */
  84. +
  85. +/*
  86. + * This fairly simple test program dumps output in a similar format to the
  87. + * "xrandr" tool everyone knows & loves. It's necessarily slightly different
  88. + * since the kernel separates outputs into encoder and connector structures,
  89. + * each with their own unique ID. The program also allows test testing of the
  90. + * memory management and mode setting APIs by allowing the user to specify a
  91. + * connector and mode to use for mode setting. If all works as expected, a
  92. + * blue background should be painted on the monitor attached to the specified
  93. + * connector after the selected mode is set.
  94. + *
  95. + * TODO: use cairo to write the mode info on the selected output once
  96. + * the mode has been programmed, along with possible test patterns.
  97. + */
  98. +
  99. +#include <assert.h>
  100. +#include <ctype.h>
  101. +#include <stdbool.h>
  102. +#include <stdio.h>
  103. +#include <stdlib.h>
  104. +#include <stdint.h>
  105. +#include <inttypes.h>
  106. +#include <unistd.h>
  107. +#include <string.h>
  108. +#include <strings.h>
  109. +#include <errno.h>
  110. +#include <poll.h>
  111. +#include <sys/time.h>
  112. +#if HAVE_SYS_SELECT_H
  113. +#include <sys/select.h>
  114. +#endif
  115. +#include <math.h>
  116. +
  117. +#include "xf86drm.h"
  118. +#include "xf86drmMode.h"
  119. +#include "drm_fourcc.h"
  120. +
  121. +#include <gst/video/video.h>
  122. +#include "gstkmssink.h"
  123. +
  124. +int gst_kms_sink_reset_drm(GstKMSSink * self);
  125. +
  126. +struct crtc {
  127. + drmModeCrtc *crtc;
  128. + drmModeObjectProperties *props;
  129. + drmModePropertyRes **props_info;
  130. + drmModeModeInfo *mode;
  131. +};
  132. +
  133. +struct encoder {
  134. + drmModeEncoder *encoder;
  135. +};
  136. +
  137. +struct connector {
  138. + drmModeConnector *connector;
  139. + drmModeObjectProperties *props;
  140. + drmModePropertyRes **props_info;
  141. + char *name;
  142. +};
  143. +
  144. +struct fb {
  145. + drmModeFB *fb;
  146. +};
  147. +
  148. +struct plane {
  149. + drmModePlane *plane;
  150. + drmModeObjectProperties *props;
  151. + drmModePropertyRes **props_info;
  152. +};
  153. +
  154. +struct resources {
  155. + struct crtc *crtcs;
  156. + int count_crtcs;
  157. + struct encoder *encoders;
  158. + int count_encoders;
  159. + struct connector *connectors;
  160. + int count_connectors;
  161. + struct fb *fbs;
  162. + int count_fbs;
  163. + struct plane *planes;
  164. + uint32_t count_planes;
  165. +};
  166. +
  167. +struct device {
  168. + int fd;
  169. +
  170. + struct resources *resources;
  171. +
  172. + struct {
  173. + unsigned int width;
  174. + unsigned int height;
  175. +
  176. + unsigned int fb_id;
  177. + struct bo *bo;
  178. + struct bo *cursor_bo;
  179. + } mode;
  180. +
  181. + int use_atomic;
  182. + drmModeAtomicReq *req;
  183. +};
  184. +
  185. +static inline int64_t U642I64(uint64_t val)
  186. +{
  187. + return (int64_t)*((int64_t *)&val);
  188. +}
  189. +
  190. +static float mode_vrefresh(drmModeModeInfo *mode)
  191. +{
  192. + return mode->clock * 1000.00
  193. + / (mode->htotal * mode->vtotal);
  194. +}
  195. +
  196. +static void free_resources(struct resources *res)
  197. +{
  198. + int i;
  199. +
  200. + if (!res)
  201. + return;
  202. +
  203. +#define free_resource(_res, type, Type) \
  204. + do { \
  205. + if (!(_res)->type##s) \
  206. + break; \
  207. + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \
  208. + if (!(_res)->type##s[i].type) \
  209. + break; \
  210. + drmModeFree##Type((_res)->type##s[i].type); \
  211. + } \
  212. + free((_res)->type##s); \
  213. + } while (0)
  214. +
  215. +#define free_properties(_res, type) \
  216. + do { \
  217. + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \
  218. + unsigned int j; \
  219. + for (j = 0; j < res->type##s[i].props->count_props; ++j)\
  220. + drmModeFreeProperty(res->type##s[i].props_info[j]);\
  221. + free(res->type##s[i].props_info); \
  222. + drmModeFreeObjectProperties(res->type##s[i].props); \
  223. + } \
  224. + } while (0)
  225. +
  226. + free_properties(res, plane);
  227. + free_resource(res, plane, Plane);
  228. +
  229. + free_properties(res, connector);
  230. + free_properties(res, crtc);
  231. +
  232. + for (i = 0; i < res->count_connectors; i++)
  233. + free(res->connectors[i].name);
  234. +
  235. + free_resource(res, fb, FB);
  236. + free_resource(res, connector, Connector);
  237. + free_resource(res, encoder, Encoder);
  238. + free_resource(res, crtc, Crtc);
  239. +
  240. + free(res);
  241. +}
  242. +
  243. +struct type_name {
  244. + unsigned int type;
  245. + const char *name;
  246. +};
  247. +
  248. +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
  249. +
  250. +static const char *util_lookup_type_name(unsigned int type,
  251. + const struct type_name *table,
  252. + unsigned int count)
  253. +{
  254. + unsigned int i;
  255. +
  256. + for (i = 0; i < count; i++)
  257. + if (table[i].type == type)
  258. + return table[i].name;
  259. +
  260. + return NULL;
  261. +}
  262. +
  263. +static const struct type_name connector_type_names[] = {
  264. + { DRM_MODE_CONNECTOR_Unknown, "unknown" },
  265. + { DRM_MODE_CONNECTOR_VGA, "VGA" },
  266. + { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
  267. + { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
  268. + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
  269. + { DRM_MODE_CONNECTOR_Composite, "composite" },
  270. + { DRM_MODE_CONNECTOR_SVIDEO, "s-video" },
  271. + { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
  272. + { DRM_MODE_CONNECTOR_Component, "component" },
  273. + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" },
  274. + { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
  275. + { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
  276. + { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
  277. + { DRM_MODE_CONNECTOR_TV, "TV" },
  278. + { DRM_MODE_CONNECTOR_eDP, "eDP" },
  279. + { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
  280. + { DRM_MODE_CONNECTOR_DSI, "DSI" },
  281. + { DRM_MODE_CONNECTOR_DPI, "DPI" },
  282. +};
  283. +
  284. +static const char *util_lookup_connector_type_name(unsigned int type)
  285. +{
  286. + return util_lookup_type_name(type, connector_type_names,
  287. + ARRAY_SIZE(connector_type_names));
  288. +}
  289. +
  290. +static struct resources *get_resources(struct device *dev)
  291. +{
  292. + drmModeRes *_res;
  293. + drmModePlaneRes *plane_res;
  294. + struct resources *res;
  295. + int i;
  296. +
  297. + res = calloc(1, sizeof(*res));
  298. + if (res == 0)
  299. + return NULL;
  300. +
  301. + drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
  302. +
  303. + _res = drmModeGetResources(dev->fd);
  304. + if (!_res) {
  305. + fprintf(stderr, "drmModeGetResources failed: %s\n",
  306. + strerror(errno));
  307. + free(res);
  308. + return NULL;
  309. + }
  310. +
  311. + res->count_crtcs = _res->count_crtcs;
  312. + res->count_encoders = _res->count_encoders;
  313. + res->count_connectors = _res->count_connectors;
  314. + res->count_fbs = _res->count_fbs;
  315. +
  316. + res->crtcs = calloc(res->count_crtcs, sizeof(*res->crtcs));
  317. + res->encoders = calloc(res->count_encoders, sizeof(*res->encoders));
  318. + res->connectors = calloc(res->count_connectors, sizeof(*res->connectors));
  319. + res->fbs = calloc(res->count_fbs, sizeof(*res->fbs));
  320. +
  321. + if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs) {
  322. + drmModeFreeResources(_res);
  323. + goto error;
  324. + }
  325. +
  326. +#define get_resource(_res, __res, type, Type) \
  327. + do { \
  328. + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \
  329. + uint32_t type##id = (__res)->type##s[i]; \
  330. + (_res)->type##s[i].type = \
  331. + drmModeGet##Type(dev->fd, type##id); \
  332. + if (!(_res)->type##s[i].type) \
  333. + fprintf(stderr, "could not get %s %i: %s\n", \
  334. + #type, type##id, \
  335. + strerror(errno)); \
  336. + } \
  337. + } while (0)
  338. +
  339. + get_resource(res, _res, crtc, Crtc);
  340. + get_resource(res, _res, encoder, Encoder);
  341. + get_resource(res, _res, connector, Connector);
  342. + get_resource(res, _res, fb, FB);
  343. +
  344. + drmModeFreeResources(_res);
  345. +
  346. + /* Set the name of all connectors based on the type name and the per-type ID. */
  347. + for (i = 0; i < res->count_connectors; i++) {
  348. + struct connector *connector = &res->connectors[i];
  349. + drmModeConnector *conn = connector->connector;
  350. + int num;
  351. +
  352. + num = asprintf(&connector->name, "%s-%u",
  353. + util_lookup_connector_type_name(conn->connector_type),
  354. + conn->connector_type_id);
  355. + if (num < 0)
  356. + goto error;
  357. + }
  358. +
  359. +#define get_properties(_res, type, Type) \
  360. + do { \
  361. + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \
  362. + struct type *obj = &res->type##s[i]; \
  363. + unsigned int j; \
  364. + obj->props = \
  365. + drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \
  366. + DRM_MODE_OBJECT_##Type); \
  367. + if (!obj->props) { \
  368. + fprintf(stderr, \
  369. + "could not get %s %i properties: %s\n", \
  370. + #type, obj->type->type##_id, \
  371. + strerror(errno)); \
  372. + continue; \
  373. + } \
  374. + obj->props_info = calloc(obj->props->count_props, \
  375. + sizeof(*obj->props_info)); \
  376. + if (!obj->props_info) \
  377. + continue; \
  378. + for (j = 0; j < obj->props->count_props; ++j) \
  379. + obj->props_info[j] = \
  380. + drmModeGetProperty(dev->fd, obj->props->props[j]); \
  381. + } \
  382. + } while (0)
  383. +
  384. + get_properties(res, crtc, CRTC);
  385. + get_properties(res, connector, CONNECTOR);
  386. +
  387. + for (i = 0; i < res->count_crtcs; ++i)
  388. + res->crtcs[i].mode = &res->crtcs[i].crtc->mode;
  389. +
  390. + plane_res = drmModeGetPlaneResources(dev->fd);
  391. + if (!plane_res) {
  392. + fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
  393. + strerror(errno));
  394. + return res;
  395. + }
  396. +
  397. + res->count_planes = plane_res->count_planes;
  398. +
  399. + res->planes = calloc(res->count_planes, sizeof(*res->planes));
  400. + if (!res->planes) {
  401. + drmModeFreePlaneResources(plane_res);
  402. + goto error;
  403. + }
  404. +
  405. + get_resource(res, plane_res, plane, Plane);
  406. + drmModeFreePlaneResources(plane_res);
  407. + get_properties(res, plane, PLANE);
  408. +
  409. + return res;
  410. +
  411. +error:
  412. + free_resources(res);
  413. + return NULL;
  414. +}
  415. +
  416. +static struct crtc *get_crtc_by_id(struct device *dev, uint32_t id)
  417. +{
  418. + int i;
  419. +
  420. + for (i = 0; i < dev->resources->count_crtcs; ++i) {
  421. + drmModeCrtc *crtc = dev->resources->crtcs[i].crtc;
  422. + if (crtc && crtc->crtc_id == id)
  423. + return &dev->resources->crtcs[i];
  424. + }
  425. +
  426. + return NULL;
  427. +}
  428. +
  429. +static uint32_t get_crtc_mask(struct device *dev, struct crtc *crtc)
  430. +{
  431. + unsigned int i;
  432. +
  433. + for (i = 0; i < (unsigned int)dev->resources->count_crtcs; i++) {
  434. + if (crtc->crtc->crtc_id == dev->resources->crtcs[i].crtc->crtc_id)
  435. + return 1 << i;
  436. + }
  437. + /* Unreachable: crtc->crtc is one of resources->crtcs[] */
  438. + /* Don't return zero or static analysers will complain */
  439. + abort();
  440. + return 0;
  441. +}
  442. +
  443. +static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id)
  444. +{
  445. + drmModeConnector *connector;
  446. + int i;
  447. +
  448. + for (i = 0; i < dev->resources->count_connectors; i++) {
  449. + connector = dev->resources->connectors[i].connector;
  450. + if (connector && connector->connector_id == id)
  451. + return connector;
  452. + }
  453. +
  454. + return NULL;
  455. +}
  456. +
  457. +static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id)
  458. +{
  459. + drmModeEncoder *encoder;
  460. + int i;
  461. +
  462. + for (i = 0; i < dev->resources->count_encoders; i++) {
  463. + encoder = dev->resources->encoders[i].encoder;
  464. + if (encoder && encoder->encoder_id == id)
  465. + return encoder;
  466. + }
  467. +
  468. + return NULL;
  469. +}
  470. +
  471. +/* -----------------------------------------------------------------------------
  472. + * Pipes and planes
  473. + */
  474. +
  475. +/*
  476. + * Mode setting with the kernel interfaces is a bit of a chore.
  477. + * First you have to find the connector in question and make sure the
  478. + * requested mode is available.
  479. + * Then you need to find the encoder attached to that connector so you
  480. + * can bind it with a free crtc.
  481. + */
  482. +struct pipe_arg {
  483. + const char **cons;
  484. + uint32_t *con_ids;
  485. + unsigned int num_cons;
  486. + uint32_t crtc_id;
  487. + char mode_str[64];
  488. + char format_str[5];
  489. + float vrefresh;
  490. + unsigned int fourcc;
  491. + drmModeModeInfo *mode;
  492. + struct crtc *crtc;
  493. + unsigned int fb_id[2], current_fb_id;
  494. + struct timeval start;
  495. +
  496. + int swap_count;
  497. +};
  498. +
  499. +struct plane_arg {
  500. + uint32_t plane_id; /* the id of plane to use */
  501. + uint32_t crtc_id; /* the id of CRTC to bind to */
  502. + bool has_position;
  503. + int32_t x, y;
  504. + uint32_t w, h;
  505. + double scale;
  506. + unsigned int fb_id;
  507. + unsigned int old_fb_id;
  508. + struct bo *bo;
  509. + struct bo *old_bo;
  510. + char format_str[5]; /* need to leave room for terminating \0 */
  511. + unsigned int fourcc;
  512. +};
  513. +
  514. +static drmModeModeInfo *
  515. +connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str,
  516. + const float vrefresh)
  517. +{
  518. + drmModeConnector *connector;
  519. + drmModeModeInfo *mode;
  520. + int i;
  521. +
  522. + connector = get_connector_by_id(dev, con_id);
  523. + if (!connector || !connector->count_modes)
  524. + return NULL;
  525. +
  526. + /* Pick by Index */
  527. + if (mode_str[0] == '#') {
  528. + int index = atoi(mode_str + 1);
  529. +
  530. + if (index >= connector->count_modes || index < 0)
  531. + return NULL;
  532. + return &connector->modes[index];
  533. + }
  534. +
  535. + /* Pick by Name */
  536. + for (i = 0; i < connector->count_modes; i++) {
  537. + mode = &connector->modes[i];
  538. + if (!strcmp(mode->name, mode_str)) {
  539. + /* If the vertical refresh frequency is not specified
  540. + * then return the first mode that match with the name.
  541. + * Else, return the mode that match the name and
  542. + * the specified vertical refresh frequency.
  543. + */
  544. + if (vrefresh == 0)
  545. + return mode;
  546. + else if (fabs(mode_vrefresh(mode) - vrefresh) < 0.005)
  547. + return mode;
  548. + }
  549. + }
  550. +
  551. + return NULL;
  552. +}
  553. +
  554. +static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe)
  555. +{
  556. + uint32_t possible_crtcs = ~0;
  557. + uint32_t active_crtcs = 0;
  558. + unsigned int crtc_idx;
  559. + unsigned int i;
  560. + int j;
  561. +
  562. + for (i = 0; i < pipe->num_cons; ++i) {
  563. + uint32_t crtcs_for_connector = 0;
  564. + drmModeConnector *connector;
  565. + drmModeEncoder *encoder;
  566. + struct crtc *crtc;
  567. +
  568. + connector = get_connector_by_id(dev, pipe->con_ids[i]);
  569. + if (!connector)
  570. + return NULL;
  571. +
  572. + for (j = 0; j < connector->count_encoders; ++j) {
  573. + encoder = get_encoder_by_id(dev, connector->encoders[j]);
  574. + if (!encoder)
  575. + continue;
  576. +
  577. + crtcs_for_connector |= encoder->possible_crtcs;
  578. + crtc = get_crtc_by_id(dev, encoder->crtc_id);
  579. + if (!crtc)
  580. + continue;
  581. + active_crtcs |= get_crtc_mask(dev, crtc);
  582. + }
  583. +
  584. + possible_crtcs &= crtcs_for_connector;
  585. + }
  586. +
  587. + if (!possible_crtcs)
  588. + return NULL;
  589. +
  590. + /* Return the first possible and active CRTC if one exists, or the first
  591. + * possible CRTC otherwise.
  592. + */
  593. + if (possible_crtcs & active_crtcs)
  594. + crtc_idx = ffs(possible_crtcs & active_crtcs);
  595. + else
  596. + crtc_idx = ffs(possible_crtcs);
  597. +
  598. + return &dev->resources->crtcs[crtc_idx - 1];
  599. +}
  600. +
  601. +static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe)
  602. +{
  603. + drmModeModeInfo *mode = NULL;
  604. + int i;
  605. +
  606. + pipe->mode = NULL;
  607. +
  608. + for (i = 0; i < (int)pipe->num_cons; i++) {
  609. + mode = connector_find_mode(dev, pipe->con_ids[i],
  610. + pipe->mode_str, pipe->vrefresh);
  611. + if (mode == NULL) {
  612. + if (pipe->vrefresh)
  613. + fprintf(stderr,
  614. + "failed to find mode "
  615. + "\"%s-%.2fHz\" for connector %d\n",
  616. + pipe->mode_str, pipe->vrefresh, pipe->con_ids[i]);
  617. + else
  618. + fprintf(stderr,
  619. + "failed to find mode \"%s\" for connector %d\n",
  620. + pipe->mode_str, pipe->con_ids[i]);
  621. + return -EINVAL;
  622. + }
  623. + }
  624. +
  625. + /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise
  626. + * locate a CRTC that can be attached to all the connectors.
  627. + */
  628. + if (pipe->crtc_id != (uint32_t)-1) {
  629. + pipe->crtc = get_crtc_by_id(dev, pipe->crtc_id);
  630. + } else {
  631. + pipe->crtc = pipe_find_crtc(dev, pipe);
  632. + pipe->crtc_id = pipe->crtc->crtc->crtc_id;
  633. + }
  634. +
  635. + if (!pipe->crtc) {
  636. + fprintf(stderr, "failed to find CRTC for pipe\n");
  637. + return -EINVAL;
  638. + }
  639. +
  640. + pipe->mode = mode;
  641. + pipe->crtc->mode = mode;
  642. +
  643. + return 0;
  644. +}
  645. +
  646. +/* -----------------------------------------------------------------------------
  647. + * Properties
  648. + */
  649. +
  650. +struct property_arg {
  651. + uint32_t obj_id;
  652. + uint32_t obj_type;
  653. + char name[DRM_PROP_NAME_LEN+1];
  654. + uint32_t prop_id;
  655. + uint64_t value;
  656. + bool optional;
  657. +};
  658. +
  659. +static bool set_property(struct device *dev, struct property_arg *p)
  660. +{
  661. + drmModeObjectProperties *props = NULL;
  662. + drmModePropertyRes **props_info = NULL;
  663. + const char *obj_type;
  664. + int ret;
  665. + int i;
  666. +
  667. + p->obj_type = 0;
  668. + p->prop_id = 0;
  669. +
  670. +#define find_object(_res, type, Type) \
  671. + do { \
  672. + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \
  673. + struct type *obj = &(_res)->type##s[i]; \
  674. + if (obj->type->type##_id != p->obj_id) \
  675. + continue; \
  676. + p->obj_type = DRM_MODE_OBJECT_##Type; \
  677. + obj_type = #Type; \
  678. + props = obj->props; \
  679. + props_info = obj->props_info; \
  680. + } \
  681. + } while(0) \
  682. +
  683. + find_object(dev->resources, crtc, CRTC);
  684. + if (p->obj_type == 0)
  685. + find_object(dev->resources, connector, CONNECTOR);
  686. + if (p->obj_type == 0)
  687. + find_object(dev->resources, plane, PLANE);
  688. + if (p->obj_type == 0) {
  689. + fprintf(stderr, "Object %i not found, can't set property\n",
  690. + p->obj_id);
  691. + return false;
  692. + }
  693. +
  694. + if (!props) {
  695. + fprintf(stderr, "%s %i has no properties\n",
  696. + obj_type, p->obj_id);
  697. + return false;
  698. + }
  699. +
  700. + for (i = 0; i < (int)props->count_props; ++i) {
  701. + if (!props_info[i])
  702. + continue;
  703. + if (strcmp(props_info[i]->name, p->name) == 0)
  704. + break;
  705. + }
  706. +
  707. + if (i == (int)props->count_props) {
  708. + if (!p->optional)
  709. + fprintf(stderr, "%s %i has no %s property\n",
  710. + obj_type, p->obj_id, p->name);
  711. + return false;
  712. + }
  713. +
  714. + p->prop_id = props->props[i];
  715. +
  716. + if (!dev->use_atomic)
  717. + ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type,
  718. + p->prop_id, p->value);
  719. + else
  720. + ret = drmModeAtomicAddProperty(dev->req, p->obj_id, p->prop_id, p->value);
  721. +
  722. + if (ret < 0)
  723. + fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n",
  724. + obj_type, p->obj_id, p->name, p->value, strerror(errno));
  725. +
  726. + return true;
  727. +}
  728. +
  729. +/* -------------------------------------------------------------------------- */
  730. +
  731. +static void add_property(struct device *dev, uint32_t obj_id,
  732. + const char *name, uint64_t value)
  733. +{
  734. + struct property_arg p;
  735. +
  736. + p.obj_id = obj_id;
  737. + strcpy(p.name, name);
  738. + p.value = value;
  739. +
  740. + set_property(dev, &p);
  741. +}
  742. +
  743. +static bool add_property_optional(struct device *dev, uint32_t obj_id,
  744. + const char *name, uint64_t value)
  745. +{
  746. + struct property_arg p;
  747. +
  748. + p.obj_id = obj_id;
  749. + strcpy(p.name, name);
  750. + p.value = value;
  751. + p.optional = true;
  752. +
  753. + return set_property(dev, &p);
  754. +}
  755. +
  756. +static void util_smpte_c8_gamma(unsigned size, struct drm_color_lut *lut)
  757. +{
  758. + if (size < 7 + 7 + 8) {
  759. + printf("Error: gamma too small: %d < %d\n", size, 7 + 7 + 8);
  760. + return;
  761. + }
  762. + memset(lut, 0, size * sizeof(struct drm_color_lut));
  763. +
  764. +#define FILL_COLOR(idx, r, g, b) \
  765. + lut[idx].red = (r) << 8; \
  766. + lut[idx].green = (g) << 8; \
  767. + lut[idx].blue = (b) << 8
  768. +
  769. + FILL_COLOR( 0, 192, 192, 192); /* grey */
  770. + FILL_COLOR( 1, 192, 192, 0 ); /* yellow */
  771. + FILL_COLOR( 2, 0, 192, 192); /* cyan */
  772. + FILL_COLOR( 3, 0, 192, 0 ); /* green */
  773. + FILL_COLOR( 4, 192, 0, 192); /* magenta */
  774. + FILL_COLOR( 5, 192, 0, 0 ); /* red */
  775. + FILL_COLOR( 6, 0, 0, 192); /* blue */
  776. +
  777. + FILL_COLOR( 7, 0, 0, 192); /* blue */
  778. + FILL_COLOR( 8, 19, 19, 19 ); /* black */
  779. + FILL_COLOR( 9, 192, 0, 192); /* magenta */
  780. + FILL_COLOR(10, 19, 19, 19 ); /* black */
  781. + FILL_COLOR(11, 0, 192, 192); /* cyan */
  782. + FILL_COLOR(12, 19, 19, 19 ); /* black */
  783. + FILL_COLOR(13, 192, 192, 192); /* grey */
  784. +
  785. + FILL_COLOR(14, 0, 33, 76); /* in-phase */
  786. + FILL_COLOR(15, 255, 255, 255); /* super white */
  787. + FILL_COLOR(16, 50, 0, 106); /* quadrature */
  788. + FILL_COLOR(17, 19, 19, 19); /* black */
  789. + FILL_COLOR(18, 9, 9, 9); /* 3.5% */
  790. + FILL_COLOR(19, 19, 19, 19); /* 7.5% */
  791. + FILL_COLOR(20, 29, 29, 29); /* 11.5% */
  792. + FILL_COLOR(21, 19, 19, 19); /* black */
  793. +
  794. +#undef FILL_COLOR
  795. +}
  796. +
  797. +static void set_gamma(struct device *dev, unsigned crtc_id, unsigned fourcc)
  798. +{
  799. + unsigned blob_id = 0;
  800. + /* TODO: support 1024-sized LUTs, when the use-case arises */
  801. + struct drm_color_lut gamma_lut[256];
  802. + int i, ret;
  803. +
  804. + if (fourcc == DRM_FORMAT_C8) {
  805. + /* TODO: Add C8 support for more patterns */
  806. + util_smpte_c8_gamma(256, gamma_lut);
  807. + drmModeCreatePropertyBlob(dev->fd, gamma_lut, sizeof(gamma_lut), &blob_id);
  808. + } else {
  809. + for (i = 0; i < 256; i++) {
  810. + gamma_lut[i].red =
  811. + gamma_lut[i].green =
  812. + gamma_lut[i].blue = i << 8;
  813. + }
  814. + }
  815. +
  816. + add_property_optional(dev, crtc_id, "DEGAMMA_LUT", 0);
  817. + add_property_optional(dev, crtc_id, "CTM", 0);
  818. + if (!add_property_optional(dev, crtc_id, "GAMMA_LUT", blob_id)) {
  819. + uint16_t r[256], g[256], b[256];
  820. +
  821. + for (i = 0; i < 256; i++) {
  822. + r[i] = gamma_lut[i].red;
  823. + g[i] = gamma_lut[i].green;
  824. + b[i] = gamma_lut[i].blue;
  825. + }
  826. +
  827. + ret = drmModeCrtcSetGamma(dev->fd, crtc_id, 256, r, g, b);
  828. + if (ret)
  829. + fprintf(stderr, "failed to set gamma: %s\n", strerror(errno));
  830. + }
  831. +}
  832. +
  833. +static void atomic_set_planes(struct device *dev, struct plane_arg *p,
  834. + unsigned int count)
  835. +{
  836. + if (p && (count > 0))
  837. + set_gamma(dev, p[0].crtc_id, p[0].fourcc);
  838. +}
  839. +
  840. +static void atomic_clear_planes(struct device *dev, struct plane_arg *p, unsigned int count)
  841. +{
  842. + unsigned int i;
  843. +
  844. + for (i = 0; i < count; i++) {
  845. + add_property(dev, p[i].plane_id, "FB_ID", 0);
  846. + add_property(dev, p[i].plane_id, "CRTC_ID", 0);
  847. + add_property(dev, p[i].plane_id, "SRC_X", 0);
  848. + add_property(dev, p[i].plane_id, "SRC_Y", 0);
  849. + add_property(dev, p[i].plane_id, "SRC_W", 0);
  850. + add_property(dev, p[i].plane_id, "SRC_H", 0);
  851. + add_property(dev, p[i].plane_id, "CRTC_X", 0);
  852. + add_property(dev, p[i].plane_id, "CRTC_Y", 0);
  853. + add_property(dev, p[i].plane_id, "CRTC_W", 0);
  854. + add_property(dev, p[i].plane_id, "CRTC_H", 0);
  855. + }
  856. +}
  857. +
  858. +static void atomic_clear_FB(struct device *dev, struct plane_arg *p, unsigned int count)
  859. +{
  860. + unsigned int i;
  861. +
  862. + for (i = 0; i < count; i++) {
  863. + if (p[i].fb_id) {
  864. + drmModeRmFB(dev->fd, p[i].fb_id);
  865. + p[i].fb_id = 0;
  866. + }
  867. + if (p[i].old_fb_id) {
  868. + drmModeRmFB(dev->fd, p[i].old_fb_id);
  869. + p[i].old_fb_id = 0;
  870. + }
  871. + }
  872. +}
  873. +
  874. +static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
  875. +{
  876. + unsigned int i, j;
  877. + int ret;
  878. +
  879. + for (i = 0; i < count; i++) {
  880. + struct pipe_arg *pipe = &pipes[i];
  881. + ret = pipe_find_crtc_and_mode(dev, pipe);
  882. + if (ret < 0)
  883. + continue;
  884. + }
  885. +
  886. + for (i = 0; i < count; i++) {
  887. + struct pipe_arg *pipe = &pipes[i];
  888. + uint32_t blob_id;
  889. +
  890. + if (pipe->mode == NULL)
  891. + continue;
  892. +
  893. + for (j = 0; j < pipe->num_cons; ++j) {
  894. + add_property(dev, pipe->con_ids[j], "CRTC_ID", pipe->crtc_id);
  895. + }
  896. +
  897. + drmModeCreatePropertyBlob(dev->fd, pipe->mode, sizeof(*pipe->mode), &blob_id);
  898. + add_property(dev, pipe->crtc_id, "MODE_ID", blob_id);
  899. + add_property(dev, pipe->crtc_id, "ACTIVE", 1);
  900. + }
  901. +}
  902. +
  903. +static void atomic_clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
  904. +{
  905. + unsigned int i;
  906. + unsigned int j;
  907. +
  908. + for (i = 0; i < count; i++) {
  909. + struct pipe_arg *pipe = &pipes[i];
  910. +
  911. + if (pipe->mode == NULL)
  912. + continue;
  913. +
  914. + for (j = 0; j < pipe->num_cons; ++j)
  915. + add_property(dev, pipe->con_ids[j], "CRTC_ID",0);
  916. +
  917. + add_property(dev, pipe->crtc_id, "MODE_ID", 0);
  918. + add_property(dev, pipe->crtc_id, "ACTIVE", 0);
  919. + }
  920. +}
  921. +
  922. +int
  923. +gst_kms_sink_reset_drm(GstKMSSink * self)
  924. +{
  925. + int ret = -1;
  926. + struct device dev;
  927. + uint64_t cap = 0;
  928. +
  929. + const unsigned int connector_count = 1, plane_count = 1;
  930. + struct pipe_arg pipe_args[1];
  931. + struct plane_arg plane_args[1];
  932. + uint32_t connectors[1];
  933. + GValueArray *formats = NULL;
  934. + GstStructure *st = NULL;
  935. +
  936. + if (!self || (self->fd < 0))
  937. + return ret;
  938. +
  939. + memset (&dev, 0, sizeof(dev));
  940. + memset (&plane_args, 0, sizeof(*plane_args));
  941. + memset (&pipe_args, 0, sizeof(*pipe_args));
  942. +
  943. + dev.fd = self->fd;
  944. + ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1);
  945. + if (ret) {
  946. + fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno));
  947. + goto out;
  948. + }
  949. +
  950. + ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap);
  951. + if (ret || cap == 0) {
  952. + fprintf(stderr, "driver doesn't support the dumb buffer API\n");
  953. + goto out;
  954. + }
  955. +
  956. + dev.use_atomic = 1;
  957. + dev.resources = get_resources(&dev);
  958. + if (!dev.resources)
  959. + goto out;
  960. +
  961. + plane_args[0].plane_id = self->plane_id; /* the id of plane to use */
  962. + plane_args[0].crtc_id = self->crtc_id; /* the id of CRTC to bind to */
  963. + plane_args[0].w = self->render_rect.w;
  964. + plane_args[0].h = self->render_rect.h;
  965. + plane_args[0].scale = 1.0;
  966. + strncpy(plane_args[0].format_str, "NV12", 4);
  967. +
  968. + /* Find the first supported format and also has correct FOURCC value. */
  969. + st = gst_caps_get_structure(self->allowed_caps, 0);
  970. + if (st && gst_structure_get_list (st, "format", &formats)) {
  971. + for (int i = 0; formats && (i < formats->n_values); ++i) {
  972. + const gchar *format = g_value_get_string(g_value_array_get_nth(formats, i));
  973. + if (format && (gst_video_format_to_fourcc(gst_video_format_from_string(format)) != 0)) {
  974. + strncpy(plane_args[0].format_str, format, 4);
  975. + break;
  976. + }
  977. + }
  978. +
  979. + g_value_array_free(formats);
  980. + formats = NULL;
  981. + }
  982. +
  983. + plane_args[0].fourcc = gst_video_format_to_fourcc(gst_video_format_from_string(plane_args[0].format_str));
  984. +
  985. + connectors[0] = self->conn_id;
  986. + pipe_args[0].con_ids = connectors;
  987. + pipe_args[0].num_cons = connector_count;
  988. + pipe_args[0].crtc_id = self->crtc_id;
  989. + strncpy(pipe_args[0].format_str, plane_args[0].format_str, 4);
  990. + pipe_args[0].fourcc = plane_args[0].fourcc;
  991. + snprintf(pipe_args[0].mode_str, sizeof(pipe_args[0].mode_str), "%dx%d", plane_args[0].w, plane_args[0].h);
  992. +
  993. + dev.req = drmModeAtomicAlloc();
  994. + set_mode(&dev, pipe_args, connector_count);
  995. + atomic_set_planes(&dev, plane_args, plane_count);
  996. + ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
  997. + if (ret) {
  998. + fprintf(stderr, "Atomic Commit failed [1]\n");
  999. + goto out;
  1000. + }
  1001. +
  1002. + // clear
  1003. + atomic_clear_planes(&dev, plane_args, plane_count);
  1004. + atomic_clear_mode(&dev, pipe_args, connector_count);
  1005. + ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
  1006. + if (ret)
  1007. + fprintf(stderr, "Atomic Commit failed\n");
  1008. + atomic_clear_FB(&dev, plane_args, plane_count);
  1009. + drmModeAtomicFree(dev.req);
  1010. + ret = 0;
  1011. +
  1012. +out:
  1013. + free_resources(dev.resources);
  1014. +
  1015. + ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 0);
  1016. + if (ret)
  1017. + fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno));
  1018. +
  1019. + return ret;
  1020. +}