composer.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. #include "composer.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <sys/stat.h>
  6. #include <sys/mman.h>
  7. #include <sys/ioctl.h>
  8. #include <fcntl.h>
  9. #include <errno.h>
  10. #include <unistd.h>
  11. #include <time.h>
  12. #include <sys/time.h>
  13. #include <linux/dma-buf.h>
  14. #include <rga/im2d.h>
  15. #include <rga/rga.h>
  16. int dma_heap_alloc(const char *heap_name, size_t size, int *fd);
  17. #define MAX_TILES 25
  18. typedef struct {
  19. int x, y, w, h;
  20. } TileRect;
  21. /* Cache of RGA-imported dmabuf handles. importbuffer_fd/releasebuffer_handle
  22. * are driver round-trips; doing both per tile per frame costs measurable CPU.
  23. * Each entry keeps its own dup'd fd so the fd number can never be recycled
  24. * and alias a different buffer while cached.
  25. *
  26. * DRIVER LIMIT: the RGA driver only keeps a bounded number of imported
  27. * handles; once that table is full every new importbuffer_fd returns EINVAL
  28. * (and never makes it into the cache, so the table stays full forever =
  29. * permanent black tiles). The cache size must stay well below the driver
  30. * table limit so a fresh import always has a free slot. 128 was observed to
  31. * wedge the table on 8 RV-streams; 64 still failed on the live site; 32 keeps
  32. * every buffer that is *currently being blitted* cached (the LRU re-imports
  33. * the rest) while leaving the driver table mostly empty. */
  34. typedef struct {
  35. int fd; /* our own dup (never the caller's fd) */
  36. ino_t ino; /* dmabuf anon-inode identity */
  37. int w, h, stride, vstride;
  38. rga_buffer_handle_t handle;
  39. uint64_t last_use;
  40. } RgaCacheEnt;
  41. #define RGA_CACHE_SIZE 32
  42. struct Composer {
  43. int output_w;
  44. int output_h;
  45. int num_streams;
  46. int letterbox;
  47. TileRect tiles[MAX_TILES];
  48. RgaCacheEnt rga_cache[RGA_CACHE_SIZE];
  49. uint64_t rga_clock;
  50. /* Per-tile health counters for diagnosing flicker: a tile that fails to
  51. * import its source buffer keeps the dark clear = a black flashing tile. */
  52. uint64_t src_ok[MAX_TILES];
  53. uint64_t src_import_fail[MAX_TILES];
  54. uint64_t src_improcess_fail[MAX_TILES];
  55. uint64_t dst_fail;
  56. /* Emergency low-address mirror per tile (invalid <= 0). See comment
  57. * on mirror_refresh(). */
  58. int mirror_fd[MAX_TILES];
  59. uint64_t mirror_hits;
  60. };
  61. int composer_grid_rects(int out_w, int out_h, int n,
  62. int *xs, int *ys, int *ws, int *hs, int y_off) {
  63. if (!xs || !ys || !ws || !hs) return -1;
  64. if (n < 0) n = 0;
  65. if (n > MAX_TILES) n = MAX_TILES;
  66. if (y_off < 0) y_off = 0;
  67. if (y_off > out_h) y_off = out_h;
  68. int usable_h = out_h - y_off;
  69. int cols = 1, rows = 1;
  70. if (n <= 1) {
  71. cols = 1; rows = 1;
  72. } else if (n <= 2) {
  73. cols = 2; rows = 1;
  74. } else if (n <= 4) {
  75. cols = 2; rows = 2;
  76. } else if (n <= 6) {
  77. cols = 3; rows = 2;
  78. } else if (n <= 9) {
  79. cols = 3; rows = 3;
  80. } else if (n <= 12) {
  81. cols = 4; rows = 3;
  82. } else if (n <= 16) {
  83. cols = 4; rows = 4;
  84. } else {
  85. cols = 5; rows = 5;
  86. }
  87. int grid_w = out_w / cols;
  88. int grid_h = usable_h / rows;
  89. if (grid_h < 1) grid_h = 1;
  90. for (int i = 0; i < n; i++) {
  91. int col = i % cols;
  92. int row = i / cols;
  93. int w = grid_w;
  94. int h = grid_h;
  95. /* Edge column/row extends to the output edge. */
  96. if (col == cols - 1) w = out_w - col * grid_w;
  97. if (row == rows - 1) h = out_h - y_off - row * grid_h;
  98. xs[i] = col * grid_w;
  99. ys[i] = y_off + row * grid_h;
  100. ws[i] = w;
  101. hs[i] = h;
  102. }
  103. return n;
  104. }
  105. int composer_flow_rects(int out_w, int out_h, const int *row_cols, int nrows,
  106. int *xs, int *ys, int *ws, int *hs, int y_off) {
  107. if (!row_cols || !xs || !ys || !ws || !hs) return -1;
  108. if (nrows <= 0) return 0;
  109. if (nrows > MAX_TILES) nrows = MAX_TILES;
  110. if (y_off < 0) y_off = 0;
  111. if (y_off > out_h) y_off = out_h;
  112. int usable_h = out_h - y_off;
  113. if (usable_h <= 0) return 0;
  114. int total = 0;
  115. for (int r = 0; r < nrows; r++) {
  116. if (row_cols[r] <= 0) continue;
  117. total += row_cols[r];
  118. }
  119. if (total <= 0) return 0;
  120. if (total > MAX_TILES) return -1;
  121. /* Row heights: inversely proportional to the number of cells in the row,
  122. * so a row with fewer cells ends up taller (a 1-cell "main" row + a
  123. * multi-cell "thumbnail" row is the common case). The last row always
  124. * extends to the bottom edge so the canvas is fully filled. Each row
  125. * height is forced even (NV12 needs even row strides). */
  126. int *rh = NULL;
  127. double *wcol = NULL;
  128. if (nrows > 1) {
  129. rh = calloc((size_t)nrows, sizeof(int));
  130. wcol = calloc((size_t)nrows, sizeof(double));
  131. if (!rh || !wcol) { free(rh); free(wcol); return -1; }
  132. double wsum = 0.0;
  133. for (int r = 0; r < nrows; r++)
  134. if (row_cols[r] > 0) { wcol[r] = 1.0 / (double)row_cols[r]; wsum += wcol[r]; }
  135. if (wsum <= 0.0) { free(rh); free(wcol); return 0; }
  136. /* All rows except the last: proportional to 1/cols, rounded even,
  137. * leaving room for the last row to take whatever is left. */
  138. int sum = 0;
  139. for (int r = 0; r < nrows - 1; r++) {
  140. if (row_cols[r] <= 0) { rh[r] = 0; continue; }
  141. int h = (int)(usable_h * wcol[r] / wsum);
  142. if (h & 1) h--;
  143. if (h < 2) h = 2;
  144. rh[r] = h;
  145. sum += h;
  146. }
  147. /* Last row fills exactly the remaining height (full canvas). */
  148. int last_h = usable_h - sum;
  149. if (last_h & 1) {
  150. last_h++;
  151. for (int r = nrows - 2; r >= 0 && (last_h & 1); r--)
  152. if (rh[r] > 2) { rh[r] -= 2; last_h += 2; }
  153. }
  154. if (last_h < 2 && row_cols[nrows - 1] > 0) last_h = 2;
  155. rh[nrows - 1] = last_h;
  156. }
  157. int idx = 0;
  158. int y = y_off;
  159. for (int r = 0; r < nrows; r++) {
  160. int cols = row_cols[r];
  161. int rheight = rh ? rh[r] : (usable_h - (y - y_off)); /* single row: fill all */
  162. if (cols <= 0 || rheight < 2) continue;
  163. if (r == nrows - 1) rheight = usable_h - (y - y_off); /* last row to bottom edge */
  164. for (int c = 0; c < cols; c++) {
  165. int w = out_w / cols;
  166. int x = c * w;
  167. if (c == cols - 1) w = out_w - x; /* last cell to right edge */
  168. if (w < 2) w = 2;
  169. if (x < 0) x = 0;
  170. xs[idx] = x;
  171. ys[idx] = y;
  172. ws[idx] = w;
  173. hs[idx] = rheight;
  174. idx++;
  175. }
  176. y += rheight;
  177. }
  178. free(wcol);
  179. free(rh);
  180. return idx;
  181. }
  182. int composer_split_rects(int out_w, int out_h, int y_off,
  183. const int *top_ids, int top_n, double top_ratio,
  184. const int *bottom_ids, int bottom_n,
  185. int actual_bottom,
  186. int *xs, int *ys, int *ws, int *hs, int *sid) {
  187. if (!top_ids || !bottom_ids || !xs || !ys || !ws || !hs || !sid) return -1;
  188. if (top_n <= 0 || top_n > MAX_TILES) return -1;
  189. if (y_off < 0) y_off = 0;
  190. if (y_off > out_h) y_off = out_h;
  191. if (top_ratio < 0.05) top_ratio = 0.05;
  192. if (top_ratio > 0.95) top_ratio = 0.95;
  193. if (actual_bottom < 0) actual_bottom = 0;
  194. if (actual_bottom > bottom_n) actual_bottom = bottom_n;
  195. if (actual_bottom > MAX_TILES - top_n) actual_bottom = MAX_TILES - top_n;
  196. int usable_h = out_h - y_off;
  197. if (usable_h <= 0) return 0;
  198. /* Top row: height proportional to top_ratio, even dimensions */
  199. int top_h = (int)(usable_h * top_ratio);
  200. top_h &= ~1; /* even for NV12 */
  201. if (top_h < 2) top_h = 2;
  202. if (top_h > usable_h - 2) top_h = usable_h - 2;
  203. int bot_h = usable_h - top_h;
  204. if (bot_h < 2) bot_h = 2;
  205. int n = 0;
  206. /* Top row: top_n cameras, equal width, full row width */
  207. int cell_w = out_w / top_n;
  208. for (int i = 0; i < top_n && n < MAX_TILES; i++) {
  209. xs[n] = i * cell_w;
  210. ys[n] = y_off;
  211. ws[n] = (i == top_n - 1) ? out_w - i * cell_w : cell_w;
  212. hs[n] = top_h;
  213. sid[n] = top_ids[i];
  214. n++;
  215. }
  216. /* Bottom row: actual_bottom cameras, equal width, centered */
  217. if (actual_bottom > 0) {
  218. int bot_w = out_w / actual_bottom;
  219. int total_bot_w = bot_w * actual_bottom;
  220. int bot_x_start = (out_w - total_bot_w) / 2;
  221. bot_x_start &= ~1; /* even offset for NV12 */
  222. for (int i = 0; i < actual_bottom && n < MAX_TILES; i++) {
  223. xs[n] = bot_x_start + i * bot_w;
  224. ys[n] = y_off + top_h;
  225. ws[n] = (i == actual_bottom - 1)
  226. ? out_w - bot_x_start - i * bot_w : bot_w;
  227. hs[n] = bot_h;
  228. sid[n] = bottom_ids[i];
  229. n++;
  230. }
  231. }
  232. return n;
  233. }
  234. int composer_region_rects(int out_w, int out_h, const int *row_cols, int nrows,
  235. const int *cells, int *region_x, int *region_y,
  236. int *region_w, int *region_h, int *region_sid,
  237. int y_off) {
  238. if (!row_cols || !cells || !region_x || !region_y ||
  239. !region_w || !region_h || !region_sid) return -1;
  240. if (nrows <= 0 || nrows > MAX_TILES) return 0;
  241. if (y_off < 0) y_off = 0;
  242. if (y_off > out_h) y_off = out_h;
  243. int usable_h = out_h - y_off;
  244. if (usable_h <= 0) return 0;
  245. /* ---- per-row geometry (inverse cell-count height, fill to bottom) ---- */
  246. int rh[MAX_TILES];
  247. int ysum = 0;
  248. if (nrows > 1) {
  249. double wcol[MAX_TILES], wsum = 0.0;
  250. for (int r = 0; r < nrows; r++)
  251. if (row_cols[r] > 0) { wcol[r] = 1.0 / (double)row_cols[r]; wsum += wcol[r]; }
  252. if (wsum <= 0.0) return 0;
  253. for (int r = 0; r < nrows - 1; r++) {
  254. int h = (int)(usable_h * wcol[r] / wsum);
  255. if (h & 1) h--;
  256. if (h < 2) h = 2;
  257. rh[r] = h;
  258. ysum += h;
  259. }
  260. int last_h = usable_h - ysum;
  261. if (last_h & 1) {
  262. last_h++;
  263. for (int r = nrows - 2; r >= 0 && (last_h & 1); r--)
  264. if (rh[r] > 2) { rh[r] -= 2; last_h += 2; }
  265. }
  266. if (last_h < 2) last_h = 2;
  267. rh[nrows - 1] = last_h;
  268. } else {
  269. rh[0] = usable_h;
  270. }
  271. /* ---- assign every cell a label bucket ---- */
  272. /* We'll accumulate pixel spans per label directly. */
  273. int lb_minx[MAX_TILES], lb_miny[MAX_TILES];
  274. int lb_maxx[MAX_TILES], lb_maxy[MAX_TILES];
  275. int lb_init[MAX_TILES];
  276. int nlabels = 0;
  277. int lbl[MAX_TILES];
  278. for (int i = 0; i < MAX_TILES; i++) lb_init[i] = 0;
  279. int idx = 0;
  280. int row_top = y_off;
  281. for (int r = 0; r < nrows; r++) {
  282. int cols = row_cols[r];
  283. int rheight = rh[r];
  284. if (cols <= 0 || rheight < 2) continue;
  285. for (int c = 0; c < cols; c++) {
  286. int lab = cells[idx]; /* flat, row-major */
  287. int cellw = out_w / cols;
  288. int cellx = c * cellw;
  289. if (c == cols - 1) cellw = out_w - cellx;
  290. if (cellw < 2) cellw = 2;
  291. int cell_bot = row_top + rheight;
  292. if (lab >= 0) {
  293. int li = -1;
  294. for (int k = 0; k < nlabels; k++) if (lbl[k] == lab) { li = k; break; }
  295. if (li < 0) {
  296. if (nlabels >= MAX_TILES) { idx++; continue; }
  297. li = nlabels;
  298. lbl[li] = lab;
  299. lb_minx[li] = cellx; lb_miny[li] = row_top;
  300. lb_maxx[li] = cellx + cellw; lb_maxy[li] = cell_bot;
  301. lb_init[li] = 1;
  302. nlabels++;
  303. } else {
  304. if (cellx < lb_minx[li]) lb_minx[li] = cellx;
  305. if (row_top < lb_miny[li]) lb_miny[li] = row_top;
  306. if (cellx + cellw > lb_maxx[li]) lb_maxx[li] = cellx + cellw;
  307. if (cell_bot > lb_maxy[li]) lb_maxy[li] = cell_bot;
  308. }
  309. }
  310. idx++;
  311. }
  312. row_top += rheight;
  313. }
  314. /* dedupe/merge: same label already merged during accumulation */
  315. int n = 0;
  316. for (int k = 0; k < nlabels; k++) {
  317. if (!lb_init[k]) continue;
  318. region_x[n] = lb_minx[k];
  319. region_y[n] = lb_miny[k];
  320. region_w[n] = lb_maxx[k] - lb_minx[k];
  321. region_h[n] = lb_maxy[k] - lb_miny[k];
  322. if (region_w[n] < 2) region_w[n] = 2;
  323. if (region_h[n] < 2) region_h[n] = 2;
  324. region_sid[n] = lbl[k];
  325. n++;
  326. }
  327. return n;
  328. }
  329. Composer *composer_create(int output_width, int output_height,
  330. int num_streams, int y_off) {
  331. Composer *comp = calloc(1, sizeof(Composer));
  332. if (!comp) return NULL;
  333. comp->output_w = output_width;
  334. comp->output_h = output_height;
  335. comp->num_streams = num_streams > MAX_TILES ? MAX_TILES : num_streams;
  336. /* Pin RGA to the RGA3 core (64-bit addressing). The RGA2 cores are
  337. * 32-bit only and refuse any dmabuf whose physical pages sit above 4G
  338. * ("rga_mm: RGA_MMU unsupported memory larger than 4G!"), which is what
  339. * made importbuffer_fd return EINVAL and black out tiles on the live
  340. * site. RGA3 has no such limitation and is faster. If the driver/kernel
  341. * rejects it we keep the default scheduler. */
  342. IM_STATUS sc = imconfig(IM_CONFIG_SCHEDULER_CORE, IM_SCHEDULER_RGA3_CORE0);
  343. if (sc == IM_STATUS_SUCCESS)
  344. fprintf(stderr, "composer: RGA scheduler pinned to RGA3 (64-bit addressing)\n");
  345. else
  346. fprintf(stderr, "composer: imconfig(RGA3_CORE0) failed st=%d, using default scheduler\n", sc);
  347. int xs[MAX_TILES], ys[MAX_TILES], ws[MAX_TILES], hs[MAX_TILES];
  348. int n = composer_grid_rects(output_width, output_height, comp->num_streams,
  349. xs, ys, ws, hs, y_off);
  350. for (int i = 0; i < n; i++) {
  351. comp->tiles[i].x = xs[i];
  352. comp->tiles[i].y = ys[i];
  353. comp->tiles[i].w = ws[i];
  354. comp->tiles[i].h = hs[i];
  355. }
  356. return comp;
  357. }
  358. void composer_invalidate_all(Composer *comp) {
  359. if (!comp) return;
  360. for (int i = 0; i < RGA_CACHE_SIZE; i++) {
  361. RgaCacheEnt *e = &comp->rga_cache[i];
  362. if (e->handle) releasebuffer_handle(e->handle);
  363. if (e->fd > 0) close(e->fd);
  364. memset(e, 0, sizeof(*e));
  365. }
  366. }
  367. void composer_destroy(Composer *comp) {
  368. composer_invalidate_all(comp);
  369. for (int i = 0; i < MAX_TILES; i++)
  370. if (comp->mirror_fd[i] > 0) close(comp->mirror_fd[i]);
  371. free(comp);
  372. }
  373. void composer_get_tile_layout(Composer *comp, int stream_idx,
  374. int *x, int *y, int *w, int *h) {
  375. if (stream_idx < 0 || stream_idx >= MAX_TILES) {
  376. *x = *y = *w = *h = 0;
  377. return;
  378. }
  379. *x = comp->tiles[stream_idx].x;
  380. *y = comp->tiles[stream_idx].y;
  381. *w = comp->tiles[stream_idx].w;
  382. *h = comp->tiles[stream_idx].h;
  383. }
  384. int composer_set_tiles(Composer *comp, const int *x, const int *y,
  385. const int *w, const int *h, int n) {
  386. if (!comp || !x || !y || !w || !h) return -1;
  387. if (n < 0) n = 0;
  388. if (n > MAX_TILES) n = MAX_TILES;
  389. for (int i = 0; i < n; i++) {
  390. comp->tiles[i].x = x[i];
  391. comp->tiles[i].y = y[i];
  392. comp->tiles[i].w = w[i];
  393. comp->tiles[i].h = h[i];
  394. }
  395. return 0;
  396. }
  397. void composer_set_letterbox(Composer *comp, int enable) {
  398. if (comp) comp->letterbox = enable ? 1 : 0;
  399. }
  400. static void rga_cache_evict_one(Composer *comp) {
  401. RgaCacheEnt *oldest = NULL;
  402. for (int i = 0; i < RGA_CACHE_SIZE; i++) {
  403. RgaCacheEnt *e = &comp->rga_cache[i];
  404. if (!e->fd) continue;
  405. if (!oldest || e->last_use < oldest->last_use) oldest = e;
  406. }
  407. if (!oldest) return;
  408. if (oldest->handle) releasebuffer_handle(oldest->handle);
  409. close(oldest->fd);
  410. memset(oldest, 0, sizeof(*oldest));
  411. }
  412. /* Wrap fd for RGA use, importing into a cached handle when the fast
  413. * wrapbuffer_fd path is unavailable. On return *out_handle is nonzero only
  414. * when the caller must releasebuffer_handle it (legacy one-shot import);
  415. * cached handles are owned by the composer and must not be released. */
  416. static rga_buffer_t import_nv12(Composer *comp, int fd, int w, int h,
  417. int stride, int vstride,
  418. rga_buffer_handle_t *out_handle) {
  419. *out_handle = 0;
  420. rga_buffer_t buf = wrapbuffer_fd_t(fd, w, h, stride, vstride, RK_FORMAT_YCbCr_420_SP);
  421. if (buf.handle != 0)
  422. return buf;
  423. im_handle_param_t param;
  424. memset(&param, 0, sizeof(param));
  425. param.width = w;
  426. param.height = h;
  427. param.format = RK_FORMAT_YCbCr_420_SP;
  428. /* Identity of the underlying dmabuf: its anon-inode number is unique
  429. * per buffer instance, immune to fd-number recycling. */
  430. struct stat st;
  431. ino_t ino = (fstat(fd, &st) == 0) ? st.st_ino : 0;
  432. if (ino != 0) {
  433. for (int i = 0; i < RGA_CACHE_SIZE; i++) {
  434. RgaCacheEnt *e = &comp->rga_cache[i];
  435. if (e->fd > 0 && e->handle && e->ino == ino &&
  436. e->w == w && e->h == h &&
  437. e->stride == stride && e->vstride == vstride) {
  438. e->last_use = ++comp->rga_clock;
  439. return wrapbuffer_handle_t(e->handle, w, h, stride, vstride,
  440. RK_FORMAT_YCbCr_420_SP);
  441. }
  442. }
  443. }
  444. /* Prepare a free cache slot BEFORE importing. If the table is full when
  445. * importbuffer_fd runs the driver refuses the new handle with EINVAL and
  446. * it never gets cached (stale entries then keep the table full forever).
  447. * Evicting one old handle up front guarantees the import has room. */
  448. int slot = -1;
  449. if (ino != 0) {
  450. for (int i = 0; i < RGA_CACHE_SIZE; i++)
  451. if (!comp->rga_cache[i].fd) { slot = i; break; }
  452. if (slot < 0) {
  453. rga_cache_evict_one(comp);
  454. for (int i = 0; i < RGA_CACHE_SIZE; i++)
  455. if (!comp->rga_cache[i].fd) { slot = i; break; }
  456. }
  457. }
  458. rga_buffer_handle_t handle = importbuffer_fd(fd, &param);
  459. if (handle == 0) {
  460. /* Import failed even with room for it (or a wedged table): report
  461. * and let the caller's self-heal invalidate fire instead of CACHING
  462. * the failure. Rate-limit the line: boards that map part of DDR above
  463. * 4G keep the same two high-bank decode buffers failing every frame
  464. * (the composer's low-4G mirror then rescues them), so a per-frame
  465. * print floods; the counts still live in composer_dump_stats(). */
  466. static struct timeval last_err = {0, 0}, now;
  467. gettimeofday(&now, NULL);
  468. if (last_err.tv_sec == 0 || now.tv_sec - last_err.tv_sec >= 2) {
  469. last_err = now;
  470. fprintf(stderr, "import_nv12: importbuffer_fd failed for fd=%d ino=%llu %dx%d stride=%d errno=%d(%s)\n",
  471. fd, (unsigned long long)ino, w, h, stride, errno, strerror(errno));
  472. }
  473. memset(&buf, 0, sizeof(buf));
  474. return buf;
  475. }
  476. /* Pin in the cache with our own dup: while our dup stays open the kernel
  477. * cannot hand that fd number to anyone else, so stale hits are impossible. */
  478. if (ino != 0 && slot >= 0) {
  479. int mydup = fcntl(fd, F_DUPFD_CLOEXEC, 3);
  480. if (mydup >= 0) {
  481. RgaCacheEnt *e = &comp->rga_cache[slot];
  482. e->fd = mydup;
  483. e->ino = ino;
  484. e->w = w; e->h = h;
  485. e->stride = stride; e->vstride = vstride;
  486. e->handle = handle;
  487. e->last_use = ++comp->rga_clock;
  488. return wrapbuffer_handle_t(handle, w, h, stride, vstride,
  489. RK_FORMAT_YCbCr_420_SP);
  490. }
  491. /* dup failed: hand the handle back one-shot (slot stays free). */
  492. }
  493. /* could not cache: hand out one-shot ownership to the caller */
  494. *out_handle = handle;
  495. return wrapbuffer_handle_t(handle, w, h, stride, vstride,
  496. RK_FORMAT_YCbCr_420_SP);
  497. }
  498. /* Emergency low-address mirror: the board maps part of DDR above 4G and the
  499. * RGA driver refuses any dmabuf whose physical pages sit above 4G
  500. * ("rga_mm: RGA_MMU unsupported memory larger than 4G!") — importbuffer_fd
  501. * then returns EINVAL and the tile goes black. When a tile's import fails we
  502. * memcpy its latest frame into a per-tile system-uncached-dma32 buffer
  503. * (guaranteed <4G) and hand RGA that instead. Only failing tiles pay the
  504. * copy cost; healthy ones keep the zero-copy path. */
  505. static int mirror_refresh(Composer *comp, int idx, int src_fd,
  506. int stride, int vstride) {
  507. size_t size = (size_t)stride * (size_t)vstride * 3 / 2;
  508. if (comp->mirror_fd[idx] <= 0) {
  509. if (dma_heap_alloc("system-uncached-dma32", size, &comp->mirror_fd[idx]) < 0 &&
  510. dma_heap_alloc("cma", size, &comp->mirror_fd[idx]) < 0) {
  511. fprintf(stderr, "mirror: dma32+cma heap alloc of %zuB failed\n", size);
  512. return -1;
  513. }
  514. }
  515. void *src = mmap(NULL, size, PROT_READ, MAP_SHARED, src_fd, 0);
  516. if (src == MAP_FAILED) {
  517. fprintf(stderr, "mirror: mmap src fd=%d failed (%s)\n", src_fd, strerror(errno));
  518. return -1;
  519. }
  520. void *dst = mmap(NULL, size, PROT_WRITE, MAP_SHARED, comp->mirror_fd[idx], 0);
  521. if (dst == MAP_FAILED) {
  522. fprintf(stderr, "mirror: mmap mirror fd=%d failed (%s)\n", comp->mirror_fd[idx], strerror(errno));
  523. munmap(src, size);
  524. return -1;
  525. }
  526. memcpy(dst, src, size);
  527. munmap(dst, size);
  528. munmap(src, size);
  529. struct dma_buf_sync sync = { .flags = DMA_BUF_SYNC_RW };
  530. ioctl(comp->mirror_fd[idx], DMA_BUF_IOCTL_SYNC, &sync);
  531. return 0;
  532. }
  533. int composer_compose(Composer *comp,
  534. int *src_fds, int *src_widths, int *src_heights,
  535. int *src_strides, int *src_vstrides, int num_src,
  536. int dst_fd, int dst_stride) {
  537. int n = num_src;
  538. if (n > MAX_TILES) n = MAX_TILES;
  539. if (n <= 0) return 0;
  540. rga_buffer_handle_t dst_handle = 0;
  541. rga_buffer_t dst_buf = import_nv12(comp, dst_fd, comp->output_w, comp->output_h,
  542. dst_stride, comp->output_h, &dst_handle);
  543. if (dst_buf.handle == 0) {
  544. /* Output import failed: the RGA handle table is likely stale (this
  545. * driver returns EINVAL for every import once it wedges). Drop every
  546. * cached import and retry once before giving up on this frame. */
  547. composer_invalidate_all(comp);
  548. usleep(1000);
  549. dst_buf = import_nv12(comp, dst_fd, comp->output_w, comp->output_h,
  550. dst_stride, comp->output_h, &dst_handle);
  551. if (dst_buf.handle == 0) { comp->dst_fail++; return -1; }
  552. }
  553. rga_buffer_t pat;
  554. memset(&pat, 0, sizeof(pat));
  555. im_rect prect;
  556. memset(&prect, 0, sizeof(prect));
  557. int src_fail_frame = 0;
  558. for (int i = 0; i < n; i++) {
  559. if (src_fds[i] < 0) continue;
  560. int vstride = (src_vstrides && src_vstrides[i] > 0) ? src_vstrides[i] : src_heights[i];
  561. rga_buffer_handle_t src_handle = 0;
  562. rga_buffer_t src_buf = import_nv12(comp, src_fds[i], src_widths[i], src_heights[i],
  563. src_strides[i], vstride, &src_handle);
  564. if (src_buf.handle == 0) {
  565. /* Likely landed on a >4G physical page (RGA refuses it). Copy the
  566. * frame into the per-tile low-address mirror and import that. */
  567. if (mirror_refresh(comp, i, src_fds[i], src_strides[i], vstride) == 0) {
  568. src_handle = 0;
  569. src_buf = import_nv12(comp, comp->mirror_fd[i],
  570. src_widths[i], src_heights[i],
  571. src_strides[i], vstride, &src_handle);
  572. if (src_buf.handle == 0)
  573. fprintf(stderr, "mirror: import mirror fd=%d still failed for tile %d\n",
  574. comp->mirror_fd[i], i);
  575. }
  576. if (src_buf.handle == 0) { comp->src_import_fail[i]++; src_fail_frame++; continue; }
  577. comp->mirror_hits++;
  578. }
  579. comp->src_ok[i]++;
  580. im_rect src_rect = {0, 0, src_widths[i], src_heights[i]};
  581. im_rect dst_rect;
  582. int tw = comp->tiles[i].w, th = comp->tiles[i].h;
  583. if (comp->letterbox) {
  584. /* Preserve aspect ratio: fit inside the tile, centered, with
  585. * black bars. NV12 needs even dims/offsets. */
  586. int sw = src_widths[i], sh = src_heights[i];
  587. double sc = ((double)tw / sw < (double)th / sh) ?
  588. (double)tw / sw : (double)th / sh;
  589. int dw = (int)(sw * sc);
  590. int dh = (int)(sh * sc);
  591. if (dw > tw) dw = tw;
  592. if (dh > th) dh = th;
  593. dw &= ~1;
  594. dh &= ~1;
  595. if (dw < 2) dw = 2;
  596. if (dh < 2) dh = 2;
  597. dst_rect.x = comp->tiles[i].x + (tw - dw) / 2;
  598. dst_rect.y = comp->tiles[i].y + (th - dh) / 2;
  599. if (dst_rect.x & 1) dst_rect.x--;
  600. if (dst_rect.y & 1) dst_rect.y--;
  601. if (dst_rect.x < 0) dst_rect.x = 0;
  602. if (dst_rect.y < 0) dst_rect.y = 0;
  603. dst_rect.width = dw;
  604. dst_rect.height = dh;
  605. } else {
  606. dst_rect.x = comp->tiles[i].x;
  607. dst_rect.y = comp->tiles[i].y;
  608. dst_rect.width = tw;
  609. dst_rect.height = th;
  610. }
  611. int ret = improcess(src_buf, dst_buf, pat,
  612. src_rect, dst_rect, prect, IM_SYNC);
  613. if (ret != IM_STATUS_SUCCESS) {
  614. comp->src_improcess_fail[i]++;
  615. fprintf(stderr, "RGA improcess failed for tile %d: ret=%d (fail=%llu)\n",
  616. i, ret, (unsigned long long)comp->src_improcess_fail[i]);
  617. }
  618. if (src_handle) releasebuffer_handle(src_handle);
  619. }
  620. if (dst_handle) releasebuffer_handle(dst_handle);
  621. if (src_fail_frame > 0) {
  622. static struct timeval last_iva = {0, 0};
  623. struct timeval now;
  624. gettimeofday(&now, NULL);
  625. if (last_iva.tv_sec == 0 || now.tv_sec - last_iva.tv_sec >= 30) {
  626. last_iva = now;
  627. composer_invalidate_all(comp);
  628. fprintf(stderr, "compose: %d src import(s) failed this frame; "
  629. "invalidated RGA cache for self-heal\n", src_fail_frame);
  630. }
  631. }
  632. return 0;
  633. }
  634. void composer_dump_stats(const Composer *comp) {
  635. if (!comp) return;
  636. int any = 0;
  637. for (int i = 0; i < MAX_TILES; i++)
  638. if (comp->src_import_fail[i] || comp->src_improcess_fail[i]) { any = 1; break; }
  639. if (!any && !comp->dst_fail) {
  640. fprintf(stderr, "compose stats: all tiles clean (%llu dst-fail)\n",
  641. (unsigned long long)comp->dst_fail);
  642. return;
  643. }
  644. for (int i = 0; i < MAX_TILES; i++) {
  645. if (comp->src_ok[i] || comp->src_import_fail[i] || comp->src_improcess_fail[i])
  646. fprintf(stderr, "compose stats tile %d: ok=%llu import_fail=%llu improcess_fail=%llu\n",
  647. i,
  648. (unsigned long long)comp->src_ok[i],
  649. (unsigned long long)comp->src_import_fail[i],
  650. (unsigned long long)comp->src_improcess_fail[i]);
  651. }
  652. if (comp->dst_fail)
  653. fprintf(stderr, "compose stats dst: import_fail=%llu\n",
  654. (unsigned long long)comp->dst_fail);
  655. if (comp->mirror_hits)
  656. fprintf(stderr, "compose stats mirror: rescued=%llu frames via low-4G copy\n",
  657. (unsigned long long)comp->mirror_hits);
  658. }