replace _mesa_logbase2 with util_logbase2
[mesa.git] / src / mesa / state_tracker / st_cb_readpixels.c
index 39d2274b3b432bebc599b5a333d76bbfbaa6571b..96526508cfc1933599a3fa68f70ea4e79e51b3ba 100644 (file)
 #include "main/bufferobj.h"
 #include "main/image.h"
 #include "main/pbo.h"
-#include "main/imports.h"
+#include "util/imports.h"
 #include "main/readpix.h"
 #include "main/enums.h"
 #include "main/framebuffer.h"
 #include "util/u_inlines.h"
-#include "util/u_format.h"
+#include "util/format/u_format.h"
 #include "cso_cache/cso_context.h"
 
 #include "st_cb_fbo.h"
@@ -46,6 +46,8 @@
 #include "state_tracker/st_format.h"
 #include "state_tracker/st_pbo.h"
 #include "state_tracker/st_texture.h"
+#include "state_tracker/st_util.h"
+
 
 /* The readpixels cache caches a blitted staging texture so that back-to-back
  * calls to glReadPixels with user pointers require less CPU-GPU synchronization.
@@ -112,8 +114,7 @@ try_pbo_readpixels(struct st_context *st, struct st_renderbuffer *strb,
    if (texture->nr_samples > 1)
       return false;
 
-   if (!screen->is_format_supported(screen, dst_format, PIPE_TEXTURE_2D,
-                                    texture->nr_samples,
+   if (!screen->is_format_supported(screen, dst_format, PIPE_BUFFER, 0, 0,
                                     PIPE_BIND_SHADER_IMAGE))
       return false;
 
@@ -132,6 +133,7 @@ try_pbo_readpixels(struct st_context *st, struct st_renderbuffer *strb,
    cso_save_state(cso, (CSO_BIT_FRAGMENT_SAMPLER_VIEWS |
                         CSO_BIT_FRAGMENT_SAMPLERS |
                         CSO_BIT_FRAGMENT_IMAGE0 |
+                        CSO_BIT_BLEND |
                         CSO_BIT_VERTEX_ELEMENTS |
                         CSO_BIT_AUX_VERTEX_BUFFER_SLOT |
                         CSO_BIT_FRAMEBUFFER |
@@ -139,10 +141,17 @@ try_pbo_readpixels(struct st_context *st, struct st_renderbuffer *strb,
                         CSO_BIT_RASTERIZER |
                         CSO_BIT_DEPTH_STENCIL_ALPHA |
                         CSO_BIT_STREAM_OUTPUTS |
-                        CSO_BIT_PAUSE_QUERIES |
+                        (st->active_queries ? CSO_BIT_PAUSE_QUERIES : 0) |
+                        CSO_BIT_SAMPLE_MASK |
+                        CSO_BIT_MIN_SAMPLES |
+                        CSO_BIT_RENDER_CONDITION |
                         CSO_BITS_ALL_SHADERS));
    cso_save_constant_buffer_slot0(cso, PIPE_SHADER_FRAGMENT);
 
+   cso_set_sample_mask(cso, ~0);
+   cso_set_min_samples(cso, 1);
+   cso_set_render_condition(cso, NULL, FALSE, 0);
+
    /* Set up the sampler_view */
    {
       struct pipe_sampler_view templ;
@@ -168,7 +177,7 @@ try_pbo_readpixels(struct st_context *st, struct st_renderbuffer *strb,
 
       if (view_target != PIPE_TEXTURE_3D) {
          templ.u.tex.first_layer = surface->u.tex.first_layer;
-         templ.u.tex.last_layer = templ.u.tex.last_layer;
+         templ.u.tex.last_layer = templ.u.tex.first_layer;
       } else {
          addr.constants.layer_offset = surface->u.tex.first_layer;
       }
@@ -192,8 +201,10 @@ try_pbo_readpixels(struct st_context *st, struct st_renderbuffer *strb,
       image.resource = addr.buffer;
       image.format = dst_format;
       image.access = PIPE_IMAGE_ACCESS_WRITE;
-      image.u.buf.first_element = addr.first_element;
-      image.u.buf.last_element = addr.last_element;
+      image.shader_access = PIPE_IMAGE_ACCESS_WRITE;
+      image.u.buf.offset = addr.first_element * addr.bytes_per_pixel;
+      image.u.buf.size = (addr.last_element - addr.first_element + 1) *
+                         addr.bytes_per_pixel;
 
       cso_set_shader_images(cso, PIPE_SHADER_FRAGMENT, 0, 1, &image);
    }
@@ -206,6 +217,11 @@ try_pbo_readpixels(struct st_context *st, struct st_renderbuffer *strb,
    fb.layers = 1;
    cso_set_framebuffer(cso, &fb);
 
+   /* Any blend state would do. Set this just to prevent drivers having
+    * blend == NULL.
+    */
+   cso_set_blend(cso, &st->pbo.upload_blend);
+
    cso_set_viewport_dims(cso, fb.width, fb.height, invert_y);
 
    if (invert_y)
@@ -219,7 +235,7 @@ try_pbo_readpixels(struct st_context *st, struct st_renderbuffer *strb,
 
    /* Set up the fragment shader */
    {
-      void *fs = st_pbo_get_download_fs(st, view_target);
+      void *fs = st_pbo_get_download_fs(st, view_target, src_format, dst_format);
       if (!fs)
          goto fail;
 
@@ -238,14 +254,6 @@ fail:
    return success;
 }
 
-/* Invalidate the readpixels cache to ensure we don't read stale data.
- */
-void st_invalidate_readpix_cache(struct st_context *st)
-{
-   pipe_resource_reference(&st->readpix_cache.src, NULL);
-   pipe_resource_reference(&st->readpix_cache.cache, NULL);
-}
-
 /**
  * Create a staging texture and blit the requested region to it.
  */
@@ -265,15 +273,14 @@ blit_to_staging(struct st_context *st, struct st_renderbuffer *strb,
    /* We are creating a texture of the size of the region being read back.
     * Need to check for NPOT texture support. */
    if (!screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES) &&
-       (!util_is_power_of_two(width) ||
-        !util_is_power_of_two(height)))
+       (!util_is_power_of_two_or_zero(width) ||
+        !util_is_power_of_two_or_zero(height)))
       return NULL;
 
    /* create the destination texture */
    memset(&dst_templ, 0, sizeof(dst_templ));
    dst_templ.target = PIPE_TEXTURE_2D;
    dst_templ.format = dst_format;
-   dst_templ.bind = PIPE_BIND_TRANSFER_READ;
    if (util_format_is_depth_or_stencil(dst_format))
       dst_templ.bind |= PIPE_BIND_DEPTH_STENCIL;
    else
@@ -403,14 +410,14 @@ st_ReadPixels(struct gl_context *ctx, GLint x, GLint y,
    struct pipe_resource *src;
    struct pipe_resource *dst = NULL;
    enum pipe_format dst_format, src_format;
-   unsigned bind = PIPE_BIND_TRANSFER_READ;
+   unsigned bind;
    struct pipe_transfer *tex_xfer;
    ubyte *map = NULL;
-   bool window;
+   int dst_x, dst_y;
 
    /* Validate state (to be sure we have up-to-date framebuffer surfaces)
     * and flush the bitmap cache prior to reading. */
-   st_validate_state(st, ST_PIPELINE_RENDER);
+   st_validate_state(st, ST_PIPELINE_UPDATE_FRAMEBUFFER);
    st_flush_bitmap_cache(st);
 
    if (!st->prefer_blit_based_texture_transfer) {
@@ -445,15 +452,15 @@ st_ReadPixels(struct gl_context *ctx, GLint x, GLint y,
 
    if (!src_format ||
        !screen->is_format_supported(screen, src_format, src->target,
-                                    src->nr_samples,
+                                    src->nr_samples, src->nr_storage_samples,
                                     PIPE_BIND_SAMPLER_VIEW)) {
       goto fallback;
    }
 
    if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)
-      bind |= PIPE_BIND_DEPTH_STENCIL;
+      bind = PIPE_BIND_DEPTH_STENCIL;
    else
-      bind |= PIPE_BIND_RENDER_TARGET;
+      bind = PIPE_BIND_RENDER_TARGET;
 
    /* Choose the destination format by finding the best match
     * for the format+type combo. */
@@ -463,7 +470,7 @@ st_ReadPixels(struct gl_context *ctx, GLint x, GLint y,
       goto fallback;
    }
 
-   if (st->pbo.download_enabled && _mesa_is_bufferobj(pack->BufferObj)) {
+   if (st->pbo.download_enabled && pack->BufferObj) {
       if (try_pbo_readpixels(st, strb,
                              st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP,
                              x, y, width, height,
@@ -483,7 +490,8 @@ st_ReadPixels(struct gl_context *ctx, GLint x, GLint y,
                                st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP,
                                width, height, format, src_format, dst_format);
    if (dst) {
-      window = false;
+      dst_x = x;
+      dst_y = y;
    } else {
       /* See if the texture format already matches the format and type,
        * in which case the memcpy-based fast path will likely be used and
@@ -500,34 +508,39 @@ st_ReadPixels(struct gl_context *ctx, GLint x, GLint y,
       if (!dst)
          goto fallback;
 
-      window = true;
+      dst_x = 0;
+      dst_y = 0;
    }
 
    /* map resources */
    pixels = _mesa_map_pbo_dest(ctx, pack, pixels);
 
    map = pipe_transfer_map_3d(pipe, dst, 0, PIPE_TRANSFER_READ,
-                              0, 0, 0, width, height, 1, &tex_xfer);
+                              dst_x, dst_y, 0, width, height, 1, &tex_xfer);
    if (!map) {
       _mesa_unmap_pbo_dest(ctx, pack);
       pipe_resource_reference(&dst, NULL);
       goto fallback;
    }
 
-   if (!window)
-      map += y * tex_xfer->stride + x * util_format_get_blocksize(dst_format);
-
    /* memcpy data into a user buffer */
    {
       const uint bytesPerRow = width * util_format_get_blocksize(dst_format);
-      GLuint row;
-
-      for (row = 0; row < (unsigned) height; row++) {
-         void *dest = _mesa_image_address2d(pack, pixels,
-                                              width, height, format,
-                                              type, row, 0);
-         memcpy(dest, map, bytesPerRow);
-         map += tex_xfer->stride;
+      const int destStride = _mesa_image_row_stride(pack, width, format, type);
+      char *dest = _mesa_image_address2d(pack, pixels,
+                                         width, height, format,
+                                         type, 0, 0);
+
+      if (tex_xfer->stride == bytesPerRow && destStride == bytesPerRow) {
+         memcpy(dest, map, bytesPerRow * height);
+      } else {
+         GLuint row;
+
+         for (row = 0; row < (unsigned) height; row++) {
+            memcpy(dest, map, bytesPerRow);
+            map += tex_xfer->stride;
+            dest += destStride;
+         }
       }
    }