st/vega: Add FILTER renderer state for image filtering.
authorChia-I Wu <olv@lunarg.com>
Fri, 26 Nov 2010 15:25:18 +0000 (23:25 +0800)
committerChia-I Wu <olv@lunarg.com>
Wed, 1 Dec 2010 03:23:49 +0000 (11:23 +0800)
The state is designated to perform image filtering.  execute_filter is
updated to make use of the state.

src/gallium/state_trackers/vega/api_filters.c
src/gallium/state_trackers/vega/renderer.c
src/gallium/state_trackers/vega/renderer.h

index fa1e00d1f88523bd6cdfed0b48a7747d65d44247..841df10ab73b36ee4c97c27cce50617e2250f941 100644 (file)
@@ -114,153 +114,11 @@ static INLINE struct pipe_sampler_view *create_texture_1d_view(struct vg_context
    return view;
 }
 
-static INLINE struct pipe_surface * setup_framebuffer(struct vg_image *dst)
-{
-   struct vg_context *ctx = vg_current_context();
-   struct pipe_context *pipe = ctx->pipe;
-   struct pipe_framebuffer_state fb;
-   struct pipe_surface *dst_surf = pipe->screen->get_tex_surface(
-      pipe->screen, dst->sampler_view->texture, 0, 0, 0,
-      PIPE_BIND_RENDER_TARGET);
-
-   /* drawing dest */
-   memset(&fb, 0, sizeof(fb));
-   fb.width  = dst->x + dst_surf->width;
-   fb.height = dst->y + dst_surf->height;
-   fb.nr_cbufs = 1;
-   fb.cbufs[0] = dst_surf;
-   {
-      VGint i;
-      for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
-         fb.cbufs[i] = 0;
-   }
-   cso_set_framebuffer(ctx->cso_context, &fb);
-
-   return dst_surf;
-}
-
-static void setup_viewport(struct vg_image *dst)
-{
-   struct vg_context *ctx = vg_current_context();
-   vg_set_viewport(ctx, VEGA_Y0_TOP);
-}
-
-static void setup_blend()
-{
-   struct vg_context *ctx = vg_current_context();
-   struct pipe_blend_state blend;
-   memset(&blend, 0, sizeof(blend));
-   blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
-   blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
-   blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
-   blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
-   if (ctx->state.vg.filter_channel_mask & VG_RED)
-      blend.rt[0].colormask |= PIPE_MASK_R;
-   if (ctx->state.vg.filter_channel_mask & VG_GREEN)
-      blend.rt[0].colormask |= PIPE_MASK_G;
-   if (ctx->state.vg.filter_channel_mask & VG_BLUE)
-      blend.rt[0].colormask |= PIPE_MASK_B;
-   if (ctx->state.vg.filter_channel_mask & VG_ALPHA)
-      blend.rt[0].colormask |= PIPE_MASK_A;
-   blend.rt[0].blend_enable = 0;
-   cso_set_blend(ctx->cso_context, &blend);
-}
-
-static void setup_constant_buffer(struct vg_context *ctx, const void *buffer,
-                                  VGint param_bytes)
-{
-   struct pipe_context *pipe = ctx->pipe;
-   struct pipe_resource **cbuf = &ctx->filter.buffer;
-
-   /* We always need to get a new buffer, to keep the drivers simple and
-    * avoid gratuitous rendering synchronization. */
-   pipe_resource_reference(cbuf, NULL);
-
-   *cbuf = pipe_buffer_create(pipe->screen, 
-                              PIPE_BIND_CONSTANT_BUFFER,
-                              param_bytes);
-
-   if (*cbuf) {
-      st_no_flush_pipe_buffer_write(ctx, *cbuf,
-                                    0, param_bytes, buffer);
-   }
-
-   ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, *cbuf);
-}
-
-static void setup_samplers(struct vg_context *ctx, struct filter_info *info)
-{
-   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
-   struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
-   struct pipe_sampler_state sampler[3];
-   int num_samplers = 0;
-   int num_textures = 0;
-
-   samplers[0] = NULL;
-   samplers[1] = NULL;
-   samplers[2] = NULL;
-   samplers[3] = NULL;
-   sampler_views[0] = NULL;
-   sampler_views[1] = NULL;
-   sampler_views[2] = NULL;
-   sampler_views[3] = NULL;
-
-   memset(&sampler[0], 0, sizeof(struct pipe_sampler_state));
-   sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
-   sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
-   sampler[0].wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
-   sampler[0].min_img_filter = PIPE_TEX_MIPFILTER_LINEAR;
-   sampler[0].mag_img_filter = PIPE_TEX_MIPFILTER_LINEAR;
-   sampler[0].normalized_coords = 1;
-
-   switch(info->tiling_mode) {
-   case VG_TILE_FILL:
-      sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
-      sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
-      memcpy(sampler[0].border_color,
-             ctx->state.vg.tile_fill_color,
-             sizeof(VGfloat) * 4);
-      break;
-   case VG_TILE_PAD:
-      sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
-      sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
-      break;
-   case VG_TILE_REPEAT:
-      sampler[0].wrap_s = PIPE_TEX_WRAP_REPEAT;
-      sampler[0].wrap_t = PIPE_TEX_WRAP_REPEAT;
-      break;
-   case VG_TILE_REFLECT:
-      sampler[0].wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT;
-      sampler[0].wrap_t = PIPE_TEX_WRAP_MIRROR_REPEAT;
-      break;
-   default:
-      debug_assert(!"Unknown tiling mode");
-   }
-
-   samplers[0] = &sampler[0];
-   sampler_views[0] = info->src->sampler_view;
-   ++num_samplers;
-   ++num_textures;
-
-   if (info->extra_texture_view) {
-      memcpy(&sampler[1], &sampler[0], sizeof(struct pipe_sampler_state));
-      samplers[1] = &sampler[1];
-      sampler_views[1] = info->extra_texture_view;
-      ++num_samplers;
-      ++num_textures;
-   }
-
-
-   cso_set_samplers(ctx->cso_context, num_samplers, (const struct pipe_sampler_state **)samplers);
-   cso_set_fragment_sampler_views(ctx->cso_context, num_textures, sampler_views);
-}
-
 static struct vg_shader * setup_color_matrix(struct vg_context *ctx, void *user_data)
 {
    struct vg_shader *shader =
       shader_create_from_text(ctx->pipe, color_matrix_asm, 200,
          PIPE_SHADER_FRAGMENT);
-   cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
    return shader;
 }
 
@@ -275,7 +133,6 @@ static struct vg_shader * setup_convolution(struct vg_context *ctx, void *user_d
    shader = shader_create_from_text(ctx->pipe, buffer, 200,
                                     PIPE_SHADER_FRAGMENT);
 
-   cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
    return shader;
 }
 
@@ -285,7 +142,6 @@ static struct vg_shader * setup_lookup(struct vg_context *ctx, void *user_data)
       shader_create_from_text(ctx->pipe, lookup_asm,
                               200, PIPE_SHADER_FRAGMENT);
 
-   cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
    return shader;
 }
 
@@ -316,49 +172,67 @@ static struct vg_shader * setup_lookup_single(struct vg_context *ctx, void *user
    shader = shader_create_from_text(ctx->pipe, buffer, 200,
                                     PIPE_SHADER_FRAGMENT);
 
-   cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
    return shader;
 }
 
 static void execute_filter(struct vg_context *ctx,
                            struct filter_info *info)
 {
-   struct pipe_surface *dst_surf;
    struct vg_shader *shader;
+   const struct pipe_sampler_state *samplers[2];
+   struct pipe_sampler_view *views[2];
+   struct pipe_sampler_state sampler;
+   uint tex_wrap;
+
+   memset(&sampler, 0, sizeof(sampler));
+   sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
+   sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
+   sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
+   sampler.normalized_coords = 1;
+
+   switch (info->tiling_mode) {
+   case VG_TILE_FILL:
+      tex_wrap = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
+      /* copy border color */
+      memcpy(sampler.border_color, ctx->state.vg.tile_fill_color,
+            sizeof(sampler.border_color));
+      break;
+   case VG_TILE_PAD:
+      tex_wrap = PIPE_TEX_WRAP_CLAMP_TO_EDGE;;
+      break;
+   case VG_TILE_REPEAT:
+      tex_wrap = PIPE_TEX_WRAP_REPEAT;;
+      break;
+   case VG_TILE_REFLECT:
+      tex_wrap = PIPE_TEX_WRAP_MIRROR_REPEAT;
+      break;
+   default:
+      debug_assert(!"Unknown tiling mode");
+      break;
+   }
+
+   sampler.wrap_s = tex_wrap;
+   sampler.wrap_t = tex_wrap;
+   sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+
+   samplers[0] = samplers[1] = &sampler;
+   views[0] = info->src->sampler_view;
+   views[1] = info->extra_texture_view;
 
-   cso_save_framebuffer(ctx->cso_context);
-   cso_save_fragment_shader(ctx->cso_context);
-   cso_save_viewport(ctx->cso_context);
-   cso_save_blend(ctx->cso_context);
-   cso_save_samplers(ctx->cso_context);
-   cso_save_fragment_sampler_views(ctx->cso_context);
-
-   dst_surf = setup_framebuffer(info->dst);
-   setup_viewport(info->dst);
-   setup_blend();
-   setup_constant_buffer(ctx, info->const_buffer, info->const_buffer_len);
    shader = info->setup_shader(ctx, info->user_data);
-   setup_samplers(ctx, info);
-
-   renderer_draw_texture(ctx->renderer,
-                         info->src->sampler_view->texture,
-                         info->dst->x, info->dst->y,
-                         info->dst->x + info->dst->width,
-                         info->dst->y + info->dst->height,
-                         info->dst->x, info->dst->y,
-                         info->dst->x + info->dst->width,
-                         info->dst->y + info->dst->height);
-
-   cso_restore_framebuffer(ctx->cso_context);
-   cso_restore_fragment_shader(ctx->cso_context);
-   cso_restore_viewport(ctx->cso_context);
-   cso_restore_blend(ctx->cso_context);
-   cso_restore_samplers(ctx->cso_context);
-   cso_restore_fragment_sampler_views(ctx->cso_context);
 
-   vg_shader_destroy(ctx, shader);
+   if (renderer_filter_begin(ctx->renderer,
+            info->dst->sampler_view->texture, VG_TRUE,
+            ctx->state.vg.filter_channel_mask,
+            samplers, views, (info->extra_texture_view) ? 2 : 1,
+            shader->driver, info->const_buffer, info->const_buffer_len)) {
+      renderer_filter(ctx->renderer,
+            info->dst->x, info->dst->y, info->dst->width, info->dst->height,
+            info->src->x, info->src->y, info->src->width, info->src->height);
+      renderer_filter_end(ctx->renderer);
+   }
 
-   pipe_surface_reference(&dst_surf, NULL);
+   vg_shader_destroy(ctx, shader);
 }
 
 void vegaColorMatrix(VGImage dst, VGImage src,
index d326cfc50156c26387e2a6f44c50f7cb45c551b0..e14eb4706e472cac8cc218bcc343b5306ae4dcad 100644 (file)
@@ -28,6 +28,7 @@
 #include "renderer.h"
 
 #include "vg_context.h"
+#include "image.h"
 
 #include "pipe/p_context.h"
 #include "pipe/p_state.h"
@@ -49,6 +50,7 @@ typedef enum {
    RENDERER_STATE_DRAWTEX,
    RENDERER_STATE_SCISSOR,
    RENDERER_STATE_CLEAR,
+   RENDERER_STATE_FILTER,
    NUM_RENDERER_STATES
 } RendererState;
 
@@ -96,6 +98,11 @@ struct renderer {
       struct {
          VGboolean restore_dsa;
       } scissor;
+
+      struct {
+         VGboolean use_sampler;
+         VGint tex_width, tex_height;
+      } filter;
    } u;
 };
 
@@ -320,6 +327,45 @@ static void renderer_set_samplers(struct renderer *r,
    cso_set_fragment_sampler_views(r->cso, num_views, views);
 }
 
+/**
+ * Set custom renderer fragment shader, and optionally set samplers and views
+ * and upload the fragment constant buffer.
+ *
+ * This function modifies fragment_shader, samplers and fragment_sampler_views
+ * states.
+ */
+static void renderer_set_custom_fs(struct renderer *renderer,
+                                   void *fs,
+                                   const struct pipe_sampler_state **samplers,
+                                   struct pipe_sampler_view **views,
+                                   VGint num_samplers,
+                                   const void *const_buffer,
+                                   VGint const_buffer_len)
+{
+   cso_set_fragment_shader_handle(renderer->cso, fs);
+
+   /* set samplers and views */
+   if (num_samplers) {
+      cso_set_samplers(renderer->cso, num_samplers, samplers);
+      cso_set_fragment_sampler_views(renderer->cso, num_samplers, views);
+   }
+
+   /* upload fs constant buffer */
+   if (const_buffer_len) {
+      struct pipe_resource *cbuf;
+
+      cbuf = pipe_buffer_create(renderer->pipe->screen,
+            PIPE_BIND_CONSTANT_BUFFER, const_buffer_len);
+      pipe_buffer_write(renderer->pipe, cbuf, 0,
+            const_buffer_len, const_buffer);
+      renderer->pipe->set_constant_buffer(renderer->pipe,
+            PIPE_SHADER_FRAGMENT, 0, cbuf);
+
+      /* destroy cbuf automatically */
+      pipe_resource_reference(&cbuf, NULL);
+   }
+}
+
 /**
  * Setup renderer quad position.
  */
@@ -678,6 +724,119 @@ void renderer_clear_end(struct renderer *renderer)
    renderer->state = RENDERER_STATE_INIT;
 }
 
+/**
+ * Prepare the renderer for image filtering.
+ */
+VGboolean renderer_filter_begin(struct renderer *renderer,
+                                struct pipe_resource *dst,
+                                VGboolean y0_top,
+                                VGbitfield channel_mask,
+                                const struct pipe_sampler_state **samplers,
+                                struct pipe_sampler_view **views,
+                                VGint num_samplers,
+                                void *fs,
+                                const void *const_buffer,
+                                VGint const_buffer_len)
+{
+   struct pipe_surface *surf;
+
+   assert(renderer->state == RENDERER_STATE_INIT);
+
+   if (!fs)
+      return VG_FALSE;
+   if (!renderer_can_support(renderer, dst, PIPE_BIND_RENDER_TARGET))
+      return VG_FALSE;
+
+   surf = renderer->pipe->screen->get_tex_surface(renderer->pipe->screen,
+         dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET);
+   if (!surf)
+      return VG_FALSE;
+
+   cso_save_framebuffer(renderer->cso);
+   cso_save_viewport(renderer->cso);
+   cso_save_blend(renderer->cso);
+
+   /* set the image as the target */
+   renderer_set_target(renderer, surf, NULL, y0_top);
+   pipe_surface_reference(&surf, NULL);
+
+   renderer_set_blend(renderer, channel_mask);
+
+   if (num_samplers) {
+      struct pipe_resource *tex;
+
+      cso_save_samplers(renderer->cso);
+      cso_save_fragment_sampler_views(renderer->cso);
+      cso_save_fragment_shader(renderer->cso);
+      cso_save_vertex_shader(renderer->cso);
+
+      renderer_set_custom_fs(renderer, fs,
+                             samplers, views, num_samplers,
+                             const_buffer, const_buffer_len);
+      renderer_set_vs(renderer, RENDERER_VS_TEXTURE);
+
+      tex = views[0]->texture;
+      renderer->u.filter.tex_width = tex->width0;
+      renderer->u.filter.tex_height = tex->height0;
+      renderer->u.filter.use_sampler = VG_TRUE;
+   }
+   else {
+      cso_save_fragment_shader(renderer->cso);
+
+      renderer_set_custom_fs(renderer, fs, NULL, NULL, 0,
+                             const_buffer, const_buffer_len);
+
+      renderer->u.filter.use_sampler = VG_FALSE;
+   }
+
+   renderer->state = RENDERER_STATE_FILTER;
+
+   return VG_TRUE;
+}
+
+/**
+ * Draw into a rectangle of the destination with the specified region of the
+ * texture(s).
+ *
+ * The coordinates are in surface coordinates.
+ */
+void renderer_filter(struct renderer *renderer,
+                    VGint x, VGint y, VGint w, VGint h,
+                    VGint sx, VGint sy, VGint sw, VGint sh)
+{
+   assert(renderer->state == RENDERER_STATE_FILTER);
+
+   renderer_quad_pos(renderer, x, y, x + w, y + h, VG_FALSE);
+   if (renderer->u.filter.use_sampler) {
+      renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh,
+            renderer->u.filter.tex_width,
+            renderer->u.filter.tex_height);
+   }
+
+   renderer_quad_draw(renderer);
+}
+
+/**
+ * End image filtering and restore the states.
+ */
+void renderer_filter_end(struct renderer *renderer)
+{
+   assert(renderer->state == RENDERER_STATE_FILTER);
+
+   if (renderer->u.filter.use_sampler) {
+      cso_restore_samplers(renderer->cso);
+      cso_restore_fragment_sampler_views(renderer->cso);
+      cso_restore_vertex_shader(renderer->cso);
+   }
+
+   cso_restore_framebuffer(renderer->cso);
+   cso_restore_viewport(renderer->cso);
+   cso_restore_blend(renderer->cso);
+   cso_restore_fragment_shader(renderer->cso);
+
+   renderer->state = RENDERER_STATE_INIT;
+}
+
 static void setup_shaders(struct renderer *ctx)
 {
    struct pipe_context *pipe = ctx->pipe;
index fa0782280ad053739138282edf14a96006ce51a8..288c17f9c893216c5403271c11262b5d17ea69e6 100644 (file)
@@ -34,6 +34,7 @@ struct renderer;
 
 struct vg_context;
 struct pipe_resource;
+struct pipe_sampler_state;
 struct pipe_sampler_view;
 struct pipe_surface;
 
@@ -76,6 +77,23 @@ void renderer_clear(struct renderer *renderer,
 
 void renderer_clear_end(struct renderer *renderer);
 
+VGboolean renderer_filter_begin(struct renderer *renderer,
+                                struct pipe_resource *dst,
+                                VGboolean y0_top,
+                                VGbitfield channel_mask,
+                                const struct pipe_sampler_state **samplers,
+                                struct pipe_sampler_view **views,
+                                VGint num_samplers,
+                                void *fs,
+                                const void *const_buffer,
+                                VGint const_buffer_len);
+
+void renderer_filter(struct renderer *renderer,
+                     VGint x, VGint y, VGint w, VGint h,
+                     VGint sx, VGint sy, VGint sw, VGint sh);
+
+void renderer_filter_end(struct renderer *renderer);
+
 void renderer_draw_quad(struct renderer *,
                         VGfloat x1, VGfloat y1,
                         VGfloat x2, VGfloat y2,