Path: blob/21.2-virgl/src/gallium/drivers/r300/r300_transfer.c
4570 views
/*1* Copyright 2008 Corbin Simpson <[email protected]>2* Copyright 2010 Marek Olšák <[email protected]>3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the "Software"),6* to deal in the Software without restriction, including without limitation7* on the rights to use, copy, modify, merge, publish, distribute, sub8* license, and/or sell copies of the Software, and to permit persons to whom9* the Software is furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice (including the next12* paragraph) shall be included in all copies or substantial portions of the13* Software.14*15* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL18* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,19* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR20* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE21* USE OR OTHER DEALINGS IN THE SOFTWARE. */2223#include "r300_transfer.h"24#include "r300_texture_desc.h"25#include "r300_screen_buffer.h"2627#include "util/u_memory.h"28#include "util/format/u_format.h"29#include "util/u_box.h"3031struct r300_transfer {32/* Parent class */33struct pipe_transfer transfer;3435/* Linear texture. */36struct r300_resource *linear_texture;37};3839/* Convenience cast wrapper. */40static inline struct r300_transfer*41r300_transfer(struct pipe_transfer* transfer)42{43return (struct r300_transfer*)transfer;44}4546/* Copy from a tiled texture to a detiled one. */47static void r300_copy_from_tiled_texture(struct pipe_context *ctx,48struct r300_transfer *r300transfer)49{50struct pipe_transfer *transfer = (struct pipe_transfer*)r300transfer;51struct pipe_resource *src = transfer->resource;52struct pipe_resource *dst = &r300transfer->linear_texture->b;5354if (src->nr_samples <= 1) {55ctx->resource_copy_region(ctx, dst, 0, 0, 0, 0,56src, transfer->level, &transfer->box);57} else {58/* Resolve the resource. */59struct pipe_blit_info blit;6061memset(&blit, 0, sizeof(blit));62blit.src.resource = src;63blit.src.format = src->format;64blit.src.level = transfer->level;65blit.src.box = transfer->box;66blit.dst.resource = dst;67blit.dst.format = dst->format;68blit.dst.box.width = transfer->box.width;69blit.dst.box.height = transfer->box.height;70blit.dst.box.depth = transfer->box.depth;71blit.mask = PIPE_MASK_RGBA;72blit.filter = PIPE_TEX_FILTER_NEAREST;7374ctx->blit(ctx, &blit);75}76}7778/* Copy a detiled texture to a tiled one. */79static void r300_copy_into_tiled_texture(struct pipe_context *ctx,80struct r300_transfer *r300transfer)81{82struct pipe_transfer *transfer = (struct pipe_transfer*)r300transfer;83struct pipe_resource *tex = transfer->resource;84struct pipe_box src_box;8586u_box_3d(0, 0, 0,87transfer->box.width, transfer->box.height, transfer->box.depth,88&src_box);8990ctx->resource_copy_region(ctx, tex, transfer->level,91transfer->box.x, transfer->box.y, transfer->box.z,92&r300transfer->linear_texture->b, 0, &src_box);9394/* XXX remove this. */95r300_flush(ctx, 0, NULL);96}9798void *99r300_texture_transfer_map(struct pipe_context *ctx,100struct pipe_resource *texture,101unsigned level,102unsigned usage,103const struct pipe_box *box,104struct pipe_transfer **transfer)105{106struct r300_context *r300 = r300_context(ctx);107struct r300_resource *tex = r300_resource(texture);108struct r300_transfer *trans;109boolean referenced_cs, referenced_hw;110enum pipe_format format = tex->b.format;111char *map;112113referenced_cs =114r300->rws->cs_is_buffer_referenced(&r300->cs, tex->buf, RADEON_USAGE_READWRITE);115if (referenced_cs) {116referenced_hw = TRUE;117} else {118referenced_hw =119!r300->rws->buffer_wait(r300->rws, tex->buf, 0, RADEON_USAGE_READWRITE);120}121122trans = CALLOC_STRUCT(r300_transfer);123if (trans) {124/* Initialize the transfer object. */125trans->transfer.resource = texture;126trans->transfer.level = level;127trans->transfer.usage = usage;128trans->transfer.box = *box;129130/* If the texture is tiled, we must create a temporary detiled texture131* for this transfer.132* Also make write transfers pipelined. */133if (tex->tex.microtile || tex->tex.macrotile[level] ||134(referenced_hw && !(usage & PIPE_MAP_READ) &&135r300_is_blit_supported(texture->format))) {136struct pipe_resource base;137138if (r300->blitter->running) {139fprintf(stderr, "r300: ERROR: Blitter recursion in texture_get_transfer.\n");140os_break();141}142143memset(&base, 0, sizeof(base));144base.target = PIPE_TEXTURE_2D;145base.format = texture->format;146base.width0 = box->width;147base.height0 = box->height;148base.depth0 = 1;149base.array_size = 1;150base.usage = PIPE_USAGE_STAGING;151base.flags = R300_RESOURCE_FLAG_TRANSFER;152153/* We must set the correct texture target and dimensions if needed for a 3D transfer. */154if (box->depth > 1 && util_max_layer(texture, level) > 0) {155base.target = texture->target;156157if (base.target == PIPE_TEXTURE_3D) {158base.depth0 = util_next_power_of_two(box->depth);159}160}161162/* Create the temporary texture. */163trans->linear_texture = r300_resource(164ctx->screen->resource_create(ctx->screen,165&base));166167if (!trans->linear_texture) {168/* Oh crap, the thing can't create the texture.169* Let's flush and try again. */170r300_flush(ctx, 0, NULL);171172trans->linear_texture = r300_resource(173ctx->screen->resource_create(ctx->screen,174&base));175176if (!trans->linear_texture) {177fprintf(stderr,178"r300: Failed to create a transfer object.\n");179FREE(trans);180return NULL;181}182}183184assert(!trans->linear_texture->tex.microtile &&185!trans->linear_texture->tex.macrotile[0]);186187/* Set the stride. */188trans->transfer.stride =189trans->linear_texture->tex.stride_in_bytes[0];190trans->transfer.layer_stride =191trans->linear_texture->tex.layer_size_in_bytes[0];192193if (usage & PIPE_MAP_READ) {194/* We cannot map a tiled texture directly because the data is195* in a different order, therefore we do detiling using a blit. */196r300_copy_from_tiled_texture(ctx, trans);197198/* Always referenced in the blit. */199r300_flush(ctx, 0, NULL);200}201} else {202/* Unpipelined transfer. */203trans->transfer.stride = tex->tex.stride_in_bytes[level];204trans->transfer.layer_stride = tex->tex.layer_size_in_bytes[level];205trans->transfer.offset = r300_texture_get_offset(tex, level, box->z);206207if (referenced_cs &&208!(usage & PIPE_MAP_UNSYNCHRONIZED)) {209r300_flush(ctx, 0, NULL);210}211}212}213214if (trans->linear_texture) {215/* The detiled texture is of the same size as the region being mapped216* (no offset needed). */217map = r300->rws->buffer_map(r300->rws, trans->linear_texture->buf,218&r300->cs, usage);219if (!map) {220pipe_resource_reference(221(struct pipe_resource**)&trans->linear_texture, NULL);222FREE(trans);223return NULL;224}225*transfer = &trans->transfer;226return map;227} else {228/* Tiling is disabled. */229map = r300->rws->buffer_map(r300->rws, tex->buf, &r300->cs, usage);230if (!map) {231FREE(trans);232return NULL;233}234235*transfer = &trans->transfer;236return map + trans->transfer.offset +237box->y / util_format_get_blockheight(format) * trans->transfer.stride +238box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);239}240}241242void r300_texture_transfer_unmap(struct pipe_context *ctx,243struct pipe_transfer *transfer)244{245struct r300_transfer *trans = r300_transfer(transfer);246247if (trans->linear_texture) {248if (transfer->usage & PIPE_MAP_WRITE) {249r300_copy_into_tiled_texture(ctx, trans);250}251252pipe_resource_reference(253(struct pipe_resource**)&trans->linear_texture, NULL);254}255FREE(transfer);256}257258259