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.
27 #include "pipe/p_screen.h"
28 #include "util/u_memory.h"
29 #include "util/u_rect.h"
30 #include "egldriver.h"
31 #include "eglcurrent.h"
32 #include "eglconfigutil.h"
40 * Validate the draw/read surfaces of the context.
43 egl_g3d_validate_context(_EGLDisplay
*dpy
, _EGLContext
*ctx
)
45 struct egl_g3d_display
*gdpy
= egl_g3d_display(dpy
);
46 struct pipe_screen
*screen
= gdpy
->native
->screen
;
47 struct egl_g3d_context
*gctx
= egl_g3d_context(ctx
);
48 const uint st_att_map
[NUM_NATIVE_ATTACHMENTS
] = {
49 ST_SURFACE_FRONT_LEFT
,
51 ST_SURFACE_FRONT_RIGHT
,
52 ST_SURFACE_BACK_RIGHT
,
54 EGLint num_surfaces
, s
;
56 /* validate draw and/or read buffers */
57 num_surfaces
= (gctx
->base
.ReadSurface
== gctx
->base
.DrawSurface
) ? 1 : 2;
58 for (s
= 0; s
< num_surfaces
; s
++) {
59 struct pipe_texture
*textures
[NUM_NATIVE_ATTACHMENTS
];
60 struct egl_g3d_surface
*gsurf
;
61 struct egl_g3d_buffer
*gbuf
;
65 gsurf
= egl_g3d_surface(gctx
->base
.DrawSurface
);
69 gsurf
= egl_g3d_surface(gctx
->base
.ReadSurface
);
73 if (!gctx
->force_validate
) {
76 gsurf
->native
->validate(gsurf
->native
, gbuf
->attachment_mask
,
77 &seq_num
, NULL
, NULL
, NULL
);
79 if (gsurf
->sequence_number
== seq_num
)
83 pipe_surface_reference(&gsurf
->render_surface
, NULL
);
84 memset(textures
, 0, sizeof(textures
));
86 gsurf
->native
->validate(gsurf
->native
, gbuf
->attachment_mask
,
87 &gsurf
->sequence_number
, textures
,
88 &gsurf
->base
.Width
, &gsurf
->base
.Height
);
89 for (att
= 0; att
< NUM_NATIVE_ATTACHMENTS
; att
++) {
90 struct pipe_texture
*pt
= textures
[att
];
91 struct pipe_surface
*ps
;
93 if (native_attachment_mask_test(gbuf
->attachment_mask
, att
) && pt
) {
94 ps
= screen
->get_tex_surface(screen
, pt
, 0, 0, 0,
95 PIPE_BUFFER_USAGE_GPU_READ
|
96 PIPE_BUFFER_USAGE_GPU_WRITE
);
97 gctx
->stapi
->st_set_framebuffer_surface(gbuf
->st_fb
,
100 if (gsurf
->render_att
== att
)
101 pipe_surface_reference(&gsurf
->render_surface
, ps
);
103 pipe_surface_reference(&ps
, NULL
);
104 pipe_texture_reference(&pt
, NULL
);
108 gctx
->stapi
->st_resize_framebuffer(gbuf
->st_fb
,
109 gsurf
->base
.Width
, gsurf
->base
.Height
);
112 gctx
->force_validate
= EGL_FALSE
;
117 * Create a st_framebuffer.
119 static struct st_framebuffer
*
120 create_framebuffer(_EGLContext
*ctx
, _EGLSurface
*surf
)
122 struct egl_g3d_context
*gctx
= egl_g3d_context(ctx
);
123 struct egl_g3d_surface
*gsurf
= egl_g3d_surface(surf
);
124 struct egl_g3d_config
*gconf
= egl_g3d_config(gsurf
->base
.Config
);
126 return gctx
->stapi
->st_create_framebuffer(&gconf
->native
->mode
,
127 gconf
->native
->color_format
, gconf
->native
->depth_format
,
128 gconf
->native
->stencil_format
,
129 gsurf
->base
.Width
, gsurf
->base
.Height
, &gsurf
->base
);
133 * Update the attachments of draw/read surfaces.
136 egl_g3d_route_context(_EGLDisplay
*dpy
, _EGLContext
*ctx
)
138 struct egl_g3d_context
*gctx
= egl_g3d_context(ctx
);
141 /* route draw and read buffers' attachments */
142 for (s
= 0; s
< 2; s
++) {
143 struct egl_g3d_surface
*gsurf
;
144 struct egl_g3d_buffer
*gbuf
;
147 gsurf
= egl_g3d_surface(gctx
->base
.DrawSurface
);
151 gsurf
= egl_g3d_surface(gctx
->base
.ReadSurface
);
155 gbuf
->attachment_mask
= (1 << gsurf
->render_att
);
157 /* FIXME OpenGL defaults to draw the front or back buffer when the
158 * context is single-buffered or double-buffered respectively. In EGL,
159 * however, the buffer to be drawn is determined by the surface, instead
160 * of the context. As a result, rendering to a pixmap surface with a
161 * double-buffered context does not work as expected.
163 * gctx->stapi->st_draw_front_buffer(gctx->st_ctx, natt ==
164 * NATIVE_ATTACHMENT_FRONT_LEFT);
168 * FIXME If the back buffer is asked for here, and the front buffer is
169 * later needed by the client API (e.g. glDrawBuffer is called to draw
170 * the front buffer), it will create a new pipe texture and draw there.
171 * One fix is to ask for both buffers here, but it would be a waste if
172 * the front buffer is never used. A better fix is to add a callback to
173 * the pipe screen with context private (just like flush_frontbuffer).
179 * Reallocate the context's framebuffers after draw/read surfaces change.
182 egl_g3d_realloc_context(_EGLDisplay
*dpy
, _EGLContext
*ctx
)
184 struct egl_g3d_context
*gctx
= egl_g3d_context(ctx
);
185 struct egl_g3d_surface
*gdraw
= egl_g3d_surface(gctx
->base
.DrawSurface
);
186 struct egl_g3d_surface
*gread
= egl_g3d_surface(gctx
->base
.ReadSurface
);
188 /* unreference the old framebuffers */
189 if (gctx
->draw
.st_fb
) {
190 EGLBoolean is_equal
= (gctx
->draw
.st_fb
== gctx
->read
.st_fb
);
193 priv
= gctx
->stapi
->st_framebuffer_private(gctx
->draw
.st_fb
);
194 if (!gdraw
|| priv
!= (void *) &gdraw
->base
) {
195 gctx
->stapi
->st_unreference_framebuffer(gctx
->draw
.st_fb
);
196 gctx
->draw
.st_fb
= NULL
;
197 gctx
->draw
.attachment_mask
= 0x0;
201 gctx
->read
.st_fb
= NULL
;
202 gctx
->draw
.attachment_mask
= 0x0;
205 priv
= gctx
->stapi
->st_framebuffer_private(gctx
->read
.st_fb
);
206 if (!gread
|| priv
!= (void *) &gread
->base
) {
207 gctx
->stapi
->st_unreference_framebuffer(gctx
->read
.st_fb
);
208 gctx
->read
.st_fb
= NULL
;
209 gctx
->draw
.attachment_mask
= 0x0;
217 /* create the draw fb */
218 if (!gctx
->draw
.st_fb
) {
219 gctx
->draw
.st_fb
= create_framebuffer(&gctx
->base
, &gdraw
->base
);
220 if (!gctx
->draw
.st_fb
)
224 /* create the read fb */
225 if (!gctx
->read
.st_fb
) {
226 if (gread
!= gdraw
) {
227 gctx
->read
.st_fb
= create_framebuffer(&gctx
->base
, &gread
->base
);
228 if (!gctx
->read
.st_fb
) {
229 gctx
->stapi
->st_unreference_framebuffer(gctx
->draw
.st_fb
);
230 gctx
->draw
.st_fb
= NULL
;
235 /* there is no st_reference_framebuffer... */
236 gctx
->read
.st_fb
= gctx
->draw
.st_fb
;
240 egl_g3d_route_context(dpy
, &gctx
->base
);
241 gctx
->force_validate
= EGL_TRUE
;
247 * Return the current context of the given API.
249 static struct egl_g3d_context
*
250 egl_g3d_get_current_context(EGLint api
)
252 _EGLThreadInfo
*t
= _eglGetCurrentThread();
253 EGLint api_index
= _eglConvertApiToIndex(api
);
254 return egl_g3d_context(t
->CurrentContexts
[api_index
]);
258 * Return the state tracker for the given context.
260 static const struct egl_g3d_st
*
261 egl_g3d_choose_st(_EGLDriver
*drv
, _EGLContext
*ctx
)
263 struct egl_g3d_driver
*gdrv
= egl_g3d_driver(drv
);
264 const struct egl_g3d_st
*stapi
;
267 switch (ctx
->ClientAPI
) {
268 case EGL_OPENGL_ES_API
:
269 switch (ctx
->ClientVersion
) {
271 idx
= EGL_G3D_ST_OPENGL_ES
;
274 idx
= EGL_G3D_ST_OPENGL_ES2
;
277 _eglLog(_EGL_WARNING
, "unknown client version %d",
283 idx
= EGL_G3D_ST_OPENVG
;
286 idx
= EGL_G3D_ST_OPENGL
;
289 _eglLog(_EGL_WARNING
, "unknown client API 0x%04x", ctx
->ClientAPI
);
293 stapi
= (idx
>= 0) ? gdrv
->stapis
[idx
] : NULL
;
298 * Initialize the state trackers.
301 egl_g3d_init_st(_EGLDriver
*drv
)
303 struct egl_g3d_driver
*gdrv
= egl_g3d_driver(drv
);
306 /* already initialized */
310 for (i
= 0; i
< NUM_EGL_G3D_STS
; i
++) {
311 gdrv
->stapis
[i
] = egl_g3d_get_st(i
);
313 gdrv
->api_mask
|= gdrv
->stapis
[i
]->api_bit
;
317 _eglLog(_EGL_DEBUG
, "Driver API mask: 0x%x", gdrv
->api_mask
);
319 _eglLog(_EGL_WARNING
, "No supported client API");
323 * Get the probe object of the display.
325 * Note that this function may be called before the display is initialized.
327 static struct native_probe
*
328 egl_g3d_get_probe(_EGLDriver
*drv
, _EGLDisplay
*dpy
)
330 struct egl_g3d_driver
*gdrv
= egl_g3d_driver(drv
);
331 struct native_probe
*nprobe
;
333 nprobe
= (struct native_probe
*) _eglGetProbeCache(gdrv
->probe_key
);
334 if (!nprobe
|| nprobe
->display
!= dpy
->NativeDisplay
) {
336 nprobe
->destroy(nprobe
);
337 nprobe
= native_create_probe(dpy
->NativeDisplay
);
338 _eglSetProbeCache(gdrv
->probe_key
, (void *) nprobe
);
345 * Destroy the probe object of the display. The display may be NULL.
347 * Note that this function may be called before the display is initialized.
350 egl_g3d_destroy_probe(_EGLDriver
*drv
, _EGLDisplay
*dpy
)
352 struct egl_g3d_driver
*gdrv
= egl_g3d_driver(drv
);
353 struct native_probe
*nprobe
;
355 nprobe
= (struct native_probe
*) _eglGetProbeCache(gdrv
->probe_key
);
356 if (nprobe
&& (!dpy
|| nprobe
->display
== dpy
->NativeDisplay
)) {
357 nprobe
->destroy(nprobe
);
358 _eglSetProbeCache(gdrv
->probe_key
, NULL
);
363 * Return an API mask that consists of the state trackers that supports the
366 * FIXME add st_is_mode_supported()?
369 get_mode_api_mask(const __GLcontextModes
*mode
, EGLint api_mask
)
373 /* OpenGL ES 1.x and 2.x are checked together */
374 check
= EGL_OPENGL_ES_BIT
| EGL_OPENGL_ES2_BIT
;
375 if (api_mask
& check
) {
376 /* this is required by EGL, not by OpenGL ES */
377 if (mode
->drawableType
& GLX_WINDOW_BIT
&& !mode
->doubleBufferMode
)
381 check
= EGL_OPENVG_BIT
;
382 if (api_mask
& check
) {
383 /* vega st needs the depth/stencil rb */
384 if (!mode
->depthBits
&& !mode
->stencilBits
)
391 #ifdef EGL_MESA_screen_surface
394 egl_g3d_add_screens(_EGLDriver
*drv
, _EGLDisplay
*dpy
)
396 struct egl_g3d_display
*gdpy
= egl_g3d_display(dpy
);
397 const struct native_connector
**native_connectors
;
398 EGLint num_connectors
, i
;
401 gdpy
->native
->modeset
->get_connectors(gdpy
->native
, &num_connectors
, NULL
);
402 if (!num_connectors
) {
403 if (native_connectors
)
404 free(native_connectors
);
408 for (i
= 0; i
< num_connectors
; i
++) {
409 const struct native_connector
*nconn
= native_connectors
[i
];
410 struct egl_g3d_screen
*gscr
;
411 const struct native_mode
**native_modes
;
414 /* TODO support for hotplug */
416 gdpy
->native
->modeset
->get_modes(gdpy
->native
, nconn
, &num_modes
);
423 gscr
= CALLOC_STRUCT(egl_g3d_screen
);
429 _eglInitScreen(&gscr
->base
);
431 for (j
= 0; j
< num_modes
; j
++) {
432 const struct native_mode
*nmode
= native_modes
[j
];
435 mode
= _eglAddNewMode(&gscr
->base
, nmode
->width
, nmode
->height
,
436 nmode
->refresh_rate
, nmode
->desc
);
439 /* gscr->native_modes and gscr->base.Modes should be consistent */
440 assert(mode
== &gscr
->base
.Modes
[j
]);
443 gscr
->native
= nconn
;
444 gscr
->native_modes
= native_modes
;
446 _eglAddScreen(dpy
, &gscr
->base
);
449 free(native_connectors
);
452 #endif /* EGL_MESA_screen_surface */
455 * Add configs to display and return the next config ID.
458 egl_g3d_add_configs(_EGLDriver
*drv
, _EGLDisplay
*dpy
, EGLint id
)
460 struct egl_g3d_driver
*gdrv
= egl_g3d_driver(drv
);
461 struct egl_g3d_display
*gdpy
= egl_g3d_display(dpy
);
462 const struct native_config
**native_configs
;
465 native_configs
= gdpy
->native
->get_configs(gdpy
->native
,
469 free(native_configs
);
473 for (i
= 0; i
< num_configs
; i
++) {
475 struct egl_g3d_config
*gconf
;
478 api_mask
= get_mode_api_mask(&native_configs
[i
]->mode
, gdrv
->api_mask
);
480 _eglLog(_EGL_DEBUG
, "no state tracker supports config 0x%x",
481 native_configs
[i
]->mode
.visualID
);
485 gconf
= CALLOC_STRUCT(egl_g3d_config
);
489 _eglInitConfig(&gconf
->base
, id
);
490 valid
= _eglConfigFromContextModesRec(&gconf
->base
,
491 &native_configs
[i
]->mode
, api_mask
, api_mask
);
493 #ifdef EGL_MESA_screen_surface
494 /* check if scanout surface bit is set */
495 if (native_configs
[i
]->scanout_bit
) {
496 EGLint val
= GET_CONFIG_ATTRIB(&gconf
->base
, EGL_SURFACE_TYPE
);
497 val
|= EGL_SCREEN_BIT_MESA
;
498 SET_CONFIG_ATTRIB(&gconf
->base
, EGL_SURFACE_TYPE
, val
);
501 valid
= _eglValidateConfig(&gconf
->base
, EGL_FALSE
);
504 _eglLog(_EGL_DEBUG
, "skip invalid config 0x%x",
505 native_configs
[i
]->mode
.visualID
);
510 gconf
->native
= native_configs
[i
];
511 _eglAddConfig(dpy
, &gconf
->base
);
515 free(native_configs
);
520 * Flush the front buffer of the context's draw surface.
523 egl_g3d_flush_frontbuffer(struct pipe_screen
*screen
,
524 struct pipe_surface
*surf
, void *context_private
)
526 struct egl_g3d_context
*gctx
= egl_g3d_context(context_private
);
527 struct egl_g3d_surface
*gsurf
= egl_g3d_surface(gctx
->base
.DrawSurface
);
530 gsurf
->native
->flush_frontbuffer(gsurf
->native
);
534 * Re-validate the context.
537 egl_g3d_update_buffer(struct pipe_screen
*screen
, void *context_private
)
539 struct egl_g3d_context
*gctx
= egl_g3d_context(context_private
);
542 * It is likely that the surface has changed when this function is called.
543 * Set force_validate to skip an unnecessary check.
545 gctx
->force_validate
= EGL_TRUE
;
546 egl_g3d_validate_context(gctx
->base
.Display
, &gctx
->base
);
550 egl_g3d_terminate(_EGLDriver
*drv
, _EGLDisplay
*dpy
)
552 struct egl_g3d_display
*gdpy
= egl_g3d_display(dpy
);
555 _eglReleaseDisplayResources(drv
, dpy
);
556 _eglCleanupDisplay(dpy
);
559 for (i
= 0; i
< dpy
->NumScreens
; i
++) {
560 struct egl_g3d_screen
*gscr
= egl_g3d_screen(dpy
->Screens
[i
]);
561 free(gscr
->native_modes
);
568 gdpy
->native
->destroy(gdpy
->native
);
571 dpy
->DriverData
= NULL
;
577 egl_g3d_initialize(_EGLDriver
*drv
, _EGLDisplay
*dpy
,
578 EGLint
*major
, EGLint
*minor
)
580 struct egl_g3d_driver
*gdrv
= egl_g3d_driver(drv
);
581 struct egl_g3d_display
*gdpy
;
583 /* the probe object is unlikely to be needed again */
584 egl_g3d_destroy_probe(drv
, dpy
);
586 gdpy
= CALLOC_STRUCT(egl_g3d_display
);
588 _eglError(EGL_BAD_ALLOC
, "eglInitialize");
591 dpy
->DriverData
= gdpy
;
593 gdpy
->native
= native_create_display(dpy
->NativeDisplay
);
595 _eglError(EGL_NOT_INITIALIZED
, "eglInitialize(no usable display)");
599 gdpy
->native
->screen
->flush_frontbuffer
= egl_g3d_flush_frontbuffer
;
600 gdpy
->native
->screen
->update_buffer
= egl_g3d_update_buffer
;
602 egl_g3d_init_st(&gdrv
->base
);
603 dpy
->ClientAPIsMask
= gdrv
->api_mask
;
605 if (egl_g3d_add_configs(drv
, dpy
, 1) == 1) {
606 _eglError(EGL_NOT_INITIALIZED
, "eglInitialize(unable to add configs)");
610 #ifdef EGL_MESA_screen_surface
611 /* enable MESA_screen_surface */
612 if (gdpy
->native
->modeset
) {
613 dpy
->Extensions
.MESA_screen_surface
= EGL_TRUE
;
614 egl_g3d_add_screens(drv
, dpy
);
625 egl_g3d_terminate(drv
, dpy
);
630 egl_g3d_create_context(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLConfig
*conf
,
631 _EGLContext
*share
, const EGLint
*attribs
)
633 struct egl_g3d_display
*gdpy
= egl_g3d_display(dpy
);
634 struct egl_g3d_context
*gshare
= egl_g3d_context(share
);
635 struct egl_g3d_config
*gconf
= egl_g3d_config(conf
);
636 struct egl_g3d_context
*gctx
;
637 const __GLcontextModes
*mode
;
639 gctx
= CALLOC_STRUCT(egl_g3d_context
);
641 _eglError(EGL_BAD_ALLOC
, "eglCreateContext");
645 if (!_eglInitContext(drv
, &gctx
->base
, conf
, attribs
)) {
650 gctx
->stapi
= egl_g3d_choose_st(drv
, &gctx
->base
);
656 mode
= &gconf
->native
->mode
;
658 gdpy
->native
->create_context(gdpy
->native
, (void *) &gctx
->base
);
664 gctx
->st_ctx
= gctx
->stapi
->st_create_context(gctx
->pipe
, mode
,
665 (gshare
) ? gshare
->st_ctx
: NULL
);
667 gctx
->pipe
->destroy(gctx
->pipe
);
676 egl_g3d_destroy_context(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLContext
*ctx
)
678 struct egl_g3d_context
*gctx
= egl_g3d_context(ctx
);
680 if (_eglIsContextBound(&gctx
->base
))
683 egl_g3d_realloc_context(dpy
, &gctx
->base
);
685 /* it will destroy pipe context */
686 gctx
->stapi
->st_destroy_context(gctx
->st_ctx
);
694 init_surface_geometry(_EGLSurface
*surf
)
696 struct egl_g3d_surface
*gsurf
= egl_g3d_surface(surf
);
698 return gsurf
->native
->validate(gsurf
->native
, 0x0,
699 &gsurf
->sequence_number
, NULL
,
700 &gsurf
->base
.Width
, &gsurf
->base
.Height
);
704 egl_g3d_create_window_surface(_EGLDriver
*drv
, _EGLDisplay
*dpy
,
705 _EGLConfig
*conf
, EGLNativeWindowType win
,
706 const EGLint
*attribs
)
708 struct egl_g3d_display
*gdpy
= egl_g3d_display(dpy
);
709 struct egl_g3d_config
*gconf
= egl_g3d_config(conf
);
710 struct egl_g3d_surface
*gsurf
;
712 gsurf
= CALLOC_STRUCT(egl_g3d_surface
);
714 _eglError(EGL_BAD_ALLOC
, "eglCreateWindowSurface");
718 if (!_eglInitSurface(drv
, &gsurf
->base
, EGL_WINDOW_BIT
, conf
, attribs
)) {
724 gdpy
->native
->create_window_surface(gdpy
->native
, win
, gconf
->native
);
725 if (!gsurf
->native
) {
730 if (!init_surface_geometry(&gsurf
->base
)) {
731 gsurf
->native
->destroy(gsurf
->native
);
736 gsurf
->render_att
= (gsurf
->base
.RenderBuffer
== EGL_SINGLE_BUFFER
||
737 !gconf
->native
->mode
.doubleBufferMode
) ?
738 NATIVE_ATTACHMENT_FRONT_LEFT
: NATIVE_ATTACHMENT_BACK_LEFT
;
744 egl_g3d_create_pixmap_surface(_EGLDriver
*drv
, _EGLDisplay
*dpy
,
745 _EGLConfig
*conf
, EGLNativePixmapType pix
,
746 const EGLint
*attribs
)
748 struct egl_g3d_display
*gdpy
= egl_g3d_display(dpy
);
749 struct egl_g3d_config
*gconf
= egl_g3d_config(conf
);
750 struct egl_g3d_surface
*gsurf
;
752 gsurf
= CALLOC_STRUCT(egl_g3d_surface
);
754 _eglError(EGL_BAD_ALLOC
, "eglCreatePixmapSurface");
758 if (!_eglInitSurface(drv
, &gsurf
->base
, EGL_PIXMAP_BIT
, conf
, attribs
)) {
764 gdpy
->native
->create_pixmap_surface(gdpy
->native
, pix
, gconf
->native
);
765 if (!gsurf
->native
) {
770 if (!init_surface_geometry(&gsurf
->base
)) {
771 gsurf
->native
->destroy(gsurf
->native
);
776 gsurf
->render_att
= NATIVE_ATTACHMENT_FRONT_LEFT
;
782 egl_g3d_create_pbuffer_surface(_EGLDriver
*drv
, _EGLDisplay
*dpy
,
783 _EGLConfig
*conf
, const EGLint
*attribs
)
785 struct egl_g3d_display
*gdpy
= egl_g3d_display(dpy
);
786 struct egl_g3d_config
*gconf
= egl_g3d_config(conf
);
787 struct egl_g3d_surface
*gsurf
;
789 gsurf
= CALLOC_STRUCT(egl_g3d_surface
);
791 _eglError(EGL_BAD_ALLOC
, "eglCreatePbufferSurface");
795 if (!_eglInitSurface(drv
, &gsurf
->base
, EGL_PBUFFER_BIT
, conf
, attribs
)) {
801 gdpy
->native
->create_pbuffer_surface(gdpy
->native
, gconf
->native
,
802 gsurf
->base
.Width
, gsurf
->base
.Height
);
803 if (!gsurf
->native
) {
808 if (!init_surface_geometry(&gsurf
->base
)) {
809 gsurf
->native
->destroy(gsurf
->native
);
814 gsurf
->render_att
= (!gconf
->native
->mode
.doubleBufferMode
) ?
815 NATIVE_ATTACHMENT_FRONT_LEFT
: NATIVE_ATTACHMENT_BACK_LEFT
;
821 egl_g3d_destroy_surface(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*surf
)
823 struct egl_g3d_surface
*gsurf
= egl_g3d_surface(surf
);
825 if (_eglIsSurfaceBound(&gsurf
->base
))
828 pipe_surface_reference(&gsurf
->render_surface
, NULL
);
829 gsurf
->native
->destroy(gsurf
->native
);
835 egl_g3d_make_current(_EGLDriver
*drv
, _EGLDisplay
*dpy
,
836 _EGLSurface
*draw
, _EGLSurface
*read
, _EGLContext
*ctx
)
838 struct egl_g3d_context
*gctx
= egl_g3d_context(ctx
);
839 struct egl_g3d_context
*old_gctx
;
841 EGLBoolean ok
= EGL_TRUE
;
843 /* find the old context */
844 api
= (gctx
) ? gctx
->base
.ClientAPI
: eglQueryAPI();
845 old_gctx
= egl_g3d_get_current_context(api
);
846 if (old_gctx
&& !_eglIsContextLinked(&old_gctx
->base
))
849 if (!_eglMakeCurrent(drv
, dpy
, draw
, read
, ctx
))
853 /* flush old context */
854 old_gctx
->stapi
->st_flush(old_gctx
->st_ctx
,
855 PIPE_FLUSH_RENDER_CACHE
| PIPE_FLUSH_FRAME
, NULL
);
858 * The old context is no longer current, and egl_g3d_realloc_context()
859 * should be called to destroy the framebuffers. However, it is possible
860 * that it will be made current again with the same draw/read surfaces.
861 * It might be better to keep it around.
866 struct egl_g3d_surface
*gdraw
= egl_g3d_surface(draw
);
868 ok
= egl_g3d_realloc_context(dpy
, &gctx
->base
);
870 ok
= gctx
->stapi
->st_make_current(gctx
->st_ctx
,
871 gctx
->draw
.st_fb
, gctx
->read
.st_fb
);
873 egl_g3d_validate_context(dpy
, &gctx
->base
);
874 if (gdraw
->base
.Type
== EGL_WINDOW_BIT
) {
875 gctx
->base
.WindowRenderBuffer
=
876 (gdraw
->render_att
== NATIVE_ATTACHMENT_FRONT_LEFT
) ?
877 EGL_SINGLE_BUFFER
: EGL_BACK_BUFFER
;
883 ok
= old_gctx
->stapi
->st_make_current(NULL
, NULL
, NULL
);
884 old_gctx
->base
.WindowRenderBuffer
= EGL_NONE
;
891 egl_g3d_swap_buffers(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*surf
)
893 struct egl_g3d_surface
*gsurf
= egl_g3d_surface(surf
);
894 _EGLContext
*ctx
= _eglGetCurrentContext();
895 struct egl_g3d_context
*gctx
= NULL
;
897 /* no-op for pixmap or pbuffer surface */
898 if (gsurf
->base
.Type
== EGL_PIXMAP_BIT
||
899 gsurf
->base
.Type
== EGL_PBUFFER_BIT
)
902 /* or when the surface is single-buffered */
903 if (gsurf
->render_att
== NATIVE_ATTACHMENT_FRONT_LEFT
)
906 if (ctx
&& ctx
->DrawSurface
== surf
)
907 gctx
= egl_g3d_context(ctx
);
909 /* flush if the surface is current */
911 gctx
->stapi
->st_notify_swapbuffers(gctx
->draw
.st_fb
);
914 * We drew on the back buffer, unless there was no back buffer.
915 * In that case, we drew on the front buffer. Either case, we call
918 if (!gsurf
->native
->swap_buffers(gsurf
->native
))
922 struct egl_g3d_config
*gconf
= egl_g3d_config(gsurf
->base
.Config
);
924 /* force validation if the swap method is not copy */
925 if (gconf
->native
->mode
.swapMethod
!= GLX_SWAP_COPY_OML
) {
926 gctx
->force_validate
= EGL_TRUE
;
927 egl_g3d_validate_context(dpy
, &gctx
->base
);
935 * Find a config that supports the pixmap.
938 find_pixmap_config(_EGLDisplay
*dpy
, EGLNativePixmapType pix
)
940 struct egl_g3d_display
*gdpy
= egl_g3d_display(dpy
);
941 struct egl_g3d_config
*gconf
;
944 for (i
= 0; i
< dpy
->NumConfigs
; i
++) {
945 gconf
= egl_g3d_config(dpy
->Configs
[i
]);
946 if (gdpy
->native
->is_pixmap_supported(gdpy
->native
, pix
, gconf
->native
))
950 return (i
< dpy
->NumConfigs
) ? &gconf
->base
: NULL
;
954 * Get the pipe surface of the given attachment of the native surface.
956 static struct pipe_surface
*
957 get_pipe_surface(struct native_display
*ndpy
, struct native_surface
*nsurf
,
958 enum native_attachment natt
)
960 struct pipe_texture
*textures
[NUM_NATIVE_ATTACHMENTS
];
961 struct pipe_surface
*psurf
;
963 textures
[natt
] = NULL
;
964 nsurf
->validate(nsurf
, 1 << natt
, NULL
, textures
, NULL
, NULL
);
968 psurf
= ndpy
->screen
->get_tex_surface(ndpy
->screen
, textures
[natt
],
969 0, 0, 0, PIPE_BUFFER_USAGE_CPU_WRITE
);
970 pipe_texture_reference(&textures
[natt
], NULL
);
976 egl_g3d_copy_buffers(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*surf
,
977 NativePixmapType target
)
979 struct egl_g3d_display
*gdpy
= egl_g3d_display(dpy
);
980 struct egl_g3d_surface
*gsurf
= egl_g3d_surface(surf
);
981 _EGLContext
*ctx
= _eglGetCurrentContext();
982 struct egl_g3d_config
*gconf
;
983 struct native_surface
*nsurf
;
984 struct pipe_screen
*screen
= gdpy
->native
->screen
;
985 struct pipe_surface
*psurf
;
987 if (!gsurf
->render_surface
)
990 gconf
= egl_g3d_config(find_pixmap_config(dpy
, target
));
992 return _eglError(EGL_BAD_NATIVE_PIXMAP
, "eglCopyBuffers");
994 nsurf
= gdpy
->native
->create_pixmap_surface(gdpy
->native
,
995 target
, gconf
->native
);
997 return _eglError(EGL_BAD_NATIVE_PIXMAP
, "eglCopyBuffers");
999 /* flush if the surface is current */
1000 if (ctx
&& ctx
->DrawSurface
== &gsurf
->base
) {
1001 struct egl_g3d_context
*gctx
= egl_g3d_context(ctx
);
1002 gctx
->stapi
->st_flush(gctx
->st_ctx
,
1003 PIPE_FLUSH_RENDER_CACHE
| PIPE_FLUSH_FRAME
, NULL
);
1006 psurf
= get_pipe_surface(gdpy
->native
, nsurf
, NATIVE_ATTACHMENT_FRONT_LEFT
);
1008 struct pipe_context pipe
;
1011 * XXX This is hacky. If we might allow the EGLDisplay to create a pipe
1012 * context of its own and use the blitter context for this.
1014 memset(&pipe
, 0, sizeof(pipe
));
1015 pipe
.screen
= screen
;
1017 util_surface_copy(&pipe
, FALSE
, psurf
, 0, 0,
1018 gsurf
->render_surface
, 0, 0, psurf
->width
, psurf
->height
);
1020 pipe_surface_reference(&psurf
, NULL
);
1021 nsurf
->flush_frontbuffer(nsurf
);
1024 nsurf
->destroy(nsurf
);
1030 egl_g3d_wait_client(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLContext
*ctx
)
1032 struct egl_g3d_context
*gctx
= egl_g3d_context(ctx
);
1033 gctx
->stapi
->st_finish(gctx
->st_ctx
);
1038 egl_g3d_wait_native(_EGLDriver
*drv
, _EGLDisplay
*dpy
, EGLint engine
)
1040 _EGLSurface
*surf
= _eglGetCurrentSurface(EGL_DRAW
);
1041 struct egl_g3d_surface
*gsurf
= egl_g3d_surface(surf
);
1043 if (engine
!= EGL_CORE_NATIVE_ENGINE
)
1044 return _eglError(EGL_BAD_PARAMETER
, "eglWaitNative");
1047 gsurf
->native
->wait(gsurf
->native
);
1053 egl_g3d_get_proc_address(_EGLDriver
*drv
, const char *procname
)
1055 struct egl_g3d_driver
*gdrv
= egl_g3d_driver(drv
);
1059 /* in case this is called before a display is initialized */
1060 egl_g3d_init_st(&gdrv
->base
);
1062 for (i
= 0; i
< NUM_EGL_G3D_STS
; i
++) {
1063 const struct egl_g3d_st
*stapi
= gdrv
->stapis
[i
];
1065 proc
= (_EGLProc
) stapi
->st_get_proc_address(procname
);
1071 return (_EGLProc
) NULL
;
1075 egl_g3d_bind_tex_image(_EGLDriver
*drv
, _EGLDisplay
*dpy
,
1076 _EGLSurface
*surf
, EGLint buffer
)
1078 struct egl_g3d_surface
*gsurf
= egl_g3d_surface(surf
);
1079 struct egl_g3d_context
*gctx
;
1080 enum pipe_format target_format
;
1083 if (!gsurf
|| gsurf
->base
.Type
!= EGL_PBUFFER_BIT
)
1084 return _eglError(EGL_BAD_SURFACE
, "eglBindTexImage");
1085 if (buffer
!= EGL_BACK_BUFFER
)
1086 return _eglError(EGL_BAD_PARAMETER
, "eglBindTexImage");
1087 if (gsurf
->base
.BoundToTexture
)
1088 return _eglError(EGL_BAD_ACCESS
, "eglBindTexImage");
1090 switch (gsurf
->base
.TextureFormat
) {
1091 case EGL_TEXTURE_RGB
:
1092 target_format
= PIPE_FORMAT_R8G8B8_UNORM
;
1094 case EGL_TEXTURE_RGBA
:
1095 target_format
= PIPE_FORMAT_A8R8G8B8_UNORM
;
1098 return _eglError(EGL_BAD_MATCH
, "eglBindTexImage");
1101 switch (gsurf
->base
.TextureTarget
) {
1102 case EGL_TEXTURE_2D
:
1103 target
= ST_TEXTURE_2D
;
1106 return _eglError(EGL_BAD_MATCH
, "eglBindTexImage");
1109 /* flush properly if the surface is bound */
1110 if (gsurf
->base
.Binding
) {
1111 gctx
= egl_g3d_context(gsurf
->base
.Binding
);
1112 gctx
->stapi
->st_flush(gctx
->st_ctx
,
1113 PIPE_FLUSH_RENDER_CACHE
| PIPE_FLUSH_FRAME
, NULL
);
1116 /* XXX change to EGL_OPENGL_ES_API once OpenGL ES is merged */
1117 gctx
= egl_g3d_get_current_context(EGL_OPENGL_API
);
1119 if (!gsurf
->render_surface
)
1122 gctx
->stapi
->st_bind_texture_surface(gsurf
->render_surface
,
1123 target
, gsurf
->base
.MipmapLevel
, target_format
);
1124 gsurf
->base
.BoundToTexture
= EGL_TRUE
;
1131 egl_g3d_release_tex_image(_EGLDriver
*drv
, _EGLDisplay
*dpy
,
1132 _EGLSurface
*surf
, EGLint buffer
)
1134 struct egl_g3d_surface
*gsurf
= egl_g3d_surface(surf
);
1136 if (!gsurf
|| gsurf
->base
.Type
!= EGL_PBUFFER_BIT
||
1137 !gsurf
->base
.BoundToTexture
)
1138 return _eglError(EGL_BAD_SURFACE
, "eglReleaseTexImage");
1139 if (buffer
!= EGL_BACK_BUFFER
)
1140 return _eglError(EGL_BAD_PARAMETER
, "eglReleaseTexImage");
1142 if (gsurf
->render_surface
) {
1143 _EGLThreadInfo
*t
= _eglGetCurrentThread();
1144 /* XXX change to EGL_OPENGL_ES_API once OpenGL ES is merged */
1145 struct egl_g3d_context
*gctx
= egl_g3d_context(
1146 t
->CurrentContexts
[_eglConvertApiToIndex(EGL_OPENGL_API
)]);
1148 /* what if the context the surface binds to is no longer current? */
1150 gctx
->stapi
->st_unbind_texture_surface(gsurf
->render_surface
,
1151 ST_TEXTURE_2D
, gsurf
->base
.MipmapLevel
);
1154 gsurf
->base
.BoundToTexture
= EGL_FALSE
;
1159 #ifdef EGL_MESA_screen_surface
1161 static _EGLSurface
*
1162 egl_g3d_create_screen_surface(_EGLDriver
*drv
, _EGLDisplay
*dpy
,
1163 _EGLConfig
*conf
, const EGLint
*attribs
)
1165 struct egl_g3d_display
*gdpy
= egl_g3d_display(dpy
);
1166 struct egl_g3d_config
*gconf
= egl_g3d_config(conf
);
1167 struct egl_g3d_surface
*gsurf
;
1169 gsurf
= CALLOC_STRUCT(egl_g3d_surface
);
1171 _eglError(EGL_BAD_ALLOC
, "eglCreatePbufferSurface");
1175 if (!_eglInitSurface(drv
, &gsurf
->base
,
1176 EGL_SCREEN_BIT_MESA
, conf
, attribs
)) {
1182 gdpy
->native
->modeset
->create_scanout_surface(gdpy
->native
,
1183 gconf
->native
, gsurf
->base
.Width
, gsurf
->base
.Height
);
1184 if (!gsurf
->native
) {
1189 gsurf
->render_att
= (!gconf
->native
->mode
.doubleBufferMode
) ?
1190 NATIVE_ATTACHMENT_FRONT_LEFT
: NATIVE_ATTACHMENT_BACK_LEFT
;
1192 return &gsurf
->base
;
1196 egl_g3d_show_screen_surface(_EGLDriver
*drv
, _EGLDisplay
*dpy
,
1197 _EGLScreen
*scr
, _EGLSurface
*surf
,
1200 struct egl_g3d_display
*gdpy
= egl_g3d_display(dpy
);
1201 struct egl_g3d_screen
*gscr
= egl_g3d_screen(scr
);
1202 struct egl_g3d_surface
*gsurf
= egl_g3d_surface(surf
);
1203 struct native_surface
*nsurf
;
1204 const struct native_mode
*nmode
;
1211 return _eglError(EGL_BAD_MATCH
, "eglShowSurfaceMESA");
1212 if (gsurf
->base
.Type
!= EGL_SCREEN_BIT_MESA
)
1213 return _eglError(EGL_BAD_SURFACE
, "eglShowScreenSurfaceMESA");
1214 if (gsurf
->base
.Width
< mode
->Width
|| gsurf
->base
.Height
< mode
->Height
)
1215 return _eglError(EGL_BAD_MATCH
,
1216 "eglShowSurfaceMESA(surface smaller than mode size)");
1218 /* find the index of the mode */
1219 for (idx
= 0; idx
< gscr
->base
.NumModes
; idx
++)
1220 if (mode
== &gscr
->base
.Modes
[idx
])
1222 if (idx
>= gscr
->base
.NumModes
) {
1223 return _eglError(EGL_BAD_MODE_MESA
,
1224 "eglShowSurfaceMESA(unknown mode)");
1227 nsurf
= gsurf
->native
;
1228 nmode
= gscr
->native_modes
[idx
];
1232 return _eglError(EGL_BAD_MATCH
, "eglShowSurfaceMESA");
1234 /* disable the screen */
1239 /* TODO surface panning by CRTC choosing */
1240 changed
= gdpy
->native
->modeset
->program(gdpy
->native
, 0, nsurf
,
1241 gscr
->base
.OriginX
, gscr
->base
.OriginY
, &gscr
->native
, 1, nmode
);
1243 gscr
->base
.CurrentSurface
= &gsurf
->base
;
1244 gscr
->base
.CurrentMode
= mode
;
1250 #endif /* EGL_MESA_screen_surface */
1253 egl_g3d_probe(_EGLDriver
*drv
, _EGLDisplay
*dpy
)
1255 struct native_probe
*nprobe
;
1256 enum native_probe_result res
;
1259 nprobe
= egl_g3d_get_probe(drv
, dpy
);
1260 res
= native_get_probe_result(nprobe
);
1263 case NATIVE_PROBE_UNKNOWN
:
1267 case NATIVE_PROBE_FALLBACK
:
1270 case NATIVE_PROBE_SUPPORTED
:
1273 case NATIVE_PROBE_EXACT
:
1282 egl_g3d_unload(_EGLDriver
*drv
)
1284 struct egl_g3d_driver
*gdrv
= egl_g3d_driver(drv
);
1286 egl_g3d_destroy_probe(drv
, NULL
);
1291 _eglMain(const char *args
)
1293 static char driver_name
[64];
1294 struct egl_g3d_driver
*gdrv
;
1296 snprintf(driver_name
, sizeof(driver_name
),
1297 "Gallium/%s", native_get_name());
1299 gdrv
= CALLOC_STRUCT(egl_g3d_driver
);
1303 _eglInitDriverFallbacks(&gdrv
->base
);
1305 gdrv
->base
.API
.Initialize
= egl_g3d_initialize
;
1306 gdrv
->base
.API
.Terminate
= egl_g3d_terminate
;
1307 gdrv
->base
.API
.CreateContext
= egl_g3d_create_context
;
1308 gdrv
->base
.API
.DestroyContext
= egl_g3d_destroy_context
;
1309 gdrv
->base
.API
.CreateWindowSurface
= egl_g3d_create_window_surface
;
1310 gdrv
->base
.API
.CreatePixmapSurface
= egl_g3d_create_pixmap_surface
;
1311 gdrv
->base
.API
.CreatePbufferSurface
= egl_g3d_create_pbuffer_surface
;
1312 gdrv
->base
.API
.DestroySurface
= egl_g3d_destroy_surface
;
1313 gdrv
->base
.API
.MakeCurrent
= egl_g3d_make_current
;
1314 gdrv
->base
.API
.SwapBuffers
= egl_g3d_swap_buffers
;
1315 gdrv
->base
.API
.CopyBuffers
= egl_g3d_copy_buffers
;
1316 gdrv
->base
.API
.WaitClient
= egl_g3d_wait_client
;
1317 gdrv
->base
.API
.WaitNative
= egl_g3d_wait_native
;
1318 gdrv
->base
.API
.GetProcAddress
= egl_g3d_get_proc_address
;
1320 gdrv
->base
.API
.BindTexImage
= egl_g3d_bind_tex_image
;
1321 gdrv
->base
.API
.ReleaseTexImage
= egl_g3d_release_tex_image
;
1323 #ifdef EGL_MESA_screen_surface
1324 gdrv
->base
.API
.CreateScreenSurfaceMESA
= egl_g3d_create_screen_surface
;
1325 gdrv
->base
.API
.ShowScreenSurfaceMESA
= egl_g3d_show_screen_surface
;
1328 gdrv
->base
.Name
= driver_name
;
1329 gdrv
->base
.Probe
= egl_g3d_probe
;
1330 gdrv
->base
.Unload
= egl_g3d_unload
;
1332 /* the key is " EGL G3D" */
1333 gdrv
->probe_key
= 0x0E61063D;