blob: 0acb30fb2b97f70516bf2a2f9efb48a774a2d59c [file] [log] [blame]
George Kiagiadakis53868982014-06-12 16:26:49 +02001/*
2 * Copyright © 2011 Benjamin Franzke
3 * Copyright © 2010 Intel Corporation
4 * Copyright © 2014 Collabora Ltd.
5 *
Yong Bakos53361532017-01-23 06:17:44 -08006 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
George Kiagiadakis53868982014-06-12 16:26:49 +020013 *
Yong Bakos53361532017-01-23 06:17:44 -080014 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
George Kiagiadakis53868982014-06-12 16:26:49 +020026 */
27
Bryce Harringtonb4dae9b2016-06-15 18:13:07 -070028#include "config.h"
George Kiagiadakis53868982014-06-12 16:26:49 +020029
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030030#include <stdint.h>
George Kiagiadakis53868982014-06-12 16:26:49 +020031#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <stdbool.h>
35#include <assert.h>
36#include <unistd.h>
37#include <sys/mman.h>
38#include <signal.h>
39#include <fcntl.h>
40
41#include <xf86drm.h>
Varad Gautamf7b3a392017-04-26 19:17:18 +053042
43#ifdef HAVE_LIBDRM_INTEL
Emmanuel Gil Peyrot8ef29572016-01-11 19:04:37 +000044#include <i915_drm.h>
45#include <intel_bufmgr.h>
Varad Gautamf7b3a392017-04-26 19:17:18 +053046#elif HAVE_LIBDRM_FREEDRENO
47#include <freedreno/freedreno_drmif.h>
48#endif
Emmanuel Gil Peyrot8ef29572016-01-11 19:04:37 +000049#include <drm_fourcc.h>
George Kiagiadakis53868982014-06-12 16:26:49 +020050
51#include <wayland-client.h>
Bryce Harrington0d1a6222016-02-11 16:42:49 -080052#include "shared/zalloc.h"
Jonas Ådahl42682622016-08-11 23:44:41 +080053#include "xdg-shell-unstable-v6-client-protocol.h"
Jonas Ådahl496adb32015-11-17 16:00:27 +080054#include "fullscreen-shell-unstable-v1-client-protocol.h"
Jonas Ådahl57e48f02015-11-17 16:00:28 +080055#include "linux-dmabuf-unstable-v1-client-protocol.h"
George Kiagiadakis53868982014-06-12 16:26:49 +020056
Varad Gautamf7b3a392017-04-26 19:17:18 +053057struct buffer;
58
George Kiagiadakis53868982014-06-12 16:26:49 +020059struct display {
60 struct wl_display *display;
61 struct wl_registry *registry;
62 struct wl_compositor *compositor;
Jonas Ådahl42682622016-08-11 23:44:41 +080063 struct zxdg_shell_v6 *shell;
Jonas Ådahl496adb32015-11-17 16:00:27 +080064 struct zwp_fullscreen_shell_v1 *fshell;
Jonas Ådahl57e48f02015-11-17 16:00:28 +080065 struct zwp_linux_dmabuf_v1 *dmabuf;
George Kiagiadakis53868982014-06-12 16:26:49 +020066 int xrgb8888_format_found;
Varad Gautam48be0be2017-04-26 19:16:00 +053067 int req_dmabuf_immediate;
George Kiagiadakis53868982014-06-12 16:26:49 +020068};
69
Varad Gautamf7b3a392017-04-26 19:17:18 +053070struct drm_device {
71 int fd;
72 char *name;
73
74 int (*alloc_bo)(struct buffer *buf);
75 void (*free_bo)(struct buffer *buf);
76 int (*export_bo_to_prime)(struct buffer *buf);
77 int (*map_bo)(struct buffer *buf);
78 void (*unmap_bo)(struct buffer *buf);
79};
80
George Kiagiadakis53868982014-06-12 16:26:49 +020081struct buffer {
82 struct wl_buffer *buffer;
83 int busy;
84
Varad Gautamf7b3a392017-04-26 19:17:18 +053085 struct drm_device *dev;
George Kiagiadakis53868982014-06-12 16:26:49 +020086 int drm_fd;
87
Varad Gautamf7b3a392017-04-26 19:17:18 +053088#ifdef HAVE_LIBDRM_INTEL
George Kiagiadakis53868982014-06-12 16:26:49 +020089 drm_intel_bufmgr *bufmgr;
90 drm_intel_bo *bo;
Varad Gautamf7b3a392017-04-26 19:17:18 +053091#elif HAVE_LIBDRM_FREEDRENO
92 struct fd_device *fd_dev;
93 struct fd_bo *bo;
94#endif /* HAVE_LIBDRM_FREEDRENO */
George Kiagiadakis53868982014-06-12 16:26:49 +020095
96 uint32_t gem_handle;
97 int dmabuf_fd;
98 uint8_t *mmap;
99
100 int width;
101 int height;
102 int bpp;
103 unsigned long stride;
104};
105
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300106#define NUM_BUFFERS 3
107
George Kiagiadakis53868982014-06-12 16:26:49 +0200108struct window {
109 struct display *display;
110 int width, height;
111 struct wl_surface *surface;
Jonas Ådahl42682622016-08-11 23:44:41 +0800112 struct zxdg_surface_v6 *xdg_surface;
113 struct zxdg_toplevel_v6 *xdg_toplevel;
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300114 struct buffer buffers[NUM_BUFFERS];
George Kiagiadakis53868982014-06-12 16:26:49 +0200115 struct buffer *prev_buffer;
116 struct wl_callback *callback;
Jonas Ådahl42682622016-08-11 23:44:41 +0800117 bool initialized;
118 bool wait_for_configure;
George Kiagiadakis53868982014-06-12 16:26:49 +0200119};
120
121static int running = 1;
122
123static void
Jonas Ådahl42682622016-08-11 23:44:41 +0800124redraw(void *data, struct wl_callback *callback, uint32_t time);
125
126static void
George Kiagiadakis53868982014-06-12 16:26:49 +0200127buffer_release(void *data, struct wl_buffer *buffer)
128{
129 struct buffer *mybuf = data;
130
131 mybuf->busy = 0;
132}
133
134static const struct wl_buffer_listener buffer_listener = {
135 buffer_release
136};
137
Varad Gautamf7b3a392017-04-26 19:17:18 +0530138
139#ifdef HAVE_LIBDRM_INTEL
George Kiagiadakis53868982014-06-12 16:26:49 +0200140static int
Varad Gautamf7b3a392017-04-26 19:17:18 +0530141intel_alloc_bo(struct buffer *my_buf)
George Kiagiadakis53868982014-06-12 16:26:49 +0200142{
143 /* XXX: try different tiling modes for testing FB modifiers. */
144 uint32_t tiling = I915_TILING_NONE;
145
146 assert(my_buf->bufmgr);
147
148 my_buf->bo = drm_intel_bo_alloc_tiled(my_buf->bufmgr, "test",
149 my_buf->width, my_buf->height,
150 (my_buf->bpp / 8), &tiling,
151 &my_buf->stride, 0);
152
153 printf("buffer allocated w %d, h %d, stride %lu, size %lu\n",
154 my_buf->width, my_buf->height, my_buf->stride, my_buf->bo->size);
155
156 if (!my_buf->bo)
157 return 0;
158
159 if (tiling != I915_TILING_NONE)
160 return 0;
161
162 return 1;
163}
164
165static void
Varad Gautamf7b3a392017-04-26 19:17:18 +0530166intel_free_bo(struct buffer *my_buf)
George Kiagiadakis53868982014-06-12 16:26:49 +0200167{
168 drm_intel_bo_unreference(my_buf->bo);
169}
170
171static int
Varad Gautamf7b3a392017-04-26 19:17:18 +0530172intel_map_bo(struct buffer *my_buf)
George Kiagiadakis53868982014-06-12 16:26:49 +0200173{
174 if (drm_intel_gem_bo_map_gtt(my_buf->bo) != 0)
175 return 0;
176
177 my_buf->mmap = my_buf->bo->virtual;
178
179 return 1;
180}
181
Varad Gautamf7b3a392017-04-26 19:17:18 +0530182static int
183intel_bo_export_to_prime(struct buffer *buffer)
184{
185 return drm_intel_bo_gem_export_to_prime(buffer->bo, &buffer->dmabuf_fd);
186}
187
188static void
189intel_unmap_bo(struct buffer *my_buf)
190{
191 drm_intel_gem_bo_unmap_gtt(my_buf->bo);
192}
193#elif HAVE_LIBDRM_FREEDRENO
194#define ALIGN(v, a) ((v + a - 1) & ~(a - 1))
195
196static
197int fd_alloc_bo(struct buffer *buf)
198{
199 int flags = DRM_FREEDRENO_GEM_CACHE_WCOMBINE;
200 int size = buf->width * buf->height * buf->bpp / 8;
201 buf->fd_dev = fd_device_new(buf->drm_fd);
202
203 buf->bo = fd_bo_new(buf->fd_dev, size, flags);
204
205 if (!buf->bo)
206 return 0;
207 buf->stride = ALIGN(buf->width, 32) * buf->bpp / 8;
208 return 1;
209}
210
211static
212void fd_free_bo(struct buffer *buf)
213{
214 fd_bo_del(buf->bo);
215}
216
217static
218int fd_bo_export_to_prime(struct buffer *buf)
219{
220 buf->dmabuf_fd = fd_bo_dmabuf(buf->bo);
221 if (buf->dmabuf_fd > 0)
222 return 0;
223
224 return 1;
225}
226
227static
228int fd_map_bo(struct buffer *buf)
229{
230 buf->mmap = fd_bo_map(buf->bo);
231
232 if (buf->mmap != NULL)
233 return 1;
234
235 return 0;
236}
237
238static
239void fd_unmap_bo(struct buffer *buf)
240{
241}
242#endif
243
George Kiagiadakis53868982014-06-12 16:26:49 +0200244static void
245fill_content(struct buffer *my_buf)
246{
247 int x = 0, y = 0;
248 uint32_t *pix;
249
250 assert(my_buf->mmap);
251
252 for (y = 0; y < my_buf->height; y++) {
253 pix = (uint32_t *)(my_buf->mmap + y * my_buf->stride);
254 for (x = 0; x < my_buf->width; x++) {
255 *pix++ = (0xff << 24) | ((x % 256) << 16) |
256 ((y % 256) << 8) | 0xf0;
257 }
258 }
259}
260
261static void
Varad Gautamf7b3a392017-04-26 19:17:18 +0530262drm_device_destroy(struct buffer *buf)
George Kiagiadakis53868982014-06-12 16:26:49 +0200263{
Varad Gautamf7b3a392017-04-26 19:17:18 +0530264#ifdef HAVE_LIBDRM_INTEL
265 drm_intel_bufmgr_destroy(buf->bufmgr);
266#elif HAVE_LIBDRM_FREEDRENO
267 fd_device_del(buf->fd_dev);
268#endif
269
270 close(buf->drm_fd);
George Kiagiadakis53868982014-06-12 16:26:49 +0200271}
272
Varad Gautamf7b3a392017-04-26 19:17:18 +0530273static int
274drm_device_init(struct buffer *buf)
275{
276 struct drm_device *dev = calloc(1, sizeof(struct drm_device));
277
278 drmVersionPtr version = drmGetVersion(buf->drm_fd);
279
280 dev->fd = buf->drm_fd;
281 dev->name = strdup(version->name);
282 if (0) {
283 /* nothing */
284 }
285#ifdef HAVE_LIBDRM_INTEL
286 else if (!strcmp(dev->name, "i915")) {
287 buf->bufmgr = drm_intel_bufmgr_gem_init(buf->drm_fd, 32);
288 if (!buf->bufmgr)
289 return 0;
290 dev->alloc_bo = intel_alloc_bo;
291 dev->free_bo = intel_free_bo;
292 dev->export_bo_to_prime = intel_bo_export_to_prime;
293 dev->map_bo = intel_map_bo;
294 dev->unmap_bo = intel_unmap_bo;
295 }
296#elif HAVE_LIBDRM_FREEDRENO
297 else if (!strcmp(dev->name, "msm")) {
298 dev->alloc_bo = fd_alloc_bo;
299 dev->free_bo = fd_free_bo;
300 dev->export_bo_to_prime = fd_bo_export_to_prime;
301 dev->map_bo = fd_map_bo;
302 dev->unmap_bo = fd_unmap_bo;
303 }
304#endif
305 else {
306 fprintf(stderr, "Error: drm device %s unsupported.\n",
307 dev->name);
308 free(dev);
309 return 0;
310 }
311 buf->dev = dev;
312 return 1;
313}
314
315static int
316drm_connect(struct buffer *my_buf)
317{
318 /* This won't work with card0 as we need to be authenticated; instead,
319 * boot with drm.rnodes=1 and use that. */
320 my_buf->drm_fd = open("/dev/dri/renderD128", O_RDWR);
321 if (my_buf->drm_fd < 0)
322 return 0;
323
324 return drm_device_init(my_buf);
325}
326
327static void
328drm_shutdown(struct buffer *my_buf)
329{
330 drm_device_destroy(my_buf);
331}
332
333
George Kiagiadakis53868982014-06-12 16:26:49 +0200334static void
335create_succeeded(void *data,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800336 struct zwp_linux_buffer_params_v1 *params,
George Kiagiadakis53868982014-06-12 16:26:49 +0200337 struct wl_buffer *new_buffer)
338{
339 struct buffer *buffer = data;
340
341 buffer->buffer = new_buffer;
342 wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
343
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800344 zwp_linux_buffer_params_v1_destroy(params);
George Kiagiadakis53868982014-06-12 16:26:49 +0200345}
346
347static void
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800348create_failed(void *data, struct zwp_linux_buffer_params_v1 *params)
George Kiagiadakis53868982014-06-12 16:26:49 +0200349{
350 struct buffer *buffer = data;
351
352 buffer->buffer = NULL;
Emmanuel Gil Peyrot8ef29572016-01-11 19:04:37 +0000353 running = 0;
George Kiagiadakis53868982014-06-12 16:26:49 +0200354
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800355 zwp_linux_buffer_params_v1_destroy(params);
George Kiagiadakis53868982014-06-12 16:26:49 +0200356
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800357 fprintf(stderr, "Error: zwp_linux_buffer_params.create failed.\n");
George Kiagiadakis53868982014-06-12 16:26:49 +0200358}
359
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800360static const struct zwp_linux_buffer_params_v1_listener params_listener = {
George Kiagiadakis53868982014-06-12 16:26:49 +0200361 create_succeeded,
362 create_failed
363};
364
365static int
366create_dmabuf_buffer(struct display *display, struct buffer *buffer,
367 int width, int height)
368{
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800369 struct zwp_linux_buffer_params_v1 *params;
George Kiagiadakis53868982014-06-12 16:26:49 +0200370 uint64_t modifier;
371 uint32_t flags;
Varad Gautamf7b3a392017-04-26 19:17:18 +0530372 struct drm_device *drm_dev;
George Kiagiadakis53868982014-06-12 16:26:49 +0200373
374 if (!drm_connect(buffer)) {
375 fprintf(stderr, "drm_connect failed\n");
376 goto error;
377 }
Varad Gautamf7b3a392017-04-26 19:17:18 +0530378 drm_dev = buffer->dev;
George Kiagiadakis53868982014-06-12 16:26:49 +0200379
380 buffer->width = width;
381 buffer->height = height;
382 buffer->bpp = 32; /* hardcoded XRGB8888 format */
383
Varad Gautamf7b3a392017-04-26 19:17:18 +0530384 if (!drm_dev->alloc_bo(buffer)) {
George Kiagiadakis53868982014-06-12 16:26:49 +0200385 fprintf(stderr, "alloc_bo failed\n");
386 goto error1;
387 }
388
Varad Gautamf7b3a392017-04-26 19:17:18 +0530389 if (!drm_dev->map_bo(buffer)) {
George Kiagiadakis53868982014-06-12 16:26:49 +0200390 fprintf(stderr, "map_bo failed\n");
391 goto error2;
392 }
393 fill_content(buffer);
Varad Gautamf7b3a392017-04-26 19:17:18 +0530394 drm_dev->unmap_bo(buffer);
George Kiagiadakis53868982014-06-12 16:26:49 +0200395
Varad Gautamf7b3a392017-04-26 19:17:18 +0530396 if (drm_dev->export_bo_to_prime(buffer) != 0) {
397 fprintf(stderr, "gem_export_to_prime failed\n");
George Kiagiadakis53868982014-06-12 16:26:49 +0200398 goto error2;
399 }
400 if (buffer->dmabuf_fd < 0) {
401 fprintf(stderr, "error: dmabuf_fd < 0\n");
402 goto error2;
403 }
404
405 /* We now have a dmabuf! It should contain 2x2 tiles (i.e. each tile
406 * is 256x256) of misc colours, and be mappable, either as ARGB8888, or
407 * XRGB8888. */
408 modifier = 0;
409 flags = 0;
410
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800411 params = zwp_linux_dmabuf_v1_create_params(display->dmabuf);
412 zwp_linux_buffer_params_v1_add(params,
413 buffer->dmabuf_fd,
414 0, /* plane_idx */
415 0, /* offset */
416 buffer->stride,
417 modifier >> 32,
418 modifier & 0xffffffff);
419 zwp_linux_buffer_params_v1_add_listener(params, &params_listener, buffer);
Varad Gautam48be0be2017-04-26 19:16:00 +0530420 if (display->req_dmabuf_immediate) {
421 buffer->buffer = zwp_linux_buffer_params_v1_create_immed(params,
422 buffer->width,
423 buffer->height,
424 DRM_FORMAT_XRGB8888,
425 flags);
426 wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
427 }
428 else
429 zwp_linux_buffer_params_v1_create(params,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800430 buffer->width,
431 buffer->height,
432 DRM_FORMAT_XRGB8888,
433 flags);
George Kiagiadakis53868982014-06-12 16:26:49 +0200434
George Kiagiadakis53868982014-06-12 16:26:49 +0200435 return 0;
436
437error2:
Varad Gautamf7b3a392017-04-26 19:17:18 +0530438 drm_dev->free_bo(buffer);
George Kiagiadakis53868982014-06-12 16:26:49 +0200439error1:
440 drm_shutdown(buffer);
441error:
442 return -1;
443}
444
445static void
Jonas Ådahl42682622016-08-11 23:44:41 +0800446xdg_surface_handle_configure(void *data, struct zxdg_surface_v6 *surface,
447 uint32_t serial)
448{
449 struct window *window = data;
450
451 zxdg_surface_v6_ack_configure(surface, serial);
452
453 if (window->initialized && window->wait_for_configure)
454 redraw(window, NULL, 0);
455 window->wait_for_configure = false;
456}
457
458static const struct zxdg_surface_v6_listener xdg_surface_listener = {
459 xdg_surface_handle_configure,
460};
461
462static void
463xdg_toplevel_handle_configure(void *data, struct zxdg_toplevel_v6 *toplevel,
464 int32_t width, int32_t height,
465 struct wl_array *states)
George Kiagiadakis53868982014-06-12 16:26:49 +0200466{
467}
468
469static void
Jonas Ådahl42682622016-08-11 23:44:41 +0800470xdg_toplevel_handle_close(void *data, struct zxdg_toplevel_v6 *xdg_toplevel)
George Kiagiadakis53868982014-06-12 16:26:49 +0200471{
472 running = 0;
473}
474
Jonas Ådahl42682622016-08-11 23:44:41 +0800475static const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
476 xdg_toplevel_handle_configure,
477 xdg_toplevel_handle_close,
George Kiagiadakis53868982014-06-12 16:26:49 +0200478};
479
480static struct window *
481create_window(struct display *display, int width, int height)
482{
483 struct window *window;
Emmanuel Gil Peyrot8ef29572016-01-11 19:04:37 +0000484 int i;
485 int ret;
George Kiagiadakis53868982014-06-12 16:26:49 +0200486
Bryce Harrington0d1a6222016-02-11 16:42:49 -0800487 window = zalloc(sizeof *window);
George Kiagiadakis53868982014-06-12 16:26:49 +0200488 if (!window)
489 return NULL;
490
491 window->callback = NULL;
492 window->display = display;
493 window->width = width;
494 window->height = height;
495 window->surface = wl_compositor_create_surface(display->compositor);
496
497 if (display->shell) {
498 window->xdg_surface =
Jonas Ådahl42682622016-08-11 23:44:41 +0800499 zxdg_shell_v6_get_xdg_surface(display->shell,
500 window->surface);
George Kiagiadakis53868982014-06-12 16:26:49 +0200501
502 assert(window->xdg_surface);
503
Jonas Ådahl42682622016-08-11 23:44:41 +0800504 zxdg_surface_v6_add_listener(window->xdg_surface,
505 &xdg_surface_listener, window);
George Kiagiadakis53868982014-06-12 16:26:49 +0200506
Jonas Ådahl42682622016-08-11 23:44:41 +0800507 window->xdg_toplevel =
508 zxdg_surface_v6_get_toplevel(window->xdg_surface);
509
510 assert(window->xdg_toplevel);
511
512 zxdg_toplevel_v6_add_listener(window->xdg_toplevel,
513 &xdg_toplevel_listener, window);
514
515 zxdg_toplevel_v6_set_title(window->xdg_toplevel, "simple-dmabuf");
516
517 window->wait_for_configure = true;
518 wl_surface_commit(window->surface);
George Kiagiadakis53868982014-06-12 16:26:49 +0200519 } else if (display->fshell) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800520 zwp_fullscreen_shell_v1_present_surface(display->fshell,
521 window->surface,
522 ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT,
523 NULL);
George Kiagiadakis53868982014-06-12 16:26:49 +0200524 } else {
525 assert(0);
526 }
527
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300528 for (i = 0; i < NUM_BUFFERS; ++i) {
Emmanuel Gil Peyrot8ef29572016-01-11 19:04:37 +0000529 ret = create_dmabuf_buffer(display, &window->buffers[i],
530 width, height);
531
532 if (ret < 0)
533 return NULL;
534 }
535
George Kiagiadakis53868982014-06-12 16:26:49 +0200536 return window;
537}
538
539static void
540destroy_window(struct window *window)
541{
Varad Gautamf7b3a392017-04-26 19:17:18 +0530542 struct drm_device* dev;
George Kiagiadakis53868982014-06-12 16:26:49 +0200543 int i;
544
545 if (window->callback)
546 wl_callback_destroy(window->callback);
547
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300548 for (i = 0; i < NUM_BUFFERS; i++) {
George Kiagiadakis53868982014-06-12 16:26:49 +0200549 if (!window->buffers[i].buffer)
550 continue;
551
552 wl_buffer_destroy(window->buffers[i].buffer);
Varad Gautamf7b3a392017-04-26 19:17:18 +0530553 dev = window->buffers[i].dev;
554 dev->free_bo(&window->buffers[i]);
George Kiagiadakis53868982014-06-12 16:26:49 +0200555 close(window->buffers[i].dmabuf_fd);
556 drm_shutdown(&window->buffers[i]);
557 }
558
Jonas Ådahl42682622016-08-11 23:44:41 +0800559 if (window->xdg_toplevel)
560 zxdg_toplevel_v6_destroy(window->xdg_toplevel);
George Kiagiadakis53868982014-06-12 16:26:49 +0200561 if (window->xdg_surface)
Jonas Ådahl42682622016-08-11 23:44:41 +0800562 zxdg_surface_v6_destroy(window->xdg_surface);
George Kiagiadakis53868982014-06-12 16:26:49 +0200563 wl_surface_destroy(window->surface);
564 free(window);
565}
566
567static struct buffer *
568window_next_buffer(struct window *window)
569{
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300570 int i;
George Kiagiadakis53868982014-06-12 16:26:49 +0200571
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300572 for (i = 0; i < NUM_BUFFERS; i++)
573 if (!window->buffers[i].busy)
574 return &window->buffers[i];
George Kiagiadakis53868982014-06-12 16:26:49 +0200575
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300576 return NULL;
George Kiagiadakis53868982014-06-12 16:26:49 +0200577}
578
579static const struct wl_callback_listener frame_listener;
580
581static void
582redraw(void *data, struct wl_callback *callback, uint32_t time)
583{
584 struct window *window = data;
585 struct buffer *buffer;
586
587 buffer = window_next_buffer(window);
588 if (!buffer) {
589 fprintf(stderr,
590 !callback ? "Failed to create the first buffer.\n" :
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300591 "All buffers busy at redraw(). Server bug?\n");
George Kiagiadakis53868982014-06-12 16:26:49 +0200592 abort();
593 }
594
595 /* XXX: would be nice to draw something that changes here... */
596
597 wl_surface_attach(window->surface, buffer->buffer, 0, 0);
598 wl_surface_damage(window->surface, 0, 0, window->width, window->height);
599
600 if (callback)
601 wl_callback_destroy(callback);
602
603 window->callback = wl_surface_frame(window->surface);
604 wl_callback_add_listener(window->callback, &frame_listener, window);
605 wl_surface_commit(window->surface);
606 buffer->busy = 1;
607}
608
609static const struct wl_callback_listener frame_listener = {
610 redraw
611};
612
613static void
Varad Gautamf7b3a392017-04-26 19:17:18 +0530614dmabuf_modifiers(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
615 uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo)
George Kiagiadakis53868982014-06-12 16:26:49 +0200616{
617 struct display *d = data;
618
619 if (format == DRM_FORMAT_XRGB8888)
620 d->xrgb8888_format_found = 1;
Varad Gautamf7b3a392017-04-26 19:17:18 +0530621
622 /* XXX: do something useful with modifiers */
623}
624
625static void
626dmabuf_format(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, uint32_t format)
627{
628 /* XXX: will be deprecated. */
George Kiagiadakis53868982014-06-12 16:26:49 +0200629}
630
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800631static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
Varad Gautamf7b3a392017-04-26 19:17:18 +0530632 dmabuf_format,
633 dmabuf_modifiers
George Kiagiadakis53868982014-06-12 16:26:49 +0200634};
635
636static void
Jonas Ådahl42682622016-08-11 23:44:41 +0800637xdg_shell_ping(void *data, struct zxdg_shell_v6 *shell, uint32_t serial)
George Kiagiadakis53868982014-06-12 16:26:49 +0200638{
Jonas Ådahl42682622016-08-11 23:44:41 +0800639 zxdg_shell_v6_pong(shell, serial);
George Kiagiadakis53868982014-06-12 16:26:49 +0200640}
641
Jonas Ådahl42682622016-08-11 23:44:41 +0800642static const struct zxdg_shell_v6_listener xdg_shell_listener = {
George Kiagiadakis53868982014-06-12 16:26:49 +0200643 xdg_shell_ping,
644};
645
George Kiagiadakis53868982014-06-12 16:26:49 +0200646static void
647registry_handle_global(void *data, struct wl_registry *registry,
648 uint32_t id, const char *interface, uint32_t version)
649{
650 struct display *d = data;
651
652 if (strcmp(interface, "wl_compositor") == 0) {
653 d->compositor =
654 wl_registry_bind(registry,
655 id, &wl_compositor_interface, 1);
Jonas Ådahl42682622016-08-11 23:44:41 +0800656 } else if (strcmp(interface, "zxdg_shell_v6") == 0) {
George Kiagiadakis53868982014-06-12 16:26:49 +0200657 d->shell = wl_registry_bind(registry,
Jonas Ådahl42682622016-08-11 23:44:41 +0800658 id, &zxdg_shell_v6_interface, 1);
659 zxdg_shell_v6_add_listener(d->shell, &xdg_shell_listener, d);
Jonas Ådahl496adb32015-11-17 16:00:27 +0800660 } else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
George Kiagiadakis53868982014-06-12 16:26:49 +0200661 d->fshell = wl_registry_bind(registry,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800662 id, &zwp_fullscreen_shell_v1_interface, 1);
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800663 } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
George Kiagiadakis53868982014-06-12 16:26:49 +0200664 d->dmabuf = wl_registry_bind(registry,
Varad Gautam48be0be2017-04-26 19:16:00 +0530665 id, &zwp_linux_dmabuf_v1_interface,
666 d->req_dmabuf_immediate ? 2 : 1);
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800667 zwp_linux_dmabuf_v1_add_listener(d->dmabuf, &dmabuf_listener, d);
George Kiagiadakis53868982014-06-12 16:26:49 +0200668 }
669}
670
671static void
672registry_handle_global_remove(void *data, struct wl_registry *registry,
673 uint32_t name)
674{
675}
676
677static const struct wl_registry_listener registry_listener = {
678 registry_handle_global,
679 registry_handle_global_remove
680};
681
682static struct display *
Varad Gautam48be0be2017-04-26 19:16:00 +0530683create_display(int is_immediate)
George Kiagiadakis53868982014-06-12 16:26:49 +0200684{
685 struct display *display;
686
687 display = malloc(sizeof *display);
688 if (display == NULL) {
689 fprintf(stderr, "out of memory\n");
690 exit(1);
691 }
692 display->display = wl_display_connect(NULL);
693 assert(display->display);
694
695 /* XXX: fake, because the compositor does not yet advertise anything */
696 display->xrgb8888_format_found = 1;
Varad Gautam48be0be2017-04-26 19:16:00 +0530697 display->req_dmabuf_immediate = is_immediate;
George Kiagiadakis53868982014-06-12 16:26:49 +0200698
699 display->registry = wl_display_get_registry(display->display);
700 wl_registry_add_listener(display->registry,
701 &registry_listener, display);
702 wl_display_roundtrip(display->display);
703 if (display->dmabuf == NULL) {
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800704 fprintf(stderr, "No zwp_linux_dmabuf global\n");
George Kiagiadakis53868982014-06-12 16:26:49 +0200705 exit(1);
706 }
707
708 wl_display_roundtrip(display->display);
709
710 if (!display->xrgb8888_format_found) {
711 fprintf(stderr, "DRM_FORMAT_XRGB8888 not available\n");
712 exit(1);
713 }
714
715 return display;
716}
717
718static void
719destroy_display(struct display *display)
720{
721 if (display->dmabuf)
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800722 zwp_linux_dmabuf_v1_destroy(display->dmabuf);
George Kiagiadakis53868982014-06-12 16:26:49 +0200723
724 if (display->shell)
Jonas Ådahl42682622016-08-11 23:44:41 +0800725 zxdg_shell_v6_destroy(display->shell);
George Kiagiadakis53868982014-06-12 16:26:49 +0200726
727 if (display->fshell)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800728 zwp_fullscreen_shell_v1_release(display->fshell);
George Kiagiadakis53868982014-06-12 16:26:49 +0200729
730 if (display->compositor)
731 wl_compositor_destroy(display->compositor);
732
733 wl_registry_destroy(display->registry);
734 wl_display_flush(display->display);
735 wl_display_disconnect(display->display);
736 free(display);
737}
738
739static void
740signal_int(int signum)
741{
742 running = 0;
743}
744
745int
746main(int argc, char **argv)
747{
748 struct sigaction sigint;
749 struct display *display;
750 struct window *window;
Varad Gautam48be0be2017-04-26 19:16:00 +0530751 int is_immediate = 0;
George Kiagiadakis53868982014-06-12 16:26:49 +0200752 int ret = 0;
753
Varad Gautam48be0be2017-04-26 19:16:00 +0530754 if (argc > 1) {
755 if (!strcmp(argv[1], "immed")) {
756 is_immediate = 1;
757 }
758 else {
759 fprintf(stderr, "usage:\n\tsimple-dmabuf-intel [options]\n"
760 "available options:\n\timmed: avoid dmabuf "
761 "creation roundtrip and import immediately\n");
762 return 1;
763 }
764 }
765
766 display = create_display(is_immediate);
George Kiagiadakis53868982014-06-12 16:26:49 +0200767 window = create_window(display, 250, 250);
768 if (!window)
769 return 1;
770
771 sigint.sa_handler = signal_int;
772 sigemptyset(&sigint.sa_mask);
773 sigint.sa_flags = SA_RESETHAND;
774 sigaction(SIGINT, &sigint, NULL);
775
Varad Gautam48be0be2017-04-26 19:16:00 +0530776 /* Here we retrieve the linux-dmabuf objects if executed without immed,
777 * or error */
Emmanuel Gil Peyrot8ef29572016-01-11 19:04:37 +0000778 wl_display_roundtrip(display->display);
779
780 if (!running)
781 return 1;
George Kiagiadakis53868982014-06-12 16:26:49 +0200782
Jonas Ådahl42682622016-08-11 23:44:41 +0800783 window->initialized = true;
784
785 if (!window->wait_for_configure)
786 redraw(window, NULL, 0);
George Kiagiadakis53868982014-06-12 16:26:49 +0200787
788 while (running && ret != -1)
789 ret = wl_display_dispatch(display->display);
790
791 fprintf(stderr, "simple-dmabuf exiting\n");
792 destroy_window(window);
793 destroy_display(display);
794
795 return 0;
796}