replace _mesa_logbase2 with util_logbase2
[mesa.git] / src / mesa / state_tracker / st_cb_copyimage.c
index 75114cdb712a254d78bd41fb12b8fefb891c53e4..a58cdf62703397640d310352c824b721ef0a5220 100644 (file)
  */
 
 #include "state_tracker/st_context.h"
+#include "state_tracker/st_cb_bitmap.h"
 #include "state_tracker/st_cb_copyimage.h"
 #include "state_tracker/st_cb_fbo.h"
 #include "state_tracker/st_texture.h"
+#include "state_tracker/st_util.h"
 
 #include "util/u_box.h"
-#include "util/u_format.h"
+#include "util/format/u_format.h"
 #include "util/u_inlines.h"
 
 
@@ -67,34 +69,34 @@ get_canonical_format(enum pipe_format format)
        desc->channel[1].size == 10 &&
        desc->channel[2].size == 10 &&
        desc->channel[3].size == 2) {
-      if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_X &&
-          desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_Y &&
-          desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_Z)
+      if (desc->swizzle[0] == PIPE_SWIZZLE_X &&
+          desc->swizzle[1] == PIPE_SWIZZLE_Y &&
+          desc->swizzle[2] == PIPE_SWIZZLE_Z)
          return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT);
 
       return PIPE_FORMAT_NONE;
    }
 
 #define RETURN_FOR_SWIZZLE1(x, format) \
-   if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_##x) \
+   if (desc->swizzle[0] == PIPE_SWIZZLE_##x) \
       return format
 
 #define RETURN_FOR_SWIZZLE2(x, y, format) \
-   if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_##x && \
-       desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_##y) \
+   if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
+       desc->swizzle[1] == PIPE_SWIZZLE_##y) \
       return format
 
 #define RETURN_FOR_SWIZZLE3(x, y, z, format) \
-   if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_##x && \
-       desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_##y && \
-       desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_##z) \
+   if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
+       desc->swizzle[1] == PIPE_SWIZZLE_##y && \
+       desc->swizzle[2] == PIPE_SWIZZLE_##z) \
       return format
 
 #define RETURN_FOR_SWIZZLE4(x, y, z, w, format) \
-   if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_##x && \
-       desc->swizzle[1] == UTIL_FORMAT_SWIZZLE_##y && \
-       desc->swizzle[2] == UTIL_FORMAT_SWIZZLE_##z && \
-       desc->swizzle[3] == UTIL_FORMAT_SWIZZLE_##w) \
+   if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
+       desc->swizzle[1] == PIPE_SWIZZLE_##y && \
+       desc->swizzle[2] == PIPE_SWIZZLE_##z && \
+       desc->swizzle[3] == PIPE_SWIZZLE_##w) \
       return format
 
    /* Array formats. */
@@ -161,9 +163,9 @@ get_canonical_format(enum pipe_format format)
             RETURN_FOR_SWIZZLE4(Z, Y, X, W, PIPE_FORMAT_B8G8R8A8_UNORM);
             RETURN_FOR_SWIZZLE4(Z, Y, X, 1, PIPE_FORMAT_B8G8R8A8_UNORM);
             RETURN_FOR_SWIZZLE4(W, Z, Y, X, PIPE_FORMAT_A8B8G8R8_UNORM);
-            RETURN_FOR_SWIZZLE4(1, Z, Y, X, PIPE_FORMAT_A8B8G8R8_UNORM);
-            RETURN_FOR_SWIZZLE4(W, X, Y, Z, PIPE_FORMAT_A8R8G8B8_UNORM);
-            RETURN_FOR_SWIZZLE4(1, X, Y, Z, PIPE_FORMAT_A8R8G8B8_UNORM);
+            RETURN_FOR_SWIZZLE4(W, Z, Y, 1, PIPE_FORMAT_A8B8G8R8_UNORM);
+            RETURN_FOR_SWIZZLE4(Y, Z, W, X, PIPE_FORMAT_A8R8G8B8_UNORM);
+            RETURN_FOR_SWIZZLE4(Y, Z, W, 1, PIPE_FORMAT_A8R8G8B8_UNORM);
             break;
 
          case 16:
@@ -196,7 +198,7 @@ has_identity_swizzle(const struct util_format_description *desc)
    int i;
 
    for (i = 0; i < desc->nr_channels; i++)
-      if (desc->swizzle[i] != UTIL_FORMAT_SWIZZLE_X + i)
+      if (desc->swizzle[i] != PIPE_SWIZZLE_X + i)
          return false;
 
    return true;
@@ -348,8 +350,8 @@ same_size_and_swizzle(const struct util_format_description *d1,
       if (d1->channel[i].size != d2->channel[i].size)
          return false;
 
-      if (d1->swizzle[i] <= UTIL_FORMAT_SWIZZLE_W &&
-          d2->swizzle[i] <= UTIL_FORMAT_SWIZZLE_W &&
+      if (d1->swizzle[i] <= PIPE_SWIZZLE_W &&
+          d2->swizzle[i] <= PIPE_SWIZZLE_W &&
           d1->swizzle[i] != d2->swizzle[i])
          return false;
    }
@@ -359,7 +361,7 @@ same_size_and_swizzle(const struct util_format_description *d1,
 
 static struct pipe_resource *
 create_texture(struct pipe_screen *screen, enum pipe_format format,
-               unsigned nr_samples,
+               unsigned nr_samples, unsigned nr_storage_samples,
                unsigned width, unsigned height, unsigned depth)
 {
    struct pipe_resource templ;
@@ -371,6 +373,7 @@ create_texture(struct pipe_screen *screen, enum pipe_format format,
    templ.depth0 = 1;
    templ.array_size = depth;
    templ.nr_samples = nr_samples;
+   templ.nr_storage_samples = nr_storage_samples;
    templ.usage = PIPE_USAGE_DEFAULT;
    templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
 
@@ -442,7 +445,7 @@ handle_complex_copy(struct pipe_context *pipe,
        * then proceed the generic swizzled_copy.
        */
       temp = create_texture(pipe->screen, canon_format, src->nr_samples,
-                            src_box->width,
+                            src->nr_storage_samples, src_box->width,
                             src_box->height, src_box->depth);
 
       u_box_3d(0, 0, 0, src_box->width, src_box->height, src_box->depth,
@@ -467,7 +470,7 @@ handle_complex_copy(struct pipe_context *pipe,
       /* Use the temporary texture. First, use the generic copy, but use
        * a canonical format in the destination. Then convert */
       temp = create_texture(pipe->screen, canon_format, dst->nr_samples,
-                            src_box->width,
+                            dst->nr_storage_samples, src_box->width,
                             src_box->height, src_box->depth);
 
       u_box_3d(0, 0, 0, src_box->width, src_box->height, src_box->depth,
@@ -531,6 +534,95 @@ copy_image(struct pipe_context *pipe,
                  src_box);
 }
 
+static void
+fallback_copy_image(struct st_context *st,
+                    struct gl_texture_image *dst_image,
+                    struct pipe_resource *dst_res,
+                    int dst_x, int dst_y, int dst_z,
+                    struct gl_texture_image *src_image,
+                    struct pipe_resource *src_res,
+                    int src_x, int src_y, int src_z,
+                    int src_w, int src_h)
+{
+   uint8_t *dst, *src;
+   int dst_stride, src_stride;
+   struct pipe_transfer *dst_transfer, *src_transfer;
+   unsigned line_bytes;
+
+   bool dst_is_compressed = dst_image && _mesa_is_format_compressed(dst_image->TexFormat);
+   bool src_is_compressed = src_image && _mesa_is_format_compressed(src_image->TexFormat);
+
+   unsigned dst_blk_w = 1, dst_blk_h = 1, src_blk_w = 1, src_blk_h = 1;
+   if (dst_image)
+      _mesa_get_format_block_size(dst_image->TexFormat, &dst_blk_w, &dst_blk_h);
+   if (src_image)
+      _mesa_get_format_block_size(src_image->TexFormat, &src_blk_w, &src_blk_h);
+
+   unsigned dst_w = src_w;
+   unsigned dst_h = src_h;
+   unsigned lines = src_h;
+
+   if (src_is_compressed && !dst_is_compressed) {
+      dst_w = DIV_ROUND_UP(dst_w, src_blk_w);
+      dst_h = DIV_ROUND_UP(dst_h, src_blk_h);
+   } else if (!src_is_compressed && dst_is_compressed) {
+      dst_w *= dst_blk_w;
+      dst_h *= dst_blk_h;
+   }
+   if (src_is_compressed) {
+      lines = DIV_ROUND_UP(lines, src_blk_h);
+   }
+
+   if (src_image)
+      line_bytes = _mesa_format_row_stride(src_image->TexFormat, src_w);
+   else
+      line_bytes = _mesa_format_row_stride(dst_image->TexFormat, dst_w);
+
+   if (dst_image) {
+      st->ctx->Driver.MapTextureImage(
+            st->ctx, dst_image, dst_z,
+            dst_x, dst_y, dst_w, dst_h,
+            GL_MAP_WRITE_BIT, &dst, &dst_stride);
+   } else {
+      dst = pipe_transfer_map(st->pipe, dst_res, 0, dst_z,
+                              PIPE_TRANSFER_WRITE,
+                              dst_x, dst_y, dst_w, dst_h,
+                              &dst_transfer);
+      dst_stride = dst_transfer->stride;
+   }
+
+   if (src_image) {
+      st->ctx->Driver.MapTextureImage(
+            st->ctx, src_image, src_z,
+            src_x, src_y, src_w, src_h,
+            GL_MAP_READ_BIT, &src, &src_stride);
+   } else {
+      src = pipe_transfer_map(st->pipe, src_res, 0, src_z,
+                              PIPE_TRANSFER_READ,
+                              src_x, src_y, src_w, src_h,
+                              &src_transfer);
+      src_stride = src_transfer->stride;
+   }
+
+   for (int y = 0; y < lines; y++) {
+      memcpy(dst, src, line_bytes);
+      dst += dst_stride;
+      src += src_stride;
+   }
+
+   if (dst_image) {
+      st->ctx->Driver.UnmapTextureImage(st->ctx, dst_image, dst_z);
+   } else {
+      pipe_transfer_unmap(st->pipe, dst_transfer);
+   }
+
+   if (src_image) {
+      st->ctx->Driver.UnmapTextureImage(st->ctx, src_image, src_z);
+   } else {
+      pipe_transfer_unmap(st->pipe, src_transfer);
+   }
+}
+
 static void
 st_CopyImageSubData(struct gl_context *ctx,
                     struct gl_texture_image *src_image,
@@ -546,12 +638,20 @@ st_CopyImageSubData(struct gl_context *ctx,
    struct pipe_resource *src_res, *dst_res;
    struct pipe_box box;
    int src_level, dst_level;
+   int orig_src_z = src_z, orig_dst_z = dst_z;
+
+   st_flush_bitmap_cache(st);
+   st_invalidate_readpix_cache(st);
 
    if (src_image) {
       struct st_texture_image *src = st_texture_image(src_image);
       src_res = src->pt;
       src_level = src_image->Level;
       src_z += src_image->Face;
+      if (src_image->TexObject->Immutable) {
+         src_level += src_image->TexObject->MinLevel;
+         src_z += src_image->TexObject->MinLayer;
+      }
    } else {
       struct st_renderbuffer *src = st_renderbuffer(src_renderbuffer);
       src_res = src->texture;
@@ -563,6 +663,10 @@ st_CopyImageSubData(struct gl_context *ctx,
       dst_res = dst->pt;
       dst_level = dst_image->Level;
       dst_z += dst_image->Face;
+      if (dst_image->TexObject->Immutable) {
+         dst_level += dst_image->TexObject->MinLevel;
+         dst_z += dst_image->TexObject->MinLayer;
+      }
    } else {
       struct st_renderbuffer *dst = st_renderbuffer(dst_renderbuffer);
       dst_res = dst->texture;
@@ -571,8 +675,15 @@ st_CopyImageSubData(struct gl_context *ctx,
 
    u_box_2d_zslice(src_x, src_y, src_z, src_width, src_height, &box);
 
-   copy_image(pipe, dst_res, dst_level, dst_x, dst_y, dst_z,
-              src_res, src_level, &box);
+   if ((src_image && st_compressed_format_fallback(st, src_image->TexFormat)) ||
+       (dst_image && st_compressed_format_fallback(st, dst_image->TexFormat))) {
+      fallback_copy_image(st, dst_image, dst_res, dst_x, dst_y, orig_dst_z,
+                          src_image, src_res, src_x, src_y, orig_src_z,
+                          src_width, src_height);
+   } else {
+      copy_image(pipe, dst_res, dst_level, dst_x, dst_y, dst_z,
+                 src_res, src_level, &box);
+   }
 }
 
 void