Merge branch 'mesa_7_7_branch'
[mesa.git] / src / gallium / state_trackers / egl / egl_surface.c
index d4cd2d3c743e442432494deb92bf1b89e462d3b9..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,85 +36,93 @@ 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;
        struct pipe_texture templat;
-       struct pipe_buffer *buf;
-       unsigned stride = 1024;
+       struct pipe_buffer *buf = NULL;
        unsigned pitch = 0;
-       unsigned size = 0;
-
-       /* ugly */
-       if (stride < w)
-               stride = 2048;
-
-       pitch = stride * 4;
-       size = h * 2 * pitch;
-
-       buf = pipe_buffer_create(screen,
-                                0, /* alignment */
-                                PIPE_BUFFER_USAGE_GPU_READ_WRITE |
-                                PIPE_BUFFER_USAGE_CPU_READ_WRITE,
-                                size);
-
-       if (!buf)
-               goto err_buf;
 
        memset(&templat, 0, sizeof(templat));
        templat.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
        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);
-
-       texture = screen->texture_blanket(dev->screen,
-                                         &templat,
-                                         &pitch,
-                                         buf);
+       templat.width0 = w;
+       templat.height0 = h;
+
+       texture = screen->texture_create(dev->screen,
+                                        &templat);
+
        if (!texture)
                goto err_tex;
 
@@ -125,14 +136,13 @@ drm_create_texture(_EGLDriver *drv,
        if (!surface)
                goto err_surf;
 
-
        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;
 
@@ -144,7 +154,6 @@ err_surf:
        pipe_texture_reference(&texture, NULL);
 err_tex:
        pipe_buffer_reference(&buf, NULL);
-err_buf:
        return;
 }
 
@@ -153,18 +162,18 @@ err_buf:
  */
 
 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);
@@ -173,41 +182,43 @@ 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;
 }
 
-EGLSurface
-drm_create_window_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list)
+/**
+ * Called by libEGL's eglCreateWindowSurface().
+ */
+_EGLSurface *
+drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, NativeWindowType window, const EGLint *attrib_list)
 {
-       return EGL_NO_SURFACE;
+       return NULL;
 }
 
 
-EGLSurface
-drm_create_pixmap_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list)
+/**
+ * Called by libEGL's eglCreatePixmapSurface().
+ */
+_EGLSurface *
+drm_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, NativePixmapType pixmap, const EGLint *attrib_list)
 {
-       return EGL_NO_SURFACE;
+       return NULL;
 }
 
 
-EGLSurface
-drm_create_pbuffer_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
+/**
+ * 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;
        struct drm_surface *surf = NULL;
        __GLcontextModes *visual;
-       _EGLConfig *conf;
-
-       conf = _eglLookupConfig(drv, dpy, config);
-       if (!conf) {
-               _eglError(EGL_BAD_CONFIG, "eglCreatePbufferSurface");
-               return EGL_NO_CONTEXT;
-       }
 
        for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
                switch (attrib_list[i]) {
@@ -225,7 +236,7 @@ drm_create_pbuffer_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
 
        if (width < 1 || height < 1) {
                _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface");
-               return EGL_NO_SURFACE;
+               return NULL;
        }
 
        surf = (struct drm_surface *) calloc(1, sizeof(struct drm_surface));
@@ -239,23 +250,24 @@ drm_create_pbuffer_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
        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);
 
-        _eglLinkSurface(&surf->base, _eglLookupDisplay(dpy));
-       return surf->base.Handle;
+       return &surf->base;
 
 err_surf:
        free(surf);
 err:
-       return EGL_NO_SURFACE;
+       return NULL;
 }
 
-EGLSurface
-drm_create_screen_surface_mesa(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
+/**
+ * Called by libEGL's eglCreateScreenSurfaceMESA().
+ */
+_EGLSurface *
+drm_create_screen_surface_mesa(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *cfg,
                                const EGLint *attrib_list)
 {
        EGLSurface surf = drm_create_pbuffer_surface(drv, dpy, cfg, attrib_list);
@@ -263,25 +275,27 @@ drm_create_screen_surface_mesa(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
        return surf;
 }
 
+/**
+ * Called by libEGL's eglShowScreenSurfaceMESA().
+ */
 EGLBoolean
-drm_show_screen_surface_mesa(_EGLDriver *drv, EGLDisplay dpy,
-                             EGLScreenMESA screen,
-                             EGLSurface surface, EGLModeMESA m)
+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(dpy, screen);
-       _EGLMode *mode = _eglLookupMode(dpy, m);
+       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,
@@ -355,55 +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)
+drm_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface)
 {
        struct drm_surface *surf = lookup_drm_surface(surface);
-       _eglUnlinkSurface(&surf->base);
-
        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)
+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 */
                }
        }