Path: blob/21.2-virgl/src/gallium/drivers/nouveau/nv30/nv30_miptree.c
4574 views
/*1* Copyright 2012 Red Hat Inc.2*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*21* Authors: Ben Skeggs22*23*/2425#include "util/format/u_format.h"26#include "util/u_inlines.h"27#include "util/u_surface.h"2829#include "nv_m2mf.xml.h"30#include "nv_object.xml.h"31#include "nv30/nv30_screen.h"32#include "nv30/nv30_context.h"33#include "nv30/nv30_resource.h"34#include "nv30/nv30_transfer.h"3536static inline unsigned37layer_offset(struct pipe_resource *pt, unsigned level, unsigned layer)38{39struct nv30_miptree *mt = nv30_miptree(pt);40struct nv30_miptree_level *lvl = &mt->level[level];4142if (pt->target == PIPE_TEXTURE_CUBE)43return (layer * mt->layer_size) + lvl->offset;4445return lvl->offset + (layer * lvl->zslice_size);46}4748bool49nv30_miptree_get_handle(struct pipe_screen *pscreen,50struct pipe_context *context,51struct pipe_resource *pt,52struct winsys_handle *handle,53unsigned usage)54{55if (pt->target == PIPE_BUFFER)56return false;5758struct nv30_miptree *mt = nv30_miptree(pt);59unsigned stride;6061if (!mt || !mt->base.bo)62return false;6364stride = mt->level[0].pitch;6566return nouveau_screen_bo_get_handle(pscreen, mt->base.bo, stride, handle);67}6869void70nv30_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt)71{72struct nv30_miptree *mt = nv30_miptree(pt);7374nouveau_bo_ref(NULL, &mt->base.bo);75FREE(mt);76}7778struct nv30_transfer {79struct pipe_transfer base;80struct nv30_rect img;81struct nv30_rect tmp;82unsigned nblocksx;83unsigned nblocksy;84};8586static inline struct nv30_transfer *87nv30_transfer(struct pipe_transfer *ptx)88{89return (struct nv30_transfer *)ptx;90}9192static inline void93define_rect(struct pipe_resource *pt, unsigned level, unsigned z,94unsigned x, unsigned y, unsigned w, unsigned h,95struct nv30_rect *rect)96{97struct nv30_miptree *mt = nv30_miptree(pt);98struct nv30_miptree_level *lvl = &mt->level[level];99100rect->w = u_minify(pt->width0, level) << mt->ms_x;101rect->w = util_format_get_nblocksx(pt->format, rect->w);102rect->h = u_minify(pt->height0, level) << mt->ms_y;103rect->h = util_format_get_nblocksy(pt->format, rect->h);104rect->d = 1;105rect->z = 0;106if (mt->swizzled) {107if (pt->target == PIPE_TEXTURE_3D) {108rect->d = u_minify(pt->depth0, level);109rect->z = z; z = 0;110}111rect->pitch = 0;112} else {113rect->pitch = lvl->pitch;114}115116rect->bo = mt->base.bo;117rect->domain = NOUVEAU_BO_VRAM;118rect->offset = layer_offset(pt, level, z);119rect->cpp = util_format_get_blocksize(pt->format);120121rect->x0 = util_format_get_nblocksx(pt->format, x) << mt->ms_x;122rect->y0 = util_format_get_nblocksy(pt->format, y) << mt->ms_y;123rect->x1 = rect->x0 + (util_format_get_nblocksx(pt->format, w) << mt->ms_x);124rect->y1 = rect->y0 + (util_format_get_nblocksy(pt->format, h) << mt->ms_y);125126/* XXX There's some indication that swizzled formats > 4 bytes are treated127* differently. However that only applies to RGBA16_FLOAT, RGBA32_FLOAT,128* and the DXT* formats. The former aren't properly supported yet, and the129* latter avoid swizzled layouts.130131if (mt->swizzled && rect->cpp > 4) {132unsigned scale = rect->cpp / 4;133rect->w *= scale;134rect->x0 *= scale;135rect->x1 *= scale;136rect->cpp = 4;137}138*/139}140141void142nv30_resource_copy_region(struct pipe_context *pipe,143struct pipe_resource *dstres, unsigned dst_level,144unsigned dstx, unsigned dsty, unsigned dstz,145struct pipe_resource *srcres, unsigned src_level,146const struct pipe_box *src_box)147{148struct nv30_context *nv30 = nv30_context(pipe);149struct nv30_rect src, dst;150151if (dstres->target == PIPE_BUFFER && srcres->target == PIPE_BUFFER) {152nouveau_copy_buffer(&nv30->base,153nv04_resource(dstres), dstx,154nv04_resource(srcres), src_box->x, src_box->width);155return;156}157158define_rect(srcres, src_level, src_box->z, src_box->x, src_box->y,159src_box->width, src_box->height, &src);160define_rect(dstres, dst_level, dstz, dstx, dsty,161src_box->width, src_box->height, &dst);162163nv30_transfer_rect(nv30, NEAREST, &src, &dst);164}165166static void167nv30_resource_resolve(struct nv30_context *nv30,168const struct pipe_blit_info *info)169{170struct nv30_miptree *src_mt = nv30_miptree(info->src.resource);171struct nv30_rect src, dst;172unsigned x, x0, x1, y, y1, w, h;173174define_rect(info->src.resource, 0, info->src.box.z, info->src.box.x,175info->src.box.y, info->src.box.width, info->src.box.height, &src);176define_rect(info->dst.resource, 0, info->dst.box.z, info->dst.box.x,177info->dst.box.y, info->dst.box.width, info->dst.box.height, &dst);178179x0 = src.x0;180x1 = src.x1;181y1 = src.y1;182183/* On nv3x we must use sifm which is restricted to 1024x1024 tiles */184for (y = src.y0; y < y1; y += h) {185h = y1 - y;186if (h > 1024)187h = 1024;188189src.y0 = 0;190src.y1 = h;191src.h = h;192193dst.y1 = dst.y0 + (h >> src_mt->ms_y);194dst.h = h >> src_mt->ms_y;195196for (x = x0; x < x1; x += w) {197w = x1 - x;198if (w > 1024)199w = 1024;200201src.offset = y * src.pitch + x * src.cpp;202src.x0 = 0;203src.x1 = w;204src.w = w;205206dst.offset = (y >> src_mt->ms_y) * dst.pitch +207(x >> src_mt->ms_x) * dst.cpp;208dst.x1 = dst.x0 + (w >> src_mt->ms_x);209dst.w = w >> src_mt->ms_x;210211nv30_transfer_rect(nv30, BILINEAR, &src, &dst);212}213}214}215216void217nv30_blit(struct pipe_context *pipe,218const struct pipe_blit_info *blit_info)219{220struct nv30_context *nv30 = nv30_context(pipe);221struct pipe_blit_info info = *blit_info;222223if (info.src.resource->nr_samples > 1 &&224info.dst.resource->nr_samples <= 1 &&225!util_format_is_depth_or_stencil(info.src.resource->format) &&226!util_format_is_pure_integer(info.src.resource->format)) {227nv30_resource_resolve(nv30, blit_info);228return;229}230231if (util_try_blit_via_copy_region(pipe, &info)) {232return; /* done */233}234235if (info.mask & PIPE_MASK_S) {236debug_printf("nv30: cannot blit stencil, skipping\n");237info.mask &= ~PIPE_MASK_S;238}239240if (!util_blitter_is_blit_supported(nv30->blitter, &info)) {241debug_printf("nv30: blit unsupported %s -> %s\n",242util_format_short_name(info.src.resource->format),243util_format_short_name(info.dst.resource->format));244return;245}246247/* XXX turn off occlusion queries */248249util_blitter_save_vertex_buffer_slot(nv30->blitter, nv30->vtxbuf);250util_blitter_save_vertex_elements(nv30->blitter, nv30->vertex);251util_blitter_save_vertex_shader(nv30->blitter, nv30->vertprog.program);252util_blitter_save_rasterizer(nv30->blitter, nv30->rast);253util_blitter_save_viewport(nv30->blitter, &nv30->viewport);254util_blitter_save_scissor(nv30->blitter, &nv30->scissor);255util_blitter_save_fragment_shader(nv30->blitter, nv30->fragprog.program);256util_blitter_save_blend(nv30->blitter, nv30->blend);257util_blitter_save_depth_stencil_alpha(nv30->blitter,258nv30->zsa);259util_blitter_save_stencil_ref(nv30->blitter, &nv30->stencil_ref);260util_blitter_save_sample_mask(nv30->blitter, nv30->sample_mask);261util_blitter_save_framebuffer(nv30->blitter, &nv30->framebuffer);262util_blitter_save_fragment_sampler_states(nv30->blitter,263nv30->fragprog.num_samplers,264(void**)nv30->fragprog.samplers);265util_blitter_save_fragment_sampler_views(nv30->blitter,266nv30->fragprog.num_textures, nv30->fragprog.textures);267util_blitter_save_render_condition(nv30->blitter, nv30->render_cond_query,268nv30->render_cond_cond, nv30->render_cond_mode);269util_blitter_blit(nv30->blitter, &info);270}271272void273nv30_flush_resource(struct pipe_context *pipe,274struct pipe_resource *resource)275{276}277278void *279nv30_miptree_transfer_map(struct pipe_context *pipe, struct pipe_resource *pt,280unsigned level, unsigned usage,281const struct pipe_box *box,282struct pipe_transfer **ptransfer)283{284struct nv30_context *nv30 = nv30_context(pipe);285struct nouveau_device *dev = nv30->screen->base.device;286struct nv30_miptree *mt = nv30_miptree(pt);287struct nv30_transfer *tx;288unsigned access = 0;289int ret;290291tx = CALLOC_STRUCT(nv30_transfer);292if (!tx)293return NULL;294pipe_resource_reference(&tx->base.resource, pt);295tx->base.level = level;296tx->base.usage = usage;297tx->base.box = *box;298tx->base.stride = align(util_format_get_nblocksx(pt->format, box->width) *299util_format_get_blocksize(pt->format), 64);300tx->base.layer_stride = util_format_get_nblocksy(pt->format, box->height) *301tx->base.stride;302303tx->nblocksx = util_format_get_nblocksx(pt->format, box->width);304tx->nblocksy = util_format_get_nblocksy(pt->format, box->height);305306define_rect(pt, level, box->z, box->x, box->y,307box->width, box->height, &tx->img);308309ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,310tx->base.layer_stride * tx->base.box.depth, NULL,311&tx->tmp.bo);312if (ret) {313pipe_resource_reference(&tx->base.resource, NULL);314FREE(tx);315return NULL;316}317318tx->tmp.domain = NOUVEAU_BO_GART;319tx->tmp.offset = 0;320tx->tmp.pitch = tx->base.stride;321tx->tmp.cpp = tx->img.cpp;322tx->tmp.w = tx->nblocksx;323tx->tmp.h = tx->nblocksy;324tx->tmp.d = 1;325tx->tmp.x0 = 0;326tx->tmp.y0 = 0;327tx->tmp.x1 = tx->tmp.w;328tx->tmp.y1 = tx->tmp.h;329tx->tmp.z = 0;330331if (usage & PIPE_MAP_READ) {332bool is_3d = mt->base.base.target == PIPE_TEXTURE_3D;333unsigned offset = tx->img.offset;334unsigned z = tx->img.z;335unsigned i;336for (i = 0; i < box->depth; ++i) {337nv30_transfer_rect(nv30, NEAREST, &tx->img, &tx->tmp);338if (is_3d && mt->swizzled)339tx->img.z++;340else if (is_3d)341tx->img.offset += mt->level[level].zslice_size;342else343tx->img.offset += mt->layer_size;344tx->tmp.offset += tx->base.layer_stride;345}346tx->img.z = z;347tx->img.offset = offset;348tx->tmp.offset = 0;349}350351if (tx->tmp.bo->map) {352*ptransfer = &tx->base;353return tx->tmp.bo->map;354}355356if (usage & PIPE_MAP_READ)357access |= NOUVEAU_BO_RD;358if (usage & PIPE_MAP_WRITE)359access |= NOUVEAU_BO_WR;360361ret = nouveau_bo_map(tx->tmp.bo, access, nv30->base.client);362if (ret) {363pipe_resource_reference(&tx->base.resource, NULL);364FREE(tx);365return NULL;366}367368*ptransfer = &tx->base;369return tx->tmp.bo->map;370}371372void373nv30_miptree_transfer_unmap(struct pipe_context *pipe,374struct pipe_transfer *ptx)375{376struct nv30_context *nv30 = nv30_context(pipe);377struct nv30_transfer *tx = nv30_transfer(ptx);378struct nv30_miptree *mt = nv30_miptree(tx->base.resource);379unsigned i;380381if (ptx->usage & PIPE_MAP_WRITE) {382bool is_3d = mt->base.base.target == PIPE_TEXTURE_3D;383for (i = 0; i < tx->base.box.depth; ++i) {384nv30_transfer_rect(nv30, NEAREST, &tx->tmp, &tx->img);385if (is_3d && mt->swizzled)386tx->img.z++;387else if (is_3d)388tx->img.offset += mt->level[tx->base.level].zslice_size;389else390tx->img.offset += mt->layer_size;391tx->tmp.offset += tx->base.layer_stride;392}393394/* Allow the copies above to finish executing before freeing the source */395nouveau_fence_work(nv30->screen->base.fence.current,396nouveau_fence_unref_bo, tx->tmp.bo);397} else {398nouveau_bo_ref(NULL, &tx->tmp.bo);399}400pipe_resource_reference(&ptx->resource, NULL);401FREE(tx);402}403404struct pipe_resource *405nv30_miptree_create(struct pipe_screen *pscreen,406const struct pipe_resource *tmpl)407{408struct nouveau_device *dev = nouveau_screen(pscreen)->device;409struct nv30_miptree *mt = CALLOC_STRUCT(nv30_miptree);410struct pipe_resource *pt = &mt->base.base;411unsigned blocksz, size;412unsigned w, h, d, l;413int ret;414415switch (tmpl->nr_samples) {416case 4:417mt->ms_mode = 0x00004000;418mt->ms_x = 1;419mt->ms_y = 1;420break;421case 2:422mt->ms_mode = 0x00003000;423mt->ms_x = 1;424mt->ms_y = 0;425break;426default:427mt->ms_mode = 0x00000000;428mt->ms_x = 0;429mt->ms_y = 0;430break;431}432433*pt = *tmpl;434pipe_reference_init(&pt->reference, 1);435pt->screen = pscreen;436437w = pt->width0 << mt->ms_x;438h = pt->height0 << mt->ms_y;439d = (pt->target == PIPE_TEXTURE_3D) ? pt->depth0 : 1;440blocksz = util_format_get_blocksize(pt->format);441442if ((pt->target == PIPE_TEXTURE_RECT) ||443(pt->bind & PIPE_BIND_SCANOUT) ||444!util_is_power_of_two_or_zero(pt->width0) ||445!util_is_power_of_two_or_zero(pt->height0) ||446!util_is_power_of_two_or_zero(pt->depth0) ||447mt->ms_mode) {448mt->uniform_pitch = util_format_get_nblocksx(pt->format, w) * blocksz;449mt->uniform_pitch = align(mt->uniform_pitch, 64);450if (pt->bind & PIPE_BIND_SCANOUT) {451struct nv30_screen *screen = nv30_screen(pscreen);452int pitch_align = MAX2(453screen->eng3d->oclass >= NV40_3D_CLASS ? 1024 : 256,454/* round_down_pow2(mt->uniform_pitch / 4) */4551 << (util_last_bit(mt->uniform_pitch / 4) - 1));456mt->uniform_pitch = align(mt->uniform_pitch, pitch_align);457}458}459460if (util_format_is_compressed(pt->format)) {461// Compressed (DXT) formats are packed tightly. We don't mark them as462// swizzled, since their layout is largely linear. However we do end up463// omitting the LINEAR flag when texturing them, as the levels are not464// uniformly sized (for POT sizes).465} else if (!mt->uniform_pitch) {466mt->swizzled = true;467}468469size = 0;470for (l = 0; l <= pt->last_level; l++) {471struct nv30_miptree_level *lvl = &mt->level[l];472unsigned nbx = util_format_get_nblocksx(pt->format, w);473unsigned nby = util_format_get_nblocksy(pt->format, h);474475lvl->offset = size;476lvl->pitch = mt->uniform_pitch;477if (!lvl->pitch)478lvl->pitch = nbx * blocksz;479480lvl->zslice_size = lvl->pitch * nby;481size += lvl->zslice_size * d;482483w = u_minify(w, 1);484h = u_minify(h, 1);485d = u_minify(d, 1);486}487488mt->layer_size = size;489if (pt->target == PIPE_TEXTURE_CUBE) {490if (!mt->uniform_pitch)491mt->layer_size = align(mt->layer_size, 128);492size = mt->layer_size * 6;493}494495ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 256, size, NULL, &mt->base.bo);496if (ret) {497FREE(mt);498return NULL;499}500501mt->base.domain = NOUVEAU_BO_VRAM;502return &mt->base.base;503}504505struct pipe_resource *506nv30_miptree_from_handle(struct pipe_screen *pscreen,507const struct pipe_resource *tmpl,508struct winsys_handle *handle)509{510struct nv30_miptree *mt;511unsigned stride;512513/* only supports 2D, non-mipmapped textures for the moment */514if ((tmpl->target != PIPE_TEXTURE_2D &&515tmpl->target != PIPE_TEXTURE_RECT) ||516tmpl->last_level != 0 ||517tmpl->depth0 != 1 ||518tmpl->array_size > 1)519return NULL;520521mt = CALLOC_STRUCT(nv30_miptree);522if (!mt)523return NULL;524525mt->base.bo = nouveau_screen_bo_from_handle(pscreen, handle, &stride);526if (mt->base.bo == NULL) {527FREE(mt);528return NULL;529}530531mt->base.base = *tmpl;532pipe_reference_init(&mt->base.base.reference, 1);533mt->base.base.screen = pscreen;534mt->uniform_pitch = stride;535mt->level[0].pitch = mt->uniform_pitch;536mt->level[0].offset = 0;537538/* no need to adjust bo reference count */539return &mt->base.base;540}541542struct pipe_surface *543nv30_miptree_surface_new(struct pipe_context *pipe,544struct pipe_resource *pt,545const struct pipe_surface *tmpl)546{547struct nv30_miptree *mt = nv30_miptree(pt); /* guaranteed */548struct nv30_surface *ns;549struct pipe_surface *ps;550struct nv30_miptree_level *lvl = &mt->level[tmpl->u.tex.level];551552ns = CALLOC_STRUCT(nv30_surface);553if (!ns)554return NULL;555ps = &ns->base;556557pipe_reference_init(&ps->reference, 1);558pipe_resource_reference(&ps->texture, pt);559ps->context = pipe;560ps->format = tmpl->format;561ps->u.tex.level = tmpl->u.tex.level;562ps->u.tex.first_layer = tmpl->u.tex.first_layer;563ps->u.tex.last_layer = tmpl->u.tex.last_layer;564565ns->width = u_minify(pt->width0, ps->u.tex.level);566ns->height = u_minify(pt->height0, ps->u.tex.level);567ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1;568ns->offset = layer_offset(pt, ps->u.tex.level, ps->u.tex.first_layer);569if (mt->swizzled)570ns->pitch = 4096; /* random, just something the hw won't reject.. */571else572ns->pitch = lvl->pitch;573574/* comment says there are going to be removed, but they're used by the st */575ps->width = ns->width;576ps->height = ns->height;577return ps;578}579580void581nv30_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps)582{583struct nv30_surface *ns = nv30_surface(ps);584585pipe_resource_reference(&ps->texture, NULL);586FREE(ns);587}588589590