+ /* If the texture is tiled, we must create a temporary detiled texture
+ * for this transfer.
+ * Also make write transfers pipelined. */
+ if (tex->microtile || tex->macrotile ||
+ ((referenced_hw & !(usage & PIPE_TRANSFER_READ)) && blittable)) {
+ base.target = PIPE_TEXTURE_2D;
+ base.format = texture->format;
+ base.width0 = box->width;
+ base.height0 = box->height;
+ base.depth0 = 0;
+ base.last_level = 0;
+ base.nr_samples = 0;
+ base.usage = PIPE_USAGE_DYNAMIC;
+ base.bind = 0;
+ base.flags = R300_RESOURCE_FLAG_TRANSFER;
+
+ /* For texture reading, the temporary (detiled) texture is used as
+ * a render target when blitting from a tiled texture. */
+ if (usage & PIPE_TRANSFER_READ) {
+ base.bind |= PIPE_BIND_RENDER_TARGET;
+ }
+ /* For texture writing, the temporary texture is used as a sampler
+ * when blitting into a tiled texture. */
+ if (usage & PIPE_TRANSFER_WRITE) {
+ base.bind |= PIPE_BIND_SAMPLER_VIEW;
+ }
+
+ /* Create the temporary texture. */
+ trans->detiled_texture = r300_texture(
+ ctx->screen->resource_create(ctx->screen,
+ &base));
+
+ if (!trans->detiled_texture) {
+ /* Oh crap, the thing can't create the texture.
+ * Let's flush and try again. */
+ ctx->flush(ctx, 0, NULL);
+
+ trans->detiled_texture = r300_texture(
+ ctx->screen->resource_create(ctx->screen,
+ &base));
+
+ if (!trans->detiled_texture) {
+ /* For linear textures, it's safe to fallback to
+ * an unpipelined transfer. */
+ if (!tex->microtile && !tex->macrotile) {
+ goto unpipelined;
+ }
+
+ /* Otherwise, go to hell. */
+ fprintf(stderr,
+ "r300: Failed to create a transfer object, praise.\n");
+ FREE(trans);
+ return NULL;
+ }
+ }
+
+ assert(!trans->detiled_texture->microtile &&
+ !trans->detiled_texture->macrotile);
+
+ /* Set the stride.
+ *
+ * Even though we are using an internal texture for this,
+ * the transfer sr, box and usage parameters still reflect
+ * the arguments received to get_transfer. We just do the
+ * right thing internally.
+ */
+ trans->transfer.stride =
+ r300_texture_get_stride(r300screen, trans->detiled_texture, 0);
+
+ if (usage & PIPE_TRANSFER_READ) {
+ /* We cannot map a tiled texture directly because the data is
+ * in a different order, therefore we do detiling using a blit. */
+ r300_copy_from_tiled_texture(ctx, trans);
+
+ /* Always referenced in the blit. */
+ ctx->flush(ctx, 0, NULL);
+ }
+ return &trans->transfer;
+ }
+
+ unpipelined:
+ /* Unpipelined transfer. */
+ trans->transfer.stride =
+ r300_texture_get_stride(r300screen, tex, sr.level);
+ trans->offset = r300_texture_get_offset(tex, sr.level, box->z, sr.face);
+
+ if (referenced_cs && (usage & PIPE_TRANSFER_READ))
+ ctx->flush(ctx, PIPE_FLUSH_RENDER_CACHE, NULL);
+ return &trans->transfer;