From: Ander Conselvan de Oliveira <ander.conselvan.de.olive...@intel.com>
--- src/egl/drivers/dri2/egl_dri2.h | 18 ++ src/egl/drivers/dri2/platform_drm.c | 342 ++++++++++++++++++++++++++++++++++- src/gbm/backends/dri/gbm_dri.c | 62 ++++++- src/gbm/backends/dri/gbm_driint.h | 1 + 4 files changed, 420 insertions(+), 3 deletions(-) diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index 84ea0b6..fc31364 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -145,6 +145,15 @@ enum wayland_buffer_type { }; #endif +#ifdef HAVE_DRM_PLATFORM +enum drm_buffer_type { + DRM_BUFFER_FRONT, + DRM_BUFFER_BACK, + DRM_BUFFER_THIRD, + DRM_BUFFER_COUNT +}; +#endif + struct dri2_egl_surface { _EGLSurface base; @@ -177,6 +186,15 @@ struct dri2_egl_surface int format; #endif +#ifdef HAVE_DRM_PLATFORM + struct gbm_dri_surface *gbm_surf; + int drm_buffer_lock[DRM_BUFFER_COUNT]; +#ifndef HAVE_WAYLAND_PLATFORM + __DRIbuffer *dri_buffers[__DRI_BUFFER_COUNT]; + __DRIbuffer *third_buffer; +#endif +#endif + #ifdef HAVE_ANDROID_PLATFORM struct ANativeWindow *window; struct ANativeWindowBuffer *buffer; diff --git a/src/egl/drivers/dri2/platform_drm.c b/src/egl/drivers/dri2/platform_drm.c index bd3d1e0..b16bc42 100644 --- a/src/egl/drivers/dri2/platform_drm.c +++ b/src/egl/drivers/dri2/platform_drm.c @@ -37,6 +37,339 @@ #include "egl_dri2.h" +static __DRIbuffer * +get_front_buffer(struct gbm_dri_surface *surf, void *data) +{ + struct dri2_egl_surface *dri2_surf = data; + + (void) surf; + + dri2_surf->drm_buffer_lock[DRM_BUFFER_FRONT]++; + return dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]; +} + +static void +release_buffer(struct gbm_dri_surface *surf, __DRIbuffer *buffer, void *data) +{ + struct dri2_egl_surface *dri2_surf = data; + + if (buffer == NULL) + return; + + if (buffer == dri2_surf->third_buffer) + dri2_surf->drm_buffer_lock[DRM_BUFFER_THIRD]--; + else if (buffer->attachment == __DRI_BUFFER_FRONT_LEFT) + dri2_surf->drm_buffer_lock[DRM_BUFFER_FRONT]--; + else if (buffer->attachment == __DRI_BUFFER_BACK_LEFT) + dri2_surf->drm_buffer_lock[DRM_BUFFER_BACK]--; + +} + +static _EGLSurface * +dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, + _EGLConfig *conf, EGLNativeWindowType window, + const EGLint *attrib_list) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); + struct dri2_egl_surface *dri2_surf; + struct dri2_egl_buffer *dri2_buf; + struct gbm_dri_surface *surf; + int i; + + (void) drv; + + dri2_surf = malloc(sizeof *dri2_surf); + if (!dri2_surf) { + _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); + return NULL; + } + + if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list)) + goto cleanup_surf; + + for (i = 0; i < __DRI_BUFFER_COUNT; ++i) + dri2_surf->dri_buffers[i] = NULL; + + dri2_surf->third_buffer = NULL; + + switch (type) { + case EGL_WINDOW_BIT: + surf = gbm_dri_surface((struct gbm_surface *) window); + dri2_surf->gbm_surf = surf; + + dri2_surf->base.Width = surf->base.width; + dri2_surf->base.Height = surf->base.height; + + surf->get_front_buffer = get_front_buffer; + surf->release_buffer = release_buffer; + surf->dri_private = dri2_surf; + + break; + default: + goto cleanup_surf; + } + + dri2_surf->dri_drawable = + (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen, + dri2_conf->dri_double_config, + dri2_surf->gbm_surf); + + if (dri2_surf->dri_drawable == NULL) { + _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable"); + goto cleanup_surf; + } + + return &dri2_surf->base; + + cleanup_surf: + free(dri2_surf); + + return NULL; +} + +static _EGLSurface * +dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, + _EGLConfig *conf, EGLNativeWindowType window, + const EGLint *attrib_list) +{ + return dri2_create_surface(drv, disp, EGL_WINDOW_BIT, conf, + window, attrib_list); +} + +static EGLBoolean +dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + int i; + + if (!_eglPutSurface(surf)) + return EGL_TRUE; + + (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable); + + for (i = 0; i < __DRI_BUFFER_COUNT; i++) + if (dri2_surf->dri_buffers[i]) + dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, + dri2_surf->dri_buffers[i]); + + free(surf); + + return EGL_TRUE; +} + +static void +dri2_process_back_buffer(struct dri2_egl_surface *dri2_surf, unsigned format) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + + (void) format; + + switch (dri2_surf->base.Type) { + case EGL_WINDOW_BIT: + /* allocate a front buffer for our double-buffered window*/ + if (dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] != NULL) + break; + dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] = + dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, + __DRI_BUFFER_FRONT_LEFT, format, + dri2_surf->base.Width, dri2_surf->base.Height); + break; + default: + break; + } +} + +static inline void +pointer_swap(const void **p1, const void **p2) +{ + const void *tmp = *p1; + *p1 = *p2; + *p2 = tmp; +} + +static void +destroy_third_buffer(struct dri2_egl_surface *dri2_surf) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + + if (dri2_surf->third_buffer == NULL) + return; + + dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, + dri2_surf->third_buffer); + dri2_surf->third_buffer = NULL; + dri2_surf->drm_buffer_lock[DRM_BUFFER_THIRD] = 0; +} + +static void +swap_drm_buffers(struct dri2_egl_surface *dri2_surf, + enum drm_buffer_type a, enum drm_buffer_type b) +{ + int tmp; + + tmp = dri2_surf->drm_buffer_lock[a]; + dri2_surf->drm_buffer_lock[a] = dri2_surf->drm_buffer_lock[b]; + dri2_surf->drm_buffer_lock[b] = tmp; +} + +static void +swap_back_and_third(struct dri2_egl_surface *dri2_surf) +{ + if (dri2_surf->drm_buffer_lock[DRM_BUFFER_THIRD]) + destroy_third_buffer(dri2_surf); + + pointer_swap((const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT], + (const void **) &dri2_surf->third_buffer); + + swap_drm_buffers(dri2_surf, DRM_BUFFER_BACK, DRM_BUFFER_THIRD); +} + +static void +dri2_prior_buffer_creation(struct dri2_egl_surface *dri2_surf, + unsigned int type) +{ + switch (type) { + case __DRI_BUFFER_BACK_LEFT: + if (dri2_surf->drm_buffer_lock[DRM_BUFFER_BACK]) + swap_back_and_third(dri2_surf); + else if (dri2_surf->third_buffer) + destroy_third_buffer(dri2_surf); + break; + default: + break; + + } +} + +static __DRIbuffer * +dri2_get_buffers_with_format(__DRIdrawable * driDrawable, + int *width, int *height, + unsigned int *attachments, int count, + int *out_count, void *loaderPrivate) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + int i; + + dri2_surf->buffer_count = 0; + for (i = 0; i < 2*count; i+=2) { + assert(attachments[i] < __DRI_BUFFER_COUNT); + assert(dri2_surf->buffer_count < 5); + + dri2_prior_buffer_creation(dri2_surf, attachments[i]); + + if (dri2_surf->dri_buffers[attachments[i]] == NULL) { + + dri2_surf->dri_buffers[attachments[i]] = + dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, + attachments[i], attachments[i+1], + dri2_surf->base.Width, dri2_surf->base.Height); + + if (!dri2_surf->dri_buffers[attachments[i]]) + continue; + + if (attachments[i] == __DRI_BUFFER_BACK_LEFT) + dri2_process_back_buffer(dri2_surf, attachments[i+1]); + } + + memcpy(&dri2_surf->buffers[dri2_surf->buffer_count], + dri2_surf->dri_buffers[attachments[i]], + sizeof(__DRIbuffer)); + + dri2_surf->buffer_count++; + } + + assert(dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]); + + *out_count = dri2_surf->buffer_count; + if (dri2_surf->buffer_count == 0) + return NULL; + + *width = dri2_surf->base.Width; + *height = dri2_surf->base.Height; + + return dri2_surf->buffers; +} + +static __DRIbuffer * +dri2_get_buffers(__DRIdrawable * driDrawable, + int *width, int *height, + unsigned int *attachments, int count, + int *out_count, void *loaderPrivate) +{ + unsigned int *attachments_with_format; + __DRIbuffer *buffer; + const unsigned int format = 32; + int i; + + attachments_with_format = calloc(count * 2, sizeof(unsigned int)); + if (!attachments_with_format) { + *out_count = 0; + return NULL; + } + + for (i = 0; i < count; ++i) { + attachments_with_format[2*i] = attachments[i]; + attachments_with_format[2*i + 1] = format; + } + + buffer = + dri2_get_buffers_with_format(driDrawable, + width, height, + attachments_with_format, count, + out_count, loaderPrivate); + + free(attachments_with_format); + + return buffer; +} + +static void +dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) +{ + (void) driDrawable; + (void) loaderPrivate; +} + +static EGLBoolean +dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); + + if (dri2_surf->base.Type == EGL_WINDOW_BIT) { + pointer_swap( + (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT], + (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]); + + dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]->attachment = + __DRI_BUFFER_FRONT_LEFT; + dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->attachment = + __DRI_BUFFER_BACK_LEFT; + + swap_drm_buffers(dri2_surf, DRM_BUFFER_FRONT, DRM_BUFFER_BACK); + } + + _EGLContext *ctx; + if (dri2_drv->glFlush) { + ctx = _eglGetCurrentContext(); + if (ctx && ctx->DrawSurface == &dri2_surf->base) + dri2_drv->glFlush(); + } + + (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); + (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); + + return EGL_TRUE; +} + + static _EGLImage * dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx, EGLClientBuffer buffer, const EGLint *attr_list) @@ -147,12 +480,19 @@ dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp) dri2_dpy->gbm_dri->lookup_image = dri2_lookup_egl_image; dri2_dpy->gbm_dri->lookup_user_data = disp; + dri2_dpy->gbm_dri->get_buffers = dri2_get_buffers; + dri2_dpy->gbm_dri->flush_front_buffer = dri2_flush_front_buffer; + dri2_dpy->gbm_dri->get_buffers_with_format = dri2_get_buffers_with_format; + dri2_setup_screen(disp); for (i = 0; dri2_dpy->driver_configs[i]; i++) dri2_add_config(disp, dri2_dpy->driver_configs[i], - i + 1, 0, 0, NULL, NULL); + i + 1, 0, EGL_WINDOW_BIT, NULL, NULL); + drv->API.CreateWindowSurface = dri2_create_window_surface; + drv->API.DestroySurface = dri2_destroy_surface; + drv->API.SwapBuffers = dri2_swap_buffers; drv->API.CreateImageKHR = dri2_drm_create_image_khr; #ifdef HAVE_WAYLAND_PLATFORM diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c index 9ac678a..6cc4aaa 100644 --- a/src/gbm/backends/dri/gbm_dri.c +++ b/src/gbm/backends/dri/gbm_dri.c @@ -467,18 +467,76 @@ gbm_dri_surface_destroy(struct gbm_surface *_surf) static struct gbm_bo * gbm_dri_surface_lock_front_buffer(struct gbm_surface *_surf) { - return NULL; + struct gbm_dri_device *dri = gbm_dri_device(_surf->gbm); + struct gbm_dri_surface *surf = gbm_dri_surface(_surf); + struct gbm_dri_bo *bo; + __DRIbuffer *dri_buffer; + int dri_format = 0; + + if (surf->get_front_buffer == NULL) + return NULL; + + switch (_surf->format) { + case GBM_BO_FORMAT_XRGB8888: + case GBM_FORMAT_XRGB8888: + dri_format = __DRI_IMAGE_FORMAT_XRGB8888; + break; + case GBM_BO_FORMAT_ARGB8888: + case GBM_FORMAT_ARGB8888: + dri_format = __DRI_IMAGE_FORMAT_ARGB8888; + break; + default: + return NULL; + } + + dri_buffer = surf->get_front_buffer(surf, surf->dri_private); + if (!dri_buffer) + return NULL; + + bo = calloc(1, sizeof *bo); + if (bo == NULL) + return NULL; + + bo->dri_buffer = dri_buffer; + bo->base.base.gbm = _surf->gbm; + bo->base.base.width = _surf->width; + bo->base.base.height = _surf->height; + + bo->image = + dri->image->createImageFromName(dri->screen, + _surf->width, _surf->height, dri_format, + dri_buffer->name, dri_buffer->pitch / 4, + bo); + + dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, + &bo->base.base.handle.s32); + dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, + (int *) &bo->base.base.pitch); + + return &bo->base.base; } static void gbm_dri_surface_release_buffer(struct gbm_surface *_surf, struct gbm_bo *_bo) { + struct gbm_dri_surface *surf = gbm_dri_surface(_surf); + struct gbm_dri_bo *bo = gbm_dri_bo(_bo); + + if (surf->release_buffer && bo->dri_buffer) + surf->release_buffer(surf, bo->dri_buffer, surf->dri_private); + + gbm_dri_bo_destroy(_bo); } static int gbm_dri_surface_has_free_buffers(struct gbm_surface *_surf) { - return 0; + struct gbm_dri_surface *surf = gbm_dri_surface(_surf); + + if (surf->has_free_buffers && surf->has_free_buffers(surf->dri_private)) + return 1; + else + return 0; } static void diff --git a/src/gbm/backends/dri/gbm_driint.h b/src/gbm/backends/dri/gbm_driint.h index 3b7db65..786f36b 100644 --- a/src/gbm/backends/dri/gbm_driint.h +++ b/src/gbm/backends/dri/gbm_driint.h @@ -72,6 +72,7 @@ struct gbm_dri_bo { struct gbm_drm_bo base; __DRIimage *image; + __DRIbuffer *dri_buffer; }; struct gbm_dri_surface { -- 1.7.9.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev