native_ximage.c revision f69b35fa15f43747dde29addaeec845604d7e127
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/wrap_screen.h"
38#include "util/u_debug.h"
39#include "softpipe/sp_public.h"
40#include "llvmpipe/lp_public.h"
41#include "cell/ppu/cell_public.h"
42#include "egllog.h"
43
44#include "native_x11.h"
45#include "x11_screen.h"
46
47enum ximage_surface_type {
48   XIMAGE_SURFACE_TYPE_WINDOW,
49   XIMAGE_SURFACE_TYPE_PIXMAP,
50};
51
52struct ximage_display {
53   struct native_display base;
54   Display *dpy;
55   boolean own_dpy;
56
57   struct native_event_handler *event_handler;
58
59   struct x11_screen *xscr;
60   int xscr_number;
61
62   struct ximage_config *configs;
63   int num_configs;
64};
65
66struct ximage_buffer {
67   struct pipe_texture *texture;
68   struct xlib_drawable xdraw;
69};
70
71struct ximage_surface {
72   struct native_surface base;
73   Drawable drawable;
74   enum ximage_surface_type type;
75   enum pipe_format color_format;
76   XVisualInfo visual;
77   struct ximage_display *xdpy;
78
79   unsigned int server_stamp;
80   unsigned int client_stamp;
81   int width, height;
82   struct ximage_buffer buffers[NUM_NATIVE_ATTACHMENTS];
83   uint valid_mask;
84
85   struct pipe_surface *draw_surface;
86};
87
88struct ximage_config {
89   struct native_config base;
90   const XVisualInfo *visual;
91};
92
93static INLINE struct ximage_display *
94ximage_display(const struct native_display *ndpy)
95{
96   return (struct ximage_display *) ndpy;
97}
98
99static INLINE struct ximage_surface *
100ximage_surface(const struct native_surface *nsurf)
101{
102   return (struct ximage_surface *) nsurf;
103}
104
105static INLINE struct ximage_config *
106ximage_config(const struct native_config *nconf)
107{
108   return (struct ximage_config *) nconf;
109}
110
111static void
112ximage_surface_free_buffer(struct native_surface *nsurf,
113                           enum native_attachment which)
114{
115   struct ximage_surface *xsurf = ximage_surface(nsurf);
116   struct ximage_buffer *xbuf = &xsurf->buffers[which];
117
118   pipe_texture_reference(&xbuf->texture, NULL);
119}
120
121static boolean
122ximage_surface_alloc_buffer(struct native_surface *nsurf,
123                            enum native_attachment which)
124{
125   struct ximage_surface *xsurf = ximage_surface(nsurf);
126   struct ximage_buffer *xbuf = &xsurf->buffers[which];
127   struct pipe_screen *screen = xsurf->xdpy->base.screen;
128   struct pipe_texture templ;
129
130   /* free old data */
131   if (xbuf->texture)
132      ximage_surface_free_buffer(&xsurf->base, which);
133
134   memset(&templ, 0, sizeof(templ));
135   templ.target = PIPE_TEXTURE_2D;
136   templ.format = xsurf->color_format;
137   templ.width0 = xsurf->width;
138   templ.height0 = xsurf->height;
139   templ.depth0 = 1;
140   templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
141
142   switch (which) {
143   case NATIVE_ATTACHMENT_FRONT_LEFT:
144   case NATIVE_ATTACHMENT_FRONT_RIGHT:
145      templ.tex_usage |= PIPE_TEXTURE_USAGE_SCANOUT;
146      break;
147   case NATIVE_ATTACHMENT_BACK_LEFT:
148   case NATIVE_ATTACHMENT_BACK_RIGHT:
149      templ.tex_usage |= PIPE_TEXTURE_USAGE_DISPLAY_TARGET;
150      break;
151   default:
152      break;
153   }
154
155   xbuf->texture = screen->texture_create(screen, &templ);
156   if (xbuf->texture) {
157      xbuf->xdraw.visual = xsurf->visual.visual;
158      xbuf->xdraw.depth = xsurf->visual.depth;
159      xbuf->xdraw.drawable = xsurf->drawable;
160   }
161
162   /* clean up the buffer if allocation failed */
163   if (!xbuf->texture)
164      ximage_surface_free_buffer(&xsurf->base, which);
165
166   return (xbuf->texture != NULL);
167}
168
169/**
170 * Update the geometry of the surface.  Return TRUE if the geometry has changed
171 * since last call.
172 */
173static boolean
174ximage_surface_update_geometry(struct native_surface *nsurf)
175{
176   struct ximage_surface *xsurf = ximage_surface(nsurf);
177   Status ok;
178   Window root;
179   int x, y;
180   unsigned int w, h, border, depth;
181   boolean updated = 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   assert(xsurf->drawable && xbuf->texture);
261
262   psurf = xsurf->draw_surface;
263   if (!psurf || psurf->texture != xbuf->texture) {
264      pipe_surface_reference(&xsurf->draw_surface, NULL);
265
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      xsurf->draw_surface = psurf;
272   }
273
274   screen->flush_frontbuffer(screen, psurf, &xbuf->xdraw);
275
276   return TRUE;
277}
278
279static boolean
280ximage_surface_flush_frontbuffer(struct native_surface *nsurf)
281{
282   struct ximage_surface *xsurf = ximage_surface(nsurf);
283   boolean ret;
284
285   ret = ximage_surface_draw_buffer(&xsurf->base,
286         NATIVE_ATTACHMENT_FRONT_LEFT);
287   /* force buffers to be updated in next validation call */
288   xsurf->server_stamp++;
289   ximage_surface_notify_invalid(&xsurf->base);
290
291   return ret;
292}
293
294static boolean
295ximage_surface_swap_buffers(struct native_surface *nsurf)
296{
297   struct ximage_surface *xsurf = ximage_surface(nsurf);
298   struct ximage_buffer *xfront, *xback, xtmp;
299   boolean ret;
300
301   /* display the back buffer first */
302   ret = ximage_surface_draw_buffer(&xsurf->base,
303         NATIVE_ATTACHMENT_BACK_LEFT);
304   /* force buffers to be updated in next validation call */
305   xsurf->server_stamp++;
306   ximage_surface_notify_invalid(&xsurf->base);
307
308   xfront = &xsurf->buffers[NATIVE_ATTACHMENT_FRONT_LEFT];
309   xback = &xsurf->buffers[NATIVE_ATTACHMENT_BACK_LEFT];
310
311   /* skip swapping unless there is a front buffer */
312   if (xfront->texture) {
313      xtmp = *xfront;
314      *xfront = *xback;
315      *xback = xtmp;
316   }
317
318   return ret;
319}
320
321static boolean
322ximage_surface_validate(struct native_surface *nsurf, uint attachment_mask,
323                        unsigned int *seq_num, struct pipe_texture **textures,
324                        int *width, int *height)
325{
326   struct ximage_surface *xsurf = ximage_surface(nsurf);
327
328   if (xsurf->client_stamp != xsurf->server_stamp ||
329       (xsurf->valid_mask & attachment_mask) != attachment_mask) {
330      if (!ximage_surface_update_buffers(&xsurf->base, attachment_mask))
331         return FALSE;
332   }
333
334   if (seq_num)
335      *seq_num = xsurf->client_stamp;
336
337   if (textures) {
338      int att;
339      for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
340         if (native_attachment_mask_test(attachment_mask, att)) {
341            struct ximage_buffer *xbuf = &xsurf->buffers[att];
342
343            textures[att] = NULL;
344            pipe_texture_reference(&textures[att], xbuf->texture);
345         }
346      }
347   }
348
349   if (width)
350      *width = xsurf->width;
351   if (height)
352      *height = xsurf->height;
353
354   return TRUE;
355}
356
357static void
358ximage_surface_wait(struct native_surface *nsurf)
359{
360   struct ximage_surface *xsurf = ximage_surface(nsurf);
361   XSync(xsurf->xdpy->dpy, FALSE);
362   /* TODO XGetImage and update the front texture */
363}
364
365static void
366ximage_surface_destroy(struct native_surface *nsurf)
367{
368   struct ximage_surface *xsurf = ximage_surface(nsurf);
369   int i;
370
371   pipe_surface_reference(&xsurf->draw_surface, NULL);
372
373   for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++)
374      ximage_surface_free_buffer(&xsurf->base, i);
375
376   free(xsurf);
377}
378
379static struct ximage_surface *
380ximage_display_create_surface(struct native_display *ndpy,
381                              enum ximage_surface_type type,
382                              Drawable drawable,
383                              const struct native_config *nconf)
384{
385   struct ximage_display *xdpy = ximage_display(ndpy);
386   struct ximage_config *xconf = ximage_config(nconf);
387   struct ximage_surface *xsurf;
388
389   xsurf = CALLOC_STRUCT(ximage_surface);
390   if (!xsurf)
391      return NULL;
392
393   xsurf->xdpy = xdpy;
394   xsurf->type = type;
395   xsurf->color_format = xconf->base.color_format;
396   xsurf->drawable = drawable;
397
398   xsurf->drawable = drawable;
399   xsurf->visual = *xconf->visual;
400   /* initialize the geometry */
401   ximage_surface_update_buffers(&xsurf->base, 0x0);
402
403   xsurf->base.destroy = ximage_surface_destroy;
404   xsurf->base.swap_buffers = ximage_surface_swap_buffers;
405   xsurf->base.flush_frontbuffer = ximage_surface_flush_frontbuffer;
406   xsurf->base.validate = ximage_surface_validate;
407   xsurf->base.wait = ximage_surface_wait;
408
409   return xsurf;
410}
411
412static struct native_surface *
413ximage_display_create_window_surface(struct native_display *ndpy,
414                                     EGLNativeWindowType win,
415                                     const struct native_config *nconf)
416{
417   struct ximage_surface *xsurf;
418
419   xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_WINDOW,
420         (Drawable) win, nconf);
421   return (xsurf) ? &xsurf->base : NULL;
422}
423
424static struct native_surface *
425ximage_display_create_pixmap_surface(struct native_display *ndpy,
426                                     EGLNativePixmapType pix,
427                                     const struct native_config *nconf)
428{
429   struct ximage_surface *xsurf;
430
431   xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_PIXMAP,
432         (Drawable) pix, nconf);
433   return (xsurf) ? &xsurf->base : NULL;
434}
435
436static enum pipe_format
437choose_format(const XVisualInfo *vinfo)
438{
439   enum pipe_format fmt;
440   /* TODO elaborate the formats */
441   switch (vinfo->depth) {
442   case 32:
443      fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
444      break;
445   case 24:
446      fmt = PIPE_FORMAT_B8G8R8X8_UNORM;
447      break;
448   case 16:
449      fmt = PIPE_FORMAT_B5G6R5_UNORM;
450      break;
451   default:
452      fmt = PIPE_FORMAT_NONE;
453      break;
454   }
455
456   return fmt;
457}
458
459static const struct native_config **
460ximage_display_get_configs(struct native_display *ndpy, int *num_configs)
461{
462   struct ximage_display *xdpy = ximage_display(ndpy);
463   const struct native_config **configs;
464   int i;
465
466   /* first time */
467   if (!xdpy->configs) {
468      const XVisualInfo *visuals;
469      int num_visuals, count, j;
470
471      visuals = x11_screen_get_visuals(xdpy->xscr, &num_visuals);
472      if (!visuals)
473         return NULL;
474
475      /*
476       * Create two configs for each visual.
477       * One with depth/stencil buffer; one without
478       */
479      xdpy->configs = calloc(num_visuals * 2, sizeof(*xdpy->configs));
480      if (!xdpy->configs)
481         return NULL;
482
483      count = 0;
484      for (i = 0; i < num_visuals; i++) {
485         for (j = 0; j < 2; j++) {
486            struct ximage_config *xconf = &xdpy->configs[count];
487            __GLcontextModes *mode = &xconf->base.mode;
488
489            xconf->visual = &visuals[i];
490            xconf->base.color_format = choose_format(xconf->visual);
491            if (xconf->base.color_format == PIPE_FORMAT_NONE)
492               continue;
493
494            x11_screen_convert_visual(xdpy->xscr, xconf->visual, mode);
495            /* support double buffer mode */
496            mode->doubleBufferMode = TRUE;
497
498            xconf->base.depth_format = PIPE_FORMAT_NONE;
499            xconf->base.stencil_format = PIPE_FORMAT_NONE;
500            /* create the second config with depth/stencil buffer */
501            if (j == 1) {
502               xconf->base.depth_format = PIPE_FORMAT_Z24_UNORM_S8_USCALED;
503               xconf->base.stencil_format = PIPE_FORMAT_Z24_UNORM_S8_USCALED;
504               mode->depthBits = 24;
505               mode->stencilBits = 8;
506               mode->haveDepthBuffer = TRUE;
507               mode->haveStencilBuffer = TRUE;
508            }
509
510            mode->maxPbufferWidth = 4096;
511            mode->maxPbufferHeight = 4096;
512            mode->maxPbufferPixels = 4096 * 4096;
513            mode->drawableType =
514               GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT;
515            mode->swapMethod = GLX_SWAP_EXCHANGE_OML;
516
517            if (mode->alphaBits)
518               mode->bindToTextureRgba = TRUE;
519            else
520               mode->bindToTextureRgb = TRUE;
521
522            count++;
523         }
524      }
525
526      xdpy->num_configs = count;
527   }
528
529   configs = malloc(xdpy->num_configs * sizeof(*configs));
530   if (configs) {
531      for (i = 0; i < xdpy->num_configs; i++)
532         configs[i] = (const struct native_config *) &xdpy->configs[i];
533      if (num_configs)
534         *num_configs = xdpy->num_configs;
535   }
536   return configs;
537}
538
539static boolean
540ximage_display_is_pixmap_supported(struct native_display *ndpy,
541                                   EGLNativePixmapType pix,
542                                   const struct native_config *nconf)
543{
544   struct ximage_display *xdpy = ximage_display(ndpy);
545   enum pipe_format fmt;
546   uint depth;
547
548   depth = x11_drawable_get_depth(xdpy->xscr, (Drawable) pix);
549   switch (depth) {
550   case 32:
551      fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
552      break;
553   case 24:
554      fmt = PIPE_FORMAT_B8G8R8X8_UNORM;
555      break;
556   case 16:
557      fmt = PIPE_FORMAT_B5G6R5_UNORM;
558      break;
559   default:
560      fmt = PIPE_FORMAT_NONE;
561      break;
562   }
563
564   return (fmt == nconf->color_format);
565}
566
567static int
568ximage_display_get_param(struct native_display *ndpy,
569                         enum native_param_type param)
570{
571   int val;
572
573   switch (param) {
574   case NATIVE_PARAM_USE_NATIVE_BUFFER:
575      /* private buffers are allocated */
576      val = FALSE;
577      break;
578   default:
579      val = 0;
580      break;
581   }
582
583   return val;
584}
585
586static void
587ximage_display_destroy(struct native_display *ndpy)
588{
589   struct ximage_display *xdpy = ximage_display(ndpy);
590
591   if (xdpy->configs)
592      free(xdpy->configs);
593
594   xdpy->base.screen->destroy(xdpy->base.screen);
595
596   x11_screen_destroy(xdpy->xscr);
597   if (xdpy->own_dpy)
598      XCloseDisplay(xdpy->dpy);
599   free(xdpy);
600}
601
602
603/* Helper function to build a subset of a driver stack consisting of
604 * one of the software rasterizers (cell, llvmpipe, softpipe) and the
605 * xlib winsys.
606 *
607 * This function could be shared, but currently causes headaches for
608 * the build systems, particularly scons if we try.
609 *
610 * Long term, want to avoid having global #defines for things like
611 * GALLIUM_LLVMPIPE, GALLIUM_CELL, etc.  Scons already eliminates
612 * those #defines, so things that are painful for it now are likely to
613 * be painful for other build systems in the future.
614 */
615static struct pipe_screen *
616swrast_xlib_create_screen( Display *display )
617{
618   struct sw_winsys *winsys;
619   struct pipe_screen *screen = NULL;
620
621   /* Create the underlying winsys, which performs presents to Xlib
622    * drawables:
623    */
624   winsys = xlib_create_sw_winsys( display );
625   if (winsys == NULL)
626      return NULL;
627
628   /* Create a software rasterizer on top of that winsys.  Use
629    * llvmpipe if it is available.
630    */
631#if defined(GALLIUM_LLVMPIPE)
632   if (screen == NULL &&
633       !debug_get_bool_option("GALLIUM_NO_LLVM", FALSE))
634      screen = llvmpipe_create_screen( winsys );
635#endif
636
637   if (screen == NULL)
638      screen = softpipe_create_screen( winsys );
639
640   if (screen == NULL)
641      goto fail;
642
643   /* Inject any wrapping layers we want to here:
644    */
645   return gallium_wrap_screen( screen );
646
647fail:
648   if (winsys)
649      winsys->destroy( winsys );
650
651   return NULL;
652}
653
654
655
656struct native_display *
657x11_create_ximage_display(EGLNativeDisplayType dpy,
658                          struct native_event_handler *event_handler)
659{
660   struct ximage_display *xdpy;
661
662   xdpy = CALLOC_STRUCT(ximage_display);
663   if (!xdpy)
664      return NULL;
665
666   xdpy->dpy = dpy;
667   if (!xdpy->dpy) {
668      xdpy->dpy = XOpenDisplay(NULL);
669      if (!xdpy->dpy) {
670         free(xdpy);
671         return NULL;
672      }
673      xdpy->own_dpy = TRUE;
674   }
675
676   xdpy->event_handler = event_handler;
677
678   xdpy->xscr_number = DefaultScreen(xdpy->dpy);
679   xdpy->xscr = x11_screen_create(xdpy->dpy, xdpy->xscr_number);
680   if (!xdpy->xscr) {
681      free(xdpy);
682      return NULL;
683   }
684
685   xdpy->base.screen = swrast_xlib_create_screen(xdpy->dpy);
686
687   xdpy->base.destroy = ximage_display_destroy;
688   xdpy->base.get_param = ximage_display_get_param;
689
690   xdpy->base.get_configs = ximage_display_get_configs;
691   xdpy->base.is_pixmap_supported = ximage_display_is_pixmap_supported;
692   xdpy->base.create_window_surface = ximage_display_create_window_surface;
693   xdpy->base.create_pixmap_surface = ximage_display_create_pixmap_surface;
694
695   return &xdpy->base;
696}
697