X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fr600%2Fr600_texture.c;h=6692aa6bb547958d2b2a9c11ec2eb9edfc510096;hb=f01431d0358ae337227a348e96b30adfd8d55f7c;hp=1f4f453c091b81fd7b547bd57d9765b18d8d5731;hpb=86e5b79a274ad4ed5c169aa5626106331273311c;p=mesa.git diff --git a/src/gallium/drivers/r600/r600_texture.c b/src/gallium/drivers/r600/r600_texture.c index 1f4f453c091..6692aa6bb54 100644 --- a/src/gallium/drivers/r600/r600_texture.c +++ b/src/gallium/drivers/r600/r600_texture.c @@ -25,21 +25,18 @@ * Corbin Simpson */ #include -#include -#include -#include -#include -#include -#include "state_tracker/drm_driver.h" +#include "pipe/p_screen.h" +#include "util/u_format.h" +#include "util/u_format_s3tc.h" +#include "util/u_math.h" +#include "util/u_inlines.h" +#include "util/u_memory.h" #include "pipebuffer/pb_buffer.h" #include "r600_pipe.h" #include "r600_resource.h" -#include "r600_state_inlines.h" #include "r600d.h" #include "r600_formats.h" -extern struct u_resource_vtbl r600_texture_vtbl; - /* Copy from a full GPU texture to a transfer's staging one. */ static void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer) { @@ -68,8 +65,6 @@ static void r600_copy_from_staging_texture(struct pipe_context *ctx, struct r600 transfer->box.x, transfer->box.y, transfer->box.z, rtransfer->staging_texture, 0, &sbox); - - ctx->flush(ctx, 0, NULL); } unsigned r600_texture_get_offset(struct r600_resource_texture *rtex, @@ -77,17 +72,15 @@ unsigned r600_texture_get_offset(struct r600_resource_texture *rtex, { unsigned offset = rtex->offset[level]; - switch (rtex->resource.base.b.target) { + switch (rtex->resource.b.b.b.target) { case PIPE_TEXTURE_3D: case PIPE_TEXTURE_CUBE: - return offset + layer * rtex->layer_size[level]; default: - assert(layer == 0); - return offset; + return offset + layer * rtex->layer_size[level]; } } -static unsigned r600_get_pixel_alignment(struct pipe_screen *screen, +static unsigned r600_get_block_alignment(struct pipe_screen *screen, enum pipe_format format, unsigned array_mode) { @@ -98,16 +91,19 @@ static unsigned r600_get_pixel_alignment(struct pipe_screen *screen, switch(array_mode) { case V_038000_ARRAY_1D_TILED_THIN1: p_align = MAX2(8, - ((rscreen->tiling_info->group_bytes / 8 / pixsize))); + ((rscreen->tiling_info.group_bytes / 8 / pixsize))); break; case V_038000_ARRAY_2D_TILED_THIN1: - p_align = MAX2(rscreen->tiling_info->num_banks, - (((rscreen->tiling_info->group_bytes / 8 / pixsize)) * - rscreen->tiling_info->num_banks)) * 8; + p_align = MAX2(rscreen->tiling_info.num_banks, + (((rscreen->tiling_info.group_bytes / 8 / pixsize)) * + rscreen->tiling_info.num_banks)) * 8; + break; + case V_038000_ARRAY_LINEAR_ALIGNED: + p_align = MAX2(64, rscreen->tiling_info.group_bytes / pixsize); break; case V_038000_ARRAY_LINEAR_GENERAL: default: - p_align = rscreen->tiling_info->group_bytes / pixsize; + p_align = rscreen->tiling_info.group_bytes / pixsize; break; } return p_align; @@ -121,11 +117,13 @@ static unsigned r600_get_height_alignment(struct pipe_screen *screen, switch (array_mode) { case V_038000_ARRAY_2D_TILED_THIN1: - h_align = rscreen->tiling_info->num_channels * 8; + h_align = rscreen->tiling_info.num_channels * 8; break; case V_038000_ARRAY_1D_TILED_THIN1: + case V_038000_ARRAY_LINEAR_ALIGNED: h_align = 8; break; + case V_038000_ARRAY_LINEAR_GENERAL: default: h_align = 1; break; @@ -139,18 +137,20 @@ static unsigned r600_get_base_alignment(struct pipe_screen *screen, { struct r600_screen* rscreen = (struct r600_screen *)screen; unsigned pixsize = util_format_get_blocksize(format); - int p_align = r600_get_pixel_alignment(screen, format, array_mode); + int p_align = r600_get_block_alignment(screen, format, array_mode); int h_align = r600_get_height_alignment(screen, array_mode); int b_align; switch (array_mode) { case V_038000_ARRAY_2D_TILED_THIN1: - b_align = MAX2(rscreen->tiling_info->num_banks * rscreen->tiling_info->num_channels * 8 * 8 * pixsize, + b_align = MAX2(rscreen->tiling_info.num_banks * rscreen->tiling_info.num_channels * 8 * 8 * pixsize, p_align * pixsize * h_align); break; case V_038000_ARRAY_1D_TILED_THIN1: + case V_038000_ARRAY_LINEAR_ALIGNED: + case V_038000_ARRAY_LINEAR_GENERAL: default: - b_align = rscreen->tiling_info->group_bytes; + b_align = rscreen->tiling_info.group_bytes; break; } return b_align; @@ -165,55 +165,56 @@ static unsigned mip_minify(unsigned size, unsigned level) return val; } -static unsigned r600_texture_get_stride(struct pipe_screen *screen, - struct r600_resource_texture *rtex, - unsigned level) +static unsigned r600_texture_get_nblocksx(struct pipe_screen *screen, + struct r600_resource_texture *rtex, + unsigned level) { - struct pipe_resource *ptex = &rtex->resource.base.b; - unsigned width, stride, tile_width; + struct pipe_resource *ptex = &rtex->resource.b.b.b; + unsigned nblocksx, block_align, width; + unsigned blocksize = util_format_get_blocksize(rtex->real_format); if (rtex->pitch_override) - return rtex->pitch_override; + return rtex->pitch_override / blocksize; width = mip_minify(ptex->width0, level); - if (util_format_is_plain(ptex->format)) { - tile_width = r600_get_pixel_alignment(screen, ptex->format, - rtex->array_mode[level]); - width = align(width, tile_width); - } - stride = util_format_get_stride(ptex->format, width); + nblocksx = util_format_get_nblocksx(rtex->real_format, width); - return stride; + block_align = r600_get_block_alignment(screen, rtex->real_format, + rtex->array_mode[level]); + nblocksx = align(nblocksx, block_align); + return nblocksx; } static unsigned r600_texture_get_nblocksy(struct pipe_screen *screen, struct r600_resource_texture *rtex, unsigned level) { - struct pipe_resource *ptex = &rtex->resource.base.b; + struct pipe_resource *ptex = &rtex->resource.b.b.b; unsigned height, tile_height; height = mip_minify(ptex->height0, level); - if (util_format_is_plain(ptex->format)) { - tile_height = r600_get_height_alignment(screen, - rtex->array_mode[level]); - height = align(height, tile_height); - } - return util_format_get_nblocksy(ptex->format, height); -} + height = util_format_get_nblocksy(rtex->real_format, height); + tile_height = r600_get_height_alignment(screen, + rtex->array_mode[level]); -/* Get a width in pixels from a stride in bytes. */ -static unsigned pitch_to_width(enum pipe_format format, unsigned pitch_in_bytes) -{ - return (pitch_in_bytes / util_format_get_blocksize(format)) * - util_format_get_blockwidth(format); + /* XXX Hack around an alignment issue. Less tests fail with this. + * + * The thing is depth-stencil buffers should be tiled, i.e. + * the alignment should be >=8. If I make them tiled, stencil starts + * working because it no longer overlaps with the depth buffer + * in memory, but texturing like drawpix-stencil breaks. */ + if (util_format_is_depth_or_stencil(rtex->real_format) && tile_height < 8) + tile_height = 8; + + height = align(height, tile_height); + return height; } static void r600_texture_set_array_mode(struct pipe_screen *screen, struct r600_resource_texture *rtex, unsigned level, unsigned array_mode) { - struct pipe_resource *ptex = &rtex->resource.base.b; + struct pipe_resource *ptex = &rtex->resource.b.b.b; switch (array_mode) { case V_0280A0_ARRAY_LINEAR_GENERAL: @@ -227,11 +228,11 @@ static void r600_texture_set_array_mode(struct pipe_screen *screen, unsigned w, h, tile_height, tile_width; tile_height = r600_get_height_alignment(screen, array_mode); - tile_width = r600_get_pixel_alignment(screen, ptex->format, array_mode); + tile_width = r600_get_block_alignment(screen, rtex->real_format, array_mode); w = mip_minify(ptex->width0, level); h = mip_minify(ptex->height0, level); - if (w < tile_width || h < tile_height) + if (w <= tile_width || h <= tile_height) rtex->array_mode[level] = V_0280A0_ARRAY_1D_TILED_THIN1; else rtex->array_mode[level] = array_mode; @@ -244,19 +245,24 @@ static void r600_setup_miptree(struct pipe_screen *screen, struct r600_resource_texture *rtex, unsigned array_mode) { - struct pipe_resource *ptex = &rtex->resource.base.b; - struct radeon *radeon = (struct radeon *)screen->winsys; - enum chip_class chipc = r600_get_family_class(radeon); - unsigned pitch, size, layer_size, i, offset; - unsigned nblocksy; + struct pipe_resource *ptex = &rtex->resource.b.b.b; + enum chip_class chipc = ((struct r600_screen*)screen)->chip_class; + unsigned size, layer_size, i, offset; + unsigned nblocksx, nblocksy; for (i = 0, offset = 0; i <= ptex->last_level; i++) { + unsigned blocksize = util_format_get_blocksize(rtex->real_format); + unsigned base_align = r600_get_base_alignment(screen, rtex->real_format, array_mode); + r600_texture_set_array_mode(screen, rtex, i, array_mode); - pitch = r600_texture_get_stride(screen, rtex, i); + nblocksx = r600_texture_get_nblocksx(screen, rtex, i); nblocksy = r600_texture_get_nblocksy(screen, rtex, i); - layer_size = pitch * nblocksy; + if (chipc >= EVERGREEN && array_mode == V_038000_ARRAY_LINEAR_GENERAL) + layer_size = align(nblocksx, 64) * nblocksy * blocksize; + else + layer_size = nblocksx * nblocksy * blocksize; if (ptex->target == PIPE_TEXTURE_CUBE) { if (chipc >= R700) @@ -264,63 +270,24 @@ static void r600_setup_miptree(struct pipe_screen *screen, else size = layer_size * 6; } - else + else if (ptex->target == PIPE_TEXTURE_3D) size = layer_size * u_minify(ptex->depth0, i); + else + size = layer_size * ptex->array_size; + /* align base image and start of miptree */ if ((i == 0) || (i == 1)) - offset = align(offset, r600_get_base_alignment(screen, ptex->format, array_mode)); + offset = align(offset, base_align); rtex->offset[i] = offset; rtex->layer_size[i] = layer_size; - rtex->pitch_in_bytes[i] = pitch; - rtex->pitch_in_pixels[i] = pitch_to_width(ptex->format, pitch); + rtex->pitch_in_blocks[i] = nblocksx; /* CB talks in elements */ + rtex->pitch_in_bytes[i] = nblocksx * blocksize; + offset += size; } rtex->size = offset; } -static struct r600_resource_texture * -r600_texture_create_object(struct pipe_screen *screen, - const struct pipe_resource *base, - unsigned array_mode, - unsigned pitch_in_bytes_override, - unsigned max_buffer_size, - struct r600_bo *bo) -{ - struct r600_resource_texture *rtex; - struct r600_resource *resource; - struct radeon *radeon = (struct radeon *)screen->winsys; - - rtex = CALLOC_STRUCT(r600_resource_texture); - if (rtex == NULL) - return NULL; - - resource = &rtex->resource; - resource->base.b = *base; - resource->base.vtbl = &r600_texture_vtbl; - pipe_reference_init(&resource->base.b.reference, 1); - resource->base.b.screen = screen; - resource->bo = bo; - rtex->pitch_override = pitch_in_bytes_override; - - if (array_mode) - rtex->tiled = 1; - r600_setup_miptree(screen, rtex, array_mode); - - resource->size = rtex->size; - - if (!resource->bo) { - struct pipe_resource *ptex = &rtex->resource.base.b; - int base_align = r600_get_base_alignment(screen, ptex->format, array_mode); - - resource->bo = r600_bo(radeon, rtex->size, base_align, base->bind, base->usage); - if (!resource->bo) { - FREE(rtex); - return NULL; - } - } - return rtex; -} - /* Figure out whether u_blitter will fallback to a transfer operation. * If so, don't use a staging resource. */ @@ -334,56 +301,44 @@ static boolean permit_hardware_blit(struct pipe_screen *screen, else bind = PIPE_BIND_RENDER_TARGET; - /* See r600_resource_copy_region: there is something wrong - * with depth resource copies at the moment so avoid them for - * now. - */ - if (util_format_get_component_bits(res->format, - UTIL_FORMAT_COLORSPACE_ZS, - 0) != 0) - return FALSE; - + /* hackaround for S3TC */ + if (util_format_is_compressed(res->format)) + return TRUE; + if (!screen->is_format_supported(screen, res->format, res->target, res->nr_samples, - bind, 0)) + bind)) return FALSE; if (!screen->is_format_supported(screen, res->format, res->target, res->nr_samples, - PIPE_BIND_SAMPLER_VIEW, 0)) + PIPE_BIND_SAMPLER_VIEW)) return FALSE; - if (res->usage == PIPE_USAGE_STREAM) + switch (res->usage) { + case PIPE_USAGE_STREAM: + case PIPE_USAGE_STAGING: return FALSE; - return TRUE; + default: + return TRUE; + } } -struct pipe_resource *r600_texture_create(struct pipe_screen *screen, - const struct pipe_resource *templ) +static boolean r600_texture_get_handle(struct pipe_screen* screen, + struct pipe_resource *ptex, + struct winsys_handle *whandle) { - unsigned array_mode = 0; - static int force_tiling = -1; - - /* Would like some magic "get_bool_option_once" routine. - */ - if (force_tiling == -1) - force_tiling = debug_get_bool_option("R600_FORCE_TILING", FALSE); - - if (force_tiling && permit_hardware_blit(screen, templ)) { - if (!(templ->flags & R600_RESOURCE_FLAG_TRANSFER) && - !(templ->bind & PIPE_BIND_SCANOUT)) { - array_mode = V_038000_ARRAY_2D_TILED_THIN1; - } - } - - return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode, - 0, 0, NULL); + struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex; + struct r600_resource *resource = &rtex->resource; + struct r600_screen *rscreen = (struct r600_screen*)screen; + return rscreen->ws->buffer_get_handle(resource->buf, + rtex->pitch_in_bytes[0], whandle); } static void r600_texture_destroy(struct pipe_screen *screen, @@ -391,27 +346,162 @@ static void r600_texture_destroy(struct pipe_screen *screen, { struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex; struct r600_resource *resource = &rtex->resource; - struct radeon *radeon = (struct radeon *)screen->winsys; if (rtex->flushed_depth_texture) pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL); - if (resource->bo) { - r600_bo_reference(radeon, &resource->bo, NULL); - } + if (rtex->stencil) + pipe_resource_reference((struct pipe_resource **)&rtex->stencil, NULL); + + pb_reference(&resource->buf, NULL); FREE(rtex); } -static boolean r600_texture_get_handle(struct pipe_screen* screen, - struct pipe_resource *ptex, - struct winsys_handle *whandle) +static const struct u_resource_vtbl r600_texture_vtbl = { - struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex; - struct r600_resource *resource = &rtex->resource; - struct radeon *radeon = (struct radeon *)screen->winsys; + r600_texture_get_handle, /* get_handle */ + r600_texture_destroy, /* resource_destroy */ + r600_texture_get_transfer, /* get_transfer */ + r600_texture_transfer_destroy, /* transfer_destroy */ + r600_texture_transfer_map, /* transfer_map */ + u_default_transfer_flush_region,/* transfer_flush_region */ + r600_texture_transfer_unmap, /* transfer_unmap */ + u_default_transfer_inline_write /* transfer_inline_write */ +}; + +static struct r600_resource_texture * +r600_texture_create_object(struct pipe_screen *screen, + const struct pipe_resource *base, + unsigned array_mode, + unsigned pitch_in_bytes_override, + unsigned max_buffer_size, + struct pb_buffer *buf, + boolean alloc_bo) +{ + struct r600_resource_texture *rtex; + struct r600_resource *resource; + struct r600_screen *rscreen = (struct r600_screen*)screen; + + rtex = CALLOC_STRUCT(r600_resource_texture); + if (rtex == NULL) + return NULL; + + resource = &rtex->resource; + resource->b.b.b = *base; + resource->b.b.vtbl = &r600_texture_vtbl; + pipe_reference_init(&resource->b.b.b.reference, 1); + resource->b.b.b.screen = screen; + rtex->pitch_override = pitch_in_bytes_override; + rtex->real_format = base->format; + + /* We must split depth and stencil into two separate buffers on Evergreen. */ + if (!(base->flags & R600_RESOURCE_FLAG_TRANSFER) && + ((struct r600_screen*)screen)->chip_class >= EVERGREEN && + util_format_is_depth_and_stencil(base->format)) { + struct pipe_resource stencil; + unsigned stencil_pitch_override = 0; + + switch (base->format) { + case PIPE_FORMAT_Z24_UNORM_S8_UINT: + rtex->real_format = PIPE_FORMAT_Z24X8_UNORM; + break; + case PIPE_FORMAT_S8_UINT_Z24_UNORM: + rtex->real_format = PIPE_FORMAT_X8Z24_UNORM; + break; + case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: + rtex->real_format = PIPE_FORMAT_Z32_FLOAT; + break; + default: + assert(0); + FREE(rtex); + return NULL; + } + + /* Divide the pitch in bytes by 4 for stencil, because it has a smaller pixel size. */ + if (pitch_in_bytes_override) { + assert(base->format == PIPE_FORMAT_Z24_UNORM_S8_UINT || + base->format == PIPE_FORMAT_S8_UINT_Z24_UNORM); + stencil_pitch_override = pitch_in_bytes_override / 4; + } + + /* Allocate the stencil buffer. */ + stencil = *base; + stencil.format = PIPE_FORMAT_S8_UINT; + rtex->stencil = r600_texture_create_object(screen, &stencil, array_mode, + stencil_pitch_override, + max_buffer_size, NULL, FALSE); + if (!rtex->stencil) { + FREE(rtex); + return NULL; + } + /* Proceed in creating the depth buffer. */ + } + + /* only mark depth textures the HW can hit as depth textures */ + if (util_format_is_depth_or_stencil(rtex->real_format) && permit_hardware_blit(screen, base)) + rtex->depth = 1; + + r600_setup_miptree(screen, rtex, array_mode); + + /* If we initialized separate stencil for Evergreen. place it after depth. */ + if (rtex->stencil) { + unsigned stencil_align, stencil_offset; + + stencil_align = r600_get_base_alignment(screen, rtex->stencil->real_format, array_mode); + stencil_offset = align(rtex->size, stencil_align); + + for (unsigned i = 0; i <= rtex->stencil->resource.b.b.b.last_level; i++) + rtex->stencil->offset[i] += stencil_offset; + + rtex->size = stencil_offset + rtex->stencil->size; + } + + /* Now create the backing buffer. */ + if (!buf && alloc_bo) { + struct pipe_resource *ptex = &rtex->resource.b.b.b; + unsigned base_align = r600_get_base_alignment(screen, ptex->format, array_mode); + + if (!r600_init_resource(rscreen, resource, rtex->size, base_align, base->bind, base->usage)) { + pipe_resource_reference((struct pipe_resource**)&rtex->stencil, NULL); + FREE(rtex); + return NULL; + } + } else if (buf) { + resource->buf = buf; + resource->cs_buf = rscreen->ws->buffer_get_cs_handle(buf); + resource->domains = RADEON_DOMAIN_GTT | RADEON_DOMAIN_VRAM; + } + + if (rtex->stencil) { + pb_reference(&rtex->stencil->resource.buf, rtex->resource.buf); + rtex->stencil->resource.cs_buf = rtex->resource.cs_buf; + rtex->stencil->resource.domains = rtex->resource.domains; + } + return rtex; +} + +DEBUG_GET_ONCE_BOOL_OPTION(tiling_enabled, "R600_TILING", FALSE); + +struct pipe_resource *r600_texture_create(struct pipe_screen *screen, + const struct pipe_resource *templ) +{ + struct r600_screen *rscreen = (struct r600_screen*)screen; + unsigned array_mode = 0; + + if (!(templ->flags & R600_RESOURCE_FLAG_TRANSFER) && + !(templ->bind & PIPE_BIND_SCANOUT)) { + if (util_format_is_compressed(templ->format)) { + array_mode = V_038000_ARRAY_1D_TILED_THIN1; + } + else if (debug_get_option_tiling_enabled() && + rscreen->info.drm_minor >= 9 && + permit_hardware_blit(screen, templ)) { + array_mode = V_038000_ARRAY_2D_TILED_THIN1; + } + } - return r600_bo_get_winsys_handle(radeon, resource->bo, - rtex->pitch_in_bytes[0], whandle); + return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode, + 0, 0, NULL, TRUE); } static struct pipe_surface *r600_create_surface(struct pipe_context *pipe, @@ -420,7 +510,6 @@ static struct pipe_surface *r600_create_surface(struct pipe_context *pipe, { struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; struct r600_surface *surface = CALLOC_STRUCT(r600_surface); - unsigned tile_height; unsigned level = surf_tmpl->u.tex.level; assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer); @@ -440,8 +529,8 @@ static struct pipe_surface *r600_create_surface(struct pipe_context *pipe, surface->base.u.tex.last_layer = surf_tmpl->u.tex.last_layer; surface->base.u.tex.level = level; - tile_height = r600_get_height_alignment(pipe->screen, rtex->array_mode[level]); - surface->aligned_height = align(surface->base.height, tile_height); + surface->aligned_height = r600_texture_get_nblocksy(pipe->screen, + rtex, level); return &surface->base; } @@ -452,41 +541,40 @@ static void r600_surface_destroy(struct pipe_context *pipe, FREE(surface); } - struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen, const struct pipe_resource *templ, struct winsys_handle *whandle) { - struct radeon *rw = (struct radeon*)screen->winsys; - struct r600_bo *bo = NULL; + struct r600_screen *rscreen = (struct r600_screen*)screen; + struct pb_buffer *buf = NULL; + unsigned stride = 0; unsigned array_mode = 0; + enum radeon_bo_layout micro, macro; /* Support only 2D textures without mipmaps */ if ((templ->target != PIPE_TEXTURE_2D && templ->target != PIPE_TEXTURE_RECT) || templ->depth0 != 1 || templ->last_level != 0) return NULL; - bo = r600_bo_handle(rw, whandle->handle, &array_mode); - if (bo == NULL) { + buf = rscreen->ws->buffer_from_handle(rscreen->ws, whandle, &stride); + if (!buf) return NULL; - } - return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode, - whandle->stride, - 0, - bo); -} + rscreen->ws->buffer_get_tiling(buf, µ, ¯o); -static unsigned int r600_texture_is_referenced(struct pipe_context *context, - struct pipe_resource *texture, - unsigned level, int layer) -{ - /* FIXME */ - return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE; + if (macro == RADEON_LAYOUT_TILED) + array_mode = V_0280A0_ARRAY_2D_TILED_THIN1; + else if (micro == RADEON_LAYOUT_TILED) + array_mode = V_0280A0_ARRAY_1D_TILED_THIN1; + else + array_mode = 0; + + return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode, + stride, 0, buf, FALSE); } int r600_texture_depth_flush(struct pipe_context *ctx, - struct pipe_resource *texture) + struct pipe_resource *texture, boolean just_create) { struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; struct pipe_resource resource; @@ -494,18 +582,17 @@ int r600_texture_depth_flush(struct pipe_context *ctx, if (rtex->flushed_depth_texture) goto out; - resource.target = PIPE_TEXTURE_2D; + resource.target = texture->target; resource.format = texture->format; resource.width0 = texture->width0; resource.height0 = texture->height0; - resource.depth0 = 1; - resource.last_level = 0; - resource.nr_samples = 0; + resource.depth0 = texture->depth0; + resource.array_size = texture->array_size; + resource.last_level = texture->last_level; + resource.nr_samples = texture->nr_samples; resource.usage = PIPE_USAGE_DYNAMIC; - resource.bind = 0; - resource.flags = R600_RESOURCE_FLAG_TRANSFER; - - resource.bind |= PIPE_BIND_DEPTH_STENCIL; + resource.bind = texture->bind | PIPE_BIND_DEPTH_STENCIL; + resource.flags = R600_RESOURCE_FLAG_TRANSFER | texture->flags; rtex->flushed_depth_texture = (struct r600_resource_texture *)ctx->screen->resource_create(ctx->screen, &resource); if (rtex->flushed_depth_texture == NULL) { @@ -513,7 +600,11 @@ int r600_texture_depth_flush(struct pipe_context *ctx, return -ENOMEM; } + ((struct r600_resource_texture *)rtex->flushed_depth_texture)->is_flushing_texture = TRUE; out: + if (just_create) + return 0; + /* XXX: only do this if the depth texture has actually changed: */ r600_blit_uncompress_depth(ctx, rtex); @@ -539,6 +630,10 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, int r; boolean use_staging_texture = FALSE; + if (usage & PIPE_TRANSFER_MAP_PERMANENTLY) { + return NULL; + } + /* We cannot map a tiled texture directly because the data is * in a different order, therefore we do detiling using a blit. * @@ -546,7 +641,7 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, * the CPU is much happier reading out of cached system memory * than uncached VRAM. */ - if (rtex->tiled) + if (R600_TEX_IS_TILED(rtex, level)) use_staging_texture = TRUE; if ((usage & PIPE_TRANSFER_READ) && u_box_volume(box) > 1024) @@ -567,6 +662,9 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, (texture->flags & R600_RESOURCE_FLAG_TRANSFER)) use_staging_texture = FALSE; + if (use_staging_texture && (usage & PIPE_TRANSFER_MAP_DIRECTLY)) + return NULL; + trans = CALLOC_STRUCT(r600_transfer); if (trans == NULL) return NULL; @@ -579,13 +677,16 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, */ /* XXX: when discard is true, no need to read back from depth texture */ - r = r600_texture_depth_flush(ctx, texture); + r = r600_texture_depth_flush(ctx, texture, FALSE); if (r < 0) { R600_ERR("failed to create temporary texture to hold untiled copy\n"); pipe_resource_reference(&trans->transfer.resource, NULL); FREE(trans); return NULL; } + trans->transfer.stride = rtex->flushed_depth_texture->pitch_in_bytes[level]; + trans->offset = r600_texture_get_offset(rtex->flushed_depth_texture, level, box->z); + return &trans->transfer; } else if (use_staging_texture) { resource.target = PIPE_TEXTURE_2D; resource.format = texture->format; @@ -622,11 +723,12 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, if (usage & PIPE_TRANSFER_READ) { r600_copy_to_staging_texture(ctx, trans); /* Always referenced in the blit. */ - ctx->flush(ctx, 0, NULL); + r600_flush(ctx, NULL, 0); } return &trans->transfer; } trans->transfer.stride = rtex->pitch_in_bytes[level]; + trans->transfer.layer_stride = rtex->layer_size[level]; trans->offset = r600_texture_get_offset(rtex, level, box->z); return &trans->transfer; } @@ -635,7 +737,8 @@ void r600_texture_transfer_destroy(struct pipe_context *ctx, struct pipe_transfer *transfer) { struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; - struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource; + struct pipe_resource *texture = transfer->resource; + struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; if (rtransfer->staging_texture) { if (transfer->usage & PIPE_TRANSFER_WRITE) { @@ -643,9 +746,12 @@ void r600_texture_transfer_destroy(struct pipe_context *ctx, } pipe_resource_reference(&rtransfer->staging_texture, NULL); } - if (rtex->flushed_depth_texture) { - pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL); + + if (rtex->depth && !rtex->is_flushing_texture) { + if ((transfer->usage & PIPE_TRANSFER_WRITE) && rtex->flushed_depth_texture) + r600_blit_push_depth(ctx, rtex); } + pipe_resource_reference(&transfer->resource, NULL); FREE(transfer); } @@ -653,53 +759,29 @@ void r600_texture_transfer_destroy(struct pipe_context *ctx, void* r600_texture_transfer_map(struct pipe_context *ctx, struct pipe_transfer* transfer) { + struct r600_pipe_context *rctx = (struct r600_pipe_context *)ctx; struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; - struct r600_bo *bo; + struct pb_buffer *buf; enum pipe_format format = transfer->resource->format; - struct radeon *radeon = (struct radeon *)ctx->screen->winsys; unsigned offset = 0; - unsigned usage = 0; char *map; if (rtransfer->staging_texture) { - bo = ((struct r600_resource *)rtransfer->staging_texture)->bo; + buf = ((struct r600_resource *)rtransfer->staging_texture)->buf; } else { struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource; if (rtex->flushed_depth_texture) - bo = ((struct r600_resource *)rtex->flushed_depth_texture)->bo; + buf = ((struct r600_resource *)rtex->flushed_depth_texture)->buf; else - bo = ((struct r600_resource *)transfer->resource)->bo; + buf = ((struct r600_resource *)transfer->resource)->buf; offset = rtransfer->offset + transfer->box.y / util_format_get_blockheight(format) * transfer->stride + transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); } - if (transfer->usage & PIPE_TRANSFER_WRITE) { - usage |= PB_USAGE_CPU_WRITE; - - if (transfer->usage & PIPE_TRANSFER_DISCARD) { - } - - if (transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) { - } - } - - if (transfer->usage & PIPE_TRANSFER_READ) { - usage |= PB_USAGE_CPU_READ; - } - - if (transfer->usage & PIPE_TRANSFER_DONTBLOCK) { - usage |= PB_USAGE_DONTBLOCK; - } - - if (transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) { - usage |= PB_USAGE_UNSYNCHRONIZED; - } - - map = r600_bo_map(radeon, bo, usage, ctx); - if (!map) { + if (!(map = rctx->ws->buffer_map(buf, rctx->ctx.cs, transfer->usage))) { return NULL; } @@ -710,36 +792,23 @@ void r600_texture_transfer_unmap(struct pipe_context *ctx, struct pipe_transfer* transfer) { struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; - struct radeon *radeon = (struct radeon *)ctx->screen->winsys; - struct r600_bo *bo; + struct r600_pipe_context *rctx = (struct r600_pipe_context*)ctx; + struct pb_buffer *buf; if (rtransfer->staging_texture) { - bo = ((struct r600_resource *)rtransfer->staging_texture)->bo; + buf = ((struct r600_resource *)rtransfer->staging_texture)->buf; } else { struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource; if (rtex->flushed_depth_texture) { - bo = ((struct r600_resource *)rtex->flushed_depth_texture)->bo; + buf = ((struct r600_resource *)rtex->flushed_depth_texture)->buf; } else { - bo = ((struct r600_resource *)transfer->resource)->bo; + buf = ((struct r600_resource *)transfer->resource)->buf; } } - r600_bo_unmap(radeon, bo); + rctx->ws->buffer_unmap(buf); } -struct u_resource_vtbl r600_texture_vtbl = -{ - r600_texture_get_handle, /* get_handle */ - r600_texture_destroy, /* resource_destroy */ - r600_texture_is_referenced, /* is_resource_referenced */ - r600_texture_get_transfer, /* get_transfer */ - r600_texture_transfer_destroy, /* transfer_destroy */ - r600_texture_transfer_map, /* transfer_map */ - u_default_transfer_flush_region,/* transfer_flush_region */ - r600_texture_transfer_unmap, /* transfer_unmap */ - u_default_transfer_inline_write /* transfer_inline_write */ -}; - void r600_init_surface_functions(struct r600_pipe_context *r600) { r600->context.create_surface = r600_create_surface; @@ -760,11 +829,7 @@ static unsigned r600_get_swizzle_combined(const unsigned char *swizzle_format, }; if (swizzle_view) { - /* Combine two sets of swizzles. */ - for (i = 0; i < 4; i++) { - swizzle[i] = swizzle_view[i] <= UTIL_FORMAT_SWIZZLE_W ? - swizzle_format[swizzle_view[i]] : swizzle_view[i]; - } + util_format_compose_swizzles(swizzle_format, swizzle_view, swizzle); } else { memcpy(swizzle, swizzle_format, 4); } @@ -795,13 +860,17 @@ static unsigned r600_get_swizzle_combined(const unsigned char *swizzle_format, } /* texture format translate */ -uint32_t r600_translate_texformat(enum pipe_format format, +uint32_t r600_translate_texformat(struct pipe_screen *screen, + enum pipe_format format, const unsigned char *swizzle_view, uint32_t *word4_p, uint32_t *yuv_format_p) { uint32_t result = 0, word4 = 0, yuv_format = 0; const struct util_format_description *desc; boolean uniform = TRUE; + static int r600_enable_s3tc = -1; + bool is_srgb_valid = FALSE; + int i; const uint32_t sign_bit[4] = { S_038010_FORMAT_COMP_X(V_038010_SQ_FORMAT_COMP_SIGNED), @@ -821,22 +890,28 @@ uint32_t r600_translate_texformat(enum pipe_format format, case PIPE_FORMAT_Z16_UNORM: result = FMT_16; goto out_word4; - case PIPE_FORMAT_X24S8_USCALED: + case PIPE_FORMAT_X24S8_UINT: word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); case PIPE_FORMAT_Z24X8_UNORM: - case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + case PIPE_FORMAT_Z24_UNORM_S8_UINT: result = FMT_8_24; goto out_word4; - case PIPE_FORMAT_S8X24_USCALED: + case PIPE_FORMAT_S8X24_UINT: word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); case PIPE_FORMAT_X8Z24_UNORM: - case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + case PIPE_FORMAT_S8_UINT_Z24_UNORM: result = FMT_24_8; goto out_word4; - case PIPE_FORMAT_S8_USCALED: + case PIPE_FORMAT_S8_UINT: result = FMT_8; word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); goto out_word4; + case PIPE_FORMAT_Z32_FLOAT: + result = FMT_32_FLOAT; + goto out_word4; + case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: + result = FMT_X24_8_32_FLOAT; + goto out_word4; default: goto out_unknown; } @@ -853,41 +928,84 @@ uint32_t r600_translate_texformat(enum pipe_format format, case UTIL_FORMAT_COLORSPACE_SRGB: word4 |= S_038010_FORCE_DEGAMMA(1); - if (format == PIPE_FORMAT_L8A8_SRGB || format == PIPE_FORMAT_L8_SRGB) - goto out_unknown; /* fails for some reason - TODO */ break; default: break; } - /* S3TC formats. TODO */ - if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { - static int r600_enable_s3tc = -1; + if (r600_enable_s3tc == -1) { + struct r600_screen *rscreen = (struct r600_screen *)screen; + if (rscreen->info.drm_minor >= 9) + r600_enable_s3tc = 1; + else + r600_enable_s3tc = debug_get_bool_option("R600_ENABLE_S3TC", FALSE); + } + + if (desc->layout == UTIL_FORMAT_LAYOUT_RGTC) { + if (!r600_enable_s3tc) + goto out_unknown; + + switch (format) { + case PIPE_FORMAT_RGTC1_SNORM: + case PIPE_FORMAT_LATC1_SNORM: + word4 |= sign_bit[0]; + case PIPE_FORMAT_RGTC1_UNORM: + case PIPE_FORMAT_LATC1_UNORM: + result = FMT_BC4; + goto out_word4; + case PIPE_FORMAT_RGTC2_SNORM: + case PIPE_FORMAT_LATC2_SNORM: + word4 |= sign_bit[0] | sign_bit[1]; + case PIPE_FORMAT_RGTC2_UNORM: + case PIPE_FORMAT_LATC2_UNORM: + result = FMT_BC5; + goto out_word4; + default: + goto out_unknown; + } + } - if (r600_enable_s3tc == -1) - r600_enable_s3tc = - debug_get_bool_option("R600_ENABLE_S3TC", FALSE); + if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { if (!r600_enable_s3tc) goto out_unknown; + if (!util_format_s3tc_enabled) { + goto out_unknown; + } + switch (format) { case PIPE_FORMAT_DXT1_RGB: case PIPE_FORMAT_DXT1_RGBA: + case PIPE_FORMAT_DXT1_SRGB: + case PIPE_FORMAT_DXT1_SRGBA: result = FMT_BC1; + is_srgb_valid = TRUE; goto out_word4; case PIPE_FORMAT_DXT3_RGBA: + case PIPE_FORMAT_DXT3_SRGBA: result = FMT_BC2; + is_srgb_valid = TRUE; goto out_word4; case PIPE_FORMAT_DXT5_RGBA: + case PIPE_FORMAT_DXT5_SRGBA: result = FMT_BC3; + is_srgb_valid = TRUE; goto out_word4; default: goto out_unknown; } } + if (format == PIPE_FORMAT_R9G9B9E5_FLOAT) { + result = FMT_5_9_9_9_SHAREDEXP; + goto out_word4; + } else if (format == PIPE_FORMAT_R11G11B10_FLOAT) { + result = FMT_10_11_11_FLOAT; + goto out_word4; + } + for (i = 0; i < desc->nr_channels; i++) { if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) { @@ -897,8 +1015,6 @@ uint32_t r600_translate_texformat(enum pipe_format format, /* R8G8Bx_SNORM - TODO CxV8U8 */ - /* RGTC - TODO */ - /* See whether the components are of the same size. */ for (i = 1; i < desc->nr_channels; i++) { uniform = uniform && desc->channel[0].size == desc->channel[i].size; @@ -906,6 +1022,9 @@ uint32_t r600_translate_texformat(enum pipe_format format, /* Non-uniform formats. */ if (!uniform) { + if (desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB && + desc->channel[0].pure_integer) + word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); switch(desc->nr_channels) { case 3: if (desc->channel[0].size == 5 && @@ -927,7 +1046,7 @@ uint32_t r600_translate_texformat(enum pipe_format format, desc->channel[1].size == 10 && desc->channel[2].size == 10 && desc->channel[3].size == 2) { - result = FMT_10_10_10_2; + result = FMT_2_10_10_10; goto out_word4; } goto out_unknown; @@ -949,10 +1068,15 @@ uint32_t r600_translate_texformat(enum pipe_format format, switch (desc->channel[i].type) { case UTIL_FORMAT_TYPE_UNSIGNED: case UTIL_FORMAT_TYPE_SIGNED: +#if 0 if (!desc->channel[i].normalized && desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) { goto out_unknown; } +#endif + if (desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB && + desc->channel[i].pure_integer) + word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT); switch (desc->channel[i].size) { case 4: @@ -975,6 +1099,7 @@ uint32_t r600_translate_texformat(enum pipe_format format, goto out_word4; case 4: result = FMT_8_8_8_8; + is_srgb_valid = TRUE; goto out_word4; } goto out_unknown; @@ -990,6 +1115,19 @@ uint32_t r600_translate_texformat(enum pipe_format format, result = FMT_16_16_16_16; goto out_word4; } + goto out_unknown; + case 32: + switch (desc->nr_channels) { + case 1: + result = FMT_32; + goto out_word4; + case 2: + result = FMT_32_32; + goto out_word4; + case 4: + result = FMT_32_32_32_32; + goto out_word4; + } } goto out_unknown; @@ -1021,15 +1159,19 @@ uint32_t r600_translate_texformat(enum pipe_format format, goto out_word4; } } - + goto out_unknown; } + out_word4: + + if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB && !is_srgb_valid) + return ~0; if (word4_p) *word4_p = word4; if (yuv_format_p) *yuv_format_p = yuv_format; return result; out_unknown: -// R600_ERR("Unable to handle texformat %d %s\n", format, util_format_name(format)); + /* R600_ERR("Unable to handle texformat %d %s\n", format, util_format_name(format)); */ return ~0; }