diff options
Diffstat (limited to 'src/gallium/state_trackers')
24 files changed, 803 insertions, 74 deletions
diff --git a/src/gallium/state_trackers/dri/common/dri_context.h b/src/gallium/state_trackers/dri/common/dri_context.h index 692c49d7cd..35b870a8a3 100644 --- a/src/gallium/state_trackers/dri/common/dri_context.h +++ b/src/gallium/state_trackers/dri/common/dri_context.h @@ -34,7 +34,6 @@ #include "pipe/p_compiler.h" #include "dri_wrapper.h" -#include "main/mtypes.h" struct pipe_context; struct pipe_fence; diff --git a/src/gallium/state_trackers/dri/common/dri_screen.c b/src/gallium/state_trackers/dri/common/dri_screen.c index 6ad2c7da4d..0ab4dd1893 100644 --- a/src/gallium/state_trackers/dri/common/dri_screen.c +++ b/src/gallium/state_trackers/dri/common/dri_screen.c @@ -383,6 +383,11 @@ dri_init_screen_helper(struct dri_screen *screen, if (!screen->st_api) return NULL; + if(pscreen->get_param(pscreen, PIPE_CAP_NPOT_TEXTURES)) + screen->target = PIPE_TEXTURE_2D; + else + screen->target = PIPE_TEXTURE_RECT; + driParseOptionInfo(&screen->optionCache, __driConfigOptions, __driNConfigOptions); diff --git a/src/gallium/state_trackers/dri/common/dri_screen.h b/src/gallium/state_trackers/dri/common/dri_screen.h index 53ccce145b..849f399b2f 100644 --- a/src/gallium/state_trackers/dri/common/dri_screen.h +++ b/src/gallium/state_trackers/dri/common/dri_screen.h @@ -68,6 +68,7 @@ struct dri_screen boolean d_depth_bits_last; boolean sd_depth_bits_last; boolean auto_fake_front; + enum pipe_texture_target target; }; /** cast wrapper */ diff --git a/src/gallium/state_trackers/dri/drm/dri2.c b/src/gallium/state_trackers/dri/drm/dri2.c index 47005c17e2..93f910a26d 100644 --- a/src/gallium/state_trackers/dri/drm/dri2.c +++ b/src/gallium/state_trackers/dri/drm/dri2.c @@ -195,7 +195,7 @@ dri2_drawable_process_buffers(struct dri_drawable *drawable, pipe_resource_reference(&drawable->textures[i], NULL); memset(&templ, 0, sizeof(templ)); - templ.target = PIPE_TEXTURE_2D; + templ.target = screen->target; templ.last_level = 0; templ.width0 = dri_drawable->w; templ.height0 = dri_drawable->h; @@ -342,7 +342,7 @@ dri2_create_image_from_name(__DRIcontext *context, memset(&templ, 0, sizeof(templ)); templ.bind = tex_usage; templ.format = pf; - templ.target = PIPE_TEXTURE_2D; + templ.target = screen->target; templ.last_level = 0; templ.width0 = width; templ.height0 = height; diff --git a/src/gallium/state_trackers/dri/sw/drisw.c b/src/gallium/state_trackers/dri/sw/drisw.c index 249ccd7fcf..04bba631ae 100644 --- a/src/gallium/state_trackers/dri/sw/drisw.c +++ b/src/gallium/state_trackers/dri/sw/drisw.c @@ -216,7 +216,7 @@ drisw_allocate_textures(struct dri_drawable *drawable, } memset(&templ, 0, sizeof(templ)); - templ.target = PIPE_TEXTURE_2D; + templ.target = screen->target; templ.width0 = width; templ.height0 = height; templ.depth0 = 1; diff --git a/src/gallium/state_trackers/egl/Makefile b/src/gallium/state_trackers/egl/Makefile index 9e9e479e7e..4199d7c6ba 100644 --- a/src/gallium/state_trackers/egl/Makefile +++ b/src/gallium/state_trackers/egl/Makefile @@ -24,7 +24,7 @@ x11_SOURCES = $(wildcard x11/*.c) \ x11_OBJECTS = $(x11_SOURCES:.c=.o) -kms_INCLUDES = $(shell pkg-config --cflags-only-I libdrm) +kms_INCLUDES = -I$(TOP)/src/gallium/winsys $(shell pkg-config --cflags-only-I libdrm) kms_SOURCES = $(wildcard kms/*.c) kms_OBJECTS = $(kms_SOURCES:.c=.o) diff --git a/src/gallium/state_trackers/egl/SConscript b/src/gallium/state_trackers/egl/SConscript index e71aec35b7..efcce25e31 100644 --- a/src/gallium/state_trackers/egl/SConscript +++ b/src/gallium/state_trackers/egl/SConscript @@ -21,6 +21,7 @@ if 'egl' in env['statetrackers']: 'common/egl_g3d_api.c', 'common/egl_g3d_image.c', 'common/egl_g3d_st.c', + 'common/egl_g3d_sync.c', 'common/native_helper.c', ] diff --git a/src/gallium/state_trackers/egl/common/egl_g3d.c b/src/gallium/state_trackers/egl/common/egl_g3d.c index 56d575ffe0..4e653bdf3b 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d.c @@ -530,6 +530,18 @@ egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy, if (gdpy->native->get_param(gdpy->native, NATIVE_PARAM_USE_NATIVE_BUFFER)) dpy->Extensions.KHR_image_pixmap = EGL_TRUE; + dpy->Extensions.KHR_reusable_sync = EGL_TRUE; + dpy->Extensions.KHR_fence_sync = EGL_TRUE; + + dpy->Extensions.KHR_surfaceless_gles1 = EGL_TRUE; + dpy->Extensions.KHR_surfaceless_gles2 = EGL_TRUE; + dpy->Extensions.KHR_surfaceless_opengl = EGL_TRUE; + + if (dpy->Platform == _EGL_PLATFORM_DRM) { + dpy->Extensions.MESA_drm_display = EGL_TRUE; + dpy->Extensions.MESA_drm_image = EGL_TRUE; + } + if (egl_g3d_add_configs(drv, dpy, 1) == 1) { _eglError(EGL_NOT_INITIALIZED, "eglInitialize(unable to add configs)"); goto fail; diff --git a/src/gallium/state_trackers/egl/common/egl_g3d.h b/src/gallium/state_trackers/egl/common/egl_g3d.h index f33dc91cf9..be450bbede 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d.h +++ b/src/gallium/state_trackers/egl/common/egl_g3d.h @@ -30,12 +30,14 @@ #include "pipe/p_screen.h" #include "pipe/p_context.h" #include "pipe/p_format.h" +#include "os/os_thread.h" #include "egldriver.h" #include "egldisplay.h" #include "eglcontext.h" #include "eglsurface.h" #include "eglconfig.h" #include "eglimage.h" +#include "eglsync.h" #include "eglscreen.h" #include "eglmode.h" @@ -99,6 +101,24 @@ struct egl_g3d_image { _EGL_DRIVER_STANDARD_TYPECASTS(egl_g3d) _EGL_DRIVER_TYPECAST(egl_g3d_image, _EGLImage, obj) +#ifdef EGL_KHR_reusable_sync + +struct egl_g3d_sync { + _EGLSync base; + + int refs; + + /* the mutex protects only the condvar, not the struct */ + pipe_mutex mutex; + pipe_condvar condvar; + + /* for fence sync */ + struct pipe_fence_handle *fence; +}; +_EGL_DRIVER_TYPECAST(egl_g3d_sync, _EGLSync, obj) + +#endif /* EGL_KHR_reusable_sync */ + #ifdef EGL_MESA_screen_surface struct egl_g3d_screen { diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_api.c b/src/gallium/state_trackers/egl/common/egl_g3d_api.c index edac72a822..3ec53653f4 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d_api.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d_api.c @@ -34,6 +34,7 @@ #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 "egl_g3d_loader.h" #include "native.h" @@ -103,7 +104,7 @@ egl_g3d_create_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, } gctx->stctxi = gctx->stapi->create_context(gctx->stapi, gdpy->smapi, - &gconf->stvis, (gshare) ? gshare->stctxi : NULL); + (gconf) ? &gconf->stvis : NULL, (gshare) ? gshare->stctxi : NULL); if (!gctx->stctxi) { FREE(gctx); return NULL; @@ -437,16 +438,19 @@ egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy, ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi, (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL); if (ok) { - gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gdraw->stfbi); - if (gread != gdraw) { + if (gdraw) { gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, - gread->stfbi); - } + gdraw->stfbi); - if (gdraw->base.Type == EGL_WINDOW_BIT) { - gctx->base.WindowRenderBuffer = - (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ? - EGL_SINGLE_BUFFER : EGL_BACK_BUFFER; + if (gdraw->base.Type == EGL_WINDOW_BIT) { + gctx->base.WindowRenderBuffer = + (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ? + EGL_SINGLE_BUFFER : EGL_BACK_BUFFER; + } + } + if (gread && gread != gdraw) { + gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, + gread->stfbi); } } } @@ -805,6 +809,17 @@ egl_g3d_init_driver_api(_EGLDriver *drv) 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_KHR_reusable_sync + 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; +#endif #ifdef EGL_MESA_screen_surface drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface; diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_image.c b/src/gallium/state_trackers/egl/common/egl_g3d_image.c index 1e13cfcf7e..558638e72f 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d_image.c +++ b/src/gallium/state_trackers/egl/common/egl_g3d_image.c @@ -31,12 +31,16 @@ #include "util/u_rect.h" #include "util/u_inlines.h" #include "eglcurrent.h" +#include "egllog.h" #include "native.h" #include "egl_g3d.h" #include "egl_g3d_api.h" #include "egl_g3d_image.h" +/* move this to native display? */ +#include "state_tracker/drm_driver.h" + /** * Reference and return the front left buffer of the native pixmap. */ @@ -67,6 +71,165 @@ egl_g3d_reference_native_pixmap(_EGLDisplay *dpy, EGLNativePixmapType pix) return textures[natt]; } +#ifdef EGL_MESA_drm_image + +static struct pipe_resource * +egl_g3d_create_drm_buffer(_EGLDisplay *dpy, const EGLint *attribs) +{ + struct egl_g3d_display *gdpy = egl_g3d_display(dpy); + struct pipe_screen *screen = gdpy->native->screen; + struct pipe_resource templ; + EGLint width = 0, height = 0, format = 0, use = 0; + EGLint valid_use; + EGLint i, err = EGL_SUCCESS; + + for (i = 0; attribs[i] != EGL_NONE; i++) { + EGLint attr = attribs[i++]; + EGLint val = attribs[i]; + + switch (attr) { + case EGL_WIDTH: + width = val; + break; + case EGL_HEIGHT: + height = val; + break; + case EGL_DRM_BUFFER_FORMAT_MESA: + format = val; + break; + case EGL_DRM_BUFFER_USE_MESA: + use = val; + break; + default: + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (err != EGL_SUCCESS) { + _eglLog(_EGL_DEBUG, "bad image attribute 0x%04x", attr); + return NULL; + } + } + + if (width <= 0 || height <= 0) { + _eglLog(_EGL_DEBUG, "bad width or height (%dx%d)", width, height); + return NULL; + } + + switch (format) { + case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: + format = PIPE_FORMAT_B8G8R8A8_UNORM; + break; + default: + _eglLog(_EGL_DEBUG, "bad image format value 0x%04x", format); + return NULL; + break; + } + + valid_use = EGL_DRM_BUFFER_USE_SCANOUT_MESA | + EGL_DRM_BUFFER_USE_SHARE_MESA; + if (use & ~valid_use) { + _eglLog(_EGL_DEBUG, "bad image use bit 0x%04x", use); + return NULL; + } + + memset(&templ, 0, sizeof(templ)); + templ.target = PIPE_TEXTURE_2D; + templ.format = format; + templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; + templ.width0 = width; + templ.height0 = height; + templ.depth0 = 1; + + /* + * XXX fix apps (e.g. wayland) and pipe drivers (e.g. i915) and remove the + * size check + */ + if ((use & EGL_DRM_BUFFER_USE_SCANOUT_MESA) && + width >= 640 && height >= 480) + templ.bind |= PIPE_BIND_SCANOUT; + if (use & EGL_DRM_BUFFER_USE_SHARE_MESA) + templ.bind |= PIPE_BIND_SHARED; + + return screen->resource_create(screen, &templ); +} + +static struct pipe_resource * +egl_g3d_reference_drm_buffer(_EGLDisplay *dpy, EGLint name, + const EGLint *attribs) +{ + struct egl_g3d_display *gdpy = egl_g3d_display(dpy); + struct pipe_screen *screen = gdpy->native->screen; + struct pipe_resource templ; + struct winsys_handle wsh; + EGLint width = 0, height = 0, format = 0, stride = 0; + EGLint i, err = EGL_SUCCESS; + + /* winsys_handle is in theory platform-specific */ + if (dpy->Platform != _EGL_PLATFORM_DRM) + return NULL; + + for (i = 0; attribs[i] != EGL_NONE; i++) { + EGLint attr = attribs[i++]; + EGLint val = attribs[i]; + + switch (attr) { + case EGL_WIDTH: + width = val; + break; + case EGL_HEIGHT: + height = val; + break; + case EGL_DRM_BUFFER_FORMAT_MESA: + format = val; + break; + case EGL_DRM_BUFFER_STRIDE_MESA: + stride = val; + break; + default: + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (err != EGL_SUCCESS) { + _eglLog(_EGL_DEBUG, "bad image attribute 0x%04x", attr); + return NULL; + } + } + + if (width <= 0 || height <= 0 || stride <= 0) { + _eglLog(_EGL_DEBUG, "bad width, height, or stride (%dx%dx%d)", + width, height, stride); + return NULL; + } + + switch (format) { + case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: + format = PIPE_FORMAT_B8G8R8A8_UNORM; + break; + default: + _eglLog(_EGL_DEBUG, "bad image format value 0x%04x", format); + return NULL; + break; + } + + memset(&templ, 0, sizeof(templ)); + templ.target = PIPE_TEXTURE_2D; + templ.format = format; + templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; + templ.width0 = width; + templ.height0 = height; + templ.depth0 = 1; + + memset(&wsh, 0, sizeof(wsh)); + wsh.handle = (unsigned) name; + wsh.stride = stride; + + return screen->resource_from_handle(screen, &templ, &wsh); +} + +#endif /* EGL_MESA_drm_image */ + _EGLImage * egl_g3d_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, EGLenum target, EGLClientBuffer buffer, @@ -92,6 +255,11 @@ egl_g3d_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, ptex = egl_g3d_reference_native_pixmap(dpy, (EGLNativePixmapType) buffer); break; +#ifdef EGL_MESA_drm_image + case EGL_DRM_BUFFER_MESA: + ptex = egl_g3d_reference_drm_buffer(dpy, (EGLint) buffer, attribs); + break; +#endif default: ptex = NULL; break; @@ -134,3 +302,80 @@ egl_g3d_destroy_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img) return EGL_TRUE; } + +_EGLImage * +egl_g3d_create_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, + const EGLint *attribs) +{ + struct egl_g3d_image *gimg; + struct pipe_resource *ptex; + + gimg = CALLOC_STRUCT(egl_g3d_image); + if (!gimg) { + _eglError(EGL_BAD_ALLOC, "eglCreateDRMImageKHR"); + return NULL; + } + + if (!_eglInitImage(&gimg->base, dpy, attribs)) { + FREE(gimg); + return NULL; + } + +#ifdef EGL_MESA_drm_image + ptex = egl_g3d_create_drm_buffer(dpy, attribs); +#else + ptex = NULL; +#endif + if (!ptex) { + FREE(gimg); + return NULL; + } + + /* transfer the ownership to the image */ + gimg->texture = ptex; + gimg->face = 0; + gimg->level = 0; + gimg->zslice = 0; + + return &gimg->base; +} + +EGLBoolean +egl_g3d_export_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img, + EGLint *name, EGLint *handle, EGLint *stride) +{ + struct egl_g3d_display *gdpy = egl_g3d_display(dpy); + struct egl_g3d_image *gimg = egl_g3d_image(img); + struct pipe_screen *screen = gdpy->native->screen; + struct winsys_handle wsh; + + /* winsys_handle is in theory platform-specific */ + if (dpy->Platform != _EGL_PLATFORM_DRM) + return EGL_FALSE; + + /* get shared handle */ + if (name) { + memset(&handle, 0, sizeof(handle)); + wsh.type = DRM_API_HANDLE_TYPE_SHARED; + if (!screen->resource_get_handle(screen, gimg->texture, &wsh)) { + return EGL_FALSE; + } + + *name = wsh.handle; + } + + /* get KMS handle */ + if (handle || stride) { + memset(&wsh, 0, sizeof(wsh)); + wsh.type = DRM_API_HANDLE_TYPE_KMS; + if (!screen->resource_get_handle(screen, gimg->texture, &wsh)) + return EGL_FALSE; + + if (handle) + *handle = wsh.handle; + if (stride) + *stride = wsh.stride; + } + + return EGL_TRUE; +} diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_image.h b/src/gallium/state_trackers/egl/common/egl_g3d_image.h index adda933371..f051da8283 100644 --- a/src/gallium/state_trackers/egl/common/egl_g3d_image.h +++ b/src/gallium/state_trackers/egl/common/egl_g3d_image.h @@ -39,4 +39,12 @@ egl_g3d_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, EGLBoolean egl_g3d_destroy_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *image); +_EGLImage * +egl_g3d_create_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, + const EGLint *attribs); + +EGLBoolean +egl_g3d_export_drm_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLImage *img, + EGLint *name, EGLint *handle, EGLint *stride); + #endif /* _EGL_G3D_IMAGE_H_ */ diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_sync.c b/src/gallium/state_trackers/egl/common/egl_g3d_sync.c new file mode 100644 index 0000000000..ec74e9eb94 --- /dev/null +++ b/src/gallium/state_trackers/egl/common/egl_g3d_sync.c @@ -0,0 +1,284 @@ +/* + * Mesa 3-D graphics library + * Version: 7.9 + * + * Copyright (C) 2010 LunarG Inc. + * + * 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. + * + * Authors: + * Chia-I Wu <olv@lunarg.com> + */ + +#include "util/u_memory.h" +#include "util/u_atomic.h" +#include "os/os_thread.h" +#include "eglsync.h" +#include "eglcurrent.h" + +#include "egl_g3d.h" +#include "egl_g3d_sync.h" + +#ifdef EGL_KHR_reusable_sync + +/** + * Wait for the conditional variable. + */ +static EGLint +egl_g3d_wait_sync_condvar(struct egl_g3d_sync *gsync, EGLTimeKHR timeout) +{ + _EGLDisplay *dpy = gsync->base.Resource.Display; + + pipe_mutex_lock(gsync->mutex); + + /* unlock display lock just before waiting */ + _eglUnlockMutex(&dpy->Mutex); + + /* No timed wait. Always treat timeout as EGL_FOREVER_KHR */ + pipe_condvar_wait(gsync->condvar, gsync->mutex); + + _eglLockMutex(&dpy->Mutex); + + pipe_mutex_unlock(gsync->mutex); + + return EGL_CONDITION_SATISFIED_KHR; +} + +/** + * Signal the conditional variable. + */ +static void +egl_g3d_signal_sync_condvar(struct egl_g3d_sync *gsync) +{ + pipe_mutex_lock(gsync->mutex); + pipe_condvar_broadcast(gsync->condvar); + pipe_mutex_unlock(gsync->mutex); +} + +/** + * Insert a fence command to the command stream of the current context. + */ +static EGLint +egl_g3d_insert_fence_sync(struct egl_g3d_sync *gsync) +{ + _EGLContext *ctx = _eglGetCurrentContext(); + struct egl_g3d_context *gctx = egl_g3d_context(ctx); + + /* already checked in egl_g3d_create_sync */ + assert(gctx); + + /* insert the fence command */ + gctx->stctxi->flush(gctx->stctxi, 0x0, &gsync->fence); + if (!gsync->fence) + gsync->base.SyncStatus = EGL_SIGNALED_KHR; + + return EGL_SUCCESS; +} + +/** + * Wait for the fence sync to be signaled. + */ +static EGLint +egl_g3d_wait_fence_sync(struct egl_g3d_sync *gsync, EGLTimeKHR timeout) +{ + EGLint ret; + + if (gsync->fence) { + _EGLDisplay *dpy = gsync->base.Resource.Display; + struct egl_g3d_display *gdpy = egl_g3d_display(dpy); + struct pipe_screen *screen = gdpy->native->screen; + struct pipe_fence_handle *fence = gsync->fence; + + gsync->fence = NULL; + + _eglUnlockMutex(&dpy->Mutex); + /* no timed finish? */ + screen->fence_finish(screen, fence, 0x0); + ret = EGL_CONDITION_SATISFIED_KHR; + _eglLockMutex(&dpy->Mutex); + + gsync->base.SyncStatus = EGL_SIGNALED_KHR; + + screen->fence_reference(screen, &fence, NULL); + egl_g3d_signal_sync_condvar(gsync); + } + else { + ret = egl_g3d_wait_sync_condvar(gsync, timeout); + } + + return ret; +} + +static INLINE void +egl_g3d_ref_sync(struct egl_g3d_sync *gsync) +{ + p_atomic_inc(&gsync->refs); +} + +static INLINE void +egl_g3d_unref_sync(struct egl_g3d_sync *gsync) +{ + if (p_atomic_dec_zero(&gsync->refs)) { + pipe_condvar_destroy(gsync->condvar); + pipe_mutex_destroy(gsync->mutex); + + if (gsync->fence) { + struct egl_g3d_display *gdpy = + egl_g3d_display(gsync->base.Resource.Display); + struct pipe_screen *screen = gdpy->native->screen; + + screen->fence_reference(screen, &gsync->fence, NULL); + } + + FREE(gsync); + } +} + +_EGLSync * +egl_g3d_create_sync(_EGLDriver *drv, _EGLDisplay *dpy, + EGLenum type, const EGLint *attrib_list) +{ + _EGLContext *ctx = _eglGetCurrentContext(); + struct egl_g3d_sync *gsync; + EGLint err; + + if (!ctx || ctx->Resource.Display != dpy) { + _eglError(EGL_BAD_MATCH, "eglCreateSyncKHR"); + return NULL; + } + + gsync = CALLOC_STRUCT(egl_g3d_sync); + if (!gsync) { + _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR"); + return NULL; + } + + if (!_eglInitSync(&gsync->base, dpy, type, attrib_list)) { + FREE(gsync); + return NULL; + } + + switch (type) { + case EGL_SYNC_REUSABLE_KHR: + err = EGL_SUCCESS; + break; + case EGL_SYNC_FENCE_KHR: + err = egl_g3d_insert_fence_sync(gsync); + break; + default: + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (err != EGL_SUCCESS) { + _eglError(err, "eglCreateSyncKHR"); + FREE(gsync); + return NULL; + } + + pipe_mutex_init(gsync->mutex); + pipe_condvar_init(gsync->condvar); + p_atomic_set(&gsync->refs, 1); + + return &gsync->base; +} + +EGLBoolean +egl_g3d_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) +{ + struct egl_g3d_sync *gsync = egl_g3d_sync(sync); + + switch (gsync->base.Type) { + case EGL_SYNC_REUSABLE_KHR: + /* signal the waiters */ + if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) { + gsync->base.SyncStatus = EGL_SIGNALED_KHR; + egl_g3d_signal_sync_condvar(gsync); + } + break; + default: + break; + } + + egl_g3d_unref_sync(gsync); + + return EGL_TRUE; +} + +EGLint +egl_g3d_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLint flags, EGLTimeKHR timeout) +{ + struct egl_g3d_sync *gsync = egl_g3d_sync(sync); + EGLint ret = EGL_CONDITION_SATISFIED_KHR; + + if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) { + /* flush if there is a current context */ + if (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) { + _EGLContext *ctx = _eglGetCurrentContext(); + struct egl_g3d_context *gctx = egl_g3d_context(ctx); + + if (gctx) + gctx->stctxi->flush(gctx->stctxi, PIPE_FLUSH_RENDER_CACHE , NULL); + } + + if (timeout) { + /* reference the sync object in case it is destroyed while waiting */ + egl_g3d_ref_sync(gsync); + + switch (gsync->base.Type) { + case EGL_SYNC_REUSABLE_KHR: + ret = egl_g3d_wait_sync_condvar(gsync, timeout); + break; + case EGL_SYNC_FENCE_KHR: + ret = egl_g3d_wait_fence_sync(gsync, timeout); + default: + break; + } + + egl_g3d_unref_sync(gsync); + } + else { + ret = EGL_TIMEOUT_EXPIRED_KHR; + } + } + + return ret; +} + +EGLBoolean +egl_g3d_signal_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLenum mode) +{ + struct egl_g3d_sync *gsync = egl_g3d_sync(sync); + + /* only for reusable sync */ + if (sync->Type != EGL_SYNC_REUSABLE_KHR) + return _eglError(EGL_BAD_MATCH, "eglSignalSyncKHR"); + + if (gsync->base.SyncStatus != mode) { + gsync->base.SyncStatus = mode; + if (mode == EGL_SIGNALED_KHR) + egl_g3d_signal_sync_condvar(gsync); + } + + return EGL_TRUE; +} + +#endif /* EGL_KHR_reusable_sync */ diff --git a/src/gallium/state_trackers/egl/common/egl_g3d_sync.h b/src/gallium/state_trackers/egl/common/egl_g3d_sync.h new file mode 100644 index 0000000000..3179ca04e1 --- /dev/null +++ b/src/gallium/state_trackers/egl/common/egl_g3d_sync.h @@ -0,0 +1,53 @@ +/* + * Mesa 3-D graphics library + * Version: 7.9 + * + * Copyright (C) 2010 LunarG Inc. + * + * 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. + * + * Authors: + * Chia-I Wu <olv@lunarg.com> + */ + +#ifndef _EGL_G3D_SYNC_H_ +#define _EGL_G3D_SYNC_H_ + +#include "egl_g3d.h" + +#ifdef EGL_KHR_reusable_sync + +_EGLSync * +egl_g3d_create_sync(_EGLDriver *drv, _EGLDisplay *dpy, + EGLenum type, const EGLint *attrib_list); + +EGLBoolean +egl_g3d_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync); + +EGLint +egl_g3d_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLint flags, EGLTimeKHR timeout); + +EGLBoolean +egl_g3d_signal_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLenum mode); + +#endif /* EGL_KHR_reusable_sync */ + +#endif /* _EGL_G3D_SYNC_H_ */ diff --git a/src/gallium/state_trackers/egl/kms/native_kms.c b/src/gallium/state_trackers/egl/kms/native_kms.c index d4e8fbc913..208f73306c 100644 --- a/src/gallium/state_trackers/egl/kms/native_kms.c +++ b/src/gallium/state_trackers/egl/kms/native_kms.c @@ -38,6 +38,10 @@ #include "native_kms.h" +/* see get_drm_screen_name */ +#include <radeon_drm.h> +#include "radeon/drm/radeon_drm.h" + static boolean kms_surface_validate(struct native_surface *nsurf, uint attachment_mask, unsigned int *seq_num, struct pipe_resource **textures, @@ -584,7 +588,9 @@ kms_display_get_configs(struct native_display *ndpy, int *num_configs) nconf->color_format = format; - nconf->scanout_bit = TRUE; + /* support KMS */ + if (kdpy->resources) + nconf->scanout_bit = TRUE; } configs = MALLOC(sizeof(*configs)); @@ -664,6 +670,27 @@ kms_display_destroy(struct native_display *ndpy) FREE(kdpy); } +static const char * +get_drm_screen_name(int fd, drmVersionPtr version) +{ + const char *name = version->name; + + if (name && !strcmp(name, "radeon")) { + int chip_id; + struct drm_radeon_info info; + + memset(&info, 0, sizeof(info)); + info.request = RADEON_INFO_DEVICE_ID; + info.value = pointer_to_intptr(&chip_id); + if (drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info)) != 0) + return NULL; + + name = is_r3xx(chip_id) ? "r300" : "r600"; + } + + return name; +} + /** * Initialize KMS and pipe screen. */ @@ -672,6 +699,7 @@ kms_display_init_screen(struct native_display *ndpy) { struct kms_display *kdpy = kms_display(ndpy); drmVersionPtr version; + const char *name; version = drmGetVersion(kdpy->fd); if (!version) { @@ -679,8 +707,11 @@ kms_display_init_screen(struct native_display *ndpy) return FALSE; } - kdpy->base.screen = kdpy->event_handler->new_drm_screen(&kdpy->base, - version->name, kdpy->fd);; + name = get_drm_screen_name(kdpy->fd, version); + if (name) { + kdpy->base.screen = + kdpy->event_handler->new_drm_screen(&kdpy->base, name, kdpy->fd); + } drmFreeVersion(version); if (!kdpy->base.screen) { @@ -717,32 +748,32 @@ kms_create_display(int fd, struct native_event_handler *event_handler, return NULL; } + kdpy->base.destroy = kms_display_destroy; + kdpy->base.get_param = kms_display_get_param; + kdpy->base.get_configs = kms_display_get_configs; + /* resources are fixed, unlike crtc, connector, or encoder */ kdpy->resources = drmModeGetResources(kdpy->fd); - if (!kdpy->resources) { - kms_display_destroy(&kdpy->base); - return NULL; - } + if (kdpy->resources) { + kdpy->saved_crtcs = + CALLOC(kdpy->resources->count_crtcs, sizeof(*kdpy->saved_crtcs)); + if (!kdpy->saved_crtcs) { + kms_display_destroy(&kdpy->base); + return NULL; + } - kdpy->saved_crtcs = - CALLOC(kdpy->resources->count_crtcs, sizeof(*kdpy->saved_crtcs)); - if (!kdpy->saved_crtcs) { - kms_display_destroy(&kdpy->base); - return NULL; - } + kdpy->shown_surfaces = + CALLOC(kdpy->resources->count_crtcs, sizeof(*kdpy->shown_surfaces)); + if (!kdpy->shown_surfaces) { + kms_display_destroy(&kdpy->base); + return NULL; + } - kdpy->shown_surfaces = - CALLOC(kdpy->resources->count_crtcs, sizeof(*kdpy->shown_surfaces)); - if (!kdpy->shown_surfaces) { - kms_display_destroy(&kdpy->base); - return NULL; + kdpy->base.modeset = &kms_display_modeset; + } + else { + _eglLog(_EGL_DEBUG, "Failed to get KMS resources. Disable modeset."); } - - kdpy->base.destroy = kms_display_destroy; - kdpy->base.get_param = kms_display_get_param; - kdpy->base.get_configs = kms_display_get_configs; - - kdpy->base.modeset = &kms_display_modeset; return &kdpy->base; } diff --git a/src/gallium/state_trackers/glx/xlib/glx_api.c b/src/gallium/state_trackers/glx/xlib/glx_api.c index eb8d6a1933..dcd50e19d7 100644 --- a/src/gallium/state_trackers/glx/xlib/glx_api.c +++ b/src/gallium/state_trackers/glx/xlib/glx_api.c @@ -34,10 +34,6 @@ #include "GL/glx.h" #include "xm_api.h" -#include "main/context.h" -#include "main/macros.h" -#include "main/imports.h" -#include "main/version.h" /* This indicates the client-side GLX API and GLX encoder version. */ @@ -603,8 +599,8 @@ destroy_visuals_on_display(Display *dpy) static int close_display_callback(Display *dpy, XExtCodes *codes) { - destroy_visuals_on_display(dpy); xmesa_destroy_buffers_on_display(dpy); + destroy_visuals_on_display(dpy); return 0; } @@ -1299,7 +1295,7 @@ glXCopyContext( Display *dpy, GLXContext src, GLXContext dst, XMesaContext xm_dst = dst->xmesaContext; (void) dpy; if (MakeCurrent_PrevContext == src) { - _mesa_Flush(); + glFlush(); } XMesaCopyContext(xm_src, xm_dst, mask); } diff --git a/src/gallium/state_trackers/glx/xlib/glx_usefont.c b/src/gallium/state_trackers/glx/xlib/glx_usefont.c index 8903b0e6cb..0aa37e150b 100644 --- a/src/gallium/state_trackers/glx/xlib/glx_usefont.c +++ b/src/gallium/state_trackers/glx/xlib/glx_usefont.c @@ -30,8 +30,7 @@ */ -#include "main/context.h" -#include "main/imports.h" +#include "main/core.h" #include <GL/glx.h> diff --git a/src/gallium/state_trackers/glx/xlib/xm_api.c b/src/gallium/state_trackers/glx/xlib/xm_api.c index c0c418306f..eb4ce74266 100644 --- a/src/gallium/state_trackers/glx/xlib/xm_api.c +++ b/src/gallium/state_trackers/glx/xlib/xm_api.c @@ -56,7 +56,6 @@ #include "xm_api.h" #include "xm_st.h" -#include "main/context.h" #include "pipe/p_defines.h" #include "pipe/p_screen.h" #include "pipe/p_context.h" @@ -72,10 +71,35 @@ static struct xm_driver driver; static struct st_api *stapi; +/* Default strict invalidate to false. This means we will not call + * XGetGeometry after every swapbuffers, which allows swapbuffers to + * remain asynchronous. For apps running at 100fps with synchronous + * swapping, a 10% boost is typical. For gears, I see closer to 20% + * speedup. + * + * Note that the work of copying data on swapbuffers doesn't disappear + * - this change just allows the X server to execute the PutImage + * asynchronously without us effectively blocked until its completion. + * + * This speeds up even llvmpipe's threaded rasterization as the + * swapbuffers operation was a large part of the serial component of + * an llvmpipe frame. + * + * The downside of this is correctness - applications which don't call + * glViewport on window resizes will get incorrect rendering. A + * better solution would be to have per-frame but asynchronous + * invalidation. Xcb almost looks as if it could provide this, but + * the API doesn't seem to quite be there. + */ +boolean xmesa_strict_invalidate = FALSE; + void xmesa_set_driver( const struct xm_driver *templ ) { driver = *templ; stapi = driver.create_st_api(); + + xmesa_strict_invalidate = + debug_get_bool_option("XMESA_STRICT_INVALIDATE", FALSE); } @@ -91,7 +115,12 @@ static int xmesa_get_param(struct st_manager *smapi, enum st_manager_param param) { - return 0; + switch(param) { + case ST_MANAGER_BROKEN_INVALIDATE: + return !xmesa_strict_invalidate; + default: + return 0; + } } static XMesaDisplay @@ -263,7 +292,6 @@ xmesa_get_window_size(Display *dpy, XMesaBuffer b, Status stat; pipe_mutex_lock(xmdpy->mutex); - XSync(b->xm_visual->display, 0); /* added for Chromium */ stat = get_drawable_size(dpy, b->ws.drawable, width, height); pipe_mutex_unlock(xmdpy->mutex); @@ -726,15 +754,39 @@ XMesaVisual XMesaCreateVisual( Display *display, alpha_bits = v->mesa_visual.alphaBits; } - _mesa_initialize_visual( &v->mesa_visual, - db_flag, stereo_flag, - red_bits, green_bits, - blue_bits, alpha_bits, - depth_size, - stencil_size, - accum_red_size, accum_green_size, - accum_blue_size, accum_alpha_size, - 0 ); + /* initialize visual */ + { + __GLcontextModes *vis = &v->mesa_visual; + + vis->rgbMode = GL_TRUE; + vis->doubleBufferMode = db_flag; + vis->stereoMode = stereo_flag; + + vis->redBits = red_bits; + vis->greenBits = green_bits; + vis->blueBits = blue_bits; + vis->alphaBits = alpha_bits; + vis->rgbBits = red_bits + green_bits + blue_bits; + + vis->indexBits = 0; + vis->depthBits = depth_size; + vis->stencilBits = stencil_size; + + vis->accumRedBits = accum_red_size; + vis->accumGreenBits = accum_green_size; + vis->accumBlueBits = accum_blue_size; + vis->accumAlphaBits = accum_alpha_size; + + vis->haveAccumBuffer = accum_red_size > 0; + vis->haveDepthBuffer = depth_size > 0; + vis->haveStencilBuffer = stencil_size > 0; + + vis->numAuxBuffers = 0; + vis->level = 0; + vis->pixmapMode = 0; + vis->sampleBuffers = 0; + vis->samples = 0; + } v->stvis.buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK; if (db_flag) @@ -1154,7 +1206,7 @@ void XMesaFlush( XMesaContext c ) xmdpy->screen->fence_finish(xmdpy->screen, fence, 0); xmdpy->screen->fence_reference(xmdpy->screen, &fence, NULL); } - XSync( c->xm_visual->display, False ); + XFlush( c->xm_visual->display ); } } diff --git a/src/gallium/state_trackers/glx/xlib/xm_api.h b/src/gallium/state_trackers/glx/xlib/xm_api.h index 4f2c8a6e6a..f209b14ea1 100644 --- a/src/gallium/state_trackers/glx/xlib/xm_api.h +++ b/src/gallium/state_trackers/glx/xlib/xm_api.h @@ -57,7 +57,7 @@ and create a window, you must do the following to use the X/Mesa interface: #define XMESA_H -#include "main/mtypes.h" +#include "main/core.h" /* for GLvisual and MESA_VERSION_STRING */ #include "state_tracker/st_api.h" #include "os/os_thread.h" @@ -378,6 +378,6 @@ xmesa_buffer_height(XMesaBuffer b) return b->height; } - +extern boolean xmesa_strict_invalidate; #endif diff --git a/src/gallium/state_trackers/glx/xlib/xm_st.c b/src/gallium/state_trackers/glx/xlib/xm_st.c index c62eb8bfbd..0f74b3f7aa 100644 --- a/src/gallium/state_trackers/glx/xlib/xm_st.c +++ b/src/gallium/state_trackers/glx/xlib/xm_st.c @@ -26,18 +26,18 @@ * Chia-I Wu <olv@lunarg.com> */ -#include "util/u_memory.h" -#include "util/u_inlines.h" - #include "xm_api.h" #include "xm_st.h" +#include "util/u_inlines.h" + struct xmesa_st_framebuffer { XMesaDisplay display; XMesaBuffer buffer; struct pipe_screen *screen; struct st_visual stvis; + enum pipe_texture_target target; unsigned texture_width, texture_height, texture_mask; struct pipe_resource *textures[ST_ATTACHMENT_COUNT]; @@ -139,7 +139,7 @@ xmesa_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi, } memset(&templ, 0, sizeof(templ)); - templ.target = PIPE_TEXTURE_2D; + templ.target = xstfb->target; templ.width0 = width; templ.height0 = height; templ.depth0 = 1; @@ -210,6 +210,12 @@ xmesa_st_framebuffer_validate(struct st_framebuffer_iface *stfbi, /* record newly allocated textures */ new_mask = statt_mask & ~xstfb->texture_mask; + /* If xmesa_strict_invalidate is not set, we will not yet have + * called XGetGeometry(). Do so here: + */ + if (!xmesa_strict_invalidate) + xmesa_check_buffer_size(xstfb->buffer); + resized = (xstfb->buffer->width != xstfb->texture_width || xstfb->buffer->height != xstfb->texture_height); @@ -251,7 +257,8 @@ xmesa_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi, boolean ret; ret = xmesa_st_framebuffer_display(stfbi, statt); - if (ret) + + if (ret && xmesa_strict_invalidate) xmesa_check_buffer_size(xstfb->buffer); return ret; @@ -279,6 +286,10 @@ xmesa_create_st_framebuffer(XMesaDisplay xmdpy, XMesaBuffer b) xstfb->buffer = b; xstfb->screen = xmdpy->screen; xstfb->stvis = b->xm_visual->stvis; + if(xstfb->screen->get_param(xstfb->screen, PIPE_CAP_NPOT_TEXTURES)) + xstfb->target = PIPE_TEXTURE_2D; + else + xstfb->target = PIPE_TEXTURE_RECT; stfbi->visual = &xstfb->stvis; stfbi->flush_front = xmesa_st_framebuffer_flush_front; @@ -322,7 +333,8 @@ xmesa_swap_st_framebuffer(struct st_framebuffer_iface *stfbi) *back = tmp; } - xmesa_check_buffer_size(xstfb->buffer); + if (xmesa_strict_invalidate) + xmesa_check_buffer_size(xstfb->buffer); } } diff --git a/src/gallium/state_trackers/wgl/stw_context.c b/src/gallium/state_trackers/wgl/stw_context.c index 0fb7cd8306..a0e14b9601 100644 --- a/src/gallium/state_trackers/wgl/stw_context.c +++ b/src/gallium/state_trackers/wgl/stw_context.c @@ -33,7 +33,7 @@ /* for _mesa_share_state */ #include "state_tracker/st_context.h" -#include "main/context.h" +#include "main/core.h" #include "stw_icd.h" #include "stw_device.h" diff --git a/src/gallium/state_trackers/wgl/stw_device.c b/src/gallium/state_trackers/wgl/stw_device.c index a107c71bda..37809d084c 100644 --- a/src/gallium/state_trackers/wgl/stw_device.c +++ b/src/gallium/state_trackers/wgl/stw_device.c @@ -27,7 +27,7 @@ #include <windows.h> -#include "glapi/glthread.h" +#include "glapi/glapi.h" #include "util/u_debug.h" #include "util/u_math.h" #include "util/u_memory.h" diff --git a/src/gallium/state_trackers/wgl/stw_pixelformat.c b/src/gallium/state_trackers/wgl/stw_pixelformat.c index e606477e97..18ac482369 100644 --- a/src/gallium/state_trackers/wgl/stw_pixelformat.c +++ b/src/gallium/state_trackers/wgl/stw_pixelformat.c @@ -25,15 +25,13 @@ * **************************************************************************/ -#include "main/mtypes.h" -#include "main/context.h" - #include "pipe/p_format.h" #include "pipe/p_defines.h" #include "pipe/p_screen.h" #include "util/u_format.h" #include "util/u_debug.h" +#include "util/u_memory.h" #include "stw_icd.h" #include "stw_device.h" diff --git a/src/gallium/state_trackers/wgl/stw_pixelformat.h b/src/gallium/state_trackers/wgl/stw_pixelformat.h index d405172773..282c9f643c 100644 --- a/src/gallium/state_trackers/wgl/stw_pixelformat.h +++ b/src/gallium/state_trackers/wgl/stw_pixelformat.h @@ -34,8 +34,6 @@ #define PFD_SUPPORT_COMPOSITION 0x00008000 #endif -#include "main/mtypes.h" - #include "pipe/p_compiler.h" #include "pipe/p_format.h" #include "state_tracker/st_api.h" |