util: Properly init memory for blitter CSOs.
[mesa.git] / src / gallium / auxiliary / util / u_blitter.c
index cef3b69e46ddf21e05d90658a9d096b4c7514c3e..18f8606818381180c127e1b1e56c9e93610c4307 100644 (file)
@@ -34,7 +34,7 @@
 
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
-#include "pipe/p_inlines.h"
+#include "util/u_inlines.h"
 #include "pipe/p_shader_tokens.h"
 #include "pipe/p_state.h"
 
@@ -60,13 +60,12 @@ struct blitter_context_priv
    float vertices[4][2][4];   /**< {pos, color} or {pos, texcoord} */
 
    /* Templates for various state objects. */
-   struct pipe_depth_stencil_alpha_state template_dsa;
    struct pipe_sampler_state template_sampler_state;
 
    /* Constant state objects. */
    /* Vertex shaders. */
    void *vs_col; /**< Vertex shader which passes {pos, color} to the output */
-   void *vs_tex; /**<Vertex shader which passes {pos, texcoord} to the output.*/
+   void *vs_tex; /**< Vertex shader which passes {pos, texcoord} to the output.*/
 
    /* Fragment shaders. */
    /* FS which outputs a color to multiple color buffers. */
@@ -85,7 +84,7 @@ struct blitter_context_priv
    void *blend_keep_color;    /**< blend state with writemask of 0 */
 
    /* Depth stencil alpha state. */
-   void *dsa_write_depth_stencil[0xff]; /**< indices are stencil clear values */
+   void *dsa_write_depth_stencil;
    void *dsa_write_depth_keep_stencil;
    void *dsa_keep_depth_stencil;
 
@@ -99,9 +98,9 @@ struct blitter_context_priv
 struct blitter_context *util_blitter_create(struct pipe_context *pipe)
 {
    struct blitter_context_priv *ctx;
-   struct pipe_blend_state blend;
-   struct pipe_depth_stencil_alpha_state *dsa;
-   struct pipe_rasterizer_state rs_state;
+   struct pipe_blend_state blend = { 0 };
+   struct pipe_depth_stencil_alpha_state dsa = { { 0 } };
+   struct pipe_rasterizer_state rs_state = { 0 };
    struct pipe_sampler_state *sampler_state;
    unsigned i;
 
@@ -122,30 +121,30 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe)
    ctx->blitter.saved_num_sampler_states = ~0;
 
    /* blend state objects */
-   memset(&blend, 0, sizeof(blend));
    ctx->blend_keep_color = pipe->create_blend_state(pipe, &blend);
 
-   blend.colormask = PIPE_MASK_RGBA;
+   blend.rt[0].colormask = PIPE_MASK_RGBA;
    ctx->blend_write_color = pipe->create_blend_state(pipe, &blend);
 
    /* depth stencil alpha state objects */
-   dsa = &ctx->template_dsa;
    ctx->dsa_keep_depth_stencil =
-      pipe->create_depth_stencil_alpha_state(pipe, dsa);
+      pipe->create_depth_stencil_alpha_state(pipe, &dsa);
 
-   dsa->depth.enabled = 1;
-   dsa->depth.writemask = 1;
-   dsa->depth.func = PIPE_FUNC_ALWAYS;
+   dsa.depth.enabled = 1;
+   dsa.depth.writemask = 1;
+   dsa.depth.func = PIPE_FUNC_ALWAYS;
    ctx->dsa_write_depth_keep_stencil =
-      pipe->create_depth_stencil_alpha_state(pipe, dsa);
-
-   dsa->stencil[0].enabled = 1;
-   dsa->stencil[0].func = PIPE_FUNC_ALWAYS;
-   dsa->stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
-   dsa->stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
-   dsa->stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
-   dsa->stencil[0].valuemask = 0xff;
-   dsa->stencil[0].writemask = 0xff;
+      pipe->create_depth_stencil_alpha_state(pipe, &dsa);
+
+   dsa.stencil[0].enabled = 1;
+   dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
+   dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
+   dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
+   dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
+   dsa.stencil[0].valuemask = 0xff;
+   dsa.stencil[0].writemask = 0xff;
+   ctx->dsa_write_depth_stencil =
+      pipe->create_depth_stencil_alpha_state(pipe, &dsa);
    /* The DSA state objects which write depth and stencil are created
     * on-demand. */
 
@@ -163,6 +162,7 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe)
    rs_state.cull_mode = PIPE_WINDING_NONE;
    rs_state.bypass_vs_clip_and_viewport = 1;
    rs_state.gl_rasterization_rules = 1;
+   rs_state.flatshade = 1;
    ctx->rs_state = pipe->create_rasterizer_state(pipe, &rs_state);
 
    /* fragment shaders are created on-demand */
@@ -209,11 +209,7 @@ void util_blitter_destroy(struct blitter_context *blitter)
    pipe->delete_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_stencil);
    pipe->delete_depth_stencil_alpha_state(pipe,
                                           ctx->dsa_write_depth_keep_stencil);
-
-   for (i = 0; i < 0xff; i++)
-      if (ctx->dsa_write_depth_stencil[i])
-         pipe->delete_depth_stencil_alpha_state(pipe,
-            ctx->dsa_write_depth_stencil[i]);
+   pipe->delete_depth_stencil_alpha_state(pipe, ctx->dsa_write_depth_stencil);
 
    pipe->delete_rasterizer_state(pipe, ctx->rs_state);
    pipe->delete_vs_state(pipe, ctx->vs_col);
@@ -265,6 +261,8 @@ static void blitter_restore_CSOs(struct blitter_context_priv *ctx)
    ctx->blitter.saved_fs = INVALID_PTR;
    ctx->blitter.saved_vs = INVALID_PTR;
 
+   pipe->set_stencil_ref(pipe, &ctx->blitter.saved_stencil_ref);
+
    /* restore the state objects which are required to be saved before copy/fill
     */
    if (ctx->blitter.saved_fb_state.nr_cbufs != ~0) {
@@ -378,9 +376,16 @@ static void blitter_set_texcoords_cube(struct blitter_context_priv *ctx,
    float t1 = y1 / (float)surf->height;
    float s2 = x2 / (float)surf->width;
    float t2 = y2 / (float)surf->height;
-   const float st[4][2] = {
-      {s1, t1}, {s2, t1}, {s2, t2}, {s1, t2}
-   };
+   float st[4][2];
+
+   st[0][0] = s1;
+   st[0][1] = t1;
+   st[1][0] = s2;
+   st[1][1] = t1;
+   st[2][0] = s2;
+   st[2][1] = t2;
+   st[3][0] = s1;
+   st[3][1] = t2;
 
    util_map_texcoords2d_onto_cubemap(surf->face,
                                      /* pointer, stride in floats */
@@ -404,26 +409,6 @@ static void blitter_draw_quad(struct blitter_context_priv *ctx)
                            2); /* attribs/vert */
 }
 
-static INLINE
-void *blitter_get_state_write_depth_stencil(
-               struct blitter_context_priv *ctx,
-               unsigned stencil)
-{
-   struct pipe_context *pipe = ctx->pipe;
-
-   stencil &= 0xff;
-
-   /* Create the DSA state on-demand. */
-   if (!ctx->dsa_write_depth_stencil[stencil]) {
-      ctx->template_dsa.stencil[0].ref_value = stencil;
-
-      ctx->dsa_write_depth_stencil[stencil] =
-         pipe->create_depth_stencil_alpha_state(pipe, &ctx->template_dsa);
-   }
-
-   return ctx->dsa_write_depth_stencil[stencil];
-}
-
 static INLINE
 void **blitter_get_sampler_state(struct blitter_context_priv *ctx,
                                  int miplevel)
@@ -540,6 +525,7 @@ void util_blitter_clear(struct blitter_context *blitter,
 {
    struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
    struct pipe_context *pipe = ctx->pipe;
+   struct pipe_stencil_ref sr = { { 0 } };
 
    assert(num_cbufs <= PIPE_MAX_COLOR_BUFS);
 
@@ -551,9 +537,11 @@ void util_blitter_clear(struct blitter_context *blitter,
    else
       pipe->bind_blend_state(pipe, ctx->blend_keep_color);
 
-   if (clear_buffers & PIPE_CLEAR_DEPTHSTENCIL)
-      pipe->bind_depth_stencil_alpha_state(pipe,
-         blitter_get_state_write_depth_stencil(ctx, stencil));
+   if (clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) {
+      sr.ref_value[0] = stencil & 0xff;
+      pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_write_depth_stencil);
+      pipe->set_stencil_ref(pipe, &sr);
+   }
    else
       pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_stencil);
 
@@ -567,45 +555,29 @@ void util_blitter_clear(struct blitter_context *blitter,
    blitter_restore_CSOs(ctx);
 }
 
-void util_blitter_copy(struct blitter_context *blitter,
-                       struct pipe_surface *dst,
-                       unsigned dstx, unsigned dsty,
-                       struct pipe_surface *src,
-                       unsigned srcx, unsigned srcy,
-                       unsigned width, unsigned height,
-                       boolean ignore_stencil)
+static boolean
+is_overlap(unsigned sx1, unsigned sx2, unsigned sy1, unsigned sy2,
+           unsigned dx1, unsigned dx2, unsigned dy1, unsigned dy2)
+{
+    if (sx1 >= dx2 || sx2 <= dx1 || sy1 >= dy2 || sy2 <= dy1) {
+        return FALSE;
+    } else {
+        return TRUE;
+    }
+}
+
+static void util_blitter_do_copy(struct blitter_context *blitter,
+                                struct pipe_surface *dst,
+                                unsigned dstx, unsigned dsty,
+                                struct pipe_surface *src,
+                                unsigned srcx, unsigned srcy,
+                                unsigned width, unsigned height,
+                                boolean is_depth)
 {
    struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
    struct pipe_context *pipe = ctx->pipe;
-   struct pipe_screen *screen = pipe->screen;
    struct pipe_framebuffer_state fb_state;
-   boolean is_stencil, is_depth;
-   unsigned dst_tex_usage;
 
-   /* give up if textures are not set */
-   assert(dst->texture && src->texture);
-   if (!dst->texture || !src->texture)
-      return;
-
-   is_depth = util_format_get_component_bits(src->format, UTIL_FORMAT_COLORSPACE_ZS, 0) != 0;
-   is_stencil = util_format_get_component_bits(src->format, UTIL_FORMAT_COLORSPACE_ZS, 1) != 0;
-   dst_tex_usage = is_depth || is_stencil ? PIPE_TEXTURE_USAGE_DEPTH_STENCIL :
-                                            PIPE_TEXTURE_USAGE_RENDER_TARGET;
-
-   /* check if we can sample from and render to the surfaces */
-   /* (assuming copying a stencil buffer is not possible) */
-   if ((!ignore_stencil && is_stencil) ||
-       !screen->is_format_supported(screen, dst->format, dst->texture->target,
-                                    dst_tex_usage, 0) ||
-       !screen->is_format_supported(screen, src->format, src->texture->target,
-                                    PIPE_TEXTURE_USAGE_SAMPLER, 0)) {
-      util_surface_copy(pipe, FALSE, dst, dstx, dsty, src, srcx, srcy,
-                        width, height);
-      return;
-   }
-
-   /* check whether the states are properly saved */
-   blitter_check_saved_CSOs(ctx);
    assert(blitter->saved_fb_state.nr_cbufs != ~0);
    assert(blitter->saved_num_textures != ~0);
    assert(blitter->saved_num_sampler_states != ~0);
@@ -663,6 +635,108 @@ void util_blitter_copy(struct blitter_context *blitter,
 
    blitter_set_rectangle(ctx, dstx, dsty, dstx+width, dsty+height, 0);
    blitter_draw_quad(ctx);
+
+}
+
+static void util_blitter_overlap_copy(struct blitter_context *blitter,
+                                     struct pipe_surface *dst,
+                                     unsigned dstx, unsigned dsty,
+                                     struct pipe_surface *src,
+                                     unsigned srcx, unsigned srcy,
+                                     unsigned width, unsigned height)
+{
+   struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_screen *screen = pipe->screen;
+
+   struct pipe_texture texTemp;
+   struct pipe_texture *texture;
+   struct pipe_surface *tex_surf;
+
+   /* check whether the states are properly saved */
+   blitter_check_saved_CSOs(ctx);
+
+   memset(&texTemp, 0, sizeof(texTemp));
+   texTemp.target = PIPE_TEXTURE_2D;
+   texTemp.format = dst->texture->format; /* XXX verify supported by driver! */
+   texTemp.last_level = 0;
+   texTemp.width0 = width;
+   texTemp.height0 = height;
+   texTemp.depth0 = 1;
+
+   texture = screen->texture_create(screen, &texTemp);
+   if (!texture)
+      return;
+
+   tex_surf = screen->get_tex_surface(screen, texture, 0, 0, 0,
+                                     PIPE_BUFFER_USAGE_GPU_READ | 
+                                     PIPE_BUFFER_USAGE_GPU_WRITE);
+
+   /* blit from the src to the temp */
+   util_blitter_do_copy(blitter, tex_surf, 0, 0,
+                       src, srcx, srcy,
+                       width, height,
+                       FALSE);
+   util_blitter_do_copy(blitter, dst, dstx, dsty,
+                       tex_surf, 0, 0,
+                       width, height,
+                       FALSE);
+   pipe_surface_reference(&tex_surf, NULL);
+   pipe_texture_reference(&texture, NULL);
+   blitter_restore_CSOs(ctx);
+}
+
+void util_blitter_copy(struct blitter_context *blitter,
+                       struct pipe_surface *dst,
+                       unsigned dstx, unsigned dsty,
+                       struct pipe_surface *src,
+                       unsigned srcx, unsigned srcy,
+                       unsigned width, unsigned height,
+                       boolean ignore_stencil)
+{
+   struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
+   struct pipe_context *pipe = ctx->pipe;
+   struct pipe_screen *screen = pipe->screen;
+   boolean is_stencil, is_depth;
+   unsigned dst_tex_usage;
+
+   /* give up if textures are not set */
+   assert(dst->texture && src->texture);
+   if (!dst->texture || !src->texture)
+      return;
+
+   if (dst->texture == src->texture) {
+      if (is_overlap(srcx, srcx + width, srcy, srcy + height,
+                            dstx, dstx + width, dsty, dsty + height)) {
+         util_blitter_overlap_copy(blitter, dst, dstx, dsty, src, srcx, srcy,
+                                   width, height);
+         return;
+      }
+   }
+                  
+   is_depth = util_format_get_component_bits(src->format, UTIL_FORMAT_COLORSPACE_ZS, 0) != 0;
+   is_stencil = util_format_get_component_bits(src->format, UTIL_FORMAT_COLORSPACE_ZS, 1) != 0;
+   dst_tex_usage = is_depth || is_stencil ? PIPE_TEXTURE_USAGE_DEPTH_STENCIL :
+                                            PIPE_TEXTURE_USAGE_RENDER_TARGET;
+
+   /* check if we can sample from and render to the surfaces */
+   /* (assuming copying a stencil buffer is not possible) */
+   if ((!ignore_stencil && is_stencil) ||
+       !screen->is_format_supported(screen, dst->format, dst->texture->target,
+                                    dst_tex_usage, 0) ||
+       !screen->is_format_supported(screen, src->format, src->texture->target,
+                                    PIPE_TEXTURE_USAGE_SAMPLER, 0)) {
+      util_surface_copy(pipe, FALSE, dst, dstx, dsty, src, srcx, srcy,
+                        width, height);
+      return;
+   }
+
+   /* check whether the states are properly saved */
+   blitter_check_saved_CSOs(ctx);
+   util_blitter_do_copy(blitter,
+                       dst, dstx, dsty,
+                       src, srcx, srcy,
+                       width, height, is_depth);
    blitter_restore_CSOs(ctx);
 }