2 * Mesa 3-D graphics library
5 * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
25 #include "util/u_memory.h"
26 #include "util/u_math.h"
27 #include "util/u_format.h"
28 #include "pipe/p_compiler.h"
29 #include "pipe/p_screen.h"
30 #include "pipe/p_context.h"
31 #include "pipe/p_state.h"
32 #include "state_tracker/drm_api.h"
35 #include "native_x11.h"
36 #include "x11_screen.h"
38 enum dri2_surface_type
{
39 DRI2_SURFACE_TYPE_WINDOW
,
40 DRI2_SURFACE_TYPE_PIXMAP
,
41 DRI2_SURFACE_TYPE_PBUFFER
45 struct native_display base
;
50 struct x11_screen
*xscr
;
53 struct dri2_config
*configs
;
58 struct native_surface base
;
60 enum dri2_surface_type type
;
61 enum pipe_format color_format
;
62 struct dri2_display
*dri2dpy
;
64 struct pipe_texture
*pbuffer_textures
[NUM_NATIVE_ATTACHMENTS
];
65 boolean have_back
, have_fake
;
67 unsigned int sequence_number
;
71 struct native_config base
;
74 static INLINE
struct dri2_display
*
75 dri2_display(const struct native_display
*ndpy
)
77 return (struct dri2_display
*) ndpy
;
80 static INLINE
struct dri2_surface
*
81 dri2_surface(const struct native_surface
*nsurf
)
83 return (struct dri2_surface
*) nsurf
;
86 static INLINE
struct dri2_config
*
87 dri2_config(const struct native_config
*nconf
)
89 return (struct dri2_config
*) nconf
;
93 dri2_surface_flush_frontbuffer(struct native_surface
*nsurf
)
95 struct dri2_surface
*dri2surf
= dri2_surface(nsurf
);
96 struct dri2_display
*dri2dpy
= dri2surf
->dri2dpy
;
98 /* pbuffer is private */
99 if (dri2surf
->type
== DRI2_SURFACE_TYPE_PBUFFER
)
102 /* copy to real front buffer */
103 if (dri2surf
->have_fake
)
104 x11_drawable_copy_buffers(dri2dpy
->xscr
, dri2surf
->drawable
,
105 0, 0, dri2surf
->width
, dri2surf
->height
,
106 DRI2BufferFakeFrontLeft
, DRI2BufferFrontLeft
);
112 dri2_surface_swap_buffers(struct native_surface
*nsurf
)
114 struct dri2_surface
*dri2surf
= dri2_surface(nsurf
);
115 struct dri2_display
*dri2dpy
= dri2surf
->dri2dpy
;
117 /* pbuffer is private */
118 if (dri2surf
->type
== DRI2_SURFACE_TYPE_PBUFFER
)
121 /* copy to front buffer */
122 if (dri2surf
->have_back
)
123 x11_drawable_copy_buffers(dri2dpy
->xscr
, dri2surf
->drawable
,
124 0, 0, dri2surf
->width
, dri2surf
->height
,
125 DRI2BufferBackLeft
, DRI2BufferFrontLeft
);
127 /* and update fake front buffer */
128 if (dri2surf
->have_fake
)
129 x11_drawable_copy_buffers(dri2dpy
->xscr
, dri2surf
->drawable
,
130 0, 0, dri2surf
->width
, dri2surf
->height
,
131 DRI2BufferFrontLeft
, DRI2BufferFakeFrontLeft
);
137 dri2_surface_validate(struct native_surface
*nsurf
, uint attachment_mask
,
138 unsigned int *seq_num
, struct pipe_texture
**textures
,
139 int *width
, int *height
)
141 struct dri2_surface
*dri2surf
= dri2_surface(nsurf
);
142 struct dri2_display
*dri2dpy
= dri2surf
->dri2dpy
;
143 unsigned int dri2atts
[NUM_NATIVE_ATTACHMENTS
];
144 struct pipe_texture templ
;
145 struct x11_drawable_buffer
*xbufs
;
146 int num_ins
, num_outs
, att
, i
;
148 if (attachment_mask
) {
149 memset(&templ
, 0, sizeof(templ
));
150 templ
.target
= PIPE_TEXTURE_2D
;
151 templ
.last_level
= 0;
152 templ
.width0
= dri2surf
->width
;
153 templ
.height0
= dri2surf
->height
;
155 templ
.format
= dri2surf
->color_format
;
156 templ
.tex_usage
= PIPE_TEXTURE_USAGE_RENDER_TARGET
;
159 memset(textures
, 0, sizeof(*textures
) * NUM_NATIVE_ATTACHMENTS
);
162 /* create textures for pbuffer */
163 if (dri2surf
->type
== DRI2_SURFACE_TYPE_PBUFFER
) {
164 struct pipe_screen
*screen
= dri2dpy
->base
.screen
;
166 for (att
= 0; att
< NUM_NATIVE_ATTACHMENTS
; att
++) {
167 struct pipe_texture
*ptex
= dri2surf
->pbuffer_textures
[att
];
169 /* delay the allocation */
170 if (!native_attachment_mask_test(attachment_mask
, att
))
174 ptex
= screen
->texture_create(screen
, &templ
);
175 dri2surf
->pbuffer_textures
[att
] = ptex
;
179 pipe_texture_reference(&textures
[att
], ptex
);
183 *seq_num
= dri2surf
->sequence_number
;
185 *width
= dri2surf
->width
;
187 *height
= dri2surf
->height
;
192 /* prepare the attachments */
194 for (att
= 0; att
< NUM_NATIVE_ATTACHMENTS
; att
++) {
195 if (native_attachment_mask_test(attachment_mask
, att
)) {
196 unsigned int dri2att
;
199 case NATIVE_ATTACHMENT_FRONT_LEFT
:
200 dri2att
= DRI2BufferFrontLeft
;
202 case NATIVE_ATTACHMENT_BACK_LEFT
:
203 dri2att
= DRI2BufferBackLeft
;
205 case NATIVE_ATTACHMENT_FRONT_RIGHT
:
206 dri2att
= DRI2BufferFrontRight
;
208 case NATIVE_ATTACHMENT_BACK_RIGHT
:
209 dri2att
= DRI2BufferBackRight
;
217 dri2atts
[num_ins
] = dri2att
;
222 dri2surf
->have_back
= FALSE
;
223 dri2surf
->have_fake
= FALSE
;
225 /* remember old geometry */
226 templ
.width0
= dri2surf
->width
;
227 templ
.height0
= dri2surf
->height
;
229 xbufs
= x11_drawable_get_buffers(dri2dpy
->xscr
, dri2surf
->drawable
,
230 &dri2surf
->width
, &dri2surf
->height
,
231 dri2atts
, FALSE
, num_ins
, &num_outs
);
235 if (templ
.width0
!= dri2surf
->width
|| templ
.height0
!= dri2surf
->height
) {
236 /* are there cases where the buffers change and the geometry doesn't? */
237 dri2surf
->sequence_number
++;
239 templ
.width0
= dri2surf
->width
;
240 templ
.height0
= dri2surf
->height
;
243 for (i
= 0; i
< num_outs
; i
++) {
244 struct x11_drawable_buffer
*xbuf
= &xbufs
[i
];
246 enum native_attachment natt
;
248 switch (xbuf
->attachment
) {
249 case DRI2BufferFrontLeft
:
250 natt
= NATIVE_ATTACHMENT_FRONT_LEFT
;
251 desc
= "DRI2 Front Buffer";
253 case DRI2BufferFakeFrontLeft
:
254 natt
= NATIVE_ATTACHMENT_FRONT_LEFT
;
255 desc
= "DRI2 Fake Front Buffer";
256 dri2surf
->have_fake
= TRUE
;
258 case DRI2BufferBackLeft
:
259 natt
= NATIVE_ATTACHMENT_BACK_LEFT
;
260 desc
= "DRI2 Back Buffer";
261 dri2surf
->have_back
= TRUE
;
268 if (!desc
|| !native_attachment_mask_test(attachment_mask
, natt
) ||
269 (textures
&& textures
[natt
])) {
271 _eglLog(_EGL_WARNING
, "unknown buffer %d", xbuf
->attachment
);
272 else if (!native_attachment_mask_test(attachment_mask
, natt
))
273 _eglLog(_EGL_WARNING
, "unexpected buffer %d", xbuf
->attachment
);
275 _eglLog(_EGL_WARNING
, "both real and fake front buffers are listed");
280 struct pipe_texture
*ptex
=
281 dri2dpy
->api
->texture_from_shared_handle(dri2dpy
->api
,
282 dri2dpy
->base
.screen
, &templ
,
283 desc
, xbuf
->pitch
, xbuf
->name
);
285 /* the caller owns the textures */
286 textures
[natt
] = ptex
;
294 *seq_num
= dri2surf
->sequence_number
;
296 *width
= dri2surf
->width
;
298 *height
= dri2surf
->height
;
304 dri2_surface_wait(struct native_surface
*nsurf
)
306 struct dri2_surface
*dri2surf
= dri2_surface(nsurf
);
307 struct dri2_display
*dri2dpy
= dri2surf
->dri2dpy
;
309 if (dri2surf
->have_fake
) {
310 x11_drawable_copy_buffers(dri2dpy
->xscr
, dri2surf
->drawable
,
311 0, 0, dri2surf
->width
, dri2surf
->height
,
312 DRI2BufferFrontLeft
, DRI2BufferFakeFrontLeft
);
317 dri2_surface_destroy(struct native_surface
*nsurf
)
319 struct dri2_surface
*dri2surf
= dri2_surface(nsurf
);
322 for (i
= 0; i
< NUM_NATIVE_ATTACHMENTS
; i
++) {
323 struct pipe_texture
*ptex
= dri2surf
->pbuffer_textures
[i
];
324 pipe_texture_reference(&ptex
, NULL
);
327 if (dri2surf
->drawable
)
328 x11_drawable_enable_dri2(dri2surf
->dri2dpy
->xscr
,
329 dri2surf
->drawable
, FALSE
);
333 static struct dri2_surface
*
334 dri2_display_create_surface(struct native_display
*ndpy
,
335 enum dri2_surface_type type
,
337 const struct native_config
*nconf
)
339 struct dri2_display
*dri2dpy
= dri2_display(ndpy
);
340 struct dri2_config
*dri2conf
= dri2_config(nconf
);
341 struct dri2_surface
*dri2surf
;
343 dri2surf
= CALLOC_STRUCT(dri2_surface
);
348 x11_drawable_enable_dri2(dri2dpy
->xscr
, drawable
, TRUE
);
350 dri2surf
->dri2dpy
= dri2dpy
;
351 dri2surf
->type
= type
;
352 dri2surf
->drawable
= drawable
;
353 dri2surf
->color_format
= dri2conf
->base
.color_format
;
355 dri2surf
->base
.destroy
= dri2_surface_destroy
;
356 dri2surf
->base
.swap_buffers
= dri2_surface_swap_buffers
;
357 dri2surf
->base
.flush_frontbuffer
= dri2_surface_flush_frontbuffer
;
358 dri2surf
->base
.validate
= dri2_surface_validate
;
359 dri2surf
->base
.wait
= dri2_surface_wait
;
364 static struct native_surface
*
365 dri2_display_create_window_surface(struct native_display
*ndpy
,
366 EGLNativeWindowType win
,
367 const struct native_config
*nconf
)
369 struct dri2_surface
*dri2surf
;
371 dri2surf
= dri2_display_create_surface(ndpy
, DRI2_SURFACE_TYPE_WINDOW
,
372 (Drawable
) win
, nconf
);
373 return (dri2surf
) ? &dri2surf
->base
: NULL
;
376 static struct native_surface
*
377 dri2_display_create_pixmap_surface(struct native_display
*ndpy
,
378 EGLNativePixmapType pix
,
379 const struct native_config
*nconf
)
381 struct dri2_surface
*dri2surf
;
383 dri2surf
= dri2_display_create_surface(ndpy
, DRI2_SURFACE_TYPE_PIXMAP
,
384 (Drawable
) pix
, nconf
);
385 return (dri2surf
) ? &dri2surf
->base
: NULL
;
388 static struct native_surface
*
389 dri2_display_create_pbuffer_surface(struct native_display
*ndpy
,
390 const struct native_config
*nconf
,
391 uint width
, uint height
)
393 struct dri2_surface
*dri2surf
;
395 dri2surf
= dri2_display_create_surface(ndpy
, DRI2_SURFACE_TYPE_PBUFFER
,
396 (Drawable
) None
, nconf
);
398 dri2surf
->width
= width
;
399 dri2surf
->height
= height
;
401 return (dri2surf
) ? &dri2surf
->base
: NULL
;
404 static struct pipe_context
*
405 dri2_display_create_context(struct native_display
*ndpy
, void *context_private
)
407 struct dri2_display
*dri2dpy
= dri2_display(ndpy
);
408 struct pipe_context
*pctx
;
410 pctx
= dri2dpy
->api
->create_context(dri2dpy
->api
, dri2dpy
->base
.screen
);
412 pctx
->priv
= context_private
;
417 choose_color_format(const __GLcontextModes
*mode
, enum pipe_format formats
[32])
421 switch (mode
->rgbBits
) {
423 formats
[count
++] = PIPE_FORMAT_A8R8G8B8_UNORM
;
424 formats
[count
++] = PIPE_FORMAT_B8G8R8A8_UNORM
;
427 formats
[count
++] = PIPE_FORMAT_X8R8G8B8_UNORM
;
428 formats
[count
++] = PIPE_FORMAT_B8G8R8X8_UNORM
;
429 formats
[count
++] = PIPE_FORMAT_A8R8G8B8_UNORM
;
430 formats
[count
++] = PIPE_FORMAT_B8G8R8A8_UNORM
;
433 formats
[count
++] = PIPE_FORMAT_R5G6B5_UNORM
;
443 choose_depth_stencil_format(const __GLcontextModes
*mode
,
444 enum pipe_format formats
[32])
448 switch (mode
->depthBits
) {
450 formats
[count
++] = PIPE_FORMAT_Z32_UNORM
;
453 if (mode
->stencilBits
) {
454 formats
[count
++] = PIPE_FORMAT_S8Z24_UNORM
;
455 formats
[count
++] = PIPE_FORMAT_Z24S8_UNORM
;
458 formats
[count
++] = PIPE_FORMAT_X8Z24_UNORM
;
459 formats
[count
++] = PIPE_FORMAT_Z24X8_UNORM
;
463 formats
[count
++] = PIPE_FORMAT_Z16_UNORM
;
473 is_format_supported(struct pipe_screen
*screen
,
474 enum pipe_format fmt
, boolean is_color
)
476 return screen
->is_format_supported(screen
, fmt
, PIPE_TEXTURE_2D
,
477 (is_color
) ? PIPE_TEXTURE_USAGE_RENDER_TARGET
:
478 PIPE_TEXTURE_USAGE_DEPTH_STENCIL
, 0);
482 dri2_display_convert_config(struct native_display
*ndpy
,
483 const __GLcontextModes
*mode
,
484 struct native_config
*nconf
)
486 enum pipe_format formats
[32];
489 if (!(mode
->renderType
& GLX_RGBA_BIT
) || !mode
->rgbMode
)
492 /* skip single-buffered configs */
493 if (!mode
->doubleBufferMode
)
497 nconf
->mode
.renderType
= GLX_RGBA_BIT
;
498 nconf
->mode
.rgbMode
= TRUE
;
499 /* pbuffer is allocated locally and is always supported */
500 nconf
->mode
.drawableType
|= GLX_PBUFFER_BIT
;
501 /* the swap method is always copy */
502 nconf
->mode
.swapMethod
= GLX_SWAP_COPY_OML
;
505 nconf
->mode
.rgbBits
=
506 nconf
->mode
.redBits
+ nconf
->mode
.greenBits
+
507 nconf
->mode
.blueBits
+ nconf
->mode
.alphaBits
;
508 if (!(nconf
->mode
.drawableType
& GLX_WINDOW_BIT
)) {
509 nconf
->mode
.visualID
= 0;
510 nconf
->mode
.visualType
= GLX_NONE
;
512 if (!(nconf
->mode
.drawableType
& GLX_PBUFFER_BIT
)) {
513 nconf
->mode
.bindToTextureRgb
= FALSE
;
514 nconf
->mode
.bindToTextureRgba
= FALSE
;
517 nconf
->color_format
= PIPE_FORMAT_NONE
;
518 nconf
->depth_format
= PIPE_FORMAT_NONE
;
519 nconf
->stencil_format
= PIPE_FORMAT_NONE
;
521 /* choose color format */
522 num_formats
= choose_color_format(mode
, formats
);
523 for (i
= 0; i
< num_formats
; i
++) {
524 if (is_format_supported(ndpy
->screen
, formats
[i
], TRUE
)) {
525 nconf
->color_format
= formats
[i
];
529 if (nconf
->color_format
== PIPE_FORMAT_NONE
)
532 /* choose depth/stencil format */
533 num_formats
= choose_depth_stencil_format(mode
, formats
);
534 for (i
= 0; i
< num_formats
; i
++) {
535 if (is_format_supported(ndpy
->screen
, formats
[i
], FALSE
)) {
536 nconf
->depth_format
= formats
[i
];
537 nconf
->stencil_format
= formats
[i
];
541 if ((nconf
->mode
.depthBits
&& nconf
->depth_format
== PIPE_FORMAT_NONE
) ||
542 (nconf
->mode
.stencilBits
&& nconf
->stencil_format
== PIPE_FORMAT_NONE
))
548 static const struct native_config
**
549 dri2_display_get_configs(struct native_display
*ndpy
, int *num_configs
)
551 struct dri2_display
*dri2dpy
= dri2_display(ndpy
);
552 const struct native_config
**configs
;
556 if (!dri2dpy
->configs
) {
557 const __GLcontextModes
*modes
;
558 int num_modes
, count
;
560 modes
= x11_screen_get_glx_configs(dri2dpy
->xscr
);
563 num_modes
= x11_context_modes_count(modes
);
565 dri2dpy
->configs
= calloc(num_modes
, sizeof(*dri2dpy
->configs
));
566 if (!dri2dpy
->configs
)
570 for (i
= 0; i
< num_modes
; i
++) {
571 struct native_config
*nconf
= &dri2dpy
->configs
[count
].base
;
572 if (dri2_display_convert_config(&dri2dpy
->base
, modes
, nconf
))
577 dri2dpy
->num_configs
= count
;
580 configs
= malloc(dri2dpy
->num_configs
* sizeof(*configs
));
582 for (i
= 0; i
< dri2dpy
->num_configs
; i
++)
583 configs
[i
] = (const struct native_config
*) &dri2dpy
->configs
[i
];
585 *num_configs
= dri2dpy
->num_configs
;
592 dri2_display_is_pixmap_supported(struct native_display
*ndpy
,
593 EGLNativePixmapType pix
,
594 const struct native_config
*nconf
)
596 struct dri2_display
*dri2dpy
= dri2_display(ndpy
);
597 uint depth
, nconf_depth
;
599 depth
= x11_drawable_get_depth(dri2dpy
->xscr
, (Drawable
) pix
);
600 nconf_depth
= util_format_get_blocksizebits(nconf
->color_format
);
602 /* simple depth match for now */
603 return (depth
== nconf_depth
|| (depth
== 24 && depth
+ 8 == nconf_depth
));
607 dri2_display_destroy(struct native_display
*ndpy
)
609 struct dri2_display
*dri2dpy
= dri2_display(ndpy
);
611 if (dri2dpy
->configs
)
612 free(dri2dpy
->configs
);
614 if (dri2dpy
->base
.screen
)
615 dri2dpy
->base
.screen
->destroy(dri2dpy
->base
.screen
);
618 x11_screen_destroy(dri2dpy
->xscr
);
619 if (dri2dpy
->own_dpy
)
620 XCloseDisplay(dri2dpy
->dpy
);
621 if (dri2dpy
->api
&& dri2dpy
->api
->destroy
)
622 dri2dpy
->api
->destroy(dri2dpy
->api
);
627 * Initialize DRI2 and pipe screen.
630 dri2_display_init_screen(struct native_display
*ndpy
)
632 struct dri2_display
*dri2dpy
= dri2_display(ndpy
);
633 const char *driver
= dri2dpy
->api
->name
;
634 struct drm_create_screen_arg arg
;
637 if (!x11_screen_support(dri2dpy
->xscr
, X11_SCREEN_EXTENSION_DRI2
) ||
638 !x11_screen_support(dri2dpy
->xscr
, X11_SCREEN_EXTENSION_GLX
)) {
639 _eglLog(_EGL_WARNING
, "GLX/DRI2 is not supported");
643 fd
= x11_screen_enable_dri2(dri2dpy
->xscr
, driver
);
647 memset(&arg
, 0, sizeof(arg
));
648 arg
.mode
= DRM_CREATE_NORMAL
;
649 dri2dpy
->base
.screen
= dri2dpy
->api
->create_screen(dri2dpy
->api
, fd
, &arg
);
650 if (!dri2dpy
->base
.screen
) {
651 _eglLog(_EGL_WARNING
, "failed to create DRM screen");
658 struct native_display
*
659 x11_create_dri2_display(EGLNativeDisplayType dpy
, struct drm_api
*api
)
661 struct dri2_display
*dri2dpy
;
663 dri2dpy
= CALLOC_STRUCT(dri2_display
);
669 _eglLog(_EGL_WARNING
, "failed to create DRM API");
676 dri2dpy
->dpy
= XOpenDisplay(NULL
);
678 dri2_display_destroy(&dri2dpy
->base
);
681 dri2dpy
->own_dpy
= TRUE
;
684 dri2dpy
->xscr_number
= DefaultScreen(dri2dpy
->dpy
);
685 dri2dpy
->xscr
= x11_screen_create(dri2dpy
->dpy
, dri2dpy
->xscr_number
);
686 if (!dri2dpy
->xscr
) {
687 dri2_display_destroy(&dri2dpy
->base
);
691 if (!dri2_display_init_screen(&dri2dpy
->base
)) {
692 dri2_display_destroy(&dri2dpy
->base
);
696 dri2dpy
->base
.destroy
= dri2_display_destroy
;
697 dri2dpy
->base
.get_configs
= dri2_display_get_configs
;
698 dri2dpy
->base
.is_pixmap_supported
= dri2_display_is_pixmap_supported
;
699 dri2dpy
->base
.create_context
= dri2_display_create_context
;
700 dri2dpy
->base
.create_window_surface
= dri2_display_create_window_surface
;
701 dri2dpy
->base
.create_pixmap_surface
= dri2_display_create_pixmap_surface
;
702 dri2dpy
->base
.create_pbuffer_surface
= dri2_display_create_pbuffer_surface
;
704 return &dri2dpy
->base
;