X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fr600%2Fr600_texture.c;h=4673d86fd02d71089d12f4cf42793cadfa843eef;hb=897d2351322e4c516eee622b3f49eedca7a2e308;hp=10c32c53a6dd66ed2e9c60d39b9e881cc63d0111;hpb=f7a85f603b0da0770c27b200bff6e239e3aeae95;p=mesa.git diff --git a/src/gallium/drivers/r600/r600_texture.c b/src/gallium/drivers/r600/r600_texture.c index 10c32c53a6d..4673d86fd02 100644 --- a/src/gallium/drivers/r600/r600_texture.c +++ b/src/gallium/drivers/r600/r600_texture.c @@ -24,19 +24,12 @@ * Jerome Glisse * Corbin Simpson */ -#include -#include -#include -#include -#include -#include -#include -#include "state_tracker/drm_driver.h" -#include "pipebuffer/pb_buffer.h" -#include "r600_pipe.h" -#include "r600_resource.h" -#include "r600d.h" #include "r600_formats.h" +#include "r600d.h" + +#include +#include "util/u_format_s3tc.h" +#include "util/u_memory.h" /* 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) @@ -44,7 +37,7 @@ static void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_t struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer; struct pipe_resource *texture = transfer->resource; - ctx->resource_copy_region(ctx, rtransfer->staging_texture, + ctx->resource_copy_region(ctx, &rtransfer->staging->b.b, 0, 0, 0, 0, texture, transfer->level, &transfer->box); } @@ -64,10 +57,8 @@ static void r600_copy_from_staging_texture(struct pipe_context *ctx, struct r600 sbox.depth = 1; ctx->resource_copy_region(ctx, texture, transfer->level, transfer->box.x, transfer->box.y, transfer->box.z, - rtransfer->staging_texture, + &rtransfer->staging->b.b, 0, &sbox); - - ctx->flush(ctx, NULL); } unsigned r600_texture_get_offset(struct r600_resource_texture *rtex, @@ -75,7 +66,7 @@ unsigned r600_texture_get_offset(struct r600_resource_texture *rtex, { unsigned offset = rtex->offset[level]; - switch (rtex->resource.b.b.b.target) { + switch (rtex->resource.b.b.target) { case PIPE_TEXTURE_3D: case PIPE_TEXTURE_CUBE: default: @@ -94,19 +85,19 @@ static unsigned r600_get_block_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); + 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; @@ -120,7 +111,7 @@ 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: @@ -146,14 +137,14 @@ static unsigned r600_get_base_alignment(struct pipe_screen *screen, 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; @@ -172,17 +163,17 @@ static unsigned r600_texture_get_nblocksx(struct pipe_screen *screen, struct r600_resource_texture *rtex, unsigned level) { - struct pipe_resource *ptex = &rtex->resource.b.b.b; + struct pipe_resource *ptex = &rtex->resource.b.b; unsigned nblocksx, block_align, width; - unsigned blocksize = util_format_get_blocksize(ptex->format); + unsigned blocksize = util_format_get_blocksize(rtex->real_format); if (rtex->pitch_override) return rtex->pitch_override / blocksize; width = mip_minify(ptex->width0, level); - nblocksx = util_format_get_nblocksx(ptex->format, width); + nblocksx = util_format_get_nblocksx(rtex->real_format, width); - block_align = r600_get_block_alignment(screen, ptex->format, + block_align = r600_get_block_alignment(screen, rtex->real_format, rtex->array_mode[level]); nblocksx = align(nblocksx, block_align); return nblocksx; @@ -192,13 +183,23 @@ static unsigned r600_texture_get_nblocksy(struct pipe_screen *screen, struct r600_resource_texture *rtex, unsigned level) { - struct pipe_resource *ptex = &rtex->resource.b.b.b; + struct pipe_resource *ptex = &rtex->resource.b.b; unsigned height, tile_height; height = mip_minify(ptex->height0, level); - height = 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]); + + /* 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; } @@ -207,7 +208,7 @@ 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.b.b.b; + struct pipe_resource *ptex = &rtex->resource.b.b; switch (array_mode) { case V_0280A0_ARRAY_LINEAR_GENERAL: @@ -221,7 +222,7 @@ 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_block_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); @@ -234,26 +235,154 @@ static void r600_texture_set_array_mode(struct pipe_screen *screen, } } +static int r600_init_surface(struct radeon_surface *surface, + const struct pipe_resource *ptex, + unsigned array_mode) +{ + surface->npix_x = ptex->width0; + surface->npix_y = ptex->height0; + surface->npix_z = ptex->depth0; + surface->blk_w = util_format_get_blockwidth(ptex->format); + surface->blk_h = util_format_get_blockheight(ptex->format); + surface->blk_d = 1; + surface->array_size = 1; + surface->last_level = ptex->last_level; + surface->bpe = util_format_get_blocksize(ptex->format); + /* align byte per element on dword */ + if (surface->bpe == 3) { + surface->bpe = 4; + } + surface->nsamples = 1; + surface->flags = 0; + switch (array_mode) { + case V_038000_ARRAY_1D_TILED_THIN1: + surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); + break; + case V_038000_ARRAY_2D_TILED_THIN1: + surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); + break; + case V_038000_ARRAY_LINEAR_ALIGNED: + surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE); + break; + case V_038000_ARRAY_LINEAR_GENERAL: + default: + surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE); + break; + } + switch (ptex->target) { + case PIPE_TEXTURE_1D: + surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D, TYPE); + break; + case PIPE_TEXTURE_RECT: + case PIPE_TEXTURE_2D: + surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); + break; + case PIPE_TEXTURE_3D: + surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_3D, TYPE); + break; + case PIPE_TEXTURE_1D_ARRAY: + surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D_ARRAY, TYPE); + surface->array_size = ptex->array_size; + break; + case PIPE_TEXTURE_2D_ARRAY: + surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D_ARRAY, TYPE); + surface->array_size = ptex->array_size; + break; + case PIPE_TEXTURE_CUBE: + surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_CUBEMAP, TYPE); + break; + case PIPE_BUFFER: + default: + return -EINVAL; + } + if (ptex->bind & PIPE_BIND_SCANOUT) { + surface->flags |= RADEON_SURF_SCANOUT; + } + if (util_format_is_depth_and_stencil(ptex->format)) { + surface->flags |= RADEON_SURF_ZBUFFER; + surface->flags |= RADEON_SURF_SBUFFER; + } + + return 0; +} + +static int r600_setup_surface(struct pipe_screen *screen, + struct r600_resource_texture *rtex, + unsigned array_mode, + unsigned pitch_in_bytes_override) +{ + struct pipe_resource *ptex = &rtex->resource.b.b; + struct r600_screen *rscreen = (struct r600_screen*)screen; + unsigned i; + int r; + + if (util_format_is_depth_or_stencil(rtex->real_format)) { + rtex->surface.flags |= RADEON_SURF_ZBUFFER; + rtex->surface.flags |= RADEON_SURF_SBUFFER; + } + + r = rscreen->ws->surface_init(rscreen->ws, &rtex->surface); + if (r) { + return r; + } + rtex->size = rtex->surface.bo_size; + if (pitch_in_bytes_override && pitch_in_bytes_override != rtex->surface.level[0].pitch_bytes) { + /* old ddx on evergreen over estimate alignment for 1d, only 1 level + * for those + */ + rtex->surface.level[0].nblk_x = pitch_in_bytes_override / rtex->surface.bpe; + rtex->surface.level[0].pitch_bytes = pitch_in_bytes_override; + rtex->surface.level[0].slice_size = pitch_in_bytes_override * rtex->surface.level[0].nblk_y; + if (rtex->surface.flags & RADEON_SURF_SBUFFER) { + rtex->surface.stencil_offset = rtex->surface.level[0].slice_size; + } + } + for (i = 0; i <= ptex->last_level; i++) { + rtex->offset[i] = rtex->surface.level[i].offset; + rtex->layer_size[i] = rtex->surface.level[i].slice_size; + rtex->pitch_in_bytes[i] = rtex->surface.level[i].pitch_bytes; + switch (rtex->surface.level[i].mode) { + case RADEON_SURF_MODE_LINEAR_ALIGNED: + rtex->array_mode[i] = V_038000_ARRAY_LINEAR_ALIGNED; + break; + case RADEON_SURF_MODE_1D: + rtex->array_mode[i] = V_038000_ARRAY_1D_TILED_THIN1; + break; + case RADEON_SURF_MODE_2D: + rtex->array_mode[i] = V_038000_ARRAY_2D_TILED_THIN1; + break; + default: + case RADEON_SURF_MODE_LINEAR: + rtex->array_mode[i] = 0; + break; + } + } + return 0; +} + static void r600_setup_miptree(struct pipe_screen *screen, struct r600_resource_texture *rtex, unsigned array_mode) { - struct pipe_resource *ptex = &rtex->resource.b.b.b; - struct radeon *radeon = (struct radeon *)screen->winsys; - enum chip_class chipc = r600_get_family_class(radeon); + struct pipe_resource *ptex = &rtex->resource.b.b; + enum chip_class chipc = ((struct r600_screen*)screen)->chip_class; unsigned size, layer_size, i, offset; - unsigned nblocksx, nblocksy, extra_size = 0; + unsigned nblocksx, nblocksy; for (i = 0, offset = 0; i <= ptex->last_level; i++) { - unsigned blocksize = util_format_get_blocksize(ptex->format); - unsigned base_align = r600_get_base_alignment(screen, ptex->format, array_mode); + 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); nblocksx = r600_texture_get_nblocksx(screen, rtex, i); nblocksy = r600_texture_get_nblocksy(screen, rtex, i); - layer_size = nblocksx * nblocksy * blocksize; + 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) size = layer_size * 8; @@ -265,10 +394,6 @@ static void r600_setup_miptree(struct pipe_screen *screen, else size = layer_size * ptex->array_size; - /* evergreen stores depth and stencil separately */ - if ((chipc >= EVERGREEN) && util_format_is_depth_or_stencil(ptex->format)) - extra_size = align(extra_size + (nblocksx * nblocksy * 1), base_align); - /* align base image and start of miptree */ if ((i == 0) || (i == 1)) offset = align(offset, base_align); @@ -279,7 +404,7 @@ static void r600_setup_miptree(struct pipe_screen *screen, offset += size; } - rtex->size = offset + extra_size; + rtex->size = offset; } /* Figure out whether u_blitter will fallback to a transfer operation. @@ -298,7 +423,7 @@ static boolean permit_hardware_blit(struct pipe_screen *screen, /* hackaround for S3TC */ if (util_format_is_compressed(res->format)) return TRUE; - + if (!screen->is_format_supported(screen, res->format, res->target, @@ -313,14 +438,7 @@ static boolean permit_hardware_blit(struct pipe_screen *screen, PIPE_BIND_SAMPLER_VIEW)) return FALSE; - switch (res->usage) { - case PIPE_USAGE_STREAM: - case PIPE_USAGE_STAGING: - return FALSE; - - default: - return TRUE; - } + return TRUE; } static boolean r600_texture_get_handle(struct pipe_screen* screen, @@ -329,10 +447,10 @@ static boolean r600_texture_get_handle(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; + struct r600_screen *rscreen = (struct r600_screen*)screen; - return r600_bo_get_winsys_handle(radeon, resource->bo, - rtex->pitch_in_bytes[0], whandle); + return rscreen->ws->buffer_get_handle(resource->buf, + rtex->pitch_in_bytes[0], whandle); } static void r600_texture_destroy(struct pipe_screen *screen, @@ -340,14 +458,14 @@ 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); } @@ -358,9 +476,9 @@ static const struct u_resource_vtbl r600_texture_vtbl = 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 */ + NULL, /* transfer_flush_region */ r600_texture_transfer_unmap, /* transfer_unmap */ - u_default_transfer_inline_write /* transfer_inline_write */ + NULL /* transfer_inline_write */ }; static struct r600_resource_texture * @@ -369,40 +487,124 @@ r600_texture_create_object(struct pipe_screen *screen, unsigned array_mode, unsigned pitch_in_bytes_override, unsigned max_buffer_size, - struct r600_bo *bo) + struct pb_buffer *buf, + boolean alloc_bo, + struct radeon_surface *surface) { struct r600_resource_texture *rtex; struct r600_resource *resource; - struct radeon *radeon = (struct radeon *)screen->winsys; + struct r600_screen *rscreen = (struct r600_screen*)screen; + int r; 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; - resource->bo = bo; + resource->b.b = *base; + resource->b.vtbl = &r600_texture_vtbl; + pipe_reference_init(&resource->b.b.reference, 1); + resource->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) && + !rscreen->use_surface_alloc) { + 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, surface); + 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(base->format) && permit_hardware_blit(screen, base)) - rtex->depth = 1; + if (util_format_is_depth_or_stencil(rtex->real_format) && permit_hardware_blit(screen, base)) + rtex->is_depth = true; r600_setup_miptree(screen, rtex, array_mode); + if (rscreen->use_surface_alloc) { + rtex->surface = *surface; + r = r600_setup_surface(screen, rtex, array_mode, pitch_in_bytes_override); + if (r) { + FREE(rtex); + return NULL; + } + } - resource->size = rtex->size; + /* If we initialized separate stencil for Evergreen. place it after depth. */ + if (rtex->stencil) { + unsigned stencil_align, stencil_offset; - if (!resource->bo) { - struct pipe_resource *ptex = &rtex->resource.b.b.b; - int base_align = r600_get_base_alignment(screen, ptex->format, array_mode); + stencil_align = r600_get_base_alignment(screen, rtex->stencil->real_format, array_mode); + stencil_offset = align(rtex->size, stencil_align); - resource->bo = r600_bo(radeon, rtex->size, base_align, base->bind, base->usage); - if (!resource->bo) { + for (unsigned i = 0; i <= rtex->stencil->resource.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; + unsigned base_align = r600_get_base_alignment(screen, ptex->format, array_mode); + + if (rscreen->use_surface_alloc) { + base_align = rtex->surface.bo_alignment; + } else if (util_format_is_depth_or_stencil(rtex->real_format)) { + /* ugly work around depth buffer need stencil room at end of bo */ + rtex->size += ptex->width0 * ptex->height0; + } + 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; } @@ -410,35 +612,33 @@ r600_texture_create_object(struct pipe_screen *screen, struct pipe_resource *r600_texture_create(struct pipe_screen *screen, const struct pipe_resource *templ) { + struct r600_screen *rscreen = (struct r600_screen*)screen; + struct radeon_surface surface; unsigned array_mode = 0; - static int force_tiling = -1; - - /* Would like some magic "get_bool_option_once" routine. - */ - if (force_tiling == -1) { -#if 0 - /* reenable when 2D tiling is fixed better */ - struct r600_screen *rscreen = (struct r600_screen *)screen; - if (r600_get_minor_version(rscreen->radeon) >= 9) - force_tiling = debug_get_bool_option("R600_TILING", TRUE); -#endif - force_tiling = debug_get_bool_option("R600_TILING", FALSE); - } + int r; - if (force_tiling && permit_hardware_blit(screen, templ)) { - if (!(templ->flags & R600_RESOURCE_FLAG_TRANSFER) && - !(templ->bind & PIPE_BIND_SCANOUT)) { + if (!(templ->flags & R600_RESOURCE_FLAG_TRANSFER)) { + if (rscreen->use_surface_alloc && + !(templ->bind & PIPE_BIND_SCANOUT) && + templ->usage != PIPE_USAGE_STAGING && + templ->usage != PIPE_USAGE_STREAM && + permit_hardware_blit(screen, templ)) { array_mode = V_038000_ARRAY_2D_TILED_THIN1; + } else if (util_format_is_compressed(templ->format)) { + array_mode = V_038000_ARRAY_1D_TILED_THIN1; } } - if (!(templ->flags & R600_RESOURCE_FLAG_TRANSFER) && - util_format_is_compressed(templ->format)) - array_mode = V_038000_ARRAY_1D_TILED_THIN1; - + r = r600_init_surface(&surface, templ, array_mode); + if (r) { + return NULL; + } + r = rscreen->ws->surface_best(rscreen->ws, &surface); + if (r) { + return NULL; + } return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode, - 0, 0, NULL); - + 0, 0, NULL, TRUE, &surface); } static struct pipe_surface *r600_create_surface(struct pipe_context *pipe, @@ -452,8 +652,6 @@ static struct pipe_surface *r600_create_surface(struct pipe_context *pipe, assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer); if (surface == NULL) return NULL; - /* XXX no offset */ -/* offset = r600_texture_get_offset(rtex, level, surf_tmpl->u.tex.first_layer);*/ pipe_reference_init(&surface->base.reference, 1); pipe_resource_reference(&surface->base.texture, texture); surface->base.context = pipe; @@ -478,29 +676,46 @@ 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; + struct radeon_surface surface; + int r; /* 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; - } + rscreen->ws->buffer_get_tiling(buf, µ, ¯o, + &surface.bankw, &surface.bankh, + &surface.tile_split, + &surface.stencil_tile_split, + &surface.mtilea); + + 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; + + r = r600_init_surface(&surface, templ, array_mode); + if (r) { + return NULL; + } return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode, - whandle->stride, - 0, - bo); + stride, 0, buf, FALSE, &surface); } int r600_texture_depth_flush(struct pipe_context *ctx, @@ -512,19 +727,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.array_size = 1; + resource.depth0 = texture->depth0; + resource.array_size = texture->array_size; resource.last_level = texture->last_level; - resource.nr_samples = 0; + 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) { @@ -556,6 +769,7 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, unsigned usage, const struct pipe_box *box) { + struct r600_context *rctx = (struct r600_context*)ctx; struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; struct pipe_resource resource; struct r600_transfer *trans; @@ -575,21 +789,19 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, if ((usage & PIPE_TRANSFER_READ) && u_box_volume(box) > 1024) use_staging_texture = TRUE; - /* XXX: Use a staging texture for uploads if the underlying BO - * is busy. No interface for checking that currently? so do - * it eagerly whenever the transfer doesn't require a readback - * and might block. - */ - if ((usage & PIPE_TRANSFER_WRITE) && - !(usage & (PIPE_TRANSFER_READ | - PIPE_TRANSFER_DONTBLOCK | - PIPE_TRANSFER_UNSYNCHRONIZED))) + /* Use a staging texture for uploads if the underlying BO is busy. */ + if (!(usage & PIPE_TRANSFER_READ) && + (rctx->ws->cs_is_buffer_referenced(rctx->cs, rtex->resource.cs_buf, RADEON_USAGE_READWRITE) || + rctx->ws->buffer_is_busy(rtex->resource.buf, RADEON_USAGE_READWRITE))) use_staging_texture = TRUE; if (!permit_hardware_blit(ctx->screen, texture) || (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; @@ -597,7 +809,7 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, trans->transfer.level = level; trans->transfer.usage = usage; trans->transfer.box = *box; - if (rtex->depth) { + if (rtex->is_depth) { /* XXX: only readback the rectangle which is being mapped? */ /* XXX: when discard is true, no need to read back from depth texture @@ -635,8 +847,8 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, resource.bind |= PIPE_BIND_SAMPLER_VIEW; } /* Create the temporary texture. */ - trans->staging_texture = ctx->screen->resource_create(ctx->screen, &resource); - if (trans->staging_texture == NULL) { + trans->staging = (struct r600_resource*)ctx->screen->resource_create(ctx->screen, &resource); + if (trans->staging == NULL) { R600_ERR("failed to create temporary texture to hold untiled copy\n"); pipe_resource_reference(&trans->transfer.resource, NULL); FREE(trans); @@ -644,11 +856,11 @@ struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, } trans->transfer.stride = - ((struct r600_resource_texture *)trans->staging_texture)->pitch_in_bytes[0]; + ((struct r600_resource_texture *)trans->staging)->pitch_in_bytes[0]; if (usage & PIPE_TRANSFER_READ) { r600_copy_to_staging_texture(ctx, trans); /* Always referenced in the blit. */ - ctx->flush(ctx, NULL); + r600_flush(ctx, NULL, 0); } return &trans->transfer; } @@ -665,14 +877,14 @@ void r600_texture_transfer_destroy(struct pipe_context *ctx, struct pipe_resource *texture = transfer->resource; struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture; - if (rtransfer->staging_texture) { + if (rtransfer->staging) { if (transfer->usage & PIPE_TRANSFER_WRITE) { r600_copy_from_staging_texture(ctx, rtransfer); } - pipe_resource_reference(&rtransfer->staging_texture, NULL); + pipe_resource_reference((struct pipe_resource**)&rtransfer->staging, NULL); } - if (rtex->depth && !rtex->is_flushing_texture) { + if (rtex->is_depth && !rtex->is_flushing_texture) { if ((transfer->usage & PIPE_TRANSFER_WRITE) && rtex->flushed_depth_texture) r600_blit_push_depth(ctx, rtex); } @@ -684,53 +896,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_context *rctx = (struct r600_context *)ctx; struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; - struct r600_bo *bo; + struct radeon_winsys_cs_handle *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; + if (rtransfer->staging) { + buf = ((struct r600_resource *)rtransfer->staging)->cs_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)->cs_buf; else - bo = ((struct r600_resource *)transfer->resource)->bo; + buf = ((struct r600_resource *)transfer->resource)->cs_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->cs, transfer->usage))) { return NULL; } @@ -741,24 +929,24 @@ 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_context *rctx = (struct r600_context*)ctx; + struct radeon_winsys_cs_handle *buf; - if (rtransfer->staging_texture) { - bo = ((struct r600_resource *)rtransfer->staging_texture)->bo; + if (rtransfer->staging) { + buf = ((struct r600_resource *)rtransfer->staging)->cs_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)->cs_buf; } else { - bo = ((struct r600_resource *)transfer->resource)->bo; + buf = ((struct r600_resource *)transfer->resource)->cs_buf; } } - r600_bo_unmap(radeon, bo); + rctx->ws->buffer_unmap(buf); } -void r600_init_surface_functions(struct r600_pipe_context *r600) +void r600_init_surface_functions(struct r600_context *r600) { r600->context.create_surface = r600_create_surface; r600->context.surface_destroy = r600_surface_destroy; @@ -778,11 +966,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); } @@ -822,6 +1006,7 @@ uint32_t r600_translate_texformat(struct pipe_screen *screen, 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] = { @@ -842,26 +1027,26 @@ uint32_t r600_translate_texformat(struct pipe_screen *screen, 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_USCALED: + case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: result = FMT_X24_8_32_FLOAT; goto out_word4; default: @@ -876,7 +1061,7 @@ uint32_t r600_translate_texformat(struct pipe_screen *screen, default: break; } - goto out_unknown; /* TODO */ + goto out_unknown; /* XXX */ case UTIL_FORMAT_COLORSPACE_SRGB: word4 |= S_038010_FORCE_DEGAMMA(1); @@ -888,7 +1073,7 @@ uint32_t r600_translate_texformat(struct pipe_screen *screen, if (r600_enable_s3tc == -1) { struct r600_screen *rscreen = (struct r600_screen *)screen; - if (r600_get_minor_version(rscreen->radeon) >= 9) + if (rscreen->info.drm_minor >= 9) r600_enable_s3tc = 1; else r600_enable_s3tc = debug_get_bool_option("R600_ENABLE_S3TC", FALSE); @@ -933,14 +1118,32 @@ uint32_t r600_translate_texformat(struct pipe_screen *screen, 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 (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) { + switch (format) { + case PIPE_FORMAT_R8G8_B8G8_UNORM: + case PIPE_FORMAT_G8R8_B8R8_UNORM: + result = FMT_GB_GR; + goto out_word4; + case PIPE_FORMAT_G8R8_G8B8_UNORM: + case PIPE_FORMAT_R8G8_R8B8_UNORM: + result = FMT_BG_RG; goto out_word4; default: goto out_unknown; @@ -962,7 +1165,7 @@ uint32_t r600_translate_texformat(struct pipe_screen *screen, } } - /* R8G8Bx_SNORM - TODO CxV8U8 */ + /* R8G8Bx_SNORM - XXX CxV8U8 */ /* See whether the components are of the same size. */ for (i = 1; i < desc->nr_channels; i++) { @@ -971,6 +1174,9 @@ uint32_t r600_translate_texformat(struct pipe_screen *screen, /* 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 && @@ -1014,10 +1220,15 @@ uint32_t r600_translate_texformat(struct pipe_screen *screen, 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: @@ -1040,6 +1251,7 @@ uint32_t r600_translate_texformat(struct pipe_screen *screen, goto out_word4; case 4: result = FMT_8_8_8_8; + is_srgb_valid = TRUE; goto out_word4; } goto out_unknown; @@ -1103,6 +1315,9 @@ uint32_t r600_translate_texformat(struct pipe_screen *screen, } out_word4: + + if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB && !is_srgb_valid) + return ~0; if (word4_p) *word4_p = word4; if (yuv_format_p)