| /* |
| * Copyright 2015 Advanced Micro Devices, Inc. |
| * |
| * 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 without limitation |
| * on the rights to use, copy, modify, merge, publish, 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. IN NO EVENT SHALL |
| * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR 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. |
| * |
| */ |
| |
| #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/format/u_format.h" |
| #include "util/u_inlines.h" |
| |
| |
| /** |
| * Return an equivalent canonical format without "X" channels. |
| * |
| * Copying between incompatible formats is easier when the format is |
| * canonicalized, meaning that it is in a standard form. |
| * |
| * The returned format has the same component sizes and swizzles as |
| * the source format, the type is changed to UINT or UNORM, depending on |
| * which one has the most swizzle combinations in their group. |
| * |
| * If it's not an array format, return a memcpy-equivalent array format. |
| * |
| * The key feature is that swizzled versions of formats of the same |
| * component size always return the same component type. |
| * |
| * X returns A. |
| * Luminance, intensity, alpha, depth, stencil, and 8-bit and 16-bit packed |
| * formats are not supported. (same as ARB_copy_image) |
| */ |
| static enum pipe_format |
| get_canonical_format(enum pipe_format format) |
| { |
| const struct util_format_description *desc = |
| util_format_description(format); |
| |
| /* Packed formats. Return the equivalent array format. */ |
| if (format == PIPE_FORMAT_R11G11B10_FLOAT || |
| format == PIPE_FORMAT_R9G9B9E5_FLOAT) |
| return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT); |
| |
| if (desc->nr_channels == 4 && |
| desc->channel[0].size == 10 && |
| desc->channel[1].size == 10 && |
| desc->channel[2].size == 10 && |
| desc->channel[3].size == 2) { |
| 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] == PIPE_SWIZZLE_##x) \ |
| return format |
| |
| #define RETURN_FOR_SWIZZLE2(x, y, format) \ |
| 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] == 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] == 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. */ |
| if (desc->is_array) { |
| switch (desc->nr_channels) { |
| case 1: |
| switch (desc->channel[0].size) { |
| case 8: |
| RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R8_UINT); |
| break; |
| |
| case 16: |
| RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R16_UINT); |
| break; |
| |
| case 32: |
| RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R32_UINT); |
| break; |
| } |
| break; |
| |
| case 2: |
| switch (desc->channel[0].size) { |
| case 8: |
| /* All formats in each group must be of the same type. |
| * We can't use UINT for R8G8 while using UNORM for G8R8. |
| */ |
| RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R8G8_UNORM); |
| RETURN_FOR_SWIZZLE2(Y, X, PIPE_FORMAT_G8R8_UNORM); |
| break; |
| |
| case 16: |
| RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R16G16_UNORM); |
| RETURN_FOR_SWIZZLE2(Y, X, PIPE_FORMAT_G16R16_UNORM); |
| break; |
| |
| case 32: |
| RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R32G32_UINT); |
| break; |
| } |
| break; |
| |
| case 3: |
| switch (desc->channel[0].size) { |
| case 8: |
| RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R8G8B8_UINT); |
| break; |
| |
| case 16: |
| RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R16G16B16_UINT); |
| break; |
| |
| case 32: |
| RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R32G32B32_UINT); |
| break; |
| } |
| break; |
| |
| case 4: |
| switch (desc->channel[0].size) { |
| case 8: |
| RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R8G8B8A8_UNORM); |
| RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R8G8B8A8_UNORM); |
| 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(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: |
| RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R16G16B16A16_UINT); |
| RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R16G16B16A16_UINT); |
| break; |
| |
| case 32: |
| RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R32G32B32A32_UINT); |
| RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R32G32B32A32_UINT); |
| break; |
| } |
| } |
| |
| assert(!"unknown array format"); |
| return PIPE_FORMAT_NONE; |
| } |
| |
| assert(!"unknown packed format"); |
| return PIPE_FORMAT_NONE; |
| } |
| |
| /** |
| * Return true if the swizzle is XYZW in case of a 4-channel format, |
| * XY in case of a 2-channel format, or X in case of a 1-channel format. |
| */ |
| static bool |
| has_identity_swizzle(const struct util_format_description *desc) |
| { |
| int i; |
| |
| for (i = 0; i < desc->nr_channels; i++) |
| if (desc->swizzle[i] != PIPE_SWIZZLE_X + i) |
| return false; |
| |
| return true; |
| } |
| |
| /** |
| * Return a canonical format for the given bits and channel size. |
| */ |
| static enum pipe_format |
| canonical_format_from_bits(unsigned bits, unsigned channel_size) |
| { |
| switch (bits) { |
| case 8: |
| if (channel_size == 8) |
| return get_canonical_format(PIPE_FORMAT_R8_UINT); |
| break; |
| |
| case 16: |
| if (channel_size == 8) |
| return get_canonical_format(PIPE_FORMAT_R8G8_UINT); |
| if (channel_size == 16) |
| return get_canonical_format(PIPE_FORMAT_R16_UINT); |
| break; |
| |
| case 32: |
| if (channel_size == 8) |
| return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT); |
| if (channel_size == 16) |
| return get_canonical_format(PIPE_FORMAT_R16G16_UINT); |
| if (channel_size == 32) |
| return get_canonical_format(PIPE_FORMAT_R32_UINT); |
| break; |
| |
| case 64: |
| if (channel_size == 16) |
| return get_canonical_format(PIPE_FORMAT_R16G16B16A16_UINT); |
| if (channel_size == 32) |
| return get_canonical_format(PIPE_FORMAT_R32G32_UINT); |
| break; |
| |
| case 128: |
| if (channel_size == 32) |
| return get_canonical_format(PIPE_FORMAT_R32G32B32A32_UINT); |
| break; |
| } |
| |
| assert(!"impossible format"); |
| return PIPE_FORMAT_NONE; |
| } |
| |
| static void |
| blit(struct pipe_context *pipe, |
| struct pipe_resource *dst, |
| enum pipe_format dst_format, |
| unsigned dst_level, |
| unsigned dstx, unsigned dsty, unsigned dstz, |
| struct pipe_resource *src, |
| enum pipe_format src_format, |
| unsigned src_level, |
| const struct pipe_box *src_box) |
| { |
| struct pipe_blit_info blit = {{0}}; |
| |
| blit.src.resource = src; |
| blit.dst.resource = dst; |
| blit.src.format = src_format; |
| blit.dst.format = dst_format; |
| blit.src.level = src_level; |
| blit.dst.level = dst_level; |
| blit.src.box = *src_box; |
| u_box_3d(dstx, dsty, dstz, src_box->width, src_box->height, |
| src_box->depth, &blit.dst.box); |
| blit.mask = PIPE_MASK_RGBA; |
| blit.filter = PIPE_TEX_FILTER_NEAREST; |
| |
| pipe->blit(pipe, &blit); |
| } |
| |
| static void |
| swizzled_copy(struct pipe_context *pipe, |
| struct pipe_resource *dst, |
| unsigned dst_level, |
| unsigned dstx, unsigned dsty, unsigned dstz, |
| struct pipe_resource *src, |
| unsigned src_level, |
| const struct pipe_box *src_box) |
| { |
| const struct util_format_description *src_desc, *dst_desc; |
| unsigned bits; |
| enum pipe_format blit_src_format, blit_dst_format; |
| |
| /* Get equivalent canonical formats. Those are always array formats and |
| * copying between compatible canonical formats behaves either like |
| * memcpy or like swizzled memcpy. The idea is that we won't have to care |
| * about the channel type from this point on. |
| * Only the swizzle and channel size. |
| */ |
| blit_src_format = get_canonical_format(src->format); |
| blit_dst_format = get_canonical_format(dst->format); |
| |
| assert(blit_src_format != PIPE_FORMAT_NONE); |
| assert(blit_dst_format != PIPE_FORMAT_NONE); |
| |
| src_desc = util_format_description(blit_src_format); |
| dst_desc = util_format_description(blit_dst_format); |
| |
| assert(src_desc->block.bits == dst_desc->block.bits); |
| bits = src_desc->block.bits; |
| |
| if (dst_desc->channel[0].size == src_desc->channel[0].size) { |
| /* Only the swizzle is different, which means we can just blit, |
| * e.g. RGBA -> BGRA. |
| */ |
| } else if (has_identity_swizzle(src_desc)) { |
| /* Src is unswizzled and dst can be swizzled, so src is typecast |
| * to an equivalent dst-compatible format. |
| * e.g. R32 -> BGRA8 is realized as RGBA8 -> BGRA8 |
| */ |
| blit_src_format = |
| canonical_format_from_bits(bits, dst_desc->channel[0].size); |
| } else if (has_identity_swizzle(dst_desc)) { |
| /* Dst is unswizzled and src can be swizzled, so dst is typecast |
| * to an equivalent src-compatible format. |
| * e.g. BGRA8 -> R32 is realized as BGRA8 -> RGBA8 |
| */ |
| blit_dst_format = |
| canonical_format_from_bits(bits, src_desc->channel[0].size); |
| } else { |
| assert(!"This should have been handled by handle_complex_copy."); |
| return; |
| } |
| |
| blit(pipe, dst, blit_dst_format, dst_level, dstx, dsty, dstz, |
| src, blit_src_format, src_level, src_box); |
| } |
| |
| static bool |
| same_size_and_swizzle(const struct util_format_description *d1, |
| const struct util_format_description *d2) |
| { |
| int i; |
| |
| if (d1->layout != d2->layout || |
| d1->nr_channels != d2->nr_channels || |
| d1->is_array != d2->is_array) |
| return false; |
| |
| for (i = 0; i < d1->nr_channels; i++) { |
| if (d1->channel[i].size != d2->channel[i].size) |
| return false; |
| |
| if (d1->swizzle[i] <= PIPE_SWIZZLE_W && |
| d2->swizzle[i] <= PIPE_SWIZZLE_W && |
| d1->swizzle[i] != d2->swizzle[i]) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static struct pipe_resource * |
| create_texture(struct pipe_screen *screen, enum pipe_format format, |
| unsigned nr_samples, unsigned nr_storage_samples, |
| unsigned width, unsigned height, unsigned depth) |
| { |
| struct pipe_resource templ; |
| |
| memset(&templ, 0, sizeof(templ)); |
| templ.format = format; |
| templ.width0 = width; |
| templ.height0 = height; |
| 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; |
| |
| if (depth > 1) |
| templ.target = PIPE_TEXTURE_2D_ARRAY; |
| else |
| templ.target = PIPE_TEXTURE_2D; |
| |
| return screen->resource_create(screen, &templ); |
| } |
| |
| /** |
| * Handle complex format conversions using 2 blits with a temporary texture |
| * in between, e.g. blitting from B10G10R10A2 to G16R16. |
| * |
| * This example is implemented this way: |
| * 1) First, blit from B10G10R10A2 to R10G10B10A2, which is canonical, so it |
| * can be reinterpreted as a different canonical format of the same bpp, |
| * such as R16G16. This blit only swaps R and B 10-bit components. |
| * 2) Finally, blit the result, which is R10G10B10A2, as R16G16 to G16R16. |
| * This blit only swaps R and G 16-bit components. |
| */ |
| static bool |
| handle_complex_copy(struct pipe_context *pipe, |
| struct pipe_resource *dst, |
| unsigned dst_level, |
| unsigned dstx, unsigned dsty, unsigned dstz, |
| struct pipe_resource *src, |
| unsigned src_level, |
| const struct pipe_box *src_box, |
| enum pipe_format noncanon_format, |
| enum pipe_format canon_format) |
| { |
| struct pipe_box temp_box; |
| struct pipe_resource *temp = NULL; |
| const struct util_format_description *src_desc, *dst_desc; |
| const struct util_format_description *canon_desc, *noncanon_desc; |
| bool src_is_canon; |
| bool src_is_noncanon; |
| bool dst_is_canon; |
| bool dst_is_noncanon; |
| |
| src_desc = util_format_description(src->format); |
| dst_desc = util_format_description(dst->format); |
| canon_desc = util_format_description(canon_format); |
| noncanon_desc = util_format_description(noncanon_format); |
| |
| src_is_canon = same_size_and_swizzle(src_desc, canon_desc); |
| dst_is_canon = same_size_and_swizzle(dst_desc, canon_desc); |
| src_is_noncanon = same_size_and_swizzle(src_desc, noncanon_desc); |
| dst_is_noncanon = same_size_and_swizzle(dst_desc, noncanon_desc); |
| |
| if (src_is_noncanon) { |
| /* Simple case - only types differ (e.g. UNORM and UINT). */ |
| if (dst_is_noncanon) { |
| blit(pipe, dst, noncanon_format, dst_level, dstx, dsty, dstz, src, |
| noncanon_format, src_level, src_box); |
| return true; |
| } |
| |
| /* Simple case - only types and swizzles differ. */ |
| if (dst_is_canon) { |
| blit(pipe, dst, canon_format, dst_level, dstx, dsty, dstz, src, |
| noncanon_format, src_level, src_box); |
| return true; |
| } |
| |
| /* Use the temporary texture. Src is converted to a canonical format, |
| * then proceed the generic swizzled_copy. |
| */ |
| temp = create_texture(pipe->screen, canon_format, src->nr_samples, |
| 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, |
| &temp_box); |
| |
| blit(pipe, temp, canon_format, 0, 0, 0, 0, src, noncanon_format, |
| src_level, src_box); |
| swizzled_copy(pipe, dst, dst_level, dstx, dsty, dstz, temp, 0, |
| &temp_box); |
| pipe_resource_reference(&temp, NULL); |
| return true; |
| } |
| |
| if (dst_is_noncanon) { |
| /* Simple case - only types and swizzles differ. */ |
| if (src_is_canon) { |
| blit(pipe, dst, noncanon_format, dst_level, dstx, dsty, dstz, src, |
| canon_format, src_level, src_box); |
| return true; |
| } |
| |
| /* 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, |
| 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, |
| &temp_box); |
| |
| swizzled_copy(pipe, temp, 0, 0, 0, 0, src, src_level, src_box); |
| blit(pipe, dst, noncanon_format, dst_level, dstx, dsty, dstz, temp, |
| canon_format, 0, &temp_box); |
| pipe_resource_reference(&temp, NULL); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| static void |
| copy_image(struct pipe_context *pipe, |
| struct pipe_resource *dst, |
| unsigned dst_level, |
| unsigned dstx, unsigned dsty, unsigned dstz, |
| struct pipe_resource *src, |
| unsigned src_level, |
| const struct pipe_box *src_box) |
| { |
| if (src->format == dst->format || |
| util_format_is_compressed(src->format) || |
| util_format_is_compressed(dst->format)) { |
| pipe->resource_copy_region(pipe, dst, dst_level, dstx, dsty, dstz, |
| src, src_level, src_box); |
| return; |
| } |
| |
| /* Copying to/from B10G10R10*2 needs 2 blits with R10G10B10A2 |
| * as a temporary texture in between. |
| */ |
| if (handle_complex_copy(pipe, dst, dst_level, dstx, dsty, dstz, src, |
| src_level, src_box, PIPE_FORMAT_B10G10R10A2_UINT, |
| PIPE_FORMAT_R10G10B10A2_UINT)) |
| return; |
| |
| /* Copying to/from G8R8 needs 2 blits with R8G8 as a temporary texture |
| * in between. |
| */ |
| if (handle_complex_copy(pipe, dst, dst_level, dstx, dsty, dstz, src, |
| src_level, src_box, PIPE_FORMAT_G8R8_UNORM, |
| PIPE_FORMAT_R8G8_UNORM)) |
| return; |
| |
| /* Copying to/from G16R16 needs 2 blits with R16G16 as a temporary texture |
| * in between. |
| */ |
| if (handle_complex_copy(pipe, dst, dst_level, dstx, dsty, dstz, src, |
| src_level, src_box, PIPE_FORMAT_G16R16_UNORM, |
| PIPE_FORMAT_R16G16_UNORM)) |
| return; |
| |
| /* Only allow non-identity swizzling on RGBA8 formats. */ |
| |
| /* Simple copy, memcpy with swizzling, no format conversion. */ |
| swizzled_copy(pipe, dst, dst_level, dstx, dsty, dstz, src, src_level, |
| 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, |
| struct gl_renderbuffer *src_renderbuffer, |
| int src_x, int src_y, int src_z, |
| struct gl_texture_image *dst_image, |
| struct gl_renderbuffer *dst_renderbuffer, |
| int dst_x, int dst_y, int dst_z, |
| int src_width, int src_height) |
| { |
| struct st_context *st = st_context(ctx); |
| struct pipe_context *pipe = st->pipe; |
| 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); |
| struct st_texture_object *stObj = st_texture_object(src_image->TexObject); |
| src_res = src->pt; |
| src_level = stObj->pt != src_res ? 0 : 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; |
| src_level = 0; |
| } |
| |
| if (dst_image) { |
| struct st_texture_image *dst = st_texture_image(dst_image); |
| struct st_texture_object *stObj = st_texture_object(dst_image->TexObject); |
| dst_res = dst->pt; |
| dst_level = stObj->pt != dst_res ? 0 : 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; |
| dst_level = 0; |
| } |
| |
| u_box_2d_zslice(src_x, src_y, src_z, src_width, src_height, &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 |
| st_init_copy_image_functions(struct dd_function_table *functions) |
| { |
| functions->CopyImageSubData = st_CopyImageSubData; |
| } |