st/mesa: optimize DEPTH_STENCIL copies using fragment shader
[mesa.git] / src / mesa / state_tracker / st_cb_drawpixels.c
index 6b47548d33ba7ab7355a3bf4c5a12728d7fe9bef..2a1ac8f4f0269df4ab47c4e94d5720eaacb32c14 100644 (file)
@@ -1,8 +1,8 @@
 /**************************************************************************
- * 
+ *
  * Copyright 2007 VMware, Inc.
  * All Rights Reserved.
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the
  * "Software"), to deal in the Software without restriction, including
  * distribute, sub license, and/or sell copies of the Software, and to
  * permit persons to whom the Software is furnished to do so, subject to
  * the following conditions:
- * 
+ *
  * The above copyright notice and this permission notice (including the
  * next paragraph) shall be included in all copies or substantial portions
  * of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
@@ -22,7 +22,7 @@
  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- * 
+ *
  **************************************************************************/
 
  /*
@@ -31,7 +31,7 @@
   */
 
 #include "main/errors.h"
-#include "main/imports.h"
+
 #include "main/image.h"
 #include "main/bufferobj.h"
 #include "main/blit.h"
 
 static nir_ssa_def *
 sample_via_nir(nir_builder *b, nir_variable *texcoord,
-               const char *name, int sampler)
+               const char *name, int sampler, enum glsl_base_type base_type,
+               nir_alu_type alu_type)
 {
    const struct glsl_type *sampler2D =
-      glsl_sampler_type(GLSL_SAMPLER_DIM_2D, false, false, GLSL_TYPE_FLOAT);
+      glsl_sampler_type(GLSL_SAMPLER_DIM_2D, false, false, base_type);
 
    nir_variable *var =
       nir_variable_create(b->shader, nir_var_uniform, sampler2D, name);
@@ -127,7 +128,7 @@ sample_via_nir(nir_builder *b, nir_variable *texcoord,
    tex->op = nir_texop_tex;
    tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
    tex->coord_components = 2;
-   tex->dest_type = nir_type_float;
+   tex->dest_type = alu_type;
    tex->src[0].src_type = nir_tex_src_texture_deref;
    tex->src[0].src = nir_src_for_ssa(&deref->dest.ssa);
    tex->src[1].src_type = nir_tex_src_sampler_deref;
@@ -163,7 +164,8 @@ make_drawpix_z_stencil_program_nir(struct st_context *st,
          nir_variable_create(b.shader, nir_var_shader_out, glsl_float_type(),
                              "gl_FragDepth");
       out->data.location = FRAG_RESULT_DEPTH;
-      nir_ssa_def *depth = sample_via_nir(&b, texcoord, "depth", 0);
+      nir_ssa_def *depth = sample_via_nir(&b, texcoord, "depth", 0,
+                                          GLSL_TYPE_FLOAT, nir_type_float);
       nir_store_var(&b, out, depth, 0x1);
 
       /* Also copy color */
@@ -184,7 +186,8 @@ make_drawpix_z_stencil_program_nir(struct st_context *st,
          nir_variable_create(b.shader, nir_var_shader_out, glsl_uint_type(),
                              "gl_FragStencilRefARB");
       out->data.location = FRAG_RESULT_STENCIL;
-      nir_ssa_def *stencil = sample_via_nir(&b, texcoord, "stencil", 1);
+      nir_ssa_def *stencil = sample_via_nir(&b, texcoord, "stencil", 1,
+                                            GLSL_TYPE_UINT, nir_type_uint);
       nir_store_var(&b, out, stencil, 0x1);
    }
 
@@ -500,7 +503,7 @@ search_drawpixels_cache(struct st_context *st,
        unpack->SkipPixels != 0 ||
        unpack->SkipRows != 0 ||
        unpack->SwapBytes ||
-       _mesa_is_bufferobj(unpack->BufferObj)) {
+       unpack->BufferObj) {
       /* we don't allow non-default pixel unpacking values */
       return NULL;
    }
@@ -722,12 +725,12 @@ make_texture(struct st_context *st,
       ctx->_ImageTransferState = imageTransferStateSave;
    }
 
-   _mesa_unmap_pbo_source(ctx, unpack);
-
 #if USE_DRAWPIXELS_CACHE
    cache_drawpixels_image(st, width, height, format, type, unpack, pixels, pt);
 #endif
 
+   _mesa_unmap_pbo_source(ctx, unpack);
+
    return pt;
 }
 
@@ -893,7 +896,8 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z,
    /* viewport state: viewport matching window dims */
    cso_set_viewport_dims(cso, fb_width, fb_height, TRUE);
 
-   cso_set_vertex_elements(cso, 3, st->util_velems);
+   st->util_velems.count = 3;
+   cso_set_vertex_elements(cso, &st->util_velems);
    cso_set_stream_outputs(cso, 0, NULL, NULL);
 
    /* Compute Gallium window coords (y=0=top) with pixel zoom.
@@ -973,7 +977,7 @@ draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y,
       y = ctx->DrawBuffer->Height - y - height;
    }
 
-   if (format == GL_STENCIL_INDEX && 
+   if (format == GL_STENCIL_INDEX &&
        _mesa_is_format_packed_depth_stencil(strb->Base.Format)) {
       /* writing stencil to a combined depth+stencil buffer */
       usage = PIPE_TRANSFER_READ_WRITE;
@@ -1363,7 +1367,7 @@ st_DrawPixels(struct gl_context *ctx, GLint x, GLint y,
       fpv = (format != GL_COLOR_INDEX) ? get_color_fp_variant(st) :
                                          get_color_index_fp_variant(st);
 
-      driver_fp = fpv->driver_shader;
+      driver_fp = fpv->base.driver_shader;
 
       if (ctx->Pixel.MapColorFlag && format != GL_COLOR_INDEX) {
          pipe_sampler_view_reference(&sv[1],
@@ -1700,6 +1704,8 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
    GLboolean invertTex = GL_FALSE;
    GLint readX, readY, readW, readH;
    struct gl_pixelstore_attrib pack = ctx->DefaultPacking;
+   GLboolean write_stencil = GL_FALSE;
+   GLboolean write_depth = GL_FALSE;
 
    _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer);
 
@@ -1711,15 +1717,17 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
    if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type))
       return;
 
-   if (type == GL_DEPTH_STENCIL) {
-      /* XXX make this more efficient */
+   /* fallback if the driver can't do stencil exports */
+   if (type == GL_DEPTH_STENCIL &&
+      !pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) {
       st_CopyPixels(ctx, srcx, srcy, width, height, dstx, dsty, GL_STENCIL);
       st_CopyPixels(ctx, srcx, srcy, width, height, dstx, dsty, GL_DEPTH);
       return;
    }
 
-   if (type == GL_STENCIL) {
-      /* can't use texturing to do stencil */
+   /* fallback if the driver can't do stencil exports */
+   if (type == GL_STENCIL &&
+       !pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) {
       copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
       return;
    }
@@ -1741,7 +1749,7 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
 
       rbRead = st_get_color_read_renderbuffer(ctx);
 
-      driver_fp = fpv->driver_shader;
+      driver_fp = fpv->base.driver_shader;
 
       if (ctx->Pixel.MapColorFlag) {
          pipe_sampler_view_reference(&sv[1],
@@ -1753,15 +1761,22 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
        * into the constant buffer, we need to update them
        */
       st_upload_constants(st, &st->fp->Base);
-   }
-   else {
-      assert(type == GL_DEPTH);
+   } else if (type == GL_DEPTH) {
       rbRead = st_renderbuffer(ctx->ReadBuffer->
                                Attachment[BUFFER_DEPTH].Renderbuffer);
-
       driver_fp = get_drawpix_z_stencil_program(st, GL_TRUE, GL_FALSE);
+   } else if (type == GL_STENCIL) {
+      rbRead = st_renderbuffer(ctx->ReadBuffer->
+                               Attachment[BUFFER_STENCIL].Renderbuffer);
+      driver_fp = get_drawpix_z_stencil_program(st, GL_FALSE, GL_TRUE);
+   } else {
+      assert(type == GL_DEPTH_STENCIL);
+      rbRead = st_renderbuffer(ctx->ReadBuffer->
+                               Attachment[BUFFER_DEPTH].Renderbuffer);
+      driver_fp = get_drawpix_z_stencil_program(st, GL_TRUE, GL_TRUE);
    }
 
+
    /* Choose the format for the temporary texture. */
    srcFormat = rbRead->texture->format;
    srcBind = PIPE_BIND_SAMPLER_VIEW |
@@ -1775,6 +1790,11 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
                                       GL_NONE, st->internal_target, 0, 0,
                                       srcBind, false, false);
       }
+      else if (type == GL_STENCIL) {
+         /* can't use texturing, fallback to copy */
+         copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
+         return;
+      }
       else {
          assert(type == GL_COLOR);
 
@@ -1850,6 +1870,25 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
       return;
    }
 
+   /* Create a second sampler view to read stencil */
+   if (type == GL_STENCIL || type == GL_DEPTH_STENCIL) {
+      write_stencil = GL_TRUE;
+      if (type == GL_DEPTH_STENCIL)
+         write_depth = GL_TRUE;
+      enum pipe_format stencil_format =
+         util_format_stencil_only(pt->format);
+      /* we should not be doing pixel map/transfer (see above) */
+      assert(num_sampler_view == 1);
+      sv[1] = st_create_texture_sampler_view_format(st->pipe, pt,
+                                                    stencil_format);
+      if (!sv[1]) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
+         pipe_resource_reference(&pt, NULL);
+         pipe_sampler_view_reference(&sv[0], NULL);
+         return;
+      }
+      num_sampler_view++;
+   }
    /* Copy the src region to the temporary texture. */
    {
       struct pipe_blit_info blit;
@@ -1873,7 +1912,12 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
       blit.dst.box.width = readW;
       blit.dst.box.height = readH;
       blit.dst.box.depth = 1;
-      blit.mask = util_format_get_mask(pt->format) & ~PIPE_MASK_S;
+      if (type == GL_DEPTH)
+          blit.mask = util_format_get_mask(pt->format) & ~PIPE_MASK_S;
+      else if (type == GL_STENCIL)
+          blit.mask = util_format_get_mask(pt->format) & ~PIPE_MASK_Z;
+      else
+         blit.mask = util_format_get_mask(pt->format);
       blit.filter = PIPE_TEX_FILTER_NEAREST;
 
       pipe->blit(pipe, &blit);
@@ -1890,7 +1934,7 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
                       st->passthrough_vs,
                       driver_fp, fpv,
                       ctx->Current.Attrib[VERT_ATTRIB_COLOR0],
-                      invertTex, GL_FALSE, GL_FALSE);
+                      invertTex, write_depth, write_stencil);
 
    pipe_resource_reference(&pt, NULL);
    pipe_sampler_view_reference(&sv[0], NULL);
@@ -1912,12 +1956,11 @@ st_destroy_drawpix(struct st_context *st)
 
    for (i = 0; i < ARRAY_SIZE(st->drawpix.zs_shaders); i++) {
       if (st->drawpix.zs_shaders[i])
-         cso_delete_fragment_shader(st->cso_context,
-                                    st->drawpix.zs_shaders[i]);
+         st->pipe->delete_fs_state(st->pipe, st->drawpix.zs_shaders[i]);
    }
 
    if (st->passthrough_vs)
-      cso_delete_vertex_shader(st->cso_context, st->passthrough_vs);
+      st->pipe->delete_vs_state(st->pipe, st->passthrough_vs);
 
    /* Free cache data */
    for (i = 0; i < ARRAY_SIZE(st->drawpix_cache.entries); i++) {