native_ximage.c revision 5e72b89b89fe172638afa66abdd6607d11970e5a
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
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include <assert.h>
26#include <sys/ipc.h>
27#include <sys/types.h>
28#include <sys/shm.h>
29#include <X11/Xlib.h>
30#include <X11/Xutil.h>
31#include "util/u_memory.h"
32#include "util/u_math.h"
33#include "util/u_format.h"
34#include "pipe/p_compiler.h"
35#include "util/u_inlines.h"
36#include "state_tracker/xlib_sw_winsys.h"
37#include "target-helpers/swrast_xlib.h"
38#include "egllog.h"
39
40#include "native_x11.h"
41#include "x11_screen.h"
42
43enum ximage_surface_type {
44   XIMAGE_SURFACE_TYPE_WINDOW,
45   XIMAGE_SURFACE_TYPE_PIXMAP,
46   XIMAGE_SURFACE_TYPE_PBUFFER
47};
48
49struct ximage_display {
50   struct native_display base;
51   Display *dpy;
52   boolean own_dpy;
53
54   struct x11_screen *xscr;
55   int xscr_number;
56
57   struct xm_driver *driver;
58
59   struct ximage_config *configs;
60   int num_configs;
61};
62
63struct ximage_buffer {
64   struct pipe_texture *texture;
65   struct xlib_drawable xdraw;
66};
67
68struct ximage_surface {
69   struct native_surface base;
70   Drawable drawable;
71   enum ximage_surface_type type;
72   enum pipe_format color_format;
73   XVisualInfo visual;
74   struct ximage_display *xdpy;
75
76   unsigned int server_stamp;
77   unsigned int client_stamp;
78   int width, height;
79   struct ximage_buffer buffers[NUM_NATIVE_ATTACHMENTS];
80   uint valid_mask;
81};
82
83struct ximage_config {
84   struct native_config base;
85   const XVisualInfo *visual;
86};
87
88static INLINE struct ximage_display *
89ximage_display(const struct native_display *ndpy)
90{
91   return (struct ximage_display *) ndpy;
92}
93
94static INLINE struct ximage_surface *
95ximage_surface(const struct native_surface *nsurf)
96{
97   return (struct ximage_surface *) nsurf;
98}
99
100static INLINE struct ximage_config *
101ximage_config(const struct native_config *nconf)
102{
103   return (struct ximage_config *) nconf;
104}
105
106static void
107ximage_surface_free_buffer(struct native_surface *nsurf,
108                           enum native_attachment which)
109{
110   struct ximage_surface *xsurf = ximage_surface(nsurf);
111   struct ximage_buffer *xbuf = &xsurf->buffers[which];
112
113   pipe_texture_reference(&xbuf->texture, NULL);
114}
115
116static boolean
117ximage_surface_alloc_buffer(struct native_surface *nsurf,
118                            enum native_attachment which)
119{
120   struct ximage_surface *xsurf = ximage_surface(nsurf);
121   struct ximage_buffer *xbuf = &xsurf->buffers[which];
122   struct pipe_screen *screen = xsurf->xdpy->base.screen;
123   struct pipe_texture templ;
124
125   /* free old data */
126   if (xbuf->texture)
127      ximage_surface_free_buffer(&xsurf->base, which);
128
129   memset(&templ, 0, sizeof(templ));
130   templ.target = PIPE_TEXTURE_2D;
131   templ.format = xsurf->color_format;
132   templ.width0 = xsurf->width;
133   templ.height0 = xsurf->height;
134   templ.depth0 = 1;
135   templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
136
137   if (xsurf->type != XIMAGE_SURFACE_TYPE_PBUFFER) {
138      switch (which) {
139      case NATIVE_ATTACHMENT_FRONT_LEFT:
140      case NATIVE_ATTACHMENT_FRONT_RIGHT:
141         templ.tex_usage |= PIPE_TEXTURE_USAGE_PRIMARY;
142         break;
143      case NATIVE_ATTACHMENT_BACK_LEFT:
144      case NATIVE_ATTACHMENT_BACK_RIGHT:
145         templ.tex_usage |= PIPE_TEXTURE_USAGE_DISPLAY_TARGET;
146         break;
147      default:
148         break;
149      }
150   }
151   xbuf->texture = screen->texture_create(screen, &templ);
152   if (xbuf->texture) {
153      xbuf->xdraw.visual = xsurf->visual.visual;
154      xbuf->xdraw.depth = xsurf->visual.depth;
155      xbuf->xdraw.drawable = xsurf->drawable;
156   }
157
158   /* clean up the buffer if allocation failed */
159   if (!xbuf->texture)
160      ximage_surface_free_buffer(&xsurf->base, which);
161
162   return (xbuf->texture != NULL);
163}
164
165/**
166 * Update the geometry of the surface.  Return TRUE if the geometry has changed
167 * since last call.
168 */
169static boolean
170ximage_surface_update_geometry(struct native_surface *nsurf)
171{
172   struct ximage_surface *xsurf = ximage_surface(nsurf);
173   Status ok;
174   Window root;
175   int x, y;
176   unsigned int w, h, border, depth;
177   boolean updated = FALSE;
178
179   /* pbuffer has fixed geometry */
180   if (xsurf->type == XIMAGE_SURFACE_TYPE_PBUFFER)
181      return FALSE;
182
183   ok = XGetGeometry(xsurf->xdpy->dpy, xsurf->drawable,
184         &root, &x, &y, &w, &h, &border, &depth);
185   if (ok && (xsurf->width != w || xsurf->height != h)) {
186      xsurf->width = w;
187      xsurf->height = h;
188
189      xsurf->server_stamp++;
190      updated = TRUE;
191   }
192
193   return updated;
194}
195
196static void
197ximage_surface_notify_invalid(struct native_surface *nsurf)
198{
199   struct ximage_surface *xsurf = ximage_surface(nsurf);
200   struct ximage_display *xdpy = xsurf->xdpy;
201
202   xdpy->event_handler->invalid_surface(&xdpy->base,
203         &xsurf->base, xsurf->server_stamp);
204}
205
206/**
207 * Update the buffers of the surface.  It is a slow function due to the
208 * round-trip to the server.
209 */
210static boolean
211ximage_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
212{
213   struct ximage_surface *xsurf = ximage_surface(nsurf);
214   boolean updated;
215   uint new_valid;
216   int att;
217
218   updated = ximage_surface_update_geometry(&xsurf->base);
219   if (updated) {
220      /* all buffers become invalid */
221      xsurf->valid_mask = 0x0;
222   }
223   else {
224      buffer_mask &= ~xsurf->valid_mask;
225      /* all requested buffers are valid */
226      if (!buffer_mask) {
227         xsurf->client_stamp = xsurf->server_stamp;
228         return TRUE;
229      }
230   }
231
232   new_valid = 0x0;
233   for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
234      if (native_attachment_mask_test(buffer_mask, att)) {
235         /* reallocate the texture */
236         if (!ximage_surface_alloc_buffer(&xsurf->base, att))
237            break;
238
239         new_valid |= (1 << att);
240         if (buffer_mask == new_valid)
241            break;
242      }
243   }
244
245   xsurf->valid_mask |= new_valid;
246   xsurf->client_stamp = xsurf->server_stamp;
247
248   return (new_valid == buffer_mask);
249}
250
251static boolean
252ximage_surface_draw_buffer(struct native_surface *nsurf,
253                           enum native_attachment which)
254{
255   struct ximage_surface *xsurf = ximage_surface(nsurf);
256   struct ximage_buffer *xbuf = &xsurf->buffers[which];
257   struct pipe_screen *screen = xsurf->xdpy->base.screen;
258   struct pipe_surface *psurf;
259
260   if (xsurf->type == XIMAGE_SURFACE_TYPE_PBUFFER)
261      return TRUE;
262
263   assert(xsurf->drawable && xbuf->texture);
264
265   /* what's the cost of surface creation? */
266   psurf = screen->get_tex_surface(screen,
267         xbuf->texture, 0, 0, 0, PIPE_BUFFER_USAGE_CPU_READ);
268   if (!psurf)
269      return FALSE;
270
271   screen->flush_frontbuffer(screen, psurf, &xbuf->xdraw);
272
273   pipe_surface_reference(&psurf, NULL);
274
275   return TRUE;
276}
277
278static boolean
279ximage_surface_flush_frontbuffer(struct native_surface *nsurf)
280{
281   struct ximage_surface *xsurf = ximage_surface(nsurf);
282   boolean ret;
283
284   ret = ximage_surface_draw_buffer(&xsurf->base,
285         NATIVE_ATTACHMENT_FRONT_LEFT);
286   /* force buffers to be updated in next validation call */
287   xsurf->server_stamp++;
288   ximage_surface_notify_invalid(&xsurf->base);
289
290   return ret;
291}
292
293static boolean
294ximage_surface_swap_buffers(struct native_surface *nsurf)
295{
296   struct ximage_surface *xsurf = ximage_surface(nsurf);
297   struct ximage_buffer *xfront, *xback, xtmp;
298   boolean ret;
299
300   /* display the back buffer first */
301   ret = ximage_surface_draw_buffer(&xsurf->base,
302         NATIVE_ATTACHMENT_BACK_LEFT);
303   /* force buffers to be updated in next validation call */
304   xsurf->server_stamp++;
305   ximage_surface_notify_invalid(&xsurf->base);
306
307   xfront = &xsurf->buffers[NATIVE_ATTACHMENT_FRONT_LEFT];
308   xback = &xsurf->buffers[NATIVE_ATTACHMENT_BACK_LEFT];
309
310   /* skip swapping unless there is a front buffer */
311   if (xfront->texture) {
312      xtmp = *xfront;
313      *xfront = *xback;
314      *xback = xtmp;
315   }
316
317   return ret;
318}
319
320static boolean
321ximage_surface_validate(struct native_surface *nsurf, uint attachment_mask,
322                        unsigned int *seq_num, struct pipe_texture **textures,
323                        int *width, int *height)
324{
325   struct ximage_surface *xsurf = ximage_surface(nsurf);
326
327   if (xsurf->client_stamp != xsurf->server_stamp ||
328       (xsurf->valid_mask & attachment_mask) != attachment_mask) {
329      if (!ximage_surface_update_buffers(&xsurf->base, attachment_mask))
330         return FALSE;
331   }
332
333   if (seq_num)
334      *seq_num = xsurf->client_stamp;
335
336   if (textures) {
337      int att;
338      for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
339         if (native_attachment_mask_test(attachment_mask, att)) {
340            struct ximage_buffer *xbuf = &xsurf->buffers[att];
341
342            textures[att] = NULL;
343            pipe_texture_reference(&textures[att], xbuf->texture);
344         }
345      }
346   }
347
348   if (width)
349      *width = xsurf->width;
350   if (height)
351      *height = xsurf->height;
352
353   return TRUE;
354}
355
356static void
357ximage_surface_wait(struct native_surface *nsurf)
358{
359   struct ximage_surface *xsurf = ximage_surface(nsurf);
360   XSync(xsurf->xdpy->dpy, FALSE);
361   /* TODO XGetImage and update the front texture */
362}
363
364static void
365ximage_surface_destroy(struct native_surface *nsurf)
366{
367   struct ximage_surface *xsurf = ximage_surface(nsurf);
368   int i;
369
370   for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++)
371      ximage_surface_free_buffer(&xsurf->base, i);
372
373   free(xsurf);
374}
375
376static struct ximage_surface *
377ximage_display_create_surface(struct native_display *ndpy,
378                              enum ximage_surface_type type,
379                              Drawable drawable,
380                              const struct native_config *nconf)
381{
382   struct ximage_display *xdpy = ximage_display(ndpy);
383   struct ximage_config *xconf = ximage_config(nconf);
384   struct ximage_surface *xsurf;
385
386   xsurf = CALLOC_STRUCT(ximage_surface);
387   if (!xsurf)
388      return NULL;
389
390   xsurf->xdpy = xdpy;
391   xsurf->type = type;
392   xsurf->color_format = xconf->base.color_format;
393   xsurf->drawable = drawable;
394
395   if (xsurf->type != XIMAGE_SURFACE_TYPE_PBUFFER) {
396      xsurf->drawable = drawable;
397      xsurf->visual = *xconf->visual;
398      /* initialize the geometry */
399      ximage_surface_update_buffers(&xsurf->base, 0x0);
400   }
401
402   xsurf->base.destroy = ximage_surface_destroy;
403   xsurf->base.swap_buffers = ximage_surface_swap_buffers;
404   xsurf->base.flush_frontbuffer = ximage_surface_flush_frontbuffer;
405   xsurf->base.validate = ximage_surface_validate;
406   xsurf->base.wait = ximage_surface_wait;
407
408   return xsurf;
409}
410
411static struct native_surface *
412ximage_display_create_window_surface(struct native_display *ndpy,
413                                     EGLNativeWindowType win,
414                                     const struct native_config *nconf)
415{
416   struct ximage_surface *xsurf;
417
418   xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_WINDOW,
419         (Drawable) win, nconf);
420   return (xsurf) ? &xsurf->base : NULL;
421}
422
423static struct native_surface *
424ximage_display_create_pixmap_surface(struct native_display *ndpy,
425                                     EGLNativePixmapType pix,
426                                     const struct native_config *nconf)
427{
428   struct ximage_surface *xsurf;
429
430   xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_PIXMAP,
431         (Drawable) pix, nconf);
432   return (xsurf) ? &xsurf->base : NULL;
433}
434
435static struct native_surface *
436ximage_display_create_pbuffer_surface(struct native_display *ndpy,
437                                      const struct native_config *nconf,
438                                      uint width, uint height)
439{
440   struct ximage_surface *xsurf;
441
442   xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_PBUFFER,
443         (Drawable) None, nconf);
444   if (xsurf) {
445      xsurf->width = width;
446      xsurf->height = height;
447   }
448   return (xsurf) ? &xsurf->base : NULL;
449}
450
451static enum pipe_format
452choose_format(const XVisualInfo *vinfo)
453{
454   enum pipe_format fmt;
455   /* TODO elaborate the formats */
456   switch (vinfo->depth) {
457   case 32:
458      fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
459      break;
460   case 24:
461      fmt = PIPE_FORMAT_B8G8R8X8_UNORM;
462      break;
463   case 16:
464      fmt = PIPE_FORMAT_B5G6R5_UNORM;
465      break;
466   default:
467      fmt = PIPE_FORMAT_NONE;
468      break;
469   }
470
471   return fmt;
472}
473
474static const struct native_config **
475ximage_display_get_configs(struct native_display *ndpy, int *num_configs)
476{
477   struct ximage_display *xdpy = ximage_display(ndpy);
478   const struct native_config **configs;
479   int i;
480
481   /* first time */
482   if (!xdpy->configs) {
483      const XVisualInfo *visuals;
484      int num_visuals, count, j;
485
486      visuals = x11_screen_get_visuals(xdpy->xscr, &num_visuals);
487      if (!visuals)
488         return NULL;
489
490      /*
491       * Create two configs for each visual.
492       * One with depth/stencil buffer; one without
493       */
494      xdpy->configs = calloc(num_visuals * 2, sizeof(*xdpy->configs));
495      if (!xdpy->configs)
496         return NULL;
497
498      count = 0;
499      for (i = 0; i < num_visuals; i++) {
500         for (j = 0; j < 2; j++) {
501            struct ximage_config *xconf = &xdpy->configs[count];
502            __GLcontextModes *mode = &xconf->base.mode;
503
504            xconf->visual = &visuals[i];
505            xconf->base.color_format = choose_format(xconf->visual);
506            if (xconf->base.color_format == PIPE_FORMAT_NONE)
507               continue;
508
509            x11_screen_convert_visual(xdpy->xscr, xconf->visual, mode);
510            /* support double buffer mode */
511            mode->doubleBufferMode = TRUE;
512
513            xconf->base.depth_format = PIPE_FORMAT_NONE;
514            xconf->base.stencil_format = PIPE_FORMAT_NONE;
515            /* create the second config with depth/stencil buffer */
516            if (j == 1) {
517               xconf->base.depth_format = PIPE_FORMAT_Z24S8_UNORM;
518               xconf->base.stencil_format = PIPE_FORMAT_Z24S8_UNORM;
519               mode->depthBits = 24;
520               mode->stencilBits = 8;
521               mode->haveDepthBuffer = TRUE;
522               mode->haveStencilBuffer = TRUE;
523            }
524
525            mode->maxPbufferWidth = 4096;
526            mode->maxPbufferHeight = 4096;
527            mode->maxPbufferPixels = 4096 * 4096;
528            mode->drawableType =
529               GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT;
530            mode->swapMethod = GLX_SWAP_EXCHANGE_OML;
531
532            if (mode->alphaBits)
533               mode->bindToTextureRgba = TRUE;
534            else
535               mode->bindToTextureRgb = TRUE;
536
537            count++;
538         }
539      }
540
541      xdpy->num_configs = count;
542   }
543
544   configs = malloc(xdpy->num_configs * sizeof(*configs));
545   if (configs) {
546      for (i = 0; i < xdpy->num_configs; i++)
547         configs[i] = (const struct native_config *) &xdpy->configs[i];
548      if (num_configs)
549         *num_configs = xdpy->num_configs;
550   }
551   return configs;
552}
553
554static boolean
555ximage_display_is_pixmap_supported(struct native_display *ndpy,
556                                   EGLNativePixmapType pix,
557                                   const struct native_config *nconf)
558{
559   struct ximage_display *xdpy = ximage_display(ndpy);
560   enum pipe_format fmt;
561   uint depth;
562
563   depth = x11_drawable_get_depth(xdpy->xscr, (Drawable) pix);
564   switch (depth) {
565   case 32:
566      fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
567      break;
568   case 24:
569      fmt = PIPE_FORMAT_B8G8R8X8_UNORM;
570      break;
571   case 16:
572      fmt = PIPE_FORMAT_B5G6R5_UNORM;
573      break;
574   default:
575      fmt = PIPE_FORMAT_NONE;
576      break;
577   }
578
579   return (fmt == nconf->color_format);
580}
581
582static int
583ximage_display_get_param(struct native_display *ndpy,
584                         enum native_param_type param)
585{
586   int val;
587
588   switch (param) {
589   case NATIVE_PARAM_USE_NATIVE_BUFFER:
590      /* private buffers are allocated */
591      val = FALSE;
592      break;
593   default:
594      val = 0;
595      break;
596   }
597
598   return val;
599}
600
601static void
602ximage_display_destroy(struct native_display *ndpy)
603{
604   struct ximage_display *xdpy = ximage_display(ndpy);
605
606   if (xdpy->configs)
607      free(xdpy->configs);
608
609   xdpy->base.screen->destroy(xdpy->base.screen);
610
611   x11_screen_destroy(xdpy->xscr);
612   if (xdpy->own_dpy)
613      XCloseDisplay(xdpy->dpy);
614   free(xdpy);
615}
616
617struct native_display *
618x11_create_ximage_display(EGLNativeDisplayType dpy)
619{
620   struct ximage_display *xdpy;
621
622   xdpy = CALLOC_STRUCT(ximage_display);
623   if (!xdpy)
624      return NULL;
625
626   xdpy->dpy = dpy;
627   if (!xdpy->dpy) {
628      xdpy->dpy = XOpenDisplay(NULL);
629      if (!xdpy->dpy) {
630         free(xdpy);
631         return NULL;
632      }
633      xdpy->own_dpy = TRUE;
634   }
635
636   xdpy->xscr_number = DefaultScreen(xdpy->dpy);
637   xdpy->xscr = x11_screen_create(xdpy->dpy, xdpy->xscr_number);
638   if (!xdpy->xscr) {
639      free(xdpy);
640      return NULL;
641   }
642
643   xdpy->base.screen = swrast_xlib_create_screen(xdpy->dpy);
644
645   xdpy->base.destroy = ximage_display_destroy;
646   xdpy->base.get_param = ximage_display_get_param;
647
648   xdpy->base.get_configs = ximage_display_get_configs;
649   xdpy->base.is_pixmap_supported = ximage_display_is_pixmap_supported;
650   xdpy->base.create_window_surface = ximage_display_create_window_surface;
651   xdpy->base.create_pixmap_surface = ximage_display_create_pixmap_surface;
652   xdpy->base.create_pbuffer_surface = ximage_display_create_pbuffer_surface;
653
654   return &xdpy->base;
655}
656