X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fradeon%2Fr600_texture.c;h=ab8ce7bd7136d9be8d0f6cd2173dc4c3b6c70ce5;hb=76039b38f0ef54ca61cbe72b899dfcf0f0c724e4;hp=99f8445fcc8dae0d47b486d0c4e22ee0b1d1b84f;hpb=4c110994533c67f2e501cd32ee0c2f91060630e0;p=mesa.git diff --git a/src/gallium/drivers/radeon/r600_texture.c b/src/gallium/drivers/radeon/r600_texture.c index 99f8445fcc8..ab8ce7bd713 100644 --- a/src/gallium/drivers/radeon/r600_texture.c +++ b/src/gallium/drivers/radeon/r600_texture.c @@ -28,6 +28,7 @@ #include "r600_cs.h" #include "util/u_format.h" #include "util/u_memory.h" +#include "util/u_pack_color.h" #include #include @@ -79,12 +80,8 @@ static void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_t return; } - if (!rctx->dma_copy(ctx, dst, 0, 0, 0, 0, - src, transfer->level, - &transfer->box)) { - ctx->resource_copy_region(ctx, dst, 0, 0, 0, 0, - src, transfer->level, &transfer->box); - } + rctx->dma_copy(ctx, dst, 0, 0, 0, 0, src, transfer->level, + &transfer->box); } /* Copy from a transfer's staging texture to a full GPU one. */ @@ -105,13 +102,9 @@ static void r600_copy_from_staging_texture(struct pipe_context *ctx, struct r600 return; } - if (!rctx->dma_copy(ctx, dst, transfer->level, - transfer->box.x, transfer->box.y, transfer->box.z, - src, 0, &sbox)) { - ctx->resource_copy_region(ctx, dst, transfer->level, - transfer->box.x, transfer->box.y, transfer->box.z, - src, 0, &sbox); - } + rctx->dma_copy(ctx, dst, transfer->level, + transfer->box.x, transfer->box.y, transfer->box.z, + src, 0, &sbox); } static unsigned r600_texture_get_offset(struct r600_texture *rtex, unsigned level, @@ -236,8 +229,8 @@ static int r600_setup_surface(struct pipe_screen *screen, } static boolean r600_texture_get_handle(struct pipe_screen* screen, - struct pipe_resource *ptex, - struct winsys_handle *whandle) + struct pipe_resource *ptex, + struct winsys_handle *whandle) { struct r600_texture *rtex = (struct r600_texture*)ptex; struct r600_resource *resource = &rtex->resource; @@ -254,7 +247,8 @@ static boolean r600_texture_get_handle(struct pipe_screen* screen, surface->tile_split, surface->stencil_tile_split, surface->mtilea, - surface->level[0].pitch_bytes); + surface->level[0].pitch_bytes, + (surface->flags & RADEON_SURF_SCANOUT) != 0); return rscreen->ws->buffer_get_handle(resource->buf, surface->level[0].pitch_bytes, whandle); @@ -269,7 +263,7 @@ static void r600_texture_destroy(struct pipe_screen *screen, if (rtex->flushed_depth_texture) pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL); - pipe_resource_reference((struct pipe_resource**)&rtex->htile, NULL); + pipe_resource_reference((struct pipe_resource**)&rtex->htile_buffer, NULL); if (rtex->cmask_buffer != &rtex->resource) { pipe_resource_reference((struct pipe_resource**)&rtex->cmask_buffer, NULL); } @@ -295,6 +289,12 @@ void r600_texture_get_fmask_info(struct r600_common_screen *rscreen, fmask.nsamples = 1; fmask.flags |= RADEON_SURF_FMASK; + /* Force 2D tiling if it wasn't set. This may occur when creating + * FMASK for MSAA resolve on R6xx. On R6xx, the single-sample + * destination buffer must have an FMASK too. */ + fmask.flags = RADEON_SURF_CLR(fmask.flags, MODE); + fmask.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); + if (rscreen->chip_class >= SI) { fmask.flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; } @@ -380,7 +380,8 @@ void r600_texture_get_cmask_info(struct r600_common_screen *rscreen, out->slice_tile_max = ((pitch_elements * height) / (128*128)) - 1; out->alignment = MAX2(256, base_align); - out->size = rtex->surface.array_size * align(slice_bytes, base_align); + out->size = (util_max_layer(&rtex->resource.b.b, 0) + 1) * + align(slice_bytes, base_align); } static void si_texture_get_cmask_info(struct r600_common_screen *rscreen, @@ -427,7 +428,8 @@ static void si_texture_get_cmask_info(struct r600_common_screen *rscreen, out->slice_tile_max -= 1; out->alignment = MAX2(256, base_align); - out->size = rtex->surface.array_size * align(slice_bytes, base_align); + out->size = (util_max_layer(&rtex->resource.b.b, 0) + 1) * + align(slice_bytes, base_align); } static void r600_texture_allocate_cmask(struct r600_common_screen *rscreen, @@ -441,59 +443,128 @@ static void r600_texture_allocate_cmask(struct r600_common_screen *rscreen, rtex->cmask.offset = align(rtex->size, rtex->cmask.alignment); rtex->size = rtex->cmask.offset + rtex->cmask.size; + + if (rscreen->chip_class >= SI) + rtex->cb_color_info |= SI_S_028C70_FAST_CLEAR(1); + else + rtex->cb_color_info |= EG_S_028C70_FAST_CLEAR(1); } -void r600_texture_init_cmask(struct r600_common_screen *rscreen, - struct r600_texture *rtex) +static void r600_texture_alloc_cmask_separate(struct r600_common_screen *rscreen, + struct r600_texture *rtex) { + if (rtex->cmask_buffer) + return; + assert(rtex->cmask.size == 0); - r600_texture_get_cmask_info(rscreen, rtex, &rtex->cmask); + if (rscreen->chip_class >= SI) { + si_texture_get_cmask_info(rscreen, rtex, &rtex->cmask); + } else { + r600_texture_get_cmask_info(rscreen, rtex, &rtex->cmask); + } rtex->cmask_buffer = (struct r600_resource *) pipe_buffer_create(&rscreen->b, PIPE_BIND_CUSTOM, - PIPE_USAGE_STATIC, rtex->cmask.size); + PIPE_USAGE_DEFAULT, rtex->cmask.size); if (rtex->cmask_buffer == NULL) { rtex->cmask.size = 0; + return; + } + + /* update colorbuffer state bits */ + rtex->cmask.base_address_reg = rtex->cmask_buffer->gpu_address >> 8; + + if (rscreen->chip_class >= SI) + rtex->cb_color_info |= SI_S_028C70_FAST_CLEAR(1); + else + rtex->cb_color_info |= EG_S_028C70_FAST_CLEAR(1); +} + +static unsigned r600_texture_get_htile_size(struct r600_common_screen *rscreen, + struct r600_texture *rtex) +{ + unsigned cl_width, cl_height, width, height; + unsigned slice_elements, slice_bytes, pipe_interleave_bytes, base_align; + unsigned num_pipes = rscreen->tiling_info.num_channels; + + if (rscreen->chip_class <= EVERGREEN && + rscreen->info.drm_minor < 26) + return 0; + + /* HW bug on R6xx. */ + if (rscreen->chip_class == R600 && + (rtex->surface.level[0].npix_x > 7680 || + rtex->surface.level[0].npix_y > 7680)) + return 0; + + /* HTILE is broken with 1D tiling on old kernels and CIK. */ + if (rscreen->chip_class >= CIK && + rtex->surface.level[0].mode == RADEON_SURF_MODE_1D && + rscreen->info.drm_minor < 38) + return 0; + + switch (num_pipes) { + case 1: + cl_width = 32; + cl_height = 16; + break; + case 2: + cl_width = 32; + cl_height = 32; + break; + case 4: + cl_width = 64; + cl_height = 32; + break; + case 8: + cl_width = 64; + cl_height = 64; + break; + case 16: + cl_width = 128; + cl_height = 64; + break; + default: + assert(0); + return 0; } + + width = align(rtex->surface.npix_x, cl_width * 8); + height = align(rtex->surface.npix_y, cl_height * 8); + + slice_elements = (width * height) / (8 * 8); + slice_bytes = slice_elements * 4; + + pipe_interleave_bytes = rscreen->tiling_info.group_bytes; + base_align = num_pipes * pipe_interleave_bytes; + + return (util_max_layer(&rtex->resource.b.b, 0) + 1) * + align(slice_bytes, base_align); } static void r600_texture_allocate_htile(struct r600_common_screen *rscreen, struct r600_texture *rtex) { - unsigned sw = rtex->surface.level[0].nblk_x * rtex->surface.blk_w; - unsigned sh = rtex->surface.level[0].nblk_y * rtex->surface.blk_h; - unsigned htile_size; - unsigned npipes = rscreen->info.r600_num_tile_pipes; + unsigned htile_size = r600_texture_get_htile_size(rscreen, rtex); - /* XXX also use it for other texture targets */ - if (rscreen->info.drm_minor < 26 || - rtex->resource.b.b.target != PIPE_TEXTURE_2D || - rtex->surface.level[0].nblk_x < 32 || - rtex->surface.level[0].nblk_y < 32) { + if (!htile_size) return; - } - /* this alignment and htile size only apply to linear htile buffer */ - sw = align(sw, 16 << 3); - sh = align(sh, npipes << 3); - htile_size = (sw >> 3) * (sh >> 3) * 4; - /* must be aligned with 2K * npipes */ - htile_size = align(htile_size, (2 << 10) * npipes); - - /* XXX don't allocate it separately */ - rtex->htile = (struct r600_resource*)pipe_buffer_create(&rscreen->b, PIPE_BIND_CUSTOM, - PIPE_USAGE_STATIC, htile_size); - if (rtex->htile == NULL) { + rtex->htile_buffer = (struct r600_resource*) + pipe_buffer_create(&rscreen->b, PIPE_BIND_CUSTOM, + PIPE_USAGE_DEFAULT, htile_size); + if (rtex->htile_buffer == NULL) { /* this is not a fatal error as we can still keep rendering - * without htile buffer - */ - R600_ERR("r600: failed to create bo for htile buffers\n"); + * without htile buffer */ + R600_ERR("Failed to create buffer object for htile buffer.\n"); } else { - r600_screen_clear_buffer(rscreen, &rtex->htile->b.b, 0, htile_size, 0); + r600_screen_clear_buffer(rscreen, &rtex->htile_buffer->b.b, 0, + htile_size, 0, true); } } +/* Common processing for r600_texture_create and r600_texture_from_handle */ static struct r600_texture * r600_texture_create_object(struct pipe_screen *screen, const struct pipe_resource *base, @@ -504,7 +575,6 @@ r600_texture_create_object(struct pipe_screen *screen, struct r600_texture *rtex; struct r600_resource *resource; struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; - int r; rtex = CALLOC_STRUCT(r600_texture); if (rtex == NULL) @@ -521,8 +591,7 @@ r600_texture_create_object(struct pipe_screen *screen, rtex->is_depth = util_format_has_depth(util_format_description(rtex->resource.b.b.format)); rtex->surface = *surface; - r = r600_setup_surface(screen, rtex, pitch_in_bytes_override); - if (r) { + if (r600_setup_surface(screen, rtex, pitch_in_bytes_override)) { FREE(rtex); return NULL; } @@ -532,56 +601,56 @@ r600_texture_create_object(struct pipe_screen *screen, * Applies to R600-Cayman. */ rtex->non_disp_tiling = rtex->is_depth && rtex->surface.level[0].mode >= RADEON_SURF_MODE_1D; - if (base->nr_samples > 1 && !rtex->is_depth && !buf) { - r600_texture_allocate_fmask(rscreen, rtex); - r600_texture_allocate_cmask(rscreen, rtex); - rtex->cmask_buffer = &rtex->resource; - } - - if (!rtex->is_depth && base->nr_samples > 1 && - (!rtex->fmask.size || !rtex->cmask.size)) { - FREE(rtex); - return NULL; - } + if (rtex->is_depth) { + if (!(base->flags & (R600_RESOURCE_FLAG_TRANSFER | + R600_RESOURCE_FLAG_FLUSHED_DEPTH)) && + !(rscreen->debug_flags & DBG_NO_HYPERZ)) { - if (rtex->is_depth && - !(base->flags & (R600_RESOURCE_FLAG_TRANSFER | - R600_RESOURCE_FLAG_FLUSHED_DEPTH)) && - !(rscreen->debug_flags & DBG_NO_HYPERZ)) { - if (rscreen->chip_class >= SI) { - /* XXX implement Hyper-Z for SI. - * Reuse the CMASK allocator, which is almost the same as HTILE. */ - } else { r600_texture_allocate_htile(rscreen, rtex); } + } else { + if (base->nr_samples > 1) { + if (!buf) { + r600_texture_allocate_fmask(rscreen, rtex); + r600_texture_allocate_cmask(rscreen, rtex); + rtex->cmask_buffer = &rtex->resource; + } + if (!rtex->fmask.size || !rtex->cmask.size) { + FREE(rtex); + return NULL; + } + } } /* Now create the backing buffer. */ if (!buf) { - unsigned base_align = rtex->surface.bo_alignment; - unsigned usage = rtex->surface.level[0].mode >= RADEON_SURF_MODE_1D ? - PIPE_USAGE_STATIC : base->usage; - - if (!r600_init_resource(rscreen, resource, rtex->size, base_align, FALSE, usage)) { + if (!r600_init_resource(rscreen, resource, rtex->size, + rtex->surface.bo_alignment, TRUE)) { FREE(rtex); return NULL; } } else { resource->buf = buf; resource->cs_buf = rscreen->ws->buffer_get_cs_handle(buf); - resource->domains = RADEON_DOMAIN_GTT | RADEON_DOMAIN_VRAM; + resource->gpu_address = rscreen->ws->buffer_get_virtual_address(resource->cs_buf); + resource->domains = rscreen->ws->buffer_get_initial_domain(resource->cs_buf); } if (rtex->cmask.size) { /* Initialize the cmask to 0xCC (= compressed state). */ r600_screen_clear_buffer(rscreen, &rtex->cmask_buffer->b.b, - rtex->cmask.offset, rtex->cmask.size, 0xCCCCCCCC); + rtex->cmask.offset, rtex->cmask.size, + 0xCCCCCCCC, true); } + /* Initialize the CMASK base register value. */ + rtex->cmask.base_address_reg = + (rtex->resource.gpu_address + rtex->cmask.offset) >> 8; + if (rscreen->debug_flags & DBG_VM) { - fprintf(stderr, "VM start=0x%"PRIu64" end=0x%"PRIu64" | Texture %ix%ix%i, %i levels, %i samples, %s\n", - r600_resource_va(screen, &rtex->resource.b.b), - r600_resource_va(screen, &rtex->resource.b.b) + rtex->resource.buf->size, + fprintf(stderr, "VM start=0x%"PRIX64" end=0x%"PRIX64" | Texture %ix%ix%i, %i levels, %i samples, %s\n", + rtex->resource.gpu_address, + rtex->resource.gpu_address + rtex->resource.buf->size, base->width0, base->height0, util_max_layer(base, 0)+1, base->last_level+1, base->nr_samples ? base->nr_samples : 1, util_format_short_name(base->format)); } @@ -650,9 +719,15 @@ static unsigned r600_choose_tiling(struct r600_common_screen *rscreen, * Compressed textures must always be tiled. */ if (!(templ->flags & R600_RESOURCE_FLAG_FORCE_TILING) && !util_format_is_compressed(templ->format)) { - /* Tiling doesn't work with the 422 (SUBSAMPLED) formats on R600-Cayman. */ - if (rscreen->chip_class <= CAYMAN && - desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) + /* Not everything can be linear, so we cannot enforce it + * for all textures. */ + if ((rscreen->debug_flags & DBG_NO_TILING) && + (!util_format_is_depth_or_stencil(templ->format) || + !(templ->flags & R600_RESOURCE_FLAG_FLUSHED_DEPTH))) + return RADEON_SURF_MODE_LINEAR_ALIGNED; + + /* Tiling doesn't work with the 422 (SUBSAMPLED) formats on R600+. */ + if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) return RADEON_SURF_MODE_LINEAR_ALIGNED; /* Cursors are linear on SI. @@ -677,7 +752,8 @@ static unsigned r600_choose_tiling(struct r600_common_screen *rscreen, } /* Make small textures 1D tiled. */ - if (templ->width0 <= 16 || templ->height0 <= 16) + if (templ->width0 <= 16 || templ->height0 <= 16 || + (rscreen->debug_flags & DBG_NO_2D_TILING)) return RADEON_SURF_MODE_1D; /* The allocator will switch to 1D if needed. */ @@ -705,9 +781,9 @@ struct pipe_resource *r600_texture_create(struct pipe_screen *screen, 0, NULL, &surface); } -struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen, - const struct pipe_resource *templ, - struct winsys_handle *whandle) +static struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen, + const struct pipe_resource *templ, + struct winsys_handle *whandle) { struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; struct pb_buffer *buf = NULL; @@ -715,6 +791,7 @@ struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen, unsigned array_mode; enum radeon_bo_layout micro, macro; struct radeon_surface surface; + bool scanout; int r; /* Support only 2D textures without mipmaps */ @@ -730,7 +807,7 @@ struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen, &surface.bankw, &surface.bankh, &surface.tile_split, &surface.stencil_tile_split, - &surface.mtilea); + &surface.mtilea, &scanout); if (macro == RADEON_LAYOUT_TILED) array_mode = RADEON_SURF_MODE_2D; @@ -744,8 +821,7 @@ struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen, return NULL; } - /* always set the scanout flags on SI */ - if (rscreen->chip_class >= SI) + if (scanout) surface.flags |= RADEON_SURF_SCANOUT; return (struct pipe_resource *)r600_texture_create_object(screen, templ, @@ -772,7 +848,7 @@ bool r600_init_flushed_depth_texture(struct pipe_context *ctx, resource.array_size = texture->array_size; resource.last_level = texture->last_level; resource.nr_samples = texture->nr_samples; - resource.usage = staging ? PIPE_USAGE_STAGING : PIPE_USAGE_STATIC; + resource.usage = staging ? PIPE_USAGE_STAGING : PIPE_USAGE_DEFAULT; resource.bind = texture->bind & ~PIPE_BIND_DEPTH_STENCIL; resource.flags = texture->flags | R600_RESOURCE_FLAG_FLUSHED_DEPTH; @@ -806,7 +882,7 @@ static void r600_init_temp_resource_from_box(struct pipe_resource *res, res->height0 = box->height; res->depth0 = 1; res->array_size = 1; - res->usage = flags & R600_RESOURCE_FLAG_TRANSFER ? PIPE_USAGE_STAGING : PIPE_USAGE_STATIC; + res->usage = flags & R600_RESOURCE_FLAG_TRANSFER ? PIPE_USAGE_STAGING : PIPE_USAGE_DEFAULT; res->flags = flags; /* We must set the correct texture target and dimensions for a 3D box. */ @@ -850,19 +926,16 @@ static void *r600_texture_transfer_map(struct pipe_context *ctx, * the CPU is much happier reading out of cached system memory * than uncached VRAM. */ - if (rtex->surface.level[level].mode >= RADEON_SURF_MODE_1D) + if (rtex->surface.level[0].mode >= RADEON_SURF_MODE_1D) { use_staging_texture = TRUE; - - /* Untiled buffers in VRAM, which is slow for CPU reads */ - if ((usage & PIPE_TRANSFER_READ) && !(usage & PIPE_TRANSFER_MAP_DIRECTLY) && + } else if ((usage & PIPE_TRANSFER_READ) && !(usage & PIPE_TRANSFER_MAP_DIRECTLY) && (rtex->resource.domains == RADEON_DOMAIN_VRAM)) { + /* Untiled buffers in VRAM, which is slow for CPU reads */ use_staging_texture = TRUE; - } - - /* Use a staging texture for uploads if the underlying BO is busy. */ - if (!(usage & PIPE_TRANSFER_READ) && + } else if (!(usage & PIPE_TRANSFER_READ) && (r600_rings_is_buffer_referenced(rctx, rtex->resource.cs_buf, RADEON_USAGE_READWRITE) || rctx->ws->buffer_is_busy(rtex->resource.buf, RADEON_USAGE_READWRITE))) { + /* Use a staging texture for uploads if the underlying BO is busy. */ use_staging_texture = TRUE; } @@ -941,6 +1014,8 @@ static void *r600_texture_transfer_map(struct pipe_context *ctx, r600_init_temp_resource_from_box(&resource, texture, box, level, R600_RESOURCE_FLAG_TRANSFER); + resource.usage = (usage & PIPE_TRANSFER_READ) ? + PIPE_USAGE_STAGING : PIPE_USAGE_STREAM; /* Create the temporary texture. */ staging = (struct r600_texture*)ctx->screen->resource_create(ctx->screen, &resource); @@ -964,6 +1039,8 @@ static void *r600_texture_transfer_map(struct pipe_context *ctx, if (trans->staging) { buf = trans->staging; + if (!rtex->is_depth && !(usage & PIPE_TRANSFER_READ)) + usage |= PIPE_TRANSFER_UNSYNCHRONIZED; } else { buf = &rtex->resource; } @@ -1013,10 +1090,207 @@ static void r600_texture_transfer_unmap(struct pipe_context *ctx, static const struct u_resource_vtbl r600_texture_vtbl = { - r600_texture_get_handle, /* get_handle */ + NULL, /* get_handle */ r600_texture_destroy, /* resource_destroy */ r600_texture_transfer_map, /* transfer_map */ NULL, /* transfer_flush_region */ r600_texture_transfer_unmap, /* transfer_unmap */ NULL /* transfer_inline_write */ }; + +struct pipe_surface *r600_create_surface_custom(struct pipe_context *pipe, + struct pipe_resource *texture, + const struct pipe_surface *templ, + unsigned width, unsigned height) +{ + struct r600_surface *surface = CALLOC_STRUCT(r600_surface); + + if (surface == NULL) + return NULL; + + assert(templ->u.tex.first_layer <= util_max_layer(texture, templ->u.tex.level)); + assert(templ->u.tex.last_layer <= util_max_layer(texture, templ->u.tex.level)); + + pipe_reference_init(&surface->base.reference, 1); + pipe_resource_reference(&surface->base.texture, texture); + surface->base.context = pipe; + surface->base.format = templ->format; + surface->base.width = width; + surface->base.height = height; + surface->base.u = templ->u; + return &surface->base; +} + +static struct pipe_surface *r600_create_surface(struct pipe_context *pipe, + struct pipe_resource *tex, + const struct pipe_surface *templ) +{ + unsigned level = templ->u.tex.level; + + return r600_create_surface_custom(pipe, tex, templ, + u_minify(tex->width0, level), + u_minify(tex->height0, level)); +} + +static void r600_surface_destroy(struct pipe_context *pipe, + struct pipe_surface *surface) +{ + struct r600_surface *surf = (struct r600_surface*)surface; + pipe_resource_reference((struct pipe_resource**)&surf->cb_buffer_fmask, NULL); + pipe_resource_reference((struct pipe_resource**)&surf->cb_buffer_cmask, NULL); + pipe_resource_reference(&surface->texture, NULL); + FREE(surface); +} + +unsigned r600_translate_colorswap(enum pipe_format format) +{ + const struct util_format_description *desc = util_format_description(format); + +#define HAS_SWIZZLE(chan,swz) (desc->swizzle[chan] == UTIL_FORMAT_SWIZZLE_##swz) + + if (format == PIPE_FORMAT_R11G11B10_FLOAT) /* isn't plain */ + return V_0280A0_SWAP_STD; + + if (desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) + return ~0U; + + switch (desc->nr_channels) { + case 1: + if (HAS_SWIZZLE(0,X)) + return V_0280A0_SWAP_STD; /* X___ */ + else if (HAS_SWIZZLE(3,X)) + return V_0280A0_SWAP_ALT_REV; /* ___X */ + break; + case 2: + if ((HAS_SWIZZLE(0,X) && HAS_SWIZZLE(1,Y)) || + (HAS_SWIZZLE(0,X) && HAS_SWIZZLE(1,NONE)) || + (HAS_SWIZZLE(0,NONE) && HAS_SWIZZLE(1,Y))) + return V_0280A0_SWAP_STD; /* XY__ */ + else if ((HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(1,X)) || + (HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(1,NONE)) || + (HAS_SWIZZLE(0,NONE) && HAS_SWIZZLE(1,X))) + return V_0280A0_SWAP_STD_REV; /* YX__ */ + else if (HAS_SWIZZLE(0,X) && HAS_SWIZZLE(3,Y)) + return V_0280A0_SWAP_ALT; /* X__Y */ + else if (HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(3,X)) + return V_0280A0_SWAP_ALT_REV; /* Y__X */ + break; + case 3: + if (HAS_SWIZZLE(0,X)) + return V_0280A0_SWAP_STD; /* XYZ */ + else if (HAS_SWIZZLE(0,Z)) + return V_0280A0_SWAP_STD_REV; /* ZYX */ + break; + case 4: + /* check the middle channels, the 1st and 4th channel can be NONE */ + if (HAS_SWIZZLE(1,Y) && HAS_SWIZZLE(2,Z)) + return V_0280A0_SWAP_STD; /* XYZW */ + else if (HAS_SWIZZLE(1,Z) && HAS_SWIZZLE(2,Y)) + return V_0280A0_SWAP_STD_REV; /* WZYX */ + else if (HAS_SWIZZLE(1,Y) && HAS_SWIZZLE(2,X)) + return V_0280A0_SWAP_ALT; /* ZYXW */ + else if (HAS_SWIZZLE(1,X) && HAS_SWIZZLE(2,Y)) + return V_0280A0_SWAP_ALT_REV; /* WXYZ */ + break; + } + return ~0U; +} + +static void evergreen_set_clear_color(struct r600_texture *rtex, + enum pipe_format surface_format, + const union pipe_color_union *color) +{ + union util_color uc; + + memset(&uc, 0, sizeof(uc)); + + if (util_format_is_pure_uint(surface_format)) { + util_format_write_4ui(surface_format, color->ui, 0, &uc, 0, 0, 0, 1, 1); + } else if (util_format_is_pure_sint(surface_format)) { + util_format_write_4i(surface_format, color->i, 0, &uc, 0, 0, 0, 1, 1); + } else { + util_pack_color(color->f, surface_format, &uc); + } + + memcpy(rtex->color_clear_value, &uc, 2 * sizeof(uint32_t)); +} + +void evergreen_do_fast_color_clear(struct r600_common_context *rctx, + struct pipe_framebuffer_state *fb, + struct r600_atom *fb_state, + unsigned *buffers, + const union pipe_color_union *color) +{ + int i; + + if (rctx->current_render_cond) + return; + + for (i = 0; i < fb->nr_cbufs; i++) { + struct r600_texture *tex; + unsigned clear_bit = PIPE_CLEAR_COLOR0 << i; + + if (!fb->cbufs[i]) + continue; + + /* if this colorbuffer is not being cleared */ + if (!(*buffers & clear_bit)) + continue; + + tex = (struct r600_texture *)fb->cbufs[i]->texture; + + /* 128-bit formats are unusupported */ + if (util_format_get_blocksizebits(fb->cbufs[i]->format) > 64) { + continue; + } + + /* the clear is allowed if all layers are bound */ + if (fb->cbufs[i]->u.tex.first_layer != 0 || + fb->cbufs[i]->u.tex.last_layer != util_max_layer(&tex->resource.b.b, 0)) { + continue; + } + + /* cannot clear mipmapped textures */ + if (fb->cbufs[i]->texture->last_level != 0) { + continue; + } + + /* only supported on tiled surfaces */ + if (tex->surface.level[0].mode < RADEON_SURF_MODE_1D) { + continue; + } + + /* fast color clear with 1D tiling doesn't work on old kernels and CIK */ + if (tex->surface.level[0].mode == RADEON_SURF_MODE_1D && + rctx->chip_class >= CIK && rctx->screen->info.drm_minor < 38) { + continue; + } + + /* ensure CMASK is enabled */ + r600_texture_alloc_cmask_separate(rctx->screen, tex); + if (tex->cmask.size == 0) { + continue; + } + + /* Do the fast clear. */ + evergreen_set_clear_color(tex, fb->cbufs[i]->format, color); + rctx->clear_buffer(&rctx->b, &tex->cmask_buffer->b.b, + tex->cmask.offset, tex->cmask.size, 0, true); + + tex->dirty_level_mask |= 1 << fb->cbufs[i]->u.tex.level; + fb_state->dirty = true; + *buffers &= ~clear_bit; + } +} + +void r600_init_screen_texture_functions(struct r600_common_screen *rscreen) +{ + rscreen->b.resource_from_handle = r600_texture_from_handle; + rscreen->b.resource_get_handle = r600_texture_get_handle; +} + +void r600_init_context_texture_functions(struct r600_common_context *rctx) +{ + rctx->b.create_surface = r600_create_surface; + rctx->b.surface_destroy = r600_surface_destroy; +}