st/vega: Do not rely on st_resize_framebuffer.
authorChia-I Wu <olv@lunarg.com>
Mon, 12 Apr 2010 08:36:24 +0000 (16:36 +0800)
committerChia-I Wu <olv@lunarg.com>
Tue, 13 Apr 2010 07:15:43 +0000 (15:15 +0800)
Add vg_context_update_draw_buffer (and helpers) that duplicates the
logic of st_resize_framebuffer.  Use the new function instead of
st_resize_framebuffer in vg_manager.c.

src/gallium/state_trackers/vega/vg_manager.c

index 19a3405360fa3c74545c0e6039ffd4cfe7416fca..5ed5ae117ae4457a863578da2c615f59a3e0eb67 100644 (file)
@@ -2,6 +2,7 @@
  * Mesa 3-D graphics library
  * Version:  7.9
  *
+ * Copyright 2009 VMware, Inc.  All Rights Reserved.
  * Copyright (C) 2010 LunarG Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
 #include "util/u_memory.h"
 #include "util/u_inlines.h"
 #include "util/u_format.h"
+#include "util/u_sampler.h"
 
 #include "vg_manager.h"
 #include "vg_context.h"
-#include "vg_tracker.h" /* for st_resize_framebuffer */
 #include "image.h"
+#include "mask.h"
+
+static struct pipe_resource *
+create_texture(struct pipe_context *pipe, enum pipe_format format,
+                    VGint width, VGint height)
+{
+   struct pipe_resource templ;
+
+   memset(&templ, 0, sizeof(templ));
+
+   if (format != PIPE_FORMAT_NONE) {
+      templ.format = format;
+   }
+   else {
+      templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
+   }
+
+   templ.target = PIPE_TEXTURE_2D;
+   templ.width0 = width;
+   templ.height0 = height;
+   templ.depth0 = 1;
+   templ.last_level = 0;
+
+   if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) {
+      templ.bind = PIPE_BIND_DEPTH_STENCIL;
+   } else {
+      templ.bind = (PIPE_BIND_DISPLAY_TARGET |
+                    PIPE_BIND_RENDER_TARGET |
+                    PIPE_BIND_SAMPLER_VIEW);
+   }
+
+   return pipe->screen->resource_create(pipe->screen, &templ);
+}
+
+static struct pipe_sampler_view *
+create_tex_and_view(struct pipe_context *pipe, enum pipe_format format,
+                    VGint width, VGint height)
+{
+   struct pipe_resource *texture;
+   struct pipe_sampler_view view_templ;
+   struct pipe_sampler_view *view;
+
+   texture = create_texture(pipe, format, width, height);
+
+   if (!texture)
+      return NULL;
+
+   u_sampler_view_default_template(&view_templ, texture, texture->format);
+   view = pipe->create_sampler_view(pipe, texture, &view_templ);
+   /* want the texture to go away if the view is freed */
+   pipe_resource_reference(&texture, NULL);
+
+   return view;
+}
+
+static void
+setup_new_alpha_mask(struct vg_context *ctx, struct st_framebuffer *stfb)
+{
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_sampler_view *old_sampler_view = stfb->alpha_mask_view;
+
+   /*
+     we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to
+     this texture and use it as a sampler, so while this wastes some
+     space it makes both of those a lot simpler
+   */
+   stfb->alpha_mask_view = create_tex_and_view(pipe,
+         PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height);
+
+   if (!stfb->alpha_mask_view) {
+      if (old_sampler_view)
+         pipe_sampler_view_reference(&old_sampler_view, NULL);
+      return;
+   }
+
+   /* XXX could this call be avoided? */
+   vg_validate_state(ctx);
+
+   /* alpha mask starts with 1.f alpha */
+   mask_fill(0, 0, stfb->width, stfb->height, 1.f);
+
+   /* if we had an old surface copy it over */
+   if (old_sampler_view) {
+      struct pipe_surface *surface = pipe->screen->get_tex_surface(
+         pipe->screen,
+         stfb->alpha_mask_view->texture,
+         0, 0, 0,
+         PIPE_BIND_RENDER_TARGET |
+         PIPE_BIND_BLIT_DESTINATION);
+      struct pipe_surface *old_surface = pipe->screen->get_tex_surface(
+         pipe->screen,
+         old_sampler_view->texture,
+         0, 0, 0,
+         PIPE_BIND_BLIT_SOURCE);
+      pipe->surface_copy(pipe,
+                         surface,
+                         0, 0,
+                         old_surface,
+                         0, 0,
+                         MIN2(old_surface->width, surface->width),
+                         MIN2(old_surface->height, surface->height));
+      if (surface)
+         pipe_surface_reference(&surface, NULL);
+      if (old_surface)
+         pipe_surface_reference(&old_surface, NULL);
+   }
+
+   /* Free the old texture
+    */
+   if (old_sampler_view)
+      pipe_sampler_view_reference(&old_sampler_view, NULL);
+}
+
+static boolean
+vg_context_update_depth_stencil_rb(struct vg_context * ctx,
+                                   uint width, uint height)
+{
+   struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb;
+   struct pipe_context *pipe = ctx->pipe;
+   unsigned surface_usage;
+
+   if ((dsrb->width == width && dsrb->height == height) && dsrb->texture)
+      return FALSE;
+
+   /* unreference existing ones */
+   pipe_surface_reference(&dsrb->surface, NULL);
+   pipe_resource_reference(&dsrb->texture, NULL);
+   dsrb->width = dsrb->height = 0;
+
+   /* Probably need dedicated flags for surface usage too:
+    */
+   surface_usage = (PIPE_BIND_RENDER_TARGET |
+                    PIPE_BIND_BLIT_SOURCE |
+                    PIPE_BIND_BLIT_DESTINATION);
+
+   dsrb->texture = create_texture(pipe, dsrb->format, width, height);
+   if (!dsrb->texture)
+      return TRUE;
+
+   dsrb->surface = pipe->screen->get_tex_surface(pipe->screen,
+                                                 dsrb->texture,
+                                                 0, 0, 0,
+                                                 surface_usage);
+   if (!dsrb->surface) {
+      pipe_resource_reference(&dsrb->texture, NULL);
+      return TRUE;
+   }
+
+   dsrb->width = width;
+   dsrb->height = height;
+
+   assert(dsrb->surface->width == width);
+   assert(dsrb->surface->height == height);
+
+   return TRUE;
+}
+
+static boolean
+vg_context_update_color_rb(struct vg_context *ctx, struct pipe_resource *pt)
+{
+   struct st_renderbuffer *strb = ctx->draw_buffer->strb;
+   struct pipe_screen *screen = ctx->pipe->screen;
+
+   if (strb->texture == pt) {
+      pipe_resource_reference(&pt, NULL);
+      return FALSE;
+   }
+
+   /* unreference existing ones */
+   pipe_surface_reference(&strb->surface, NULL);
+   pipe_resource_reference(&strb->texture, NULL);
+   strb->width = strb->height = 0;
+
+   strb->texture = pt;
+   strb->surface = screen->get_tex_surface(screen, strb->texture, 0, 0, 0,
+         PIPE_BIND_RENDER_TARGET |
+         PIPE_BIND_BLIT_SOURCE |
+         PIPE_BIND_BLIT_DESTINATION);
+   if (!strb->surface) {
+      pipe_resource_reference(&strb->texture, NULL);
+      return TRUE;
+   }
+
+   strb->width = pt->width0;
+   strb->height = pt->height0;
+
+   return TRUE;
+}
+
+static void
+vg_context_update_draw_buffer(struct vg_context *ctx, struct pipe_resource *pt)
+{
+   struct st_framebuffer *stfb = ctx->draw_buffer;
+   boolean new_cbuf, new_zsbuf, new_size;
+
+   new_cbuf = vg_context_update_color_rb(ctx, pt);
+   new_zsbuf =
+      vg_context_update_depth_stencil_rb(ctx, pt->width0, pt->height0);
+
+   new_size = (stfb->width != pt->width0 || stfb->height != pt->height0);
+   stfb->width = pt->width0;
+   stfb->height = pt->height0;
+
+   if (new_cbuf || new_zsbuf || new_size) {
+      struct pipe_framebuffer_state *state = &ctx->state.g3d.fb;
+
+      memset(state, 0, sizeof(struct pipe_framebuffer_state));
+      state->width  = stfb->width;
+      state->height = stfb->height;
+      state->nr_cbufs = 1;
+      state->cbufs[0] = stfb->strb->surface;
+      state->zsbuf = stfb->dsrb->surface;
+
+      cso_set_framebuffer(ctx->cso_context, state);
+   }
+
+   if (new_zsbuf || new_size) {
+      ctx->state.dirty |= VIEWPORT_DIRTY;
+      ctx->state.dirty |= DEPTH_STENCIL_DIRTY;/*to reset the scissors*/
+
+      ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL, NULL, 0.0, 0);
+
+      /* we need all the other state already set */
+
+      setup_new_alpha_mask(ctx, stfb);
+
+      pipe_sampler_view_reference( &stfb->blend_texture_view, NULL);
+      stfb->blend_texture_view = create_tex_and_view(ctx->pipe,
+            PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height);
+   }
+}
 
 /**
  * Flush the front buffer if the current context renders to the front buffer.
@@ -76,9 +308,7 @@ vg_manager_flush_frontbuffer(struct vg_context *ctx)
 void
 vg_manager_validate_framebuffer(struct vg_context *ctx)
 {
-   struct pipe_screen *screen = ctx->pipe->screen;
    struct st_framebuffer *stfb = ctx->draw_buffer;
-   struct st_renderbuffer *rb;
    struct pipe_resource *pt;
 
    /* no binding surface */
@@ -100,28 +330,13 @@ vg_manager_validate_framebuffer(struct vg_context *ctx)
    if (!stfb->iface->validate(stfb->iface, &stfb->strb_att, 1, &pt) || !pt)
       return;
 
-   rb = stfb->strb;
-   if (rb->texture == pt) {
-      pipe_resource_reference(&pt, NULL);
-      return;
-   }
-
-   /* unreference existing ones */
-   pipe_surface_reference(&rb->surface, NULL);
-   pipe_resource_reference(&rb->texture, NULL);
-
-   rb->texture = pt;
-   rb->surface = screen->get_tex_surface(screen, rb->texture, 0, 0, 0,
-                                        PIPE_BIND_RENDER_TARGET |
-                                        PIPE_BIND_BLIT_SOURCE |
-                                        PIPE_BIND_BLIT_DESTINATION);
-
-   rb->width = rb->surface->width;
-   rb->height = rb->surface->height;
-
-   st_resize_framebuffer(stfb, rb->width, rb->height);
-
+   /*
+    * unset draw_buffer_invalid first because vg_context_update_draw_buffer
+    * will cause the framebuffer to be validated again because of a call to
+    * vg_validate_state
+    */
    p_atomic_set(&ctx->draw_buffer_invalid, FALSE);
+   vg_context_update_draw_buffer(ctx, pt);
 }