Path: blob/21.2-virgl/src/gallium/frontends/nine/basetexture9.c
4561 views
/*1* Copyright 2011 Joakim Sindholt <[email protected]>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* on the rights to use, copy, modify, merge, publish, distribute, sub7* license, and/or sell copies of the Software, and to permit persons to whom8* the Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL17* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,18* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR19* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE20* USE OR OTHER DEALINGS IN THE SOFTWARE. */2122#include "basetexture9.h"23#include "device9.h"2425/* For UploadSelf: */26#include "texture9.h"27#include "cubetexture9.h"28#include "volumetexture9.h"29#include "nine_pipe.h"3031#if defined(DEBUG) || !defined(NDEBUG)32#include "nine_dump.h"33#endif3435#include "util/format/u_format.h"3637#define DBG_CHANNEL DBG_BASETEXTURE3839HRESULT40NineBaseTexture9_ctor( struct NineBaseTexture9 *This,41struct NineUnknownParams *pParams,42struct pipe_resource *initResource,43D3DRESOURCETYPE Type,44D3DFORMAT format,45D3DPOOL Pool,46DWORD Usage)47{48BOOL alloc = (Pool == D3DPOOL_DEFAULT) && !initResource &&49(format != D3DFMT_NULL);50HRESULT hr;5152DBG("This=%p, pParams=%p initResource=%p Type=%d format=%d Pool=%d Usage=%d\n",53This, pParams, initResource, Type, format, Pool, Usage);5455user_assert(!(Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) ||56Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);57user_assert(!(Usage & D3DUSAGE_DYNAMIC) ||58!(Pool == D3DPOOL_MANAGED ||59Pool == D3DPOOL_SCRATCH), D3DERR_INVALIDCALL);6061hr = NineResource9_ctor(&This->base, pParams, initResource, alloc, Type, Pool, Usage);62if (FAILED(hr))63return hr;6465This->format = format;66This->mipfilter = (Usage & D3DUSAGE_AUTOGENMIPMAP) ?67D3DTEXF_LINEAR : D3DTEXF_NONE;68/* In the case of D3DUSAGE_AUTOGENMIPMAP, only the first level is accessible,69* and thus needs a surface created. */70This->level_count = (Usage & D3DUSAGE_AUTOGENMIPMAP) ? 1 : (This->base.info.last_level+1);71This->managed.lod = 0;72This->managed.lod_resident = -1;73/* Mark the texture as dirty to trigger first upload when we need the texture,74* even if it wasn't set by the application */75if (Pool == D3DPOOL_MANAGED)76This->managed.dirty = TRUE;77/* When a depth buffer is sampled, it is for shadow mapping, except for78* D3DFMT_INTZ, D3DFMT_DF16 and D3DFMT_DF24.79* In addition D3DFMT_INTZ can be used for both texturing and depth buffering80* if z write is disabled. This particular feature may not work for us in81* practice because OGL doesn't have that. However apparently it is known82* some cards have performance issues with this feature, so real apps83* shouldn't use it. */84This->shadow = (This->format != D3DFMT_INTZ && This->format != D3DFMT_DF16 &&85This->format != D3DFMT_DF24) &&86util_format_has_depth(util_format_description(This->base.info.format));87This->fetch4_compatible = fetch4_compatible_format(This->format);8889list_inithead(&This->list);90list_inithead(&This->list2);91if (Pool == D3DPOOL_MANAGED)92list_add(&This->list2, &This->base.base.device->managed_textures);9394return D3D_OK;95}9697void98NineBaseTexture9_dtor( struct NineBaseTexture9 *This )99{100DBG("This=%p\n", This);101102pipe_sampler_view_reference(&This->view[0], NULL);103pipe_sampler_view_reference(&This->view[1], NULL);104105if (list_is_linked(&This->list))106list_del(&This->list);107if (list_is_linked(&This->list2))108list_del(&This->list2);109110NineResource9_dtor(&This->base);111}112113DWORD NINE_WINAPI114NineBaseTexture9_SetLOD( struct NineBaseTexture9 *This,115DWORD LODNew )116{117DWORD old = This->managed.lod;118119DBG("This=%p LODNew=%d\n", This, LODNew);120121user_assert(This->base.pool == D3DPOOL_MANAGED, 0);122123This->managed.lod = MIN2(LODNew, This->level_count-1);124125if (This->managed.lod != old && This->bind_count && list_is_empty(&This->list))126list_add(&This->list, &This->base.base.device->update_textures);127128return old;129}130131DWORD NINE_WINAPI132NineBaseTexture9_GetLOD( struct NineBaseTexture9 *This )133{134DBG("This=%p\n", This);135136return This->managed.lod;137}138139DWORD NINE_WINAPI140NineBaseTexture9_GetLevelCount( struct NineBaseTexture9 *This )141{142DBG("This=%p\n", This);143144return This->level_count;145}146147HRESULT NINE_WINAPI148NineBaseTexture9_SetAutoGenFilterType( struct NineBaseTexture9 *This,149D3DTEXTUREFILTERTYPE FilterType )150{151DBG("This=%p FilterType=%d\n", This, FilterType);152153if (!(This->base.usage & D3DUSAGE_AUTOGENMIPMAP))154return D3D_OK;155user_assert(FilterType != D3DTEXF_NONE, D3DERR_INVALIDCALL);156157This->mipfilter = FilterType;158This->dirty_mip = TRUE;159NineBaseTexture9_GenerateMipSubLevels(This);160161return D3D_OK;162}163164D3DTEXTUREFILTERTYPE NINE_WINAPI165NineBaseTexture9_GetAutoGenFilterType( struct NineBaseTexture9 *This )166{167DBG("This=%p\n", This);168169return This->mipfilter;170}171172HRESULT173NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )174{175HRESULT hr;176unsigned l, min_level_dirty = This->managed.lod;177BOOL update_lod;178179DBG("This=%p dirty=%i type=%s\n", This, This->managed.dirty,180nine_D3DRTYPE_to_str(This->base.type));181182assert(This->base.pool == D3DPOOL_MANAGED);183184update_lod = This->managed.lod_resident != This->managed.lod;185if (!update_lod && !This->managed.dirty)186return D3D_OK;187188/* Allocate a new resource with the correct number of levels,189* Mark states for update, and tell the nine surfaces/volumes190* their new resource. */191if (update_lod) {192struct pipe_resource *res;193194DBG("updating LOD from %u to %u ...\n", This->managed.lod_resident, This->managed.lod);195196pipe_sampler_view_reference(&This->view[0], NULL);197pipe_sampler_view_reference(&This->view[1], NULL);198199/* Allocate a new resource */200hr = NineBaseTexture9_CreatePipeResource(This, This->managed.lod_resident != -1);201if (FAILED(hr))202return hr;203res = This->base.resource;204205if (This->managed.lod_resident == -1) {/* no levels were resident */206This->managed.dirty = FALSE; /* We are going to upload everything. */207This->managed.lod_resident = This->level_count;208}209210if (This->base.type == D3DRTYPE_TEXTURE) {211struct NineTexture9 *tex = NineTexture9(This);212213/* last content (if apply) has been copied to the new resource.214* Note: We cannot render to surfaces of managed textures.215* Note2: the level argument passed is to get the level offset216* right when the texture is uploaded (the texture first level217* corresponds to This->managed.lod).218* Note3: We don't care about the value passed for the surfaces219* before This->managed.lod, negative with this implementation. */220for (l = 0; l < This->level_count; ++l)221NineSurface9_SetResource(tex->surfaces[l], res, l - This->managed.lod);222} else223if (This->base.type == D3DRTYPE_CUBETEXTURE) {224struct NineCubeTexture9 *tex = NineCubeTexture9(This);225unsigned z;226227for (l = 0; l < This->level_count; ++l) {228for (z = 0; z < 6; ++z)229NineSurface9_SetResource(tex->surfaces[l * 6 + z],230res, l - This->managed.lod);231}232} else233if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {234struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);235236for (l = 0; l < This->level_count; ++l)237NineVolume9_SetResource(tex->volumes[l], res, l - This->managed.lod);238} else {239assert(!"invalid texture type");240}241242/* We are going to fully upload the new levels,243* no need to update dirty parts of the texture for these */244min_level_dirty = MAX2(This->managed.lod, This->managed.lod_resident);245}246247/* Update dirty parts of the texture */248if (This->managed.dirty) {249if (This->base.type == D3DRTYPE_TEXTURE) {250struct NineTexture9 *tex = NineTexture9(This);251struct pipe_box box;252box.z = 0;253box.depth = 1;254255DBG("TEXTURE: dirty rect=(%u,%u) (%ux%u)\n",256tex->dirty_rect.x, tex->dirty_rect.y,257tex->dirty_rect.width, tex->dirty_rect.height);258259/* Note: for l < min_level_dirty, the resource is260* either non-existing (and thus will be entirely re-uploaded261* if the lod changes) or going to have a full upload */262if (tex->dirty_rect.width) {263for (l = min_level_dirty; l < This->level_count; ++l) {264u_box_minify_2d(&box, &tex->dirty_rect, l);265NineSurface9_UploadSelf(tex->surfaces[l], &box);266}267memset(&tex->dirty_rect, 0, sizeof(tex->dirty_rect));268tex->dirty_rect.depth = 1;269}270} else271if (This->base.type == D3DRTYPE_CUBETEXTURE) {272struct NineCubeTexture9 *tex = NineCubeTexture9(This);273unsigned z;274struct pipe_box box;275box.z = 0;276box.depth = 1;277278for (z = 0; z < 6; ++z) {279DBG("FACE[%u]: dirty rect=(%u,%u) (%ux%u)\n", z,280tex->dirty_rect[z].x, tex->dirty_rect[z].y,281tex->dirty_rect[z].width, tex->dirty_rect[z].height);282283if (tex->dirty_rect[z].width) {284for (l = min_level_dirty; l < This->level_count; ++l) {285u_box_minify_2d(&box, &tex->dirty_rect[z], l);286NineSurface9_UploadSelf(tex->surfaces[l * 6 + z], &box);287}288memset(&tex->dirty_rect[z], 0, sizeof(tex->dirty_rect[z]));289tex->dirty_rect[z].depth = 1;290}291}292} else293if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {294struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);295struct pipe_box box;296297DBG("VOLUME: dirty_box=(%u,%u,%u) (%ux%ux%u)\n",298tex->dirty_box.x, tex->dirty_box.y, tex->dirty_box.y,299tex->dirty_box.width, tex->dirty_box.height, tex->dirty_box.depth);300301if (tex->dirty_box.width) {302for (l = min_level_dirty; l < This->level_count; ++l) {303u_box_minify_3d(&box, &tex->dirty_box, l);304NineVolume9_UploadSelf(tex->volumes[l], &box);305}306memset(&tex->dirty_box, 0, sizeof(tex->dirty_box));307}308} else {309assert(!"invalid texture type");310}311This->managed.dirty = FALSE;312}313314/* Upload the new levels */315if (update_lod) {316if (This->base.type == D3DRTYPE_TEXTURE) {317struct NineTexture9 *tex = NineTexture9(This);318struct pipe_box box;319320box.x = box.y = box.z = 0;321box.depth = 1;322for (l = This->managed.lod; l < This->managed.lod_resident; ++l) {323box.width = u_minify(This->base.info.width0, l);324box.height = u_minify(This->base.info.height0, l);325NineSurface9_UploadSelf(tex->surfaces[l], &box);326}327} else328if (This->base.type == D3DRTYPE_CUBETEXTURE) {329struct NineCubeTexture9 *tex = NineCubeTexture9(This);330struct pipe_box box;331unsigned z;332333box.x = box.y = box.z = 0;334box.depth = 1;335for (l = This->managed.lod; l < This->managed.lod_resident; ++l) {336box.width = u_minify(This->base.info.width0, l);337box.height = u_minify(This->base.info.height0, l);338for (z = 0; z < 6; ++z)339NineSurface9_UploadSelf(tex->surfaces[l * 6 + z], &box);340}341} else342if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {343struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);344struct pipe_box box;345346box.x = box.y = box.z = 0;347for (l = This->managed.lod; l < This->managed.lod_resident; ++l) {348box.width = u_minify(This->base.info.width0, l);349box.height = u_minify(This->base.info.height0, l);350box.depth = u_minify(This->base.info.depth0, l);351NineVolume9_UploadSelf(tex->volumes[l], &box);352}353} else {354assert(!"invalid texture type");355}356357This->managed.lod_resident = This->managed.lod;358}359360if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)361This->dirty_mip = TRUE;362363/* Set again the textures currently bound to update the texture data */364if (This->bind_count) {365struct nine_state *state = &This->base.base.device->state;366unsigned s;367for (s = 0; s < NINE_MAX_SAMPLERS; ++s)368/* Dirty tracking is done in device9 state, not nine_context. */369if (state->texture[s] == This)370nine_context_set_texture(This->base.base.device, s, This);371}372373DBG("DONE, generate mip maps = %i\n", This->dirty_mip);374return D3D_OK;375}376377void NINE_WINAPI378NineBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This )379{380unsigned base_level = 0;381unsigned last_level = This->base.info.last_level - This->managed.lod;382unsigned first_layer = 0;383unsigned last_layer;384unsigned filter = This->mipfilter == D3DTEXF_POINT ? PIPE_TEX_FILTER_NEAREST385: PIPE_TEX_FILTER_LINEAR;386DBG("This=%p\n", This);387388if (This->base.pool == D3DPOOL_MANAGED)389NineBaseTexture9_UploadSelf(This);390if (!This->dirty_mip)391return;392if (This->managed.lod) {393ERR("AUTOGENMIPMAP if level 0 is not resident not supported yet !\n");394return;395}396397if (!This->view[0])398NineBaseTexture9_UpdateSamplerView(This, 0);399400last_layer = util_max_layer(This->view[0]->texture, base_level);401402nine_context_gen_mipmap(This->base.base.device, (struct NineUnknown *)This,403This->base.resource,404base_level, last_level,405first_layer, last_layer, filter);406407This->dirty_mip = FALSE;408}409410HRESULT411NineBaseTexture9_CreatePipeResource( struct NineBaseTexture9 *This,412BOOL CopyData )413{414struct pipe_context *pipe;415struct pipe_screen *screen = This->base.info.screen;416struct pipe_resource templ;417unsigned l, m;418struct pipe_resource *res;419struct pipe_resource *old = This->base.resource;420421DBG("This=%p lod=%u last_level=%u\n", This,422This->managed.lod, This->base.info.last_level);423424assert(This->base.pool == D3DPOOL_MANAGED);425426templ = This->base.info;427428if (This->managed.lod) {429templ.width0 = u_minify(templ.width0, This->managed.lod);430templ.height0 = u_minify(templ.height0, This->managed.lod);431templ.depth0 = u_minify(templ.depth0, This->managed.lod);432}433templ.last_level = This->base.info.last_level - This->managed.lod;434435if (old) {436/* LOD might have changed. */437if (old->width0 == templ.width0 &&438old->height0 == templ.height0 &&439old->depth0 == templ.depth0)440return D3D_OK;441}442443res = nine_resource_create_with_retry(This->base.base.device, screen, &templ);444if (!res)445return D3DERR_OUTOFVIDEOMEMORY;446This->base.resource = res;447448if (old && CopyData) { /* Don't return without releasing old ! */449struct pipe_box box;450box.x = 0;451box.y = 0;452box.z = 0;453454l = (This->managed.lod < This->managed.lod_resident) ? This->managed.lod_resident - This->managed.lod : 0;455m = (This->managed.lod < This->managed.lod_resident) ? 0 : This->managed.lod - This->managed.lod_resident;456457box.width = u_minify(templ.width0, l);458box.height = u_minify(templ.height0, l);459box.depth = u_minify(templ.depth0, l);460461pipe = nine_context_get_pipe_acquire(This->base.base.device);462463for (; l <= templ.last_level; ++l, ++m) {464pipe->resource_copy_region(pipe,465res, l, 0, 0, 0,466old, m, &box);467box.width = u_minify(box.width, 1);468box.height = u_minify(box.height, 1);469box.depth = u_minify(box.depth, 1);470}471472nine_context_get_pipe_release(This->base.base.device);473}474pipe_resource_reference(&old, NULL);475476return D3D_OK;477}478479#define SWIZZLE_TO_REPLACE(s) (s == PIPE_SWIZZLE_0 || \480s == PIPE_SWIZZLE_1 || \481s == PIPE_SWIZZLE_NONE)482483HRESULT484NineBaseTexture9_UpdateSamplerView( struct NineBaseTexture9 *This,485const int sRGB )486{487const struct util_format_description *desc;488struct pipe_context *pipe;489struct pipe_screen *screen = NineDevice9_GetScreen(This->base.base.device);490struct pipe_resource *resource = This->base.resource;491struct pipe_sampler_view templ;492enum pipe_format srgb_format;493unsigned i;494uint8_t swizzle[4];495496DBG("This=%p sRGB=%d\n", This, sRGB);497498if (unlikely(!resource)) {499if (unlikely(This->format == D3DFMT_NULL))500return D3D_OK;501NineBaseTexture9_Dump(This);502}503assert(resource);504505pipe_sampler_view_reference(&This->view[sRGB], NULL);506507swizzle[0] = PIPE_SWIZZLE_X;508swizzle[1] = PIPE_SWIZZLE_Y;509swizzle[2] = PIPE_SWIZZLE_Z;510swizzle[3] = PIPE_SWIZZLE_W;511desc = util_format_description(resource->format);512if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {513/* msdn doc is incomplete here and wrong.514* The only formats that can be read directly here515* are DF16, DF24 and INTZ.516* Tested on win the swizzle is517* R = depth, G = B = 0, A = 1 for DF16 and DF24518* R = G = B = A = depth for INTZ519* For the other ZS formats that can't be read directly520* but can be used as shadow map, the result is duplicated on521* all channel */522if (This->format == D3DFMT_DF16 ||523This->format == D3DFMT_DF24) {524swizzle[1] = PIPE_SWIZZLE_0;525swizzle[2] = PIPE_SWIZZLE_0;526swizzle[3] = PIPE_SWIZZLE_1;527} else {528swizzle[1] = PIPE_SWIZZLE_X;529swizzle[2] = PIPE_SWIZZLE_X;530swizzle[3] = PIPE_SWIZZLE_X;531}532} else if (resource->format == PIPE_FORMAT_RGTC2_UNORM) {533swizzle[0] = PIPE_SWIZZLE_Y;534swizzle[1] = PIPE_SWIZZLE_X;535swizzle[2] = PIPE_SWIZZLE_1;536swizzle[3] = PIPE_SWIZZLE_1;537} else if (resource->format != PIPE_FORMAT_A8_UNORM &&538resource->format != PIPE_FORMAT_RGTC1_UNORM) {539/* exceptions:540* A8 should have 0.0 as default values for RGB.541* ATI1/RGTC1 should be r 0 0 1 (tested on windows).542* It is already what gallium does. All the other ones543* should have 1.0 for non-defined values */544for (i = 0; i < 4; i++) {545if (SWIZZLE_TO_REPLACE(desc->swizzle[i]))546swizzle[i] = PIPE_SWIZZLE_1;547}548}549550/* if requested and supported, convert to the sRGB format */551srgb_format = util_format_srgb(resource->format);552if (sRGB && srgb_format != PIPE_FORMAT_NONE &&553screen->is_format_supported(screen, srgb_format,554resource->target, 0, 0, resource->bind))555templ.format = srgb_format;556else557templ.format = resource->format;558templ.u.tex.first_layer = 0;559templ.u.tex.last_layer = resource->target == PIPE_TEXTURE_3D ?5600 : resource->array_size - 1;561templ.u.tex.first_level = 0;562templ.u.tex.last_level = resource->last_level;563templ.swizzle_r = swizzle[0];564templ.swizzle_g = swizzle[1];565templ.swizzle_b = swizzle[2];566templ.swizzle_a = swizzle[3];567templ.target = resource->target;568569pipe = nine_context_get_pipe_acquire(This->base.base.device);570This->view[sRGB] = pipe->create_sampler_view(pipe, resource, &templ);571nine_context_get_pipe_release(This->base.base.device);572573DBG("sampler view = %p(resource = %p)\n", This->view[sRGB], resource);574575return This->view[sRGB] ? D3D_OK : D3DERR_DRIVERINTERNALERROR;576}577578void NINE_WINAPI579NineBaseTexture9_PreLoad( struct NineBaseTexture9 *This )580{581DBG("This=%p\n", This);582583if (This->base.pool == D3DPOOL_MANAGED)584NineBaseTexture9_UploadSelf(This);585}586587void588NineBaseTexture9_UnLoad( struct NineBaseTexture9 *This )589{590DBG("This=%p\n", This);591592if (This->base.pool != D3DPOOL_MANAGED ||593This->managed.lod_resident == -1)594return;595596DBG("This=%p, releasing resource\n", This);597pipe_resource_reference(&This->base.resource, NULL);598This->managed.lod_resident = -1;599This->managed.dirty = TRUE;600601/* If the texture is bound, we have to re-upload it */602BASETEX_REGISTER_UPDATE(This);603}604605#if defined(DEBUG) || !defined(NDEBUG)606void607NineBaseTexture9_Dump( struct NineBaseTexture9 *This )608{609DBG("\nNineBaseTexture9(%p->NULL/%p): Pool=%s Type=%s Usage=%s\n"610"Format=%s Dims=%ux%ux%u/%u LastLevel=%u Lod=%u(%u)\n", This,611This->base.resource,612nine_D3DPOOL_to_str(This->base.pool),613nine_D3DRTYPE_to_str(This->base.type),614nine_D3DUSAGE_to_str(This->base.usage),615d3dformat_to_string(This->format),616This->base.info.width0, This->base.info.height0, This->base.info.depth0,617This->base.info.array_size, This->base.info.last_level,618This->managed.lod, This->managed.lod_resident);619}620#endif /* DEBUG || !NDEBUG */621622623