common.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /*
  2. * Source updates from:
  3. * - https://wayland-book.com/xdg-shell-basics/example-code.html
  4. * - weston's clients examples
  5. */
  6. #include <errno.h>
  7. #include <fcntl.h>
  8. #include <getopt.h>
  9. #include <limits.h>
  10. #include <stdbool.h>
  11. #include <stdint.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <sys/mman.h>
  16. #include <time.h>
  17. #include <unistd.h>
  18. #include "drm/drm.h"
  19. #include "drm/drm_fourcc.h"
  20. #include "xf86drm.h"
  21. #include "linux-dmabuf-unstable-v1-client-protocol.h"
  22. #include "xdg-shell-client-protocol.h"
  23. #include <wayland-client.h>
  24. #include "viewporter-client-protocol.h"
  25. #include "xdg-output-unstable-v1-client-protocol.h"
  26. #include "buffers.h"
  27. #include "common.h"
  28. int ms_buf_index = 0;
  29. int raw_frame_index = 0;
  30. static const int benchmark_interval = 5;
  31. static void ms_flip(void *data, struct wl_callback *callback, uint32_t time);
  32. static void wl_buffer_release(void *data, struct wl_buffer *wl_buffer) {
  33. }
  34. const struct wl_buffer_listener wl_buffer_listener = {
  35. .release = wl_buffer_release,
  36. };
  37. static void fb_buffer_release(void *data, struct wl_buffer *wl_buffer) {
  38. struct fb_buffer *buffer = data;
  39. buffer->busy = false;
  40. }
  41. const struct wl_buffer_listener fb_buffer_listener = {
  42. .release = fb_buffer_release,
  43. };
  44. static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface,
  45. uint32_t serial) {
  46. struct example_window *window = data;
  47. if ( !window->wait_for_configure)
  48. return;
  49. xdg_surface_ack_configure(xdg_surface, serial);
  50. if (window->initialized && window->wait_for_configure) {
  51. ms_flip(data, NULL, 0);
  52. }
  53. window->wait_for_configure = false;
  54. }
  55. const struct xdg_surface_listener xdg_surface_listener = {
  56. .configure = xdg_surface_configure,
  57. };
  58. static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base,
  59. uint32_t serial) {
  60. xdg_wm_base_pong(xdg_wm_base, serial);
  61. }
  62. const struct xdg_wm_base_listener xdg_wm_base_listener = {
  63. .ping = xdg_wm_base_ping,
  64. };
  65. static void dmabuf_modifier(void *data,
  66. struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
  67. uint32_t format, uint32_t modifier_hi,
  68. uint32_t modifier_lo) {}
  69. static void dmabuf_format(void *data,
  70. struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
  71. uint32_t format) {}
  72. const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
  73. .format = dmabuf_format,
  74. .modifier = dmabuf_modifier,
  75. };
  76. /* Start of XDG Output */
  77. /* Can got output infos to future usages */
  78. static void
  79. display_handle_geometry(void *data,
  80. struct wl_output *wl_output,
  81. int x, int y,
  82. int physical_width,
  83. int physical_height,
  84. int subpixel,
  85. const char *make,
  86. const char *model,
  87. int transform)
  88. {
  89. //printf("YG: x=%d, y=%d, p-width=%d, p-height=%d, subpixel=%d, transform=%d, model=\"%s\"\n", x, y,
  90. // physical_width, physical_height, subpixel, transform, model);
  91. }
  92. static void
  93. display_handle_done(void *data,
  94. struct wl_output *wl_output)
  95. {
  96. }
  97. static void
  98. display_handle_scale(void *data,
  99. struct wl_output *wl_output,
  100. int32_t scale)
  101. {
  102. }
  103. static void
  104. display_handle_mode(void *data,
  105. struct wl_output *wl_output,
  106. uint32_t flags,
  107. int width,
  108. int height,
  109. int refresh)
  110. {
  111. //printf("YG:width=%d, height=%d, flags=%d, refresh=%d\n", width, height, flags, refresh);
  112. }
  113. static const struct wl_output_listener output_listener = {
  114. display_handle_geometry,
  115. display_handle_mode,
  116. display_handle_done,
  117. display_handle_scale
  118. };
  119. static void
  120. window_add_output(struct example_window *window, uint32_t id)
  121. {
  122. struct output *output;
  123. output = malloc(sizeof *output);
  124. memset(output, 0, sizeof *output);
  125. output->output = wl_registry_bind(window->wl_registry, id, &wl_output_interface, 2);
  126. //wl_list_insert(window->output_list.prev, &output->link);
  127. wl_output_add_listener(output->output, &output_listener, output);
  128. }
  129. static void
  130. handle_xdg_output_v1_logical_position(void *data, struct zxdg_output_v1 *output,
  131. int32_t x, int32_t y)
  132. {
  133. }
  134. static void
  135. handle_xdg_output_v1_logical_size(void *data, struct zxdg_output_v1 *output,
  136. int32_t width, int32_t height)
  137. {
  138. }
  139. static void
  140. handle_xdg_output_v1_done(void *data, struct zxdg_output_v1 *output)
  141. {
  142. }
  143. static void
  144. handle_xdg_output_v1_name(void *data, struct zxdg_output_v1 *output,
  145. const char *name)
  146. {
  147. }
  148. static void
  149. handle_xdg_output_v1_description(void *data, struct zxdg_output_v1 *output,
  150. const char *description)
  151. {
  152. }
  153. static const struct zxdg_output_v1_listener xdg_output_v1_listener = {
  154. .logical_position = handle_xdg_output_v1_logical_position,
  155. .logical_size = handle_xdg_output_v1_logical_size,
  156. .done = handle_xdg_output_v1_done,
  157. .name = handle_xdg_output_v1_name,
  158. .description = handle_xdg_output_v1_description,
  159. };
  160. static void
  161. add_xdg_output_manager_v1_info(struct example_window *window, uint32_t id, uint32_t version)
  162. {
  163. window->xdg_output_manager = wl_registry_bind(window->wl_registry, id,
  164. &zxdg_output_manager_v1_interface, version > 2 ? 2 : version);
  165. }
  166. /* End of XDG Output */
  167. static void registry_global(void *data, struct wl_registry *wl_registry,
  168. uint32_t name, const char *interface,
  169. uint32_t version) {
  170. struct example_window *window = data;
  171. if (strcmp(interface, wl_shm_interface.name) == 0) {
  172. window->ss_buffer.wl_shm = wl_registry_bind(wl_registry, name, &wl_shm_interface, 1);
  173. } else if (strcmp(interface, wl_compositor_interface.name) == 0) {
  174. window->wl_compositor =
  175. wl_registry_bind(wl_registry, name, &wl_compositor_interface, 4);
  176. } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
  177. window->xdg_wm_base =
  178. wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1);
  179. xdg_wm_base_add_listener(window->xdg_wm_base, &xdg_wm_base_listener, window);
  180. } else if (strcmp(interface, wl_subcompositor_interface.name) == 0) {
  181. window->wl_subcompositor =
  182. wl_registry_bind(wl_registry, name, &wl_subcompositor_interface, 1);
  183. } else if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) {
  184. window->dmabuf =
  185. wl_registry_bind(wl_registry, name, &zwp_linux_dmabuf_v1_interface, 3);
  186. zwp_linux_dmabuf_v1_add_listener(window->dmabuf, &dmabuf_listener, window);
  187. } else if (strcmp(interface, wl_output_interface.name) == 0) {
  188. window_add_output(window, name);
  189. } else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0)
  190. add_xdg_output_manager_v1_info(window, name, version);
  191. }
  192. static void registry_global_remove(void *data, struct wl_registry *wl_registry,
  193. uint32_t name) {}
  194. const struct wl_registry_listener wl_registry_listener = {
  195. .global = registry_global,
  196. .global_remove = registry_global_remove,
  197. };
  198. static const struct wl_callback_listener frame_listener = {
  199. ms_flip
  200. };
  201. static void ms_flip(void *data, struct wl_callback *callback, uint32_t time) {
  202. struct example_window *window = data;
  203. while(1){
  204. if (ms_buf_index >= FB_BUFFER_NUM)
  205. ms_buf_index = 0;
  206. if (!window->ms_buffers[ms_buf_index].busy){
  207. break;
  208. }
  209. ms_buf_index++;
  210. }
  211. if (!window->noread){
  212. int ret = fill_with_raw(window->raw_fp, window->width, window->height, (uint8_t *)(window->ms_buffers[ms_buf_index].buf_vma));
  213. if (ret != 0) {
  214. fprintf(stderr, "failed to fill the buf\n");
  215. }
  216. }
  217. wl_surface_attach(window->wl_surface, window->ms_buffers[ms_buf_index].buffer, 0, 0);
  218. wl_surface_damage(window->wl_surface, 0, 0, window->width, window->height);
  219. if (callback)
  220. wl_callback_destroy(callback);
  221. window->callback = wl_surface_frame(window->wl_surface);
  222. wl_callback_add_listener(window->callback, &frame_listener, window);
  223. wl_surface_commit(window->wl_surface);
  224. window->ms_buffers[ms_buf_index].busy = true;
  225. struct timeval tv;
  226. gettimeofday(&tv, NULL);
  227. time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
  228. if (window->frames_num == 0)
  229. window->benchmark_time = time;
  230. if (time - window->benchmark_time > (benchmark_interval * 1000)) {
  231. printf("%d frames in %d seconds: %f fps\n",
  232. window->frames_num,
  233. benchmark_interval,
  234. (float) window->frames_num / benchmark_interval);
  235. window->benchmark_time = time;
  236. window->frames_num = 0;
  237. }
  238. window->frames_num++;
  239. return;
  240. }
  241. static void create_succeeded(void *data,
  242. struct zwp_linux_buffer_params_v1 *params,
  243. struct wl_buffer *new_buffer) {
  244. zwp_linux_buffer_params_v1_destroy(params);
  245. }
  246. static void create_failed(void *data,
  247. struct zwp_linux_buffer_params_v1 *params) {
  248. zwp_linux_buffer_params_v1_destroy(params);
  249. fprintf(stderr, "Error: zwp_linux_buffer_params.create failed.\n");
  250. }
  251. static const struct zwp_linux_buffer_params_v1_listener params_listener = {
  252. create_succeeded, create_failed};
  253. int init_buffers(struct example_window *window) {
  254. int ret = 0;
  255. window->drm_dev_fd = open(window->drm_node, O_RDWR);
  256. if (window->drm_dev_fd < 0) {
  257. fprintf(stderr, "failed to open device %s: %s\n", window->drm_node, strerror(errno));
  258. return -1;
  259. }
  260. //Init main surface buffers
  261. for(int i_buf = 0; i_buf < FB_BUFFER_NUM; i_buf++){
  262. uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
  263. window->ms_buffers[i_buf].bo = bo_create(window->drm_dev_fd, DRM_FORMAT_NV12, window->width, window->height, handles, pitches, offsets);
  264. window->ms_buffers[i_buf].busy = false;
  265. if (!window->ms_buffers[i_buf].bo) {
  266. fprintf(stderr, "failed to create bo\n");
  267. close(window->drm_dev_fd);
  268. return -1;
  269. }
  270. //TODO: need unmap in handling of exception or exit
  271. ret = bo_map(window->ms_buffers[i_buf].bo, &(window->ms_buffers[i_buf].buf_vma));
  272. if (ret) {
  273. fprintf(stderr, "failed to map buffer: %s\n", strerror(-errno));
  274. bo_destroy(window->ms_buffers[i_buf].bo);
  275. return -1;
  276. }
  277. struct zwp_linux_buffer_params_v1 *params;
  278. params = zwp_linux_dmabuf_v1_create_params(window->dmabuf);
  279. int fd_plane = 0;
  280. for (int i = 0; i < FORMAT_MAX_PLANES; ++i) {
  281. if (!handles[i])
  282. continue;
  283. int ret = drmPrimeHandleToFD(window->drm_dev_fd, handles[i], 0, &fd_plane);
  284. if (ret < 0 || fd_plane < 0) {
  285. fprintf(stderr, "error: failed to get dmabuf_fd\n");
  286. bo_destroy(window->ms_buffers[i_buf].bo);
  287. close(window->drm_dev_fd);
  288. return -1;
  289. }
  290. zwp_linux_buffer_params_v1_add(params, fd_plane, i, offsets[i], pitches[i],
  291. DRM_FORMAT_MOD_INVALID >> 32,
  292. DRM_FORMAT_MOD_INVALID & 0xffffffff);
  293. }
  294. uint32_t flags = 0;
  295. zwp_linux_buffer_params_v1_add_listener(params, &params_listener, window);
  296. window->ms_buffers[i_buf].buffer = zwp_linux_buffer_params_v1_create_immed(params, window->width, window->height, WL_SHM_FORMAT_NV12, flags);
  297. wl_buffer_add_listener(window->ms_buffers[i_buf].buffer, &fb_buffer_listener, &(window->ms_buffers[i_buf]));
  298. }
  299. //Init sub surface buffers
  300. if (window->show_bar) {
  301. int ss_stride = window->width * 4;
  302. int ss_height = window->width/5;
  303. int ss_size = ss_stride * (ss_height);
  304. if (window->ss_usedma){
  305. uint32_t ss_handles[4] = {0}, ss_pitches[4] = {0}, ss_offsets[4] = {0};
  306. //Using BGR as DMA Buf in Light can't support RGB
  307. struct bo *ss_bo = bo_create(window->drm_dev_fd, DRM_FORMAT_ARGB8888, window->width, ss_height, ss_handles, ss_pitches, ss_offsets);
  308. if (!ss_bo) {
  309. fprintf(stderr, "failed to create ss_bo\n");
  310. close(window->drm_dev_fd);
  311. return -1;
  312. }
  313. ret = bo_map(ss_bo, &(window->ss_buffer.buf_vma));
  314. if (ret) {
  315. fprintf(stderr, "failed to map buffer: %s\n", strerror(-errno));
  316. bo_destroy(ss_bo);
  317. return -1;
  318. }
  319. struct zwp_linux_buffer_params_v1 *ss_params;
  320. ss_params = zwp_linux_dmabuf_v1_create_params(window->dmabuf);
  321. int ss_fd_plane = 0;
  322. for (int i = 0; i < FORMAT_MAX_PLANES; ++i) {
  323. if (!ss_handles[i])
  324. continue;
  325. ret = drmPrimeHandleToFD(window->drm_dev_fd, ss_handles[i], 0, &ss_fd_plane);
  326. if (ret < 0 || ss_fd_plane < 0) {
  327. fprintf(stderr, "error: failed to get ss dmabuf fd\n");
  328. bo_destroy(ss_bo);
  329. close(window->drm_dev_fd);
  330. return -1;
  331. }
  332. zwp_linux_buffer_params_v1_add(ss_params, ss_fd_plane, i, ss_offsets[i], ss_pitches[i],
  333. DRM_FORMAT_MOD_INVALID >> 32,
  334. DRM_FORMAT_MOD_INVALID & 0xffffffff);
  335. }
  336. uint32_t ss_flags = 0;
  337. zwp_linux_buffer_params_v1_add_listener(ss_params, &params_listener, window);
  338. window->ss_buffer.buffer = zwp_linux_buffer_params_v1_create_immed(ss_params, window->width,
  339. ss_height, 0x34325241, ss_flags);
  340. } else {
  341. window->ss_buffer.fd = allocate_shm_file(ss_size);
  342. if (window->ss_buffer.fd == -1) {
  343. return -1;
  344. }
  345. struct wl_shm_pool *pool = wl_shm_create_pool(window->ss_buffer.wl_shm, window->ss_buffer.fd, ss_size);
  346. window->ss_buffer.buffer = wl_shm_pool_create_buffer(pool, 0, window->width, ss_height, ss_stride, WL_SHM_FORMAT_XRGB8888);
  347. wl_shm_pool_destroy(pool);
  348. window->ss_buffer.buf_vma = mmap(NULL, ss_size, PROT_READ | PROT_WRITE, MAP_SHARED, window->ss_buffer.fd, 0);
  349. if (window->ss_buffer.buf_vma == MAP_FAILED) {
  350. close(window->ss_buffer.fd);
  351. return -1;
  352. }
  353. }
  354. //Start fill sub surface buffer
  355. for (int y = 0; y < ss_height; ++y) {
  356. for (int x = 0; x < window->width; ++x) {
  357. if ((x + y / 8 * 8) % 16 < 8)
  358. ((uint32_t *)window->ss_buffer.buf_vma)[y * window->width + x] = 0xFF666666;
  359. else
  360. ((uint32_t *)window->ss_buffer.buf_vma)[y * window->width + x] = 0xFFEEEEEE;
  361. }
  362. }
  363. munmap(window->ss_buffer.buf_vma, ss_size);
  364. wl_surface_attach(window->wl_subsurface, window->ss_buffer.buffer, 0, 0);
  365. wl_surface_damage(window->wl_subsurface, 0, 0, window->width, ss_height);
  366. wl_surface_commit(window->wl_subsurface);
  367. wl_buffer_add_listener(window->ss_buffer.buffer, &wl_buffer_listener, NULL);
  368. }
  369. return 0;
  370. }
  371. int init_window(struct example_window *window) {
  372. window->frames_num = 0;
  373. window->wl_display = wl_display_connect(NULL);
  374. window->wl_registry = wl_display_get_registry(window->wl_display);
  375. wl_registry_add_listener(window->wl_registry, &wl_registry_listener, window);
  376. wl_display_roundtrip(window->wl_display);
  377. window->wl_surface = wl_compositor_create_surface(window->wl_compositor);
  378. window->wl_subsurface =
  379. wl_compositor_create_surface(window->wl_compositor);
  380. window->subsurface = wl_subcompositor_get_subsurface(
  381. window->wl_subcompositor, window->wl_subsurface, window->wl_surface);
  382. //we are using xdg_surface_set_window_geometry() to set window position now.
  383. //wl_subsurface_set_position(window->subsurface, window->x, window->y);
  384. window->xdg_surface =
  385. xdg_wm_base_get_xdg_surface(window->xdg_wm_base, window->wl_surface);
  386. xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window);
  387. window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface);
  388. xdg_toplevel_set_title(window->xdg_toplevel,
  389. "Graphics Wayland Buf Display Example");
  390. xdg_toplevel_set_app_id(window->xdg_toplevel, "wl-tester");
  391. xdg_surface_set_window_geometry(window->xdg_surface, window->x, window->y, window->width, window->height);
  392. //Not sure if it is workable?
  393. //xdg_toplevel_set_fullscreen();
  394. window->wait_for_configure = true;
  395. if (window->sync)
  396. wl_subsurface_set_sync(window->subsurface);
  397. else
  398. wl_subsurface_set_desync(window->subsurface);
  399. wl_surface_commit(window->wl_surface);
  400. int ret = init_buffers(window);
  401. if (ret != 0){
  402. fprintf(stderr, "Error init buffers\n");
  403. return -1;
  404. }
  405. wl_display_roundtrip(window->wl_display);
  406. if (!window->wait_for_configure){
  407. ms_flip(window, NULL, 0);
  408. }
  409. window->initialized = true;
  410. while (wl_display_dispatch(window->wl_display)) {
  411. }
  412. return 0;
  413. }