0,0 → 1,940 |
/* |
* Mesa 3-D graphics library |
* |
* Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org> |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* 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, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* 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 "egldriver.h" |
#include "eglcurrent.h" |
#include "egllog.h" |
|
#include "pipe/p_screen.h" |
#include "util/u_memory.h" |
#include "util/u_inlines.h" |
#include "util/u_box.h" |
|
#include "egl_g3d.h" |
#include "egl_g3d_api.h" |
#include "egl_g3d_image.h" |
#include "egl_g3d_sync.h" |
#include "egl_g3d_st.h" |
#include "native.h" |
|
/** |
* Return the state tracker for the given context. |
*/ |
static struct st_api * |
egl_g3d_choose_st(_EGLDriver *drv, _EGLContext *ctx, |
enum st_profile_type *profile) |
{ |
struct st_api *stapi; |
EGLint api = -1; |
|
*profile = ST_PROFILE_DEFAULT; |
|
switch (ctx->ClientAPI) { |
case EGL_OPENGL_ES_API: |
switch (ctx->ClientMajorVersion) { |
case 1: |
api = ST_API_OPENGL; |
*profile = ST_PROFILE_OPENGL_ES1; |
break; |
case 2: |
api = ST_API_OPENGL; |
*profile = ST_PROFILE_OPENGL_ES2; |
break; |
default: |
_eglLog(_EGL_WARNING, "unknown client major version %d", |
ctx->ClientMajorVersion); |
break; |
} |
break; |
case EGL_OPENVG_API: |
api = ST_API_OPENVG; |
break; |
case EGL_OPENGL_API: |
api = ST_API_OPENGL; |
break; |
default: |
_eglLog(_EGL_WARNING, "unknown client API 0x%04x", ctx->ClientAPI); |
break; |
} |
|
stapi = egl_g3d_get_st_api(drv, api); |
if (stapi && !(stapi->profile_mask & (1 << *profile))) |
stapi = NULL; |
|
return stapi; |
} |
|
struct egl_g3d_choose_config_data { |
_EGLConfig criteria; |
enum pipe_format format; |
}; |
|
static int |
egl_g3d_compare_config(const _EGLConfig *conf1, const _EGLConfig *conf2, |
void *priv_data) |
{ |
struct egl_g3d_choose_config_data *data = |
(struct egl_g3d_choose_config_data *) priv_data; |
const _EGLConfig *criteria = &data->criteria;; |
|
/* EGL_NATIVE_VISUAL_TYPE ignored? */ |
return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE); |
} |
|
static EGLBoolean |
egl_g3d_match_config(const _EGLConfig *conf, void *priv_data) |
{ |
struct egl_g3d_choose_config_data *data = |
(struct egl_g3d_choose_config_data *) priv_data; |
struct egl_g3d_config *gconf = egl_g3d_config(conf); |
|
if (data->format != PIPE_FORMAT_NONE && |
data->format != gconf->native->color_format) |
return EGL_FALSE; |
|
return _eglMatchConfig(conf, &data->criteria); |
} |
|
static EGLBoolean |
egl_g3d_choose_config(_EGLDriver *drv, _EGLDisplay *dpy, const EGLint *attribs, |
EGLConfig *configs, EGLint size, EGLint *num_configs) |
{ |
struct egl_g3d_choose_config_data data; |
|
if (!_eglParseConfigAttribList(&data.criteria, dpy, attribs)) |
return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); |
|
data.format = PIPE_FORMAT_NONE; |
if (data.criteria.MatchNativePixmap != EGL_NONE && |
data.criteria.MatchNativePixmap != EGL_DONT_CARE) { |
struct egl_g3d_display *gdpy = egl_g3d_display(dpy); |
|
if (!gdpy->native->get_pixmap_format(gdpy->native, |
(EGLNativePixmapType) data.criteria.MatchNativePixmap, |
&data.format)) |
return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglChooseConfig"); |
} |
|
return _eglFilterConfigArray(dpy->Configs, configs, size, num_configs, |
egl_g3d_match_config, egl_g3d_compare_config, &data); |
} |
|
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; |
struct st_context_attribs stattribs; |
enum st_context_error ctx_err = 0; |
|
gctx = CALLOC_STRUCT(egl_g3d_context); |
if (!gctx) { |
_eglError(EGL_BAD_ALLOC, "eglCreateContext"); |
return NULL; |
} |
|
if (!_eglInitContext(&gctx->base, dpy, conf, attribs)) { |
FREE(gctx); |
return NULL; |
} |
|
memset(&stattribs, 0, sizeof(stattribs)); |
if (gconf) |
stattribs.visual = gconf->stvis; |
|
gctx->stapi = egl_g3d_choose_st(drv, &gctx->base, &stattribs.profile); |
if (!gctx->stapi) { |
FREE(gctx); |
return NULL; |
} |
|
gctx->stctxi = gctx->stapi->create_context(gctx->stapi, gdpy->smapi, |
&stattribs, &ctx_err, (gshare) ? gshare->stctxi : NULL); |
if (!gctx->stctxi) { |
FREE(gctx); |
return NULL; |
} |
|
gctx->stctxi->st_manager_private = (void *) &gctx->base; |
|
return &gctx->base; |
} |
|
/** |
* Destroy a context. |
*/ |
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"); |
|
gctx->stctxi->destroy(gctx->stctxi); |
|
FREE(gctx); |
} |
|
static EGLBoolean |
egl_g3d_destroy_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) |
{ |
if (_eglPutContext(ctx)) |
destroy_context(dpy, ctx); |
return EGL_TRUE; |
} |
|
struct egl_g3d_create_surface_arg { |
EGLint type; |
union { |
EGLNativeWindowType win; |
EGLNativePixmapType pix; |
} u; |
}; |
|
static _EGLSurface * |
egl_g3d_create_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, |
struct egl_g3d_create_surface_arg *arg, |
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; |
struct native_surface *nsurf; |
const char *err; |
|
switch (arg->type) { |
case EGL_WINDOW_BIT: |
err = "eglCreateWindowSurface"; |
break; |
case EGL_PIXMAP_BIT: |
err = "eglCreatePixmapSurface"; |
break; |
#ifdef EGL_MESA_screen_surface |
case EGL_SCREEN_BIT_MESA: |
err = "eglCreateScreenSurface"; |
break; |
#endif |
default: |
err = "eglCreateUnknownSurface"; |
break; |
} |
|
gsurf = CALLOC_STRUCT(egl_g3d_surface); |
if (!gsurf) { |
_eglError(EGL_BAD_ALLOC, err); |
return NULL; |
} |
|
if (!_eglInitSurface(&gsurf->base, dpy, arg->type, conf, attribs)) { |
FREE(gsurf); |
return NULL; |
} |
|
/* create the native surface */ |
switch (arg->type) { |
case EGL_WINDOW_BIT: |
nsurf = gdpy->native->create_window_surface(gdpy->native, |
arg->u.win, gconf->native); |
break; |
case EGL_PIXMAP_BIT: |
nsurf = gdpy->native->create_pixmap_surface(gdpy->native, |
arg->u.pix, gconf->native); |
break; |
#ifdef EGL_MESA_screen_surface |
case EGL_SCREEN_BIT_MESA: |
/* prefer back buffer (move to _eglInitSurface?) */ |
gsurf->base.RenderBuffer = EGL_BACK_BUFFER; |
nsurf = gdpy->native->modeset->create_scanout_surface(gdpy->native, |
gconf->native, gsurf->base.Width, gsurf->base.Height); |
break; |
#endif |
default: |
nsurf = NULL; |
break; |
} |
|
if (!nsurf) { |
FREE(gsurf); |
return NULL; |
} |
/* initialize the geometry */ |
if (!nsurf->validate(nsurf, 0x0, &gsurf->sequence_number, NULL, |
&gsurf->base.Width, &gsurf->base.Height)) { |
nsurf->destroy(nsurf); |
FREE(gsurf); |
return NULL; |
} |
|
gsurf->stvis = gconf->stvis; |
if (gsurf->base.RenderBuffer == EGL_SINGLE_BUFFER && |
gconf->stvis.buffer_mask & ST_ATTACHMENT_FRONT_LEFT_MASK) |
gsurf->stvis.render_buffer = ST_ATTACHMENT_FRONT_LEFT; |
|
/* surfaces can always be posted when the display supports it */ |
if (dpy->Extensions.NV_post_sub_buffer) |
gsurf->base.PostSubBufferSupportedNV = EGL_TRUE; |
|
gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base); |
if (!gsurf->stfbi) { |
nsurf->destroy(nsurf); |
FREE(gsurf); |
return NULL; |
} |
|
nsurf->user_data = &gsurf->base; |
gsurf->native = nsurf; |
|
return &gsurf->base; |
} |
|
static _EGLSurface * |
egl_g3d_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy, |
_EGLConfig *conf, EGLNativeWindowType win, |
const EGLint *attribs) |
{ |
struct egl_g3d_create_surface_arg arg; |
|
memset(&arg, 0, sizeof(arg)); |
arg.type = EGL_WINDOW_BIT; |
arg.u.win = win; |
|
return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs); |
} |
|
static _EGLSurface * |
egl_g3d_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy, |
_EGLConfig *conf, EGLNativePixmapType pix, |
const EGLint *attribs) |
{ |
struct egl_g3d_create_surface_arg arg; |
|
memset(&arg, 0, sizeof(arg)); |
arg.type = EGL_PIXMAP_BIT; |
arg.u.pix = pix; |
|
return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs); |
} |
|
static struct egl_g3d_surface * |
create_pbuffer_surface(_EGLDisplay *dpy, _EGLConfig *conf, |
const EGLint *attribs, const char *func) |
{ |
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, func); |
return NULL; |
} |
|
if (!_eglInitSurface(&gsurf->base, dpy, EGL_PBUFFER_BIT, conf, attribs)) { |
FREE(gsurf); |
return NULL; |
} |
|
gsurf->stvis = gconf->stvis; |
|
gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base); |
if (!gsurf->stfbi) { |
FREE(gsurf); |
return NULL; |
} |
|
return gsurf; |
} |
|
static _EGLSurface * |
egl_g3d_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy, |
_EGLConfig *conf, const EGLint *attribs) |
{ |
struct egl_g3d_surface *gsurf; |
|
gsurf = create_pbuffer_surface(dpy, conf, attribs, |
"eglCreatePbufferSurface"); |
if (!gsurf) |
return NULL; |
|
gsurf->client_buffer_type = EGL_NONE; |
|
return &gsurf->base; |
} |
|
static _EGLSurface * |
egl_g3d_create_pbuffer_from_client_buffer(_EGLDriver *drv, _EGLDisplay *dpy, |
EGLenum buftype, |
EGLClientBuffer buffer, |
_EGLConfig *conf, |
const EGLint *attribs) |
{ |
struct egl_g3d_surface *gsurf; |
struct pipe_resource *ptex = NULL; |
EGLint pbuffer_attribs[32]; |
EGLint count, i; |
|
switch (buftype) { |
case EGL_OPENVG_IMAGE: |
break; |
default: |
_eglError(EGL_BAD_PARAMETER, "eglCreatePbufferFromClientBuffer"); |
return NULL; |
break; |
} |
|
/* parse the attributes first */ |
count = 0; |
for (i = 0; attribs && attribs[i] != EGL_NONE; i++) { |
EGLint attr = attribs[i++]; |
EGLint val = attribs[i]; |
EGLint err = EGL_SUCCESS; |
|
switch (attr) { |
case EGL_TEXTURE_FORMAT: |
case EGL_TEXTURE_TARGET: |
case EGL_MIPMAP_TEXTURE: |
pbuffer_attribs[count++] = attr; |
pbuffer_attribs[count++] = val; |
break; |
default: |
err = EGL_BAD_ATTRIBUTE; |
break; |
} |
/* bail out */ |
if (err != EGL_SUCCESS) { |
_eglError(err, "eglCreatePbufferFromClientBuffer"); |
return NULL; |
} |
} |
|
pbuffer_attribs[count++] = EGL_NONE; |
|
gsurf = create_pbuffer_surface(dpy, conf, pbuffer_attribs, |
"eglCreatePbufferFromClientBuffer"); |
if (!gsurf) |
return NULL; |
|
gsurf->client_buffer_type = buftype; |
gsurf->client_buffer = buffer; |
|
/* validate now so that it fails if the client buffer is invalid */ |
if (!gsurf->stfbi->validate(NULL, gsurf->stfbi, |
&gsurf->stvis.render_buffer, 1, &ptex)) { |
egl_g3d_destroy_st_framebuffer(gsurf->stfbi); |
FREE(gsurf); |
return NULL; |
} |
pipe_resource_reference(&ptex, NULL); |
|
return &gsurf->base; |
} |
|
/** |
* Destroy a surface. |
*/ |
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_resource_reference(&gsurf->render_texture, NULL); |
egl_g3d_destroy_st_framebuffer(gsurf->stfbi); |
if (gsurf->native) |
gsurf->native->destroy(gsurf->native); |
FREE(gsurf); |
} |
|
static EGLBoolean |
egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) |
{ |
if (_eglPutSurface(surf)) |
destroy_surface(dpy, surf); |
return EGL_TRUE; |
} |
|
static EGLBoolean |
egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy, |
_EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx) |
{ |
struct egl_g3d_context *gctx = egl_g3d_context(ctx); |
struct egl_g3d_surface *gdraw = egl_g3d_surface(draw); |
struct egl_g3d_surface *gread = egl_g3d_surface(read); |
struct egl_g3d_context *old_gctx; |
_EGLContext *old_ctx; |
_EGLSurface *old_draw, *old_read; |
EGLBoolean ok = EGL_TRUE; |
|
/* make new bindings */ |
if (!_eglBindContext(ctx, draw, read, &old_ctx, &old_draw, &old_read)) |
return EGL_FALSE; |
|
old_gctx = egl_g3d_context(old_ctx); |
if (old_gctx) { |
/* flush old context */ |
old_gctx->stctxi->flush(old_gctx->stctxi, ST_FLUSH_FRONT, NULL); |
} |
|
if (gctx) { |
ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi, |
(gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL); |
if (ok) { |
if (gdraw) { |
if (gdraw->base.Type == EGL_WINDOW_BIT) { |
gctx->base.WindowRenderBuffer = |
(gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ? |
EGL_SINGLE_BUFFER : EGL_BACK_BUFFER; |
} |
} |
} |
} |
else if (old_gctx) { |
ok = old_gctx->stapi->make_current(old_gctx->stapi, NULL, NULL, NULL); |
if (ok) |
old_gctx->base.WindowRenderBuffer = EGL_NONE; |
} |
|
if (ok) { |
if (_eglPutContext(old_ctx)) |
destroy_context(dpy, old_ctx); |
if (_eglPutSurface(old_draw)) |
destroy_surface(dpy, old_draw); |
if (_eglPutSurface(old_read)) |
destroy_surface(dpy, old_read); |
} |
else { |
/* undo the previous _eglBindContext */ |
_eglBindContext(old_ctx, old_draw, old_read, &ctx, &draw, &read); |
assert(&gctx->base == ctx && |
&gdraw->base == draw && |
&gread->base == read); |
|
_eglPutSurface(draw); |
_eglPutSurface(read); |
_eglPutContext(ctx); |
|
_eglPutSurface(old_draw); |
_eglPutSurface(old_read); |
_eglPutContext(old_ctx); |
} |
|
return ok; |
} |
|
static EGLBoolean |
swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, |
EGLint num_rects, const EGLint *rects, EGLBoolean preserve) |
{ |
struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); |
_EGLContext *ctx = _eglGetCurrentContext(); |
struct egl_g3d_context *gctx = NULL; |
struct native_present_control ctrl; |
|
/* 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->stvis.render_buffer == ST_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->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL); |
} |
|
memset(&ctrl, 0, sizeof(ctrl)); |
ctrl.natt = NATIVE_ATTACHMENT_BACK_LEFT; |
ctrl.preserve = preserve; |
ctrl.swap_interval = gsurf->base.SwapInterval; |
ctrl.premultiplied_alpha = (gsurf->base.VGAlphaFormat == EGL_VG_ALPHA_FORMAT_PRE); |
ctrl.num_rects = num_rects; |
ctrl.rects = rects; |
|
return gsurf->native->present(gsurf->native, &ctrl); |
} |
|
static EGLBoolean |
egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) |
{ |
struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); |
|
return swap_buffers(drv, dpy, surf, 0, NULL, |
(gsurf->base.SwapBehavior == EGL_BUFFER_PRESERVED)); |
} |
|
#ifdef EGL_NOK_swap_region |
static EGLBoolean |
egl_g3d_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, |
EGLint num_rects, const EGLint *rects) |
{ |
/* Note: y=0=top */ |
return swap_buffers(drv, dpy, surf, num_rects, rects, EGL_TRUE); |
} |
#endif /* EGL_NOK_swap_region */ |
|
static EGLBoolean |
egl_g3d_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, |
EGLint x, EGLint y, EGLint width, EGLint height) |
{ |
EGLint rect[4]; |
|
if (x < 0 || y < 0 || width < 0 || height < 0) |
return _eglError(EGL_BAD_PARAMETER, "eglPostSubBufferNV"); |
|
/* clamp */ |
if (x + width > surf->Width) |
width = surf->Width - x; |
if (y + height > surf->Height) |
height = surf->Height - y; |
|
if (width <= 0 || height <= 0) |
return EGL_TRUE; |
|
rect[0] = x; |
/* Note: y=0=bottom */ |
rect[1] = surf->Height - y - height; |
rect[2] = width; |
rect[3] = height; |
|
return swap_buffers(drv, dpy, surf, 1, rect, EGL_TRUE); |
} |
|
static EGLBoolean |
egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, |
EGLNativePixmapType target) |
{ |
struct egl_g3d_display *gdpy = egl_g3d_display(dpy); |
struct egl_g3d_surface *gsurf = egl_g3d_surface(surf); |
_EGLContext *ctx = _eglGetCurrentContext(); |
|
if (!gsurf->render_texture) |
return EGL_TRUE; |
|
/* flush if the surface is current */ |
if (ctx && ctx->DrawSurface == &gsurf->base) { |
struct egl_g3d_context *gctx = egl_g3d_context(ctx); |
gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL); |
} |
|
return gdpy->native->copy_to_pixmap(gdpy->native, |
target, gsurf->render_texture); |
} |
|
static EGLBoolean |
egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx) |
{ |
struct egl_g3d_display *gdpy = egl_g3d_display(dpy); |
struct egl_g3d_context *gctx = egl_g3d_context(ctx); |
struct pipe_screen *screen = gdpy->native->screen; |
struct pipe_fence_handle *fence = NULL; |
|
gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, &fence); |
if (fence) { |
screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE); |
screen->fence_reference(screen, &fence, NULL); |
} |
|
return EGL_TRUE; |
} |
|
static EGLBoolean |
egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine) |
{ |
_EGLContext *ctx = _eglGetCurrentContext(); |
|
if (engine != EGL_CORE_NATIVE_ENGINE) |
return _eglError(EGL_BAD_PARAMETER, "eglWaitNative"); |
|
if (ctx && ctx->DrawSurface) { |
struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface); |
|
if (gsurf->native) |
gsurf->native->wait(gsurf->native); |
} |
|
return EGL_TRUE; |
} |
|
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 *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API); |
struct egl_g3d_context *gctx; |
enum pipe_format internal_format; |
enum st_texture_type 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: |
internal_format = PIPE_FORMAT_R8G8B8_UNORM; |
break; |
case EGL_TEXTURE_RGBA: |
internal_format = PIPE_FORMAT_B8G8R8A8_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"); |
} |
|
if (!es1) |
return EGL_TRUE; |
if (!gsurf->render_texture) |
return EGL_FALSE; |
|
/* flush properly if the surface is bound */ |
if (gsurf->base.CurrentContext) { |
gctx = egl_g3d_context(gsurf->base.CurrentContext); |
gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL); |
} |
|
gctx = egl_g3d_context(es1); |
if (gctx->stctxi->teximage) { |
if (!gctx->stctxi->teximage(gctx->stctxi, target, |
gsurf->base.MipmapLevel, internal_format, |
gsurf->render_texture, gsurf->base.MipmapTexture)) |
return EGL_FALSE; |
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_texture) { |
_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->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D, |
gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE); |
} |
} |
|
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_create_surface_arg arg; |
|
memset(&arg, 0, sizeof(arg)); |
arg.type = EGL_SCREEN_BIT_MESA; |
|
return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs); |
} |
|
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 */ |
|
#ifdef EGL_WL_bind_wayland_display |
|
static EGLBoolean |
egl_g3d_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *dpy, |
struct wl_display *wl_dpy) |
{ |
struct egl_g3d_display *gdpy = egl_g3d_display(dpy); |
|
if (!gdpy->native->wayland_bufmgr) |
return EGL_FALSE; |
|
return gdpy->native->wayland_bufmgr->bind_display(gdpy->native, wl_dpy); |
} |
|
static EGLBoolean |
egl_g3d_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *dpy, |
struct wl_display *wl_dpy) |
{ |
struct egl_g3d_display *gdpy = egl_g3d_display(dpy); |
|
if (!gdpy->native->wayland_bufmgr) |
return EGL_FALSE; |
|
return gdpy->native->wayland_bufmgr->unbind_display(gdpy->native, wl_dpy); |
} |
|
static EGLBoolean |
egl_g3d_query_wayland_buffer_wl(_EGLDriver *drv, _EGLDisplay *dpy, |
struct wl_buffer *buffer, |
EGLint attribute, EGLint *value) |
{ |
struct egl_g3d_display *gdpy = egl_g3d_display(dpy); |
|
if (!gdpy->native->wayland_bufmgr) |
return EGL_FALSE; |
|
return gdpy->native->wayland_bufmgr->query_buffer(gdpy->native, |
buffer, attribute, value); |
} |
#endif /* EGL_WL_bind_wayland_display */ |
|
void |
egl_g3d_init_driver_api(_EGLDriver *drv) |
{ |
_eglInitDriverFallbacks(drv); |
|
drv->API.ChooseConfig = egl_g3d_choose_config; |
|
drv->API.CreateContext = egl_g3d_create_context; |
drv->API.DestroyContext = egl_g3d_destroy_context; |
drv->API.CreateWindowSurface = egl_g3d_create_window_surface; |
drv->API.CreatePixmapSurface = egl_g3d_create_pixmap_surface; |
drv->API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface; |
drv->API.CreatePbufferFromClientBuffer = egl_g3d_create_pbuffer_from_client_buffer; |
drv->API.DestroySurface = egl_g3d_destroy_surface; |
drv->API.MakeCurrent = egl_g3d_make_current; |
drv->API.SwapBuffers = egl_g3d_swap_buffers; |
drv->API.CopyBuffers = egl_g3d_copy_buffers; |
drv->API.WaitClient = egl_g3d_wait_client; |
drv->API.WaitNative = egl_g3d_wait_native; |
|
drv->API.BindTexImage = egl_g3d_bind_tex_image; |
drv->API.ReleaseTexImage = egl_g3d_release_tex_image; |
|
drv->API.CreateImageKHR = egl_g3d_create_image; |
drv->API.DestroyImageKHR = egl_g3d_destroy_image; |
#ifdef EGL_MESA_drm_image |
drv->API.CreateDRMImageMESA = egl_g3d_create_drm_image; |
drv->API.ExportDRMImageMESA = egl_g3d_export_drm_image; |
#endif |
#ifdef EGL_WL_bind_wayland_display |
drv->API.BindWaylandDisplayWL = egl_g3d_bind_wayland_display_wl; |
drv->API.UnbindWaylandDisplayWL = egl_g3d_unbind_wayland_display_wl; |
drv->API.QueryWaylandBufferWL = egl_g3d_query_wayland_buffer_wl; |
#endif |
|
drv->API.CreateSyncKHR = egl_g3d_create_sync; |
drv->API.DestroySyncKHR = egl_g3d_destroy_sync; |
drv->API.ClientWaitSyncKHR = egl_g3d_client_wait_sync; |
drv->API.SignalSyncKHR = egl_g3d_signal_sync; |
|
#ifdef EGL_MESA_screen_surface |
drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface; |
drv->API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface; |
#endif |
|
#ifdef EGL_NOK_swap_region |
drv->API.SwapBuffersRegionNOK = egl_g3d_swap_buffers_region; |
#endif |
|
drv->API.PostSubBufferNV = egl_g3d_post_sub_buffer; |
} |