st/egl: add buffer preserving support to Android
authorChia-I Wu <olvaffe@gmail.com>
Sun, 31 Jul 2011 02:16:53 +0000 (11:16 +0900)
committerChia-I Wu <olvaffe@gmail.com>
Sat, 20 Aug 2011 18:01:50 +0000 (02:01 +0800)
Use a staging color buffer when buffer preserving is enabled.

src/gallium/state_trackers/egl/android/native_android.cpp

index b9f12dadc416bba0b5d4ceb0a3f2f802ddff2458..2d7ae8b58bdd9a882474b802c70ab91654533ed7 100644 (file)
@@ -37,6 +37,7 @@ extern "C" {
 #include "util/u_memory.h"
 #include "util/u_inlines.h"
 #include "util/u_format.h"
+#include "util/u_box.h"
 #include "common/native.h"
 #include "common/native_helper.h"
 #include "android/android_sw_winsys.h"
@@ -59,9 +60,12 @@ struct android_surface {
    struct android_display *adpy;
    android_native_window_t *win;
 
+   /* staging color buffer for when buffer preserving is enabled */
+   struct pipe_resource *color_res;
+
    uint stamp;
    android_native_buffer_t *buf;
-   struct pipe_resource *res;
+   struct pipe_resource *buf_res;
 
    /* cache the current back buffers */
    struct {
@@ -309,7 +313,7 @@ android_surface_dequeue_buffer(struct native_surface *nsurf)
    if (!res)
       return FALSE;
 
-   pipe_resource_reference(&asurf->res, res);
+   pipe_resource_reference(&asurf->buf_res, res);
 
    return TRUE;
 }
@@ -322,7 +326,7 @@ android_surface_enqueue_buffer(struct native_surface *nsurf)
 {
    struct android_surface *asurf = android_surface(nsurf);
 
-   pipe_resource_reference(&asurf->res, NULL);
+   pipe_resource_reference(&asurf->buf_res, NULL);
 
    asurf->win->queueBuffer(asurf->win, asurf->buf);
 
@@ -350,17 +354,63 @@ android_surface_swap_buffers(struct native_surface *nsurf)
    return TRUE;
 }
 
+static void
+copy_resources(struct native_display *ndpy,
+               struct pipe_resource *src,
+               struct pipe_resource *dst)
+{
+   struct pipe_context *pipe;
+   struct pipe_box box;
+
+   pipe = ndpy_get_copy_context(ndpy);
+   if (!pipe)
+      return;
+
+   u_box_origin_2d(src->width0, src->height0, &box);
+   pipe->resource_copy_region(pipe, dst, 0, 0, 0, 0, src, 0, &box);
+   pipe->flush(pipe, NULL);
+}
+
 static boolean
 android_surface_present(struct native_surface *nsurf,
                         enum native_attachment natt,
                         boolean preserve,
                         uint swap_interval)
 {
+   struct android_surface *asurf = android_surface(nsurf);
+   struct android_display *adpy = asurf->adpy;
    boolean ret;
 
    if (swap_interval || natt != NATIVE_ATTACHMENT_BACK_LEFT)
       return FALSE;
 
+   /* we always render to color_res first when it exists */
+   if (asurf->color_res) {
+      copy_resources(&adpy->base, asurf->color_res, asurf->buf_res);
+      if (!preserve)
+         pipe_resource_reference(&asurf->color_res, NULL);
+   }
+   else if (preserve) {
+      struct pipe_resource templ;
+
+      memset(&templ, 0, sizeof(templ));
+      templ.target = asurf->buf_res->target;
+      templ.format = asurf->buf_res->format;
+      templ.bind = PIPE_BIND_RENDER_TARGET;
+      templ.width0 = asurf->buf_res->width0;
+      templ.height0 = asurf->buf_res->height0;
+      templ.depth0 = asurf->buf_res->depth0;
+      templ.array_size = asurf->buf_res->array_size;
+
+      asurf->color_res =
+         adpy->base.screen->resource_create(adpy->base.screen, &templ);
+      if (!asurf->color_res)
+         return FALSE;
+
+      /* preserve the contents */
+      copy_resources(&adpy->base, asurf->buf_res, asurf->color_res);
+   }
+
    return android_surface_swap_buffers(nsurf);
 }
 
@@ -375,6 +425,13 @@ android_surface_validate(struct native_surface *nsurf, uint attachment_mask,
    if (!asurf->buf) {
       if (!android_surface_dequeue_buffer(&asurf->base))
          return FALSE;
+
+      /* color_res must be compatible with buf_res */
+      if (asurf->color_res &&
+          (asurf->color_res->format != asurf->buf_res->format ||
+           asurf->color_res->width0 != asurf->buf_res->width0 ||
+           asurf->color_res->height0 != asurf->buf_res->height0))
+         pipe_resource_reference(&asurf->color_res, NULL);
    }
 
    if (textures) {
@@ -383,7 +440,8 @@ android_surface_validate(struct native_surface *nsurf, uint attachment_mask,
 
       if (native_attachment_mask_test(attachment_mask, att)) {
          textures[att] = NULL;
-         pipe_resource_reference(&textures[att], asurf->res);
+         pipe_resource_reference(&textures[att],
+               (asurf->color_res) ? asurf->color_res : asurf->buf_res);
       }
    }
 
@@ -408,6 +466,8 @@ android_surface_destroy(struct native_surface *nsurf)
    struct android_surface *asurf = android_surface(nsurf);
    int i;
 
+   pipe_resource_reference(&asurf->color_res, NULL);
+
    if (asurf->buf)
       android_surface_enqueue_buffer(&asurf->base);
 
@@ -625,6 +685,9 @@ android_display_get_param(struct native_display *ndpy,
    int val;
 
    switch (param) {
+   case NATIVE_PARAM_PRESERVE_BUFFER:
+      val = 1;
+      break;
    default:
       val = 0;
       break;