1b8e80941Smrg/* 2b8e80941Smrg * Copyright 2011 Joakim Sindholt <opensource@zhasha.com> 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub 8b8e80941Smrg * license, and/or sell copies of the Software, and to permit persons to whom 9b8e80941Smrg * the Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19b8e80941Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20b8e80941Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21b8e80941Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 22b8e80941Smrg 23b8e80941Smrg#include "basetexture9.h" 24b8e80941Smrg#include "device9.h" 25b8e80941Smrg 26b8e80941Smrg/* For UploadSelf: */ 27b8e80941Smrg#include "texture9.h" 28b8e80941Smrg#include "cubetexture9.h" 29b8e80941Smrg#include "volumetexture9.h" 30b8e80941Smrg 31b8e80941Smrg#if defined(DEBUG) || !defined(NDEBUG) 32b8e80941Smrg#include "nine_pipe.h" 33b8e80941Smrg#include "nine_dump.h" 34b8e80941Smrg#endif 35b8e80941Smrg 36b8e80941Smrg#include "util/u_format.h" 37b8e80941Smrg 38b8e80941Smrg#define DBG_CHANNEL DBG_BASETEXTURE 39b8e80941Smrg 40b8e80941SmrgHRESULT 41b8e80941SmrgNineBaseTexture9_ctor( struct NineBaseTexture9 *This, 42b8e80941Smrg struct NineUnknownParams *pParams, 43b8e80941Smrg struct pipe_resource *initResource, 44b8e80941Smrg D3DRESOURCETYPE Type, 45b8e80941Smrg D3DFORMAT format, 46b8e80941Smrg D3DPOOL Pool, 47b8e80941Smrg DWORD Usage) 48b8e80941Smrg{ 49b8e80941Smrg BOOL alloc = (Pool == D3DPOOL_DEFAULT) && !initResource && 50b8e80941Smrg (format != D3DFMT_NULL); 51b8e80941Smrg HRESULT hr; 52b8e80941Smrg 53b8e80941Smrg DBG("This=%p, pParams=%p initResource=%p Type=%d format=%d Pool=%d Usage=%d\n", 54b8e80941Smrg This, pParams, initResource, Type, format, Pool, Usage); 55b8e80941Smrg 56b8e80941Smrg user_assert(!(Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) || 57b8e80941Smrg Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); 58b8e80941Smrg user_assert(!(Usage & D3DUSAGE_DYNAMIC) || 59b8e80941Smrg !(Pool == D3DPOOL_MANAGED || 60b8e80941Smrg Pool == D3DPOOL_SCRATCH), D3DERR_INVALIDCALL); 61b8e80941Smrg 62b8e80941Smrg hr = NineResource9_ctor(&This->base, pParams, initResource, alloc, Type, Pool, Usage); 63b8e80941Smrg if (FAILED(hr)) 64b8e80941Smrg return hr; 65b8e80941Smrg 66b8e80941Smrg This->format = format; 67b8e80941Smrg This->mipfilter = (Usage & D3DUSAGE_AUTOGENMIPMAP) ? 68b8e80941Smrg D3DTEXF_LINEAR : D3DTEXF_NONE; 69b8e80941Smrg This->managed.lod = 0; 70b8e80941Smrg This->managed.lod_resident = -1; 71b8e80941Smrg /* Mark the texture as dirty to trigger first upload when we need the texture, 72b8e80941Smrg * even if it wasn't set by the application */ 73b8e80941Smrg if (Pool == D3DPOOL_MANAGED) 74b8e80941Smrg This->managed.dirty = TRUE; 75b8e80941Smrg /* When a depth buffer is sampled, it is for shadow mapping, except for 76b8e80941Smrg * D3DFMT_INTZ, D3DFMT_DF16 and D3DFMT_DF24. 77b8e80941Smrg * In addition D3DFMT_INTZ can be used for both texturing and depth buffering 78b8e80941Smrg * if z write is disabled. This particular feature may not work for us in 79b8e80941Smrg * practice because OGL doesn't have that. However apparently it is known 80b8e80941Smrg * some cards have performance issues with this feature, so real apps 81b8e80941Smrg * shouldn't use it. */ 82b8e80941Smrg This->shadow = (This->format != D3DFMT_INTZ && This->format != D3DFMT_DF16 && 83b8e80941Smrg This->format != D3DFMT_DF24) && 84b8e80941Smrg util_format_has_depth(util_format_description(This->base.info.format)); 85b8e80941Smrg 86b8e80941Smrg list_inithead(&This->list); 87b8e80941Smrg list_inithead(&This->list2); 88b8e80941Smrg if (Pool == D3DPOOL_MANAGED) 89b8e80941Smrg list_add(&This->list2, &This->base.base.device->managed_textures); 90b8e80941Smrg 91b8e80941Smrg return D3D_OK; 92b8e80941Smrg} 93b8e80941Smrg 94b8e80941Smrgvoid 95b8e80941SmrgNineBaseTexture9_dtor( struct NineBaseTexture9 *This ) 96b8e80941Smrg{ 97b8e80941Smrg DBG("This=%p\n", This); 98b8e80941Smrg 99b8e80941Smrg pipe_sampler_view_reference(&This->view[0], NULL); 100b8e80941Smrg pipe_sampler_view_reference(&This->view[1], NULL); 101b8e80941Smrg 102b8e80941Smrg if (This->list.prev != NULL && This->list.next != NULL) 103b8e80941Smrg list_del(&This->list); 104b8e80941Smrg if (This->list2.prev != NULL && This->list2.next != NULL) 105b8e80941Smrg list_del(&This->list2); 106b8e80941Smrg 107b8e80941Smrg NineResource9_dtor(&This->base); 108b8e80941Smrg} 109b8e80941Smrg 110b8e80941SmrgDWORD NINE_WINAPI 111b8e80941SmrgNineBaseTexture9_SetLOD( struct NineBaseTexture9 *This, 112b8e80941Smrg DWORD LODNew ) 113b8e80941Smrg{ 114b8e80941Smrg DWORD old = This->managed.lod; 115b8e80941Smrg DWORD max_level; 116b8e80941Smrg 117b8e80941Smrg DBG("This=%p LODNew=%d\n", This, LODNew); 118b8e80941Smrg 119b8e80941Smrg user_assert(This->base.pool == D3DPOOL_MANAGED, 0); 120b8e80941Smrg 121b8e80941Smrg max_level = (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) ? 122b8e80941Smrg 0 : This->base.info.last_level; 123b8e80941Smrg This->managed.lod = MIN2(LODNew, max_level); 124b8e80941Smrg 125b8e80941Smrg if (This->managed.lod != old && This->bind_count && LIST_IS_EMPTY(&This->list)) 126b8e80941Smrg list_add(&This->list, &This->base.base.device->update_textures); 127b8e80941Smrg 128b8e80941Smrg return old; 129b8e80941Smrg} 130b8e80941Smrg 131b8e80941SmrgDWORD NINE_WINAPI 132b8e80941SmrgNineBaseTexture9_GetLOD( struct NineBaseTexture9 *This ) 133b8e80941Smrg{ 134b8e80941Smrg DBG("This=%p\n", This); 135b8e80941Smrg 136b8e80941Smrg return This->managed.lod; 137b8e80941Smrg} 138b8e80941Smrg 139b8e80941SmrgDWORD NINE_WINAPI 140b8e80941SmrgNineBaseTexture9_GetLevelCount( struct NineBaseTexture9 *This ) 141b8e80941Smrg{ 142b8e80941Smrg DBG("This=%p\n", This); 143b8e80941Smrg 144b8e80941Smrg if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) 145b8e80941Smrg return 1; 146b8e80941Smrg return This->base.info.last_level + 1; 147b8e80941Smrg} 148b8e80941Smrg 149b8e80941SmrgHRESULT NINE_WINAPI 150b8e80941SmrgNineBaseTexture9_SetAutoGenFilterType( struct NineBaseTexture9 *This, 151b8e80941Smrg D3DTEXTUREFILTERTYPE FilterType ) 152b8e80941Smrg{ 153b8e80941Smrg DBG("This=%p FilterType=%d\n", This, FilterType); 154b8e80941Smrg 155b8e80941Smrg if (!(This->base.usage & D3DUSAGE_AUTOGENMIPMAP)) 156b8e80941Smrg return D3D_OK; 157b8e80941Smrg user_assert(FilterType != D3DTEXF_NONE, D3DERR_INVALIDCALL); 158b8e80941Smrg 159b8e80941Smrg This->mipfilter = FilterType; 160b8e80941Smrg This->dirty_mip = TRUE; 161b8e80941Smrg NineBaseTexture9_GenerateMipSubLevels(This); 162b8e80941Smrg 163b8e80941Smrg return D3D_OK; 164b8e80941Smrg} 165b8e80941Smrg 166b8e80941SmrgD3DTEXTUREFILTERTYPE NINE_WINAPI 167b8e80941SmrgNineBaseTexture9_GetAutoGenFilterType( struct NineBaseTexture9 *This ) 168b8e80941Smrg{ 169b8e80941Smrg DBG("This=%p\n", This); 170b8e80941Smrg 171b8e80941Smrg return This->mipfilter; 172b8e80941Smrg} 173b8e80941Smrg 174b8e80941SmrgHRESULT 175b8e80941SmrgNineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This ) 176b8e80941Smrg{ 177b8e80941Smrg HRESULT hr; 178b8e80941Smrg unsigned last_level = This->base.info.last_level; 179b8e80941Smrg unsigned l, min_level_dirty = This->managed.lod; 180b8e80941Smrg BOOL update_lod; 181b8e80941Smrg 182b8e80941Smrg DBG("This=%p dirty=%i type=%s\n", This, This->managed.dirty, 183b8e80941Smrg nine_D3DRTYPE_to_str(This->base.type)); 184b8e80941Smrg 185b8e80941Smrg assert(This->base.pool == D3DPOOL_MANAGED); 186b8e80941Smrg 187b8e80941Smrg if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) 188b8e80941Smrg last_level = 0; 189b8e80941Smrg 190b8e80941Smrg update_lod = This->managed.lod_resident != This->managed.lod; 191b8e80941Smrg if (!update_lod && !This->managed.dirty) 192b8e80941Smrg return D3D_OK; 193b8e80941Smrg 194b8e80941Smrg /* Allocate a new resource with the correct number of levels, 195b8e80941Smrg * Mark states for update, and tell the nine surfaces/volumes 196b8e80941Smrg * their new resource. */ 197b8e80941Smrg if (update_lod) { 198b8e80941Smrg struct pipe_resource *res; 199b8e80941Smrg 200b8e80941Smrg DBG("updating LOD from %u to %u ...\n", This->managed.lod_resident, This->managed.lod); 201b8e80941Smrg 202b8e80941Smrg pipe_sampler_view_reference(&This->view[0], NULL); 203b8e80941Smrg pipe_sampler_view_reference(&This->view[1], NULL); 204b8e80941Smrg 205b8e80941Smrg /* Allocate a new resource */ 206b8e80941Smrg hr = NineBaseTexture9_CreatePipeResource(This, This->managed.lod_resident != -1); 207b8e80941Smrg if (FAILED(hr)) 208b8e80941Smrg return hr; 209b8e80941Smrg res = This->base.resource; 210b8e80941Smrg 211b8e80941Smrg if (This->managed.lod_resident == -1) {/* no levels were resident */ 212b8e80941Smrg This->managed.dirty = FALSE; /* We are going to upload everything. */ 213b8e80941Smrg This->managed.lod_resident = This->base.info.last_level + 1; 214b8e80941Smrg } 215b8e80941Smrg 216b8e80941Smrg if (This->base.type == D3DRTYPE_TEXTURE) { 217b8e80941Smrg struct NineTexture9 *tex = NineTexture9(This); 218b8e80941Smrg 219b8e80941Smrg /* last content (if apply) has been copied to the new resource. 220b8e80941Smrg * Note: We cannot render to surfaces of managed textures. 221b8e80941Smrg * Note2: the level argument passed is to get the level offset 222b8e80941Smrg * right when the texture is uploaded (the texture first level 223b8e80941Smrg * corresponds to This->managed.lod). 224b8e80941Smrg * Note3: We don't care about the value passed for the surfaces 225b8e80941Smrg * before This->managed.lod, negative with this implementation. */ 226b8e80941Smrg for (l = 0; l <= This->base.info.last_level; ++l) 227b8e80941Smrg NineSurface9_SetResource(tex->surfaces[l], res, l - This->managed.lod); 228b8e80941Smrg } else 229b8e80941Smrg if (This->base.type == D3DRTYPE_CUBETEXTURE) { 230b8e80941Smrg struct NineCubeTexture9 *tex = NineCubeTexture9(This); 231b8e80941Smrg unsigned z; 232b8e80941Smrg 233b8e80941Smrg for (l = 0; l <= This->base.info.last_level; ++l) { 234b8e80941Smrg for (z = 0; z < 6; ++z) 235b8e80941Smrg NineSurface9_SetResource(tex->surfaces[l * 6 + z], 236b8e80941Smrg res, l - This->managed.lod); 237b8e80941Smrg } 238b8e80941Smrg } else 239b8e80941Smrg if (This->base.type == D3DRTYPE_VOLUMETEXTURE) { 240b8e80941Smrg struct NineVolumeTexture9 *tex = NineVolumeTexture9(This); 241b8e80941Smrg 242b8e80941Smrg for (l = 0; l <= This->base.info.last_level; ++l) 243b8e80941Smrg NineVolume9_SetResource(tex->volumes[l], res, l - This->managed.lod); 244b8e80941Smrg } else { 245b8e80941Smrg assert(!"invalid texture type"); 246b8e80941Smrg } 247b8e80941Smrg 248b8e80941Smrg /* We are going to fully upload the new levels, 249b8e80941Smrg * no need to update dirty parts of the texture for these */ 250b8e80941Smrg min_level_dirty = MAX2(This->managed.lod, This->managed.lod_resident); 251b8e80941Smrg } 252b8e80941Smrg 253b8e80941Smrg /* Update dirty parts of the texture */ 254b8e80941Smrg if (This->managed.dirty) { 255b8e80941Smrg if (This->base.type == D3DRTYPE_TEXTURE) { 256b8e80941Smrg struct NineTexture9 *tex = NineTexture9(This); 257b8e80941Smrg struct pipe_box box; 258b8e80941Smrg box.z = 0; 259b8e80941Smrg box.depth = 1; 260b8e80941Smrg 261b8e80941Smrg DBG("TEXTURE: dirty rect=(%u,%u) (%ux%u)\n", 262b8e80941Smrg tex->dirty_rect.x, tex->dirty_rect.y, 263b8e80941Smrg tex->dirty_rect.width, tex->dirty_rect.height); 264b8e80941Smrg 265b8e80941Smrg /* Note: for l < min_level_dirty, the resource is 266b8e80941Smrg * either non-existing (and thus will be entirely re-uploaded 267b8e80941Smrg * if the lod changes) or going to have a full upload */ 268b8e80941Smrg if (tex->dirty_rect.width) { 269b8e80941Smrg for (l = min_level_dirty; l <= last_level; ++l) { 270b8e80941Smrg u_box_minify_2d(&box, &tex->dirty_rect, l); 271b8e80941Smrg NineSurface9_UploadSelf(tex->surfaces[l], &box); 272b8e80941Smrg } 273b8e80941Smrg memset(&tex->dirty_rect, 0, sizeof(tex->dirty_rect)); 274b8e80941Smrg tex->dirty_rect.depth = 1; 275b8e80941Smrg } 276b8e80941Smrg } else 277b8e80941Smrg if (This->base.type == D3DRTYPE_CUBETEXTURE) { 278b8e80941Smrg struct NineCubeTexture9 *tex = NineCubeTexture9(This); 279b8e80941Smrg unsigned z; 280b8e80941Smrg struct pipe_box box; 281b8e80941Smrg box.z = 0; 282b8e80941Smrg box.depth = 1; 283b8e80941Smrg 284b8e80941Smrg for (z = 0; z < 6; ++z) { 285b8e80941Smrg DBG("FACE[%u]: dirty rect=(%u,%u) (%ux%u)\n", z, 286b8e80941Smrg tex->dirty_rect[z].x, tex->dirty_rect[z].y, 287b8e80941Smrg tex->dirty_rect[z].width, tex->dirty_rect[z].height); 288b8e80941Smrg 289b8e80941Smrg if (tex->dirty_rect[z].width) { 290b8e80941Smrg for (l = min_level_dirty; l <= last_level; ++l) { 291b8e80941Smrg u_box_minify_2d(&box, &tex->dirty_rect[z], l); 292b8e80941Smrg NineSurface9_UploadSelf(tex->surfaces[l * 6 + z], &box); 293b8e80941Smrg } 294b8e80941Smrg memset(&tex->dirty_rect[z], 0, sizeof(tex->dirty_rect[z])); 295b8e80941Smrg tex->dirty_rect[z].depth = 1; 296b8e80941Smrg } 297b8e80941Smrg } 298b8e80941Smrg } else 299b8e80941Smrg if (This->base.type == D3DRTYPE_VOLUMETEXTURE) { 300b8e80941Smrg struct NineVolumeTexture9 *tex = NineVolumeTexture9(This); 301b8e80941Smrg struct pipe_box box; 302b8e80941Smrg 303b8e80941Smrg DBG("VOLUME: dirty_box=(%u,%u,%u) (%ux%ux%u)\n", 304b8e80941Smrg tex->dirty_box.x, tex->dirty_box.y, tex->dirty_box.y, 305b8e80941Smrg tex->dirty_box.width, tex->dirty_box.height, tex->dirty_box.depth); 306b8e80941Smrg 307b8e80941Smrg if (tex->dirty_box.width) { 308b8e80941Smrg for (l = min_level_dirty; l <= last_level; ++l) { 309b8e80941Smrg u_box_minify_3d(&box, &tex->dirty_box, l); 310b8e80941Smrg NineVolume9_UploadSelf(tex->volumes[l], &box); 311b8e80941Smrg } 312b8e80941Smrg memset(&tex->dirty_box, 0, sizeof(tex->dirty_box)); 313b8e80941Smrg } 314b8e80941Smrg } else { 315b8e80941Smrg assert(!"invalid texture type"); 316b8e80941Smrg } 317b8e80941Smrg This->managed.dirty = FALSE; 318b8e80941Smrg } 319b8e80941Smrg 320b8e80941Smrg /* Upload the new levels */ 321b8e80941Smrg if (update_lod) { 322b8e80941Smrg if (This->base.type == D3DRTYPE_TEXTURE) { 323b8e80941Smrg struct NineTexture9 *tex = NineTexture9(This); 324b8e80941Smrg struct pipe_box box; 325b8e80941Smrg 326b8e80941Smrg box.x = box.y = box.z = 0; 327b8e80941Smrg box.depth = 1; 328b8e80941Smrg for (l = This->managed.lod; l < This->managed.lod_resident; ++l) { 329b8e80941Smrg box.width = u_minify(This->base.info.width0, l); 330b8e80941Smrg box.height = u_minify(This->base.info.height0, l); 331b8e80941Smrg NineSurface9_UploadSelf(tex->surfaces[l], &box); 332b8e80941Smrg } 333b8e80941Smrg } else 334b8e80941Smrg if (This->base.type == D3DRTYPE_CUBETEXTURE) { 335b8e80941Smrg struct NineCubeTexture9 *tex = NineCubeTexture9(This); 336b8e80941Smrg struct pipe_box box; 337b8e80941Smrg unsigned z; 338b8e80941Smrg 339b8e80941Smrg box.x = box.y = box.z = 0; 340b8e80941Smrg box.depth = 1; 341b8e80941Smrg for (l = This->managed.lod; l < This->managed.lod_resident; ++l) { 342b8e80941Smrg box.width = u_minify(This->base.info.width0, l); 343b8e80941Smrg box.height = u_minify(This->base.info.height0, l); 344b8e80941Smrg for (z = 0; z < 6; ++z) 345b8e80941Smrg NineSurface9_UploadSelf(tex->surfaces[l * 6 + z], &box); 346b8e80941Smrg } 347b8e80941Smrg } else 348b8e80941Smrg if (This->base.type == D3DRTYPE_VOLUMETEXTURE) { 349b8e80941Smrg struct NineVolumeTexture9 *tex = NineVolumeTexture9(This); 350b8e80941Smrg struct pipe_box box; 351b8e80941Smrg 352b8e80941Smrg box.x = box.y = box.z = 0; 353b8e80941Smrg for (l = This->managed.lod; l < This->managed.lod_resident; ++l) { 354b8e80941Smrg box.width = u_minify(This->base.info.width0, l); 355b8e80941Smrg box.height = u_minify(This->base.info.height0, l); 356b8e80941Smrg box.depth = u_minify(This->base.info.depth0, l); 357b8e80941Smrg NineVolume9_UploadSelf(tex->volumes[l], &box); 358b8e80941Smrg } 359b8e80941Smrg } else { 360b8e80941Smrg assert(!"invalid texture type"); 361b8e80941Smrg } 362b8e80941Smrg 363b8e80941Smrg This->managed.lod_resident = This->managed.lod; 364b8e80941Smrg } 365b8e80941Smrg 366b8e80941Smrg if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) 367b8e80941Smrg This->dirty_mip = TRUE; 368b8e80941Smrg 369b8e80941Smrg /* Set again the textures currently bound to update the texture data */ 370b8e80941Smrg if (This->bind_count) { 371b8e80941Smrg struct nine_state *state = &This->base.base.device->state; 372b8e80941Smrg unsigned s; 373b8e80941Smrg for (s = 0; s < NINE_MAX_SAMPLERS; ++s) 374b8e80941Smrg /* Dirty tracking is done in device9 state, not nine_context. */ 375b8e80941Smrg if (state->texture[s] == This) 376b8e80941Smrg nine_context_set_texture(This->base.base.device, s, This); 377b8e80941Smrg } 378b8e80941Smrg 379b8e80941Smrg DBG("DONE, generate mip maps = %i\n", This->dirty_mip); 380b8e80941Smrg return D3D_OK; 381b8e80941Smrg} 382b8e80941Smrg 383b8e80941Smrgvoid NINE_WINAPI 384b8e80941SmrgNineBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This ) 385b8e80941Smrg{ 386b8e80941Smrg unsigned base_level = 0; 387b8e80941Smrg unsigned last_level = This->base.info.last_level - This->managed.lod; 388b8e80941Smrg unsigned first_layer = 0; 389b8e80941Smrg unsigned last_layer; 390b8e80941Smrg unsigned filter = This->mipfilter == D3DTEXF_POINT ? PIPE_TEX_FILTER_NEAREST 391b8e80941Smrg : PIPE_TEX_FILTER_LINEAR; 392b8e80941Smrg DBG("This=%p\n", This); 393b8e80941Smrg 394b8e80941Smrg if (This->base.pool == D3DPOOL_MANAGED) 395b8e80941Smrg NineBaseTexture9_UploadSelf(This); 396b8e80941Smrg if (!This->dirty_mip) 397b8e80941Smrg return; 398b8e80941Smrg if (This->managed.lod) { 399b8e80941Smrg ERR("AUTOGENMIPMAP if level 0 is not resident not supported yet !\n"); 400b8e80941Smrg return; 401b8e80941Smrg } 402b8e80941Smrg 403b8e80941Smrg if (!This->view[0]) 404b8e80941Smrg NineBaseTexture9_UpdateSamplerView(This, 0); 405b8e80941Smrg 406b8e80941Smrg last_layer = util_max_layer(This->view[0]->texture, base_level); 407b8e80941Smrg 408b8e80941Smrg nine_context_gen_mipmap(This->base.base.device, (struct NineUnknown *)This, 409b8e80941Smrg This->base.resource, 410b8e80941Smrg base_level, last_level, 411b8e80941Smrg first_layer, last_layer, filter); 412b8e80941Smrg 413b8e80941Smrg This->dirty_mip = FALSE; 414b8e80941Smrg} 415b8e80941Smrg 416b8e80941SmrgHRESULT 417b8e80941SmrgNineBaseTexture9_CreatePipeResource( struct NineBaseTexture9 *This, 418b8e80941Smrg BOOL CopyData ) 419b8e80941Smrg{ 420b8e80941Smrg struct pipe_context *pipe; 421b8e80941Smrg struct pipe_screen *screen = This->base.info.screen; 422b8e80941Smrg struct pipe_resource templ; 423b8e80941Smrg unsigned l, m; 424b8e80941Smrg struct pipe_resource *res; 425b8e80941Smrg struct pipe_resource *old = This->base.resource; 426b8e80941Smrg 427b8e80941Smrg DBG("This=%p lod=%u last_level=%u\n", This, 428b8e80941Smrg This->managed.lod, This->base.info.last_level); 429b8e80941Smrg 430b8e80941Smrg assert(This->base.pool == D3DPOOL_MANAGED); 431b8e80941Smrg 432b8e80941Smrg templ = This->base.info; 433b8e80941Smrg 434b8e80941Smrg if (This->managed.lod) { 435b8e80941Smrg templ.width0 = u_minify(templ.width0, This->managed.lod); 436b8e80941Smrg templ.height0 = u_minify(templ.height0, This->managed.lod); 437b8e80941Smrg templ.depth0 = u_minify(templ.depth0, This->managed.lod); 438b8e80941Smrg } 439b8e80941Smrg templ.last_level = This->base.info.last_level - This->managed.lod; 440b8e80941Smrg 441b8e80941Smrg if (old) { 442b8e80941Smrg /* LOD might have changed. */ 443b8e80941Smrg if (old->width0 == templ.width0 && 444b8e80941Smrg old->height0 == templ.height0 && 445b8e80941Smrg old->depth0 == templ.depth0) 446b8e80941Smrg return D3D_OK; 447b8e80941Smrg } 448b8e80941Smrg 449b8e80941Smrg res = screen->resource_create(screen, &templ); 450b8e80941Smrg if (!res) 451b8e80941Smrg return D3DERR_OUTOFVIDEOMEMORY; 452b8e80941Smrg This->base.resource = res; 453b8e80941Smrg 454b8e80941Smrg if (old && CopyData) { /* Don't return without releasing old ! */ 455b8e80941Smrg struct pipe_box box; 456b8e80941Smrg box.x = 0; 457b8e80941Smrg box.y = 0; 458b8e80941Smrg box.z = 0; 459b8e80941Smrg 460b8e80941Smrg l = (This->managed.lod < This->managed.lod_resident) ? This->managed.lod_resident - This->managed.lod : 0; 461b8e80941Smrg m = (This->managed.lod < This->managed.lod_resident) ? 0 : This->managed.lod - This->managed.lod_resident; 462b8e80941Smrg 463b8e80941Smrg box.width = u_minify(templ.width0, l); 464b8e80941Smrg box.height = u_minify(templ.height0, l); 465b8e80941Smrg box.depth = u_minify(templ.depth0, l); 466b8e80941Smrg 467b8e80941Smrg pipe = nine_context_get_pipe_acquire(This->base.base.device); 468b8e80941Smrg 469b8e80941Smrg for (; l <= templ.last_level; ++l, ++m) { 470b8e80941Smrg pipe->resource_copy_region(pipe, 471b8e80941Smrg res, l, 0, 0, 0, 472b8e80941Smrg old, m, &box); 473b8e80941Smrg box.width = u_minify(box.width, 1); 474b8e80941Smrg box.height = u_minify(box.height, 1); 475b8e80941Smrg box.depth = u_minify(box.depth, 1); 476b8e80941Smrg } 477b8e80941Smrg 478b8e80941Smrg nine_context_get_pipe_release(This->base.base.device); 479b8e80941Smrg } 480b8e80941Smrg pipe_resource_reference(&old, NULL); 481b8e80941Smrg 482b8e80941Smrg return D3D_OK; 483b8e80941Smrg} 484b8e80941Smrg 485b8e80941Smrg#define SWIZZLE_TO_REPLACE(s) (s == PIPE_SWIZZLE_0 || \ 486b8e80941Smrg s == PIPE_SWIZZLE_1 || \ 487b8e80941Smrg s == PIPE_SWIZZLE_NONE) 488b8e80941Smrg 489b8e80941SmrgHRESULT 490b8e80941SmrgNineBaseTexture9_UpdateSamplerView( struct NineBaseTexture9 *This, 491b8e80941Smrg const int sRGB ) 492b8e80941Smrg{ 493b8e80941Smrg const struct util_format_description *desc; 494b8e80941Smrg struct pipe_context *pipe; 495b8e80941Smrg struct pipe_screen *screen = NineDevice9_GetScreen(This->base.base.device); 496b8e80941Smrg struct pipe_resource *resource = This->base.resource; 497b8e80941Smrg struct pipe_sampler_view templ; 498b8e80941Smrg enum pipe_format srgb_format; 499b8e80941Smrg unsigned i; 500b8e80941Smrg uint8_t swizzle[4]; 501b8e80941Smrg 502b8e80941Smrg DBG("This=%p sRGB=%d\n", This, sRGB); 503b8e80941Smrg 504b8e80941Smrg if (unlikely(!resource)) { 505b8e80941Smrg if (unlikely(This->format == D3DFMT_NULL)) 506b8e80941Smrg return D3D_OK; 507b8e80941Smrg NineBaseTexture9_Dump(This); 508b8e80941Smrg } 509b8e80941Smrg assert(resource); 510b8e80941Smrg 511b8e80941Smrg pipe_sampler_view_reference(&This->view[sRGB], NULL); 512b8e80941Smrg 513b8e80941Smrg swizzle[0] = PIPE_SWIZZLE_X; 514b8e80941Smrg swizzle[1] = PIPE_SWIZZLE_Y; 515b8e80941Smrg swizzle[2] = PIPE_SWIZZLE_Z; 516b8e80941Smrg swizzle[3] = PIPE_SWIZZLE_W; 517b8e80941Smrg desc = util_format_description(resource->format); 518b8e80941Smrg if (desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) { 519b8e80941Smrg /* msdn doc is incomplete here and wrong. 520b8e80941Smrg * The only formats that can be read directly here 521b8e80941Smrg * are DF16, DF24 and INTZ. 522b8e80941Smrg * Tested on win the swizzle is 523b8e80941Smrg * R = depth, G = B = 0, A = 1 for DF16 and DF24 524b8e80941Smrg * R = G = B = A = depth for INTZ 525b8e80941Smrg * For the other ZS formats that can't be read directly 526b8e80941Smrg * but can be used as shadow map, the result is duplicated on 527b8e80941Smrg * all channel */ 528b8e80941Smrg if (This->format == D3DFMT_DF16 || 529b8e80941Smrg This->format == D3DFMT_DF24) { 530b8e80941Smrg swizzle[1] = PIPE_SWIZZLE_0; 531b8e80941Smrg swizzle[2] = PIPE_SWIZZLE_0; 532b8e80941Smrg swizzle[3] = PIPE_SWIZZLE_1; 533b8e80941Smrg } else { 534b8e80941Smrg swizzle[1] = PIPE_SWIZZLE_X; 535b8e80941Smrg swizzle[2] = PIPE_SWIZZLE_X; 536b8e80941Smrg swizzle[3] = PIPE_SWIZZLE_X; 537b8e80941Smrg } 538b8e80941Smrg } else if (resource->format == PIPE_FORMAT_RGTC2_UNORM) { 539b8e80941Smrg swizzle[0] = PIPE_SWIZZLE_Y; 540b8e80941Smrg swizzle[1] = PIPE_SWIZZLE_X; 541b8e80941Smrg swizzle[2] = PIPE_SWIZZLE_1; 542b8e80941Smrg swizzle[3] = PIPE_SWIZZLE_1; 543b8e80941Smrg } else if (resource->format != PIPE_FORMAT_A8_UNORM && 544b8e80941Smrg resource->format != PIPE_FORMAT_RGTC1_UNORM) { 545b8e80941Smrg /* exceptions: 546b8e80941Smrg * A8 should have 0.0 as default values for RGB. 547b8e80941Smrg * ATI1/RGTC1 should be r 0 0 1 (tested on windows). 548b8e80941Smrg * It is already what gallium does. All the other ones 549b8e80941Smrg * should have 1.0 for non-defined values */ 550b8e80941Smrg for (i = 0; i < 4; i++) { 551b8e80941Smrg if (SWIZZLE_TO_REPLACE(desc->swizzle[i])) 552b8e80941Smrg swizzle[i] = PIPE_SWIZZLE_1; 553b8e80941Smrg } 554b8e80941Smrg } 555b8e80941Smrg 556b8e80941Smrg /* if requested and supported, convert to the sRGB format */ 557b8e80941Smrg srgb_format = util_format_srgb(resource->format); 558b8e80941Smrg if (sRGB && srgb_format != PIPE_FORMAT_NONE && 559b8e80941Smrg screen->is_format_supported(screen, srgb_format, 560b8e80941Smrg resource->target, 0, 0, resource->bind)) 561b8e80941Smrg templ.format = srgb_format; 562b8e80941Smrg else 563b8e80941Smrg templ.format = resource->format; 564b8e80941Smrg templ.u.tex.first_layer = 0; 565b8e80941Smrg templ.u.tex.last_layer = resource->target == PIPE_TEXTURE_3D ? 566b8e80941Smrg resource->depth0 - 1 : resource->array_size - 1; 567b8e80941Smrg templ.u.tex.first_level = 0; 568b8e80941Smrg templ.u.tex.last_level = resource->last_level; 569b8e80941Smrg templ.swizzle_r = swizzle[0]; 570b8e80941Smrg templ.swizzle_g = swizzle[1]; 571b8e80941Smrg templ.swizzle_b = swizzle[2]; 572b8e80941Smrg templ.swizzle_a = swizzle[3]; 573b8e80941Smrg templ.target = resource->target; 574b8e80941Smrg 575b8e80941Smrg pipe = nine_context_get_pipe_acquire(This->base.base.device); 576b8e80941Smrg This->view[sRGB] = pipe->create_sampler_view(pipe, resource, &templ); 577b8e80941Smrg nine_context_get_pipe_release(This->base.base.device); 578b8e80941Smrg 579b8e80941Smrg DBG("sampler view = %p(resource = %p)\n", This->view[sRGB], resource); 580b8e80941Smrg 581b8e80941Smrg return This->view ? D3D_OK : D3DERR_DRIVERINTERNALERROR; 582b8e80941Smrg} 583b8e80941Smrg 584b8e80941Smrgvoid NINE_WINAPI 585b8e80941SmrgNineBaseTexture9_PreLoad( struct NineBaseTexture9 *This ) 586b8e80941Smrg{ 587b8e80941Smrg DBG("This=%p\n", This); 588b8e80941Smrg 589b8e80941Smrg if (This->base.pool == D3DPOOL_MANAGED) 590b8e80941Smrg NineBaseTexture9_UploadSelf(This); 591b8e80941Smrg} 592b8e80941Smrg 593b8e80941Smrgvoid 594b8e80941SmrgNineBaseTexture9_UnLoad( struct NineBaseTexture9 *This ) 595b8e80941Smrg{ 596b8e80941Smrg if (This->base.pool != D3DPOOL_MANAGED || 597b8e80941Smrg This->managed.lod_resident == -1) 598b8e80941Smrg return; 599b8e80941Smrg 600b8e80941Smrg pipe_resource_reference(&This->base.resource, NULL); 601b8e80941Smrg This->managed.lod_resident = -1; 602b8e80941Smrg This->managed.dirty = TRUE; 603b8e80941Smrg 604b8e80941Smrg /* If the texture is bound, we have to re-upload it */ 605b8e80941Smrg BASETEX_REGISTER_UPDATE(This); 606b8e80941Smrg} 607b8e80941Smrg 608b8e80941Smrg#if defined(DEBUG) || !defined(NDEBUG) 609b8e80941Smrgvoid 610b8e80941SmrgNineBaseTexture9_Dump( struct NineBaseTexture9 *This ) 611b8e80941Smrg{ 612b8e80941Smrg DBG("\nNineBaseTexture9(%p->NULL/%p): Pool=%s Type=%s Usage=%s\n" 613b8e80941Smrg "Format=%s Dims=%ux%ux%u/%u LastLevel=%u Lod=%u(%u)\n", This, 614b8e80941Smrg This->base.resource, 615b8e80941Smrg nine_D3DPOOL_to_str(This->base.pool), 616b8e80941Smrg nine_D3DRTYPE_to_str(This->base.type), 617b8e80941Smrg nine_D3DUSAGE_to_str(This->base.usage), 618b8e80941Smrg d3dformat_to_string(This->format), 619b8e80941Smrg This->base.info.width0, This->base.info.height0, This->base.info.depth0, 620b8e80941Smrg This->base.info.array_size, This->base.info.last_level, 621b8e80941Smrg This->managed.lod, This->managed.lod_resident); 622b8e80941Smrg} 623b8e80941Smrg#endif /* DEBUG || !NDEBUG */ 624