X-Git-Url: https://git.libre-soc.org/?p=mesa.git;a=blobdiff_plain;f=src%2Fgallium%2Fstate_trackers%2Fegl%2Fcommon%2Fegl_g3d.c;h=3ab72dce2f3c126d3432208e99e276c468c33db7;hp=6c8f3b9f79cd5c30dc3868f2acb5efa93e3b467e;hb=1318848f782cce716d6376ca13aebf68b728e24c;hpb=bee9964b29b2428ee75e2d1efc0e1d2c2518a417 diff --git a/src/gallium/state_trackers/egl/common/egl_g3d.c b/src/gallium/state_trackers/egl/common/egl_g3d.c index 6c8f3b9f79c..3ab72dce2f3 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d.c @@ -14,274 +14,28 @@ * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ -#include -#include -#include "pipe/p_screen.h" -#include "util/u_memory.h" -#include "util/u_rect.h" #include "egldriver.h" #include "eglcurrent.h" -#include "eglconfigutil.h" #include "egllog.h" -#include "native.h" -#include "egl_g3d.h" -#include "egl_st.h" - -/** - * Validate the draw/read surfaces of the context. - */ -static void -egl_g3d_validate_context(_EGLDisplay *dpy, _EGLContext *ctx) -{ - struct egl_g3d_display *gdpy = egl_g3d_display(dpy); - struct pipe_screen *screen = gdpy->native->screen; - struct egl_g3d_context *gctx = egl_g3d_context(ctx); - const uint st_att_map[NUM_NATIVE_ATTACHMENTS] = { - ST_SURFACE_FRONT_LEFT, - ST_SURFACE_BACK_LEFT, - ST_SURFACE_FRONT_RIGHT, - ST_SURFACE_BACK_RIGHT, - }; - EGLint num_surfaces, s; - - /* validate draw and/or read buffers */ - num_surfaces = (gctx->base.ReadSurface == gctx->base.DrawSurface) ? 1 : 2; - for (s = 0; s < num_surfaces; s++) { - struct pipe_texture *textures[NUM_NATIVE_ATTACHMENTS]; - struct egl_g3d_surface *gsurf; - struct egl_g3d_buffer *gbuf; - EGLint att; - - if (s == 0) { - gsurf = egl_g3d_surface(gctx->base.DrawSurface); - gbuf = &gctx->draw; - } - else { - gsurf = egl_g3d_surface(gctx->base.ReadSurface); - gbuf = &gctx->read; - } - - if (!gctx->force_validate) { - unsigned int seq_num; - - gsurf->native->validate(gsurf->native, gbuf->attachment_mask, - &seq_num, NULL, NULL, NULL); - /* skip validation */ - if (gsurf->sequence_number == seq_num) - continue; - } - - pipe_surface_reference(&gsurf->render_surface, NULL); - memset(textures, 0, sizeof(textures)); - - gsurf->native->validate(gsurf->native, gbuf->attachment_mask, - &gsurf->sequence_number, textures, - &gsurf->base.Width, &gsurf->base.Height); - for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { - struct pipe_texture *pt = textures[att]; - struct pipe_surface *ps; - - if (native_attachment_mask_test(gbuf->attachment_mask, att) && pt) { - ps = screen->get_tex_surface(screen, pt, 0, 0, 0, - PIPE_BUFFER_USAGE_GPU_READ | - PIPE_BUFFER_USAGE_GPU_WRITE); - gctx->stapi->st_set_framebuffer_surface(gbuf->st_fb, - st_att_map[att], ps); - - if (gsurf->render_att == att) - pipe_surface_reference(&gsurf->render_surface, ps); - - pipe_surface_reference(&ps, NULL); - pipe_texture_reference(&pt, NULL); - } - } - - gctx->stapi->st_resize_framebuffer(gbuf->st_fb, - gsurf->base.Width, gsurf->base.Height); - } - - gctx->force_validate = EGL_FALSE; - -} - -/** - * Create a st_framebuffer. - */ -static struct st_framebuffer * -create_framebuffer(_EGLContext *ctx, _EGLSurface *surf) -{ - struct egl_g3d_context *gctx = egl_g3d_context(ctx); - struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); - struct egl_g3d_config *gconf = egl_g3d_config(gsurf->base.Config); - - return gctx->stapi->st_create_framebuffer(&gconf->native->mode, - gconf->native->color_format, gconf->native->depth_format, - gconf->native->stencil_format, - gsurf->base.Width, gsurf->base.Height, &gsurf->base); -} - -/** - * Update the attachments of draw/read surfaces. - */ -static void -egl_g3d_route_context(_EGLDisplay *dpy, _EGLContext *ctx) -{ - struct egl_g3d_context *gctx = egl_g3d_context(ctx); - EGLint s; - - /* route draw and read buffers' attachments */ - for (s = 0; s < 2; s++) { - struct egl_g3d_surface *gsurf; - struct egl_g3d_buffer *gbuf; - - if (s == 0) { - gsurf = egl_g3d_surface(gctx->base.DrawSurface); - gbuf = &gctx->draw; - } - else { - gsurf = egl_g3d_surface(gctx->base.ReadSurface); - gbuf = &gctx->read; - } - - gbuf->attachment_mask = (1 << gsurf->render_att); - - /* FIXME OpenGL defaults to draw the front or back buffer when the - * context is single-buffered or double-buffered respectively. In EGL, - * however, the buffer to be drawn is determined by the surface, instead - * of the context. As a result, rendering to a pixmap surface with a - * double-buffered context does not work as expected. - * - * gctx->stapi->st_draw_front_buffer(gctx->st_ctx, natt == - * NATIVE_ATTACHMENT_FRONT_LEFT); - */ - - /* - * FIXME If the back buffer is asked for here, and the front buffer is - * later needed by the client API (e.g. glDrawBuffer is called to draw - * the front buffer), it will create a new pipe texture and draw there. - * One fix is to ask for both buffers here, but it would be a waste if - * the front buffer is never used. A better fix is to add a callback to - * the pipe screen with context private (just like flush_frontbuffer). - */ - } -} - -/** - * Reallocate the context's framebuffers after draw/read surfaces change. - */ -static EGLBoolean -egl_g3d_realloc_context(_EGLDisplay *dpy, _EGLContext *ctx) -{ - struct egl_g3d_context *gctx = egl_g3d_context(ctx); - struct egl_g3d_surface *gdraw = egl_g3d_surface(gctx->base.DrawSurface); - struct egl_g3d_surface *gread = egl_g3d_surface(gctx->base.ReadSurface); - - /* unreference the old framebuffers */ - if (gctx->draw.st_fb) { - EGLBoolean is_equal = (gctx->draw.st_fb == gctx->read.st_fb); - void *priv; - - priv = gctx->stapi->st_framebuffer_private(gctx->draw.st_fb); - if (!gdraw || priv != (void *) &gdraw->base) { - gctx->stapi->st_unreference_framebuffer(gctx->draw.st_fb); - gctx->draw.st_fb = NULL; - gctx->draw.attachment_mask = 0x0; - } - - if (is_equal) { - gctx->read.st_fb = NULL; - gctx->draw.attachment_mask = 0x0; - } - else { - priv = gctx->stapi->st_framebuffer_private(gctx->read.st_fb); - if (!gread || priv != (void *) &gread->base) { - gctx->stapi->st_unreference_framebuffer(gctx->read.st_fb); - gctx->read.st_fb = NULL; - gctx->draw.attachment_mask = 0x0; - } - } - } - - if (!gdraw) - return EGL_TRUE; - - /* create the draw fb */ - if (!gctx->draw.st_fb) { - gctx->draw.st_fb = create_framebuffer(&gctx->base, &gdraw->base); - if (!gctx->draw.st_fb) - return EGL_FALSE; - } - - /* create the read fb */ - if (!gctx->read.st_fb) { - if (gread != gdraw) { - gctx->read.st_fb = create_framebuffer(&gctx->base, &gread->base); - if (!gctx->read.st_fb) { - gctx->stapi->st_unreference_framebuffer(gctx->draw.st_fb); - gctx->draw.st_fb = NULL; - return EGL_FALSE; - } - } - else { - /* there is no st_reference_framebuffer... */ - gctx->read.st_fb = gctx->draw.st_fb; - } - } - - egl_g3d_route_context(dpy, &gctx->base); - gctx->force_validate = EGL_TRUE; - - return EGL_TRUE; -} - -/** - * Return the state tracker for the given context. - */ -static const struct egl_g3d_st * -egl_g3d_choose_st(_EGLDriver *drv, _EGLContext *ctx) -{ - struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); - const struct egl_g3d_st *stapi; - EGLint idx = -1; - - switch (ctx->ClientAPI) { - case EGL_OPENGL_ES_API: - switch (ctx->ClientVersion) { - case 1: - idx = EGL_G3D_ST_OPENGL_ES; - break; - case 2: - idx = EGL_G3D_ST_OPENGL_ES2; - break; - default: - _eglLog(_EGL_WARNING, "unknown client version %d", - ctx->ClientVersion); - break; - } - break; - case EGL_OPENVG_API: - idx = EGL_G3D_ST_OPENVG; - break; - case EGL_OPENGL_API: - idx = EGL_G3D_ST_OPENGL; - break; - default: - _eglLog(_EGL_WARNING, "unknown client API 0x%04x", ctx->ClientAPI); - break; - } +#include "pipe/p_screen.h" +#include "util/u_memory.h" +#include "util/u_format.h" +#include "util/u_string.h" - stapi = (idx >= 0) ? gdrv->stapis[idx] : NULL; - return stapi; -} +#include "egl_g3d.h" +#include "egl_g3d_api.h" +#include "egl_g3d_st.h" +#include "native.h" /** * Initialize the state trackers. @@ -296,10 +50,10 @@ egl_g3d_init_st(_EGLDriver *drv) if (gdrv->api_mask) return; - for (i = 0; i < NUM_EGL_G3D_STS; i++) { - gdrv->stapis[i] = egl_g3d_get_st(i); + for (i = 0; i < ST_API_COUNT; i++) { + gdrv->stapis[i] = egl_g3d_create_st_api(i); if (gdrv->stapis[i]) - gdrv->api_mask |= gdrv->stapis[i]->api_bit; + gdrv->api_mask |= egl_g3d_st_api_bit(i); } if (gdrv->api_mask) @@ -348,35 +102,6 @@ egl_g3d_destroy_probe(_EGLDriver *drv, _EGLDisplay *dpy) } } -/** - * Return an API mask that consists of the state trackers that supports the - * given mode. - * - * FIXME add st_is_mode_supported()? - */ -static EGLint -get_mode_api_mask(const __GLcontextModes *mode, EGLint api_mask) -{ - EGLint check; - - /* OpenGL ES 1.x and 2.x are checked together */ - check = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT; - if (api_mask & check) { - /* this is required by EGL, not by OpenGL ES */ - if (mode->drawableType & GLX_WINDOW_BIT && !mode->doubleBufferMode) - api_mask &= ~check; - } - - check = EGL_OPENVG_BIT; - if (api_mask & check) { - /* vega st needs the depth/stencil rb */ - if (!mode->depthBits && !mode->stencilBits) - api_mask &= ~check; - } - - return api_mask; -} - #ifdef EGL_MESA_screen_surface static void @@ -390,7 +115,7 @@ egl_g3d_add_screens(_EGLDriver *drv, _EGLDisplay *dpy) gdpy->native->modeset->get_connectors(gdpy->native, &num_connectors, NULL); if (!num_connectors) { if (native_connectors) - free(native_connectors); + FREE(native_connectors); return; } @@ -405,13 +130,13 @@ egl_g3d_add_screens(_EGLDriver *drv, _EGLDisplay *dpy) gdpy->native->modeset->get_modes(gdpy->native, nconn, &num_modes); if (!num_modes) { if (native_modes) - free(native_modes); + FREE(native_modes); continue; } gscr = CALLOC_STRUCT(egl_g3d_screen); if (!gscr) { - free(native_modes); + FREE(native_modes); continue; } @@ -435,629 +160,370 @@ egl_g3d_add_screens(_EGLDriver *drv, _EGLDisplay *dpy) _eglAddScreen(dpy, &gscr->base); } - free(native_connectors); + FREE(native_connectors); } #endif /* EGL_MESA_screen_surface */ /** - * Add configs to display and return the next config ID. + * Initialize and validate the EGL config attributes. */ -static EGLint -egl_g3d_add_configs(_EGLDriver *drv, _EGLDisplay *dpy, EGLint id) -{ - struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); - struct egl_g3d_display *gdpy = egl_g3d_display(dpy); - const struct native_config **native_configs; - int num_configs, i; - - native_configs = gdpy->native->get_configs(gdpy->native, - &num_configs); - if (!num_configs) { - if (native_configs) - free(native_configs); - return id; - } - - for (i = 0; i < num_configs; i++) { - EGLint api_mask; - struct egl_g3d_config *gconf; - EGLBoolean valid; - - gconf = CALLOC_STRUCT(egl_g3d_config); - if (!gconf) - continue; - - _eglInitConfig(&gconf->base, id); - - api_mask = get_mode_api_mask(&native_configs[i]->mode, gdrv->api_mask); - if (!api_mask) { - _eglLog(_EGL_DEBUG, "no state tracker supports config 0x%x", - native_configs[i]->mode.visualID); - } - - valid = _eglConfigFromContextModesRec(&gconf->base, - &native_configs[i]->mode, api_mask, api_mask); - if (valid) { -#ifdef EGL_MESA_screen_surface - /* check if scanout surface bit is set */ - if (native_configs[i]->scanout_bit) { - EGLint val = GET_CONFIG_ATTRIB(&gconf->base, EGL_SURFACE_TYPE); - val |= EGL_SCREEN_BIT_MESA; - SET_CONFIG_ATTRIB(&gconf->base, EGL_SURFACE_TYPE, val); - } -#endif - valid = _eglValidateConfig(&gconf->base, EGL_FALSE); - } - if (!valid) { - _eglLog(_EGL_DEBUG, "skip invalid config 0x%x", - native_configs[i]->mode.visualID); - free(gconf); - continue; - } - - gconf->native = native_configs[i]; - _eglAddConfig(dpy, &gconf->base); - id++; - } - - free(native_configs); - return id; -} - -/** - * Flush the front buffer of the context's draw surface. - */ -static void -egl_g3d_flush_frontbuffer(struct pipe_screen *screen, - struct pipe_surface *surf, void *context_private) -{ - struct egl_g3d_context *gctx = egl_g3d_context(context_private); - struct egl_g3d_surface *gsurf = egl_g3d_surface(gctx->base.DrawSurface); - - if (gsurf) - gsurf->native->flush_frontbuffer(gsurf->native); -} - -/** - * Re-validate the context. - */ -static void -egl_g3d_update_buffer(struct pipe_screen *screen, void *context_private) -{ - struct egl_g3d_context *gctx = egl_g3d_context(context_private); - - /** - * It is likely that the surface has changed when this function is called. - * Set force_validate to skip an unnecessary check. - */ - gctx->force_validate = EGL_TRUE; - egl_g3d_validate_context(gctx->base.Resource.Display, &gctx->base); -} - static EGLBoolean -egl_g3d_terminate(_EGLDriver *drv, _EGLDisplay *dpy) +init_config_attributes(_EGLConfig *conf, const struct native_config *nconf, + EGLint api_mask, enum pipe_format depth_stencil_format) { - struct egl_g3d_display *gdpy = egl_g3d_display(dpy); + uint rgba[4], depth_stencil[2], buffer_size; + EGLint surface_type; EGLint i; - _eglReleaseDisplayResources(drv, dpy); - _eglCleanupDisplay(dpy); - - if (dpy->Screens) { - for (i = 0; i < dpy->NumScreens; i++) { - struct egl_g3d_screen *gscr = egl_g3d_screen(dpy->Screens[i]); - free(gscr->native_modes); - free(gscr); + /* get the color and depth/stencil component sizes */ + assert(nconf->color_format != PIPE_FORMAT_NONE); + buffer_size = 0; + for (i = 0; i < 4; i++) { + rgba[i] = util_format_get_component_bits(nconf->color_format, + UTIL_FORMAT_COLORSPACE_RGB, i); + buffer_size += rgba[i]; + } + for (i = 0; i < 2; i++) { + if (depth_stencil_format != PIPE_FORMAT_NONE) { + depth_stencil[i] = + util_format_get_component_bits(depth_stencil_format, + UTIL_FORMAT_COLORSPACE_ZS, i); + } + else { + depth_stencil[i] = 0; } - free(dpy->Screens); } - if (gdpy->native) - gdpy->native->destroy(gdpy->native); - - free(gdpy); - dpy->DriverData = NULL; - - return EGL_TRUE; -} - -static EGLBoolean -egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy, - EGLint *major, EGLint *minor) -{ - struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); - struct egl_g3d_display *gdpy; - - /* the probe object is unlikely to be needed again */ - egl_g3d_destroy_probe(drv, dpy); + surface_type = 0x0; + if (nconf->window_bit) + surface_type |= EGL_WINDOW_BIT; + if (nconf->pixmap_bit) + surface_type |= EGL_PIXMAP_BIT; +#ifdef EGL_MESA_screen_surface + if (nconf->scanout_bit) + surface_type |= EGL_SCREEN_BIT_MESA; +#endif - gdpy = CALLOC_STRUCT(egl_g3d_display); - if (!gdpy) { - _eglError(EGL_BAD_ALLOC, "eglInitialize"); - goto fail; - } - dpy->DriverData = gdpy; + if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT)) + surface_type |= EGL_PBUFFER_BIT; - gdpy->native = native_create_display(dpy->NativeDisplay); - if (!gdpy->native) { - _eglError(EGL_NOT_INITIALIZED, "eglInitialize(no usable display)"); - goto fail; - } + SET_CONFIG_ATTRIB(conf, EGL_CONFORMANT, api_mask); + SET_CONFIG_ATTRIB(conf, EGL_RENDERABLE_TYPE, api_mask); - gdpy->native->screen->flush_frontbuffer = egl_g3d_flush_frontbuffer; - gdpy->native->screen->update_buffer = egl_g3d_update_buffer; + SET_CONFIG_ATTRIB(conf, EGL_RED_SIZE, rgba[0]); + SET_CONFIG_ATTRIB(conf, EGL_GREEN_SIZE, rgba[1]); + SET_CONFIG_ATTRIB(conf, EGL_BLUE_SIZE, rgba[2]); + SET_CONFIG_ATTRIB(conf, EGL_ALPHA_SIZE, rgba[3]); + SET_CONFIG_ATTRIB(conf, EGL_BUFFER_SIZE, buffer_size); - egl_g3d_init_st(&gdrv->base); - dpy->ClientAPIsMask = gdrv->api_mask; + SET_CONFIG_ATTRIB(conf, EGL_DEPTH_SIZE, depth_stencil[0]); + SET_CONFIG_ATTRIB(conf, EGL_STENCIL_SIZE, depth_stencil[1]); - if (egl_g3d_add_configs(drv, dpy, 1) == 1) { - _eglError(EGL_NOT_INITIALIZED, "eglInitialize(unable to add configs)"); - goto fail; - } + SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, surface_type); -#ifdef EGL_MESA_screen_surface - /* enable MESA_screen_surface */ - if (gdpy->native->modeset) { - dpy->Extensions.MESA_screen_surface = EGL_TRUE; - egl_g3d_add_screens(drv, dpy); + SET_CONFIG_ATTRIB(conf, EGL_NATIVE_RENDERABLE, EGL_TRUE); + if (surface_type & EGL_WINDOW_BIT) { + SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID, nconf->native_visual_id); + SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, + nconf->native_visual_type); } -#endif - - *major = 1; - *minor = 4; - return EGL_TRUE; - -fail: - if (gdpy) - egl_g3d_terminate(drv, dpy); - return EGL_FALSE; -} + if (surface_type & EGL_PBUFFER_BIT) { + SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE); + if (rgba[3]) + SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE); -static _EGLContext * -egl_g3d_create_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, - _EGLContext *share, const EGLint *attribs) -{ - struct egl_g3d_display *gdpy = egl_g3d_display(dpy); - struct egl_g3d_context *gshare = egl_g3d_context(share); - struct egl_g3d_config *gconf = egl_g3d_config(conf); - struct egl_g3d_context *gctx; - const __GLcontextModes *mode; - - gctx = CALLOC_STRUCT(egl_g3d_context); - if (!gctx) { - _eglError(EGL_BAD_ALLOC, "eglCreateContext"); - return NULL; + SET_CONFIG_ATTRIB(conf, EGL_MAX_PBUFFER_WIDTH, 4096); + SET_CONFIG_ATTRIB(conf, EGL_MAX_PBUFFER_HEIGHT, 4096); + SET_CONFIG_ATTRIB(conf, EGL_MAX_PBUFFER_PIXELS, 4096 * 4096); } - if (!_eglInitContext(drv, &gctx->base, conf, attribs)) { - free(gctx); - return NULL; - } + SET_CONFIG_ATTRIB(conf, EGL_LEVEL, nconf->level); + SET_CONFIG_ATTRIB(conf, EGL_SAMPLES, nconf->samples); + SET_CONFIG_ATTRIB(conf, EGL_SAMPLE_BUFFERS, 1); - gctx->stapi = egl_g3d_choose_st(drv, &gctx->base); - if (!gctx->stapi) { - free(gctx); - return NULL; - } + if (nconf->slow_config) + SET_CONFIG_ATTRIB(conf, EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG); - mode = &gconf->native->mode; - gctx->pipe = - gdpy->native->create_context(gdpy->native, (void *) &gctx->base); - if (!gctx->pipe) { - free(gctx); - return NULL; - } + if (nconf->transparent_rgb) { + rgba[0] = nconf->transparent_rgb_values[0]; + rgba[1] = nconf->transparent_rgb_values[1]; + rgba[2] = nconf->transparent_rgb_values[2]; - gctx->st_ctx = gctx->stapi->st_create_context(gctx->pipe, mode, - (gshare) ? gshare->st_ctx : NULL); - if (!gctx->st_ctx) { - gctx->pipe->destroy(gctx->pipe); - free(gctx); - return NULL; + SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_RGB); + SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_RED_VALUE, rgba[0]); + SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_GREEN_VALUE, rgba[1]); + SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_BLUE_VALUE, rgba[2]); } - return &gctx->base; + return _eglValidateConfig(conf, EGL_FALSE); } /** - * Destroy a context. + * Initialize an EGL config from the native config. */ -static void -destroy_context(_EGLDisplay *dpy, _EGLContext *ctx) -{ - struct egl_g3d_context *gctx = egl_g3d_context(ctx); - - /* FIXME a context might live longer than its display */ - if (!dpy->Initialized) - _eglLog(_EGL_FATAL, "destroy a context with an unitialized display"); - - egl_g3d_realloc_context(dpy, &gctx->base); - /* it will destroy the associated pipe context */ - gctx->stapi->st_destroy_context(gctx->st_ctx); - - free(gctx); -} - -static EGLBoolean -egl_g3d_destroy_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) -{ - if (!_eglIsContextBound(ctx)) - destroy_context(dpy, ctx); - return EGL_TRUE; -} - static EGLBoolean -init_surface_geometry(_EGLSurface *surf) -{ - struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); - - return gsurf->native->validate(gsurf->native, 0x0, - &gsurf->sequence_number, NULL, - &gsurf->base.Width, &gsurf->base.Height); -} - -static _EGLSurface * -egl_g3d_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy, - _EGLConfig *conf, EGLNativeWindowType win, - const EGLint *attribs) +egl_g3d_init_config(_EGLDriver *drv, _EGLDisplay *dpy, + _EGLConfig *conf, const struct native_config *nconf, + enum pipe_format depth_stencil_format) { - struct egl_g3d_display *gdpy = egl_g3d_display(dpy); - struct egl_g3d_config *gconf = egl_g3d_config(conf); - struct egl_g3d_surface *gsurf; - - gsurf = CALLOC_STRUCT(egl_g3d_surface); - if (!gsurf) { - _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface"); - return NULL; - } - - if (!_eglInitSurface(drv, &gsurf->base, EGL_WINDOW_BIT, conf, attribs)) { - free(gsurf); - return NULL; - } - - gsurf->native = - gdpy->native->create_window_surface(gdpy->native, win, gconf->native); - if (!gsurf->native) { - free(gsurf); - return NULL; - } - - if (!init_surface_geometry(&gsurf->base)) { - gsurf->native->destroy(gsurf->native); - free(gsurf); - return NULL; - } - - gsurf->render_att = (gsurf->base.RenderBuffer == EGL_SINGLE_BUFFER || - !gconf->native->mode.doubleBufferMode) ? - NATIVE_ATTACHMENT_FRONT_LEFT : NATIVE_ATTACHMENT_BACK_LEFT; - - return &gsurf->base; -} - -static _EGLSurface * -egl_g3d_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy, - _EGLConfig *conf, EGLNativePixmapType pix, - const EGLint *attribs) -{ - struct egl_g3d_display *gdpy = egl_g3d_display(dpy); + struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); struct egl_g3d_config *gconf = egl_g3d_config(conf); - struct egl_g3d_surface *gsurf; - - gsurf = CALLOC_STRUCT(egl_g3d_surface); - if (!gsurf) { - _eglError(EGL_BAD_ALLOC, "eglCreatePixmapSurface"); - return NULL; - } + EGLint buffer_mask, api_mask; + EGLBoolean valid; + EGLint i; - if (!_eglInitSurface(drv, &gsurf->base, EGL_PIXMAP_BIT, conf, attribs)) { - free(gsurf); - return NULL; + buffer_mask = 0x0; + if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_LEFT)) + buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK; + if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT)) + buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK; + if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_FRONT_RIGHT)) + buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK; + if (nconf->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_RIGHT)) + buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK; + + gconf->stvis.buffer_mask = buffer_mask; + gconf->stvis.color_format = nconf->color_format; + gconf->stvis.depth_stencil_format = depth_stencil_format; + gconf->stvis.accum_format = PIPE_FORMAT_NONE; + gconf->stvis.samples = nconf->samples; + + gconf->stvis.render_buffer = (buffer_mask & ST_ATTACHMENT_BACK_LEFT_MASK) ? + ST_ATTACHMENT_BACK_LEFT : ST_ATTACHMENT_FRONT_LEFT; + + api_mask = 0; + for (i = 0; i < ST_API_COUNT; i++) { + struct st_api *stapi = gdrv->stapis[i]; + if (stapi) { + if (stapi->is_visual_supported(stapi, &gconf->stvis)) + api_mask |= egl_g3d_st_api_bit(i); + } } + /* this is required by EGL, not by OpenGL ES */ + if (nconf->window_bit && + gconf->stvis.render_buffer != ST_ATTACHMENT_BACK_LEFT) + api_mask &= ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT); - gsurf->native = - gdpy->native->create_pixmap_surface(gdpy->native, pix, gconf->native); - if (!gsurf->native) { - free(gsurf); - return NULL; + if (!api_mask) { + _eglLog(_EGL_DEBUG, "no state tracker supports config 0x%x", + nconf->native_visual_id); } - if (!init_surface_geometry(&gsurf->base)) { - gsurf->native->destroy(gsurf->native); - free(gsurf); - return NULL; + valid = init_config_attributes(&gconf->base, + nconf, api_mask, depth_stencil_format); + if (!valid) { + _eglLog(_EGL_DEBUG, "skip invalid config 0x%x", nconf->native_visual_id); + return EGL_FALSE; } - gsurf->render_att = NATIVE_ATTACHMENT_FRONT_LEFT; + gconf->native = nconf; - return &gsurf->base; + return EGL_TRUE; } -static _EGLSurface * -egl_g3d_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy, - _EGLConfig *conf, const EGLint *attribs) +/** + * Get all interested depth/stencil formats of a display. + */ +static EGLint +egl_g3d_fill_depth_stencil_formats(_EGLDisplay *dpy, + enum pipe_format formats[8]) { struct egl_g3d_display *gdpy = egl_g3d_display(dpy); - struct egl_g3d_config *gconf = egl_g3d_config(conf); - struct egl_g3d_surface *gsurf; + struct pipe_screen *screen = gdpy->native->screen; + const EGLint candidates[] = { + 1, PIPE_FORMAT_Z16_UNORM, + 1, PIPE_FORMAT_Z32_UNORM, + 2, PIPE_FORMAT_Z24_UNORM_S8_USCALED, PIPE_FORMAT_S8_USCALED_Z24_UNORM, + 2, PIPE_FORMAT_Z24X8_UNORM, PIPE_FORMAT_X8Z24_UNORM, + 0 + }; + const EGLint *fmt = candidates; + EGLint count; - gsurf = CALLOC_STRUCT(egl_g3d_surface); - if (!gsurf) { - _eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface"); - return NULL; - } + count = 0; + formats[count++] = PIPE_FORMAT_NONE; - if (!_eglInitSurface(drv, &gsurf->base, EGL_PBUFFER_BIT, conf, attribs)) { - free(gsurf); - return NULL; - } + while (*fmt) { + EGLint i, n = *fmt++; - gsurf->native = - gdpy->native->create_pbuffer_surface(gdpy->native, gconf->native, - gsurf->base.Width, gsurf->base.Height); - if (!gsurf->native) { - free(gsurf); - return NULL; - } + /* pick the first supported format */ + for (i = 0; i < n; i++) { + if (screen->is_format_supported(screen, fmt[i], + PIPE_TEXTURE_2D, PIPE_BIND_DEPTH_STENCIL, 0)) { + formats[count++] = fmt[i]; + break; + } + } - if (!init_surface_geometry(&gsurf->base)) { - gsurf->native->destroy(gsurf->native); - free(gsurf); - return NULL; + fmt += n; } - gsurf->render_att = (!gconf->native->mode.doubleBufferMode) ? - NATIVE_ATTACHMENT_FRONT_LEFT : NATIVE_ATTACHMENT_BACK_LEFT; - - return &gsurf->base; + return count; } /** - * Destroy a surface. + * Add configs to display and return the next config ID. */ -static void -destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf) -{ - struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); - - /* FIXME a surface might live longer than its display */ - if (!dpy->Initialized) - _eglLog(_EGL_FATAL, "destroy a surface with an unitialized display"); - - pipe_surface_reference(&gsurf->render_surface, NULL); - gsurf->native->destroy(gsurf->native); - free(gsurf); -} - -static EGLBoolean -egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) -{ - if (!_eglIsSurfaceBound(surf)) - destroy_surface(dpy, surf); - return EGL_TRUE; -} - -static EGLBoolean -egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy, - _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx) +static EGLint +egl_g3d_add_configs(_EGLDriver *drv, _EGLDisplay *dpy, EGLint id) { - struct egl_g3d_context *gctx = egl_g3d_context(ctx); - struct egl_g3d_surface *gdraw = egl_g3d_surface(draw); - struct egl_g3d_context *old_gctx; - EGLBoolean ok = EGL_TRUE; + struct egl_g3d_display *gdpy = egl_g3d_display(dpy); + const struct native_config **native_configs; + enum pipe_format depth_stencil_formats[8]; + int num_formats, num_configs, i, j; - /* bind the new context and return the "orphaned" one */ - if (!_eglBindContext(&ctx, &draw, &read)) - return EGL_FALSE; - old_gctx = egl_g3d_context(ctx); - - if (old_gctx) { - /* flush old context */ - old_gctx->stapi->st_flush(old_gctx->st_ctx, - PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); - - /* - * The old context is no longer current, and egl_g3d_realloc_context() - * should be called to destroy the framebuffers. However, it is possible - * that it will be made current again with the same draw/read surfaces. - * It might be better to keep it around. - */ + native_configs = gdpy->native->get_configs(gdpy->native, &num_configs); + if (!num_configs) { + if (native_configs) + FREE(native_configs); + return id; } - if (gctx) { - ok = egl_g3d_realloc_context(dpy, &gctx->base); - if (ok) { - ok = gctx->stapi->st_make_current(gctx->st_ctx, - gctx->draw.st_fb, gctx->read.st_fb); - if (ok) { - egl_g3d_validate_context(dpy, &gctx->base); - if (gdraw->base.Type == EGL_WINDOW_BIT) { - gctx->base.WindowRenderBuffer = - (gdraw->render_att == NATIVE_ATTACHMENT_FRONT_LEFT) ? - EGL_SINGLE_BUFFER : EGL_BACK_BUFFER; + num_formats = egl_g3d_fill_depth_stencil_formats(dpy, + depth_stencil_formats); + + for (i = 0; i < num_configs; i++) { + for (j = 0; j < num_formats; j++) { + struct egl_g3d_config *gconf; + + gconf = CALLOC_STRUCT(egl_g3d_config); + if (gconf) { + _eglInitConfig(&gconf->base, dpy, id); + if (!egl_g3d_init_config(drv, dpy, &gconf->base, + native_configs[i], depth_stencil_formats[j])) { + FREE(gconf); + break; } + + _eglAddConfig(dpy, &gconf->base); + id++; } } } - else if (old_gctx) { - ok = old_gctx->stapi->st_make_current(NULL, NULL, NULL); - old_gctx->base.WindowRenderBuffer = EGL_NONE; - } - if (ctx && !_eglIsContextLinked(ctx)) - destroy_context(dpy, ctx); - if (draw && !_eglIsSurfaceLinked(draw)) - destroy_surface(dpy, draw); - if (read && read != draw && !_eglIsSurfaceLinked(read)) - destroy_surface(dpy, read); - - return ok; + FREE(native_configs); + return id; } -static EGLBoolean -egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) +static void +egl_g3d_invalid_surface(struct native_display *ndpy, + struct native_surface *nsurf, + unsigned int seq_num) { - struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); - _EGLContext *ctx = _eglGetCurrentContext(); - struct egl_g3d_context *gctx = NULL; - - /* no-op for pixmap or pbuffer surface */ - if (gsurf->base.Type == EGL_PIXMAP_BIT || - gsurf->base.Type == EGL_PBUFFER_BIT) - return EGL_TRUE; - - /* or when the surface is single-buffered */ - if (gsurf->render_att == NATIVE_ATTACHMENT_FRONT_LEFT) - return EGL_TRUE; - - if (ctx && ctx->DrawSurface == surf) - gctx = egl_g3d_context(ctx); - - /* flush if the surface is current */ - if (gctx) - gctx->stapi->st_notify_swapbuffers(gctx->draw.st_fb); - + /* XXX not thread safe? */ + struct egl_g3d_surface *gsurf = egl_g3d_surface(nsurf->user_data); + struct egl_g3d_context *gctx; + /* - * We drew on the back buffer, unless there was no back buffer. - * In that case, we drew on the front buffer. Either case, we call - * swap_buffers. + * Some functions such as egl_g3d_copy_buffers create a temporary native + * surface. There is no gsurf associated with it. */ - if (!gsurf->native->swap_buffers(gsurf->native)) - return EGL_FALSE; - - if (gctx) { - struct egl_g3d_config *gconf = egl_g3d_config(gsurf->base.Config); - - /* force validation if the swap method is not copy */ - if (gconf->native->mode.swapMethod != GLX_SWAP_COPY_OML) { - gctx->force_validate = EGL_TRUE; - egl_g3d_validate_context(dpy, &gctx->base); - } - } - - return EGL_TRUE; + gctx = (gsurf) ? egl_g3d_context(gsurf->base.CurrentContext) : NULL; + if (gctx) + gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gsurf->stfbi); } -/** - * Find a config that supports the pixmap. - */ -static _EGLConfig * -find_pixmap_config(_EGLDisplay *dpy, EGLNativePixmapType pix) +static struct native_event_handler egl_g3d_native_event_handler = { + .invalid_surface = egl_g3d_invalid_surface +}; + +static EGLBoolean +egl_g3d_terminate(_EGLDriver *drv, _EGLDisplay *dpy) { struct egl_g3d_display *gdpy = egl_g3d_display(dpy); - struct egl_g3d_config *gconf; EGLint i; - for (i = 0; i < dpy->NumConfigs; i++) { - gconf = egl_g3d_config(dpy->Configs[i]); - if (gdpy->native->is_pixmap_supported(gdpy->native, pix, gconf->native)) - break; - } + _eglReleaseDisplayResources(drv, dpy); + _eglCleanupDisplay(dpy); - return (i < dpy->NumConfigs) ? &gconf->base : NULL; -} + if (gdpy->pipe) + gdpy->pipe->destroy(gdpy->pipe); -/** - * Get the pipe surface of the given attachment of the native surface. - */ -static struct pipe_surface * -get_pipe_surface(struct native_display *ndpy, struct native_surface *nsurf, - enum native_attachment natt) -{ - struct pipe_texture *textures[NUM_NATIVE_ATTACHMENTS]; - struct pipe_surface *psurf; + if (dpy->Screens) { + for (i = 0; i < dpy->NumScreens; i++) { + struct egl_g3d_screen *gscr = egl_g3d_screen(dpy->Screens[i]); + FREE(gscr->native_modes); + FREE(gscr); + } + FREE(dpy->Screens); + } - textures[natt] = NULL; - nsurf->validate(nsurf, 1 << natt, NULL, textures, NULL, NULL); - if (!textures[natt]) - return NULL; + if (gdpy->smapi) + egl_g3d_destroy_st_manager(gdpy->smapi); - psurf = ndpy->screen->get_tex_surface(ndpy->screen, textures[natt], - 0, 0, 0, PIPE_BUFFER_USAGE_CPU_WRITE); - pipe_texture_reference(&textures[natt], NULL); + if (gdpy->native) + gdpy->native->destroy(gdpy->native); + + FREE(gdpy); + dpy->DriverData = NULL; - return psurf; + return EGL_TRUE; } static EGLBoolean -egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, - EGLNativePixmapType target) +egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy, + EGLint *major, EGLint *minor) { - struct egl_g3d_display *gdpy = egl_g3d_display(dpy); - struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); - _EGLContext *ctx = _eglGetCurrentContext(); - struct egl_g3d_config *gconf; - struct native_surface *nsurf; - struct pipe_screen *screen = gdpy->native->screen; - struct pipe_surface *psurf; - - if (!gsurf->render_surface) - return EGL_TRUE; - - gconf = egl_g3d_config(find_pixmap_config(dpy, target)); - if (!gconf) - return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers"); + struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); + struct egl_g3d_display *gdpy; - nsurf = gdpy->native->create_pixmap_surface(gdpy->native, - target, gconf->native); - if (!nsurf) - return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers"); + /* the probe object is unlikely to be needed again */ + egl_g3d_destroy_probe(drv, dpy); - /* flush if the surface is current */ - if (ctx && ctx->DrawSurface == &gsurf->base) { - struct egl_g3d_context *gctx = egl_g3d_context(ctx); - gctx->stapi->st_flush(gctx->st_ctx, - PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); + gdpy = CALLOC_STRUCT(egl_g3d_display); + if (!gdpy) { + _eglError(EGL_BAD_ALLOC, "eglInitialize"); + goto fail; } + dpy->DriverData = gdpy; - psurf = get_pipe_surface(gdpy->native, nsurf, NATIVE_ATTACHMENT_FRONT_LEFT); - if (psurf) { - struct pipe_context pipe; - - /** - * XXX This is hacky. If we might allow the EGLDisplay to create a pipe - * context of its own and use the blitter context for this. - */ - memset(&pipe, 0, sizeof(pipe)); - pipe.screen = screen; - - util_surface_copy(&pipe, FALSE, psurf, 0, 0, - gsurf->render_surface, 0, 0, psurf->width, psurf->height); - - pipe_surface_reference(&psurf, NULL); - nsurf->flush_frontbuffer(nsurf); + gdpy->native = native_create_display(dpy->NativeDisplay, + &egl_g3d_native_event_handler); + if (!gdpy->native) { + _eglError(EGL_NOT_INITIALIZED, "eglInitialize(no usable display)"); + goto fail; } - nsurf->destroy(nsurf); + gdpy->native->user_data = (void *) dpy; - return EGL_TRUE; -} + egl_g3d_init_st(&gdrv->base); + dpy->ClientAPIsMask = gdrv->api_mask; -static EGLBoolean -egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) -{ - struct egl_g3d_context *gctx = egl_g3d_context(ctx); - gctx->stapi->st_finish(gctx->st_ctx); - return EGL_TRUE; -} + gdpy->smapi = egl_g3d_create_st_manager(dpy); + if (!gdpy->smapi) { + _eglError(EGL_NOT_INITIALIZED, + "eglInitialize(failed to create st manager)"); + goto fail; + } -static EGLBoolean -egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine) -{ - _EGLContext *ctx = _eglGetCurrentContext(); +#ifdef EGL_MESA_screen_surface + /* enable MESA_screen_surface before adding (and validating) configs */ + if (gdpy->native->modeset) { + dpy->Extensions.MESA_screen_surface = EGL_TRUE; + egl_g3d_add_screens(drv, dpy); + } +#endif - if (engine != EGL_CORE_NATIVE_ENGINE) - return _eglError(EGL_BAD_PARAMETER, "eglWaitNative"); + dpy->Extensions.KHR_image_base = EGL_TRUE; + if (gdpy->native->get_param(gdpy->native, NATIVE_PARAM_USE_NATIVE_BUFFER)) + dpy->Extensions.KHR_image_pixmap = EGL_TRUE; - if (ctx && ctx->DrawSurface) { - struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface); - gsurf->native->wait(gsurf->native); + if (egl_g3d_add_configs(drv, dpy, 1) == 1) { + _eglError(EGL_NOT_INITIALIZED, "eglInitialize(unable to add configs)"); + goto fail; } + *major = 1; + *minor = 4; + return EGL_TRUE; + +fail: + if (gdpy) + egl_g3d_terminate(drv, dpy); + return EGL_FALSE; } static _EGLProc @@ -1070,10 +536,10 @@ egl_g3d_get_proc_address(_EGLDriver *drv, const char *procname) /* in case this is called before a display is initialized */ egl_g3d_init_st(&gdrv->base); - for (i = 0; i < NUM_EGL_G3D_STS; i++) { - const struct egl_g3d_st *stapi = gdrv->stapis[i]; + for (i = 0; i < ST_API_COUNT; i++) { + struct st_api *stapi = gdrv->stapis[i]; if (stapi) { - proc = (_EGLProc) stapi->st_get_proc_address(procname); + proc = (_EGLProc) stapi->get_proc_address(stapi, procname); if (proc) return proc; } @@ -1082,181 +548,6 @@ egl_g3d_get_proc_address(_EGLDriver *drv, const char *procname) return (_EGLProc) NULL; } -static EGLBoolean -egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy, - _EGLSurface *surf, EGLint buffer) -{ - struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); - _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API); - struct egl_g3d_context *gctx = egl_g3d_context(ctx); - enum pipe_format target_format; - int target; - - if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT) - return _eglError(EGL_BAD_SURFACE, "eglBindTexImage"); - if (buffer != EGL_BACK_BUFFER) - return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage"); - if (gsurf->base.BoundToTexture) - return _eglError(EGL_BAD_ACCESS, "eglBindTexImage"); - - switch (gsurf->base.TextureFormat) { - case EGL_TEXTURE_RGB: - target_format = PIPE_FORMAT_R8G8B8_UNORM; - break; - case EGL_TEXTURE_RGBA: - target_format = PIPE_FORMAT_A8R8G8B8_UNORM; - break; - default: - return _eglError(EGL_BAD_MATCH, "eglBindTexImage"); - } - - switch (gsurf->base.TextureTarget) { - case EGL_TEXTURE_2D: - target = ST_TEXTURE_2D; - break; - default: - return _eglError(EGL_BAD_MATCH, "eglBindTexImage"); - } - - /* flush properly if the surface is bound */ - if (gsurf->base.CurrentContext) { - gctx = egl_g3d_context(gsurf->base.CurrentContext); - gctx->stapi->st_flush(gctx->st_ctx, - PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL); - } - - if (gctx) { - if (!gsurf->render_surface) - return EGL_FALSE; - - gctx->stapi->st_bind_texture_surface(gsurf->render_surface, - target, gsurf->base.MipmapLevel, target_format); - gsurf->base.BoundToTexture = EGL_TRUE; - } - - return EGL_TRUE; -} - -static EGLBoolean -egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy, - _EGLSurface *surf, EGLint buffer) -{ - struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); - - if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT || - !gsurf->base.BoundToTexture) - return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage"); - if (buffer != EGL_BACK_BUFFER) - return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage"); - - if (gsurf->render_surface) { - _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API); - struct egl_g3d_context *gctx = egl_g3d_context(ctx); - - /* what if the context the surface binds to is no longer current? */ - if (gctx) - gctx->stapi->st_unbind_texture_surface(gsurf->render_surface, - ST_TEXTURE_2D, gsurf->base.MipmapLevel); - } - - gsurf->base.BoundToTexture = EGL_FALSE; - - return EGL_TRUE; -} - -#ifdef EGL_MESA_screen_surface - -static _EGLSurface * -egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy, - _EGLConfig *conf, const EGLint *attribs) -{ - struct egl_g3d_display *gdpy = egl_g3d_display(dpy); - struct egl_g3d_config *gconf = egl_g3d_config(conf); - struct egl_g3d_surface *gsurf; - - gsurf = CALLOC_STRUCT(egl_g3d_surface); - if (!gsurf) { - _eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface"); - return NULL; - } - - if (!_eglInitSurface(drv, &gsurf->base, - EGL_SCREEN_BIT_MESA, conf, attribs)) { - free(gsurf); - return NULL; - } - - gsurf->native = - gdpy->native->modeset->create_scanout_surface(gdpy->native, - gconf->native, gsurf->base.Width, gsurf->base.Height); - if (!gsurf->native) { - free(gsurf); - return NULL; - } - - gsurf->render_att = (!gconf->native->mode.doubleBufferMode) ? - NATIVE_ATTACHMENT_FRONT_LEFT : NATIVE_ATTACHMENT_BACK_LEFT; - - return &gsurf->base; -} - -static EGLBoolean -egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy, - _EGLScreen *scr, _EGLSurface *surf, - _EGLMode *mode) -{ - struct egl_g3d_display *gdpy = egl_g3d_display(dpy); - struct egl_g3d_screen *gscr = egl_g3d_screen(scr); - struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); - struct native_surface *nsurf; - const struct native_mode *nmode; - EGLBoolean changed; - - if (gsurf) { - EGLint idx; - - if (!mode) - return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA"); - if (gsurf->base.Type != EGL_SCREEN_BIT_MESA) - return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA"); - if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height) - return _eglError(EGL_BAD_MATCH, - "eglShowSurfaceMESA(surface smaller than mode size)"); - - /* find the index of the mode */ - for (idx = 0; idx < gscr->base.NumModes; idx++) - if (mode == &gscr->base.Modes[idx]) - break; - if (idx >= gscr->base.NumModes) { - return _eglError(EGL_BAD_MODE_MESA, - "eglShowSurfaceMESA(unknown mode)"); - } - - nsurf = gsurf->native; - nmode = gscr->native_modes[idx]; - } - else { - if (mode) - return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA"); - - /* disable the screen */ - nsurf = NULL; - nmode = NULL; - } - - /* TODO surface panning by CRTC choosing */ - changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf, - gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode); - if (changed) { - gscr->base.CurrentSurface = &gsurf->base; - gscr->base.CurrentMode = mode; - } - - return changed; -} - -#endif /* EGL_MESA_screen_surface */ - static EGLint egl_g3d_probe(_EGLDriver *drv, _EGLDisplay *dpy) { @@ -1290,9 +581,15 @@ static void egl_g3d_unload(_EGLDriver *drv) { struct egl_g3d_driver *gdrv = egl_g3d_driver(drv); + EGLint i; + + for (i = 0; i < ST_API_COUNT; i++) { + if (gdrv->stapis[i]) + gdrv->stapis[i]->destroy(gdrv->stapis[i]); + } egl_g3d_destroy_probe(drv, NULL); - free(gdrv); + FREE(gdrv); } _EGLDriver * @@ -1301,38 +598,18 @@ _eglMain(const char *args) static char driver_name[64]; struct egl_g3d_driver *gdrv; - snprintf(driver_name, sizeof(driver_name), + util_snprintf(driver_name, sizeof(driver_name), "Gallium/%s", native_get_name()); gdrv = CALLOC_STRUCT(egl_g3d_driver); if (!gdrv) return NULL; - _eglInitDriverFallbacks(&gdrv->base); - + egl_g3d_init_driver_api(&gdrv->base); gdrv->base.API.Initialize = egl_g3d_initialize; gdrv->base.API.Terminate = egl_g3d_terminate; - gdrv->base.API.CreateContext = egl_g3d_create_context; - gdrv->base.API.DestroyContext = egl_g3d_destroy_context; - gdrv->base.API.CreateWindowSurface = egl_g3d_create_window_surface; - gdrv->base.API.CreatePixmapSurface = egl_g3d_create_pixmap_surface; - gdrv->base.API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface; - gdrv->base.API.DestroySurface = egl_g3d_destroy_surface; - gdrv->base.API.MakeCurrent = egl_g3d_make_current; - gdrv->base.API.SwapBuffers = egl_g3d_swap_buffers; - gdrv->base.API.CopyBuffers = egl_g3d_copy_buffers; - gdrv->base.API.WaitClient = egl_g3d_wait_client; - gdrv->base.API.WaitNative = egl_g3d_wait_native; gdrv->base.API.GetProcAddress = egl_g3d_get_proc_address; - gdrv->base.API.BindTexImage = egl_g3d_bind_tex_image; - gdrv->base.API.ReleaseTexImage = egl_g3d_release_tex_image; - -#ifdef EGL_MESA_screen_surface - gdrv->base.API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface; - gdrv->base.API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface; -#endif - gdrv->base.Name = driver_name; gdrv->base.Probe = egl_g3d_probe; gdrv->base.Unload = egl_g3d_unload;