Path: blob/21.2-virgl/src/gallium/winsys/radeon/drm/radeon_drm_surface.c
4566 views
/*1* Copyright © 2014 Advanced Micro Devices, Inc.2* All Rights Reserved.3*4* Permission is hereby granted, free of charge, to any person obtaining5* a copy of this software and associated documentation files (the6* "Software"), to deal in the Software without restriction, including7* without limitation the rights to use, copy, modify, merge, publish,8* distribute, sub license, and/or sell copies of the Software, and to9* permit persons to whom the Software is furnished to do so, subject to10* the following conditions:11*12* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,13* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES14* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND15* NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS16* AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER17* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE19* USE OR OTHER DEALINGS IN THE SOFTWARE.20*21* The above copyright notice and this permission notice (including the22* next paragraph) shall be included in all copies or substantial portions23* of the Software.24*/2526#include "radeon_drm_winsys.h"27#include "util/format/u_format.h"28#include <radeon_surface.h>2930static unsigned cik_get_macro_tile_index(struct radeon_surf *surf)31{32unsigned index, tileb;3334tileb = 8 * 8 * surf->bpe;35tileb = MIN2(surf->u.legacy.tile_split, tileb);3637for (index = 0; tileb > 64; index++)38tileb >>= 1;3940assert(index < 16);41return index;42}4344#define G_009910_MICRO_TILE_MODE(x) (((x) >> 0) & 0x03)45#define G_009910_MICRO_TILE_MODE_NEW(x) (((x) >> 22) & 0x07)4647static void set_micro_tile_mode(struct radeon_surf *surf,48struct radeon_info *info)49{50uint32_t tile_mode;5152if (info->chip_class < GFX6) {53surf->micro_tile_mode = 0;54return;55}5657tile_mode = info->si_tile_mode_array[surf->u.legacy.tiling_index[0]];5859if (info->chip_class >= GFX7)60surf->micro_tile_mode = G_009910_MICRO_TILE_MODE_NEW(tile_mode);61else62surf->micro_tile_mode = G_009910_MICRO_TILE_MODE(tile_mode);63}6465static void surf_level_winsys_to_drm(struct radeon_surface_level *level_drm,66const struct legacy_surf_level *level_ws,67unsigned bpe)68{69level_drm->offset = (uint64_t)level_ws->offset_256B * 256;70level_drm->slice_size = (uint64_t)level_ws->slice_size_dw * 4;71level_drm->nblk_x = level_ws->nblk_x;72level_drm->nblk_y = level_ws->nblk_y;73level_drm->pitch_bytes = level_ws->nblk_x * bpe;74level_drm->mode = level_ws->mode;75}7677static void surf_level_drm_to_winsys(struct legacy_surf_level *level_ws,78const struct radeon_surface_level *level_drm,79unsigned bpe)80{81level_ws->offset_256B = level_drm->offset / 256;82level_ws->slice_size_dw = level_drm->slice_size / 4;83level_ws->nblk_x = level_drm->nblk_x;84level_ws->nblk_y = level_drm->nblk_y;85level_ws->mode = level_drm->mode;86assert(level_drm->nblk_x * bpe == level_drm->pitch_bytes);87}8889static void surf_winsys_to_drm(struct radeon_surface *surf_drm,90const struct pipe_resource *tex,91unsigned flags, unsigned bpe,92enum radeon_surf_mode mode,93const struct radeon_surf *surf_ws)94{95int i;9697memset(surf_drm, 0, sizeof(*surf_drm));9899surf_drm->npix_x = tex->width0;100surf_drm->npix_y = tex->height0;101surf_drm->npix_z = tex->depth0;102surf_drm->blk_w = util_format_get_blockwidth(tex->format);103surf_drm->blk_h = util_format_get_blockheight(tex->format);104surf_drm->blk_d = 1;105surf_drm->array_size = 1;106surf_drm->last_level = tex->last_level;107surf_drm->bpe = bpe;108surf_drm->nsamples = tex->nr_samples ? tex->nr_samples : 1;109110surf_drm->flags = flags;111surf_drm->flags = RADEON_SURF_CLR(surf_drm->flags, TYPE);112surf_drm->flags = RADEON_SURF_CLR(surf_drm->flags, MODE);113surf_drm->flags |= RADEON_SURF_SET(mode, MODE) |114RADEON_SURF_HAS_SBUFFER_MIPTREE |115RADEON_SURF_HAS_TILE_MODE_INDEX;116117switch (tex->target) {118case PIPE_TEXTURE_1D:119surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D, TYPE);120break;121case PIPE_TEXTURE_RECT:122case PIPE_TEXTURE_2D:123surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);124break;125case PIPE_TEXTURE_3D:126surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_3D, TYPE);127break;128case PIPE_TEXTURE_1D_ARRAY:129surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D_ARRAY, TYPE);130surf_drm->array_size = tex->array_size;131break;132case PIPE_TEXTURE_CUBE_ARRAY: /* cube array layout like 2d array */133assert(tex->array_size % 6 == 0);134FALLTHROUGH;135case PIPE_TEXTURE_2D_ARRAY:136surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D_ARRAY, TYPE);137surf_drm->array_size = tex->array_size;138break;139case PIPE_TEXTURE_CUBE:140surf_drm->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_CUBEMAP, TYPE);141break;142case PIPE_BUFFER:143default:144assert(0);145}146147surf_drm->bo_size = surf_ws->surf_size;148surf_drm->bo_alignment = 1 << surf_ws->surf_alignment_log2;149150surf_drm->bankw = surf_ws->u.legacy.bankw;151surf_drm->bankh = surf_ws->u.legacy.bankh;152surf_drm->mtilea = surf_ws->u.legacy.mtilea;153surf_drm->tile_split = surf_ws->u.legacy.tile_split;154155for (i = 0; i <= surf_drm->last_level; i++) {156surf_level_winsys_to_drm(&surf_drm->level[i], &surf_ws->u.legacy.level[i],157bpe * surf_drm->nsamples);158159surf_drm->tiling_index[i] = surf_ws->u.legacy.tiling_index[i];160}161162if (flags & RADEON_SURF_SBUFFER) {163surf_drm->stencil_tile_split = surf_ws->u.legacy.stencil_tile_split;164165for (i = 0; i <= surf_drm->last_level; i++) {166surf_level_winsys_to_drm(&surf_drm->stencil_level[i],167&surf_ws->u.legacy.zs.stencil_level[i],168surf_drm->nsamples);169surf_drm->stencil_tiling_index[i] = surf_ws->u.legacy.zs.stencil_tiling_index[i];170}171}172}173174static void surf_drm_to_winsys(struct radeon_drm_winsys *ws,175struct radeon_surf *surf_ws,176const struct radeon_surface *surf_drm)177{178int i;179180memset(surf_ws, 0, sizeof(*surf_ws));181182surf_ws->blk_w = surf_drm->blk_w;183surf_ws->blk_h = surf_drm->blk_h;184surf_ws->bpe = surf_drm->bpe;185surf_ws->is_linear = surf_drm->level[0].mode <= RADEON_SURF_MODE_LINEAR_ALIGNED;186surf_ws->has_stencil = !!(surf_drm->flags & RADEON_SURF_SBUFFER);187surf_ws->flags = surf_drm->flags;188189surf_ws->surf_size = surf_drm->bo_size;190surf_ws->surf_alignment_log2 = util_logbase2(surf_drm->bo_alignment);191192surf_ws->u.legacy.bankw = surf_drm->bankw;193surf_ws->u.legacy.bankh = surf_drm->bankh;194surf_ws->u.legacy.mtilea = surf_drm->mtilea;195surf_ws->u.legacy.tile_split = surf_drm->tile_split;196197surf_ws->u.legacy.macro_tile_index = cik_get_macro_tile_index(surf_ws);198199for (i = 0; i <= surf_drm->last_level; i++) {200surf_level_drm_to_winsys(&surf_ws->u.legacy.level[i], &surf_drm->level[i],201surf_drm->bpe * surf_drm->nsamples);202surf_ws->u.legacy.tiling_index[i] = surf_drm->tiling_index[i];203}204205if (surf_ws->flags & RADEON_SURF_SBUFFER) {206surf_ws->u.legacy.stencil_tile_split = surf_drm->stencil_tile_split;207208for (i = 0; i <= surf_drm->last_level; i++) {209surf_level_drm_to_winsys(&surf_ws->u.legacy.zs.stencil_level[i],210&surf_drm->stencil_level[i],211surf_drm->nsamples);212surf_ws->u.legacy.zs.stencil_tiling_index[i] = surf_drm->stencil_tiling_index[i];213}214}215216set_micro_tile_mode(surf_ws, &ws->info);217surf_ws->is_displayable = surf_ws->is_linear ||218surf_ws->micro_tile_mode == RADEON_MICRO_MODE_DISPLAY ||219surf_ws->micro_tile_mode == RADEON_MICRO_MODE_RENDER;220}221222static void si_compute_cmask(const struct radeon_info *info,223const struct ac_surf_config *config,224struct radeon_surf *surf)225{226unsigned pipe_interleave_bytes = info->pipe_interleave_bytes;227unsigned num_pipes = info->num_tile_pipes;228unsigned cl_width, cl_height;229230if (surf->flags & RADEON_SURF_Z_OR_SBUFFER)231return;232233assert(info->chip_class <= GFX8);234235switch (num_pipes) {236case 2:237cl_width = 32;238cl_height = 16;239break;240case 4:241cl_width = 32;242cl_height = 32;243break;244case 8:245cl_width = 64;246cl_height = 32;247break;248case 16: /* Hawaii */249cl_width = 64;250cl_height = 64;251break;252default:253assert(0);254return;255}256257unsigned base_align = num_pipes * pipe_interleave_bytes;258259unsigned width = align(surf->u.legacy.level[0].nblk_x, cl_width*8);260unsigned height = align(surf->u.legacy.level[0].nblk_y, cl_height*8);261unsigned slice_elements = (width * height) / (8*8);262263/* Each element of CMASK is a nibble. */264unsigned slice_bytes = slice_elements / 2;265266surf->u.legacy.color.cmask_slice_tile_max = (width * height) / (128*128);267if (surf->u.legacy.color.cmask_slice_tile_max)268surf->u.legacy.color.cmask_slice_tile_max -= 1;269270unsigned num_layers;271if (config->is_3d)272num_layers = config->info.depth;273else if (config->is_cube)274num_layers = 6;275else276num_layers = config->info.array_size;277278surf->cmask_alignment_log2 = util_logbase2(MAX2(256, base_align));279surf->cmask_size = align(slice_bytes, base_align) * num_layers;280}281282static void si_compute_htile(const struct radeon_info *info,283struct radeon_surf *surf, unsigned num_layers)284{285unsigned cl_width, cl_height, width, height;286unsigned slice_elements, slice_bytes, pipe_interleave_bytes, base_align;287unsigned num_pipes = info->num_tile_pipes;288289surf->meta_size = 0;290291if (!(surf->flags & RADEON_SURF_Z_OR_SBUFFER) ||292surf->flags & RADEON_SURF_NO_HTILE)293return;294295if (surf->u.legacy.level[0].mode == RADEON_SURF_MODE_1D &&296!info->htile_cmask_support_1d_tiling)297return;298299/* Overalign HTILE on P2 configs to work around GPU hangs in300* piglit/depthstencil-render-miplevels 585.301*302* This has been confirmed to help Kabini & Stoney, where the hangs303* are always reproducible. I think I have seen the test hang304* on Carrizo too, though it was very rare there.305*/306if (info->chip_class >= GFX7 && num_pipes < 4)307num_pipes = 4;308309switch (num_pipes) {310case 1:311cl_width = 32;312cl_height = 16;313break;314case 2:315cl_width = 32;316cl_height = 32;317break;318case 4:319cl_width = 64;320cl_height = 32;321break;322case 8:323cl_width = 64;324cl_height = 64;325break;326case 16:327cl_width = 128;328cl_height = 64;329break;330default:331assert(0);332return;333}334335width = align(surf->u.legacy.level[0].nblk_x, cl_width * 8);336height = align(surf->u.legacy.level[0].nblk_y, cl_height * 8);337338slice_elements = (width * height) / (8 * 8);339slice_bytes = slice_elements * 4;340341pipe_interleave_bytes = info->pipe_interleave_bytes;342base_align = num_pipes * pipe_interleave_bytes;343344surf->meta_alignment_log2 = util_logbase2(base_align);345surf->meta_size = num_layers * align(slice_bytes, base_align);346}347348static int radeon_winsys_surface_init(struct radeon_winsys *rws,349const struct pipe_resource *tex,350unsigned flags, unsigned bpe,351enum radeon_surf_mode mode,352struct radeon_surf *surf_ws)353{354struct radeon_drm_winsys *ws = (struct radeon_drm_winsys*)rws;355struct radeon_surface surf_drm;356int r;357358surf_winsys_to_drm(&surf_drm, tex, flags, bpe, mode, surf_ws);359360if (!(flags & (RADEON_SURF_IMPORTED | RADEON_SURF_FMASK))) {361r = radeon_surface_best(ws->surf_man, &surf_drm);362if (r)363return r;364}365366r = radeon_surface_init(ws->surf_man, &surf_drm);367if (r)368return r;369370surf_drm_to_winsys(ws, surf_ws, &surf_drm);371372/* Compute FMASK. */373if (ws->gen == DRV_SI &&374tex->nr_samples >= 2 &&375!(flags & (RADEON_SURF_Z_OR_SBUFFER | RADEON_SURF_FMASK | RADEON_SURF_NO_FMASK))) {376/* FMASK is allocated like an ordinary texture. */377struct pipe_resource templ = *tex;378struct radeon_surf fmask = {};379unsigned fmask_flags, bpe;380381templ.nr_samples = 1;382fmask_flags = flags | RADEON_SURF_FMASK;383384switch (tex->nr_samples) {385case 2:386case 4:387bpe = 1;388break;389case 8:390bpe = 4;391break;392default:393fprintf(stderr, "radeon: Invalid sample count for FMASK allocation.\n");394return -1;395}396397if (radeon_winsys_surface_init(rws, &templ, fmask_flags, bpe,398RADEON_SURF_MODE_2D, &fmask)) {399fprintf(stderr, "Got error in surface_init while allocating FMASK.\n");400return -1;401}402403assert(fmask.u.legacy.level[0].mode == RADEON_SURF_MODE_2D);404405surf_ws->fmask_size = fmask.surf_size;406surf_ws->fmask_alignment_log2 = util_logbase2(MAX2(256, 1 << fmask.surf_alignment_log2));407surf_ws->fmask_tile_swizzle = fmask.tile_swizzle;408409surf_ws->u.legacy.color.fmask.slice_tile_max =410(fmask.u.legacy.level[0].nblk_x * fmask.u.legacy.level[0].nblk_y) / 64;411if (surf_ws->u.legacy.color.fmask.slice_tile_max)412surf_ws->u.legacy.color.fmask.slice_tile_max -= 1;413414surf_ws->u.legacy.color.fmask.tiling_index = fmask.u.legacy.tiling_index[0];415surf_ws->u.legacy.color.fmask.bankh = fmask.u.legacy.bankh;416surf_ws->u.legacy.color.fmask.pitch_in_pixels = fmask.u.legacy.level[0].nblk_x;417}418419if (ws->gen == DRV_SI &&420(tex->nr_samples <= 1 || surf_ws->fmask_size)) {421struct ac_surf_config config;422423/* Only these fields need to be set for the CMASK computation. */424config.info.width = tex->width0;425config.info.height = tex->height0;426config.info.depth = tex->depth0;427config.info.array_size = tex->array_size;428config.is_3d = !!(tex->target == PIPE_TEXTURE_3D);429config.is_cube = !!(tex->target == PIPE_TEXTURE_CUBE);430431si_compute_cmask(&ws->info, &config, surf_ws);432}433434if (ws->gen == DRV_SI) {435si_compute_htile(&ws->info, surf_ws, util_num_layers(tex, 0));436437/* Determine the memory layout of multiple allocations in one buffer. */438surf_ws->total_size = surf_ws->surf_size;439440if (surf_ws->meta_size) {441surf_ws->meta_offset = align64(surf_ws->total_size, 1 << surf_ws->meta_alignment_log2);442surf_ws->total_size = surf_ws->meta_offset + surf_ws->meta_size;443}444445if (surf_ws->fmask_size) {446assert(tex->nr_samples >= 2);447surf_ws->fmask_offset = align64(surf_ws->total_size, 1 << surf_ws->fmask_alignment_log2);448surf_ws->total_size = surf_ws->fmask_offset + surf_ws->fmask_size;449}450451/* Single-sample CMASK is in a separate buffer. */452if (surf_ws->cmask_size && tex->nr_samples >= 2) {453surf_ws->cmask_offset = align64(surf_ws->total_size, 1 << surf_ws->cmask_alignment_log2);454surf_ws->total_size = surf_ws->cmask_offset + surf_ws->cmask_size;455}456}457458return 0;459}460461void radeon_surface_init_functions(struct radeon_drm_winsys *ws)462{463ws->base.surface_init = radeon_winsys_surface_init;464}465466467