r300_transfer.c revision ae3063066cb209efd07413f125bb86108906b033
1/* 2 * Copyright 2008 Corbin Simpson <MostAwesomeDude@gmail.com> 3 * Copyright 2010 Marek Olšák <maraeo@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.h" 26#include "r300_screen_buffer.h" 27 28#include "util/u_memory.h" 29#include "util/u_format.h" 30 31struct r300_transfer { 32 /* Parent class */ 33 struct pipe_transfer transfer; 34 35 /* Offset from start of buffer. */ 36 unsigned offset; 37 38 /* Detiled texture. */ 39 struct r300_texture *detiled_texture; 40}; 41 42/* Convenience cast wrapper. */ 43static INLINE struct r300_transfer* 44r300_transfer(struct pipe_transfer* transfer) 45{ 46 return (struct r300_transfer*)transfer; 47} 48 49/* Copy from a tiled texture to a detiled one. */ 50static void r300_copy_from_tiled_texture(struct pipe_context *ctx, 51 struct r300_transfer *r300transfer) 52{ 53 struct pipe_transfer *transfer = (struct pipe_transfer*)r300transfer; 54 struct pipe_resource *tex = transfer->resource; 55 struct pipe_subresource subdst; 56 57 subdst.face = 0; 58 subdst.level = 0; 59 60 /* XXX if we don't flush before copying the texture and mapping it, 61 * we get wrong pixels, i.e. it's like latest draw calls didn't happen, 62 * including this blit. Tests: e.g. piglit/provoking-vertex 63 * 64 * Since the flush immediately before mapping is implicit (the buffer is 65 * always referenced in resource_copy_region), every read transfer costs 66 * 2 flushes. That sucks. */ 67 ctx->flush(ctx, 0, NULL); 68 69 ctx->resource_copy_region(ctx, &r300transfer->detiled_texture->b.b, subdst, 70 0, 0, 0, 71 tex, transfer->sr, 72 transfer->box.x, transfer->box.y, transfer->box.z, 73 transfer->box.width, transfer->box.height); 74 75 /* Flushing after the copy is implicit, issued by winsys. */ 76} 77 78/* Copy a detiled texture to a tiled one. */ 79static void r300_copy_into_tiled_texture(struct pipe_context *ctx, 80 struct r300_transfer *r300transfer) 81{ 82 struct pipe_transfer *transfer = (struct pipe_transfer*)r300transfer; 83 struct pipe_resource *tex = transfer->resource; 84 struct pipe_subresource subsrc; 85 86 subsrc.face = 0; 87 subsrc.level = 0; 88 89 ctx->resource_copy_region(ctx, tex, transfer->sr, 90 transfer->box.x, transfer->box.y, transfer->box.z, 91 &r300transfer->detiled_texture->b.b, subsrc, 92 0, 0, 0, 93 transfer->box.width, transfer->box.height); 94 95 /* XXX this flush fixes a few piglit tests (e.g. glean/pixelFormats). */ 96 ctx->flush(ctx, 0, NULL); 97} 98 99struct pipe_transfer* 100r300_texture_get_transfer(struct pipe_context *ctx, 101 struct pipe_resource *texture, 102 struct pipe_subresource sr, 103 unsigned usage, 104 const struct pipe_box *box) 105{ 106 struct r300_texture *tex = r300_texture(texture); 107 struct r300_screen *r300screen = r300_screen(ctx->screen); 108 struct r300_transfer *trans; 109 struct pipe_resource base; 110 boolean referenced_cs, referenced_hw; 111 112 referenced_cs = r300screen->rws->is_buffer_referenced( 113 r300screen->rws, tex->buffer, R300_REF_CS); 114 if (referenced_cs) { 115 referenced_hw = TRUE; 116 } else { 117 referenced_hw = r300screen->rws->is_buffer_referenced( 118 r300screen->rws, tex->buffer, R300_REF_HW); 119 } 120 121 trans = CALLOC_STRUCT(r300_transfer); 122 if (trans) { 123 /* Initialize the transfer object. */ 124 pipe_resource_reference(&trans->transfer.resource, texture); 125 trans->transfer.sr = sr; 126 trans->transfer.usage = usage; 127 trans->transfer.box = *box; 128 129 /* If the texture is tiled, we must create a temporary detiled texture 130 * for this transfer. 131 * Also make write transfers pipelined. */ 132 if (tex->microtile || tex->macrotile || 133 (referenced_hw & !(usage & PIPE_TRANSFER_READ))) { 134 base.target = PIPE_TEXTURE_2D; 135 base.format = texture->format; 136 base.width0 = box->width; 137 base.height0 = box->height; 138 base.depth0 = 0; 139 base.last_level = 0; 140 base.nr_samples = 0; 141 base.usage = PIPE_USAGE_DYNAMIC; 142 base.bind = 0; 143 base.flags = R300_RESOURCE_FLAG_TRANSFER; 144 145 /* For texture reading, the temporary (detiled) texture is used as 146 * a render target when blitting from a tiled texture. */ 147 if (usage & PIPE_TRANSFER_READ) { 148 base.bind |= PIPE_BIND_RENDER_TARGET; 149 } 150 /* For texture writing, the temporary texture is used as a sampler 151 * when blitting into a tiled texture. */ 152 if (usage & PIPE_TRANSFER_WRITE) { 153 base.bind |= PIPE_BIND_SAMPLER_VIEW; 154 } 155 156 /* Create the temporary texture. */ 157 trans->detiled_texture = r300_texture( 158 ctx->screen->resource_create(ctx->screen, 159 &base)); 160 161 assert(!trans->detiled_texture->microtile && 162 !trans->detiled_texture->macrotile); 163 164 /* Set the stride. 165 * 166 * Even though we are using an internal texture for this, 167 * the transfer sr, box and usage parameters still reflect 168 * the arguments received to get_transfer. We just do the 169 * right thing internally. 170 */ 171 trans->transfer.stride = 172 r300_texture_get_stride(r300screen, trans->detiled_texture, 0); 173 174 if (usage & PIPE_TRANSFER_READ) { 175 /* We cannot map a tiled texture directly because the data is 176 * in a different order, therefore we do detiling using a blit. */ 177 r300_copy_from_tiled_texture(ctx, trans); 178 179 /* Always referenced in the blit. */ 180 ctx->flush(ctx, 0, NULL); 181 } 182 } else { 183 trans->transfer.stride = 184 r300_texture_get_stride(r300screen, tex, sr.level); 185 trans->offset = r300_texture_get_offset(tex, sr.level, box->z, sr.face); 186 187 if (referenced_cs && (usage & PIPE_TRANSFER_READ)) 188 ctx->flush(ctx, PIPE_FLUSH_RENDER_CACHE, NULL); 189 } 190 } 191 return &trans->transfer; 192} 193 194void r300_texture_transfer_destroy(struct pipe_context *ctx, 195 struct pipe_transfer *trans) 196{ 197 struct r300_transfer *r300transfer = r300_transfer(trans); 198 199 if (r300transfer->detiled_texture) { 200 if (trans->usage & PIPE_TRANSFER_WRITE) { 201 r300_copy_into_tiled_texture(ctx, r300transfer); 202 } 203 204 pipe_resource_reference( 205 (struct pipe_resource**)&r300transfer->detiled_texture, NULL); 206 } 207 pipe_resource_reference(&trans->resource, NULL); 208 FREE(trans); 209} 210 211void* r300_texture_transfer_map(struct pipe_context *ctx, 212 struct pipe_transfer *transfer) 213{ 214 struct r300_winsys_screen *rws = (struct r300_winsys_screen *)ctx->winsys; 215 struct r300_transfer *r300transfer = r300_transfer(transfer); 216 struct r300_texture *tex = r300_texture(transfer->resource); 217 char *map; 218 enum pipe_format format = tex->b.b.format; 219 220 if (r300transfer->detiled_texture) { 221 /* The detiled texture is of the same size as the region being mapped 222 * (no offset needed). */ 223 return rws->buffer_map(rws, 224 r300transfer->detiled_texture->buffer, 225 transfer->usage); 226 } else { 227 /* Tiling is disabled. */ 228 map = rws->buffer_map(rws, tex->buffer, 229 transfer->usage); 230 231 if (!map) { 232 return NULL; 233 } 234 235 return map + r300_transfer(transfer)->offset + 236 transfer->box.y / util_format_get_blockheight(format) * transfer->stride + 237 transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); 238 } 239} 240 241void r300_texture_transfer_unmap(struct pipe_context *ctx, 242 struct pipe_transfer *transfer) 243{ 244 struct r300_winsys_screen *rws = (struct r300_winsys_screen *)ctx->winsys; 245 struct r300_transfer *r300transfer = r300_transfer(transfer); 246 struct r300_texture *tex = r300_texture(transfer->resource); 247 248 if (r300transfer->detiled_texture) { 249 rws->buffer_unmap(rws, r300transfer->detiled_texture->buffer); 250 } else { 251 rws->buffer_unmap(rws, tex->buffer); 252 } 253} 254