native_ximage.c revision 08e1076fd2d3f6fb879dd2529e7d035d6a399da2
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.8
4 *
5 * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26#include <X11/Xlib.h>
27#include <X11/Xutil.h>
28#include "util/u_memory.h"
29#include "util/u_math.h"
30#include "util/u_format.h"
31#include "pipe/p_compiler.h"
32#include "util/u_inlines.h"
33#include "state_tracker/xlib_sw_winsys.h"
34#include "util/u_debug.h"
35#include "egllog.h"
36
37#include "common/native_helper.h"
38#include "native_x11.h"
39#include "x11_screen.h"
40
41struct ximage_display {
42   struct native_display base;
43   Display *dpy;
44   boolean own_dpy;
45
46   const struct native_event_handler *event_handler;
47
48   struct x11_screen *xscr;
49   int xscr_number;
50
51   struct ximage_config *configs;
52   int num_configs;
53};
54
55struct ximage_surface {
56   struct native_surface base;
57   Drawable drawable;
58   enum pipe_format color_format;
59   XVisualInfo visual;
60   struct ximage_display *xdpy;
61
62   unsigned int server_stamp;
63   unsigned int client_stamp;
64
65   struct resource_surface *rsurf;
66   struct xlib_drawable xdraw;
67};
68
69struct ximage_config {
70   struct native_config base;
71   const XVisualInfo *visual;
72};
73
74static INLINE struct ximage_display *
75ximage_display(const struct native_display *ndpy)
76{
77   return (struct ximage_display *) ndpy;
78}
79
80static INLINE struct ximage_surface *
81ximage_surface(const struct native_surface *nsurf)
82{
83   return (struct ximage_surface *) nsurf;
84}
85
86static INLINE struct ximage_config *
87ximage_config(const struct native_config *nconf)
88{
89   return (struct ximage_config *) nconf;
90}
91
92/**
93 * Update the geometry of the surface.  This is a slow functions.
94 */
95static void
96ximage_surface_update_geometry(struct native_surface *nsurf)
97{
98   struct ximage_surface *xsurf = ximage_surface(nsurf);
99   Status ok;
100   Window root;
101   int x, y;
102   unsigned int w, h, border, depth;
103
104   ok = XGetGeometry(xsurf->xdpy->dpy, xsurf->drawable,
105         &root, &x, &y, &w, &h, &border, &depth);
106   if (ok && resource_surface_set_size(xsurf->rsurf, w, h))
107      xsurf->server_stamp++;
108}
109
110/**
111 * Update the buffers of the surface.
112 */
113static boolean
114ximage_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
115{
116   struct ximage_surface *xsurf = ximage_surface(nsurf);
117
118   if (xsurf->client_stamp != xsurf->server_stamp) {
119      ximage_surface_update_geometry(&xsurf->base);
120      xsurf->client_stamp = xsurf->server_stamp;
121   }
122
123   return resource_surface_add_resources(xsurf->rsurf, buffer_mask);
124}
125
126/**
127 * Emulate an invalidate event.
128 */
129static void
130ximage_surface_invalidate(struct native_surface *nsurf)
131{
132   struct ximage_surface *xsurf = ximage_surface(nsurf);
133   struct ximage_display *xdpy = xsurf->xdpy;
134
135   xsurf->server_stamp++;
136   xdpy->event_handler->invalid_surface(&xdpy->base,
137         &xsurf->base, xsurf->server_stamp);
138}
139
140static boolean
141ximage_surface_flush_frontbuffer(struct native_surface *nsurf)
142{
143   struct ximage_surface *xsurf = ximage_surface(nsurf);
144   boolean ret;
145
146   ret = resource_surface_present(xsurf->rsurf,
147         NATIVE_ATTACHMENT_FRONT_LEFT, (void *) &xsurf->xdraw);
148   /* force buffers to be updated in next validation call */
149   ximage_surface_invalidate(&xsurf->base);
150
151   return ret;
152}
153
154static boolean
155ximage_surface_swap_buffers(struct native_surface *nsurf)
156{
157   struct ximage_surface *xsurf = ximage_surface(nsurf);
158   boolean ret;
159
160   ret = resource_surface_present(xsurf->rsurf,
161         NATIVE_ATTACHMENT_BACK_LEFT, (void *) &xsurf->xdraw);
162
163   resource_surface_swap_buffers(xsurf->rsurf,
164         NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE);
165   /* the front/back buffers have been swapped */
166   ximage_surface_invalidate(&xsurf->base);
167
168   return ret;
169}
170
171static boolean
172ximage_surface_present(struct native_surface *nsurf,
173                       const struct native_present_control *ctrl)
174{
175   boolean ret;
176
177   if (ctrl->preserve || ctrl->swap_interval)
178      return FALSE;
179
180   switch (ctrl->natt) {
181   case NATIVE_ATTACHMENT_FRONT_LEFT:
182      ret = ximage_surface_flush_frontbuffer(nsurf);
183      break;
184   case NATIVE_ATTACHMENT_BACK_LEFT:
185      ret = ximage_surface_swap_buffers(nsurf);
186      break;
187   default:
188      ret = FALSE;
189      break;
190   }
191
192   return ret;
193}
194
195static boolean
196ximage_surface_validate(struct native_surface *nsurf, uint attachment_mask,
197                        unsigned int *seq_num, struct pipe_resource **textures,
198                        int *width, int *height)
199{
200   struct ximage_surface *xsurf = ximage_surface(nsurf);
201   uint w, h;
202
203   if (!ximage_surface_update_buffers(&xsurf->base, attachment_mask))
204      return FALSE;
205
206   if (seq_num)
207      *seq_num = xsurf->client_stamp;
208
209   if (textures)
210      resource_surface_get_resources(xsurf->rsurf, textures, attachment_mask);
211
212   resource_surface_get_size(xsurf->rsurf, &w, &h);
213   if (width)
214      *width = w;
215   if (height)
216      *height = h;
217
218   return TRUE;
219}
220
221static void
222ximage_surface_wait(struct native_surface *nsurf)
223{
224   struct ximage_surface *xsurf = ximage_surface(nsurf);
225   XSync(xsurf->xdpy->dpy, FALSE);
226   /* TODO XGetImage and update the front texture */
227}
228
229static void
230ximage_surface_destroy(struct native_surface *nsurf)
231{
232   struct ximage_surface *xsurf = ximage_surface(nsurf);
233
234   resource_surface_destroy(xsurf->rsurf);
235   FREE(xsurf);
236}
237
238static struct ximage_surface *
239ximage_display_create_surface(struct native_display *ndpy,
240                              Drawable drawable,
241                              const struct native_config *nconf)
242{
243   struct ximage_display *xdpy = ximage_display(ndpy);
244   struct ximage_config *xconf = ximage_config(nconf);
245   struct ximage_surface *xsurf;
246
247   xsurf = CALLOC_STRUCT(ximage_surface);
248   if (!xsurf)
249      return NULL;
250
251   xsurf->xdpy = xdpy;
252   xsurf->color_format = xconf->base.color_format;
253   xsurf->drawable = drawable;
254
255   xsurf->rsurf = resource_surface_create(xdpy->base.screen,
256         xsurf->color_format,
257         PIPE_BIND_RENDER_TARGET |
258         PIPE_BIND_SAMPLER_VIEW |
259         PIPE_BIND_DISPLAY_TARGET |
260         PIPE_BIND_SCANOUT);
261   if (!xsurf->rsurf) {
262      FREE(xsurf);
263      return NULL;
264   }
265
266   xsurf->drawable = drawable;
267   xsurf->visual = *xconf->visual;
268   /* initialize the geometry */
269   ximage_surface_update_geometry(&xsurf->base);
270
271   xsurf->xdraw.visual = xsurf->visual.visual;
272   xsurf->xdraw.depth = xsurf->visual.depth;
273   xsurf->xdraw.drawable = xsurf->drawable;
274
275   xsurf->base.destroy = ximage_surface_destroy;
276   xsurf->base.present = ximage_surface_present;
277   xsurf->base.validate = ximage_surface_validate;
278   xsurf->base.wait = ximage_surface_wait;
279
280   return xsurf;
281}
282
283static struct native_surface *
284ximage_display_create_window_surface(struct native_display *ndpy,
285                                     EGLNativeWindowType win,
286                                     const struct native_config *nconf)
287{
288   struct ximage_surface *xsurf;
289
290   xsurf = ximage_display_create_surface(ndpy, (Drawable) win, nconf);
291   return (xsurf) ? &xsurf->base : NULL;
292}
293
294static enum pipe_format
295get_pixmap_format(struct native_display *ndpy, EGLNativePixmapType pix)
296{
297   struct ximage_display *xdpy = ximage_display(ndpy);
298   enum pipe_format fmt;
299   uint depth;
300
301   depth = x11_drawable_get_depth(xdpy->xscr, (Drawable) pix);
302
303   switch (depth) {
304   case 32:
305      fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
306      break;
307   case 24:
308      fmt = PIPE_FORMAT_B8G8R8X8_UNORM;
309      break;
310   case 16:
311      fmt = PIPE_FORMAT_B5G6R5_UNORM;
312      break;
313   default:
314      fmt = PIPE_FORMAT_NONE;
315      break;
316   }
317
318   return fmt;
319}
320
321static struct native_surface *
322ximage_display_create_pixmap_surface(struct native_display *ndpy,
323                                     EGLNativePixmapType pix,
324                                     const struct native_config *nconf)
325{
326   struct ximage_surface *xsurf;
327
328   /* find the config */
329   if (!nconf) {
330      struct ximage_display *xdpy = ximage_display(ndpy);
331      enum pipe_format fmt = get_pixmap_format(&xdpy->base, pix);
332      int i;
333
334      if (fmt != PIPE_FORMAT_NONE) {
335         for (i = 0; i < xdpy->num_configs; i++) {
336            if (xdpy->configs[i].base.color_format == fmt) {
337               nconf = &xdpy->configs[i].base;
338               break;
339            }
340         }
341      }
342
343      if (!nconf)
344         return NULL;
345   }
346
347   xsurf = ximage_display_create_surface(ndpy, (Drawable) pix, nconf);
348   return (xsurf) ? &xsurf->base : NULL;
349}
350
351static enum pipe_format
352choose_format(const XVisualInfo *vinfo)
353{
354   enum pipe_format fmt;
355   /* TODO elaborate the formats */
356   switch (vinfo->depth) {
357   case 32:
358      fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
359      break;
360   case 24:
361      fmt = PIPE_FORMAT_B8G8R8X8_UNORM;
362      break;
363   case 16:
364      fmt = PIPE_FORMAT_B5G6R5_UNORM;
365      break;
366   default:
367      fmt = PIPE_FORMAT_NONE;
368      break;
369   }
370
371   return fmt;
372}
373
374static const struct native_config **
375ximage_display_get_configs(struct native_display *ndpy, int *num_configs)
376{
377   struct ximage_display *xdpy = ximage_display(ndpy);
378   const struct native_config **configs;
379   int i;
380
381   /* first time */
382   if (!xdpy->configs) {
383      const XVisualInfo *visuals;
384      int num_visuals, count;
385
386      visuals = x11_screen_get_visuals(xdpy->xscr, &num_visuals);
387      if (!visuals)
388         return NULL;
389
390      /*
391       * Create two configs for each visual.
392       * One with depth/stencil buffer; one without
393       */
394      xdpy->configs = CALLOC(num_visuals * 2, sizeof(*xdpy->configs));
395      if (!xdpy->configs)
396         return NULL;
397
398      count = 0;
399      for (i = 0; i < num_visuals; i++) {
400         struct ximage_config *xconf = &xdpy->configs[count];
401
402         xconf->visual = &visuals[i];
403         xconf->base.color_format = choose_format(xconf->visual);
404         if (xconf->base.color_format == PIPE_FORMAT_NONE)
405            continue;
406
407         xconf->base.buffer_mask =
408            (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
409            (1 << NATIVE_ATTACHMENT_BACK_LEFT);
410
411         xconf->base.window_bit = TRUE;
412         xconf->base.pixmap_bit = TRUE;
413
414         xconf->base.native_visual_id = xconf->visual->visualid;
415#if defined(__cplusplus) || defined(c_plusplus)
416         xconf->base.native_visual_type = xconf->visual->c_class;
417#else
418         xconf->base.native_visual_type = xconf->visual->class;
419#endif
420
421         count++;
422      }
423
424      xdpy->num_configs = count;
425   }
426
427   configs = MALLOC(xdpy->num_configs * sizeof(*configs));
428   if (configs) {
429      for (i = 0; i < xdpy->num_configs; i++)
430         configs[i] = (const struct native_config *) &xdpy->configs[i];
431      if (num_configs)
432         *num_configs = xdpy->num_configs;
433   }
434   return configs;
435}
436
437static boolean
438ximage_display_get_pixmap_format(struct native_display *ndpy,
439                                 EGLNativePixmapType pix,
440                                 enum pipe_format *format)
441{
442   struct ximage_display *xdpy = ximage_display(ndpy);
443
444   *format = get_pixmap_format(&xdpy->base, pix);
445
446   return (*format != PIPE_FORMAT_NONE);
447}
448
449static boolean
450ximage_display_copy_to_pixmap(struct native_display *ndpy,
451                              EGLNativePixmapType pix,
452                              struct pipe_resource *src)
453{
454   /* fast path to avoid unnecessary allocation and resource_copy_region */
455   if (src->bind & PIPE_BIND_DISPLAY_TARGET) {
456      struct ximage_display *xdpy = ximage_display(ndpy);
457      enum pipe_format fmt = get_pixmap_format(&xdpy->base, pix);
458      const struct ximage_config *xconf;
459      struct xlib_drawable xdraw;
460      int i;
461
462      if (fmt == PIPE_FORMAT_NONE || src->format != fmt)
463         return FALSE;
464
465      for (i = 0; i < xdpy->num_configs; i++) {
466         if (xdpy->configs[i].base.color_format == fmt) {
467            xconf = &xdpy->configs[i];
468            break;
469         }
470      }
471      if (!xconf)
472         return FALSE;
473
474      memset(&xdraw, 0, sizeof(xdraw));
475      xdraw.visual = xconf->visual->visual;
476      xdraw.depth = xconf->visual->depth;
477      xdraw.drawable = (Drawable) pix;
478
479      xdpy->base.screen->flush_frontbuffer(xdpy->base.screen,
480            src, 0, 0, &xdraw);
481
482      return TRUE;
483   }
484
485   return native_display_copy_to_pixmap(ndpy, pix, src);
486}
487
488static int
489ximage_display_get_param(struct native_display *ndpy,
490                         enum native_param_type param)
491{
492   int val;
493
494   switch (param) {
495   case NATIVE_PARAM_USE_NATIVE_BUFFER:
496      /* private buffers are allocated */
497      val = FALSE;
498      break;
499   case NATIVE_PARAM_PRESERVE_BUFFER:
500   case NATIVE_PARAM_MAX_SWAP_INTERVAL:
501   default:
502      val = 0;
503      break;
504   }
505
506   return val;
507}
508
509static void
510ximage_display_destroy(struct native_display *ndpy)
511{
512   struct ximage_display *xdpy = ximage_display(ndpy);
513
514   if (xdpy->configs)
515      FREE(xdpy->configs);
516
517   ndpy_uninit(ndpy);
518
519   x11_screen_destroy(xdpy->xscr);
520   if (xdpy->own_dpy)
521      XCloseDisplay(xdpy->dpy);
522   FREE(xdpy);
523}
524
525static boolean
526ximage_display_init_screen(struct native_display *ndpy)
527{
528   struct ximage_display *xdpy = ximage_display(ndpy);
529   struct sw_winsys *winsys;
530
531   winsys = xlib_create_sw_winsys(xdpy->dpy);
532   if (!winsys)
533      return FALSE;
534
535   xdpy->base.screen =
536      xdpy->event_handler->new_sw_screen(&xdpy->base, winsys);
537   if (!xdpy->base.screen) {
538      if (winsys->destroy)
539         winsys->destroy(winsys);
540      return FALSE;
541   }
542
543   return TRUE;
544}
545
546struct native_display *
547x11_create_ximage_display(Display *dpy,
548                          const struct native_event_handler *event_handler)
549{
550   struct ximage_display *xdpy;
551
552   xdpy = CALLOC_STRUCT(ximage_display);
553   if (!xdpy)
554      return NULL;
555
556   xdpy->dpy = dpy;
557   if (!xdpy->dpy) {
558      xdpy->dpy = XOpenDisplay(NULL);
559      if (!xdpy->dpy) {
560         FREE(xdpy);
561         return NULL;
562      }
563      xdpy->own_dpy = TRUE;
564   }
565
566   xdpy->event_handler = event_handler;
567
568   xdpy->xscr_number = DefaultScreen(xdpy->dpy);
569   xdpy->xscr = x11_screen_create(xdpy->dpy, xdpy->xscr_number);
570   if (!xdpy->xscr) {
571      if (xdpy->own_dpy)
572         XCloseDisplay(xdpy->dpy);
573      FREE(xdpy);
574      return NULL;
575   }
576
577   xdpy->base.init_screen = ximage_display_init_screen;
578   xdpy->base.destroy = ximage_display_destroy;
579   xdpy->base.get_param = ximage_display_get_param;
580
581   xdpy->base.get_configs = ximage_display_get_configs;
582   xdpy->base.get_pixmap_format = ximage_display_get_pixmap_format;
583   xdpy->base.copy_to_pixmap = ximage_display_copy_to_pixmap;
584   xdpy->base.create_window_surface = ximage_display_create_window_surface;
585   xdpy->base.create_pixmap_surface = ximage_display_create_pixmap_surface;
586
587   return &xdpy->base;
588}
589