1 /* 2 * Copyright 2008 Corbin Simpson <MostAwesomeDude (at) gmail.com> 3 * Copyright 2010 Marek Olk <maraeo (at) gmail.com> 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * on the rights to use, copy, modify, merge, publish, distribute, sub 9 * license, and/or sell copies of the Software, and to permit persons to whom 10 * the Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 22 * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 23 24 #include "r300_transfer.h" 25 #include "r300_texture_desc.h" 26 #include "r300_screen_buffer.h" 27 28 #include "util/u_memory.h" 29 #include "util/u_format.h" 30 #include "util/u_box.h" 31 32 struct r300_transfer { 33 /* Parent class */ 34 struct pipe_transfer transfer; 35 36 /* Offset from start of buffer. */ 37 unsigned offset; 38 39 /* Linear texture. */ 40 struct r300_resource *linear_texture; 41 }; 42 43 /* Convenience cast wrapper. */ 44 static inline struct r300_transfer* 45 r300_transfer(struct pipe_transfer* transfer) 46 { 47 return (struct r300_transfer*)transfer; 48 } 49 50 /* Copy from a tiled texture to a detiled one. */ 51 static void r300_copy_from_tiled_texture(struct pipe_context *ctx, 52 struct r300_transfer *r300transfer) 53 { 54 struct pipe_transfer *transfer = (struct pipe_transfer*)r300transfer; 55 struct pipe_resource *src = transfer->resource; 56 struct pipe_resource *dst = &r300transfer->linear_texture->b.b; 57 58 if (src->nr_samples <= 1) { 59 ctx->resource_copy_region(ctx, dst, 0, 0, 0, 0, 60 src, transfer->level, &transfer->box); 61 } else { 62 /* Resolve the resource. */ 63 struct pipe_blit_info blit; 64 65 memset(&blit, 0, sizeof(blit)); 66 blit.src.resource = src; 67 blit.src.format = src->format; 68 blit.src.level = transfer->level; 69 blit.src.box = transfer->box; 70 blit.dst.resource = dst; 71 blit.dst.format = dst->format; 72 blit.dst.box.width = transfer->box.width; 73 blit.dst.box.height = transfer->box.height; 74 blit.dst.box.depth = transfer->box.depth; 75 blit.mask = PIPE_MASK_RGBA; 76 blit.filter = PIPE_TEX_FILTER_NEAREST; 77 78 ctx->blit(ctx, &blit); 79 } 80 } 81 82 /* Copy a detiled texture to a tiled one. */ 83 static void r300_copy_into_tiled_texture(struct pipe_context *ctx, 84 struct r300_transfer *r300transfer) 85 { 86 struct pipe_transfer *transfer = (struct pipe_transfer*)r300transfer; 87 struct pipe_resource *tex = transfer->resource; 88 struct pipe_box src_box; 89 90 u_box_3d(0, 0, 0, 91 transfer->box.width, transfer->box.height, transfer->box.depth, 92 &src_box); 93 94 ctx->resource_copy_region(ctx, tex, transfer->level, 95 transfer->box.x, transfer->box.y, transfer->box.z, 96 &r300transfer->linear_texture->b.b, 0, &src_box); 97 98 /* XXX remove this. */ 99 r300_flush(ctx, 0, NULL); 100 } 101 102 void * 103 r300_texture_transfer_map(struct pipe_context *ctx, 104 struct pipe_resource *texture, 105 unsigned level, 106 unsigned usage, 107 const struct pipe_box *box, 108 struct pipe_transfer **transfer) 109 { 110 struct r300_context *r300 = r300_context(ctx); 111 struct r300_resource *tex = r300_resource(texture); 112 struct r300_transfer *trans; 113 boolean referenced_cs, referenced_hw; 114 enum pipe_format format = tex->b.b.format; 115 char *map; 116 117 referenced_cs = 118 r300->rws->cs_is_buffer_referenced(r300->cs, tex->buf, RADEON_USAGE_READWRITE); 119 if (referenced_cs) { 120 referenced_hw = TRUE; 121 } else { 122 referenced_hw = 123 !r300->rws->buffer_wait(tex->buf, 0, RADEON_USAGE_READWRITE); 124 } 125 126 trans = CALLOC_STRUCT(r300_transfer); 127 if (trans) { 128 /* Initialize the transfer object. */ 129 trans->transfer.resource = texture; 130 trans->transfer.level = level; 131 trans->transfer.usage = usage; 132 trans->transfer.box = *box; 133 134 /* If the texture is tiled, we must create a temporary detiled texture 135 * for this transfer. 136 * Also make write transfers pipelined. */ 137 if (tex->tex.microtile || tex->tex.macrotile[level] || 138 (referenced_hw && !(usage & PIPE_TRANSFER_READ) && 139 r300_is_blit_supported(texture->format))) { 140 struct pipe_resource base; 141 142 if (r300->blitter->running) { 143 fprintf(stderr, "r300: ERROR: Blitter recursion in texture_get_transfer.\n"); 144 os_break(); 145 } 146 147 memset(&base, 0, sizeof(base)); 148 base.target = PIPE_TEXTURE_2D; 149 base.format = texture->format; 150 base.width0 = box->width; 151 base.height0 = box->height; 152 base.depth0 = 1; 153 base.array_size = 1; 154 base.usage = PIPE_USAGE_STAGING; 155 base.flags = R300_RESOURCE_FLAG_TRANSFER; 156 157 /* We must set the correct texture target and dimensions if needed for a 3D transfer. */ 158 if (box->depth > 1 && util_max_layer(texture, level) > 0) { 159 base.target = texture->target; 160 161 if (base.target == PIPE_TEXTURE_3D) { 162 base.depth0 = util_next_power_of_two(box->depth); 163 } 164 } 165 166 /* Create the temporary texture. */ 167 trans->linear_texture = r300_resource( 168 ctx->screen->resource_create(ctx->screen, 169 &base)); 170 171 if (!trans->linear_texture) { 172 /* Oh crap, the thing can't create the texture. 173 * Let's flush and try again. */ 174 r300_flush(ctx, 0, NULL); 175 176 trans->linear_texture = r300_resource( 177 ctx->screen->resource_create(ctx->screen, 178 &base)); 179 180 if (!trans->linear_texture) { 181 fprintf(stderr, 182 "r300: Failed to create a transfer object.\n"); 183 FREE(trans); 184 return NULL; 185 } 186 } 187 188 assert(!trans->linear_texture->tex.microtile && 189 !trans->linear_texture->tex.macrotile[0]); 190 191 /* Set the stride. */ 192 trans->transfer.stride = 193 trans->linear_texture->tex.stride_in_bytes[0]; 194 trans->transfer.layer_stride = 195 trans->linear_texture->tex.layer_size_in_bytes[0]; 196 197 if (usage & PIPE_TRANSFER_READ) { 198 /* We cannot map a tiled texture directly because the data is 199 * in a different order, therefore we do detiling using a blit. */ 200 r300_copy_from_tiled_texture(ctx, trans); 201 202 /* Always referenced in the blit. */ 203 r300_flush(ctx, 0, NULL); 204 } 205 } else { 206 /* Unpipelined transfer. */ 207 trans->transfer.stride = tex->tex.stride_in_bytes[level]; 208 trans->transfer.layer_stride = tex->tex.layer_size_in_bytes[level]; 209 trans->offset = r300_texture_get_offset(tex, level, box->z); 210 211 if (referenced_cs && 212 !(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { 213 r300_flush(ctx, 0, NULL); 214 } 215 } 216 } 217 218 if (trans->linear_texture) { 219 /* The detiled texture is of the same size as the region being mapped 220 * (no offset needed). */ 221 map = r300->rws->buffer_map(trans->linear_texture->buf, 222 r300->cs, usage); 223 if (!map) { 224 pipe_resource_reference( 225 (struct pipe_resource**)&trans->linear_texture, NULL); 226 FREE(trans); 227 return NULL; 228 } 229 *transfer = &trans->transfer; 230 return map; 231 } else { 232 /* Tiling is disabled. */ 233 map = r300->rws->buffer_map(tex->buf, r300->cs, usage); 234 if (!map) { 235 FREE(trans); 236 return NULL; 237 } 238 239 *transfer = &trans->transfer; 240 return map + trans->offset + 241 box->y / util_format_get_blockheight(format) * trans->transfer.stride + 242 box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); 243 } 244 } 245 246 void r300_texture_transfer_unmap(struct pipe_context *ctx, 247 struct pipe_transfer *transfer) 248 { 249 struct r300_transfer *trans = r300_transfer(transfer); 250 251 if (trans->linear_texture) { 252 if (transfer->usage & PIPE_TRANSFER_WRITE) { 253 r300_copy_into_tiled_texture(ctx, trans); 254 } 255 256 pipe_resource_reference( 257 (struct pipe_resource**)&trans->linear_texture, NULL); 258 } 259 FREE(transfer); 260 } 261