Merge branch 'master' of ssh://git.freedesktop.org/git/mesa/mesa into pipe-video
[mesa.git] / src / gallium / winsys / g3dvl / dri / dri_winsys.c
index 257aa0a120192c7866681769033b15e9283e1b1b..b86f546dd61b47608168bde2b420150c452590ac 100644 (file)
@@ -40,6 +40,7 @@ struct vl_dri_screen
    dri_screen_t *dri_screen;
    dri_framebuffer_t dri_framebuf;
    struct dri1_api *api_hooks;
+   boolean dri2;
 };
 
 struct vl_dri_context
@@ -52,6 +53,7 @@ struct vl_dri_context
    int fd;
    struct pipe_video_context *vpipe;
    dri_drawable_t *drawable;
+   struct pipe_surface *dri2_front;
 };
 
 static void
@@ -171,11 +173,11 @@ vl_dri_intersect_src_bbox(struct drm_clip_rect *dst, int dst_x, int dst_y,
 
 static void
 vl_clip_copy(struct vl_dri_context *vl_dri_ctx,
-            struct pipe_surface *dst,
-            struct pipe_surface *src,
-            const struct drm_clip_rect *src_bbox)
+             struct pipe_surface *dst,
+             struct pipe_surface *src,
+             const struct drm_clip_rect *src_bbox)
 {
-   struct pipe_video_context *vpipe = vl_dri_ctx->base.vpipe;
+   struct pipe_video_context *vpipe;
    struct drm_clip_rect clip;
    struct drm_clip_rect *cur;
    int i;
@@ -185,6 +187,8 @@ vl_clip_copy(struct vl_dri_context *vl_dri_ctx,
    assert(src);
    assert(src_bbox);
 
+   vpipe = vl_dri_ctx->base.vpipe;
+
    assert(vl_dri_ctx->drawable->cliprects);
    assert(vl_dri_ctx->drawable->num_cliprects > 0);
 
@@ -238,27 +242,29 @@ vl_dri_flush_frontbuffer(struct pipe_screen *screen,
 
    vl_dri_update_drawables_locked(vl_dri_ctx);
 
-   src_bbox.x1 = 0;
-   src_bbox.x2 = vl_dri_ctx->drawable->w;
-   src_bbox.y1 = 0;
-   src_bbox.y2 = vl_dri_ctx->drawable->h;
+   if (vl_dri_ctx->drawable->cliprects) {
+      src_bbox.x1 = 0;
+      src_bbox.x2 = vl_dri_ctx->drawable->w;
+      src_bbox.y1 = 0;
+      src_bbox.y2 = vl_dri_ctx->drawable->h;
 
 #if 0
-   if (vl_dri_scrn->_api_hooks->present_locked)
-      vl_dri_scrn->api_hooks->present_locked(pipe, surf,
-                                             vl_dri_ctx->drawable->cliprects,
-                                             vl_dri_ctx->drawable->num_cliprects,
-                                             vl_dri_ctx->drawable->x, vl_dri_drawable->y,
-                                             &bbox, NULL /*fence*/);
-   else
+      if (vl_dri_scrn->_api_hooks->present_locked)
+         vl_dri_scrn->api_hooks->present_locked(pipe, surf,
+                                                vl_dri_ctx->drawable->cliprects,
+                                                vl_dri_ctx->drawable->num_cliprects,
+                                                vl_dri_ctx->drawable->x, vl_dri_drawable->y,
+                                                &bbox, NULL /*fence*/);
+      else
 #endif
-   if (vl_dri_scrn->api_hooks->front_srf_locked) {
-      struct pipe_surface *front = vl_dri_scrn->api_hooks->front_srf_locked(screen);
+      if (vl_dri_scrn->api_hooks->front_srf_locked) {
+         struct pipe_surface *front = vl_dri_scrn->api_hooks->front_srf_locked(screen);
 
-      if (front)
-         vl_clip_copy(vl_dri_ctx, front, surf, &src_bbox);
+         if (front)
+            vl_clip_copy(vl_dri_ctx, front, surf, &src_bbox);
 
-      //st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, fence);
+         //st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, fence);
+      }
    }
 
    vl_dri_ctx->lost_lock = save_lost_lock;
@@ -266,6 +272,61 @@ vl_dri_flush_frontbuffer(struct pipe_screen *screen,
    vl_dri_unlock(vl_dri_ctx);
 }
 
+static struct pipe_surface*
+vl_dri2_get_front(struct vl_dri_screen *vl_dri_scrn, Drawable drawable)
+{
+   int w, h;
+   unsigned int attachments[1] = {DRI_BUFFER_FRONT_LEFT};
+   int count;
+   DRI2Buffer *dri2_front;
+   struct pipe_resource template, *front_tex;
+   struct pipe_surface *front_surf = NULL;
+
+   assert(vl_dri_scrn);
+
+   dri2_front = DRI2GetBuffers(vl_dri_scrn->dri_screen->display,
+                               drawable, &w, &h, attachments, 1, &count);
+   if (dri2_front) {
+      struct winsys_handle dri2_front_handle =
+      {
+         .type = DRM_API_HANDLE_TYPE_SHARED,
+         .handle = dri2_front->name,
+         .stride = dri2_front->pitch
+      };
+      front_tex = vl_dri_scrn->base.pscreen->resource_from_handle(vl_dri_scrn->base.pscreen, &template, &dri2_front_handle);
+      if (front_tex)
+         front_surf = vl_dri_scrn->base.pscreen->get_tex_surface(vl_dri_scrn->base.pscreen,
+                                                                 front_tex, 0, 0, 0,
+                                                                 /*PIPE_BIND_RENDER_TARGET*/ PIPE_BIND_BLIT_DESTINATION);
+      pipe_resource_reference(&front_tex, NULL);
+   }
+
+   return front_surf;
+}
+
+static void
+vl_dri2_flush_frontbuffer(struct pipe_screen *screen,
+                          struct pipe_surface *surf, void *context_private)
+{
+   struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)context_private;
+   struct vl_dri_screen *vl_dri_scrn;
+   struct pipe_video_context *vpipe;
+
+   assert(screen);
+   assert(surf);
+   assert(context_private);
+   assert(vl_dri_ctx->dri2_front);
+
+   vl_dri_scrn = (struct vl_dri_screen*)vl_dri_ctx->base.vscreen;
+   vpipe = vl_dri_ctx->base.vpipe;
+
+   /* XXX: Why not just render to fake front? */
+   vpipe->surface_copy(vpipe, vl_dri_ctx->dri2_front, 0, 0, surf, 0, 0, surf->width, surf->height);
+
+   //st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, fence);
+}
+
+
 Drawable
 vl_video_bind_drawable(struct vl_context *vctx, Drawable drawable)
 {
@@ -279,9 +340,17 @@ vl_video_bind_drawable(struct vl_context *vctx, Drawable drawable)
    if (vl_dri_ctx->drawable)
       old_drawable = vl_dri_ctx->drawable->x_drawable;
 
-   vl_dri_scrn = (struct vl_dri_screen*)vl_dri_ctx->base.vscreen;
-   driCreateDrawable(vl_dri_scrn->dri_screen, drawable, &dri_drawable);
-   vl_dri_ctx->drawable = dri_drawable;
+   if (drawable != old_drawable) {
+      vl_dri_scrn = (struct vl_dri_screen*)vl_dri_ctx->base.vscreen;
+      if (vl_dri_scrn->dri2) {
+         /* XXX: Need dri2CreateDrawable()? */
+         vl_dri_ctx->dri2_front = vl_dri2_get_front(vl_dri_scrn, drawable);
+      }
+      else {
+         driCreateDrawable(vl_dri_scrn->dri_screen, drawable, &dri_drawable);
+         vl_dri_ctx->drawable = dri_drawable;
+      }
+   }
 
    return old_drawable;
 }
@@ -298,18 +367,39 @@ vl_screen_create(Display *display, int screen)
    if (!vl_dri_scrn)
       return NULL;
 
-   driCreateScreen(display, screen, &vl_dri_scrn->dri_screen, &vl_dri_scrn->dri_framebuf);
-   vl_dri_scrn->api = drm_api_create();
+   /* Try DRI2 first */
+   if (dri2CreateScreen(display, screen, &vl_dri_scrn->dri_screen)) {
+      /* If not, try DRI */
+      if (driCreateScreen(display, screen, &vl_dri_scrn->dri_screen, &vl_dri_scrn->dri_framebuf)) {
+         /* Now what? */
+         FREE(vl_dri_scrn);
+         return NULL;
+      }
+      else {
+         /* Got DRI */
+         arg.base.mode = DRM_CREATE_DRI1;
+         arg.lf = &dri1_lf;
+         arg.ddx_info = vl_dri_scrn->dri_framebuf.private;
+         arg.ddx_info_size = vl_dri_scrn->dri_framebuf.private_size;
+         arg.sarea = vl_dri_scrn->dri_screen->sarea;
+         vl_dri_copy_version(&arg.ddx_version, &vl_dri_scrn->dri_screen->ddx);
+         vl_dri_copy_version(&arg.dri_version, &vl_dri_scrn->dri_screen->dri);
+         vl_dri_copy_version(&arg.drm_version, &vl_dri_scrn->dri_screen->drm);
+         arg.api = NULL;
+         vl_dri_scrn->dri2 = FALSE;
+      }
+   }
+   else {
+      /* Got DRI2 */
+      arg.base.mode = DRM_CREATE_NORMAL;
+      vl_dri_scrn->dri2 = TRUE;
+   }
 
-   arg.base.mode = DRM_CREATE_DRI1;
-   arg.lf = &dri1_lf;
-   arg.ddx_info = vl_dri_scrn->dri_framebuf.private;
-   arg.ddx_info_size = vl_dri_scrn->dri_framebuf.private_size;
-   arg.sarea = vl_dri_scrn->dri_screen->sarea;
-   vl_dri_copy_version(&arg.ddx_version, &vl_dri_scrn->dri_screen->ddx);
-   vl_dri_copy_version(&arg.dri_version, &vl_dri_scrn->dri_screen->dri);
-   vl_dri_copy_version(&arg.drm_version, &vl_dri_scrn->dri_screen->drm);
-   arg.api = NULL;
+   vl_dri_scrn->api = drm_api_create();
+   if (!vl_dri_scrn->api) {
+      FREE(vl_dri_scrn);
+      return NULL;
+   }
 
    vl_dri_scrn->base.pscreen = vl_dri_scrn->api->create_screen(vl_dri_scrn->api,
                                                                vl_dri_scrn->dri_screen->fd,
@@ -320,11 +410,14 @@ vl_screen_create(Display *display, int screen)
       return NULL;
    }
 
-   vl_dri_scrn->visual = XDefaultVisual(display, screen);
-   vl_dri_scrn->api_hooks = arg.api;
-   vl_dri_scrn->base.pscreen->flush_frontbuffer = vl_dri_flush_frontbuffer;
-   /* XXX: Safe to call this while unlocked? */
-   vl_dri_scrn->base.format = vl_dri_scrn->api_hooks->front_srf_locked(vl_dri_scrn->base.pscreen)->format;
+   if (!vl_dri_scrn->dri2) {
+      vl_dri_scrn->visual = XDefaultVisual(display, screen);
+      vl_dri_scrn->api_hooks = arg.api;
+      vl_dri_scrn->base.format = vl_dri_scrn->api_hooks->front_srf_locked(vl_dri_scrn->base.pscreen)->format;
+      vl_dri_scrn->base.pscreen->flush_frontbuffer = vl_dri_flush_frontbuffer;
+   }
+   else
+      vl_dri_scrn->base.pscreen->flush_frontbuffer = vl_dri2_flush_frontbuffer;
 
    return &vl_dri_scrn->base;
 }
@@ -336,7 +429,10 @@ void vl_screen_destroy(struct vl_screen *vscreen)
    assert(vscreen);
 
    vl_dri_scrn->base.pscreen->destroy(vl_dri_scrn->base.pscreen);
-   driDestroyScreen(vl_dri_scrn->dri_screen);
+   if (vl_dri_scrn->dri2)
+      dri2DestroyScreen(vl_dri_scrn->dri_screen);
+   else
+      driDestroyScreen(vl_dri_scrn->dri_screen);
    FREE(vl_dri_scrn);
 }
 
@@ -354,20 +450,21 @@ vl_video_create(struct vl_screen *vscreen,
       return NULL;
 
    /* XXX: Is default visual correct/sufficient here? */
-   driCreateContext(vl_dri_scrn->dri_screen, vl_dri_scrn->visual, &vl_dri_ctx->dri_context);
+   if (!vl_dri_scrn->dri2)
+      driCreateContext(vl_dri_scrn->dri_screen, vl_dri_scrn->visual, &vl_dri_ctx->dri_context);
 
-   if (!vl_dri_scrn->api->create_video_context) {
+   if (!vscreen->pscreen->video_context_create) {
       debug_printf("[G3DVL] No video support found on %s/%s.\n",
-                   vl_dri_scrn->base.pscreen->get_vendor(vl_dri_scrn->base.pscreen),
-                   vl_dri_scrn->base.pscreen->get_name(vl_dri_scrn->base.pscreen));
+                   vscreen->pscreen->get_vendor(vscreen->pscreen),
+                   vscreen->pscreen->get_name(vscreen->pscreen));
       FREE(vl_dri_ctx);
       return NULL;
    }
 
-   vl_dri_ctx->base.vpipe = vl_dri_scrn->api->create_video_context(vl_dri_scrn->api,
-                                                                   vscreen->pscreen,
+   vl_dri_ctx->base.vpipe = vscreen->pscreen->video_context_create(vscreen->pscreen,
                                                                    profile, chroma_format,
-                                                                   width, height);
+                                                                   width, height,
+                                                                   vl_dri_ctx->dri_context);
 
    if (!vl_dri_ctx->base.vpipe) {
       FREE(vl_dri_ctx);
@@ -377,7 +474,8 @@ vl_video_create(struct vl_screen *vscreen,
    vl_dri_ctx->base.vpipe->priv = vl_dri_ctx;
    vl_dri_ctx->base.vscreen = vscreen;
    vl_dri_ctx->fd = vl_dri_scrn->dri_screen->fd;
-   vl_dri_ctx->lock = (drmLock*)&vl_dri_scrn->dri_screen->sarea->lock;
+   if (!vl_dri_scrn->dri2)
+      vl_dri_ctx->lock = (drmLock*)&vl_dri_scrn->dri_screen->sarea->lock;
 
    return &vl_dri_ctx->base;
 }
@@ -389,5 +487,7 @@ void vl_video_destroy(struct vl_context *vctx)
    assert(vctx);
 
    vl_dri_ctx->base.vpipe->destroy(vl_dri_ctx->base.vpipe);
+   if (!((struct vl_dri_screen *)vctx->vscreen)->dri2)
+      driDestroyContext(vl_dri_ctx->dri_context);
    FREE(vl_dri_ctx);
 }