1/*
2 * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sub license, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include <stddef.h>
26#include <errno.h>
27#include <sys/select.h>
28#ifdef IN_LIBVA
29# include "va/wayland/va_wayland.h"
30#else
31# include <va/va_wayland.h>
32#endif
33#include <wayland-server.h>
34
35static void *open_display(void);
36static void close_display(void *win_display);
37static int create_window(void *win_display,
38             int x, int y, int width, int height);
39static int check_window_event(void *win_display, void *drawable,
40                  int *width, int *height, int *quit);
41
42struct display;
43struct drawable;
44
45static VAStatus
46va_put_surface(
47    VADisplay           dpy,
48    struct drawable    *wl_drawable,
49    VASurfaceID         va_surface,
50    const VARectangle  *src_rect,
51    const VARectangle  *dst_rect,
52    const VARectangle  *cliprects,
53    unsigned int        num_cliprects,
54    unsigned int        flags
55);
56
57/* Glue code for the current PutSurface test design */
58#define CAST_DRAWABLE(a)  (struct drawable *)(a)
59
60static inline VADisplay
61vaGetDisplay(VANativeDisplay native_dpy)
62{
63    return vaGetDisplayWl(native_dpy);
64}
65
66static VAStatus
67vaPutSurface(
68    VADisplay           dpy,
69    VASurfaceID         surface,
70    struct drawable    *wl_drawable,
71    short               src_x,
72    short               src_y,
73    unsigned short      src_w,
74    unsigned short      src_h,
75    short               dst_x,
76    short               dst_y,
77    unsigned short      dst_w,
78    unsigned short      dst_h,
79    const VARectangle  *cliprects,
80    unsigned int        num_cliprects,
81    unsigned int        flags
82)
83{
84    VARectangle src_rect, dst_rect;
85
86    src_rect.x      = src_x;
87    src_rect.y      = src_y;
88    src_rect.width  = src_w;
89    src_rect.height = src_h;
90
91    dst_rect.x      = src_x;
92    dst_rect.y      = src_y;
93    dst_rect.width  = src_w;
94    dst_rect.height = src_h;
95    return va_put_surface(dpy, wl_drawable, surface, &src_rect, &dst_rect,
96                          cliprects, num_cliprects, flags);
97}
98
99#include "putsurface_common.c"
100
101struct display {
102    struct wl_display  *display;
103    struct wl_compositor *compositor;
104    struct wl_shell    *shell;
105    struct wl_registry *registry;
106    int                 event_fd;
107};
108
109struct drawable {
110    struct wl_display  *display;
111    struct wl_surface  *surface;
112    unsigned int        redraw_pending  : 1;
113};
114
115static void
116frame_redraw_callback(void *data, struct wl_callback *callback, uint32_t time)
117{
118    struct drawable * const drawable = data;
119
120    drawable->redraw_pending = 0;
121    wl_callback_destroy(callback);
122}
123
124static const struct wl_callback_listener frame_callback_listener = {
125    frame_redraw_callback
126};
127
128static VAStatus
129va_put_surface(
130    VADisplay           dpy,
131    struct drawable    *wl_drawable,
132    VASurfaceID         va_surface,
133    const VARectangle  *src_rect,
134    const VARectangle  *dst_rect,
135    const VARectangle  *cliprects,
136    unsigned int        num_cliprects,
137    unsigned int        flags
138)
139{
140    struct display *d;
141    struct wl_callback *callback;
142    VAStatus va_status;
143    struct wl_buffer *buffer;
144
145    if (!wl_drawable)
146        return VA_STATUS_ERROR_INVALID_SURFACE;
147
148    d = wl_display_get_user_data(wl_drawable->display);
149    if (!d)
150        return VA_STATUS_ERROR_INVALID_DISPLAY;
151
152    /* Wait for the previous frame to complete redraw */
153    if (wl_drawable->redraw_pending) {
154        wl_display_flush(d->display);
155        while (wl_drawable->redraw_pending)
156            wl_display_dispatch(wl_drawable->display);
157    }
158
159    va_status = vaGetSurfaceBufferWl(va_dpy, va_surface, VA_FRAME_PICTURE, &buffer);
160    if (va_status != VA_STATUS_SUCCESS)
161        return va_status;
162
163    wl_surface_attach(wl_drawable->surface, buffer, 0, 0);
164    wl_surface_damage(
165        wl_drawable->surface,
166        dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height
167    );
168
169    wl_display_flush(d->display);
170    wl_drawable->redraw_pending = 1;
171    callback = wl_surface_frame(wl_drawable->surface);
172    wl_surface_commit(wl_drawable->surface);
173    wl_callback_add_listener(callback, &frame_callback_listener, wl_drawable);
174    return VA_STATUS_SUCCESS;
175}
176
177static void
178registry_handle_global(
179    void               *data,
180    struct wl_registry *registry,
181    uint32_t            id,
182    const char         *interface,
183    uint32_t            version
184)
185{
186    struct display * const d = data;
187
188    if (strcmp(interface, "wl_compositor") == 0)
189        d->compositor =
190            wl_registry_bind(registry, id, &wl_compositor_interface, 1);
191    else if (strcmp(interface, "wl_shell") == 0)
192        d->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
193}
194
195static const struct wl_registry_listener registry_listener = {
196    registry_handle_global,
197    NULL,
198};
199
200static void *
201open_display(void)
202{
203    struct display *d;
204
205    d = calloc(1, sizeof *d);
206    if (!d)
207        return NULL;
208
209    d->display = wl_display_connect(NULL);
210    if (!d->display)
211        return NULL;
212
213    wl_display_set_user_data(d->display, d);
214    d->registry = wl_display_get_registry(d->display);
215    wl_registry_add_listener(d->registry, &registry_listener, d);
216    d->event_fd = wl_display_get_fd(d->display);
217    wl_display_dispatch(d->display);
218    return d->display;
219}
220
221static void
222close_display(void *win_display)
223{
224    struct display * const d = wl_display_get_user_data(win_display);
225
226    if (d->shell) {
227        wl_shell_destroy(d->shell);
228        d->shell = NULL;
229    }
230
231    if (d->compositor) {
232        wl_compositor_destroy(d->compositor);
233        d->compositor = NULL;
234    }
235
236    if (d->display) {
237        wl_display_disconnect(d->display);
238        d->display = NULL;
239    }
240    free(d);
241}
242
243static int
244create_window(void *win_display, int x, int y, int width, int height)
245{
246    struct wl_display * const display = win_display;
247    struct display * const d = wl_display_get_user_data(display);
248    struct wl_surface *surface1, *surface2;
249    struct wl_shell_surface *shell_surface;
250    struct wl_shell_surface *shell_surface_2;
251    struct drawable *drawable1, *drawable2;
252
253    surface1 = wl_compositor_create_surface(d->compositor);
254    shell_surface = wl_shell_get_shell_surface(d->shell, surface1);
255    wl_shell_surface_set_toplevel(shell_surface);
256
257    drawable1 = malloc(sizeof(*drawable1));
258    drawable1->display          = display;
259    drawable1->surface          = surface1;
260    drawable1->redraw_pending   = 0;
261
262    /* global out */
263    drawable_thread0 = drawable1;
264
265    if (multi_thread == 0)
266        return 0;
267
268    surface2 = wl_compositor_create_surface(d->compositor);
269    shell_surface_2 = wl_shell_get_shell_surface(d->shell, surface2);
270    wl_shell_surface_set_toplevel(shell_surface_2);
271
272    drawable2 = malloc(sizeof(*drawable2));
273    drawable2->display          = display;
274    drawable1->surface          = surface2;
275    drawable2->redraw_pending   = 0;
276
277    /* global out */
278    drawable_thread1 = drawable2;
279    return 0;
280}
281
282static int
283check_window_event(
284    void *win_display,
285    void *drawable,
286    int  *width,
287    int  *height,
288    int  *quit
289)
290{
291    struct wl_display * const display = win_display;
292    struct display * const d = wl_display_get_user_data(display);
293    struct timeval tv;
294    fd_set rfds;
295    int retval;
296
297    if (check_event == 0)
298        return 0;
299
300    tv.tv_sec  = 0;
301    tv.tv_usec = 0;
302    do {
303        FD_ZERO(&rfds);
304        FD_SET(d->event_fd, &rfds);
305
306        retval = select(d->event_fd + 1, &rfds, NULL, NULL, &tv);
307        if (retval < 0) {
308            perror("select");
309            break;
310        }
311        if (retval == 1)
312            wl_display_dispatch(d->display);
313    } while (retval > 0);
314
315#if 0
316    /* bail on any focused key press */
317    if(event.type == KeyPress) {
318        *quit = 1;
319        return 0;
320    }
321#endif
322
323#if 0
324    /* rescale the video to fit the window */
325    if(event.type == ConfigureNotify) {
326        *width = event.xconfigure.width;
327        *height = event.xconfigure.height;
328        printf("Scale window to %dx%d\n", width, height);
329    }
330#endif
331    return 0;
332}
333