13464ebd5Sriastradh/* 23464ebd5Sriastradh * Copyright 2008 Corbin Simpson <MostAwesomeDude@gmail.com> 33464ebd5Sriastradh * Copyright 2010 Marek Olšák <maraeo@gmail.com> 43464ebd5Sriastradh * 53464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a 63464ebd5Sriastradh * copy of this software and associated documentation files (the "Software"), 73464ebd5Sriastradh * to deal in the Software without restriction, including without limitation 83464ebd5Sriastradh * on the rights to use, copy, modify, merge, publish, distribute, sub 93464ebd5Sriastradh * license, and/or sell copies of the Software, and to permit persons to whom 103464ebd5Sriastradh * the Software is furnished to do so, subject to the following conditions: 113464ebd5Sriastradh * 123464ebd5Sriastradh * The above copyright notice and this permission notice (including the next 133464ebd5Sriastradh * paragraph) shall be included in all copies or substantial portions of the 143464ebd5Sriastradh * Software. 153464ebd5Sriastradh * 163464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 173464ebd5Sriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 183464ebd5Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 193464ebd5Sriastradh * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 203464ebd5Sriastradh * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 213464ebd5Sriastradh * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 223464ebd5Sriastradh * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 233464ebd5Sriastradh 243464ebd5Sriastradh#include "r300_transfer.h" 253464ebd5Sriastradh#include "r300_texture_desc.h" 263464ebd5Sriastradh#include "r300_screen_buffer.h" 273464ebd5Sriastradh 283464ebd5Sriastradh#include "util/u_memory.h" 297ec681f3Smrg#include "util/format/u_format.h" 303464ebd5Sriastradh#include "util/u_box.h" 313464ebd5Sriastradh 323464ebd5Sriastradhstruct r300_transfer { 333464ebd5Sriastradh /* Parent class */ 343464ebd5Sriastradh struct pipe_transfer transfer; 353464ebd5Sriastradh 363464ebd5Sriastradh /* Linear texture. */ 373464ebd5Sriastradh struct r300_resource *linear_texture; 383464ebd5Sriastradh}; 393464ebd5Sriastradh 403464ebd5Sriastradh/* Convenience cast wrapper. */ 4101e04c3fSmrgstatic inline struct r300_transfer* 423464ebd5Sriastradhr300_transfer(struct pipe_transfer* transfer) 433464ebd5Sriastradh{ 443464ebd5Sriastradh return (struct r300_transfer*)transfer; 453464ebd5Sriastradh} 463464ebd5Sriastradh 473464ebd5Sriastradh/* Copy from a tiled texture to a detiled one. */ 483464ebd5Sriastradhstatic void r300_copy_from_tiled_texture(struct pipe_context *ctx, 493464ebd5Sriastradh struct r300_transfer *r300transfer) 503464ebd5Sriastradh{ 513464ebd5Sriastradh struct pipe_transfer *transfer = (struct pipe_transfer*)r300transfer; 52af69d88dSmrg struct pipe_resource *src = transfer->resource; 537ec681f3Smrg struct pipe_resource *dst = &r300transfer->linear_texture->b; 543464ebd5Sriastradh 55af69d88dSmrg if (src->nr_samples <= 1) { 56af69d88dSmrg ctx->resource_copy_region(ctx, dst, 0, 0, 0, 0, 57af69d88dSmrg src, transfer->level, &transfer->box); 58af69d88dSmrg } else { 59af69d88dSmrg /* Resolve the resource. */ 60af69d88dSmrg struct pipe_blit_info blit; 61af69d88dSmrg 62af69d88dSmrg memset(&blit, 0, sizeof(blit)); 63af69d88dSmrg blit.src.resource = src; 64af69d88dSmrg blit.src.format = src->format; 65af69d88dSmrg blit.src.level = transfer->level; 66af69d88dSmrg blit.src.box = transfer->box; 67af69d88dSmrg blit.dst.resource = dst; 68af69d88dSmrg blit.dst.format = dst->format; 69af69d88dSmrg blit.dst.box.width = transfer->box.width; 70af69d88dSmrg blit.dst.box.height = transfer->box.height; 71af69d88dSmrg blit.dst.box.depth = transfer->box.depth; 72af69d88dSmrg blit.mask = PIPE_MASK_RGBA; 73af69d88dSmrg blit.filter = PIPE_TEX_FILTER_NEAREST; 74af69d88dSmrg 75af69d88dSmrg ctx->blit(ctx, &blit); 76af69d88dSmrg } 773464ebd5Sriastradh} 783464ebd5Sriastradh 793464ebd5Sriastradh/* Copy a detiled texture to a tiled one. */ 803464ebd5Sriastradhstatic void r300_copy_into_tiled_texture(struct pipe_context *ctx, 813464ebd5Sriastradh struct r300_transfer *r300transfer) 823464ebd5Sriastradh{ 833464ebd5Sriastradh struct pipe_transfer *transfer = (struct pipe_transfer*)r300transfer; 843464ebd5Sriastradh struct pipe_resource *tex = transfer->resource; 853464ebd5Sriastradh struct pipe_box src_box; 86af69d88dSmrg 87af69d88dSmrg u_box_3d(0, 0, 0, 88af69d88dSmrg transfer->box.width, transfer->box.height, transfer->box.depth, 89af69d88dSmrg &src_box); 903464ebd5Sriastradh 913464ebd5Sriastradh ctx->resource_copy_region(ctx, tex, transfer->level, 923464ebd5Sriastradh transfer->box.x, transfer->box.y, transfer->box.z, 937ec681f3Smrg &r300transfer->linear_texture->b, 0, &src_box); 943464ebd5Sriastradh 953464ebd5Sriastradh /* XXX remove this. */ 963464ebd5Sriastradh r300_flush(ctx, 0, NULL); 973464ebd5Sriastradh} 983464ebd5Sriastradh 99af69d88dSmrgvoid * 100af69d88dSmrgr300_texture_transfer_map(struct pipe_context *ctx, 1013464ebd5Sriastradh struct pipe_resource *texture, 1023464ebd5Sriastradh unsigned level, 1033464ebd5Sriastradh unsigned usage, 104af69d88dSmrg const struct pipe_box *box, 105af69d88dSmrg struct pipe_transfer **transfer) 1063464ebd5Sriastradh{ 1073464ebd5Sriastradh struct r300_context *r300 = r300_context(ctx); 1083464ebd5Sriastradh struct r300_resource *tex = r300_resource(texture); 1093464ebd5Sriastradh struct r300_transfer *trans; 110af69d88dSmrg boolean referenced_cs, referenced_hw; 1117ec681f3Smrg enum pipe_format format = tex->b.format; 112af69d88dSmrg char *map; 1133464ebd5Sriastradh 1143464ebd5Sriastradh referenced_cs = 1157ec681f3Smrg r300->rws->cs_is_buffer_referenced(&r300->cs, tex->buf, RADEON_USAGE_READWRITE); 1163464ebd5Sriastradh if (referenced_cs) { 1173464ebd5Sriastradh referenced_hw = TRUE; 1183464ebd5Sriastradh } else { 1193464ebd5Sriastradh referenced_hw = 1207ec681f3Smrg !r300->rws->buffer_wait(r300->rws, tex->buf, 0, RADEON_USAGE_READWRITE); 1213464ebd5Sriastradh } 1223464ebd5Sriastradh 1233464ebd5Sriastradh trans = CALLOC_STRUCT(r300_transfer); 1243464ebd5Sriastradh if (trans) { 1253464ebd5Sriastradh /* Initialize the transfer object. */ 126af69d88dSmrg trans->transfer.resource = texture; 1273464ebd5Sriastradh trans->transfer.level = level; 1283464ebd5Sriastradh trans->transfer.usage = usage; 1293464ebd5Sriastradh trans->transfer.box = *box; 1303464ebd5Sriastradh 1313464ebd5Sriastradh /* If the texture is tiled, we must create a temporary detiled texture 1323464ebd5Sriastradh * for this transfer. 1333464ebd5Sriastradh * Also make write transfers pipelined. */ 1343464ebd5Sriastradh if (tex->tex.microtile || tex->tex.macrotile[level] || 1357ec681f3Smrg (referenced_hw && !(usage & PIPE_MAP_READ) && 136af69d88dSmrg r300_is_blit_supported(texture->format))) { 137af69d88dSmrg struct pipe_resource base; 138af69d88dSmrg 1393464ebd5Sriastradh if (r300->blitter->running) { 1403464ebd5Sriastradh fprintf(stderr, "r300: ERROR: Blitter recursion in texture_get_transfer.\n"); 1413464ebd5Sriastradh os_break(); 1423464ebd5Sriastradh } 1433464ebd5Sriastradh 144af69d88dSmrg memset(&base, 0, sizeof(base)); 1453464ebd5Sriastradh base.target = PIPE_TEXTURE_2D; 1463464ebd5Sriastradh base.format = texture->format; 1473464ebd5Sriastradh base.width0 = box->width; 1483464ebd5Sriastradh base.height0 = box->height; 1493464ebd5Sriastradh base.depth0 = 1; 1503464ebd5Sriastradh base.array_size = 1; 151af69d88dSmrg base.usage = PIPE_USAGE_STAGING; 1523464ebd5Sriastradh base.flags = R300_RESOURCE_FLAG_TRANSFER; 1533464ebd5Sriastradh 154af69d88dSmrg /* We must set the correct texture target and dimensions if needed for a 3D transfer. */ 155af69d88dSmrg if (box->depth > 1 && util_max_layer(texture, level) > 0) { 156af69d88dSmrg base.target = texture->target; 157af69d88dSmrg 158af69d88dSmrg if (base.target == PIPE_TEXTURE_3D) { 159af69d88dSmrg base.depth0 = util_next_power_of_two(box->depth); 160af69d88dSmrg } 1613464ebd5Sriastradh } 1623464ebd5Sriastradh 1633464ebd5Sriastradh /* Create the temporary texture. */ 1643464ebd5Sriastradh trans->linear_texture = r300_resource( 1653464ebd5Sriastradh ctx->screen->resource_create(ctx->screen, 1663464ebd5Sriastradh &base)); 1673464ebd5Sriastradh 1683464ebd5Sriastradh if (!trans->linear_texture) { 1693464ebd5Sriastradh /* Oh crap, the thing can't create the texture. 1703464ebd5Sriastradh * Let's flush and try again. */ 1713464ebd5Sriastradh r300_flush(ctx, 0, NULL); 1723464ebd5Sriastradh 1733464ebd5Sriastradh trans->linear_texture = r300_resource( 1743464ebd5Sriastradh ctx->screen->resource_create(ctx->screen, 1753464ebd5Sriastradh &base)); 1763464ebd5Sriastradh 1773464ebd5Sriastradh if (!trans->linear_texture) { 1783464ebd5Sriastradh fprintf(stderr, 179af69d88dSmrg "r300: Failed to create a transfer object.\n"); 1803464ebd5Sriastradh FREE(trans); 1813464ebd5Sriastradh return NULL; 1823464ebd5Sriastradh } 1833464ebd5Sriastradh } 1843464ebd5Sriastradh 1853464ebd5Sriastradh assert(!trans->linear_texture->tex.microtile && 1863464ebd5Sriastradh !trans->linear_texture->tex.macrotile[0]); 1873464ebd5Sriastradh 1883464ebd5Sriastradh /* Set the stride. */ 1893464ebd5Sriastradh trans->transfer.stride = 1903464ebd5Sriastradh trans->linear_texture->tex.stride_in_bytes[0]; 191af69d88dSmrg trans->transfer.layer_stride = 192af69d88dSmrg trans->linear_texture->tex.layer_size_in_bytes[0]; 1933464ebd5Sriastradh 1947ec681f3Smrg if (usage & PIPE_MAP_READ) { 1953464ebd5Sriastradh /* We cannot map a tiled texture directly because the data is 1963464ebd5Sriastradh * in a different order, therefore we do detiling using a blit. */ 1973464ebd5Sriastradh r300_copy_from_tiled_texture(ctx, trans); 1983464ebd5Sriastradh 1993464ebd5Sriastradh /* Always referenced in the blit. */ 2003464ebd5Sriastradh r300_flush(ctx, 0, NULL); 2013464ebd5Sriastradh } 202af69d88dSmrg } else { 203af69d88dSmrg /* Unpipelined transfer. */ 204af69d88dSmrg trans->transfer.stride = tex->tex.stride_in_bytes[level]; 205af69d88dSmrg trans->transfer.layer_stride = tex->tex.layer_size_in_bytes[level]; 2067ec681f3Smrg trans->transfer.offset = r300_texture_get_offset(tex, level, box->z); 207af69d88dSmrg 208af69d88dSmrg if (referenced_cs && 2097ec681f3Smrg !(usage & PIPE_MAP_UNSYNCHRONIZED)) { 210af69d88dSmrg r300_flush(ctx, 0, NULL); 211af69d88dSmrg } 2123464ebd5Sriastradh } 2133464ebd5Sriastradh } 2143464ebd5Sriastradh 215af69d88dSmrg if (trans->linear_texture) { 2163464ebd5Sriastradh /* The detiled texture is of the same size as the region being mapped 2173464ebd5Sriastradh * (no offset needed). */ 2187ec681f3Smrg map = r300->rws->buffer_map(r300->rws, trans->linear_texture->buf, 2197ec681f3Smrg &r300->cs, usage); 220af69d88dSmrg if (!map) { 221af69d88dSmrg pipe_resource_reference( 222af69d88dSmrg (struct pipe_resource**)&trans->linear_texture, NULL); 223af69d88dSmrg FREE(trans); 224af69d88dSmrg return NULL; 225af69d88dSmrg } 226af69d88dSmrg *transfer = &trans->transfer; 227af69d88dSmrg return map; 2283464ebd5Sriastradh } else { 2293464ebd5Sriastradh /* Tiling is disabled. */ 2307ec681f3Smrg map = r300->rws->buffer_map(r300->rws, tex->buf, &r300->cs, usage); 2313464ebd5Sriastradh if (!map) { 232af69d88dSmrg FREE(trans); 2333464ebd5Sriastradh return NULL; 2343464ebd5Sriastradh } 2353464ebd5Sriastradh 236af69d88dSmrg *transfer = &trans->transfer; 2377ec681f3Smrg return map + trans->transfer.offset + 238af69d88dSmrg box->y / util_format_get_blockheight(format) * trans->transfer.stride + 239af69d88dSmrg box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); 2403464ebd5Sriastradh } 2413464ebd5Sriastradh} 2423464ebd5Sriastradh 2433464ebd5Sriastradhvoid r300_texture_transfer_unmap(struct pipe_context *ctx, 2443464ebd5Sriastradh struct pipe_transfer *transfer) 2453464ebd5Sriastradh{ 246af69d88dSmrg struct r300_transfer *trans = r300_transfer(transfer); 2473464ebd5Sriastradh 248af69d88dSmrg if (trans->linear_texture) { 2497ec681f3Smrg if (transfer->usage & PIPE_MAP_WRITE) { 250af69d88dSmrg r300_copy_into_tiled_texture(ctx, trans); 251af69d88dSmrg } 252af69d88dSmrg 253af69d88dSmrg pipe_resource_reference( 254af69d88dSmrg (struct pipe_resource**)&trans->linear_texture, NULL); 2553464ebd5Sriastradh } 256af69d88dSmrg FREE(transfer); 2573464ebd5Sriastradh} 258