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