Path: blob/21.2-virgl/src/gallium/drivers/nouveau/nv50/nv50_miptree.c
4574 views
/*1* Copyright 2008 Ben Skeggs2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*/2122#include "pipe/p_state.h"23#include "pipe/p_defines.h"24#include "util/u_inlines.h"25#include "util/format/u_format.h"2627#include "nv50/nv50_context.h"28#include "nv50/nv50_resource.h"2930uint32_t31nv50_tex_choose_tile_dims_helper(unsigned nx, unsigned ny, unsigned nz,32bool is_3d)33{34uint32_t tile_mode = 0x000;3536if (ny > 64) tile_mode = 0x040; /* height 128 tiles */37else38if (ny > 32) tile_mode = 0x030; /* height 64 tiles */39else40if (ny > 16) tile_mode = 0x020; /* height 32 tiles */41else42if (ny > 8) tile_mode = 0x010; /* height 16 tiles */4344if (!is_3d)45return tile_mode;46else47if (tile_mode > 0x020)48tile_mode = 0x020;4950if (nz > 16 && tile_mode < 0x020)51return tile_mode | 0x500; /* depth 32 tiles */52if (nz > 8) return tile_mode | 0x400; /* depth 16 tiles */53if (nz > 4) return tile_mode | 0x300; /* depth 8 tiles */54if (nz > 2) return tile_mode | 0x200; /* depth 4 tiles */55if (nz > 1) return tile_mode | 0x100; /* depth 2 tiles */5657return tile_mode;58}5960static uint32_t61nv50_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz, bool is_3d)62{63return nv50_tex_choose_tile_dims_helper(nx, ny * 2, nz, is_3d);64}6566static uint32_t67nv50_mt_choose_storage_type(struct nv50_miptree *mt, bool compressed)68{69const unsigned ms = util_logbase2(mt->base.base.nr_samples);70uint32_t tile_flags;7172if (unlikely(mt->base.base.flags & NOUVEAU_RESOURCE_FLAG_LINEAR))73return 0;74if (unlikely(mt->base.base.bind & PIPE_BIND_CURSOR))75return 0;7677switch (mt->base.base.format) {78case PIPE_FORMAT_Z16_UNORM:79tile_flags = 0x6c + ms;80break;81case PIPE_FORMAT_X8Z24_UNORM:82case PIPE_FORMAT_S8X24_UINT:83case PIPE_FORMAT_S8_UINT_Z24_UNORM:84tile_flags = 0x18 + ms;85break;86case PIPE_FORMAT_X24S8_UINT:87case PIPE_FORMAT_Z24X8_UNORM:88case PIPE_FORMAT_Z24_UNORM_S8_UINT:89tile_flags = 0x128 + ms;90break;91case PIPE_FORMAT_Z32_FLOAT:92tile_flags = 0x40 + ms;93break;94case PIPE_FORMAT_X32_S8X24_UINT:95case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:96tile_flags = 0x60 + ms;97break;98default:99/* Most color formats don't work with compression. */100compressed = false;101FALLTHROUGH;102case PIPE_FORMAT_R8G8B8A8_UNORM:103case PIPE_FORMAT_R8G8B8A8_SRGB:104case PIPE_FORMAT_R8G8B8X8_UNORM:105case PIPE_FORMAT_R8G8B8X8_SRGB:106case PIPE_FORMAT_B8G8R8A8_UNORM:107case PIPE_FORMAT_B8G8R8A8_SRGB:108case PIPE_FORMAT_B8G8R8X8_UNORM:109case PIPE_FORMAT_B8G8R8X8_SRGB:110case PIPE_FORMAT_R10G10B10A2_UNORM:111case PIPE_FORMAT_B10G10R10A2_UNORM:112case PIPE_FORMAT_R16G16B16A16_FLOAT:113case PIPE_FORMAT_R16G16B16X16_FLOAT:114case PIPE_FORMAT_R11G11B10_FLOAT:115switch (util_format_get_blocksizebits(mt->base.base.format)) {116case 128:117assert(ms < 3);118tile_flags = 0x74;119break;120case 64:121switch (ms) {122case 2: tile_flags = 0xfc; break;123case 3: tile_flags = 0xfd; break;124default:125tile_flags = 0x70;126break;127}128break;129case 32:130if (mt->base.base.bind & PIPE_BIND_SCANOUT) {131assert(ms == 0);132tile_flags = 0x7a;133} else {134switch (ms) {135case 2: tile_flags = 0xf8; break;136case 3: tile_flags = 0xf9; break;137default:138tile_flags = 0x70;139break;140}141}142break;143case 16:144case 8:145tile_flags = 0x70;146break;147default:148return 0;149}150if (mt->base.base.bind & PIPE_BIND_CURSOR)151tile_flags = 0;152}153154if (!compressed)155tile_flags &= ~0x180;156157return tile_flags;158}159160void161nv50_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt)162{163struct nv50_miptree *mt = nv50_miptree(pt);164165if (mt->base.fence && mt->base.fence->state < NOUVEAU_FENCE_STATE_FLUSHED)166nouveau_fence_work(mt->base.fence, nouveau_fence_unref_bo, mt->base.bo);167else168nouveau_bo_ref(NULL, &mt->base.bo);169170nouveau_fence_ref(NULL, &mt->base.fence);171nouveau_fence_ref(NULL, &mt->base.fence_wr);172173NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_count, -1);174NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_bytes,175-(uint64_t)mt->total_size);176177FREE(mt);178}179180bool181nv50_miptree_get_handle(struct pipe_screen *pscreen,182struct pipe_context *context,183struct pipe_resource *pt,184struct winsys_handle *whandle,185unsigned usage)186{187if (pt->target == PIPE_BUFFER)188return false;189190struct nv50_miptree *mt = nv50_miptree(pt);191unsigned stride;192193if (!mt || !mt->base.bo)194return false;195196stride = mt->level[0].pitch;197198return nouveau_screen_bo_get_handle(pscreen,199mt->base.bo,200stride,201whandle);202}203204static inline bool205nv50_miptree_init_ms_mode(struct nv50_miptree *mt)206{207switch (mt->base.base.nr_samples) {208case 8:209mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS8;210mt->ms_x = 2;211mt->ms_y = 1;212break;213case 4:214mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS4;215mt->ms_x = 1;216mt->ms_y = 1;217break;218case 2:219mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS2;220mt->ms_x = 1;221break;222case 1:223case 0:224mt->ms_mode = NV50_3D_MULTISAMPLE_MODE_MS1;225break;226default:227NOUVEAU_ERR("invalid nr_samples: %u\n", mt->base.base.nr_samples);228return false;229}230return true;231}232233bool234nv50_miptree_init_layout_linear(struct nv50_miptree *mt, unsigned pitch_align)235{236struct pipe_resource *pt = &mt->base.base;237const unsigned blocksize = util_format_get_blocksize(pt->format);238unsigned h = pt->height0;239240if (util_format_is_depth_or_stencil(pt->format))241return false;242243if ((pt->last_level > 0) || (pt->depth0 > 1) || (pt->array_size > 1))244return false;245if (mt->ms_x | mt->ms_y)246return false;247248mt->level[0].pitch = align(pt->width0 * blocksize, pitch_align);249250/* Account for very generous prefetch (allocate size as if tiled). */251h = MAX2(h, 8);252h = util_next_power_of_two(h);253254mt->total_size = mt->level[0].pitch * h;255256return true;257}258259static void260nv50_miptree_init_layout_video(struct nv50_miptree *mt)261{262const struct pipe_resource *pt = &mt->base.base;263const unsigned blocksize = util_format_get_blocksize(pt->format);264265assert(pt->last_level == 0);266assert(mt->ms_x == 0 && mt->ms_y == 0);267assert(!util_format_is_compressed(pt->format));268269mt->layout_3d = pt->target == PIPE_TEXTURE_3D;270271mt->level[0].tile_mode = 0x20;272mt->level[0].pitch = align(pt->width0 * blocksize, 64);273mt->total_size = align(pt->height0, 16) * mt->level[0].pitch * (mt->layout_3d ? pt->depth0 : 1);274275if (pt->array_size > 1) {276mt->layer_stride = align(mt->total_size, NV50_TILE_SIZE(0x20));277mt->total_size = mt->layer_stride * pt->array_size;278}279}280281static void282nv50_miptree_init_layout_tiled(struct nv50_miptree *mt)283{284struct pipe_resource *pt = &mt->base.base;285unsigned w, h, d, l;286const unsigned blocksize = util_format_get_blocksize(pt->format);287288mt->layout_3d = pt->target == PIPE_TEXTURE_3D;289290w = pt->width0 << mt->ms_x;291h = pt->height0 << mt->ms_y;292293/* For 3D textures, a mipmap is spanned by all the layers, for array294* textures and cube maps, each layer contains its own mipmaps.295*/296d = mt->layout_3d ? pt->depth0 : 1;297298for (l = 0; l <= pt->last_level; ++l) {299struct nv50_miptree_level *lvl = &mt->level[l];300unsigned tsx, tsy, tsz;301unsigned nbx = util_format_get_nblocksx(pt->format, w);302unsigned nby = util_format_get_nblocksy(pt->format, h);303304lvl->offset = mt->total_size;305306lvl->tile_mode = nv50_tex_choose_tile_dims(nbx, nby, d, mt->layout_3d);307308tsx = NV50_TILE_SIZE_X(lvl->tile_mode); /* x is tile row pitch in bytes */309tsy = NV50_TILE_SIZE_Y(lvl->tile_mode);310tsz = NV50_TILE_SIZE_Z(lvl->tile_mode);311312lvl->pitch = align(nbx * blocksize, tsx);313314mt->total_size += lvl->pitch * align(nby, tsy) * align(d, tsz);315316w = u_minify(w, 1);317h = u_minify(h, 1);318d = u_minify(d, 1);319}320321if (pt->array_size > 1) {322mt->layer_stride = align(mt->total_size,323NV50_TILE_SIZE(mt->level[0].tile_mode));324mt->total_size = mt->layer_stride * pt->array_size;325}326}327328struct pipe_resource *329nv50_miptree_create(struct pipe_screen *pscreen,330const struct pipe_resource *templ)331{332struct nouveau_device *dev = nouveau_screen(pscreen)->device;333struct nouveau_drm *drm = nouveau_screen(pscreen)->drm;334struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree);335struct pipe_resource *pt = &mt->base.base;336bool compressed = drm->version >= 0x01000101;337int ret;338union nouveau_bo_config bo_config;339uint32_t bo_flags;340unsigned pitch_align;341342if (!mt)343return NULL;344345*pt = *templ;346pipe_reference_init(&pt->reference, 1);347pt->screen = pscreen;348349if (pt->bind & PIPE_BIND_LINEAR)350pt->flags |= NOUVEAU_RESOURCE_FLAG_LINEAR;351352bo_config.nv50.memtype = nv50_mt_choose_storage_type(mt, compressed);353354if (!nv50_miptree_init_ms_mode(mt)) {355FREE(mt);356return NULL;357}358359if (unlikely(pt->flags & NV50_RESOURCE_FLAG_VIDEO)) {360nv50_miptree_init_layout_video(mt);361if (pt->flags & NV50_RESOURCE_FLAG_NOALLOC) {362/* BO allocation done by client */363return pt;364}365} else366if (bo_config.nv50.memtype != 0) {367nv50_miptree_init_layout_tiled(mt);368} else {369if (pt->usage & PIPE_BIND_CURSOR)370pitch_align = 1;371else if (pt->usage & PIPE_BIND_SCANOUT)372pitch_align = 256;373else374pitch_align = 64;375if (!nv50_miptree_init_layout_linear(mt, pitch_align)) {376FREE(mt);377return NULL;378}379}380bo_config.nv50.tile_mode = mt->level[0].tile_mode;381382if (!bo_config.nv50.memtype && (pt->bind & PIPE_BIND_SHARED))383mt->base.domain = NOUVEAU_BO_GART;384else385mt->base.domain = NV_VRAM_DOMAIN(nouveau_screen(pscreen));386387bo_flags = mt->base.domain | NOUVEAU_BO_NOSNOOP;388if (mt->base.base.bind & (PIPE_BIND_CURSOR | PIPE_BIND_DISPLAY_TARGET))389bo_flags |= NOUVEAU_BO_CONTIG;390391ret = nouveau_bo_new(dev, bo_flags, 4096, mt->total_size, &bo_config,392&mt->base.bo);393if (ret) {394FREE(mt);395return NULL;396}397mt->base.address = mt->base.bo->offset;398399return pt;400}401402struct pipe_resource *403nv50_miptree_from_handle(struct pipe_screen *pscreen,404const struct pipe_resource *templ,405struct winsys_handle *whandle)406{407struct nv50_miptree *mt;408unsigned stride;409410/* only supports 2D, non-mipmapped textures for the moment */411if ((templ->target != PIPE_TEXTURE_2D &&412templ->target != PIPE_TEXTURE_RECT) ||413templ->last_level != 0 ||414templ->depth0 != 1 ||415templ->array_size > 1)416return NULL;417418mt = CALLOC_STRUCT(nv50_miptree);419if (!mt)420return NULL;421422mt->base.bo = nouveau_screen_bo_from_handle(pscreen, whandle, &stride);423if (mt->base.bo == NULL) {424FREE(mt);425return NULL;426}427mt->base.domain = mt->base.bo->flags & NOUVEAU_BO_APER;428mt->base.address = mt->base.bo->offset;429430mt->base.base = *templ;431pipe_reference_init(&mt->base.base.reference, 1);432mt->base.base.screen = pscreen;433mt->level[0].pitch = stride;434mt->level[0].offset = 0;435mt->level[0].tile_mode = mt->base.bo->config.nv50.tile_mode;436437NOUVEAU_DRV_STAT(nouveau_screen(pscreen), tex_obj_current_count, 1);438439/* no need to adjust bo reference count */440return &mt->base.base;441}442443444/* Offset of zslice @z from start of level @l. */445inline unsigned446nv50_mt_zslice_offset(const struct nv50_miptree *mt, unsigned l, unsigned z)447{448const struct pipe_resource *pt = &mt->base.base;449450unsigned tds = NV50_TILE_SHIFT_Z(mt->level[l].tile_mode);451unsigned ths = NV50_TILE_SHIFT_Y(mt->level[l].tile_mode);452453unsigned nby = util_format_get_nblocksy(pt->format,454u_minify(pt->height0, l));455456/* to next 2D tile slice within a 3D tile */457unsigned stride_2d = NV50_TILE_SIZE_2D(mt->level[l].tile_mode);458459/* to slice in the next (in z direction) 3D tile */460unsigned stride_3d = (align(nby, (1 << ths)) * mt->level[l].pitch) << tds;461462return (z & ((1 << tds) - 1)) * stride_2d + (z >> tds) * stride_3d;463}464465/* Surface functions.466*/467468struct nv50_surface *469nv50_surface_from_miptree(struct nv50_miptree *mt,470const struct pipe_surface *templ)471{472struct pipe_surface *ps;473struct nv50_surface *ns = CALLOC_STRUCT(nv50_surface);474if (!ns)475return NULL;476ps = &ns->base;477478pipe_reference_init(&ps->reference, 1);479pipe_resource_reference(&ps->texture, &mt->base.base);480481ps->format = templ->format;482ps->writable = templ->writable;483ps->u.tex.level = templ->u.tex.level;484ps->u.tex.first_layer = templ->u.tex.first_layer;485ps->u.tex.last_layer = templ->u.tex.last_layer;486487ns->width = u_minify(mt->base.base.width0, ps->u.tex.level);488ns->height = u_minify(mt->base.base.height0, ps->u.tex.level);489ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1;490ns->offset = mt->level[templ->u.tex.level].offset;491492/* comment says there are going to be removed, but they're used by the st */493ps->width = ns->width;494ps->height = ns->height;495496ns->width <<= mt->ms_x;497ns->height <<= mt->ms_y;498499return ns;500}501502struct pipe_surface *503nv50_miptree_surface_new(struct pipe_context *pipe,504struct pipe_resource *pt,505const struct pipe_surface *templ)506{507struct nv50_miptree *mt = nv50_miptree(pt);508struct nv50_surface *ns = nv50_surface_from_miptree(mt, templ);509if (!ns)510return NULL;511ns->base.context = pipe;512513if (ns->base.u.tex.first_layer) {514const unsigned l = ns->base.u.tex.level;515const unsigned z = ns->base.u.tex.first_layer;516517if (mt->layout_3d) {518ns->offset += nv50_mt_zslice_offset(mt, l, z);519520/* TODO: switch to depth 1 tiles; but actually this shouldn't happen */521if (ns->depth > 1 &&522(z & (NV50_TILE_SIZE_Z(mt->level[l].tile_mode) - 1)))523NOUVEAU_ERR("Creating unsupported 3D surface !\n");524} else {525ns->offset += mt->layer_stride * z;526}527}528529return &ns->base;530}531532533