Merge branch 'mesa_7_7_branch'
[mesa.git] / src / gallium / state_trackers / egl / egl_surface.c
index ed8738e4049562aaa5b47926e08bc1fc1e3b8e84..d55aa51b82d98b5d776e698d0376e9862bc49fcc 100644 (file)
@@ -12,6 +12,9 @@
 
 #include "state_tracker/drm_api.h"
 
+#include "util/u_format.h"
+#include "util/u_rect.h"
+
 /*
  * Util functions
  */
@@ -33,45 +36,73 @@ drm_find_mode(drmModeConnectorPtr connector, _EGLMode *mode)
 }
 
 static struct st_framebuffer *
-drm_create_framebuffer(const __GLcontextModes *visual,
+drm_create_framebuffer(struct pipe_screen *screen,
+                       const __GLcontextModes *visual,
                        unsigned width,
                        unsigned height,
                        void *priv)
 {
-       enum pipe_format colorFormat, depthFormat, stencilFormat;
-
-       if (visual->redBits == 5)
-               colorFormat = PIPE_FORMAT_R5G6B5_UNORM;
-       else
-               colorFormat = PIPE_FORMAT_A8R8G8B8_UNORM;
-
-       if (visual->depthBits == 16)
-               depthFormat = PIPE_FORMAT_Z16_UNORM;
-       else if (visual->depthBits == 24)
-               depthFormat = PIPE_FORMAT_S8Z24_UNORM;
-       else
-               depthFormat = PIPE_FORMAT_NONE;
+       enum pipe_format color_format, depth_stencil_format;
+       boolean d_depth_bits_last;
+       boolean ds_depth_bits_last;
+
+       d_depth_bits_last =
+               screen->is_format_supported(screen, PIPE_FORMAT_X8Z24_UNORM,
+                                           PIPE_TEXTURE_2D,
+                                           PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0);
+       ds_depth_bits_last =
+               screen->is_format_supported(screen, PIPE_FORMAT_S8Z24_UNORM,
+                                           PIPE_TEXTURE_2D,
+                                           PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0);
+
+       if (visual->redBits == 8) {
+               if (visual->alphaBits == 8)
+                       color_format = PIPE_FORMAT_A8R8G8B8_UNORM;
+               else
+                       color_format = PIPE_FORMAT_X8R8G8B8_UNORM;
+       } else {
+               color_format = PIPE_FORMAT_R5G6B5_UNORM;
+       }
 
-       if (visual->stencilBits == 8)
-               stencilFormat = PIPE_FORMAT_S8Z24_UNORM;
-       else
-               stencilFormat = PIPE_FORMAT_NONE;
+       switch(visual->depthBits) {
+               default:
+               case 0:
+                       depth_stencil_format = PIPE_FORMAT_NONE;
+                       break;
+               case 16:
+                       depth_stencil_format = PIPE_FORMAT_Z16_UNORM;
+                       break;
+               case 24:
+                       if (visual->stencilBits == 0) {
+                               depth_stencil_format = (d_depth_bits_last) ?
+                                       PIPE_FORMAT_X8Z24_UNORM:
+                                       PIPE_FORMAT_Z24X8_UNORM;
+                       } else {
+                               depth_stencil_format = (ds_depth_bits_last) ?
+                                       PIPE_FORMAT_S8Z24_UNORM:
+                                       PIPE_FORMAT_Z24S8_UNORM;
+                       }
+                       break;
+               case 32:
+                       depth_stencil_format = PIPE_FORMAT_Z32_UNORM;
+                       break;
+       }
 
        return st_create_framebuffer(visual,
-                                    colorFormat,
-                                    depthFormat,
-                                    stencilFormat,
+                                    color_format,
+                                    depth_stencil_format,
+                                    depth_stencil_format,
                                     width,
                                     height,
                                     priv);
 }
 
 static void
-drm_create_texture(_EGLDriver *drv,
+drm_create_texture(_EGLDisplay *dpy,
                    struct drm_screen *scrn,
                    unsigned w, unsigned h)
 {
-       struct drm_device *dev = (struct drm_device *)drv;
+       struct drm_device *dev = lookup_drm_device(dpy);
        struct pipe_screen *screen = dev->screen;
        struct pipe_surface *surface;
        struct pipe_texture *texture;
@@ -84,11 +115,10 @@ drm_create_texture(_EGLDriver *drv,
        templat.tex_usage |= PIPE_TEXTURE_USAGE_PRIMARY;
        templat.target = PIPE_TEXTURE_2D;
        templat.last_level = 0;
-       templat.depth[0] = 1;
+       templat.depth0 = 1;
        templat.format = PIPE_FORMAT_A8R8G8B8_UNORM;
-       templat.width[0] = w;
-       templat.height[0] = h;
-       pf_get_block(templat.format, &templat.block);
+       templat.width0 = w;
+       templat.height0 = h;
 
        texture = screen->texture_create(dev->screen,
                                         &templat);
@@ -96,10 +126,6 @@ drm_create_texture(_EGLDriver *drv,
        if (!texture)
                goto err_tex;
 
-       dev->api->buffer_from_texture(dev->api, texture, &buf, &pitch);
-       if (!buf)
-               goto err_buf;
-
        surface = screen->get_tex_surface(screen,
                                          texture,
                                          0,
@@ -112,11 +138,11 @@ drm_create_texture(_EGLDriver *drv,
 
        scrn->tex = texture;
        scrn->surface = surface;
-       scrn->buffer = buf;
        scrn->front.width = w;
        scrn->front.height = h;
        scrn->front.pitch = pitch;
-       dev->api->handle_from_buffer(dev->api, screen, scrn->buffer, &scrn->front.handle);
+       dev->api->local_handle_from_texture(dev->api, screen, texture,
+                                           &scrn->front.pitch, &scrn->front.handle);
        if (0)
                goto err_handle;
 
@@ -126,7 +152,6 @@ err_handle:
        pipe_surface_reference(&surface, NULL);
 err_surf:
        pipe_texture_reference(&texture, NULL);
-err_buf:
 err_tex:
        pipe_buffer_reference(&buf, NULL);
        return;
@@ -137,18 +162,18 @@ err_tex:
  */
 
 void
-drm_takedown_shown_screen(_EGLDriver *drv, struct drm_screen *screen)
+drm_takedown_shown_screen(_EGLDisplay *dpy, struct drm_screen *screen)
 {
-       struct drm_device *dev = (struct drm_device *)drv;
+       struct drm_device *dev = lookup_drm_device(dpy);
 
        screen->surf = NULL;
 
        drmModeSetCrtc(
                dev->drmFD,
                screen->crtcID,
-               0, // FD
+               0, /* FD */
                0, 0,
-               NULL, 0, // List of output ids
+               NULL, 0, /* List of output ids */
                NULL);
 
        drmModeRmFB(dev->drmFD, screen->fbID);
@@ -157,11 +182,13 @@ drm_takedown_shown_screen(_EGLDriver *drv, struct drm_screen *screen)
 
        pipe_surface_reference(&screen->surface, NULL);
        pipe_texture_reference(&screen->tex, NULL);
-       pipe_buffer_reference(&screen->buffer, NULL);
 
        screen->shown = 0;
 }
 
+/**
+ * Called by libEGL's eglCreateWindowSurface().
+ */
 _EGLSurface *
 drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, NativeWindowType window, const EGLint *attrib_list)
 {
@@ -169,6 +196,9 @@ drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, N
 }
 
 
+/**
+ * Called by libEGL's eglCreatePixmapSurface().
+ */
 _EGLSurface *
 drm_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, NativePixmapType pixmap, const EGLint *attrib_list)
 {
@@ -176,10 +206,14 @@ drm_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, N
 }
 
 
+/**
+ * Called by libEGL's eglCreatePbufferSurface().
+ */
 _EGLSurface *
 drm_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
                            const EGLint *attrib_list)
 {
+       struct drm_device *dev = lookup_drm_device(dpy);
        int i;
        int width = -1;
        int height = -1;
@@ -216,9 +250,8 @@ drm_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
        surf->h = height;
 
        visual = drm_visual_from_config(conf);
-       surf->stfb = drm_create_framebuffer(visual,
-                                           width,
-                                           height,
+       surf->stfb = drm_create_framebuffer(dev->screen, visual,
+                                           width, height,
                                            (void*)surf);
        drm_visual_modes_destroy(visual);
 
@@ -230,6 +263,9 @@ err:
        return NULL;
 }
 
+/**
+ * Called by libEGL's eglCreateScreenSurfaceMESA().
+ */
 _EGLSurface *
 drm_create_screen_surface_mesa(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *cfg,
                                const EGLint *attrib_list)
@@ -239,24 +275,27 @@ drm_create_screen_surface_mesa(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *cf
        return surf;
 }
 
+/**
+ * Called by libEGL's eglShowScreenSurfaceMESA().
+ */
 EGLBoolean
 drm_show_screen_surface_mesa(_EGLDriver *drv, _EGLDisplay *dpy,
                              _EGLScreen *screen,
                              _EGLSurface *surface, _EGLMode *mode)
 {
-       struct drm_device *dev = (struct drm_device *)drv;
+       struct drm_device *dev = lookup_drm_device(dpy);
        struct drm_surface *surf = lookup_drm_surface(surface);
        struct drm_screen *scrn = lookup_drm_screen(screen);
        int ret;
        unsigned int i, k;
 
        if (scrn->shown)
-               drm_takedown_shown_screen(drv, scrn);
+               drm_takedown_shown_screen(dpy, scrn);
 
 
-       drm_create_texture(drv, scrn, mode->Width, mode->Height);
-       if (!scrn->buffer)
-               return EGL_FALSE;
+       drm_create_texture(dpy, scrn, mode->Width, mode->Height);
+       if (!scrn->tex)
+               goto err_tex;
 
        ret = drmModeAddFB(dev->drmFD,
                           scrn->front.width, scrn->front.height,
@@ -330,53 +369,73 @@ err_fb:
 err_bo:
        pipe_surface_reference(&scrn->surface, NULL);
        pipe_texture_reference(&scrn->tex, NULL);
-       pipe_buffer_reference(&scrn->buffer, NULL);
 
+err_tex:
        return EGL_FALSE;
 }
 
+/**
+ * Called by libEGL's eglDestroySurface().
+ */
 EGLBoolean
 drm_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface)
 {
        struct drm_surface *surf = lookup_drm_surface(surface);
        if (!_eglIsSurfaceBound(&surf->base)) {
                if (surf->screen)
-                       drm_takedown_shown_screen(drv, surf->screen);
+                       drm_takedown_shown_screen(dpy, surf->screen);
                st_unreference_framebuffer(surf->stfb);
                free(surf);
        }
        return EGL_TRUE;
 }
 
+/**
+ * Called by libEGL's eglSwapBuffers().
+ */
 EGLBoolean
 drm_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw)
 {
+       struct drm_device *dev = lookup_drm_device(dpy);
        struct drm_surface *surf = lookup_drm_surface(draw);
        struct pipe_surface *back_surf;
 
        if (!surf)
                return EGL_FALSE;
 
-       /* error checking */
-       if (!_eglSwapBuffers(drv, dpy, draw))
-               return EGL_FALSE;
-
        st_get_framebuffer_surface(surf->stfb, ST_SURFACE_BACK_LEFT, &back_surf);
 
        if (back_surf) {
+               struct drm_context *ctx = lookup_drm_context(draw->Binding);
 
                st_notify_swapbuffers(surf->stfb);
 
-               if (surf->screen) {
-                       surf->user->pipe->flush(surf->user->pipe, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_TEXTURE_CACHE, NULL);
-                       surf->user->pipe->surface_copy(surf->user->pipe,
-                               surf->screen->surface,
-                               0, 0,
-                               back_surf,
-                               0, 0,
-                               surf->w, surf->h);
-                       surf->user->pipe->flush(surf->user->pipe, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_TEXTURE_CACHE, NULL);
-                       /* TODO stuff here */
+               if (ctx && surf->screen) {
+            if (ctx->pipe->surface_copy) {
+                ctx->pipe->surface_copy(ctx->pipe,
+                    surf->screen->surface,
+                    0, 0,
+                    back_surf,
+                    0, 0,
+                    surf->w, surf->h);
+            } else {
+                util_surface_copy(ctx->pipe, FALSE,
+                    surf->screen->surface,
+                    0, 0,
+                    back_surf,
+                    0, 0,
+                    surf->w, surf->h);
+            }
+                       ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_TEXTURE_CACHE, NULL);
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+                       /* TODO query connector property to see if this is needed */
+                       drmModeDirtyFB(dev->drmFD, surf->screen->fbID, NULL, 0);
+#else
+                       (void)dev;
+#endif
+
+                       /* TODO more stuff here */
                }
        }