blob: 14d716de12e62c29266a50a15a5ad77ac12b8df6 [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"
Varad Gautamee589112016-11-23 14:03:21 +053029#include "simple-dmabuf-drm-data.h"
George Kiagiadakis53868982014-06-12 16:26:49 +020030
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030031#include <stdint.h>
George Kiagiadakis53868982014-06-12 16:26:49 +020032#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <stdbool.h>
36#include <assert.h>
37#include <unistd.h>
38#include <sys/mman.h>
39#include <signal.h>
40#include <fcntl.h>
41
42#include <xf86drm.h>
Varad Gautamf7b3a392017-04-26 19:17:18 +053043
44#ifdef HAVE_LIBDRM_INTEL
Emmanuel Gil Peyrot8ef29572016-01-11 19:04:37 +000045#include <i915_drm.h>
46#include <intel_bufmgr.h>
Varad Gautamf7b3a392017-04-26 19:17:18 +053047#elif HAVE_LIBDRM_FREEDRENO
48#include <freedreno/freedreno_drmif.h>
49#endif
Emmanuel Gil Peyrot8ef29572016-01-11 19:04:37 +000050#include <drm_fourcc.h>
George Kiagiadakis53868982014-06-12 16:26:49 +020051
52#include <wayland-client.h>
Bryce Harrington0d1a6222016-02-11 16:42:49 -080053#include "shared/zalloc.h"
Varad Gautamee589112016-11-23 14:03:21 +053054#include "shared/platform.h"
Jonas Ådahl42682622016-08-11 23:44:41 +080055#include "xdg-shell-unstable-v6-client-protocol.h"
Jonas Ådahl496adb32015-11-17 16:00:27 +080056#include "fullscreen-shell-unstable-v1-client-protocol.h"
Jonas Ådahl57e48f02015-11-17 16:00:28 +080057#include "linux-dmabuf-unstable-v1-client-protocol.h"
George Kiagiadakis53868982014-06-12 16:26:49 +020058
Varad Gautamee589112016-11-23 14:03:21 +053059extern const unsigned nv12_tiled[];
Varad Gautamf7b3a392017-04-26 19:17:18 +053060struct buffer;
61
George Kiagiadakis53868982014-06-12 16:26:49 +020062struct display {
63 struct wl_display *display;
64 struct wl_registry *registry;
65 struct wl_compositor *compositor;
Jonas Ådahl42682622016-08-11 23:44:41 +080066 struct zxdg_shell_v6 *shell;
Jonas Ådahl496adb32015-11-17 16:00:27 +080067 struct zwp_fullscreen_shell_v1 *fshell;
Jonas Ådahl57e48f02015-11-17 16:00:28 +080068 struct zwp_linux_dmabuf_v1 *dmabuf;
George Kiagiadakis53868982014-06-12 16:26:49 +020069 int xrgb8888_format_found;
Varad Gautamee589112016-11-23 14:03:21 +053070 int nv12_format_found;
71 int nv12_modifier_found;
Varad Gautam48be0be2017-04-26 19:16:00 +053072 int req_dmabuf_immediate;
Varad Gautamee589112016-11-23 14:03:21 +053073 int req_dmabuf_modifiers;
George Kiagiadakis53868982014-06-12 16:26:49 +020074};
75
Varad Gautamf7b3a392017-04-26 19:17:18 +053076struct drm_device {
77 int fd;
78 char *name;
79
80 int (*alloc_bo)(struct buffer *buf);
81 void (*free_bo)(struct buffer *buf);
82 int (*export_bo_to_prime)(struct buffer *buf);
83 int (*map_bo)(struct buffer *buf);
84 void (*unmap_bo)(struct buffer *buf);
85};
86
George Kiagiadakis53868982014-06-12 16:26:49 +020087struct buffer {
88 struct wl_buffer *buffer;
89 int busy;
90
Varad Gautamf7b3a392017-04-26 19:17:18 +053091 struct drm_device *dev;
George Kiagiadakis53868982014-06-12 16:26:49 +020092 int drm_fd;
93
Varad Gautamf7b3a392017-04-26 19:17:18 +053094#ifdef HAVE_LIBDRM_INTEL
George Kiagiadakis53868982014-06-12 16:26:49 +020095 drm_intel_bufmgr *bufmgr;
96 drm_intel_bo *bo;
Varad Gautamf7b3a392017-04-26 19:17:18 +053097#elif HAVE_LIBDRM_FREEDRENO
98 struct fd_device *fd_dev;
99 struct fd_bo *bo;
100#endif /* HAVE_LIBDRM_FREEDRENO */
George Kiagiadakis53868982014-06-12 16:26:49 +0200101
102 uint32_t gem_handle;
103 int dmabuf_fd;
104 uint8_t *mmap;
105
106 int width;
107 int height;
108 int bpp;
109 unsigned long stride;
Varad Gautamee589112016-11-23 14:03:21 +0530110 int format;
George Kiagiadakis53868982014-06-12 16:26:49 +0200111};
112
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300113#define NUM_BUFFERS 3
114
George Kiagiadakis53868982014-06-12 16:26:49 +0200115struct window {
116 struct display *display;
117 int width, height;
118 struct wl_surface *surface;
Jonas Ådahl42682622016-08-11 23:44:41 +0800119 struct zxdg_surface_v6 *xdg_surface;
120 struct zxdg_toplevel_v6 *xdg_toplevel;
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300121 struct buffer buffers[NUM_BUFFERS];
George Kiagiadakis53868982014-06-12 16:26:49 +0200122 struct buffer *prev_buffer;
123 struct wl_callback *callback;
Jonas Ådahl42682622016-08-11 23:44:41 +0800124 bool initialized;
125 bool wait_for_configure;
George Kiagiadakis53868982014-06-12 16:26:49 +0200126};
127
128static int running = 1;
129
130static void
Jonas Ådahl42682622016-08-11 23:44:41 +0800131redraw(void *data, struct wl_callback *callback, uint32_t time);
132
133static void
George Kiagiadakis53868982014-06-12 16:26:49 +0200134buffer_release(void *data, struct wl_buffer *buffer)
135{
136 struct buffer *mybuf = data;
137
138 mybuf->busy = 0;
139}
140
141static const struct wl_buffer_listener buffer_listener = {
142 buffer_release
143};
144
Varad Gautamf7b3a392017-04-26 19:17:18 +0530145
146#ifdef HAVE_LIBDRM_INTEL
George Kiagiadakis53868982014-06-12 16:26:49 +0200147static int
Varad Gautamf7b3a392017-04-26 19:17:18 +0530148intel_alloc_bo(struct buffer *my_buf)
George Kiagiadakis53868982014-06-12 16:26:49 +0200149{
150 /* XXX: try different tiling modes for testing FB modifiers. */
151 uint32_t tiling = I915_TILING_NONE;
152
153 assert(my_buf->bufmgr);
154
155 my_buf->bo = drm_intel_bo_alloc_tiled(my_buf->bufmgr, "test",
156 my_buf->width, my_buf->height,
157 (my_buf->bpp / 8), &tiling,
158 &my_buf->stride, 0);
159
160 printf("buffer allocated w %d, h %d, stride %lu, size %lu\n",
161 my_buf->width, my_buf->height, my_buf->stride, my_buf->bo->size);
162
163 if (!my_buf->bo)
164 return 0;
165
166 if (tiling != I915_TILING_NONE)
167 return 0;
168
169 return 1;
170}
171
172static void
Varad Gautamf7b3a392017-04-26 19:17:18 +0530173intel_free_bo(struct buffer *my_buf)
George Kiagiadakis53868982014-06-12 16:26:49 +0200174{
175 drm_intel_bo_unreference(my_buf->bo);
176}
177
178static int
Varad Gautamf7b3a392017-04-26 19:17:18 +0530179intel_map_bo(struct buffer *my_buf)
George Kiagiadakis53868982014-06-12 16:26:49 +0200180{
181 if (drm_intel_gem_bo_map_gtt(my_buf->bo) != 0)
182 return 0;
183
184 my_buf->mmap = my_buf->bo->virtual;
185
186 return 1;
187}
188
Varad Gautamf7b3a392017-04-26 19:17:18 +0530189static int
190intel_bo_export_to_prime(struct buffer *buffer)
191{
192 return drm_intel_bo_gem_export_to_prime(buffer->bo, &buffer->dmabuf_fd);
193}
194
195static void
196intel_unmap_bo(struct buffer *my_buf)
197{
198 drm_intel_gem_bo_unmap_gtt(my_buf->bo);
199}
200#elif HAVE_LIBDRM_FREEDRENO
201#define ALIGN(v, a) ((v + a - 1) & ~(a - 1))
202
203static
204int fd_alloc_bo(struct buffer *buf)
205{
206 int flags = DRM_FREEDRENO_GEM_CACHE_WCOMBINE;
207 int size = buf->width * buf->height * buf->bpp / 8;
208 buf->fd_dev = fd_device_new(buf->drm_fd);
209
210 buf->bo = fd_bo_new(buf->fd_dev, size, flags);
211
212 if (!buf->bo)
213 return 0;
214 buf->stride = ALIGN(buf->width, 32) * buf->bpp / 8;
215 return 1;
216}
217
218static
219void fd_free_bo(struct buffer *buf)
220{
221 fd_bo_del(buf->bo);
222}
223
224static
225int fd_bo_export_to_prime(struct buffer *buf)
226{
227 buf->dmabuf_fd = fd_bo_dmabuf(buf->bo);
228 if (buf->dmabuf_fd > 0)
229 return 0;
230
231 return 1;
232}
233
234static
235int fd_map_bo(struct buffer *buf)
236{
237 buf->mmap = fd_bo_map(buf->bo);
238
239 if (buf->mmap != NULL)
240 return 1;
241
242 return 0;
243}
244
245static
246void fd_unmap_bo(struct buffer *buf)
247{
248}
249#endif
250
George Kiagiadakis53868982014-06-12 16:26:49 +0200251static void
252fill_content(struct buffer *my_buf)
253{
254 int x = 0, y = 0;
255 uint32_t *pix;
256
257 assert(my_buf->mmap);
258
Varad Gautamee589112016-11-23 14:03:21 +0530259 if (my_buf->format == DRM_FORMAT_NV12) {
260 pix = (uint32_t *) my_buf->mmap;
261 for (y = 0; y < my_buf->height; y++)
262 memcpy(&pix[y * my_buf->width / 4],
263 &nv12_tiled[my_buf->width * y / 4],
264 my_buf->width);
265 }
266 else {
267 for (y = 0; y < my_buf->height; y++) {
268 pix = (uint32_t *)(my_buf->mmap + y * my_buf->stride);
269 for (x = 0; x < my_buf->width; x++)
270 *pix++ = (0xff << 24) | ((x % 256) << 16) |
271 ((y % 256) << 8) | 0xf0;
George Kiagiadakis53868982014-06-12 16:26:49 +0200272 }
273 }
274}
275
276static void
Varad Gautamf7b3a392017-04-26 19:17:18 +0530277drm_device_destroy(struct buffer *buf)
George Kiagiadakis53868982014-06-12 16:26:49 +0200278{
Varad Gautamf7b3a392017-04-26 19:17:18 +0530279#ifdef HAVE_LIBDRM_INTEL
280 drm_intel_bufmgr_destroy(buf->bufmgr);
281#elif HAVE_LIBDRM_FREEDRENO
282 fd_device_del(buf->fd_dev);
283#endif
284
285 close(buf->drm_fd);
George Kiagiadakis53868982014-06-12 16:26:49 +0200286}
287
Varad Gautamf7b3a392017-04-26 19:17:18 +0530288static int
289drm_device_init(struct buffer *buf)
290{
291 struct drm_device *dev = calloc(1, sizeof(struct drm_device));
292
293 drmVersionPtr version = drmGetVersion(buf->drm_fd);
294
295 dev->fd = buf->drm_fd;
296 dev->name = strdup(version->name);
297 if (0) {
298 /* nothing */
299 }
300#ifdef HAVE_LIBDRM_INTEL
301 else if (!strcmp(dev->name, "i915")) {
302 buf->bufmgr = drm_intel_bufmgr_gem_init(buf->drm_fd, 32);
303 if (!buf->bufmgr)
304 return 0;
305 dev->alloc_bo = intel_alloc_bo;
306 dev->free_bo = intel_free_bo;
307 dev->export_bo_to_prime = intel_bo_export_to_prime;
308 dev->map_bo = intel_map_bo;
309 dev->unmap_bo = intel_unmap_bo;
310 }
311#elif HAVE_LIBDRM_FREEDRENO
312 else if (!strcmp(dev->name, "msm")) {
313 dev->alloc_bo = fd_alloc_bo;
314 dev->free_bo = fd_free_bo;
315 dev->export_bo_to_prime = fd_bo_export_to_prime;
316 dev->map_bo = fd_map_bo;
317 dev->unmap_bo = fd_unmap_bo;
318 }
319#endif
320 else {
321 fprintf(stderr, "Error: drm device %s unsupported.\n",
322 dev->name);
323 free(dev);
324 return 0;
325 }
326 buf->dev = dev;
327 return 1;
328}
329
330static int
331drm_connect(struct buffer *my_buf)
332{
333 /* This won't work with card0 as we need to be authenticated; instead,
334 * boot with drm.rnodes=1 and use that. */
335 my_buf->drm_fd = open("/dev/dri/renderD128", O_RDWR);
336 if (my_buf->drm_fd < 0)
337 return 0;
338
339 return drm_device_init(my_buf);
340}
341
342static void
343drm_shutdown(struct buffer *my_buf)
344{
345 drm_device_destroy(my_buf);
346}
347
348
George Kiagiadakis53868982014-06-12 16:26:49 +0200349static void
350create_succeeded(void *data,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800351 struct zwp_linux_buffer_params_v1 *params,
George Kiagiadakis53868982014-06-12 16:26:49 +0200352 struct wl_buffer *new_buffer)
353{
354 struct buffer *buffer = data;
355
356 buffer->buffer = new_buffer;
357 wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
358
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800359 zwp_linux_buffer_params_v1_destroy(params);
George Kiagiadakis53868982014-06-12 16:26:49 +0200360}
361
362static void
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800363create_failed(void *data, struct zwp_linux_buffer_params_v1 *params)
George Kiagiadakis53868982014-06-12 16:26:49 +0200364{
365 struct buffer *buffer = data;
366
367 buffer->buffer = NULL;
Emmanuel Gil Peyrot8ef29572016-01-11 19:04:37 +0000368 running = 0;
George Kiagiadakis53868982014-06-12 16:26:49 +0200369
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800370 zwp_linux_buffer_params_v1_destroy(params);
George Kiagiadakis53868982014-06-12 16:26:49 +0200371
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800372 fprintf(stderr, "Error: zwp_linux_buffer_params.create failed.\n");
George Kiagiadakis53868982014-06-12 16:26:49 +0200373}
374
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800375static const struct zwp_linux_buffer_params_v1_listener params_listener = {
George Kiagiadakis53868982014-06-12 16:26:49 +0200376 create_succeeded,
377 create_failed
378};
379
380static int
381create_dmabuf_buffer(struct display *display, struct buffer *buffer,
Varad Gautamee589112016-11-23 14:03:21 +0530382 int width, int height, int format)
George Kiagiadakis53868982014-06-12 16:26:49 +0200383{
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800384 struct zwp_linux_buffer_params_v1 *params;
Varad Gautamee589112016-11-23 14:03:21 +0530385 uint64_t modifier = 0;
George Kiagiadakis53868982014-06-12 16:26:49 +0200386 uint32_t flags;
Varad Gautamf7b3a392017-04-26 19:17:18 +0530387 struct drm_device *drm_dev;
George Kiagiadakis53868982014-06-12 16:26:49 +0200388
389 if (!drm_connect(buffer)) {
390 fprintf(stderr, "drm_connect failed\n");
391 goto error;
392 }
Varad Gautamf7b3a392017-04-26 19:17:18 +0530393 drm_dev = buffer->dev;
George Kiagiadakis53868982014-06-12 16:26:49 +0200394
395 buffer->width = width;
Varad Gautamee589112016-11-23 14:03:21 +0530396 switch (format) {
397 case DRM_FORMAT_NV12:
398 /* adjust height for allocation of NV12 Y and UV planes */
399 buffer->height = height * 3 / 2;
400 buffer->bpp = 8;
401 modifier = DRM_FORMAT_MOD_SAMSUNG_64_32_TILE;
402 break;
403 default:
404 buffer->height = height;
405 buffer->bpp = 32;
406 }
407 buffer->format = format;
George Kiagiadakis53868982014-06-12 16:26:49 +0200408
Varad Gautamf7b3a392017-04-26 19:17:18 +0530409 if (!drm_dev->alloc_bo(buffer)) {
George Kiagiadakis53868982014-06-12 16:26:49 +0200410 fprintf(stderr, "alloc_bo failed\n");
411 goto error1;
412 }
413
Varad Gautamf7b3a392017-04-26 19:17:18 +0530414 if (!drm_dev->map_bo(buffer)) {
George Kiagiadakis53868982014-06-12 16:26:49 +0200415 fprintf(stderr, "map_bo failed\n");
416 goto error2;
417 }
418 fill_content(buffer);
Varad Gautamf7b3a392017-04-26 19:17:18 +0530419 drm_dev->unmap_bo(buffer);
George Kiagiadakis53868982014-06-12 16:26:49 +0200420
Varad Gautamf7b3a392017-04-26 19:17:18 +0530421 if (drm_dev->export_bo_to_prime(buffer) != 0) {
422 fprintf(stderr, "gem_export_to_prime failed\n");
George Kiagiadakis53868982014-06-12 16:26:49 +0200423 goto error2;
424 }
425 if (buffer->dmabuf_fd < 0) {
426 fprintf(stderr, "error: dmabuf_fd < 0\n");
427 goto error2;
428 }
429
Varad Gautamee589112016-11-23 14:03:21 +0530430 /* We now have a dmabuf! For format XRGB8888, it should contain 2x2
431 * tiles (i.e. each tile is 256x256) of misc colours, and be mappable,
432 * either as ARGB8888, or XRGB8888. For format NV12, it should contain
433 * the Y and UV components, and needs to be re-adjusted for passing the
434 * correct height to the compositor.
435 */
436 buffer->height = height;
George Kiagiadakis53868982014-06-12 16:26:49 +0200437 flags = 0;
438
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800439 params = zwp_linux_dmabuf_v1_create_params(display->dmabuf);
440 zwp_linux_buffer_params_v1_add(params,
441 buffer->dmabuf_fd,
442 0, /* plane_idx */
443 0, /* offset */
444 buffer->stride,
445 modifier >> 32,
446 modifier & 0xffffffff);
Varad Gautamee589112016-11-23 14:03:21 +0530447
448 if (format == DRM_FORMAT_NV12) {
449 /* add the second plane params */
450 zwp_linux_buffer_params_v1_add(params,
451 buffer->dmabuf_fd,
452 1,
453 buffer->width * buffer->height,
454 buffer->stride,
455 modifier >> 32,
456 modifier & 0xffffffff);
457 }
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800458 zwp_linux_buffer_params_v1_add_listener(params, &params_listener, buffer);
Varad Gautam48be0be2017-04-26 19:16:00 +0530459 if (display->req_dmabuf_immediate) {
460 buffer->buffer = zwp_linux_buffer_params_v1_create_immed(params,
461 buffer->width,
462 buffer->height,
Varad Gautamee589112016-11-23 14:03:21 +0530463 format,
Varad Gautam48be0be2017-04-26 19:16:00 +0530464 flags);
465 wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
466 }
467 else
468 zwp_linux_buffer_params_v1_create(params,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800469 buffer->width,
470 buffer->height,
Varad Gautamee589112016-11-23 14:03:21 +0530471 format,
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800472 flags);
George Kiagiadakis53868982014-06-12 16:26:49 +0200473
George Kiagiadakis53868982014-06-12 16:26:49 +0200474 return 0;
475
476error2:
Varad Gautamf7b3a392017-04-26 19:17:18 +0530477 drm_dev->free_bo(buffer);
George Kiagiadakis53868982014-06-12 16:26:49 +0200478error1:
479 drm_shutdown(buffer);
480error:
481 return -1;
482}
483
484static void
Jonas Ådahl42682622016-08-11 23:44:41 +0800485xdg_surface_handle_configure(void *data, struct zxdg_surface_v6 *surface,
486 uint32_t serial)
487{
488 struct window *window = data;
489
490 zxdg_surface_v6_ack_configure(surface, serial);
491
492 if (window->initialized && window->wait_for_configure)
493 redraw(window, NULL, 0);
494 window->wait_for_configure = false;
495}
496
497static const struct zxdg_surface_v6_listener xdg_surface_listener = {
498 xdg_surface_handle_configure,
499};
500
501static void
502xdg_toplevel_handle_configure(void *data, struct zxdg_toplevel_v6 *toplevel,
503 int32_t width, int32_t height,
504 struct wl_array *states)
George Kiagiadakis53868982014-06-12 16:26:49 +0200505{
506}
507
508static void
Jonas Ådahl42682622016-08-11 23:44:41 +0800509xdg_toplevel_handle_close(void *data, struct zxdg_toplevel_v6 *xdg_toplevel)
George Kiagiadakis53868982014-06-12 16:26:49 +0200510{
511 running = 0;
512}
513
Jonas Ådahl42682622016-08-11 23:44:41 +0800514static const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
515 xdg_toplevel_handle_configure,
516 xdg_toplevel_handle_close,
George Kiagiadakis53868982014-06-12 16:26:49 +0200517};
518
519static struct window *
Varad Gautamee589112016-11-23 14:03:21 +0530520create_window(struct display *display, int width, int height, int format)
George Kiagiadakis53868982014-06-12 16:26:49 +0200521{
522 struct window *window;
Emmanuel Gil Peyrot8ef29572016-01-11 19:04:37 +0000523 int i;
524 int ret;
George Kiagiadakis53868982014-06-12 16:26:49 +0200525
Bryce Harrington0d1a6222016-02-11 16:42:49 -0800526 window = zalloc(sizeof *window);
George Kiagiadakis53868982014-06-12 16:26:49 +0200527 if (!window)
528 return NULL;
529
530 window->callback = NULL;
531 window->display = display;
532 window->width = width;
533 window->height = height;
534 window->surface = wl_compositor_create_surface(display->compositor);
535
536 if (display->shell) {
537 window->xdg_surface =
Jonas Ådahl42682622016-08-11 23:44:41 +0800538 zxdg_shell_v6_get_xdg_surface(display->shell,
539 window->surface);
George Kiagiadakis53868982014-06-12 16:26:49 +0200540
541 assert(window->xdg_surface);
542
Jonas Ådahl42682622016-08-11 23:44:41 +0800543 zxdg_surface_v6_add_listener(window->xdg_surface,
544 &xdg_surface_listener, window);
George Kiagiadakis53868982014-06-12 16:26:49 +0200545
Jonas Ådahl42682622016-08-11 23:44:41 +0800546 window->xdg_toplevel =
547 zxdg_surface_v6_get_toplevel(window->xdg_surface);
548
549 assert(window->xdg_toplevel);
550
551 zxdg_toplevel_v6_add_listener(window->xdg_toplevel,
552 &xdg_toplevel_listener, window);
553
554 zxdg_toplevel_v6_set_title(window->xdg_toplevel, "simple-dmabuf");
555
556 window->wait_for_configure = true;
557 wl_surface_commit(window->surface);
George Kiagiadakis53868982014-06-12 16:26:49 +0200558 } else if (display->fshell) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800559 zwp_fullscreen_shell_v1_present_surface(display->fshell,
560 window->surface,
561 ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT,
562 NULL);
George Kiagiadakis53868982014-06-12 16:26:49 +0200563 } else {
564 assert(0);
565 }
566
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300567 for (i = 0; i < NUM_BUFFERS; ++i) {
Emmanuel Gil Peyrot8ef29572016-01-11 19:04:37 +0000568 ret = create_dmabuf_buffer(display, &window->buffers[i],
Varad Gautamee589112016-11-23 14:03:21 +0530569 width, height, format);
Emmanuel Gil Peyrot8ef29572016-01-11 19:04:37 +0000570
571 if (ret < 0)
572 return NULL;
573 }
574
George Kiagiadakis53868982014-06-12 16:26:49 +0200575 return window;
576}
577
578static void
579destroy_window(struct window *window)
580{
Varad Gautamf7b3a392017-04-26 19:17:18 +0530581 struct drm_device* dev;
George Kiagiadakis53868982014-06-12 16:26:49 +0200582 int i;
583
584 if (window->callback)
585 wl_callback_destroy(window->callback);
586
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300587 for (i = 0; i < NUM_BUFFERS; i++) {
George Kiagiadakis53868982014-06-12 16:26:49 +0200588 if (!window->buffers[i].buffer)
589 continue;
590
591 wl_buffer_destroy(window->buffers[i].buffer);
Varad Gautamf7b3a392017-04-26 19:17:18 +0530592 dev = window->buffers[i].dev;
593 dev->free_bo(&window->buffers[i]);
George Kiagiadakis53868982014-06-12 16:26:49 +0200594 close(window->buffers[i].dmabuf_fd);
595 drm_shutdown(&window->buffers[i]);
596 }
597
Jonas Ådahl42682622016-08-11 23:44:41 +0800598 if (window->xdg_toplevel)
599 zxdg_toplevel_v6_destroy(window->xdg_toplevel);
George Kiagiadakis53868982014-06-12 16:26:49 +0200600 if (window->xdg_surface)
Jonas Ådahl42682622016-08-11 23:44:41 +0800601 zxdg_surface_v6_destroy(window->xdg_surface);
George Kiagiadakis53868982014-06-12 16:26:49 +0200602 wl_surface_destroy(window->surface);
603 free(window);
604}
605
606static struct buffer *
607window_next_buffer(struct window *window)
608{
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300609 int i;
George Kiagiadakis53868982014-06-12 16:26:49 +0200610
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300611 for (i = 0; i < NUM_BUFFERS; i++)
612 if (!window->buffers[i].busy)
613 return &window->buffers[i];
George Kiagiadakis53868982014-06-12 16:26:49 +0200614
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300615 return NULL;
George Kiagiadakis53868982014-06-12 16:26:49 +0200616}
617
618static const struct wl_callback_listener frame_listener;
619
620static void
621redraw(void *data, struct wl_callback *callback, uint32_t time)
622{
623 struct window *window = data;
624 struct buffer *buffer;
625
626 buffer = window_next_buffer(window);
627 if (!buffer) {
628 fprintf(stderr,
629 !callback ? "Failed to create the first buffer.\n" :
Pekka Paalanend56b94a2016-06-10 13:13:01 +0300630 "All buffers busy at redraw(). Server bug?\n");
George Kiagiadakis53868982014-06-12 16:26:49 +0200631 abort();
632 }
633
634 /* XXX: would be nice to draw something that changes here... */
635
636 wl_surface_attach(window->surface, buffer->buffer, 0, 0);
637 wl_surface_damage(window->surface, 0, 0, window->width, window->height);
638
639 if (callback)
640 wl_callback_destroy(callback);
641
642 window->callback = wl_surface_frame(window->surface);
643 wl_callback_add_listener(window->callback, &frame_listener, window);
644 wl_surface_commit(window->surface);
645 buffer->busy = 1;
646}
647
648static const struct wl_callback_listener frame_listener = {
649 redraw
650};
651
652static void
Varad Gautamf7b3a392017-04-26 19:17:18 +0530653dmabuf_modifiers(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
654 uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo)
George Kiagiadakis53868982014-06-12 16:26:49 +0200655{
656 struct display *d = data;
Varad Gautamee589112016-11-23 14:03:21 +0530657 uint64_t modifier = ((uint64_t) modifier_hi << 32) | modifier_lo;
George Kiagiadakis53868982014-06-12 16:26:49 +0200658
Varad Gautamee589112016-11-23 14:03:21 +0530659 switch (format) {
660 case DRM_FORMAT_XRGB8888:
George Kiagiadakis53868982014-06-12 16:26:49 +0200661 d->xrgb8888_format_found = 1;
Varad Gautamee589112016-11-23 14:03:21 +0530662 break;
663 case DRM_FORMAT_NV12:
664 d->nv12_format_found = 1;
665 if (modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)
666 d->nv12_modifier_found = 1;
667 break;
668 default:
669 break;
670 }
Varad Gautamf7b3a392017-04-26 19:17:18 +0530671}
672
673static void
674dmabuf_format(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, uint32_t format)
675{
Varad Gautamee589112016-11-23 14:03:21 +0530676 /* XXX: deprecated */
George Kiagiadakis53868982014-06-12 16:26:49 +0200677}
678
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800679static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
Varad Gautamf7b3a392017-04-26 19:17:18 +0530680 dmabuf_format,
681 dmabuf_modifiers
George Kiagiadakis53868982014-06-12 16:26:49 +0200682};
683
684static void
Jonas Ådahl42682622016-08-11 23:44:41 +0800685xdg_shell_ping(void *data, struct zxdg_shell_v6 *shell, uint32_t serial)
George Kiagiadakis53868982014-06-12 16:26:49 +0200686{
Jonas Ådahl42682622016-08-11 23:44:41 +0800687 zxdg_shell_v6_pong(shell, serial);
George Kiagiadakis53868982014-06-12 16:26:49 +0200688}
689
Jonas Ådahl42682622016-08-11 23:44:41 +0800690static const struct zxdg_shell_v6_listener xdg_shell_listener = {
George Kiagiadakis53868982014-06-12 16:26:49 +0200691 xdg_shell_ping,
692};
693
George Kiagiadakis53868982014-06-12 16:26:49 +0200694static void
695registry_handle_global(void *data, struct wl_registry *registry,
696 uint32_t id, const char *interface, uint32_t version)
697{
698 struct display *d = data;
699
700 if (strcmp(interface, "wl_compositor") == 0) {
701 d->compositor =
702 wl_registry_bind(registry,
703 id, &wl_compositor_interface, 1);
Jonas Ådahl42682622016-08-11 23:44:41 +0800704 } else if (strcmp(interface, "zxdg_shell_v6") == 0) {
George Kiagiadakis53868982014-06-12 16:26:49 +0200705 d->shell = wl_registry_bind(registry,
Jonas Ådahl42682622016-08-11 23:44:41 +0800706 id, &zxdg_shell_v6_interface, 1);
707 zxdg_shell_v6_add_listener(d->shell, &xdg_shell_listener, d);
Jonas Ådahl496adb32015-11-17 16:00:27 +0800708 } else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
George Kiagiadakis53868982014-06-12 16:26:49 +0200709 d->fshell = wl_registry_bind(registry,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800710 id, &zwp_fullscreen_shell_v1_interface, 1);
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800711 } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
Varad Gautamee589112016-11-23 14:03:21 +0530712 int ver;
713 if (d->req_dmabuf_modifiers)
714 ver = 3;
715 else if (d->req_dmabuf_immediate)
716 ver = 2;
717 else
718 ver = 1;
George Kiagiadakis53868982014-06-12 16:26:49 +0200719 d->dmabuf = wl_registry_bind(registry,
Varad Gautam48be0be2017-04-26 19:16:00 +0530720 id, &zwp_linux_dmabuf_v1_interface,
Varad Gautamee589112016-11-23 14:03:21 +0530721 ver);
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800722 zwp_linux_dmabuf_v1_add_listener(d->dmabuf, &dmabuf_listener, d);
George Kiagiadakis53868982014-06-12 16:26:49 +0200723 }
724}
725
726static void
727registry_handle_global_remove(void *data, struct wl_registry *registry,
728 uint32_t name)
729{
730}
731
732static const struct wl_registry_listener registry_listener = {
733 registry_handle_global,
734 registry_handle_global_remove
735};
736
737static struct display *
Varad Gautamee589112016-11-23 14:03:21 +0530738create_display(int is_immediate, int format)
George Kiagiadakis53868982014-06-12 16:26:49 +0200739{
740 struct display *display;
Varad Gautamee589112016-11-23 14:03:21 +0530741 const char *extensions;
George Kiagiadakis53868982014-06-12 16:26:49 +0200742
743 display = malloc(sizeof *display);
744 if (display == NULL) {
745 fprintf(stderr, "out of memory\n");
746 exit(1);
747 }
748 display->display = wl_display_connect(NULL);
749 assert(display->display);
750
Varad Gautam48be0be2017-04-26 19:16:00 +0530751 display->req_dmabuf_immediate = is_immediate;
Varad Gautamee589112016-11-23 14:03:21 +0530752 display->req_dmabuf_modifiers = (format == DRM_FORMAT_NV12);
753
754 /*
755 * hard code format if the platform egl doesn't support format
756 * querying / advertising.
757 */
758 extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
759 if (extensions && !weston_check_egl_extension(extensions,
760 "EGL_EXT_image_dma_buf_import_modifiers"))
761 display->xrgb8888_format_found = 1;
George Kiagiadakis53868982014-06-12 16:26:49 +0200762
763 display->registry = wl_display_get_registry(display->display);
764 wl_registry_add_listener(display->registry,
765 &registry_listener, display);
766 wl_display_roundtrip(display->display);
767 if (display->dmabuf == NULL) {
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800768 fprintf(stderr, "No zwp_linux_dmabuf global\n");
George Kiagiadakis53868982014-06-12 16:26:49 +0200769 exit(1);
770 }
771
772 wl_display_roundtrip(display->display);
773
Varad Gautamee589112016-11-23 14:03:21 +0530774 if ((format == DRM_FORMAT_XRGB8888 && !display->xrgb8888_format_found) ||
775 (format == DRM_FORMAT_NV12 && (!display->nv12_format_found ||
776 !display->nv12_modifier_found))) {
777 fprintf(stderr, "requested format is not available\n");
George Kiagiadakis53868982014-06-12 16:26:49 +0200778 exit(1);
779 }
780
781 return display;
782}
783
784static void
785destroy_display(struct display *display)
786{
787 if (display->dmabuf)
Jonas Ådahl57e48f02015-11-17 16:00:28 +0800788 zwp_linux_dmabuf_v1_destroy(display->dmabuf);
George Kiagiadakis53868982014-06-12 16:26:49 +0200789
790 if (display->shell)
Jonas Ådahl42682622016-08-11 23:44:41 +0800791 zxdg_shell_v6_destroy(display->shell);
George Kiagiadakis53868982014-06-12 16:26:49 +0200792
793 if (display->fshell)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800794 zwp_fullscreen_shell_v1_release(display->fshell);
George Kiagiadakis53868982014-06-12 16:26:49 +0200795
796 if (display->compositor)
797 wl_compositor_destroy(display->compositor);
798
799 wl_registry_destroy(display->registry);
800 wl_display_flush(display->display);
801 wl_display_disconnect(display->display);
802 free(display);
803}
804
805static void
806signal_int(int signum)
807{
808 running = 0;
809}
810
Varad Gautamee589112016-11-23 14:03:21 +0530811static void
812print_usage_and_exit(void)
813{
814 printf("usage flags:\n"
815 "\t'--import-immediate=<>'\n\t\t0 to import dmabuf via roundtrip,"
816 "\n\t\t1 to enable import without roundtrip\n"
817 "\t'--import-format=<>'\n\t\tXRGB to import dmabuf as XRGB8888,"
818 "\n\t\tNV12 to import as multi plane NV12 with tiling modifier\n");
819 exit(0);
820}
821
822static int
823is_import_mode_immediate(const char* c)
824{
825 if (!strcmp(c, "1"))
826 return 1;
827 else if (!strcmp(c, "0"))
828 return 0;
829 else
830 print_usage_and_exit();
831
832 return 0;
833}
834
835static int
836parse_import_format(const char* c)
837{
838 if (!strcmp(c, "NV12"))
839 return DRM_FORMAT_NV12;
840 else if (!strcmp(c, "XRGB"))
841 return DRM_FORMAT_XRGB8888;
842 else
843 print_usage_and_exit();
844
845 return 0;
846}
847
George Kiagiadakis53868982014-06-12 16:26:49 +0200848int
849main(int argc, char **argv)
850{
851 struct sigaction sigint;
852 struct display *display;
853 struct window *window;
Varad Gautam48be0be2017-04-26 19:16:00 +0530854 int is_immediate = 0;
Varad Gautamee589112016-11-23 14:03:21 +0530855 int import_format = DRM_FORMAT_XRGB8888;
856 int ret = 0, i = 0;
George Kiagiadakis53868982014-06-12 16:26:49 +0200857
Varad Gautam48be0be2017-04-26 19:16:00 +0530858 if (argc > 1) {
Varad Gautamee589112016-11-23 14:03:21 +0530859 static const char import_mode[] = "--import-immediate=";
860 static const char format[] = "--import-format=";
861 for (i = 1; i < argc; i++) {
862 if (!strncmp(argv[i], import_mode,
863 sizeof(import_mode) - 1)) {
864 is_immediate = is_import_mode_immediate(argv[i]
865 + sizeof(import_mode) - 1);
866 }
867 else if (!strncmp(argv[i], format, sizeof(format) - 1)) {
868 import_format = parse_import_format(argv[i]
869 + sizeof(format) - 1);
870 }
871 else {
872 print_usage_and_exit();
873 }
Varad Gautam48be0be2017-04-26 19:16:00 +0530874 }
875 }
876
Varad Gautamee589112016-11-23 14:03:21 +0530877 display = create_display(is_immediate, import_format);
878 window = create_window(display, 256, 256, import_format);
George Kiagiadakis53868982014-06-12 16:26:49 +0200879 if (!window)
880 return 1;
881
882 sigint.sa_handler = signal_int;
883 sigemptyset(&sigint.sa_mask);
884 sigint.sa_flags = SA_RESETHAND;
885 sigaction(SIGINT, &sigint, NULL);
886
Varad Gautam48be0be2017-04-26 19:16:00 +0530887 /* Here we retrieve the linux-dmabuf objects if executed without immed,
888 * or error */
Emmanuel Gil Peyrot8ef29572016-01-11 19:04:37 +0000889 wl_display_roundtrip(display->display);
890
891 if (!running)
892 return 1;
George Kiagiadakis53868982014-06-12 16:26:49 +0200893
Jonas Ådahl42682622016-08-11 23:44:41 +0800894 window->initialized = true;
895
896 if (!window->wait_for_configure)
897 redraw(window, NULL, 0);
George Kiagiadakis53868982014-06-12 16:26:49 +0200898
899 while (running && ret != -1)
900 ret = wl_display_dispatch(display->display);
901
902 fprintf(stderr, "simple-dmabuf exiting\n");
903 destroy_window(window);
904 destroy_display(display);
905
906 return 0;
907}