1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2010 Jerome Glisse <glisse@freedesktop.org> 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub 8bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom 9bf215546Sopenharmony_ci * the Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci * Authors: 24bf215546Sopenharmony_ci * Jerome Glisse 25bf215546Sopenharmony_ci * Corbin Simpson 26bf215546Sopenharmony_ci */ 27bf215546Sopenharmony_ci#include "r600_pipe_common.h" 28bf215546Sopenharmony_ci#include "r600_cs.h" 29bf215546Sopenharmony_ci#include "r600_query.h" 30bf215546Sopenharmony_ci#include "util/format/u_format.h" 31bf215546Sopenharmony_ci#include "util/u_log.h" 32bf215546Sopenharmony_ci#include "util/u_memory.h" 33bf215546Sopenharmony_ci#include "util/u_pack_color.h" 34bf215546Sopenharmony_ci#include "util/u_surface.h" 35bf215546Sopenharmony_ci#include "util/os_time.h" 36bf215546Sopenharmony_ci#include "frontend/winsys_handle.h" 37bf215546Sopenharmony_ci#include <errno.h> 38bf215546Sopenharmony_ci#include <inttypes.h> 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_cistatic void r600_texture_discard_cmask(struct r600_common_screen *rscreen, 41bf215546Sopenharmony_ci struct r600_texture *rtex); 42bf215546Sopenharmony_cistatic enum radeon_surf_mode 43bf215546Sopenharmony_cir600_choose_tiling(struct r600_common_screen *rscreen, 44bf215546Sopenharmony_ci const struct pipe_resource *templ); 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_cibool r600_prepare_for_dma_blit(struct r600_common_context *rctx, 48bf215546Sopenharmony_ci struct r600_texture *rdst, 49bf215546Sopenharmony_ci unsigned dst_level, unsigned dstx, 50bf215546Sopenharmony_ci unsigned dsty, unsigned dstz, 51bf215546Sopenharmony_ci struct r600_texture *rsrc, 52bf215546Sopenharmony_ci unsigned src_level, 53bf215546Sopenharmony_ci const struct pipe_box *src_box) 54bf215546Sopenharmony_ci{ 55bf215546Sopenharmony_ci if (!rctx->dma.cs.priv) 56bf215546Sopenharmony_ci return false; 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci if (rdst->surface.bpe != rsrc->surface.bpe) 59bf215546Sopenharmony_ci return false; 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_ci /* MSAA: Blits don't exist in the real world. */ 62bf215546Sopenharmony_ci if (rsrc->resource.b.b.nr_samples > 1 || 63bf215546Sopenharmony_ci rdst->resource.b.b.nr_samples > 1) 64bf215546Sopenharmony_ci return false; 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci /* Depth-stencil surfaces: 67bf215546Sopenharmony_ci * When dst is linear, the DB->CB copy preserves HTILE. 68bf215546Sopenharmony_ci * When dst is tiled, the 3D path must be used to update HTILE. 69bf215546Sopenharmony_ci */ 70bf215546Sopenharmony_ci if (rsrc->is_depth || rdst->is_depth) 71bf215546Sopenharmony_ci return false; 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci /* CMASK as: 74bf215546Sopenharmony_ci * src: Both texture and SDMA paths need decompression. Use SDMA. 75bf215546Sopenharmony_ci * dst: If overwriting the whole texture, discard CMASK and use 76bf215546Sopenharmony_ci * SDMA. Otherwise, use the 3D path. 77bf215546Sopenharmony_ci */ 78bf215546Sopenharmony_ci if (rdst->cmask.size && rdst->dirty_level_mask & (1 << dst_level)) { 79bf215546Sopenharmony_ci /* The CMASK clear is only enabled for the first level. */ 80bf215546Sopenharmony_ci assert(dst_level == 0); 81bf215546Sopenharmony_ci if (!util_texrange_covers_whole_level(&rdst->resource.b.b, dst_level, 82bf215546Sopenharmony_ci dstx, dsty, dstz, src_box->width, 83bf215546Sopenharmony_ci src_box->height, src_box->depth)) 84bf215546Sopenharmony_ci return false; 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci r600_texture_discard_cmask(rctx->screen, rdst); 87bf215546Sopenharmony_ci } 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci /* All requirements are met. Prepare textures for SDMA. */ 90bf215546Sopenharmony_ci if (rsrc->cmask.size && rsrc->dirty_level_mask & (1 << src_level)) 91bf215546Sopenharmony_ci rctx->b.flush_resource(&rctx->b, &rsrc->resource.b.b); 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci assert(!(rsrc->dirty_level_mask & (1 << src_level))); 94bf215546Sopenharmony_ci assert(!(rdst->dirty_level_mask & (1 << dst_level))); 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_ci return true; 97bf215546Sopenharmony_ci} 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci/* Same as resource_copy_region, except that both upsampling and downsampling are allowed. */ 100bf215546Sopenharmony_cistatic void r600_copy_region_with_blit(struct pipe_context *pipe, 101bf215546Sopenharmony_ci struct pipe_resource *dst, 102bf215546Sopenharmony_ci unsigned dst_level, 103bf215546Sopenharmony_ci unsigned dstx, unsigned dsty, unsigned dstz, 104bf215546Sopenharmony_ci struct pipe_resource *src, 105bf215546Sopenharmony_ci unsigned src_level, 106bf215546Sopenharmony_ci const struct pipe_box *src_box) 107bf215546Sopenharmony_ci{ 108bf215546Sopenharmony_ci struct pipe_blit_info blit; 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci memset(&blit, 0, sizeof(blit)); 111bf215546Sopenharmony_ci blit.src.resource = src; 112bf215546Sopenharmony_ci blit.src.format = src->format; 113bf215546Sopenharmony_ci blit.src.level = src_level; 114bf215546Sopenharmony_ci blit.src.box = *src_box; 115bf215546Sopenharmony_ci blit.dst.resource = dst; 116bf215546Sopenharmony_ci blit.dst.format = dst->format; 117bf215546Sopenharmony_ci blit.dst.level = dst_level; 118bf215546Sopenharmony_ci blit.dst.box.x = dstx; 119bf215546Sopenharmony_ci blit.dst.box.y = dsty; 120bf215546Sopenharmony_ci blit.dst.box.z = dstz; 121bf215546Sopenharmony_ci blit.dst.box.width = src_box->width; 122bf215546Sopenharmony_ci blit.dst.box.height = src_box->height; 123bf215546Sopenharmony_ci blit.dst.box.depth = src_box->depth; 124bf215546Sopenharmony_ci blit.mask = util_format_get_mask(src->format) & 125bf215546Sopenharmony_ci util_format_get_mask(dst->format); 126bf215546Sopenharmony_ci blit.filter = PIPE_TEX_FILTER_NEAREST; 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ci if (blit.mask) { 129bf215546Sopenharmony_ci pipe->blit(pipe, &blit); 130bf215546Sopenharmony_ci } 131bf215546Sopenharmony_ci} 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci/* Copy from a full GPU texture to a transfer's staging one. */ 134bf215546Sopenharmony_cistatic void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer) 135bf215546Sopenharmony_ci{ 136bf215546Sopenharmony_ci struct r600_common_context *rctx = (struct r600_common_context*)ctx; 137bf215546Sopenharmony_ci struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer; 138bf215546Sopenharmony_ci struct pipe_resource *dst = &rtransfer->staging->b.b; 139bf215546Sopenharmony_ci struct pipe_resource *src = transfer->resource; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci if (src->nr_samples > 1) { 142bf215546Sopenharmony_ci r600_copy_region_with_blit(ctx, dst, 0, 0, 0, 0, 143bf215546Sopenharmony_ci src, transfer->level, &transfer->box); 144bf215546Sopenharmony_ci return; 145bf215546Sopenharmony_ci } 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci rctx->dma_copy(ctx, dst, 0, 0, 0, 0, src, transfer->level, 148bf215546Sopenharmony_ci &transfer->box); 149bf215546Sopenharmony_ci} 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci/* Copy from a transfer's staging texture to a full GPU one. */ 152bf215546Sopenharmony_cistatic void r600_copy_from_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer) 153bf215546Sopenharmony_ci{ 154bf215546Sopenharmony_ci struct r600_common_context *rctx = (struct r600_common_context*)ctx; 155bf215546Sopenharmony_ci struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer; 156bf215546Sopenharmony_ci struct pipe_resource *dst = transfer->resource; 157bf215546Sopenharmony_ci struct pipe_resource *src = &rtransfer->staging->b.b; 158bf215546Sopenharmony_ci struct pipe_box sbox; 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci u_box_3d(0, 0, 0, transfer->box.width, transfer->box.height, transfer->box.depth, &sbox); 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci if (dst->nr_samples > 1) { 163bf215546Sopenharmony_ci r600_copy_region_with_blit(ctx, dst, transfer->level, 164bf215546Sopenharmony_ci transfer->box.x, transfer->box.y, transfer->box.z, 165bf215546Sopenharmony_ci src, 0, &sbox); 166bf215546Sopenharmony_ci return; 167bf215546Sopenharmony_ci } 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci rctx->dma_copy(ctx, dst, transfer->level, 170bf215546Sopenharmony_ci transfer->box.x, transfer->box.y, transfer->box.z, 171bf215546Sopenharmony_ci src, 0, &sbox); 172bf215546Sopenharmony_ci} 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_cistatic unsigned r600_texture_get_offset(struct r600_common_screen *rscreen, 175bf215546Sopenharmony_ci struct r600_texture *rtex, unsigned level, 176bf215546Sopenharmony_ci const struct pipe_box *box, 177bf215546Sopenharmony_ci unsigned *stride, 178bf215546Sopenharmony_ci unsigned *layer_stride) 179bf215546Sopenharmony_ci{ 180bf215546Sopenharmony_ci *stride = rtex->surface.u.legacy.level[level].nblk_x * 181bf215546Sopenharmony_ci rtex->surface.bpe; 182bf215546Sopenharmony_ci assert((uint64_t)rtex->surface.u.legacy.level[level].slice_size_dw * 4 <= UINT_MAX); 183bf215546Sopenharmony_ci *layer_stride = (uint64_t)rtex->surface.u.legacy.level[level].slice_size_dw * 4; 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci if (!box) 186bf215546Sopenharmony_ci return (uint64_t)rtex->surface.u.legacy.level[level].offset_256B * 256; 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci /* Each texture is an array of mipmap levels. Each level is 189bf215546Sopenharmony_ci * an array of slices. */ 190bf215546Sopenharmony_ci return (uint64_t)rtex->surface.u.legacy.level[level].offset_256B * 256 + 191bf215546Sopenharmony_ci box->z * (uint64_t)rtex->surface.u.legacy.level[level].slice_size_dw * 4 + 192bf215546Sopenharmony_ci (box->y / rtex->surface.blk_h * 193bf215546Sopenharmony_ci rtex->surface.u.legacy.level[level].nblk_x + 194bf215546Sopenharmony_ci box->x / rtex->surface.blk_w) * rtex->surface.bpe; 195bf215546Sopenharmony_ci} 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_cistatic int r600_init_surface(struct r600_common_screen *rscreen, 198bf215546Sopenharmony_ci struct radeon_surf *surface, 199bf215546Sopenharmony_ci const struct pipe_resource *ptex, 200bf215546Sopenharmony_ci enum radeon_surf_mode array_mode, 201bf215546Sopenharmony_ci unsigned pitch_in_bytes_override, 202bf215546Sopenharmony_ci unsigned offset, 203bf215546Sopenharmony_ci bool is_imported, 204bf215546Sopenharmony_ci bool is_scanout, 205bf215546Sopenharmony_ci bool is_flushed_depth) 206bf215546Sopenharmony_ci{ 207bf215546Sopenharmony_ci const struct util_format_description *desc = 208bf215546Sopenharmony_ci util_format_description(ptex->format); 209bf215546Sopenharmony_ci bool is_depth, is_stencil; 210bf215546Sopenharmony_ci int r; 211bf215546Sopenharmony_ci unsigned i, bpe, flags = 0; 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci is_depth = util_format_has_depth(desc); 214bf215546Sopenharmony_ci is_stencil = util_format_has_stencil(desc); 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci if (rscreen->gfx_level >= EVERGREEN && !is_flushed_depth && 217bf215546Sopenharmony_ci ptex->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) { 218bf215546Sopenharmony_ci bpe = 4; /* stencil is allocated separately on evergreen */ 219bf215546Sopenharmony_ci } else { 220bf215546Sopenharmony_ci bpe = util_format_get_blocksize(ptex->format); 221bf215546Sopenharmony_ci assert(util_is_power_of_two_or_zero(bpe)); 222bf215546Sopenharmony_ci } 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci if (!is_flushed_depth && is_depth) { 225bf215546Sopenharmony_ci flags |= RADEON_SURF_ZBUFFER; 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci if (is_stencil) 228bf215546Sopenharmony_ci flags |= RADEON_SURF_SBUFFER; 229bf215546Sopenharmony_ci } 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci if (ptex->bind & PIPE_BIND_SCANOUT || is_scanout) { 232bf215546Sopenharmony_ci /* This should catch bugs in gallium users setting incorrect flags. */ 233bf215546Sopenharmony_ci assert(ptex->nr_samples <= 1 && 234bf215546Sopenharmony_ci ptex->array_size == 1 && 235bf215546Sopenharmony_ci ptex->depth0 == 1 && 236bf215546Sopenharmony_ci ptex->last_level == 0 && 237bf215546Sopenharmony_ci !(flags & RADEON_SURF_Z_OR_SBUFFER)); 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci flags |= RADEON_SURF_SCANOUT; 240bf215546Sopenharmony_ci } 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci if (ptex->bind & PIPE_BIND_SHARED) 243bf215546Sopenharmony_ci flags |= RADEON_SURF_SHAREABLE; 244bf215546Sopenharmony_ci if (is_imported) 245bf215546Sopenharmony_ci flags |= RADEON_SURF_IMPORTED | RADEON_SURF_SHAREABLE; 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_ci r = rscreen->ws->surface_init(rscreen->ws, ptex, 248bf215546Sopenharmony_ci flags, bpe, array_mode, surface); 249bf215546Sopenharmony_ci if (r) { 250bf215546Sopenharmony_ci return r; 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci 253bf215546Sopenharmony_ci if (pitch_in_bytes_override && 254bf215546Sopenharmony_ci pitch_in_bytes_override != surface->u.legacy.level[0].nblk_x * bpe) { 255bf215546Sopenharmony_ci /* old ddx on evergreen over estimate alignment for 1d, only 1 level 256bf215546Sopenharmony_ci * for those 257bf215546Sopenharmony_ci */ 258bf215546Sopenharmony_ci surface->u.legacy.level[0].nblk_x = pitch_in_bytes_override / bpe; 259bf215546Sopenharmony_ci surface->u.legacy.level[0].slice_size_dw = 260bf215546Sopenharmony_ci ((uint64_t)pitch_in_bytes_override * surface->u.legacy.level[0].nblk_y) / 4; 261bf215546Sopenharmony_ci } 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci if (offset) { 264bf215546Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(surface->u.legacy.level); ++i) 265bf215546Sopenharmony_ci surface->u.legacy.level[i].offset_256B += offset / 256; 266bf215546Sopenharmony_ci } 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci return 0; 269bf215546Sopenharmony_ci} 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_cistatic void r600_texture_init_metadata(struct r600_common_screen *rscreen, 272bf215546Sopenharmony_ci struct r600_texture *rtex, 273bf215546Sopenharmony_ci struct radeon_bo_metadata *metadata) 274bf215546Sopenharmony_ci{ 275bf215546Sopenharmony_ci struct radeon_surf *surface = &rtex->surface; 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci memset(metadata, 0, sizeof(*metadata)); 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci metadata->u.legacy.microtile = surface->u.legacy.level[0].mode >= RADEON_SURF_MODE_1D ? 280bf215546Sopenharmony_ci RADEON_LAYOUT_TILED : RADEON_LAYOUT_LINEAR; 281bf215546Sopenharmony_ci metadata->u.legacy.macrotile = surface->u.legacy.level[0].mode >= RADEON_SURF_MODE_2D ? 282bf215546Sopenharmony_ci RADEON_LAYOUT_TILED : RADEON_LAYOUT_LINEAR; 283bf215546Sopenharmony_ci metadata->u.legacy.pipe_config = surface->u.legacy.pipe_config; 284bf215546Sopenharmony_ci metadata->u.legacy.bankw = surface->u.legacy.bankw; 285bf215546Sopenharmony_ci metadata->u.legacy.bankh = surface->u.legacy.bankh; 286bf215546Sopenharmony_ci metadata->u.legacy.tile_split = surface->u.legacy.tile_split; 287bf215546Sopenharmony_ci metadata->u.legacy.mtilea = surface->u.legacy.mtilea; 288bf215546Sopenharmony_ci metadata->u.legacy.num_banks = surface->u.legacy.num_banks; 289bf215546Sopenharmony_ci metadata->u.legacy.stride = surface->u.legacy.level[0].nblk_x * surface->bpe; 290bf215546Sopenharmony_ci metadata->u.legacy.scanout = (surface->flags & RADEON_SURF_SCANOUT) != 0; 291bf215546Sopenharmony_ci} 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_cistatic void r600_surface_import_metadata(struct r600_common_screen *rscreen, 294bf215546Sopenharmony_ci struct radeon_surf *surf, 295bf215546Sopenharmony_ci struct radeon_bo_metadata *metadata, 296bf215546Sopenharmony_ci enum radeon_surf_mode *array_mode, 297bf215546Sopenharmony_ci bool *is_scanout) 298bf215546Sopenharmony_ci{ 299bf215546Sopenharmony_ci surf->u.legacy.pipe_config = metadata->u.legacy.pipe_config; 300bf215546Sopenharmony_ci surf->u.legacy.bankw = metadata->u.legacy.bankw; 301bf215546Sopenharmony_ci surf->u.legacy.bankh = metadata->u.legacy.bankh; 302bf215546Sopenharmony_ci surf->u.legacy.tile_split = metadata->u.legacy.tile_split; 303bf215546Sopenharmony_ci surf->u.legacy.mtilea = metadata->u.legacy.mtilea; 304bf215546Sopenharmony_ci surf->u.legacy.num_banks = metadata->u.legacy.num_banks; 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_ci if (metadata->u.legacy.macrotile == RADEON_LAYOUT_TILED) 307bf215546Sopenharmony_ci *array_mode = RADEON_SURF_MODE_2D; 308bf215546Sopenharmony_ci else if (metadata->u.legacy.microtile == RADEON_LAYOUT_TILED) 309bf215546Sopenharmony_ci *array_mode = RADEON_SURF_MODE_1D; 310bf215546Sopenharmony_ci else 311bf215546Sopenharmony_ci *array_mode = RADEON_SURF_MODE_LINEAR_ALIGNED; 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci *is_scanout = metadata->u.legacy.scanout; 314bf215546Sopenharmony_ci} 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_cistatic void r600_eliminate_fast_color_clear(struct r600_common_context *rctx, 317bf215546Sopenharmony_ci struct r600_texture *rtex) 318bf215546Sopenharmony_ci{ 319bf215546Sopenharmony_ci struct r600_common_screen *rscreen = rctx->screen; 320bf215546Sopenharmony_ci struct pipe_context *ctx = &rctx->b; 321bf215546Sopenharmony_ci 322bf215546Sopenharmony_ci if (ctx == rscreen->aux_context) 323bf215546Sopenharmony_ci mtx_lock(&rscreen->aux_context_lock); 324bf215546Sopenharmony_ci 325bf215546Sopenharmony_ci ctx->flush_resource(ctx, &rtex->resource.b.b); 326bf215546Sopenharmony_ci ctx->flush(ctx, NULL, 0); 327bf215546Sopenharmony_ci 328bf215546Sopenharmony_ci if (ctx == rscreen->aux_context) 329bf215546Sopenharmony_ci mtx_unlock(&rscreen->aux_context_lock); 330bf215546Sopenharmony_ci} 331bf215546Sopenharmony_ci 332bf215546Sopenharmony_cistatic void r600_texture_discard_cmask(struct r600_common_screen *rscreen, 333bf215546Sopenharmony_ci struct r600_texture *rtex) 334bf215546Sopenharmony_ci{ 335bf215546Sopenharmony_ci if (!rtex->cmask.size) 336bf215546Sopenharmony_ci return; 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci assert(rtex->resource.b.b.nr_samples <= 1); 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ci /* Disable CMASK. */ 341bf215546Sopenharmony_ci memset(&rtex->cmask, 0, sizeof(rtex->cmask)); 342bf215546Sopenharmony_ci rtex->cmask.base_address_reg = rtex->resource.gpu_address >> 8; 343bf215546Sopenharmony_ci rtex->dirty_level_mask = 0; 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci rtex->cb_color_info &= ~EG_S_028C70_FAST_CLEAR(1); 346bf215546Sopenharmony_ci 347bf215546Sopenharmony_ci if (rtex->cmask_buffer != &rtex->resource) 348bf215546Sopenharmony_ci r600_resource_reference(&rtex->cmask_buffer, NULL); 349bf215546Sopenharmony_ci 350bf215546Sopenharmony_ci /* Notify all contexts about the change. */ 351bf215546Sopenharmony_ci p_atomic_inc(&rscreen->dirty_tex_counter); 352bf215546Sopenharmony_ci p_atomic_inc(&rscreen->compressed_colortex_counter); 353bf215546Sopenharmony_ci} 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_cistatic void r600_reallocate_texture_inplace(struct r600_common_context *rctx, 356bf215546Sopenharmony_ci struct r600_texture *rtex, 357bf215546Sopenharmony_ci unsigned new_bind_flag, 358bf215546Sopenharmony_ci bool invalidate_storage) 359bf215546Sopenharmony_ci{ 360bf215546Sopenharmony_ci struct pipe_screen *screen = rctx->b.screen; 361bf215546Sopenharmony_ci struct r600_texture *new_tex; 362bf215546Sopenharmony_ci struct pipe_resource templ = rtex->resource.b.b; 363bf215546Sopenharmony_ci unsigned i; 364bf215546Sopenharmony_ci 365bf215546Sopenharmony_ci templ.bind |= new_bind_flag; 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_ci /* r600g doesn't react to dirty_tex_descriptor_counter */ 368bf215546Sopenharmony_ci if (rctx->gfx_level < GFX6) 369bf215546Sopenharmony_ci return; 370bf215546Sopenharmony_ci 371bf215546Sopenharmony_ci if (rtex->resource.b.is_shared) 372bf215546Sopenharmony_ci return; 373bf215546Sopenharmony_ci 374bf215546Sopenharmony_ci if (new_bind_flag == PIPE_BIND_LINEAR) { 375bf215546Sopenharmony_ci if (rtex->surface.is_linear) 376bf215546Sopenharmony_ci return; 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_ci /* This fails with MSAA, depth, and compressed textures. */ 379bf215546Sopenharmony_ci if (r600_choose_tiling(rctx->screen, &templ) != 380bf215546Sopenharmony_ci RADEON_SURF_MODE_LINEAR_ALIGNED) 381bf215546Sopenharmony_ci return; 382bf215546Sopenharmony_ci } 383bf215546Sopenharmony_ci 384bf215546Sopenharmony_ci new_tex = (struct r600_texture*)screen->resource_create(screen, &templ); 385bf215546Sopenharmony_ci if (!new_tex) 386bf215546Sopenharmony_ci return; 387bf215546Sopenharmony_ci 388bf215546Sopenharmony_ci /* Copy the pixels to the new texture. */ 389bf215546Sopenharmony_ci if (!invalidate_storage) { 390bf215546Sopenharmony_ci for (i = 0; i <= templ.last_level; i++) { 391bf215546Sopenharmony_ci struct pipe_box box; 392bf215546Sopenharmony_ci 393bf215546Sopenharmony_ci u_box_3d(0, 0, 0, 394bf215546Sopenharmony_ci u_minify(templ.width0, i), u_minify(templ.height0, i), 395bf215546Sopenharmony_ci util_num_layers(&templ, i), &box); 396bf215546Sopenharmony_ci 397bf215546Sopenharmony_ci rctx->dma_copy(&rctx->b, &new_tex->resource.b.b, i, 0, 0, 0, 398bf215546Sopenharmony_ci &rtex->resource.b.b, i, &box); 399bf215546Sopenharmony_ci } 400bf215546Sopenharmony_ci } 401bf215546Sopenharmony_ci 402bf215546Sopenharmony_ci if (new_bind_flag == PIPE_BIND_LINEAR) { 403bf215546Sopenharmony_ci r600_texture_discard_cmask(rctx->screen, rtex); 404bf215546Sopenharmony_ci } 405bf215546Sopenharmony_ci 406bf215546Sopenharmony_ci /* Replace the structure fields of rtex. */ 407bf215546Sopenharmony_ci rtex->resource.b.b.bind = templ.bind; 408bf215546Sopenharmony_ci pb_reference(&rtex->resource.buf, new_tex->resource.buf); 409bf215546Sopenharmony_ci rtex->resource.gpu_address = new_tex->resource.gpu_address; 410bf215546Sopenharmony_ci rtex->resource.vram_usage = new_tex->resource.vram_usage; 411bf215546Sopenharmony_ci rtex->resource.gart_usage = new_tex->resource.gart_usage; 412bf215546Sopenharmony_ci rtex->resource.bo_size = new_tex->resource.bo_size; 413bf215546Sopenharmony_ci rtex->resource.bo_alignment = new_tex->resource.bo_alignment; 414bf215546Sopenharmony_ci rtex->resource.domains = new_tex->resource.domains; 415bf215546Sopenharmony_ci rtex->resource.flags = new_tex->resource.flags; 416bf215546Sopenharmony_ci rtex->size = new_tex->size; 417bf215546Sopenharmony_ci rtex->db_render_format = new_tex->db_render_format; 418bf215546Sopenharmony_ci rtex->db_compatible = new_tex->db_compatible; 419bf215546Sopenharmony_ci rtex->can_sample_z = new_tex->can_sample_z; 420bf215546Sopenharmony_ci rtex->can_sample_s = new_tex->can_sample_s; 421bf215546Sopenharmony_ci rtex->surface = new_tex->surface; 422bf215546Sopenharmony_ci rtex->fmask = new_tex->fmask; 423bf215546Sopenharmony_ci rtex->cmask = new_tex->cmask; 424bf215546Sopenharmony_ci rtex->cb_color_info = new_tex->cb_color_info; 425bf215546Sopenharmony_ci rtex->last_msaa_resolve_target_micro_mode = new_tex->last_msaa_resolve_target_micro_mode; 426bf215546Sopenharmony_ci rtex->htile_offset = new_tex->htile_offset; 427bf215546Sopenharmony_ci rtex->depth_cleared = new_tex->depth_cleared; 428bf215546Sopenharmony_ci rtex->stencil_cleared = new_tex->stencil_cleared; 429bf215546Sopenharmony_ci rtex->non_disp_tiling = new_tex->non_disp_tiling; 430bf215546Sopenharmony_ci rtex->framebuffers_bound = new_tex->framebuffers_bound; 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci if (new_bind_flag == PIPE_BIND_LINEAR) { 433bf215546Sopenharmony_ci assert(!rtex->htile_offset); 434bf215546Sopenharmony_ci assert(!rtex->cmask.size); 435bf215546Sopenharmony_ci assert(!rtex->fmask.size); 436bf215546Sopenharmony_ci assert(!rtex->is_depth); 437bf215546Sopenharmony_ci } 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ci r600_texture_reference(&new_tex, NULL); 440bf215546Sopenharmony_ci 441bf215546Sopenharmony_ci p_atomic_inc(&rctx->screen->dirty_tex_counter); 442bf215546Sopenharmony_ci} 443bf215546Sopenharmony_ci 444bf215546Sopenharmony_cistatic void r600_texture_get_info(struct pipe_screen* screen, 445bf215546Sopenharmony_ci struct pipe_resource *resource, 446bf215546Sopenharmony_ci unsigned *pstride, 447bf215546Sopenharmony_ci unsigned *poffset) 448bf215546Sopenharmony_ci{ 449bf215546Sopenharmony_ci struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; 450bf215546Sopenharmony_ci struct r600_texture *rtex = (struct r600_texture*)resource; 451bf215546Sopenharmony_ci unsigned stride = 0; 452bf215546Sopenharmony_ci unsigned offset = 0; 453bf215546Sopenharmony_ci 454bf215546Sopenharmony_ci if (!rscreen || !rtex) 455bf215546Sopenharmony_ci return; 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_ci if (resource->target != PIPE_BUFFER) { 458bf215546Sopenharmony_ci offset = (uint64_t)rtex->surface.u.legacy.level[0].offset_256B * 256; 459bf215546Sopenharmony_ci stride = rtex->surface.u.legacy.level[0].nblk_x * 460bf215546Sopenharmony_ci rtex->surface.bpe; 461bf215546Sopenharmony_ci } 462bf215546Sopenharmony_ci 463bf215546Sopenharmony_ci if (pstride) 464bf215546Sopenharmony_ci *pstride = stride; 465bf215546Sopenharmony_ci 466bf215546Sopenharmony_ci if (poffset) 467bf215546Sopenharmony_ci *poffset = offset; 468bf215546Sopenharmony_ci} 469bf215546Sopenharmony_ci 470bf215546Sopenharmony_cistatic bool r600_texture_get_handle(struct pipe_screen* screen, 471bf215546Sopenharmony_ci struct pipe_context *ctx, 472bf215546Sopenharmony_ci struct pipe_resource *resource, 473bf215546Sopenharmony_ci struct winsys_handle *whandle, 474bf215546Sopenharmony_ci unsigned usage) 475bf215546Sopenharmony_ci{ 476bf215546Sopenharmony_ci struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; 477bf215546Sopenharmony_ci struct r600_common_context *rctx; 478bf215546Sopenharmony_ci struct r600_resource *res = (struct r600_resource*)resource; 479bf215546Sopenharmony_ci struct r600_texture *rtex = (struct r600_texture*)resource; 480bf215546Sopenharmony_ci struct radeon_bo_metadata metadata; 481bf215546Sopenharmony_ci bool update_metadata = false; 482bf215546Sopenharmony_ci unsigned stride, offset, slice_size; 483bf215546Sopenharmony_ci 484bf215546Sopenharmony_ci ctx = threaded_context_unwrap_sync(ctx); 485bf215546Sopenharmony_ci rctx = (struct r600_common_context*)(ctx ? ctx : rscreen->aux_context); 486bf215546Sopenharmony_ci 487bf215546Sopenharmony_ci if (resource->target != PIPE_BUFFER) { 488bf215546Sopenharmony_ci /* This is not supported now, but it might be required for OpenCL 489bf215546Sopenharmony_ci * interop in the future. 490bf215546Sopenharmony_ci */ 491bf215546Sopenharmony_ci if (resource->nr_samples > 1 || rtex->is_depth) 492bf215546Sopenharmony_ci return false; 493bf215546Sopenharmony_ci 494bf215546Sopenharmony_ci /* Move a suballocated texture into a non-suballocated allocation. */ 495bf215546Sopenharmony_ci if (rscreen->ws->buffer_is_suballocated(res->buf) || 496bf215546Sopenharmony_ci rtex->surface.tile_swizzle) { 497bf215546Sopenharmony_ci assert(!res->b.is_shared); 498bf215546Sopenharmony_ci r600_reallocate_texture_inplace(rctx, rtex, 499bf215546Sopenharmony_ci PIPE_BIND_SHARED, false); 500bf215546Sopenharmony_ci rctx->b.flush(&rctx->b, NULL, 0); 501bf215546Sopenharmony_ci assert(res->b.b.bind & PIPE_BIND_SHARED); 502bf215546Sopenharmony_ci assert(res->flags & RADEON_FLAG_NO_SUBALLOC); 503bf215546Sopenharmony_ci assert(rtex->surface.tile_swizzle == 0); 504bf215546Sopenharmony_ci } 505bf215546Sopenharmony_ci 506bf215546Sopenharmony_ci if (!(usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH) && 507bf215546Sopenharmony_ci rtex->cmask.size) { 508bf215546Sopenharmony_ci /* Eliminate fast clear (CMASK) */ 509bf215546Sopenharmony_ci r600_eliminate_fast_color_clear(rctx, rtex); 510bf215546Sopenharmony_ci 511bf215546Sopenharmony_ci /* Disable CMASK if flush_resource isn't going 512bf215546Sopenharmony_ci * to be called. 513bf215546Sopenharmony_ci */ 514bf215546Sopenharmony_ci if (rtex->cmask.size) 515bf215546Sopenharmony_ci r600_texture_discard_cmask(rscreen, rtex); 516bf215546Sopenharmony_ci } 517bf215546Sopenharmony_ci 518bf215546Sopenharmony_ci /* Set metadata. */ 519bf215546Sopenharmony_ci if (!res->b.is_shared || update_metadata) { 520bf215546Sopenharmony_ci r600_texture_init_metadata(rscreen, rtex, &metadata); 521bf215546Sopenharmony_ci 522bf215546Sopenharmony_ci rscreen->ws->buffer_set_metadata(rscreen->ws, res->buf, &metadata, NULL); 523bf215546Sopenharmony_ci } 524bf215546Sopenharmony_ci 525bf215546Sopenharmony_ci slice_size = (uint64_t)rtex->surface.u.legacy.level[0].slice_size_dw * 4; 526bf215546Sopenharmony_ci } else { 527bf215546Sopenharmony_ci /* Move a suballocated buffer into a non-suballocated allocation. */ 528bf215546Sopenharmony_ci if (rscreen->ws->buffer_is_suballocated(res->buf)) { 529bf215546Sopenharmony_ci assert(!res->b.is_shared); 530bf215546Sopenharmony_ci 531bf215546Sopenharmony_ci /* Allocate a new buffer with PIPE_BIND_SHARED. */ 532bf215546Sopenharmony_ci struct pipe_resource templ = res->b.b; 533bf215546Sopenharmony_ci templ.bind |= PIPE_BIND_SHARED; 534bf215546Sopenharmony_ci 535bf215546Sopenharmony_ci struct pipe_resource *newb = 536bf215546Sopenharmony_ci screen->resource_create(screen, &templ); 537bf215546Sopenharmony_ci if (!newb) 538bf215546Sopenharmony_ci return false; 539bf215546Sopenharmony_ci 540bf215546Sopenharmony_ci /* Copy the old buffer contents to the new one. */ 541bf215546Sopenharmony_ci struct pipe_box box; 542bf215546Sopenharmony_ci u_box_1d(0, newb->width0, &box); 543bf215546Sopenharmony_ci rctx->b.resource_copy_region(&rctx->b, newb, 0, 0, 0, 0, 544bf215546Sopenharmony_ci &res->b.b, 0, &box); 545bf215546Sopenharmony_ci /* Move the new buffer storage to the old pipe_resource. */ 546bf215546Sopenharmony_ci r600_replace_buffer_storage(&rctx->b, &res->b.b, newb); 547bf215546Sopenharmony_ci pipe_resource_reference(&newb, NULL); 548bf215546Sopenharmony_ci 549bf215546Sopenharmony_ci assert(res->b.b.bind & PIPE_BIND_SHARED); 550bf215546Sopenharmony_ci assert(res->flags & RADEON_FLAG_NO_SUBALLOC); 551bf215546Sopenharmony_ci } 552bf215546Sopenharmony_ci 553bf215546Sopenharmony_ci /* Buffers */ 554bf215546Sopenharmony_ci slice_size = 0; 555bf215546Sopenharmony_ci } 556bf215546Sopenharmony_ci 557bf215546Sopenharmony_ci r600_texture_get_info(screen, resource, &stride, &offset); 558bf215546Sopenharmony_ci 559bf215546Sopenharmony_ci if (res->b.is_shared) { 560bf215546Sopenharmony_ci /* USAGE_EXPLICIT_FLUSH must be cleared if at least one user 561bf215546Sopenharmony_ci * doesn't set it. 562bf215546Sopenharmony_ci */ 563bf215546Sopenharmony_ci res->external_usage |= usage & ~PIPE_HANDLE_USAGE_EXPLICIT_FLUSH; 564bf215546Sopenharmony_ci if (!(usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH)) 565bf215546Sopenharmony_ci res->external_usage &= ~PIPE_HANDLE_USAGE_EXPLICIT_FLUSH; 566bf215546Sopenharmony_ci } else { 567bf215546Sopenharmony_ci res->b.is_shared = true; 568bf215546Sopenharmony_ci res->external_usage = usage; 569bf215546Sopenharmony_ci } 570bf215546Sopenharmony_ci 571bf215546Sopenharmony_ci whandle->stride = stride; 572bf215546Sopenharmony_ci whandle->offset = offset + slice_size * whandle->layer; 573bf215546Sopenharmony_ci 574bf215546Sopenharmony_ci return rscreen->ws->buffer_get_handle(rscreen->ws, res->buf, whandle); 575bf215546Sopenharmony_ci} 576bf215546Sopenharmony_ci 577bf215546Sopenharmony_civoid r600_texture_destroy(struct pipe_screen *screen, struct pipe_resource *ptex) 578bf215546Sopenharmony_ci{ 579bf215546Sopenharmony_ci struct r600_texture *rtex = (struct r600_texture*)ptex; 580bf215546Sopenharmony_ci struct r600_resource *resource = &rtex->resource; 581bf215546Sopenharmony_ci 582bf215546Sopenharmony_ci r600_texture_reference(&rtex->flushed_depth_texture, NULL); 583bf215546Sopenharmony_ci pipe_resource_reference((struct pipe_resource**)&resource->immed_buffer, NULL); 584bf215546Sopenharmony_ci 585bf215546Sopenharmony_ci if (rtex->cmask_buffer != &rtex->resource) { 586bf215546Sopenharmony_ci r600_resource_reference(&rtex->cmask_buffer, NULL); 587bf215546Sopenharmony_ci } 588bf215546Sopenharmony_ci pb_reference(&resource->buf, NULL); 589bf215546Sopenharmony_ci FREE(rtex); 590bf215546Sopenharmony_ci} 591bf215546Sopenharmony_ci 592bf215546Sopenharmony_ci/* The number of samples can be specified independently of the texture. */ 593bf215546Sopenharmony_civoid r600_texture_get_fmask_info(struct r600_common_screen *rscreen, 594bf215546Sopenharmony_ci struct r600_texture *rtex, 595bf215546Sopenharmony_ci unsigned nr_samples, 596bf215546Sopenharmony_ci struct r600_fmask_info *out) 597bf215546Sopenharmony_ci{ 598bf215546Sopenharmony_ci /* FMASK is allocated like an ordinary texture. */ 599bf215546Sopenharmony_ci struct pipe_resource templ = rtex->resource.b.b; 600bf215546Sopenharmony_ci struct radeon_surf fmask = {}; 601bf215546Sopenharmony_ci unsigned flags, bpe; 602bf215546Sopenharmony_ci 603bf215546Sopenharmony_ci memset(out, 0, sizeof(*out)); 604bf215546Sopenharmony_ci 605bf215546Sopenharmony_ci templ.nr_samples = 1; 606bf215546Sopenharmony_ci flags = rtex->surface.flags | RADEON_SURF_FMASK; 607bf215546Sopenharmony_ci 608bf215546Sopenharmony_ci /* Use the same parameters and tile mode. */ 609bf215546Sopenharmony_ci fmask.u.legacy.bankw = rtex->surface.u.legacy.bankw; 610bf215546Sopenharmony_ci fmask.u.legacy.bankh = rtex->surface.u.legacy.bankh; 611bf215546Sopenharmony_ci fmask.u.legacy.mtilea = rtex->surface.u.legacy.mtilea; 612bf215546Sopenharmony_ci fmask.u.legacy.tile_split = rtex->surface.u.legacy.tile_split; 613bf215546Sopenharmony_ci 614bf215546Sopenharmony_ci if (nr_samples <= 4) 615bf215546Sopenharmony_ci fmask.u.legacy.bankh = 4; 616bf215546Sopenharmony_ci 617bf215546Sopenharmony_ci switch (nr_samples) { 618bf215546Sopenharmony_ci case 2: 619bf215546Sopenharmony_ci case 4: 620bf215546Sopenharmony_ci bpe = 1; 621bf215546Sopenharmony_ci break; 622bf215546Sopenharmony_ci case 8: 623bf215546Sopenharmony_ci bpe = 4; 624bf215546Sopenharmony_ci break; 625bf215546Sopenharmony_ci default: 626bf215546Sopenharmony_ci R600_ERR("Invalid sample count for FMASK allocation.\n"); 627bf215546Sopenharmony_ci return; 628bf215546Sopenharmony_ci } 629bf215546Sopenharmony_ci 630bf215546Sopenharmony_ci /* Overallocate FMASK on R600-R700 to fix colorbuffer corruption. 631bf215546Sopenharmony_ci * This can be fixed by writing a separate FMASK allocator specifically 632bf215546Sopenharmony_ci * for R600-R700 asics. */ 633bf215546Sopenharmony_ci if (rscreen->gfx_level <= R700) { 634bf215546Sopenharmony_ci bpe *= 2; 635bf215546Sopenharmony_ci } 636bf215546Sopenharmony_ci 637bf215546Sopenharmony_ci if (rscreen->ws->surface_init(rscreen->ws, &templ, 638bf215546Sopenharmony_ci flags, bpe, RADEON_SURF_MODE_2D, &fmask)) { 639bf215546Sopenharmony_ci R600_ERR("Got error in surface_init while allocating FMASK.\n"); 640bf215546Sopenharmony_ci return; 641bf215546Sopenharmony_ci } 642bf215546Sopenharmony_ci 643bf215546Sopenharmony_ci assert(fmask.u.legacy.level[0].mode == RADEON_SURF_MODE_2D); 644bf215546Sopenharmony_ci 645bf215546Sopenharmony_ci out->slice_tile_max = (fmask.u.legacy.level[0].nblk_x * fmask.u.legacy.level[0].nblk_y) / 64; 646bf215546Sopenharmony_ci if (out->slice_tile_max) 647bf215546Sopenharmony_ci out->slice_tile_max -= 1; 648bf215546Sopenharmony_ci 649bf215546Sopenharmony_ci out->tile_mode_index = fmask.u.legacy.tiling_index[0]; 650bf215546Sopenharmony_ci out->pitch_in_pixels = fmask.u.legacy.level[0].nblk_x; 651bf215546Sopenharmony_ci out->bank_height = fmask.u.legacy.bankh; 652bf215546Sopenharmony_ci out->tile_swizzle = fmask.tile_swizzle; 653bf215546Sopenharmony_ci out->alignment = MAX2(256, 1 << fmask.surf_alignment_log2); 654bf215546Sopenharmony_ci out->size = fmask.surf_size; 655bf215546Sopenharmony_ci} 656bf215546Sopenharmony_ci 657bf215546Sopenharmony_cistatic void r600_texture_allocate_fmask(struct r600_common_screen *rscreen, 658bf215546Sopenharmony_ci struct r600_texture *rtex) 659bf215546Sopenharmony_ci{ 660bf215546Sopenharmony_ci r600_texture_get_fmask_info(rscreen, rtex, 661bf215546Sopenharmony_ci rtex->resource.b.b.nr_samples, &rtex->fmask); 662bf215546Sopenharmony_ci 663bf215546Sopenharmony_ci rtex->fmask.offset = align64(rtex->size, rtex->fmask.alignment); 664bf215546Sopenharmony_ci rtex->size = rtex->fmask.offset + rtex->fmask.size; 665bf215546Sopenharmony_ci} 666bf215546Sopenharmony_ci 667bf215546Sopenharmony_civoid r600_texture_get_cmask_info(struct r600_common_screen *rscreen, 668bf215546Sopenharmony_ci struct r600_texture *rtex, 669bf215546Sopenharmony_ci struct r600_cmask_info *out) 670bf215546Sopenharmony_ci{ 671bf215546Sopenharmony_ci unsigned cmask_tile_width = 8; 672bf215546Sopenharmony_ci unsigned cmask_tile_height = 8; 673bf215546Sopenharmony_ci unsigned cmask_tile_elements = cmask_tile_width * cmask_tile_height; 674bf215546Sopenharmony_ci unsigned element_bits = 4; 675bf215546Sopenharmony_ci unsigned cmask_cache_bits = 1024; 676bf215546Sopenharmony_ci unsigned num_pipes = rscreen->info.num_tile_pipes; 677bf215546Sopenharmony_ci unsigned pipe_interleave_bytes = rscreen->info.pipe_interleave_bytes; 678bf215546Sopenharmony_ci 679bf215546Sopenharmony_ci unsigned elements_per_macro_tile = (cmask_cache_bits / element_bits) * num_pipes; 680bf215546Sopenharmony_ci unsigned pixels_per_macro_tile = elements_per_macro_tile * cmask_tile_elements; 681bf215546Sopenharmony_ci unsigned sqrt_pixels_per_macro_tile = sqrt(pixels_per_macro_tile); 682bf215546Sopenharmony_ci unsigned macro_tile_width = util_next_power_of_two(sqrt_pixels_per_macro_tile); 683bf215546Sopenharmony_ci unsigned macro_tile_height = pixels_per_macro_tile / macro_tile_width; 684bf215546Sopenharmony_ci 685bf215546Sopenharmony_ci unsigned pitch_elements = align(rtex->resource.b.b.width0, macro_tile_width); 686bf215546Sopenharmony_ci unsigned height = align(rtex->resource.b.b.height0, macro_tile_height); 687bf215546Sopenharmony_ci 688bf215546Sopenharmony_ci unsigned base_align = num_pipes * pipe_interleave_bytes; 689bf215546Sopenharmony_ci unsigned slice_bytes = 690bf215546Sopenharmony_ci ((pitch_elements * height * element_bits + 7) / 8) / cmask_tile_elements; 691bf215546Sopenharmony_ci 692bf215546Sopenharmony_ci assert(macro_tile_width % 128 == 0); 693bf215546Sopenharmony_ci assert(macro_tile_height % 128 == 0); 694bf215546Sopenharmony_ci 695bf215546Sopenharmony_ci out->slice_tile_max = ((pitch_elements * height) / (128*128)) - 1; 696bf215546Sopenharmony_ci out->alignment = MAX2(256, base_align); 697bf215546Sopenharmony_ci out->size = util_num_layers(&rtex->resource.b.b, 0) * 698bf215546Sopenharmony_ci align(slice_bytes, base_align); 699bf215546Sopenharmony_ci} 700bf215546Sopenharmony_ci 701bf215546Sopenharmony_cistatic void r600_texture_allocate_cmask(struct r600_common_screen *rscreen, 702bf215546Sopenharmony_ci struct r600_texture *rtex) 703bf215546Sopenharmony_ci{ 704bf215546Sopenharmony_ci r600_texture_get_cmask_info(rscreen, rtex, &rtex->cmask); 705bf215546Sopenharmony_ci 706bf215546Sopenharmony_ci rtex->cmask.offset = align64(rtex->size, rtex->cmask.alignment); 707bf215546Sopenharmony_ci rtex->size = rtex->cmask.offset + rtex->cmask.size; 708bf215546Sopenharmony_ci 709bf215546Sopenharmony_ci rtex->cb_color_info |= EG_S_028C70_FAST_CLEAR(1); 710bf215546Sopenharmony_ci} 711bf215546Sopenharmony_ci 712bf215546Sopenharmony_cistatic void r600_texture_alloc_cmask_separate(struct r600_common_screen *rscreen, 713bf215546Sopenharmony_ci struct r600_texture *rtex) 714bf215546Sopenharmony_ci{ 715bf215546Sopenharmony_ci if (rtex->cmask_buffer) 716bf215546Sopenharmony_ci return; 717bf215546Sopenharmony_ci 718bf215546Sopenharmony_ci assert(rtex->cmask.size == 0); 719bf215546Sopenharmony_ci 720bf215546Sopenharmony_ci r600_texture_get_cmask_info(rscreen, rtex, &rtex->cmask); 721bf215546Sopenharmony_ci 722bf215546Sopenharmony_ci rtex->cmask_buffer = (struct r600_resource *) 723bf215546Sopenharmony_ci r600_aligned_buffer_create(&rscreen->b, 724bf215546Sopenharmony_ci R600_RESOURCE_FLAG_UNMAPPABLE, 725bf215546Sopenharmony_ci PIPE_USAGE_DEFAULT, 726bf215546Sopenharmony_ci rtex->cmask.size, 727bf215546Sopenharmony_ci rtex->cmask.alignment); 728bf215546Sopenharmony_ci if (rtex->cmask_buffer == NULL) { 729bf215546Sopenharmony_ci rtex->cmask.size = 0; 730bf215546Sopenharmony_ci return; 731bf215546Sopenharmony_ci } 732bf215546Sopenharmony_ci 733bf215546Sopenharmony_ci /* update colorbuffer state bits */ 734bf215546Sopenharmony_ci rtex->cmask.base_address_reg = rtex->cmask_buffer->gpu_address >> 8; 735bf215546Sopenharmony_ci 736bf215546Sopenharmony_ci rtex->cb_color_info |= EG_S_028C70_FAST_CLEAR(1); 737bf215546Sopenharmony_ci 738bf215546Sopenharmony_ci p_atomic_inc(&rscreen->compressed_colortex_counter); 739bf215546Sopenharmony_ci} 740bf215546Sopenharmony_ci 741bf215546Sopenharmony_civoid eg_resource_alloc_immed(struct r600_common_screen *rscreen, 742bf215546Sopenharmony_ci struct r600_resource *res, 743bf215546Sopenharmony_ci unsigned immed_size) 744bf215546Sopenharmony_ci{ 745bf215546Sopenharmony_ci res->immed_buffer = (struct r600_resource *) 746bf215546Sopenharmony_ci pipe_buffer_create(&rscreen->b, PIPE_BIND_CUSTOM, 747bf215546Sopenharmony_ci PIPE_USAGE_DEFAULT, immed_size); 748bf215546Sopenharmony_ci} 749bf215546Sopenharmony_ci 750bf215546Sopenharmony_cistatic void r600_texture_get_htile_size(struct r600_common_screen *rscreen, 751bf215546Sopenharmony_ci struct r600_texture *rtex) 752bf215546Sopenharmony_ci{ 753bf215546Sopenharmony_ci unsigned cl_width, cl_height, width, height; 754bf215546Sopenharmony_ci unsigned slice_elements, slice_bytes, pipe_interleave_bytes, base_align; 755bf215546Sopenharmony_ci unsigned num_pipes = rscreen->info.num_tile_pipes; 756bf215546Sopenharmony_ci 757bf215546Sopenharmony_ci rtex->surface.meta_size = 0; 758bf215546Sopenharmony_ci 759bf215546Sopenharmony_ci /* HW bug on R6xx. */ 760bf215546Sopenharmony_ci if (rscreen->gfx_level == R600 && 761bf215546Sopenharmony_ci (rtex->resource.b.b.width0 > 7680 || 762bf215546Sopenharmony_ci rtex->resource.b.b.height0 > 7680)) 763bf215546Sopenharmony_ci return; 764bf215546Sopenharmony_ci 765bf215546Sopenharmony_ci switch (num_pipes) { 766bf215546Sopenharmony_ci case 1: 767bf215546Sopenharmony_ci cl_width = 32; 768bf215546Sopenharmony_ci cl_height = 16; 769bf215546Sopenharmony_ci break; 770bf215546Sopenharmony_ci case 2: 771bf215546Sopenharmony_ci cl_width = 32; 772bf215546Sopenharmony_ci cl_height = 32; 773bf215546Sopenharmony_ci break; 774bf215546Sopenharmony_ci case 4: 775bf215546Sopenharmony_ci cl_width = 64; 776bf215546Sopenharmony_ci cl_height = 32; 777bf215546Sopenharmony_ci break; 778bf215546Sopenharmony_ci case 8: 779bf215546Sopenharmony_ci cl_width = 64; 780bf215546Sopenharmony_ci cl_height = 64; 781bf215546Sopenharmony_ci break; 782bf215546Sopenharmony_ci case 16: 783bf215546Sopenharmony_ci cl_width = 128; 784bf215546Sopenharmony_ci cl_height = 64; 785bf215546Sopenharmony_ci break; 786bf215546Sopenharmony_ci default: 787bf215546Sopenharmony_ci assert(0); 788bf215546Sopenharmony_ci return; 789bf215546Sopenharmony_ci } 790bf215546Sopenharmony_ci 791bf215546Sopenharmony_ci width = align(rtex->surface.u.legacy.level[0].nblk_x, cl_width * 8); 792bf215546Sopenharmony_ci height = align(rtex->surface.u.legacy.level[0].nblk_y, cl_height * 8); 793bf215546Sopenharmony_ci 794bf215546Sopenharmony_ci slice_elements = (width * height) / (8 * 8); 795bf215546Sopenharmony_ci slice_bytes = slice_elements * 4; 796bf215546Sopenharmony_ci 797bf215546Sopenharmony_ci pipe_interleave_bytes = rscreen->info.pipe_interleave_bytes; 798bf215546Sopenharmony_ci base_align = num_pipes * pipe_interleave_bytes; 799bf215546Sopenharmony_ci 800bf215546Sopenharmony_ci rtex->surface.meta_alignment_log2 = util_logbase2(base_align); 801bf215546Sopenharmony_ci rtex->surface.meta_size = 802bf215546Sopenharmony_ci util_num_layers(&rtex->resource.b.b, 0) * 803bf215546Sopenharmony_ci align(slice_bytes, base_align); 804bf215546Sopenharmony_ci} 805bf215546Sopenharmony_ci 806bf215546Sopenharmony_cistatic void r600_texture_allocate_htile(struct r600_common_screen *rscreen, 807bf215546Sopenharmony_ci struct r600_texture *rtex) 808bf215546Sopenharmony_ci{ 809bf215546Sopenharmony_ci r600_texture_get_htile_size(rscreen, rtex); 810bf215546Sopenharmony_ci 811bf215546Sopenharmony_ci if (!rtex->surface.meta_size) 812bf215546Sopenharmony_ci return; 813bf215546Sopenharmony_ci 814bf215546Sopenharmony_ci rtex->htile_offset = align(rtex->size, 1 << rtex->surface.meta_alignment_log2); 815bf215546Sopenharmony_ci rtex->size = rtex->htile_offset + rtex->surface.meta_size; 816bf215546Sopenharmony_ci} 817bf215546Sopenharmony_ci 818bf215546Sopenharmony_civoid r600_print_texture_info(struct r600_common_screen *rscreen, 819bf215546Sopenharmony_ci struct r600_texture *rtex, struct u_log_context *log) 820bf215546Sopenharmony_ci{ 821bf215546Sopenharmony_ci int i; 822bf215546Sopenharmony_ci 823bf215546Sopenharmony_ci /* Common parameters. */ 824bf215546Sopenharmony_ci u_log_printf(log, " Info: npix_x=%u, npix_y=%u, npix_z=%u, blk_w=%u, " 825bf215546Sopenharmony_ci "blk_h=%u, array_size=%u, last_level=%u, " 826bf215546Sopenharmony_ci "bpe=%u, nsamples=%u, flags=0x%"PRIx64", %s\n", 827bf215546Sopenharmony_ci rtex->resource.b.b.width0, rtex->resource.b.b.height0, 828bf215546Sopenharmony_ci rtex->resource.b.b.depth0, rtex->surface.blk_w, 829bf215546Sopenharmony_ci rtex->surface.blk_h, 830bf215546Sopenharmony_ci rtex->resource.b.b.array_size, rtex->resource.b.b.last_level, 831bf215546Sopenharmony_ci rtex->surface.bpe, rtex->resource.b.b.nr_samples, 832bf215546Sopenharmony_ci rtex->surface.flags, util_format_short_name(rtex->resource.b.b.format)); 833bf215546Sopenharmony_ci 834bf215546Sopenharmony_ci u_log_printf(log, " Layout: size=%"PRIu64", alignment=%u, bankw=%u, " 835bf215546Sopenharmony_ci "bankh=%u, nbanks=%u, mtilea=%u, tilesplit=%u, pipeconfig=%u, scanout=%u\n", 836bf215546Sopenharmony_ci rtex->surface.surf_size, 1 << rtex->surface.surf_alignment_log2, rtex->surface.u.legacy.bankw, 837bf215546Sopenharmony_ci rtex->surface.u.legacy.bankh, rtex->surface.u.legacy.num_banks, rtex->surface.u.legacy.mtilea, 838bf215546Sopenharmony_ci rtex->surface.u.legacy.tile_split, rtex->surface.u.legacy.pipe_config, 839bf215546Sopenharmony_ci (rtex->surface.flags & RADEON_SURF_SCANOUT) != 0); 840bf215546Sopenharmony_ci 841bf215546Sopenharmony_ci if (rtex->fmask.size) 842bf215546Sopenharmony_ci u_log_printf(log, " FMask: offset=%"PRIu64", size=%"PRIu64", alignment=%u, pitch_in_pixels=%u, " 843bf215546Sopenharmony_ci "bankh=%u, slice_tile_max=%u, tile_mode_index=%u\n", 844bf215546Sopenharmony_ci rtex->fmask.offset, rtex->fmask.size, rtex->fmask.alignment, 845bf215546Sopenharmony_ci rtex->fmask.pitch_in_pixels, rtex->fmask.bank_height, 846bf215546Sopenharmony_ci rtex->fmask.slice_tile_max, rtex->fmask.tile_mode_index); 847bf215546Sopenharmony_ci 848bf215546Sopenharmony_ci if (rtex->cmask.size) 849bf215546Sopenharmony_ci u_log_printf(log, " CMask: offset=%"PRIu64", size=%"PRIu64", alignment=%u, " 850bf215546Sopenharmony_ci "slice_tile_max=%u\n", 851bf215546Sopenharmony_ci rtex->cmask.offset, rtex->cmask.size, rtex->cmask.alignment, 852bf215546Sopenharmony_ci rtex->cmask.slice_tile_max); 853bf215546Sopenharmony_ci 854bf215546Sopenharmony_ci if (rtex->htile_offset) 855bf215546Sopenharmony_ci u_log_printf(log, " HTile: offset=%"PRIu64", size=%u " 856bf215546Sopenharmony_ci "alignment=%u\n", 857bf215546Sopenharmony_ci rtex->htile_offset, rtex->surface.meta_size, 858bf215546Sopenharmony_ci 1 << rtex->surface.meta_alignment_log2); 859bf215546Sopenharmony_ci 860bf215546Sopenharmony_ci for (i = 0; i <= rtex->resource.b.b.last_level; i++) 861bf215546Sopenharmony_ci u_log_printf(log, " Level[%i]: offset=%"PRIu64", slice_size=%"PRIu64", " 862bf215546Sopenharmony_ci "npix_x=%u, npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, " 863bf215546Sopenharmony_ci "mode=%u, tiling_index = %u\n", 864bf215546Sopenharmony_ci i, (uint64_t)rtex->surface.u.legacy.level[i].offset_256B * 256, 865bf215546Sopenharmony_ci (uint64_t)rtex->surface.u.legacy.level[i].slice_size_dw * 4, 866bf215546Sopenharmony_ci u_minify(rtex->resource.b.b.width0, i), 867bf215546Sopenharmony_ci u_minify(rtex->resource.b.b.height0, i), 868bf215546Sopenharmony_ci u_minify(rtex->resource.b.b.depth0, i), 869bf215546Sopenharmony_ci rtex->surface.u.legacy.level[i].nblk_x, 870bf215546Sopenharmony_ci rtex->surface.u.legacy.level[i].nblk_y, 871bf215546Sopenharmony_ci rtex->surface.u.legacy.level[i].mode, 872bf215546Sopenharmony_ci rtex->surface.u.legacy.tiling_index[i]); 873bf215546Sopenharmony_ci 874bf215546Sopenharmony_ci if (rtex->surface.has_stencil) { 875bf215546Sopenharmony_ci u_log_printf(log, " StencilLayout: tilesplit=%u\n", 876bf215546Sopenharmony_ci rtex->surface.u.legacy.stencil_tile_split); 877bf215546Sopenharmony_ci for (i = 0; i <= rtex->resource.b.b.last_level; i++) { 878bf215546Sopenharmony_ci u_log_printf(log, " StencilLevel[%i]: offset=%"PRIu64", " 879bf215546Sopenharmony_ci "slice_size=%"PRIu64", npix_x=%u, " 880bf215546Sopenharmony_ci "npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, " 881bf215546Sopenharmony_ci "mode=%u, tiling_index = %u\n", 882bf215546Sopenharmony_ci i, (uint64_t)rtex->surface.u.legacy.zs.stencil_level[i].offset_256B * 256, 883bf215546Sopenharmony_ci (uint64_t)rtex->surface.u.legacy.zs.stencil_level[i].slice_size_dw * 4, 884bf215546Sopenharmony_ci u_minify(rtex->resource.b.b.width0, i), 885bf215546Sopenharmony_ci u_minify(rtex->resource.b.b.height0, i), 886bf215546Sopenharmony_ci u_minify(rtex->resource.b.b.depth0, i), 887bf215546Sopenharmony_ci rtex->surface.u.legacy.zs.stencil_level[i].nblk_x, 888bf215546Sopenharmony_ci rtex->surface.u.legacy.zs.stencil_level[i].nblk_y, 889bf215546Sopenharmony_ci rtex->surface.u.legacy.zs.stencil_level[i].mode, 890bf215546Sopenharmony_ci rtex->surface.u.legacy.zs.stencil_tiling_index[i]); 891bf215546Sopenharmony_ci } 892bf215546Sopenharmony_ci } 893bf215546Sopenharmony_ci} 894bf215546Sopenharmony_ci 895bf215546Sopenharmony_ci/* Common processing for r600_texture_create and r600_texture_from_handle */ 896bf215546Sopenharmony_cistatic struct r600_texture * 897bf215546Sopenharmony_cir600_texture_create_object(struct pipe_screen *screen, 898bf215546Sopenharmony_ci const struct pipe_resource *base, 899bf215546Sopenharmony_ci struct pb_buffer *buf, 900bf215546Sopenharmony_ci struct radeon_surf *surface) 901bf215546Sopenharmony_ci{ 902bf215546Sopenharmony_ci struct r600_texture *rtex; 903bf215546Sopenharmony_ci struct r600_resource *resource; 904bf215546Sopenharmony_ci struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; 905bf215546Sopenharmony_ci 906bf215546Sopenharmony_ci rtex = CALLOC_STRUCT(r600_texture); 907bf215546Sopenharmony_ci if (!rtex) 908bf215546Sopenharmony_ci return NULL; 909bf215546Sopenharmony_ci 910bf215546Sopenharmony_ci resource = &rtex->resource; 911bf215546Sopenharmony_ci resource->b.b = *base; 912bf215546Sopenharmony_ci pipe_reference_init(&resource->b.b.reference, 1); 913bf215546Sopenharmony_ci resource->b.b.screen = screen; 914bf215546Sopenharmony_ci 915bf215546Sopenharmony_ci /* don't include stencil-only formats which we don't support for rendering */ 916bf215546Sopenharmony_ci rtex->is_depth = util_format_has_depth(util_format_description(rtex->resource.b.b.format)); 917bf215546Sopenharmony_ci 918bf215546Sopenharmony_ci rtex->surface = *surface; 919bf215546Sopenharmony_ci rtex->size = rtex->surface.surf_size; 920bf215546Sopenharmony_ci rtex->db_render_format = base->format; 921bf215546Sopenharmony_ci 922bf215546Sopenharmony_ci /* Tiled depth textures utilize the non-displayable tile order. 923bf215546Sopenharmony_ci * This must be done after r600_setup_surface. 924bf215546Sopenharmony_ci * Applies to R600-Cayman. */ 925bf215546Sopenharmony_ci rtex->non_disp_tiling = rtex->is_depth && rtex->surface.u.legacy.level[0].mode >= RADEON_SURF_MODE_1D; 926bf215546Sopenharmony_ci /* Applies to GCN. */ 927bf215546Sopenharmony_ci rtex->last_msaa_resolve_target_micro_mode = rtex->surface.micro_tile_mode; 928bf215546Sopenharmony_ci 929bf215546Sopenharmony_ci if (rtex->is_depth) { 930bf215546Sopenharmony_ci if (base->flags & (R600_RESOURCE_FLAG_TRANSFER | 931bf215546Sopenharmony_ci R600_RESOURCE_FLAG_FLUSHED_DEPTH) || 932bf215546Sopenharmony_ci rscreen->gfx_level >= EVERGREEN) { 933bf215546Sopenharmony_ci rtex->can_sample_z = !rtex->surface.u.legacy.depth_adjusted; 934bf215546Sopenharmony_ci rtex->can_sample_s = !rtex->surface.u.legacy.stencil_adjusted; 935bf215546Sopenharmony_ci } else { 936bf215546Sopenharmony_ci if (rtex->resource.b.b.nr_samples <= 1 && 937bf215546Sopenharmony_ci (rtex->resource.b.b.format == PIPE_FORMAT_Z16_UNORM || 938bf215546Sopenharmony_ci rtex->resource.b.b.format == PIPE_FORMAT_Z32_FLOAT)) 939bf215546Sopenharmony_ci rtex->can_sample_z = true; 940bf215546Sopenharmony_ci } 941bf215546Sopenharmony_ci 942bf215546Sopenharmony_ci if (!(base->flags & (R600_RESOURCE_FLAG_TRANSFER | 943bf215546Sopenharmony_ci R600_RESOURCE_FLAG_FLUSHED_DEPTH))) { 944bf215546Sopenharmony_ci rtex->db_compatible = true; 945bf215546Sopenharmony_ci 946bf215546Sopenharmony_ci if (!(rscreen->debug_flags & DBG_NO_HYPERZ)) 947bf215546Sopenharmony_ci r600_texture_allocate_htile(rscreen, rtex); 948bf215546Sopenharmony_ci } 949bf215546Sopenharmony_ci } else { 950bf215546Sopenharmony_ci if (base->nr_samples > 1) { 951bf215546Sopenharmony_ci if (!buf) { 952bf215546Sopenharmony_ci r600_texture_allocate_fmask(rscreen, rtex); 953bf215546Sopenharmony_ci r600_texture_allocate_cmask(rscreen, rtex); 954bf215546Sopenharmony_ci rtex->cmask_buffer = &rtex->resource; 955bf215546Sopenharmony_ci } 956bf215546Sopenharmony_ci if (!rtex->fmask.size || !rtex->cmask.size) { 957bf215546Sopenharmony_ci FREE(rtex); 958bf215546Sopenharmony_ci return NULL; 959bf215546Sopenharmony_ci } 960bf215546Sopenharmony_ci } 961bf215546Sopenharmony_ci } 962bf215546Sopenharmony_ci 963bf215546Sopenharmony_ci /* Now create the backing buffer. */ 964bf215546Sopenharmony_ci if (!buf) { 965bf215546Sopenharmony_ci r600_init_resource_fields(rscreen, resource, rtex->size, 966bf215546Sopenharmony_ci 1 << rtex->surface.surf_alignment_log2); 967bf215546Sopenharmony_ci 968bf215546Sopenharmony_ci if (!r600_alloc_resource(rscreen, resource)) { 969bf215546Sopenharmony_ci FREE(rtex); 970bf215546Sopenharmony_ci return NULL; 971bf215546Sopenharmony_ci } 972bf215546Sopenharmony_ci } else { 973bf215546Sopenharmony_ci resource->buf = buf; 974bf215546Sopenharmony_ci resource->gpu_address = rscreen->ws->buffer_get_virtual_address(resource->buf); 975bf215546Sopenharmony_ci resource->bo_size = buf->size; 976bf215546Sopenharmony_ci resource->bo_alignment = 1 << buf->alignment_log2; 977bf215546Sopenharmony_ci resource->domains = rscreen->ws->buffer_get_initial_domain(resource->buf); 978bf215546Sopenharmony_ci if (resource->domains & RADEON_DOMAIN_VRAM) 979bf215546Sopenharmony_ci resource->vram_usage = buf->size; 980bf215546Sopenharmony_ci else if (resource->domains & RADEON_DOMAIN_GTT) 981bf215546Sopenharmony_ci resource->gart_usage = buf->size; 982bf215546Sopenharmony_ci } 983bf215546Sopenharmony_ci 984bf215546Sopenharmony_ci if (rtex->cmask.size) { 985bf215546Sopenharmony_ci /* Initialize the cmask to 0xCC (= compressed state). */ 986bf215546Sopenharmony_ci r600_screen_clear_buffer(rscreen, &rtex->cmask_buffer->b.b, 987bf215546Sopenharmony_ci rtex->cmask.offset, rtex->cmask.size, 988bf215546Sopenharmony_ci 0xCCCCCCCC); 989bf215546Sopenharmony_ci } 990bf215546Sopenharmony_ci if (rtex->htile_offset) { 991bf215546Sopenharmony_ci uint32_t clear_value = 0; 992bf215546Sopenharmony_ci 993bf215546Sopenharmony_ci r600_screen_clear_buffer(rscreen, &rtex->resource.b.b, 994bf215546Sopenharmony_ci rtex->htile_offset, 995bf215546Sopenharmony_ci rtex->surface.meta_size, 996bf215546Sopenharmony_ci clear_value); 997bf215546Sopenharmony_ci } 998bf215546Sopenharmony_ci 999bf215546Sopenharmony_ci /* Initialize the CMASK base register value. */ 1000bf215546Sopenharmony_ci rtex->cmask.base_address_reg = 1001bf215546Sopenharmony_ci (rtex->resource.gpu_address + rtex->cmask.offset) >> 8; 1002bf215546Sopenharmony_ci 1003bf215546Sopenharmony_ci if (rscreen->debug_flags & DBG_VM) { 1004bf215546Sopenharmony_ci fprintf(stderr, "VM start=0x%"PRIX64" end=0x%"PRIX64" | Texture %ix%ix%i, %i levels, %i samples, %s\n", 1005bf215546Sopenharmony_ci rtex->resource.gpu_address, 1006bf215546Sopenharmony_ci rtex->resource.gpu_address + rtex->resource.buf->size, 1007bf215546Sopenharmony_ci base->width0, base->height0, util_num_layers(base, 0), base->last_level+1, 1008bf215546Sopenharmony_ci base->nr_samples ? base->nr_samples : 1, util_format_short_name(base->format)); 1009bf215546Sopenharmony_ci } 1010bf215546Sopenharmony_ci 1011bf215546Sopenharmony_ci if (rscreen->debug_flags & DBG_TEX) { 1012bf215546Sopenharmony_ci puts("Texture:"); 1013bf215546Sopenharmony_ci struct u_log_context log; 1014bf215546Sopenharmony_ci u_log_context_init(&log); 1015bf215546Sopenharmony_ci r600_print_texture_info(rscreen, rtex, &log); 1016bf215546Sopenharmony_ci u_log_new_page_print(&log, stdout); 1017bf215546Sopenharmony_ci fflush(stdout); 1018bf215546Sopenharmony_ci u_log_context_destroy(&log); 1019bf215546Sopenharmony_ci } 1020bf215546Sopenharmony_ci 1021bf215546Sopenharmony_ci return rtex; 1022bf215546Sopenharmony_ci} 1023bf215546Sopenharmony_ci 1024bf215546Sopenharmony_cistatic enum radeon_surf_mode 1025bf215546Sopenharmony_cir600_choose_tiling(struct r600_common_screen *rscreen, 1026bf215546Sopenharmony_ci const struct pipe_resource *templ) 1027bf215546Sopenharmony_ci{ 1028bf215546Sopenharmony_ci const struct util_format_description *desc = util_format_description(templ->format); 1029bf215546Sopenharmony_ci bool force_tiling = templ->flags & R600_RESOURCE_FLAG_FORCE_TILING; 1030bf215546Sopenharmony_ci bool is_depth_stencil = util_format_is_depth_or_stencil(templ->format) && 1031bf215546Sopenharmony_ci !(templ->flags & R600_RESOURCE_FLAG_FLUSHED_DEPTH); 1032bf215546Sopenharmony_ci 1033bf215546Sopenharmony_ci /* MSAA resources must be 2D tiled. */ 1034bf215546Sopenharmony_ci if (templ->nr_samples > 1) 1035bf215546Sopenharmony_ci return RADEON_SURF_MODE_2D; 1036bf215546Sopenharmony_ci 1037bf215546Sopenharmony_ci /* Transfer resources should be linear. */ 1038bf215546Sopenharmony_ci if (templ->flags & R600_RESOURCE_FLAG_TRANSFER) 1039bf215546Sopenharmony_ci return RADEON_SURF_MODE_LINEAR_ALIGNED; 1040bf215546Sopenharmony_ci 1041bf215546Sopenharmony_ci /* r600g: force tiling on TEXTURE_2D and TEXTURE_3D compute resources. */ 1042bf215546Sopenharmony_ci if (rscreen->gfx_level >= R600 && rscreen->gfx_level <= CAYMAN && 1043bf215546Sopenharmony_ci (templ->bind & PIPE_BIND_COMPUTE_RESOURCE) && 1044bf215546Sopenharmony_ci (templ->target == PIPE_TEXTURE_2D || 1045bf215546Sopenharmony_ci templ->target == PIPE_TEXTURE_3D)) 1046bf215546Sopenharmony_ci force_tiling = true; 1047bf215546Sopenharmony_ci 1048bf215546Sopenharmony_ci /* Handle common candidates for the linear mode. 1049bf215546Sopenharmony_ci * Compressed textures and DB surfaces must always be tiled. 1050bf215546Sopenharmony_ci */ 1051bf215546Sopenharmony_ci if (!force_tiling && 1052bf215546Sopenharmony_ci !is_depth_stencil && 1053bf215546Sopenharmony_ci !util_format_is_compressed(templ->format)) { 1054bf215546Sopenharmony_ci if (rscreen->debug_flags & DBG_NO_TILING) 1055bf215546Sopenharmony_ci return RADEON_SURF_MODE_LINEAR_ALIGNED; 1056bf215546Sopenharmony_ci 1057bf215546Sopenharmony_ci /* Tiling doesn't work with the 422 (SUBSAMPLED) formats on R600+. */ 1058bf215546Sopenharmony_ci if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) 1059bf215546Sopenharmony_ci return RADEON_SURF_MODE_LINEAR_ALIGNED; 1060bf215546Sopenharmony_ci 1061bf215546Sopenharmony_ci if (templ->bind & PIPE_BIND_LINEAR) 1062bf215546Sopenharmony_ci return RADEON_SURF_MODE_LINEAR_ALIGNED; 1063bf215546Sopenharmony_ci 1064bf215546Sopenharmony_ci /* 1D textures should be linear - fixes image operations on 1d */ 1065bf215546Sopenharmony_ci if (templ->target == PIPE_TEXTURE_1D || 1066bf215546Sopenharmony_ci templ->target == PIPE_TEXTURE_1D_ARRAY) 1067bf215546Sopenharmony_ci return RADEON_SURF_MODE_LINEAR_ALIGNED; 1068bf215546Sopenharmony_ci 1069bf215546Sopenharmony_ci /* Textures likely to be mapped often. */ 1070bf215546Sopenharmony_ci if (templ->usage == PIPE_USAGE_STAGING || 1071bf215546Sopenharmony_ci templ->usage == PIPE_USAGE_STREAM) 1072bf215546Sopenharmony_ci return RADEON_SURF_MODE_LINEAR_ALIGNED; 1073bf215546Sopenharmony_ci } 1074bf215546Sopenharmony_ci 1075bf215546Sopenharmony_ci /* Make small textures 1D tiled. */ 1076bf215546Sopenharmony_ci if (templ->width0 <= 16 || templ->height0 <= 16 || 1077bf215546Sopenharmony_ci (rscreen->debug_flags & DBG_NO_2D_TILING)) 1078bf215546Sopenharmony_ci return RADEON_SURF_MODE_1D; 1079bf215546Sopenharmony_ci 1080bf215546Sopenharmony_ci /* The allocator will switch to 1D if needed. */ 1081bf215546Sopenharmony_ci return RADEON_SURF_MODE_2D; 1082bf215546Sopenharmony_ci} 1083bf215546Sopenharmony_ci 1084bf215546Sopenharmony_cistruct pipe_resource *r600_texture_create(struct pipe_screen *screen, 1085bf215546Sopenharmony_ci const struct pipe_resource *templ) 1086bf215546Sopenharmony_ci{ 1087bf215546Sopenharmony_ci struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; 1088bf215546Sopenharmony_ci struct radeon_surf surface = {0}; 1089bf215546Sopenharmony_ci bool is_flushed_depth = templ->flags & R600_RESOURCE_FLAG_FLUSHED_DEPTH; 1090bf215546Sopenharmony_ci int r; 1091bf215546Sopenharmony_ci 1092bf215546Sopenharmony_ci r = r600_init_surface(rscreen, &surface, templ, 1093bf215546Sopenharmony_ci r600_choose_tiling(rscreen, templ), 0, 0, 1094bf215546Sopenharmony_ci false, false, is_flushed_depth); 1095bf215546Sopenharmony_ci if (r) { 1096bf215546Sopenharmony_ci return NULL; 1097bf215546Sopenharmony_ci } 1098bf215546Sopenharmony_ci 1099bf215546Sopenharmony_ci return (struct pipe_resource *) 1100bf215546Sopenharmony_ci r600_texture_create_object(screen, templ, NULL, &surface); 1101bf215546Sopenharmony_ci} 1102bf215546Sopenharmony_ci 1103bf215546Sopenharmony_cistatic struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen, 1104bf215546Sopenharmony_ci const struct pipe_resource *templ, 1105bf215546Sopenharmony_ci struct winsys_handle *whandle, 1106bf215546Sopenharmony_ci unsigned usage) 1107bf215546Sopenharmony_ci{ 1108bf215546Sopenharmony_ci struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; 1109bf215546Sopenharmony_ci struct pb_buffer *buf = NULL; 1110bf215546Sopenharmony_ci enum radeon_surf_mode array_mode; 1111bf215546Sopenharmony_ci struct radeon_surf surface = {}; 1112bf215546Sopenharmony_ci int r; 1113bf215546Sopenharmony_ci struct radeon_bo_metadata metadata = {}; 1114bf215546Sopenharmony_ci struct r600_texture *rtex; 1115bf215546Sopenharmony_ci bool is_scanout; 1116bf215546Sopenharmony_ci 1117bf215546Sopenharmony_ci /* Support only 2D textures without mipmaps */ 1118bf215546Sopenharmony_ci if ((templ->target != PIPE_TEXTURE_2D && templ->target != PIPE_TEXTURE_RECT) || 1119bf215546Sopenharmony_ci templ->depth0 != 1 || templ->last_level != 0) 1120bf215546Sopenharmony_ci return NULL; 1121bf215546Sopenharmony_ci 1122bf215546Sopenharmony_ci buf = rscreen->ws->buffer_from_handle(rscreen->ws, whandle, 1123bf215546Sopenharmony_ci rscreen->info.max_alignment, false); 1124bf215546Sopenharmony_ci if (!buf) 1125bf215546Sopenharmony_ci return NULL; 1126bf215546Sopenharmony_ci 1127bf215546Sopenharmony_ci rscreen->ws->buffer_get_metadata(rscreen->ws, buf, &metadata, NULL); 1128bf215546Sopenharmony_ci r600_surface_import_metadata(rscreen, &surface, &metadata, 1129bf215546Sopenharmony_ci &array_mode, &is_scanout); 1130bf215546Sopenharmony_ci 1131bf215546Sopenharmony_ci r = r600_init_surface(rscreen, &surface, templ, array_mode, 1132bf215546Sopenharmony_ci whandle->stride, whandle->offset, 1133bf215546Sopenharmony_ci true, is_scanout, false); 1134bf215546Sopenharmony_ci if (r) { 1135bf215546Sopenharmony_ci return NULL; 1136bf215546Sopenharmony_ci } 1137bf215546Sopenharmony_ci 1138bf215546Sopenharmony_ci rtex = r600_texture_create_object(screen, templ, buf, &surface); 1139bf215546Sopenharmony_ci if (!rtex) 1140bf215546Sopenharmony_ci return NULL; 1141bf215546Sopenharmony_ci 1142bf215546Sopenharmony_ci rtex->resource.b.is_shared = true; 1143bf215546Sopenharmony_ci rtex->resource.external_usage = usage; 1144bf215546Sopenharmony_ci 1145bf215546Sopenharmony_ci assert(rtex->surface.tile_swizzle == 0); 1146bf215546Sopenharmony_ci return &rtex->resource.b.b; 1147bf215546Sopenharmony_ci} 1148bf215546Sopenharmony_ci 1149bf215546Sopenharmony_cibool r600_init_flushed_depth_texture(struct pipe_context *ctx, 1150bf215546Sopenharmony_ci struct pipe_resource *texture, 1151bf215546Sopenharmony_ci struct r600_texture **staging) 1152bf215546Sopenharmony_ci{ 1153bf215546Sopenharmony_ci struct r600_texture *rtex = (struct r600_texture*)texture; 1154bf215546Sopenharmony_ci struct pipe_resource resource; 1155bf215546Sopenharmony_ci struct r600_texture **flushed_depth_texture = staging ? 1156bf215546Sopenharmony_ci staging : &rtex->flushed_depth_texture; 1157bf215546Sopenharmony_ci enum pipe_format pipe_format = texture->format; 1158bf215546Sopenharmony_ci 1159bf215546Sopenharmony_ci if (!staging) { 1160bf215546Sopenharmony_ci if (rtex->flushed_depth_texture) 1161bf215546Sopenharmony_ci return true; /* it's ready */ 1162bf215546Sopenharmony_ci 1163bf215546Sopenharmony_ci if (!rtex->can_sample_z && rtex->can_sample_s) { 1164bf215546Sopenharmony_ci switch (pipe_format) { 1165bf215546Sopenharmony_ci case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: 1166bf215546Sopenharmony_ci /* Save memory by not allocating the S plane. */ 1167bf215546Sopenharmony_ci pipe_format = PIPE_FORMAT_Z32_FLOAT; 1168bf215546Sopenharmony_ci break; 1169bf215546Sopenharmony_ci case PIPE_FORMAT_Z24_UNORM_S8_UINT: 1170bf215546Sopenharmony_ci case PIPE_FORMAT_S8_UINT_Z24_UNORM: 1171bf215546Sopenharmony_ci /* Save memory bandwidth by not copying the 1172bf215546Sopenharmony_ci * stencil part during flush. 1173bf215546Sopenharmony_ci * 1174bf215546Sopenharmony_ci * This potentially increases memory bandwidth 1175bf215546Sopenharmony_ci * if an application uses both Z and S texturing 1176bf215546Sopenharmony_ci * simultaneously (a flushed Z24S8 texture 1177bf215546Sopenharmony_ci * would be stored compactly), but how often 1178bf215546Sopenharmony_ci * does that really happen? 1179bf215546Sopenharmony_ci */ 1180bf215546Sopenharmony_ci pipe_format = PIPE_FORMAT_Z24X8_UNORM; 1181bf215546Sopenharmony_ci break; 1182bf215546Sopenharmony_ci default:; 1183bf215546Sopenharmony_ci } 1184bf215546Sopenharmony_ci } else if (!rtex->can_sample_s && rtex->can_sample_z) { 1185bf215546Sopenharmony_ci assert(util_format_has_stencil(util_format_description(pipe_format))); 1186bf215546Sopenharmony_ci 1187bf215546Sopenharmony_ci /* DB->CB copies to an 8bpp surface don't work. */ 1188bf215546Sopenharmony_ci pipe_format = PIPE_FORMAT_X24S8_UINT; 1189bf215546Sopenharmony_ci } 1190bf215546Sopenharmony_ci } 1191bf215546Sopenharmony_ci 1192bf215546Sopenharmony_ci memset(&resource, 0, sizeof(resource)); 1193bf215546Sopenharmony_ci resource.target = texture->target; 1194bf215546Sopenharmony_ci resource.format = pipe_format; 1195bf215546Sopenharmony_ci resource.width0 = texture->width0; 1196bf215546Sopenharmony_ci resource.height0 = texture->height0; 1197bf215546Sopenharmony_ci resource.depth0 = texture->depth0; 1198bf215546Sopenharmony_ci resource.array_size = texture->array_size; 1199bf215546Sopenharmony_ci resource.last_level = texture->last_level; 1200bf215546Sopenharmony_ci resource.nr_samples = texture->nr_samples; 1201bf215546Sopenharmony_ci resource.usage = staging ? PIPE_USAGE_STAGING : PIPE_USAGE_DEFAULT; 1202bf215546Sopenharmony_ci resource.bind = texture->bind & ~PIPE_BIND_DEPTH_STENCIL; 1203bf215546Sopenharmony_ci resource.flags = texture->flags | R600_RESOURCE_FLAG_FLUSHED_DEPTH; 1204bf215546Sopenharmony_ci 1205bf215546Sopenharmony_ci if (staging) 1206bf215546Sopenharmony_ci resource.flags |= R600_RESOURCE_FLAG_TRANSFER; 1207bf215546Sopenharmony_ci 1208bf215546Sopenharmony_ci *flushed_depth_texture = (struct r600_texture *)ctx->screen->resource_create(ctx->screen, &resource); 1209bf215546Sopenharmony_ci if (*flushed_depth_texture == NULL) { 1210bf215546Sopenharmony_ci R600_ERR("failed to create temporary texture to hold flushed depth\n"); 1211bf215546Sopenharmony_ci return false; 1212bf215546Sopenharmony_ci } 1213bf215546Sopenharmony_ci 1214bf215546Sopenharmony_ci (*flushed_depth_texture)->non_disp_tiling = false; 1215bf215546Sopenharmony_ci return true; 1216bf215546Sopenharmony_ci} 1217bf215546Sopenharmony_ci 1218bf215546Sopenharmony_ci/** 1219bf215546Sopenharmony_ci * Initialize the pipe_resource descriptor to be of the same size as the box, 1220bf215546Sopenharmony_ci * which is supposed to hold a subregion of the texture "orig" at the given 1221bf215546Sopenharmony_ci * mipmap level. 1222bf215546Sopenharmony_ci */ 1223bf215546Sopenharmony_cistatic void r600_init_temp_resource_from_box(struct pipe_resource *res, 1224bf215546Sopenharmony_ci struct pipe_resource *orig, 1225bf215546Sopenharmony_ci const struct pipe_box *box, 1226bf215546Sopenharmony_ci unsigned level, unsigned flags) 1227bf215546Sopenharmony_ci{ 1228bf215546Sopenharmony_ci memset(res, 0, sizeof(*res)); 1229bf215546Sopenharmony_ci res->format = orig->format; 1230bf215546Sopenharmony_ci res->width0 = box->width; 1231bf215546Sopenharmony_ci res->height0 = box->height; 1232bf215546Sopenharmony_ci res->depth0 = 1; 1233bf215546Sopenharmony_ci res->array_size = 1; 1234bf215546Sopenharmony_ci res->usage = flags & R600_RESOURCE_FLAG_TRANSFER ? PIPE_USAGE_STAGING : PIPE_USAGE_DEFAULT; 1235bf215546Sopenharmony_ci res->flags = flags; 1236bf215546Sopenharmony_ci 1237bf215546Sopenharmony_ci /* We must set the correct texture target and dimensions for a 3D box. */ 1238bf215546Sopenharmony_ci if (box->depth > 1 && util_max_layer(orig, level) > 0) { 1239bf215546Sopenharmony_ci res->target = PIPE_TEXTURE_2D_ARRAY; 1240bf215546Sopenharmony_ci res->array_size = box->depth; 1241bf215546Sopenharmony_ci } else { 1242bf215546Sopenharmony_ci res->target = PIPE_TEXTURE_2D; 1243bf215546Sopenharmony_ci } 1244bf215546Sopenharmony_ci} 1245bf215546Sopenharmony_ci 1246bf215546Sopenharmony_cistatic bool r600_can_invalidate_texture(struct r600_common_screen *rscreen, 1247bf215546Sopenharmony_ci struct r600_texture *rtex, 1248bf215546Sopenharmony_ci unsigned transfer_usage, 1249bf215546Sopenharmony_ci const struct pipe_box *box) 1250bf215546Sopenharmony_ci{ 1251bf215546Sopenharmony_ci /* r600g doesn't react to dirty_tex_descriptor_counter */ 1252bf215546Sopenharmony_ci return rscreen->gfx_level >= GFX6 && 1253bf215546Sopenharmony_ci !rtex->resource.b.is_shared && 1254bf215546Sopenharmony_ci !(transfer_usage & PIPE_MAP_READ) && 1255bf215546Sopenharmony_ci rtex->resource.b.b.last_level == 0 && 1256bf215546Sopenharmony_ci util_texrange_covers_whole_level(&rtex->resource.b.b, 0, 1257bf215546Sopenharmony_ci box->x, box->y, box->z, 1258bf215546Sopenharmony_ci box->width, box->height, 1259bf215546Sopenharmony_ci box->depth); 1260bf215546Sopenharmony_ci} 1261bf215546Sopenharmony_ci 1262bf215546Sopenharmony_cistatic void r600_texture_invalidate_storage(struct r600_common_context *rctx, 1263bf215546Sopenharmony_ci struct r600_texture *rtex) 1264bf215546Sopenharmony_ci{ 1265bf215546Sopenharmony_ci struct r600_common_screen *rscreen = rctx->screen; 1266bf215546Sopenharmony_ci 1267bf215546Sopenharmony_ci /* There is no point in discarding depth and tiled buffers. */ 1268bf215546Sopenharmony_ci assert(!rtex->is_depth); 1269bf215546Sopenharmony_ci assert(rtex->surface.is_linear); 1270bf215546Sopenharmony_ci 1271bf215546Sopenharmony_ci /* Reallocate the buffer in the same pipe_resource. */ 1272bf215546Sopenharmony_ci r600_alloc_resource(rscreen, &rtex->resource); 1273bf215546Sopenharmony_ci 1274bf215546Sopenharmony_ci /* Initialize the CMASK base address (needed even without CMASK). */ 1275bf215546Sopenharmony_ci rtex->cmask.base_address_reg = 1276bf215546Sopenharmony_ci (rtex->resource.gpu_address + rtex->cmask.offset) >> 8; 1277bf215546Sopenharmony_ci 1278bf215546Sopenharmony_ci p_atomic_inc(&rscreen->dirty_tex_counter); 1279bf215546Sopenharmony_ci 1280bf215546Sopenharmony_ci rctx->num_alloc_tex_transfer_bytes += rtex->size; 1281bf215546Sopenharmony_ci} 1282bf215546Sopenharmony_ci 1283bf215546Sopenharmony_civoid *r600_texture_transfer_map(struct pipe_context *ctx, 1284bf215546Sopenharmony_ci struct pipe_resource *texture, 1285bf215546Sopenharmony_ci unsigned level, 1286bf215546Sopenharmony_ci unsigned usage, 1287bf215546Sopenharmony_ci const struct pipe_box *box, 1288bf215546Sopenharmony_ci struct pipe_transfer **ptransfer) 1289bf215546Sopenharmony_ci{ 1290bf215546Sopenharmony_ci struct r600_common_context *rctx = (struct r600_common_context*)ctx; 1291bf215546Sopenharmony_ci struct r600_texture *rtex = (struct r600_texture*)texture; 1292bf215546Sopenharmony_ci struct r600_transfer *trans; 1293bf215546Sopenharmony_ci struct r600_resource *buf; 1294bf215546Sopenharmony_ci unsigned offset = 0; 1295bf215546Sopenharmony_ci char *map; 1296bf215546Sopenharmony_ci bool use_staging_texture = false; 1297bf215546Sopenharmony_ci 1298bf215546Sopenharmony_ci assert(!(texture->flags & R600_RESOURCE_FLAG_TRANSFER)); 1299bf215546Sopenharmony_ci assert(box->width && box->height && box->depth); 1300bf215546Sopenharmony_ci 1301bf215546Sopenharmony_ci /* Depth textures use staging unconditionally. */ 1302bf215546Sopenharmony_ci if (!rtex->is_depth) { 1303bf215546Sopenharmony_ci /* Degrade the tile mode if we get too many transfers on APUs. 1304bf215546Sopenharmony_ci * On dGPUs, the staging texture is always faster. 1305bf215546Sopenharmony_ci * Only count uploads that are at least 4x4 pixels large. 1306bf215546Sopenharmony_ci */ 1307bf215546Sopenharmony_ci if (!rctx->screen->info.has_dedicated_vram && 1308bf215546Sopenharmony_ci level == 0 && 1309bf215546Sopenharmony_ci box->width >= 4 && box->height >= 4 && 1310bf215546Sopenharmony_ci p_atomic_inc_return(&rtex->num_level0_transfers) == 10) { 1311bf215546Sopenharmony_ci bool can_invalidate = 1312bf215546Sopenharmony_ci r600_can_invalidate_texture(rctx->screen, rtex, 1313bf215546Sopenharmony_ci usage, box); 1314bf215546Sopenharmony_ci 1315bf215546Sopenharmony_ci r600_reallocate_texture_inplace(rctx, rtex, 1316bf215546Sopenharmony_ci PIPE_BIND_LINEAR, 1317bf215546Sopenharmony_ci can_invalidate); 1318bf215546Sopenharmony_ci } 1319bf215546Sopenharmony_ci 1320bf215546Sopenharmony_ci /* Tiled textures need to be converted into a linear texture for CPU 1321bf215546Sopenharmony_ci * access. The staging texture is always linear and is placed in GART. 1322bf215546Sopenharmony_ci * 1323bf215546Sopenharmony_ci * Reading from VRAM or GTT WC is slow, always use the staging 1324bf215546Sopenharmony_ci * texture in this case. 1325bf215546Sopenharmony_ci * 1326bf215546Sopenharmony_ci * Use the staging texture for uploads if the underlying BO 1327bf215546Sopenharmony_ci * is busy. 1328bf215546Sopenharmony_ci */ 1329bf215546Sopenharmony_ci if (!rtex->surface.is_linear) 1330bf215546Sopenharmony_ci use_staging_texture = true; 1331bf215546Sopenharmony_ci else if (usage & PIPE_MAP_READ) 1332bf215546Sopenharmony_ci use_staging_texture = 1333bf215546Sopenharmony_ci rtex->resource.domains & RADEON_DOMAIN_VRAM || 1334bf215546Sopenharmony_ci rtex->resource.flags & RADEON_FLAG_GTT_WC; 1335bf215546Sopenharmony_ci /* Write & linear only: */ 1336bf215546Sopenharmony_ci else if (r600_rings_is_buffer_referenced(rctx, rtex->resource.buf, 1337bf215546Sopenharmony_ci RADEON_USAGE_READWRITE) || 1338bf215546Sopenharmony_ci !rctx->ws->buffer_wait(rctx->ws, rtex->resource.buf, 0, 1339bf215546Sopenharmony_ci RADEON_USAGE_READWRITE)) { 1340bf215546Sopenharmony_ci /* It's busy. */ 1341bf215546Sopenharmony_ci if (r600_can_invalidate_texture(rctx->screen, rtex, 1342bf215546Sopenharmony_ci usage, box)) 1343bf215546Sopenharmony_ci r600_texture_invalidate_storage(rctx, rtex); 1344bf215546Sopenharmony_ci else 1345bf215546Sopenharmony_ci use_staging_texture = true; 1346bf215546Sopenharmony_ci } 1347bf215546Sopenharmony_ci } 1348bf215546Sopenharmony_ci 1349bf215546Sopenharmony_ci trans = CALLOC_STRUCT(r600_transfer); 1350bf215546Sopenharmony_ci if (!trans) 1351bf215546Sopenharmony_ci return NULL; 1352bf215546Sopenharmony_ci pipe_resource_reference(&trans->b.b.resource, texture); 1353bf215546Sopenharmony_ci trans->b.b.level = level; 1354bf215546Sopenharmony_ci trans->b.b.usage = usage; 1355bf215546Sopenharmony_ci trans->b.b.box = *box; 1356bf215546Sopenharmony_ci 1357bf215546Sopenharmony_ci if (rtex->is_depth) { 1358bf215546Sopenharmony_ci struct r600_texture *staging_depth; 1359bf215546Sopenharmony_ci 1360bf215546Sopenharmony_ci if (rtex->resource.b.b.nr_samples > 1) { 1361bf215546Sopenharmony_ci /* MSAA depth buffers need to be converted to single sample buffers. 1362bf215546Sopenharmony_ci * 1363bf215546Sopenharmony_ci * Mapping MSAA depth buffers can occur if ReadPixels is called 1364bf215546Sopenharmony_ci * with a multisample GLX visual. 1365bf215546Sopenharmony_ci * 1366bf215546Sopenharmony_ci * First downsample the depth buffer to a temporary texture, 1367bf215546Sopenharmony_ci * then decompress the temporary one to staging. 1368bf215546Sopenharmony_ci * 1369bf215546Sopenharmony_ci * Only the region being mapped is transfered. 1370bf215546Sopenharmony_ci */ 1371bf215546Sopenharmony_ci struct pipe_resource resource; 1372bf215546Sopenharmony_ci 1373bf215546Sopenharmony_ci r600_init_temp_resource_from_box(&resource, texture, box, level, 0); 1374bf215546Sopenharmony_ci 1375bf215546Sopenharmony_ci if (!r600_init_flushed_depth_texture(ctx, &resource, &staging_depth)) { 1376bf215546Sopenharmony_ci R600_ERR("failed to create temporary texture to hold untiled copy\n"); 1377bf215546Sopenharmony_ci FREE(trans); 1378bf215546Sopenharmony_ci return NULL; 1379bf215546Sopenharmony_ci } 1380bf215546Sopenharmony_ci 1381bf215546Sopenharmony_ci if (usage & PIPE_MAP_READ) { 1382bf215546Sopenharmony_ci struct pipe_resource *temp = ctx->screen->resource_create(ctx->screen, &resource); 1383bf215546Sopenharmony_ci if (!temp) { 1384bf215546Sopenharmony_ci R600_ERR("failed to create a temporary depth texture\n"); 1385bf215546Sopenharmony_ci FREE(trans); 1386bf215546Sopenharmony_ci return NULL; 1387bf215546Sopenharmony_ci } 1388bf215546Sopenharmony_ci 1389bf215546Sopenharmony_ci r600_copy_region_with_blit(ctx, temp, 0, 0, 0, 0, texture, level, box); 1390bf215546Sopenharmony_ci rctx->blit_decompress_depth(ctx, (struct r600_texture*)temp, staging_depth, 1391bf215546Sopenharmony_ci 0, 0, 0, box->depth, 0, 0); 1392bf215546Sopenharmony_ci pipe_resource_reference(&temp, NULL); 1393bf215546Sopenharmony_ci } 1394bf215546Sopenharmony_ci 1395bf215546Sopenharmony_ci /* Just get the strides. */ 1396bf215546Sopenharmony_ci r600_texture_get_offset(rctx->screen, staging_depth, level, NULL, 1397bf215546Sopenharmony_ci &trans->b.b.stride, 1398bf215546Sopenharmony_ci &trans->b.b.layer_stride); 1399bf215546Sopenharmony_ci } else { 1400bf215546Sopenharmony_ci /* XXX: only readback the rectangle which is being mapped? */ 1401bf215546Sopenharmony_ci /* XXX: when discard is true, no need to read back from depth texture */ 1402bf215546Sopenharmony_ci if (!r600_init_flushed_depth_texture(ctx, texture, &staging_depth)) { 1403bf215546Sopenharmony_ci R600_ERR("failed to create temporary texture to hold untiled copy\n"); 1404bf215546Sopenharmony_ci FREE(trans); 1405bf215546Sopenharmony_ci return NULL; 1406bf215546Sopenharmony_ci } 1407bf215546Sopenharmony_ci 1408bf215546Sopenharmony_ci rctx->blit_decompress_depth(ctx, rtex, staging_depth, 1409bf215546Sopenharmony_ci level, level, 1410bf215546Sopenharmony_ci box->z, box->z + box->depth - 1, 1411bf215546Sopenharmony_ci 0, 0); 1412bf215546Sopenharmony_ci 1413bf215546Sopenharmony_ci offset = r600_texture_get_offset(rctx->screen, staging_depth, 1414bf215546Sopenharmony_ci level, box, 1415bf215546Sopenharmony_ci &trans->b.b.stride, 1416bf215546Sopenharmony_ci &trans->b.b.layer_stride); 1417bf215546Sopenharmony_ci } 1418bf215546Sopenharmony_ci 1419bf215546Sopenharmony_ci trans->staging = (struct r600_resource*)staging_depth; 1420bf215546Sopenharmony_ci buf = trans->staging; 1421bf215546Sopenharmony_ci } else if (use_staging_texture) { 1422bf215546Sopenharmony_ci struct pipe_resource resource; 1423bf215546Sopenharmony_ci struct r600_texture *staging; 1424bf215546Sopenharmony_ci 1425bf215546Sopenharmony_ci r600_init_temp_resource_from_box(&resource, texture, box, level, 1426bf215546Sopenharmony_ci R600_RESOURCE_FLAG_TRANSFER); 1427bf215546Sopenharmony_ci resource.usage = (usage & PIPE_MAP_READ) ? 1428bf215546Sopenharmony_ci PIPE_USAGE_STAGING : PIPE_USAGE_STREAM; 1429bf215546Sopenharmony_ci 1430bf215546Sopenharmony_ci /* Create the temporary texture. */ 1431bf215546Sopenharmony_ci staging = (struct r600_texture*)ctx->screen->resource_create(ctx->screen, &resource); 1432bf215546Sopenharmony_ci if (!staging) { 1433bf215546Sopenharmony_ci R600_ERR("failed to create temporary texture to hold untiled copy\n"); 1434bf215546Sopenharmony_ci FREE(trans); 1435bf215546Sopenharmony_ci return NULL; 1436bf215546Sopenharmony_ci } 1437bf215546Sopenharmony_ci trans->staging = &staging->resource; 1438bf215546Sopenharmony_ci 1439bf215546Sopenharmony_ci /* Just get the strides. */ 1440bf215546Sopenharmony_ci r600_texture_get_offset(rctx->screen, staging, 0, NULL, 1441bf215546Sopenharmony_ci &trans->b.b.stride, 1442bf215546Sopenharmony_ci &trans->b.b.layer_stride); 1443bf215546Sopenharmony_ci 1444bf215546Sopenharmony_ci if (usage & PIPE_MAP_READ) 1445bf215546Sopenharmony_ci r600_copy_to_staging_texture(ctx, trans); 1446bf215546Sopenharmony_ci else 1447bf215546Sopenharmony_ci usage |= PIPE_MAP_UNSYNCHRONIZED; 1448bf215546Sopenharmony_ci 1449bf215546Sopenharmony_ci buf = trans->staging; 1450bf215546Sopenharmony_ci } else { 1451bf215546Sopenharmony_ci /* the resource is mapped directly */ 1452bf215546Sopenharmony_ci offset = r600_texture_get_offset(rctx->screen, rtex, level, box, 1453bf215546Sopenharmony_ci &trans->b.b.stride, 1454bf215546Sopenharmony_ci &trans->b.b.layer_stride); 1455bf215546Sopenharmony_ci buf = &rtex->resource; 1456bf215546Sopenharmony_ci } 1457bf215546Sopenharmony_ci 1458bf215546Sopenharmony_ci if (!(map = r600_buffer_map_sync_with_rings(rctx, buf, usage))) { 1459bf215546Sopenharmony_ci r600_resource_reference(&trans->staging, NULL); 1460bf215546Sopenharmony_ci FREE(trans); 1461bf215546Sopenharmony_ci return NULL; 1462bf215546Sopenharmony_ci } 1463bf215546Sopenharmony_ci 1464bf215546Sopenharmony_ci *ptransfer = &trans->b.b; 1465bf215546Sopenharmony_ci return map + offset; 1466bf215546Sopenharmony_ci} 1467bf215546Sopenharmony_ci 1468bf215546Sopenharmony_civoid r600_texture_transfer_unmap(struct pipe_context *ctx, 1469bf215546Sopenharmony_ci struct pipe_transfer* transfer) 1470bf215546Sopenharmony_ci{ 1471bf215546Sopenharmony_ci struct r600_common_context *rctx = (struct r600_common_context*)ctx; 1472bf215546Sopenharmony_ci struct r600_transfer *rtransfer = (struct r600_transfer*)transfer; 1473bf215546Sopenharmony_ci struct pipe_resource *texture = transfer->resource; 1474bf215546Sopenharmony_ci struct r600_texture *rtex = (struct r600_texture*)texture; 1475bf215546Sopenharmony_ci 1476bf215546Sopenharmony_ci if ((transfer->usage & PIPE_MAP_WRITE) && rtransfer->staging) { 1477bf215546Sopenharmony_ci if (rtex->is_depth && rtex->resource.b.b.nr_samples <= 1) { 1478bf215546Sopenharmony_ci ctx->resource_copy_region(ctx, texture, transfer->level, 1479bf215546Sopenharmony_ci transfer->box.x, transfer->box.y, transfer->box.z, 1480bf215546Sopenharmony_ci &rtransfer->staging->b.b, transfer->level, 1481bf215546Sopenharmony_ci &transfer->box); 1482bf215546Sopenharmony_ci } else { 1483bf215546Sopenharmony_ci r600_copy_from_staging_texture(ctx, rtransfer); 1484bf215546Sopenharmony_ci } 1485bf215546Sopenharmony_ci } 1486bf215546Sopenharmony_ci 1487bf215546Sopenharmony_ci if (rtransfer->staging) { 1488bf215546Sopenharmony_ci rctx->num_alloc_tex_transfer_bytes += rtransfer->staging->buf->size; 1489bf215546Sopenharmony_ci r600_resource_reference(&rtransfer->staging, NULL); 1490bf215546Sopenharmony_ci } 1491bf215546Sopenharmony_ci 1492bf215546Sopenharmony_ci /* Heuristic for {upload, draw, upload, draw, ..}: 1493bf215546Sopenharmony_ci * 1494bf215546Sopenharmony_ci * Flush the gfx IB if we've allocated too much texture storage. 1495bf215546Sopenharmony_ci * 1496bf215546Sopenharmony_ci * The idea is that we don't want to build IBs that use too much 1497bf215546Sopenharmony_ci * memory and put pressure on the kernel memory manager and we also 1498bf215546Sopenharmony_ci * want to make temporary and invalidated buffers go idle ASAP to 1499bf215546Sopenharmony_ci * decrease the total memory usage or make them reusable. The memory 1500bf215546Sopenharmony_ci * usage will be slightly higher than given here because of the buffer 1501bf215546Sopenharmony_ci * cache in the winsys. 1502bf215546Sopenharmony_ci * 1503bf215546Sopenharmony_ci * The result is that the kernel memory manager is never a bottleneck. 1504bf215546Sopenharmony_ci */ 1505bf215546Sopenharmony_ci if (rctx->num_alloc_tex_transfer_bytes > (uint64_t)rctx->screen->info.gart_size_kb * 1024 / 4) { 1506bf215546Sopenharmony_ci rctx->gfx.flush(rctx, PIPE_FLUSH_ASYNC, NULL); 1507bf215546Sopenharmony_ci rctx->num_alloc_tex_transfer_bytes = 0; 1508bf215546Sopenharmony_ci } 1509bf215546Sopenharmony_ci 1510bf215546Sopenharmony_ci pipe_resource_reference(&transfer->resource, NULL); 1511bf215546Sopenharmony_ci FREE(transfer); 1512bf215546Sopenharmony_ci} 1513bf215546Sopenharmony_ci 1514bf215546Sopenharmony_cistruct pipe_surface *r600_create_surface_custom(struct pipe_context *pipe, 1515bf215546Sopenharmony_ci struct pipe_resource *texture, 1516bf215546Sopenharmony_ci const struct pipe_surface *templ, 1517bf215546Sopenharmony_ci unsigned width0, unsigned height0, 1518bf215546Sopenharmony_ci unsigned width, unsigned height) 1519bf215546Sopenharmony_ci{ 1520bf215546Sopenharmony_ci struct r600_surface *surface = CALLOC_STRUCT(r600_surface); 1521bf215546Sopenharmony_ci 1522bf215546Sopenharmony_ci if (!surface) 1523bf215546Sopenharmony_ci return NULL; 1524bf215546Sopenharmony_ci 1525bf215546Sopenharmony_ci assert(templ->u.tex.first_layer <= util_max_layer(texture, templ->u.tex.level)); 1526bf215546Sopenharmony_ci assert(templ->u.tex.last_layer <= util_max_layer(texture, templ->u.tex.level)); 1527bf215546Sopenharmony_ci 1528bf215546Sopenharmony_ci pipe_reference_init(&surface->base.reference, 1); 1529bf215546Sopenharmony_ci pipe_resource_reference(&surface->base.texture, texture); 1530bf215546Sopenharmony_ci surface->base.context = pipe; 1531bf215546Sopenharmony_ci surface->base.format = templ->format; 1532bf215546Sopenharmony_ci surface->base.width = width; 1533bf215546Sopenharmony_ci surface->base.height = height; 1534bf215546Sopenharmony_ci surface->base.u = templ->u; 1535bf215546Sopenharmony_ci 1536bf215546Sopenharmony_ci surface->width0 = width0; 1537bf215546Sopenharmony_ci surface->height0 = height0; 1538bf215546Sopenharmony_ci 1539bf215546Sopenharmony_ci return &surface->base; 1540bf215546Sopenharmony_ci} 1541bf215546Sopenharmony_ci 1542bf215546Sopenharmony_cistatic struct pipe_surface *r600_create_surface(struct pipe_context *pipe, 1543bf215546Sopenharmony_ci struct pipe_resource *tex, 1544bf215546Sopenharmony_ci const struct pipe_surface *templ) 1545bf215546Sopenharmony_ci{ 1546bf215546Sopenharmony_ci unsigned level = templ->u.tex.level; 1547bf215546Sopenharmony_ci unsigned width = u_minify(tex->width0, level); 1548bf215546Sopenharmony_ci unsigned height = u_minify(tex->height0, level); 1549bf215546Sopenharmony_ci unsigned width0 = tex->width0; 1550bf215546Sopenharmony_ci unsigned height0 = tex->height0; 1551bf215546Sopenharmony_ci 1552bf215546Sopenharmony_ci if (tex->target != PIPE_BUFFER && templ->format != tex->format) { 1553bf215546Sopenharmony_ci const struct util_format_description *tex_desc 1554bf215546Sopenharmony_ci = util_format_description(tex->format); 1555bf215546Sopenharmony_ci const struct util_format_description *templ_desc 1556bf215546Sopenharmony_ci = util_format_description(templ->format); 1557bf215546Sopenharmony_ci 1558bf215546Sopenharmony_ci assert(tex_desc->block.bits == templ_desc->block.bits); 1559bf215546Sopenharmony_ci 1560bf215546Sopenharmony_ci /* Adjust size of surface if and only if the block width or 1561bf215546Sopenharmony_ci * height is changed. */ 1562bf215546Sopenharmony_ci if (tex_desc->block.width != templ_desc->block.width || 1563bf215546Sopenharmony_ci tex_desc->block.height != templ_desc->block.height) { 1564bf215546Sopenharmony_ci unsigned nblks_x = util_format_get_nblocksx(tex->format, width); 1565bf215546Sopenharmony_ci unsigned nblks_y = util_format_get_nblocksy(tex->format, height); 1566bf215546Sopenharmony_ci 1567bf215546Sopenharmony_ci width = nblks_x * templ_desc->block.width; 1568bf215546Sopenharmony_ci height = nblks_y * templ_desc->block.height; 1569bf215546Sopenharmony_ci 1570bf215546Sopenharmony_ci width0 = util_format_get_nblocksx(tex->format, width0); 1571bf215546Sopenharmony_ci height0 = util_format_get_nblocksy(tex->format, height0); 1572bf215546Sopenharmony_ci } 1573bf215546Sopenharmony_ci } 1574bf215546Sopenharmony_ci 1575bf215546Sopenharmony_ci return r600_create_surface_custom(pipe, tex, templ, 1576bf215546Sopenharmony_ci width0, height0, 1577bf215546Sopenharmony_ci width, height); 1578bf215546Sopenharmony_ci} 1579bf215546Sopenharmony_ci 1580bf215546Sopenharmony_cistatic void r600_surface_destroy(struct pipe_context *pipe, 1581bf215546Sopenharmony_ci struct pipe_surface *surface) 1582bf215546Sopenharmony_ci{ 1583bf215546Sopenharmony_ci struct r600_surface *surf = (struct r600_surface*)surface; 1584bf215546Sopenharmony_ci r600_resource_reference(&surf->cb_buffer_fmask, NULL); 1585bf215546Sopenharmony_ci r600_resource_reference(&surf->cb_buffer_cmask, NULL); 1586bf215546Sopenharmony_ci pipe_resource_reference(&surface->texture, NULL); 1587bf215546Sopenharmony_ci FREE(surface); 1588bf215546Sopenharmony_ci} 1589bf215546Sopenharmony_ci 1590bf215546Sopenharmony_cistatic void r600_clear_texture(struct pipe_context *pipe, 1591bf215546Sopenharmony_ci struct pipe_resource *tex, 1592bf215546Sopenharmony_ci unsigned level, 1593bf215546Sopenharmony_ci const struct pipe_box *box, 1594bf215546Sopenharmony_ci const void *data) 1595bf215546Sopenharmony_ci{ 1596bf215546Sopenharmony_ci struct pipe_screen *screen = pipe->screen; 1597bf215546Sopenharmony_ci struct r600_texture *rtex = (struct r600_texture*)tex; 1598bf215546Sopenharmony_ci struct pipe_surface tmpl = {{0}}; 1599bf215546Sopenharmony_ci struct pipe_surface *sf; 1600bf215546Sopenharmony_ci 1601bf215546Sopenharmony_ci tmpl.format = tex->format; 1602bf215546Sopenharmony_ci tmpl.u.tex.first_layer = box->z; 1603bf215546Sopenharmony_ci tmpl.u.tex.last_layer = box->z + box->depth - 1; 1604bf215546Sopenharmony_ci tmpl.u.tex.level = level; 1605bf215546Sopenharmony_ci sf = pipe->create_surface(pipe, tex, &tmpl); 1606bf215546Sopenharmony_ci if (!sf) 1607bf215546Sopenharmony_ci return; 1608bf215546Sopenharmony_ci 1609bf215546Sopenharmony_ci if (rtex->is_depth) { 1610bf215546Sopenharmony_ci unsigned clear; 1611bf215546Sopenharmony_ci float depth; 1612bf215546Sopenharmony_ci uint8_t stencil = 0; 1613bf215546Sopenharmony_ci 1614bf215546Sopenharmony_ci /* Depth is always present. */ 1615bf215546Sopenharmony_ci clear = PIPE_CLEAR_DEPTH; 1616bf215546Sopenharmony_ci util_format_unpack_z_float(tex->format, &depth, data, 1); 1617bf215546Sopenharmony_ci 1618bf215546Sopenharmony_ci if (rtex->surface.has_stencil) { 1619bf215546Sopenharmony_ci clear |= PIPE_CLEAR_STENCIL; 1620bf215546Sopenharmony_ci util_format_unpack_s_8uint(tex->format, &stencil, data, 1); 1621bf215546Sopenharmony_ci } 1622bf215546Sopenharmony_ci 1623bf215546Sopenharmony_ci pipe->clear_depth_stencil(pipe, sf, clear, depth, stencil, 1624bf215546Sopenharmony_ci box->x, box->y, 1625bf215546Sopenharmony_ci box->width, box->height, false); 1626bf215546Sopenharmony_ci } else { 1627bf215546Sopenharmony_ci union pipe_color_union color; 1628bf215546Sopenharmony_ci 1629bf215546Sopenharmony_ci util_format_unpack_rgba(tex->format, color.ui, data, 1); 1630bf215546Sopenharmony_ci 1631bf215546Sopenharmony_ci if (screen->is_format_supported(screen, tex->format, 1632bf215546Sopenharmony_ci tex->target, 0, 0, 1633bf215546Sopenharmony_ci PIPE_BIND_RENDER_TARGET)) { 1634bf215546Sopenharmony_ci pipe->clear_render_target(pipe, sf, &color, 1635bf215546Sopenharmony_ci box->x, box->y, 1636bf215546Sopenharmony_ci box->width, box->height, false); 1637bf215546Sopenharmony_ci } else { 1638bf215546Sopenharmony_ci /* Software fallback - just for R9G9B9E5_FLOAT */ 1639bf215546Sopenharmony_ci util_clear_render_target(pipe, sf, &color, 1640bf215546Sopenharmony_ci box->x, box->y, 1641bf215546Sopenharmony_ci box->width, box->height); 1642bf215546Sopenharmony_ci } 1643bf215546Sopenharmony_ci } 1644bf215546Sopenharmony_ci pipe_surface_reference(&sf, NULL); 1645bf215546Sopenharmony_ci} 1646bf215546Sopenharmony_ci 1647bf215546Sopenharmony_ciunsigned r600_translate_colorswap(enum pipe_format format, bool do_endian_swap) 1648bf215546Sopenharmony_ci{ 1649bf215546Sopenharmony_ci const struct util_format_description *desc = util_format_description(format); 1650bf215546Sopenharmony_ci 1651bf215546Sopenharmony_ci#define HAS_SWIZZLE(chan,swz) (desc->swizzle[chan] == PIPE_SWIZZLE_##swz) 1652bf215546Sopenharmony_ci 1653bf215546Sopenharmony_ci if (format == PIPE_FORMAT_R11G11B10_FLOAT) /* isn't plain */ 1654bf215546Sopenharmony_ci return V_0280A0_SWAP_STD; 1655bf215546Sopenharmony_ci 1656bf215546Sopenharmony_ci if (desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) 1657bf215546Sopenharmony_ci return ~0U; 1658bf215546Sopenharmony_ci 1659bf215546Sopenharmony_ci switch (desc->nr_channels) { 1660bf215546Sopenharmony_ci case 1: 1661bf215546Sopenharmony_ci if (HAS_SWIZZLE(0,X)) 1662bf215546Sopenharmony_ci return V_0280A0_SWAP_STD; /* X___ */ 1663bf215546Sopenharmony_ci else if (HAS_SWIZZLE(3,X)) 1664bf215546Sopenharmony_ci return V_0280A0_SWAP_ALT_REV; /* ___X */ 1665bf215546Sopenharmony_ci break; 1666bf215546Sopenharmony_ci case 2: 1667bf215546Sopenharmony_ci if ((HAS_SWIZZLE(0,X) && HAS_SWIZZLE(1,Y)) || 1668bf215546Sopenharmony_ci (HAS_SWIZZLE(0,X) && HAS_SWIZZLE(1,NONE)) || 1669bf215546Sopenharmony_ci (HAS_SWIZZLE(0,NONE) && HAS_SWIZZLE(1,Y))) 1670bf215546Sopenharmony_ci return V_0280A0_SWAP_STD; /* XY__ */ 1671bf215546Sopenharmony_ci else if ((HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(1,X)) || 1672bf215546Sopenharmony_ci (HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(1,NONE)) || 1673bf215546Sopenharmony_ci (HAS_SWIZZLE(0,NONE) && HAS_SWIZZLE(1,X))) 1674bf215546Sopenharmony_ci /* YX__ */ 1675bf215546Sopenharmony_ci return (do_endian_swap ? V_0280A0_SWAP_STD : V_0280A0_SWAP_STD_REV); 1676bf215546Sopenharmony_ci else if (HAS_SWIZZLE(0,X) && HAS_SWIZZLE(3,Y)) 1677bf215546Sopenharmony_ci return V_0280A0_SWAP_ALT; /* X__Y */ 1678bf215546Sopenharmony_ci else if (HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(3,X)) 1679bf215546Sopenharmony_ci return V_0280A0_SWAP_ALT_REV; /* Y__X */ 1680bf215546Sopenharmony_ci break; 1681bf215546Sopenharmony_ci case 3: 1682bf215546Sopenharmony_ci if (HAS_SWIZZLE(0,X)) 1683bf215546Sopenharmony_ci return (do_endian_swap ? V_0280A0_SWAP_STD_REV : V_0280A0_SWAP_STD); 1684bf215546Sopenharmony_ci else if (HAS_SWIZZLE(0,Z)) 1685bf215546Sopenharmony_ci return V_0280A0_SWAP_STD_REV; /* ZYX */ 1686bf215546Sopenharmony_ci break; 1687bf215546Sopenharmony_ci case 4: 1688bf215546Sopenharmony_ci /* check the middle channels, the 1st and 4th channel can be NONE */ 1689bf215546Sopenharmony_ci if (HAS_SWIZZLE(1,Y) && HAS_SWIZZLE(2,Z)) { 1690bf215546Sopenharmony_ci return V_0280A0_SWAP_STD; /* XYZW */ 1691bf215546Sopenharmony_ci } else if (HAS_SWIZZLE(1,Z) && HAS_SWIZZLE(2,Y)) { 1692bf215546Sopenharmony_ci return V_0280A0_SWAP_STD_REV; /* WZYX */ 1693bf215546Sopenharmony_ci } else if (HAS_SWIZZLE(1,Y) && HAS_SWIZZLE(2,X)) { 1694bf215546Sopenharmony_ci return V_0280A0_SWAP_ALT; /* ZYXW */ 1695bf215546Sopenharmony_ci } else if (HAS_SWIZZLE(1,Z) && HAS_SWIZZLE(2,W)) { 1696bf215546Sopenharmony_ci /* YZWX */ 1697bf215546Sopenharmony_ci if (desc->is_array) 1698bf215546Sopenharmony_ci return V_0280A0_SWAP_ALT_REV; 1699bf215546Sopenharmony_ci else 1700bf215546Sopenharmony_ci return (do_endian_swap ? V_0280A0_SWAP_ALT : V_0280A0_SWAP_ALT_REV); 1701bf215546Sopenharmony_ci } 1702bf215546Sopenharmony_ci break; 1703bf215546Sopenharmony_ci } 1704bf215546Sopenharmony_ci return ~0U; 1705bf215546Sopenharmony_ci} 1706bf215546Sopenharmony_ci 1707bf215546Sopenharmony_ci/* FAST COLOR CLEAR */ 1708bf215546Sopenharmony_ci 1709bf215546Sopenharmony_cistatic void evergreen_set_clear_color(struct r600_texture *rtex, 1710bf215546Sopenharmony_ci enum pipe_format surface_format, 1711bf215546Sopenharmony_ci const union pipe_color_union *color) 1712bf215546Sopenharmony_ci{ 1713bf215546Sopenharmony_ci union util_color uc; 1714bf215546Sopenharmony_ci 1715bf215546Sopenharmony_ci memset(&uc, 0, sizeof(uc)); 1716bf215546Sopenharmony_ci 1717bf215546Sopenharmony_ci if (rtex->surface.bpe == 16) { 1718bf215546Sopenharmony_ci /* DCC fast clear only: 1719bf215546Sopenharmony_ci * CLEAR_WORD0 = R = G = B 1720bf215546Sopenharmony_ci * CLEAR_WORD1 = A 1721bf215546Sopenharmony_ci */ 1722bf215546Sopenharmony_ci assert(color->ui[0] == color->ui[1] && 1723bf215546Sopenharmony_ci color->ui[0] == color->ui[2]); 1724bf215546Sopenharmony_ci uc.ui[0] = color->ui[0]; 1725bf215546Sopenharmony_ci uc.ui[1] = color->ui[3]; 1726bf215546Sopenharmony_ci } else { 1727bf215546Sopenharmony_ci util_pack_color_union(surface_format, &uc, color); 1728bf215546Sopenharmony_ci } 1729bf215546Sopenharmony_ci 1730bf215546Sopenharmony_ci memcpy(rtex->color_clear_value, &uc, 2 * sizeof(uint32_t)); 1731bf215546Sopenharmony_ci} 1732bf215546Sopenharmony_ci 1733bf215546Sopenharmony_civoid evergreen_do_fast_color_clear(struct r600_common_context *rctx, 1734bf215546Sopenharmony_ci struct pipe_framebuffer_state *fb, 1735bf215546Sopenharmony_ci struct r600_atom *fb_state, 1736bf215546Sopenharmony_ci unsigned *buffers, ubyte *dirty_cbufs, 1737bf215546Sopenharmony_ci const union pipe_color_union *color) 1738bf215546Sopenharmony_ci{ 1739bf215546Sopenharmony_ci int i; 1740bf215546Sopenharmony_ci 1741bf215546Sopenharmony_ci /* This function is broken in BE, so just disable this path for now */ 1742bf215546Sopenharmony_ci#if UTIL_ARCH_BIG_ENDIAN 1743bf215546Sopenharmony_ci return; 1744bf215546Sopenharmony_ci#endif 1745bf215546Sopenharmony_ci 1746bf215546Sopenharmony_ci if (rctx->render_cond) 1747bf215546Sopenharmony_ci return; 1748bf215546Sopenharmony_ci 1749bf215546Sopenharmony_ci for (i = 0; i < fb->nr_cbufs; i++) { 1750bf215546Sopenharmony_ci struct r600_texture *tex; 1751bf215546Sopenharmony_ci unsigned clear_bit = PIPE_CLEAR_COLOR0 << i; 1752bf215546Sopenharmony_ci 1753bf215546Sopenharmony_ci if (!fb->cbufs[i]) 1754bf215546Sopenharmony_ci continue; 1755bf215546Sopenharmony_ci 1756bf215546Sopenharmony_ci /* if this colorbuffer is not being cleared */ 1757bf215546Sopenharmony_ci if (!(*buffers & clear_bit)) 1758bf215546Sopenharmony_ci continue; 1759bf215546Sopenharmony_ci 1760bf215546Sopenharmony_ci tex = (struct r600_texture *)fb->cbufs[i]->texture; 1761bf215546Sopenharmony_ci 1762bf215546Sopenharmony_ci /* the clear is allowed if all layers are bound */ 1763bf215546Sopenharmony_ci if (fb->cbufs[i]->u.tex.first_layer != 0 || 1764bf215546Sopenharmony_ci fb->cbufs[i]->u.tex.last_layer != util_max_layer(&tex->resource.b.b, 0)) { 1765bf215546Sopenharmony_ci continue; 1766bf215546Sopenharmony_ci } 1767bf215546Sopenharmony_ci 1768bf215546Sopenharmony_ci /* cannot clear mipmapped textures */ 1769bf215546Sopenharmony_ci if (fb->cbufs[i]->texture->last_level != 0) { 1770bf215546Sopenharmony_ci continue; 1771bf215546Sopenharmony_ci } 1772bf215546Sopenharmony_ci 1773bf215546Sopenharmony_ci /* only supported on tiled surfaces */ 1774bf215546Sopenharmony_ci if (tex->surface.is_linear) { 1775bf215546Sopenharmony_ci continue; 1776bf215546Sopenharmony_ci } 1777bf215546Sopenharmony_ci 1778bf215546Sopenharmony_ci /* shared textures can't use fast clear without an explicit flush, 1779bf215546Sopenharmony_ci * because there is no way to communicate the clear color among 1780bf215546Sopenharmony_ci * all clients 1781bf215546Sopenharmony_ci */ 1782bf215546Sopenharmony_ci if (tex->resource.b.is_shared && 1783bf215546Sopenharmony_ci !(tex->resource.external_usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH)) 1784bf215546Sopenharmony_ci continue; 1785bf215546Sopenharmony_ci 1786bf215546Sopenharmony_ci /* Use a slow clear for small surfaces where the cost of 1787bf215546Sopenharmony_ci * the eliminate pass can be higher than the benefit of fast 1788bf215546Sopenharmony_ci * clear. AMDGPU-pro does this, but the numbers may differ. 1789bf215546Sopenharmony_ci * 1790bf215546Sopenharmony_ci * This helps on both dGPUs and APUs, even small ones. 1791bf215546Sopenharmony_ci */ 1792bf215546Sopenharmony_ci if (tex->resource.b.b.nr_samples <= 1 && 1793bf215546Sopenharmony_ci tex->resource.b.b.width0 * tex->resource.b.b.height0 <= 300 * 300) 1794bf215546Sopenharmony_ci continue; 1795bf215546Sopenharmony_ci 1796bf215546Sopenharmony_ci { 1797bf215546Sopenharmony_ci /* 128-bit formats are unusupported */ 1798bf215546Sopenharmony_ci if (tex->surface.bpe > 8) { 1799bf215546Sopenharmony_ci continue; 1800bf215546Sopenharmony_ci } 1801bf215546Sopenharmony_ci 1802bf215546Sopenharmony_ci /* ensure CMASK is enabled */ 1803bf215546Sopenharmony_ci r600_texture_alloc_cmask_separate(rctx->screen, tex); 1804bf215546Sopenharmony_ci if (tex->cmask.size == 0) { 1805bf215546Sopenharmony_ci continue; 1806bf215546Sopenharmony_ci } 1807bf215546Sopenharmony_ci 1808bf215546Sopenharmony_ci /* Do the fast clear. */ 1809bf215546Sopenharmony_ci rctx->clear_buffer(&rctx->b, &tex->cmask_buffer->b.b, 1810bf215546Sopenharmony_ci tex->cmask.offset, tex->cmask.size, 0, 1811bf215546Sopenharmony_ci R600_COHERENCY_CB_META); 1812bf215546Sopenharmony_ci 1813bf215546Sopenharmony_ci bool need_compressed_update = !tex->dirty_level_mask; 1814bf215546Sopenharmony_ci 1815bf215546Sopenharmony_ci tex->dirty_level_mask |= 1 << fb->cbufs[i]->u.tex.level; 1816bf215546Sopenharmony_ci 1817bf215546Sopenharmony_ci if (need_compressed_update) 1818bf215546Sopenharmony_ci p_atomic_inc(&rctx->screen->compressed_colortex_counter); 1819bf215546Sopenharmony_ci } 1820bf215546Sopenharmony_ci 1821bf215546Sopenharmony_ci evergreen_set_clear_color(tex, fb->cbufs[i]->format, color); 1822bf215546Sopenharmony_ci 1823bf215546Sopenharmony_ci if (dirty_cbufs) 1824bf215546Sopenharmony_ci *dirty_cbufs |= 1 << i; 1825bf215546Sopenharmony_ci rctx->set_atom_dirty(rctx, fb_state, true); 1826bf215546Sopenharmony_ci *buffers &= ~clear_bit; 1827bf215546Sopenharmony_ci } 1828bf215546Sopenharmony_ci} 1829bf215546Sopenharmony_ci 1830bf215546Sopenharmony_cistatic struct pipe_memory_object * 1831bf215546Sopenharmony_cir600_memobj_from_handle(struct pipe_screen *screen, 1832bf215546Sopenharmony_ci struct winsys_handle *whandle, 1833bf215546Sopenharmony_ci bool dedicated) 1834bf215546Sopenharmony_ci{ 1835bf215546Sopenharmony_ci struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; 1836bf215546Sopenharmony_ci struct r600_memory_object *memobj = CALLOC_STRUCT(r600_memory_object); 1837bf215546Sopenharmony_ci struct pb_buffer *buf = NULL; 1838bf215546Sopenharmony_ci 1839bf215546Sopenharmony_ci if (!memobj) 1840bf215546Sopenharmony_ci return NULL; 1841bf215546Sopenharmony_ci 1842bf215546Sopenharmony_ci buf = rscreen->ws->buffer_from_handle(rscreen->ws, whandle, 1843bf215546Sopenharmony_ci rscreen->info.max_alignment, false); 1844bf215546Sopenharmony_ci if (!buf) { 1845bf215546Sopenharmony_ci free(memobj); 1846bf215546Sopenharmony_ci return NULL; 1847bf215546Sopenharmony_ci } 1848bf215546Sopenharmony_ci 1849bf215546Sopenharmony_ci memobj->b.dedicated = dedicated; 1850bf215546Sopenharmony_ci memobj->buf = buf; 1851bf215546Sopenharmony_ci memobj->stride = whandle->stride; 1852bf215546Sopenharmony_ci memobj->offset = whandle->offset; 1853bf215546Sopenharmony_ci 1854bf215546Sopenharmony_ci return (struct pipe_memory_object *)memobj; 1855bf215546Sopenharmony_ci 1856bf215546Sopenharmony_ci} 1857bf215546Sopenharmony_ci 1858bf215546Sopenharmony_cistatic void 1859bf215546Sopenharmony_cir600_memobj_destroy(struct pipe_screen *screen, 1860bf215546Sopenharmony_ci struct pipe_memory_object *_memobj) 1861bf215546Sopenharmony_ci{ 1862bf215546Sopenharmony_ci struct r600_memory_object *memobj = (struct r600_memory_object *)_memobj; 1863bf215546Sopenharmony_ci 1864bf215546Sopenharmony_ci pb_reference(&memobj->buf, NULL); 1865bf215546Sopenharmony_ci free(memobj); 1866bf215546Sopenharmony_ci} 1867bf215546Sopenharmony_ci 1868bf215546Sopenharmony_cistatic struct pipe_resource * 1869bf215546Sopenharmony_cir600_texture_from_memobj(struct pipe_screen *screen, 1870bf215546Sopenharmony_ci const struct pipe_resource *templ, 1871bf215546Sopenharmony_ci struct pipe_memory_object *_memobj, 1872bf215546Sopenharmony_ci uint64_t offset) 1873bf215546Sopenharmony_ci{ 1874bf215546Sopenharmony_ci int r; 1875bf215546Sopenharmony_ci struct r600_common_screen *rscreen = (struct r600_common_screen*)screen; 1876bf215546Sopenharmony_ci struct r600_memory_object *memobj = (struct r600_memory_object *)_memobj; 1877bf215546Sopenharmony_ci struct r600_texture *rtex; 1878bf215546Sopenharmony_ci struct radeon_surf surface = {}; 1879bf215546Sopenharmony_ci struct radeon_bo_metadata metadata = {}; 1880bf215546Sopenharmony_ci enum radeon_surf_mode array_mode; 1881bf215546Sopenharmony_ci bool is_scanout; 1882bf215546Sopenharmony_ci struct pb_buffer *buf = NULL; 1883bf215546Sopenharmony_ci 1884bf215546Sopenharmony_ci if (memobj->b.dedicated) { 1885bf215546Sopenharmony_ci rscreen->ws->buffer_get_metadata(rscreen->ws, memobj->buf, &metadata, NULL); 1886bf215546Sopenharmony_ci r600_surface_import_metadata(rscreen, &surface, &metadata, 1887bf215546Sopenharmony_ci &array_mode, &is_scanout); 1888bf215546Sopenharmony_ci } else { 1889bf215546Sopenharmony_ci /** 1890bf215546Sopenharmony_ci * The bo metadata is unset for un-dedicated images. So we fall 1891bf215546Sopenharmony_ci * back to linear. See answer to question 5 of the 1892bf215546Sopenharmony_ci * VK_KHX_external_memory spec for some details. 1893bf215546Sopenharmony_ci * 1894bf215546Sopenharmony_ci * It is possible that this case isn't going to work if the 1895bf215546Sopenharmony_ci * surface pitch isn't correctly aligned by default. 1896bf215546Sopenharmony_ci * 1897bf215546Sopenharmony_ci * In order to support it correctly we require multi-image 1898bf215546Sopenharmony_ci * metadata to be syncrhonized between radv and radeonsi. The 1899bf215546Sopenharmony_ci * semantics of associating multiple image metadata to a memory 1900bf215546Sopenharmony_ci * object on the vulkan export side are not concretely defined 1901bf215546Sopenharmony_ci * either. 1902bf215546Sopenharmony_ci * 1903bf215546Sopenharmony_ci * All the use cases we are aware of at the moment for memory 1904bf215546Sopenharmony_ci * objects use dedicated allocations. So lets keep the initial 1905bf215546Sopenharmony_ci * implementation simple. 1906bf215546Sopenharmony_ci * 1907bf215546Sopenharmony_ci * A possible alternative is to attempt to reconstruct the 1908bf215546Sopenharmony_ci * tiling information when the TexParameter TEXTURE_TILING_EXT 1909bf215546Sopenharmony_ci * is set. 1910bf215546Sopenharmony_ci */ 1911bf215546Sopenharmony_ci array_mode = RADEON_SURF_MODE_LINEAR_ALIGNED; 1912bf215546Sopenharmony_ci is_scanout = false; 1913bf215546Sopenharmony_ci 1914bf215546Sopenharmony_ci } 1915bf215546Sopenharmony_ci 1916bf215546Sopenharmony_ci r = r600_init_surface(rscreen, &surface, templ, 1917bf215546Sopenharmony_ci array_mode, memobj->stride, 1918bf215546Sopenharmony_ci offset, true, is_scanout, 1919bf215546Sopenharmony_ci false); 1920bf215546Sopenharmony_ci if (r) 1921bf215546Sopenharmony_ci return NULL; 1922bf215546Sopenharmony_ci 1923bf215546Sopenharmony_ci rtex = r600_texture_create_object(screen, templ, memobj->buf, &surface); 1924bf215546Sopenharmony_ci if (!rtex) 1925bf215546Sopenharmony_ci return NULL; 1926bf215546Sopenharmony_ci 1927bf215546Sopenharmony_ci /* r600_texture_create_object doesn't increment refcount of 1928bf215546Sopenharmony_ci * memobj->buf, so increment it here. 1929bf215546Sopenharmony_ci */ 1930bf215546Sopenharmony_ci pb_reference(&buf, memobj->buf); 1931bf215546Sopenharmony_ci 1932bf215546Sopenharmony_ci rtex->resource.b.is_shared = true; 1933bf215546Sopenharmony_ci rtex->resource.external_usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE; 1934bf215546Sopenharmony_ci 1935bf215546Sopenharmony_ci return &rtex->resource.b.b; 1936bf215546Sopenharmony_ci} 1937bf215546Sopenharmony_ci 1938bf215546Sopenharmony_civoid r600_init_screen_texture_functions(struct r600_common_screen *rscreen) 1939bf215546Sopenharmony_ci{ 1940bf215546Sopenharmony_ci rscreen->b.resource_from_handle = r600_texture_from_handle; 1941bf215546Sopenharmony_ci rscreen->b.resource_get_handle = r600_texture_get_handle; 1942bf215546Sopenharmony_ci rscreen->b.resource_get_info = r600_texture_get_info; 1943bf215546Sopenharmony_ci rscreen->b.resource_from_memobj = r600_texture_from_memobj; 1944bf215546Sopenharmony_ci rscreen->b.memobj_create_from_handle = r600_memobj_from_handle; 1945bf215546Sopenharmony_ci rscreen->b.memobj_destroy = r600_memobj_destroy; 1946bf215546Sopenharmony_ci} 1947bf215546Sopenharmony_ci 1948bf215546Sopenharmony_civoid r600_init_context_texture_functions(struct r600_common_context *rctx) 1949bf215546Sopenharmony_ci{ 1950bf215546Sopenharmony_ci rctx->b.create_surface = r600_create_surface; 1951bf215546Sopenharmony_ci rctx->b.surface_destroy = r600_surface_destroy; 1952bf215546Sopenharmony_ci rctx->b.clear_texture = r600_clear_texture; 1953bf215546Sopenharmony_ci} 1954