Path: blob/21.2-virgl/src/gallium/drivers/svga/svga_resource_texture.c
4570 views
/**********************************************************1* Copyright 2008-2009 VMware, Inc. All rights reserved.2*3* Permission is hereby granted, free of charge, to any person4* obtaining a copy of this software and associated documentation5* files (the "Software"), to deal in the Software without6* restriction, including without limitation the rights to use, copy,7* modify, merge, publish, distribute, sublicense, and/or sell copies8* of the Software, and to permit persons to whom the Software is9* furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice shall be12* included in all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS18* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN19* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN20* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*23**********************************************************/2425#include "svga3d_reg.h"26#include "svga3d_surfacedefs.h"2728#include "pipe/p_state.h"29#include "pipe/p_defines.h"30#include "os/os_thread.h"31#include "util/format/u_format.h"32#include "util/u_inlines.h"33#include "util/u_math.h"34#include "util/u_memory.h"35#include "util/u_resource.h"36#include "util/u_upload_mgr.h"3738#include "svga_cmd.h"39#include "svga_format.h"40#include "svga_screen.h"41#include "svga_context.h"42#include "svga_resource_texture.h"43#include "svga_resource_buffer.h"44#include "svga_sampler_view.h"45#include "svga_winsys.h"46#include "svga_debug.h"474849static void50svga_transfer_dma_band(struct svga_context *svga,51struct svga_transfer *st,52SVGA3dTransferType transfer,53unsigned x, unsigned y, unsigned z,54unsigned w, unsigned h, unsigned d,55unsigned srcx, unsigned srcy, unsigned srcz,56SVGA3dSurfaceDMAFlags flags)57{58struct svga_texture *texture = svga_texture(st->base.resource);59SVGA3dCopyBox box;6061assert(!st->use_direct_map);6263box.x = x;64box.y = y;65box.z = z;66box.w = w;67box.h = h;68box.d = d;69box.srcx = srcx;70box.srcy = srcy;71box.srcz = srcz;7273SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - "74"(%u, %u, %u), %ubpp\n",75transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from",76texture->handle,77st->slice,78x,79y,80z,81x + w,82y + h,83z + 1,84util_format_get_blocksize(texture->b.format) * 8 /85(util_format_get_blockwidth(texture->b.format)86* util_format_get_blockheight(texture->b.format)));8788SVGA_RETRY(svga, SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags));89}909192static void93svga_transfer_dma(struct svga_context *svga,94struct svga_transfer *st,95SVGA3dTransferType transfer,96SVGA3dSurfaceDMAFlags flags)97{98struct svga_texture *texture = svga_texture(st->base.resource);99struct svga_screen *screen = svga_screen(texture->b.screen);100struct svga_winsys_screen *sws = screen->sws;101struct pipe_fence_handle *fence = NULL;102103assert(!st->use_direct_map);104105if (transfer == SVGA3D_READ_HOST_VRAM) {106SVGA_DBG(DEBUG_PERF, "%s: readback transfer\n", __FUNCTION__);107}108109/* Ensure any pending operations on host surfaces are queued on the command110* buffer first.111*/112svga_surfaces_flush(svga);113114if (!st->swbuf) {115/* Do the DMA transfer in a single go */116svga_transfer_dma_band(svga, st, transfer,117st->box.x, st->box.y, st->box.z,118st->box.w, st->box.h, st->box.d,1190, 0, 0,120flags);121122if (transfer == SVGA3D_READ_HOST_VRAM) {123svga_context_flush(svga, &fence);124sws->fence_finish(sws, fence, PIPE_TIMEOUT_INFINITE, 0);125sws->fence_reference(sws, &fence, NULL);126}127}128else {129int y, h, srcy;130unsigned blockheight =131util_format_get_blockheight(st->base.resource->format);132133h = st->hw_nblocksy * blockheight;134srcy = 0;135136for (y = 0; y < st->box.h; y += h) {137unsigned offset, length;138void *hw, *sw;139140if (y + h > st->box.h)141h = st->box.h - y;142143/* Transfer band must be aligned to pixel block boundaries */144assert(y % blockheight == 0);145assert(h % blockheight == 0);146147offset = y * st->base.stride / blockheight;148length = h * st->base.stride / blockheight;149150sw = (uint8_t *) st->swbuf + offset;151152if (transfer == SVGA3D_WRITE_HOST_VRAM) {153unsigned usage = PIPE_MAP_WRITE;154155/* Wait for the previous DMAs to complete */156/* TODO: keep one DMA (at half the size) in the background */157if (y) {158svga_context_flush(svga, NULL);159usage |= PIPE_MAP_DISCARD_WHOLE_RESOURCE;160}161162hw = sws->buffer_map(sws, st->hwbuf, usage);163assert(hw);164if (hw) {165memcpy(hw, sw, length);166sws->buffer_unmap(sws, st->hwbuf);167}168}169170svga_transfer_dma_band(svga, st, transfer,171st->box.x, y, st->box.z,172st->box.w, h, st->box.d,1730, srcy, 0, flags);174175/*176* Prevent the texture contents to be discarded on the next band177* upload.178*/179flags.discard = FALSE;180181if (transfer == SVGA3D_READ_HOST_VRAM) {182svga_context_flush(svga, &fence);183sws->fence_finish(sws, fence, PIPE_TIMEOUT_INFINITE, 0);184185hw = sws->buffer_map(sws, st->hwbuf, PIPE_MAP_READ);186assert(hw);187if (hw) {188memcpy(sw, hw, length);189sws->buffer_unmap(sws, st->hwbuf);190}191}192}193}194}195196197198bool199svga_resource_get_handle(struct pipe_screen *screen,200struct pipe_context *context,201struct pipe_resource *texture,202struct winsys_handle *whandle,203unsigned usage)204{205struct svga_winsys_screen *sws = svga_winsys_screen(texture->screen);206unsigned stride;207208if (texture->target == PIPE_BUFFER)209return false;210211assert(svga_texture(texture)->key.cachable == 0);212svga_texture(texture)->key.cachable = 0;213214stride = util_format_get_nblocksx(texture->format, texture->width0) *215util_format_get_blocksize(texture->format);216217return sws->surface_get_handle(sws, svga_texture(texture)->handle,218stride, whandle);219}220221222/**223* Determine if we need to read back a texture image before mapping it.224*/225static inline boolean226need_tex_readback(struct svga_transfer *st)227{228if (st->base.usage & PIPE_MAP_READ)229return TRUE;230231if ((st->base.usage & PIPE_MAP_WRITE) &&232((st->base.usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) == 0)) {233return svga_was_texture_rendered_to(svga_texture(st->base.resource),234st->slice, st->base.level);235}236237return FALSE;238}239240241static void242readback_image_vgpu9(struct svga_context *svga,243struct svga_winsys_surface *surf,244unsigned slice,245unsigned level)246{247SVGA_RETRY(svga, SVGA3D_ReadbackGBImage(svga->swc, surf, slice, level));248}249250251static void252readback_image_vgpu10(struct svga_context *svga,253struct svga_winsys_surface *surf,254unsigned slice,255unsigned level,256unsigned numMipLevels)257{258unsigned subResource;259260subResource = slice * numMipLevels + level;261SVGA_RETRY(svga, SVGA3D_vgpu10_ReadbackSubResource(svga->swc, surf,262subResource));263}264265266/**267* Use DMA for the transfer request268*/269static void *270svga_texture_transfer_map_dma(struct svga_context *svga,271struct svga_transfer *st)272{273struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;274struct pipe_resource *texture = st->base.resource;275unsigned nblocksx, nblocksy;276unsigned d;277unsigned usage = st->base.usage;278279/* we'll put the data into a tightly packed buffer */280nblocksx = util_format_get_nblocksx(texture->format, st->box.w);281nblocksy = util_format_get_nblocksy(texture->format, st->box.h);282d = st->box.d;283284st->base.stride = nblocksx*util_format_get_blocksize(texture->format);285st->base.layer_stride = st->base.stride * nblocksy;286st->hw_nblocksy = nblocksy;287288st->hwbuf = svga_winsys_buffer_create(svga, 1, 0,289st->hw_nblocksy * st->base.stride * d);290291while (!st->hwbuf && (st->hw_nblocksy /= 2)) {292st->hwbuf =293svga_winsys_buffer_create(svga, 1, 0,294st->hw_nblocksy * st->base.stride * d);295}296297if (!st->hwbuf)298return NULL;299300if (st->hw_nblocksy < nblocksy) {301/* We couldn't allocate a hardware buffer big enough for the transfer,302* so allocate regular malloc memory instead303*/304if (0) {305debug_printf("%s: failed to allocate %u KB of DMA, "306"splitting into %u x %u KB DMA transfers\n",307__FUNCTION__,308(nblocksy * st->base.stride + 1023) / 1024,309(nblocksy + st->hw_nblocksy - 1) / st->hw_nblocksy,310(st->hw_nblocksy * st->base.stride + 1023) / 1024);311}312313st->swbuf = MALLOC(nblocksy * st->base.stride * d);314if (!st->swbuf) {315sws->buffer_destroy(sws, st->hwbuf);316return NULL;317}318}319320if (usage & PIPE_MAP_READ) {321SVGA3dSurfaceDMAFlags flags;322memset(&flags, 0, sizeof flags);323svga_transfer_dma(svga, st, SVGA3D_READ_HOST_VRAM, flags);324}325326if (st->swbuf) {327return st->swbuf;328}329else {330return sws->buffer_map(sws, st->hwbuf, usage);331}332}333334335/**336* Use direct map for the transfer request337*/338static void *339svga_texture_transfer_map_direct(struct svga_context *svga,340struct svga_transfer *st)341{342struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;343struct pipe_transfer *transfer = &st->base;344struct pipe_resource *texture = transfer->resource;345struct svga_texture *tex = svga_texture(texture);346struct svga_winsys_surface *surf = tex->handle;347unsigned level = st->base.level;348unsigned w, h, nblocksx, nblocksy, i;349unsigned usage = st->base.usage;350351if (need_tex_readback(st)) {352svga_surfaces_flush(svga);353354if (!svga->swc->force_coherent || tex->imported) {355for (i = 0; i < st->box.d; i++) {356if (svga_have_vgpu10(svga)) {357readback_image_vgpu10(svga, surf, st->slice + i, level,358tex->b.last_level + 1);359} else {360readback_image_vgpu9(svga, surf, st->slice + i, level);361}362}363svga->hud.num_readbacks++;364SVGA_STATS_COUNT_INC(sws, SVGA_STATS_COUNT_TEXREADBACK);365366svga_context_flush(svga, NULL);367}368/*369* Note: if PIPE_MAP_DISCARD_WHOLE_RESOURCE were specified370* we could potentially clear the flag for all faces/layers/mips.371*/372svga_clear_texture_rendered_to(tex, st->slice, level);373}374else {375assert(usage & PIPE_MAP_WRITE);376if ((usage & PIPE_MAP_UNSYNCHRONIZED) == 0) {377if (svga_is_texture_dirty(tex, st->slice, level)) {378/*379* do a surface flush if the subresource has been modified380* in this command buffer.381*/382svga_surfaces_flush(svga);383if (!sws->surface_is_flushed(sws, surf)) {384svga->hud.surface_write_flushes++;385SVGA_STATS_COUNT_INC(sws, SVGA_STATS_COUNT_SURFACEWRITEFLUSH);386svga_context_flush(svga, NULL);387}388}389}390}391392/* we'll directly access the guest-backed surface */393w = u_minify(texture->width0, level);394h = u_minify(texture->height0, level);395nblocksx = util_format_get_nblocksx(texture->format, w);396nblocksy = util_format_get_nblocksy(texture->format, h);397st->hw_nblocksy = nblocksy;398st->base.stride = nblocksx*util_format_get_blocksize(texture->format);399st->base.layer_stride = st->base.stride * nblocksy;400401/*402* Begin mapping code403*/404{405SVGA3dSize baseLevelSize;406uint8_t *map;407boolean retry, rebind;408unsigned offset, mip_width, mip_height;409struct svga_winsys_context *swc = svga->swc;410411if (swc->force_coherent) {412usage |= PIPE_MAP_PERSISTENT | PIPE_MAP_COHERENT;413}414415map = SVGA_TRY_MAP(svga->swc->surface_map416(svga->swc, surf, usage, &retry, &rebind), retry);417418if (map == NULL && retry) {419/*420* At this point, the svga_surfaces_flush() should already have421* called in svga_texture_get_transfer().422*/423svga->hud.surface_write_flushes++;424svga_retry_enter(svga);425svga_context_flush(svga, NULL);426map = svga->swc->surface_map(svga->swc, surf, usage, &retry, &rebind);427svga_retry_exit(svga);428}429430if (map && rebind) {431enum pipe_error ret;432433ret = SVGA3D_BindGBSurface(swc, surf);434if (ret != PIPE_OK) {435svga_context_flush(svga, NULL);436ret = SVGA3D_BindGBSurface(swc, surf);437assert(ret == PIPE_OK);438}439svga_context_flush(svga, NULL);440}441442/*443* Make sure we return NULL if the map fails444*/445if (!map) {446return NULL;447}448449/**450* Compute the offset to the specific texture slice in the buffer.451*/452baseLevelSize.width = tex->b.width0;453baseLevelSize.height = tex->b.height0;454baseLevelSize.depth = tex->b.depth0;455456if ((tex->b.target == PIPE_TEXTURE_1D_ARRAY) ||457(tex->b.target == PIPE_TEXTURE_2D_ARRAY) ||458(tex->b.target == PIPE_TEXTURE_CUBE_ARRAY)) {459st->base.layer_stride =460svga3dsurface_get_image_offset(tex->key.format, baseLevelSize,461tex->b.last_level + 1, 1, 0);462}463464offset = svga3dsurface_get_image_offset(tex->key.format, baseLevelSize,465tex->b.last_level + 1, /* numMips */466st->slice, level);467if (level > 0) {468assert(offset > 0);469}470471mip_width = u_minify(tex->b.width0, level);472mip_height = u_minify(tex->b.height0, level);473474offset += svga3dsurface_get_pixel_offset(tex->key.format,475mip_width, mip_height,476st->box.x,477st->box.y,478st->box.z);479480return (void *) (map + offset);481}482}483484485/**486* Request a transfer map to the texture resource487*/488void *489svga_texture_transfer_map(struct pipe_context *pipe,490struct pipe_resource *texture,491unsigned level,492unsigned usage,493const struct pipe_box *box,494struct pipe_transfer **ptransfer)495{496struct svga_context *svga = svga_context(pipe);497struct svga_winsys_screen *sws = svga_screen(pipe->screen)->sws;498struct svga_texture *tex = svga_texture(texture);499struct svga_transfer *st;500struct svga_winsys_surface *surf = tex->handle;501boolean use_direct_map = svga_have_gb_objects(svga) &&502(!svga_have_gb_dma(svga) || (usage & PIPE_MAP_WRITE));503void *map = NULL;504int64_t begin = svga_get_time(svga);505506SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_TEXTRANSFERMAP);507508if (!surf)509goto done;510511/* We can't map texture storage directly unless we have GB objects */512if (usage & PIPE_MAP_DIRECTLY) {513if (svga_have_gb_objects(svga))514use_direct_map = TRUE;515else516goto done;517}518519st = CALLOC_STRUCT(svga_transfer);520if (!st)521goto done;522523st->base.level = level;524st->base.usage = usage;525st->base.box = *box;526527/* The modified transfer map box with the array index removed from z.528* The array index is specified in slice.529*/530st->box.x = box->x;531st->box.y = box->y;532st->box.z = box->z;533st->box.w = box->width;534st->box.h = box->height;535st->box.d = box->depth;536537switch (tex->b.target) {538case PIPE_TEXTURE_CUBE:539st->slice = st->base.box.z;540st->box.z = 0; /* so we don't apply double offsets below */541break;542case PIPE_TEXTURE_1D_ARRAY:543case PIPE_TEXTURE_2D_ARRAY:544case PIPE_TEXTURE_CUBE_ARRAY:545st->slice = st->base.box.z;546st->box.z = 0; /* so we don't apply double offsets below */547548/* Force direct map for transfering multiple slices */549if (st->base.box.depth > 1)550use_direct_map = svga_have_gb_objects(svga);551552break;553default:554st->slice = 0;555break;556}557558/* Force direct map for multisample surface */559if (texture->nr_samples > 1) {560assert(svga_have_gb_objects(svga));561assert(sws->have_sm4_1);562use_direct_map = TRUE;563}564565st->use_direct_map = use_direct_map;566pipe_resource_reference(&st->base.resource, texture);567568/* If this is the first time mapping to the surface in this569* command buffer and there is no pending primitives, clear570* the dirty masks of this surface.571*/572if (sws->surface_is_flushed(sws, surf) &&573(svga_have_vgpu10(svga) ||574!svga_hwtnl_has_pending_prim(svga->hwtnl))) {575svga_clear_texture_dirty(tex);576}577578if (!use_direct_map) {579/* upload to the DMA buffer */580map = svga_texture_transfer_map_dma(svga, st);581}582else {583boolean can_use_upload = tex->can_use_upload &&584!(st->base.usage & PIPE_MAP_READ);585boolean was_rendered_to =586svga_was_texture_rendered_to(svga_texture(texture),587st->slice, st->base.level);588589/* If the texture was already rendered to and upload buffer590* is supported, then we will use upload buffer to591* avoid the need to read back the texture content; otherwise,592* we'll first try to map directly to the GB surface, if it is blocked,593* then we'll try the upload buffer.594*/595if (was_rendered_to && can_use_upload) {596map = svga_texture_transfer_map_upload(svga, st);597}598else {599unsigned orig_usage = st->base.usage;600601/* First try directly map to the GB surface */602if (can_use_upload)603st->base.usage |= PIPE_MAP_DONTBLOCK;604map = svga_texture_transfer_map_direct(svga, st);605st->base.usage = orig_usage;606607if (!map && can_use_upload) {608/* if direct map with DONTBLOCK fails, then try upload to the609* texture upload buffer.610*/611map = svga_texture_transfer_map_upload(svga, st);612}613}614615/* If upload fails, then try direct map again without forcing it616* to DONTBLOCK.617*/618if (!map) {619map = svga_texture_transfer_map_direct(svga, st);620}621}622623if (!map) {624FREE(st);625}626else {627*ptransfer = &st->base;628svga->hud.num_textures_mapped++;629if (usage & PIPE_MAP_WRITE) {630/* record texture upload for HUD */631svga->hud.num_bytes_uploaded +=632st->base.layer_stride * st->box.d;633634/* mark this texture level as dirty */635svga_set_texture_dirty(tex, st->slice, level);636}637}638639done:640svga->hud.map_buffer_time += (svga_get_time(svga) - begin);641SVGA_STATS_TIME_POP(sws);642(void) sws;643644return map;645}646647/**648* Unmap a GB texture surface.649*/650static void651svga_texture_surface_unmap(struct svga_context *svga,652struct pipe_transfer *transfer)653{654struct svga_winsys_surface *surf = svga_texture(transfer->resource)->handle;655struct svga_winsys_context *swc = svga->swc;656boolean rebind;657658assert(surf);659660swc->surface_unmap(swc, surf, &rebind);661if (rebind) {662SVGA_RETRY(svga, SVGA3D_BindGBSurface(swc, surf));663}664}665666667static void668update_image_vgpu9(struct svga_context *svga,669struct svga_winsys_surface *surf,670const SVGA3dBox *box,671unsigned slice,672unsigned level)673{674SVGA_RETRY(svga, SVGA3D_UpdateGBImage(svga->swc, surf, box, slice, level));675}676677678static void679update_image_vgpu10(struct svga_context *svga,680struct svga_winsys_surface *surf,681const SVGA3dBox *box,682unsigned slice,683unsigned level,684unsigned numMipLevels)685{686unsigned subResource;687688subResource = slice * numMipLevels + level;689690SVGA_RETRY(svga, SVGA3D_vgpu10_UpdateSubResource(svga->swc, surf, box,691subResource));692}693694695/**696* unmap DMA transfer request697*/698static void699svga_texture_transfer_unmap_dma(struct svga_context *svga,700struct svga_transfer *st)701{702struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;703704if (!st->swbuf)705sws->buffer_unmap(sws, st->hwbuf);706707if (st->base.usage & PIPE_MAP_WRITE) {708/* Use DMA to transfer texture data */709SVGA3dSurfaceDMAFlags flags;710struct pipe_resource *texture = st->base.resource;711struct svga_texture *tex = svga_texture(texture);712713714memset(&flags, 0, sizeof flags);715if (st->base.usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) {716flags.discard = TRUE;717}718if (st->base.usage & PIPE_MAP_UNSYNCHRONIZED) {719flags.unsynchronized = TRUE;720}721722svga_transfer_dma(svga, st, SVGA3D_WRITE_HOST_VRAM, flags);723svga_set_texture_rendered_to(tex, st->slice, st->base.level);724}725726FREE(st->swbuf);727sws->buffer_destroy(sws, st->hwbuf);728}729730731/**732* unmap direct map transfer request733*/734static void735svga_texture_transfer_unmap_direct(struct svga_context *svga,736struct svga_transfer *st)737{738struct pipe_transfer *transfer = &st->base;739struct svga_texture *tex = svga_texture(transfer->resource);740741svga_texture_surface_unmap(svga, transfer);742743/* Now send an update command to update the content in the backend. */744if (st->base.usage & PIPE_MAP_WRITE) {745struct svga_winsys_surface *surf = tex->handle;746747assert(svga_have_gb_objects(svga));748749/* update the effected region */750SVGA3dBox box = st->box;751unsigned nlayers;752753switch (tex->b.target) {754case PIPE_TEXTURE_2D_ARRAY:755case PIPE_TEXTURE_CUBE_ARRAY:756case PIPE_TEXTURE_1D_ARRAY:757nlayers = box.d;758box.d = 1;759break;760default:761nlayers = 1;762break;763}764765766if (0)767debug_printf("%s %d, %d, %d %d x %d x %d\n",768__FUNCTION__,769box.x, box.y, box.z,770box.w, box.h, box.d);771772if (!svga->swc->force_coherent || tex->imported) {773if (svga_have_vgpu10(svga)) {774unsigned i;775776for (i = 0; i < nlayers; i++) {777update_image_vgpu10(svga, surf, &box,778st->slice + i, transfer->level,779tex->b.last_level + 1);780}781} else {782assert(nlayers == 1);783update_image_vgpu9(svga, surf, &box, st->slice,784transfer->level);785}786}787}788}789790791void792svga_texture_transfer_unmap(struct pipe_context *pipe,793struct pipe_transfer *transfer)794{795struct svga_context *svga = svga_context(pipe);796struct svga_screen *ss = svga_screen(pipe->screen);797struct svga_winsys_screen *sws = ss->sws;798struct svga_transfer *st = svga_transfer(transfer);799struct svga_texture *tex = svga_texture(transfer->resource);800801SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_TEXTRANSFERUNMAP);802803if (!st->use_direct_map) {804svga_texture_transfer_unmap_dma(svga, st);805}806else if (st->upload.buf) {807svga_texture_transfer_unmap_upload(svga, st);808}809else {810svga_texture_transfer_unmap_direct(svga, st);811}812813if (st->base.usage & PIPE_MAP_WRITE) {814svga->hud.num_resource_updates++;815816/* Mark the texture level as dirty */817ss->texture_timestamp++;818svga_age_texture_view(tex, transfer->level);819if (transfer->resource->target == PIPE_TEXTURE_CUBE)820svga_define_texture_level(tex, st->slice, transfer->level);821else822svga_define_texture_level(tex, 0, transfer->level);823}824825pipe_resource_reference(&st->base.resource, NULL);826FREE(st);827SVGA_STATS_TIME_POP(sws);828(void) sws;829}830831832/**833* Does format store depth values?834*/835static inline boolean836format_has_depth(enum pipe_format format)837{838const struct util_format_description *desc = util_format_description(format);839return util_format_has_depth(desc);840}841842struct pipe_resource *843svga_texture_create(struct pipe_screen *screen,844const struct pipe_resource *template)845{846struct svga_screen *svgascreen = svga_screen(screen);847struct svga_texture *tex;848unsigned bindings = template->bind;849850SVGA_STATS_TIME_PUSH(svgascreen->sws,851SVGA_STATS_TIME_CREATETEXTURE);852853assert(template->last_level < SVGA_MAX_TEXTURE_LEVELS);854if (template->last_level >= SVGA_MAX_TEXTURE_LEVELS) {855goto fail_notex;856}857858/* Verify the number of mipmap levels isn't impossibly large. For example,859* if the base 2D image is 16x16, we can't have 8 mipmap levels.860* the gallium frontend should never ask us to create a resource with invalid861* parameters.862*/863{864unsigned max_dim = template->width0;865866switch (template->target) {867case PIPE_TEXTURE_1D:868case PIPE_TEXTURE_1D_ARRAY:869// nothing870break;871case PIPE_TEXTURE_2D:872case PIPE_TEXTURE_CUBE:873case PIPE_TEXTURE_CUBE_ARRAY:874case PIPE_TEXTURE_2D_ARRAY:875max_dim = MAX2(max_dim, template->height0);876break;877case PIPE_TEXTURE_3D:878max_dim = MAX3(max_dim, template->height0, template->depth0);879break;880case PIPE_TEXTURE_RECT:881case PIPE_BUFFER:882assert(template->last_level == 0);883/* the assertion below should always pass */884break;885default:886debug_printf("Unexpected texture target type\n");887}888assert(1 << template->last_level <= max_dim);889}890891tex = CALLOC_STRUCT(svga_texture);892if (!tex) {893goto fail_notex;894}895896tex->defined = CALLOC(template->depth0 * template->array_size,897sizeof(tex->defined[0]));898if (!tex->defined) {899FREE(tex);900goto fail_notex;901}902903tex->rendered_to = CALLOC(template->depth0 * template->array_size,904sizeof(tex->rendered_to[0]));905if (!tex->rendered_to) {906goto fail;907}908909tex->dirty = CALLOC(template->depth0 * template->array_size,910sizeof(tex->dirty[0]));911if (!tex->dirty) {912goto fail;913}914915tex->b = *template;916pipe_reference_init(&tex->b.reference, 1);917tex->b.screen = screen;918919tex->key.flags = 0;920tex->key.size.width = template->width0;921tex->key.size.height = template->height0;922tex->key.size.depth = template->depth0;923tex->key.arraySize = 1;924tex->key.numFaces = 1;925926/* nr_samples=1 must be treated as a non-multisample texture */927if (tex->b.nr_samples == 1) {928tex->b.nr_samples = 0;929}930else if (tex->b.nr_samples > 1) {931assert(svgascreen->sws->have_sm4_1);932tex->key.flags |= SVGA3D_SURFACE_MULTISAMPLE;933}934935tex->key.sampleCount = tex->b.nr_samples;936937if (svgascreen->sws->have_vgpu10) {938switch (template->target) {939case PIPE_TEXTURE_1D:940tex->key.flags |= SVGA3D_SURFACE_1D;941break;942case PIPE_TEXTURE_1D_ARRAY:943tex->key.flags |= SVGA3D_SURFACE_1D;944FALLTHROUGH;945case PIPE_TEXTURE_2D_ARRAY:946tex->key.flags |= SVGA3D_SURFACE_ARRAY;947tex->key.arraySize = template->array_size;948break;949case PIPE_TEXTURE_3D:950tex->key.flags |= SVGA3D_SURFACE_VOLUME;951break;952case PIPE_TEXTURE_CUBE:953tex->key.flags |= (SVGA3D_SURFACE_CUBEMAP | SVGA3D_SURFACE_ARRAY);954tex->key.numFaces = 6;955break;956case PIPE_TEXTURE_CUBE_ARRAY:957assert(svgascreen->sws->have_sm4_1);958tex->key.flags |= (SVGA3D_SURFACE_CUBEMAP | SVGA3D_SURFACE_ARRAY);959tex->key.numFaces = 1; // arraySize already includes the 6 faces960tex->key.arraySize = template->array_size;961break;962default:963break;964}965}966else {967switch (template->target) {968case PIPE_TEXTURE_3D:969tex->key.flags |= SVGA3D_SURFACE_VOLUME;970break;971case PIPE_TEXTURE_CUBE:972tex->key.flags |= SVGA3D_SURFACE_CUBEMAP;973tex->key.numFaces = 6;974break;975default:976break;977}978}979980tex->key.cachable = 1;981982if ((bindings & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL)) &&983!(bindings & PIPE_BIND_SAMPLER_VIEW)) {984/* Also check if the format can be sampled from */985if (screen->is_format_supported(screen, template->format,986template->target,987template->nr_samples,988template->nr_storage_samples,989PIPE_BIND_SAMPLER_VIEW)) {990bindings |= PIPE_BIND_SAMPLER_VIEW;991}992}993994if (bindings & PIPE_BIND_SAMPLER_VIEW) {995tex->key.flags |= SVGA3D_SURFACE_HINT_TEXTURE;996tex->key.flags |= SVGA3D_SURFACE_BIND_SHADER_RESOURCE;997998if (!(bindings & PIPE_BIND_RENDER_TARGET)) {999/* Also check if the format is color renderable */1000if (screen->is_format_supported(screen, template->format,1001template->target,1002template->nr_samples,1003template->nr_storage_samples,1004PIPE_BIND_RENDER_TARGET)) {1005bindings |= PIPE_BIND_RENDER_TARGET;1006}1007}10081009if (!(bindings & PIPE_BIND_DEPTH_STENCIL)) {1010/* Also check if the format is depth/stencil renderable */1011if (screen->is_format_supported(screen, template->format,1012template->target,1013template->nr_samples,1014template->nr_storage_samples,1015PIPE_BIND_DEPTH_STENCIL)) {1016bindings |= PIPE_BIND_DEPTH_STENCIL;1017}1018}1019}10201021if (bindings & PIPE_BIND_DISPLAY_TARGET) {1022tex->key.cachable = 0;1023}10241025if (bindings & PIPE_BIND_SHARED) {1026tex->key.cachable = 0;1027}10281029if (bindings & (PIPE_BIND_SCANOUT | PIPE_BIND_CURSOR)) {1030tex->key.scanout = 1;1031tex->key.cachable = 0;1032}10331034/*1035* Note: Previously we never passed the1036* SVGA3D_SURFACE_HINT_RENDERTARGET hint. Mesa cannot1037* know beforehand whether a texture will be used as a rendertarget or not1038* and it always requests PIPE_BIND_RENDER_TARGET, therefore1039* passing the SVGA3D_SURFACE_HINT_RENDERTARGET here defeats its purpose.1040*1041* However, this was changed since other gallium frontends1042* (XA for example) uses it accurately and certain device versions1043* relies on it in certain situations to render correctly.1044*/1045if ((bindings & PIPE_BIND_RENDER_TARGET) &&1046!util_format_is_s3tc(template->format)) {1047tex->key.flags |= SVGA3D_SURFACE_HINT_RENDERTARGET;1048tex->key.flags |= SVGA3D_SURFACE_BIND_RENDER_TARGET;1049}10501051if (bindings & PIPE_BIND_DEPTH_STENCIL) {1052tex->key.flags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL;1053tex->key.flags |= SVGA3D_SURFACE_BIND_DEPTH_STENCIL;1054}10551056tex->key.numMipLevels = template->last_level + 1;10571058tex->key.format = svga_translate_format(svgascreen, template->format,1059bindings);1060if (tex->key.format == SVGA3D_FORMAT_INVALID) {1061goto fail;1062}10631064/* Use typeless formats for sRGB and depth resources. Typeless1065* formats can be reinterpreted as other formats. For example,1066* SVGA3D_R8G8B8A8_UNORM_TYPELESS can be interpreted as1067* SVGA3D_R8G8B8A8_UNORM_SRGB or SVGA3D_R8G8B8A8_UNORM.1068*/1069if (svgascreen->sws->have_vgpu10 &&1070(util_format_is_srgb(template->format) ||1071format_has_depth(template->format))) {1072SVGA3dSurfaceFormat typeless = svga_typeless_format(tex->key.format);1073if (0) {1074debug_printf("Convert resource type %s -> %s (bind 0x%x)\n",1075svga_format_name(tex->key.format),1076svga_format_name(typeless),1077bindings);1078}10791080if (svga_format_is_uncompressed_snorm(tex->key.format)) {1081/* We can't normally render to snorm surfaces, but once we1082* substitute a typeless format, we can if the rendertarget view1083* is unorm. This can happen with GL_ARB_copy_image.1084*/1085tex->key.flags |= SVGA3D_SURFACE_HINT_RENDERTARGET;1086tex->key.flags |= SVGA3D_SURFACE_BIND_RENDER_TARGET;1087}10881089tex->key.format = typeless;1090}10911092SVGA_DBG(DEBUG_DMA, "surface_create for texture\n");1093tex->handle = svga_screen_surface_create(svgascreen, bindings,1094tex->b.usage,1095&tex->validated, &tex->key);1096if (!tex->handle) {1097goto fail;1098}10991100SVGA_DBG(DEBUG_DMA, " --> got sid %p (texture)\n", tex->handle);11011102debug_reference(&tex->b.reference,1103(debug_reference_descriptor)debug_describe_resource, 0);11041105tex->size = util_resource_size(template);11061107/* Determine if texture upload buffer can be used to upload this texture */1108tex->can_use_upload = svga_texture_transfer_map_can_upload(svgascreen,1109&tex->b);11101111/* Initialize the backing resource cache */1112tex->backed_handle = NULL;11131114svgascreen->hud.total_resource_bytes += tex->size;1115svgascreen->hud.num_resources++;11161117SVGA_STATS_TIME_POP(svgascreen->sws);11181119return &tex->b;11201121fail:1122if (tex->dirty)1123FREE(tex->dirty);1124if (tex->rendered_to)1125FREE(tex->rendered_to);1126if (tex->defined)1127FREE(tex->defined);1128FREE(tex);1129fail_notex:1130SVGA_STATS_TIME_POP(svgascreen->sws);1131return NULL;1132}113311341135struct pipe_resource *1136svga_texture_from_handle(struct pipe_screen *screen,1137const struct pipe_resource *template,1138struct winsys_handle *whandle)1139{1140struct svga_winsys_screen *sws = svga_winsys_screen(screen);1141struct svga_screen *ss = svga_screen(screen);1142struct svga_winsys_surface *srf;1143struct svga_texture *tex;1144enum SVGA3dSurfaceFormat format = 0;1145assert(screen);11461147/* Only supports one type */1148if ((template->target != PIPE_TEXTURE_2D &&1149template->target != PIPE_TEXTURE_RECT) ||1150template->last_level != 0 ||1151template->depth0 != 1) {1152return NULL;1153}11541155srf = sws->surface_from_handle(sws, whandle, &format);11561157if (!srf)1158return NULL;11591160if (!svga_format_is_shareable(ss, template->format, format,1161template->bind, true))1162goto out_unref;11631164tex = CALLOC_STRUCT(svga_texture);1165if (!tex)1166goto out_unref;11671168tex->defined = CALLOC(template->depth0 * template->array_size,1169sizeof(tex->defined[0]));1170if (!tex->defined)1171goto out_no_defined;11721173tex->b = *template;1174pipe_reference_init(&tex->b.reference, 1);1175tex->b.screen = screen;11761177SVGA_DBG(DEBUG_DMA, "wrap surface sid %p\n", srf);11781179tex->key.cachable = 0;1180tex->key.format = format;1181tex->handle = srf;11821183tex->rendered_to = CALLOC(1, sizeof(tex->rendered_to[0]));1184if (!tex->rendered_to)1185goto out_no_rendered_to;11861187tex->dirty = CALLOC(1, sizeof(tex->dirty[0]));1188if (!tex->dirty)1189goto out_no_dirty;11901191tex->imported = TRUE;11921193ss->hud.num_resources++;11941195return &tex->b;11961197out_no_dirty:1198FREE(tex->rendered_to);1199out_no_rendered_to:1200FREE(tex->defined);1201out_no_defined:1202FREE(tex);1203out_unref:1204sws->surface_reference(sws, &srf, NULL);1205return NULL;1206}12071208bool1209svga_texture_generate_mipmap(struct pipe_context *pipe,1210struct pipe_resource *pt,1211enum pipe_format format,1212unsigned base_level,1213unsigned last_level,1214unsigned first_layer,1215unsigned last_layer)1216{1217struct pipe_sampler_view templ, *psv;1218struct svga_pipe_sampler_view *sv;1219struct svga_context *svga = svga_context(pipe);1220struct svga_texture *tex = svga_texture(pt);12211222assert(svga_have_vgpu10(svga));12231224/* Only support 2D texture for now */1225if (pt->target != PIPE_TEXTURE_2D)1226return false;12271228/* Fallback to the mipmap generation utility for those formats that1229* do not support hw generate mipmap1230*/1231if (!svga_format_support_gen_mips(format))1232return false;12331234/* Make sure the texture surface was created with1235* SVGA3D_SURFACE_BIND_RENDER_TARGET1236*/1237if (!tex->handle || !(tex->key.flags & SVGA3D_SURFACE_BIND_RENDER_TARGET))1238return false;12391240templ.format = format;1241templ.u.tex.first_layer = first_layer;1242templ.u.tex.last_layer = last_layer;1243templ.u.tex.first_level = base_level;1244templ.u.tex.last_level = last_level;12451246psv = pipe->create_sampler_view(pipe, pt, &templ);1247if (psv == NULL)1248return false;12491250sv = svga_pipe_sampler_view(psv);1251SVGA_RETRY(svga, svga_validate_pipe_sampler_view(svga, sv));12521253SVGA_RETRY(svga, SVGA3D_vgpu10_GenMips(svga->swc, sv->id, tex->handle));1254pipe_sampler_view_reference(&psv, NULL);12551256svga->hud.num_generate_mipmap++;12571258return true;1259}126012611262/* texture upload buffer default size in bytes */1263#define TEX_UPLOAD_DEFAULT_SIZE (1024 * 1024)12641265/**1266* Create a texture upload buffer1267*/1268boolean1269svga_texture_transfer_map_upload_create(struct svga_context *svga)1270{1271svga->tex_upload = u_upload_create(&svga->pipe, TEX_UPLOAD_DEFAULT_SIZE,1272PIPE_BIND_CUSTOM, PIPE_USAGE_STAGING, 0);1273if (svga->tex_upload)1274u_upload_disable_persistent(svga->tex_upload);12751276return svga->tex_upload != NULL;1277}127812791280/**1281* Destroy the texture upload buffer1282*/1283void1284svga_texture_transfer_map_upload_destroy(struct svga_context *svga)1285{1286u_upload_destroy(svga->tex_upload);1287}128812891290/**1291* Returns true if this transfer map request can use the upload buffer.1292*/1293boolean1294svga_texture_transfer_map_can_upload(const struct svga_screen *svgascreen,1295const struct pipe_resource *texture)1296{1297if (svgascreen->sws->have_transfer_from_buffer_cmd == FALSE)1298return FALSE;12991300/* TransferFromBuffer command is not well supported with multi-samples surface */1301if (texture->nr_samples > 1)1302return FALSE;13031304if (util_format_is_compressed(texture->format)) {1305/* XXX Need to take a closer look to see why texture upload1306* with 3D texture with compressed format fails1307*/1308if (texture->target == PIPE_TEXTURE_3D)1309return FALSE;1310}1311else if (texture->format == PIPE_FORMAT_R9G9B9E5_FLOAT) {1312return FALSE;1313}13141315return TRUE;1316}131713181319/**1320* Use upload buffer for the transfer map request.1321*/1322void *1323svga_texture_transfer_map_upload(struct svga_context *svga,1324struct svga_transfer *st)1325{1326struct pipe_resource *texture = st->base.resource;1327struct pipe_resource *tex_buffer = NULL;1328void *tex_map;1329unsigned nblocksx, nblocksy;1330unsigned offset;1331unsigned upload_size;13321333assert(svga->tex_upload);13341335st->upload.box.x = st->base.box.x;1336st->upload.box.y = st->base.box.y;1337st->upload.box.z = st->base.box.z;1338st->upload.box.w = st->base.box.width;1339st->upload.box.h = st->base.box.height;1340st->upload.box.d = st->base.box.depth;1341st->upload.nlayers = 1;13421343switch (texture->target) {1344case PIPE_TEXTURE_CUBE:1345st->upload.box.z = 0;1346break;1347case PIPE_TEXTURE_2D_ARRAY:1348case PIPE_TEXTURE_CUBE_ARRAY:1349st->upload.nlayers = st->base.box.depth;1350st->upload.box.z = 0;1351st->upload.box.d = 1;1352break;1353case PIPE_TEXTURE_1D_ARRAY:1354st->upload.nlayers = st->base.box.depth;1355st->upload.box.y = st->upload.box.z = 0;1356st->upload.box.d = 1;1357break;1358default:1359break;1360}13611362nblocksx = util_format_get_nblocksx(texture->format, st->base.box.width);1363nblocksy = util_format_get_nblocksy(texture->format, st->base.box.height);13641365st->base.stride = nblocksx * util_format_get_blocksize(texture->format);1366st->base.layer_stride = st->base.stride * nblocksy;13671368/* In order to use the TransferFromBuffer command to update the1369* texture content from the buffer, the layer stride for a multi-layers1370* surface needs to be in multiples of 16 bytes.1371*/1372if (st->upload.nlayers > 1 && st->base.layer_stride & 15)1373return NULL;13741375upload_size = st->base.layer_stride * st->base.box.depth;1376upload_size = align(upload_size, 16);13771378#ifdef DEBUG1379if (util_format_is_compressed(texture->format)) {1380struct svga_texture *tex = svga_texture(texture);1381unsigned blockw, blockh, bytesPerBlock;13821383svga_format_size(tex->key.format, &blockw, &blockh, &bytesPerBlock);13841385/* dest box must start on block boundary */1386assert((st->base.box.x % blockw) == 0);1387assert((st->base.box.y % blockh) == 0);1388}1389#endif13901391/* If the upload size exceeds the default buffer size, the1392* upload buffer manager code will try to allocate a new buffer1393* with the new buffer size.1394*/1395u_upload_alloc(svga->tex_upload, 0, upload_size, 16,1396&offset, &tex_buffer, &tex_map);13971398if (!tex_map) {1399return NULL;1400}14011402st->upload.buf = tex_buffer;1403st->upload.map = tex_map;1404st->upload.offset = offset;14051406return tex_map;1407}140814091410/**1411* Unmap upload map transfer request1412*/1413void1414svga_texture_transfer_unmap_upload(struct svga_context *svga,1415struct svga_transfer *st)1416{1417struct svga_winsys_surface *srcsurf;1418struct svga_winsys_surface *dstsurf;1419struct pipe_resource *texture = st->base.resource;1420struct svga_texture *tex = svga_texture(texture);1421unsigned subResource;1422unsigned numMipLevels;1423unsigned i, layer;1424unsigned offset = st->upload.offset;14251426assert(svga->tex_upload);1427assert(st->upload.buf);14281429/* unmap the texture upload buffer */1430u_upload_unmap(svga->tex_upload);14311432srcsurf = svga_buffer_handle(svga, st->upload.buf, 0);1433dstsurf = svga_texture(texture)->handle;1434assert(dstsurf);14351436numMipLevels = texture->last_level + 1;14371438for (i = 0, layer = st->slice; i < st->upload.nlayers; i++, layer++) {1439subResource = layer * numMipLevels + st->base.level;14401441/* send a transferFromBuffer command to update the host texture surface */1442assert((offset & 15) == 0);14431444SVGA_RETRY(svga, SVGA3D_vgpu10_TransferFromBuffer(svga->swc, srcsurf,1445offset,1446st->base.stride,1447st->base.layer_stride,1448dstsurf, subResource,1449&st->upload.box));1450offset += st->base.layer_stride;14511452/* Set rendered-to flag */1453svga_set_texture_rendered_to(tex, layer, st->base.level);1454}14551456pipe_resource_reference(&st->upload.buf, NULL);1457}14581459/**1460* Does the device format backing this surface have an1461* alpha channel?1462*1463* \param texture[in] The texture whose format we're querying1464* \return TRUE if the format has an alpha channel, FALSE otherwise1465*1466* For locally created textures, the device (svga) format is typically1467* identical to svga_format(texture->format), and we can use the gallium1468* format tests to determine whether the device format has an alpha channel1469* or not. However, for textures backed by imported svga surfaces that is1470* not always true, and we have to look at the SVGA3D utilities.1471*/1472boolean1473svga_texture_device_format_has_alpha(struct pipe_resource *texture)1474{1475/* the svga_texture() call below is invalid for PIPE_BUFFER resources */1476assert(texture->target != PIPE_BUFFER);14771478enum svga3d_block_desc block_desc =1479svga3dsurface_get_desc(svga_texture(texture)->key.format)->block_desc;14801481return !!(block_desc & SVGA3DBLOCKDESC_ALPHA);1482}148314841485