st/nine: Reduce system memory allocated by D3DUSAGE_AUTOGENMIPMAP

For D3DUSAGE_AUTOGENMIPMAP basically, everything behaves
for the application as if the texture had one level.
However the pipe_resource has more levels, and those
get generated automatically.

Previously we did allocate all the Surfaces as if
the texture had all the levels, except of just one.
The app could still just access the first level.

This patch completly removes the useless unaccessible
Surfaces.
In addition removes redundant handling of D3DUSAGE_AUTOGENMIPMAP.

Signed-off-by: Axel Davy <davyaxel0@gmail.com>
Acked-by: Timur Kristóf <timur.kristof@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9177>
This commit is contained in:
Axel Davy
2020-05-21 17:51:55 +02:00
parent ec74a13618
commit 3dbc542f97
6 changed files with 62 additions and 82 deletions

View File

@@ -66,6 +66,9 @@ NineBaseTexture9_ctor( struct NineBaseTexture9 *This,
This->format = format;
This->mipfilter = (Usage & D3DUSAGE_AUTOGENMIPMAP) ?
D3DTEXF_LINEAR : D3DTEXF_NONE;
/* In the case of D3DUSAGE_AUTOGENMIPMAP, only the first level is accessible,
* and thus needs a surface created. */
This->level_count = (Usage & D3DUSAGE_AUTOGENMIPMAP) ? 1 : (This->base.info.last_level+1);
This->managed.lod = 0;
This->managed.lod_resident = -1;
/* Mark the texture as dirty to trigger first upload when we need the texture,
@@ -112,15 +115,12 @@ NineBaseTexture9_SetLOD( struct NineBaseTexture9 *This,
DWORD LODNew )
{
DWORD old = This->managed.lod;
DWORD max_level;
DBG("This=%p LODNew=%d\n", This, LODNew);
user_assert(This->base.pool == D3DPOOL_MANAGED, 0);
max_level = (This->base.usage & D3DUSAGE_AUTOGENMIPMAP) ?
0 : This->base.info.last_level;
This->managed.lod = MIN2(LODNew, max_level);
This->managed.lod = MIN2(LODNew, This->level_count-1);
if (This->managed.lod != old && This->bind_count && list_is_empty(&This->list))
list_add(&This->list, &This->base.base.device->update_textures);
@@ -141,9 +141,7 @@ NineBaseTexture9_GetLevelCount( struct NineBaseTexture9 *This )
{
DBG("This=%p\n", This);
if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
return 1;
return This->base.info.last_level + 1;
return This->level_count;
}
HRESULT NINE_WINAPI
@@ -175,7 +173,6 @@ HRESULT
NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
{
HRESULT hr;
unsigned last_level = This->base.info.last_level;
unsigned l, min_level_dirty = This->managed.lod;
BOOL update_lod;
@@ -184,9 +181,6 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
assert(This->base.pool == D3DPOOL_MANAGED);
if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
last_level = 0;
update_lod = This->managed.lod_resident != This->managed.lod;
if (!update_lod && !This->managed.dirty)
return D3D_OK;
@@ -210,7 +204,7 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
if (This->managed.lod_resident == -1) {/* no levels were resident */
This->managed.dirty = FALSE; /* We are going to upload everything. */
This->managed.lod_resident = This->base.info.last_level + 1;
This->managed.lod_resident = This->level_count;
}
if (This->base.type == D3DRTYPE_TEXTURE) {
@@ -223,14 +217,14 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
* corresponds to This->managed.lod).
* Note3: We don't care about the value passed for the surfaces
* before This->managed.lod, negative with this implementation. */
for (l = 0; l <= This->base.info.last_level; ++l)
for (l = 0; l < This->level_count; ++l)
NineSurface9_SetResource(tex->surfaces[l], res, l - This->managed.lod);
} else
if (This->base.type == D3DRTYPE_CUBETEXTURE) {
struct NineCubeTexture9 *tex = NineCubeTexture9(This);
unsigned z;
for (l = 0; l <= This->base.info.last_level; ++l) {
for (l = 0; l < This->level_count; ++l) {
for (z = 0; z < 6; ++z)
NineSurface9_SetResource(tex->surfaces[l * 6 + z],
res, l - This->managed.lod);
@@ -239,7 +233,7 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {
struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);
for (l = 0; l <= This->base.info.last_level; ++l)
for (l = 0; l < This->level_count; ++l)
NineVolume9_SetResource(tex->volumes[l], res, l - This->managed.lod);
} else {
assert(!"invalid texture type");
@@ -266,7 +260,7 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
* either non-existing (and thus will be entirely re-uploaded
* if the lod changes) or going to have a full upload */
if (tex->dirty_rect.width) {
for (l = min_level_dirty; l <= last_level; ++l) {
for (l = min_level_dirty; l < This->level_count; ++l) {
u_box_minify_2d(&box, &tex->dirty_rect, l);
NineSurface9_UploadSelf(tex->surfaces[l], &box);
}
@@ -287,7 +281,7 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
tex->dirty_rect[z].width, tex->dirty_rect[z].height);
if (tex->dirty_rect[z].width) {
for (l = min_level_dirty; l <= last_level; ++l) {
for (l = min_level_dirty; l < This->level_count; ++l) {
u_box_minify_2d(&box, &tex->dirty_rect[z], l);
NineSurface9_UploadSelf(tex->surfaces[l * 6 + z], &box);
}
@@ -305,7 +299,7 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
tex->dirty_box.width, tex->dirty_box.height, tex->dirty_box.depth);
if (tex->dirty_box.width) {
for (l = min_level_dirty; l <= last_level; ++l) {
for (l = min_level_dirty; l < This->level_count; ++l) {
u_box_minify_3d(&box, &tex->dirty_box, l);
NineVolume9_UploadSelf(tex->volumes[l], &box);
}

View File

@@ -47,6 +47,8 @@ struct NineBaseTexture9
boolean dirty_mip;
D3DTEXTUREFILTERTYPE mipfilter;
unsigned level_count;
/* Specific to managed textures */
struct {
boolean dirty;

View File

@@ -107,26 +107,26 @@ NineCubeTexture9_ctor( struct NineCubeTexture9 *This,
DBG("Application asked for Software Vertex Processing, "
"but this is unimplemented\n");
if (Pool != D3DPOOL_DEFAULT) {
level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1));
face_size = nine_format_get_size_and_offsets(pf, level_offsets,
EdgeLength, EdgeLength,
info->last_level);
This->managed_buffer = align_calloc(6 * face_size, 32);
if (!This->managed_buffer)
return E_OUTOFMEMORY;
}
This->surfaces = CALLOC(6 * (info->last_level + 1), sizeof(*This->surfaces));
if (!This->surfaces)
return E_OUTOFMEMORY;
hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, D3DRTYPE_CUBETEXTURE,
Format, Pool, Usage);
if (FAILED(hr))
return hr;
This->base.pstype = 2;
if (Pool != D3DPOOL_DEFAULT) {
level_offsets = alloca(sizeof(unsigned) * This->base.level_count);
face_size = nine_format_get_size_and_offsets(pf, level_offsets,
EdgeLength, EdgeLength,
This->base.level_count-1);
This->managed_buffer = align_calloc(6 * face_size, 32);
if (!This->managed_buffer)
return E_OUTOFMEMORY;
}
This->surfaces = CALLOC(6 * This->base.level_count, sizeof(*This->surfaces));
if (!This->surfaces)
return E_OUTOFMEMORY;
/* Create all the surfaces right away.
* They manage backing storage, and transfers (LockRect) are deferred
* to them.
@@ -143,7 +143,7 @@ NineCubeTexture9_ctor( struct NineCubeTexture9 *This,
*/
for (f = 0; f < 6; f++) {
offset = f * face_size;
for (l = 0; l <= info->last_level; l++) {
for (l = 0; l < This->base.level_count; l++) {
sfdesc.Width = sfdesc.Height = u_minify(EdgeLength, l);
p = This->managed_buffer ? This->managed_buffer + offset +
level_offsets[l] : NULL;
@@ -174,7 +174,7 @@ NineCubeTexture9_dtor( struct NineCubeTexture9 *This )
DBG("This=%p\n", This);
if (This->surfaces) {
for (i = 0; i < (This->base.base.info.last_level + 1) * 6; ++i)
for (i = 0; i < This->base.level_count * 6; ++i)
NineUnknown_Destroy(&This->surfaces[i]->base.base);
FREE(This->surfaces);
}
@@ -192,9 +192,7 @@ NineCubeTexture9_GetLevelDesc( struct NineCubeTexture9 *This,
{
DBG("This=%p Level=%u pDesc=%p\n", This, Level, pDesc);
user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
D3DERR_INVALIDCALL);
user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
*pDesc = This->surfaces[Level * 6]->desc;
@@ -212,9 +210,7 @@ NineCubeTexture9_GetCubeMapSurface( struct NineCubeTexture9 *This,
DBG("This=%p FaceType=%d Level=%u ppCubeMapSurface=%p\n",
This, FaceType, Level, ppCubeMapSurface);
user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
D3DERR_INVALIDCALL);
user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
user_assert(FaceType < 6, D3DERR_INVALIDCALL);
NineUnknown_AddRef(NineUnknown(This->surfaces[s]));
@@ -236,9 +232,7 @@ NineCubeTexture9_LockRect( struct NineCubeTexture9 *This,
DBG("This=%p FaceType=%d Level=%u pLockedRect=%p pRect=%p Flags=%d\n",
This, FaceType, Level, pLockedRect, pRect, Flags);
user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
D3DERR_INVALIDCALL);
user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
user_assert(FaceType < 6, D3DERR_INVALIDCALL);
return NineSurface9_LockRect(This->surfaces[s], pLockedRect, pRect, Flags);
@@ -253,7 +247,7 @@ NineCubeTexture9_UnlockRect( struct NineCubeTexture9 *This,
DBG("This=%p FaceType=%d Level=%u\n", This, FaceType, Level);
user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
user_assert(FaceType < 6, D3DERR_INVALIDCALL);
return NineSurface9_UnlockRect(This->surfaces[s]);

View File

@@ -1484,8 +1484,8 @@ NineDevice9_UpdateTexture( struct NineDevice9 *This,
* That should satisfy the constraints (and instead of crashing for some cases we return D3D_OK)
*/
last_src_level = (srcb->base.usage & D3DUSAGE_AUTOGENMIPMAP) ? 0 : srcb->base.info.last_level;
last_dst_level = (dstb->base.usage & D3DUSAGE_AUTOGENMIPMAP) ? 0 : dstb->base.info.last_level;
last_src_level = srcb->level_count-1;
last_dst_level = dstb->level_count-1;
for (m = 0; m <= last_src_level; ++m) {
unsigned w = u_minify(srcb->base.info.width0, m);

View File

@@ -149,37 +149,32 @@ NineTexture9_ctor( struct NineTexture9 *This,
DBG("Application asked for Software Vertex Processing, "
"but this is unimplemented\n");
hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, D3DRTYPE_TEXTURE, Format, Pool, Usage);
if (FAILED(hr))
return hr;
This->base.pstype = (Height == 1) ? 1 : 0;
if (pSharedHandle && *pSharedHandle) { /* Pool == D3DPOOL_SYSTEMMEM */
user_buffer = (void *)*pSharedHandle;
level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1));
level_offsets = alloca(sizeof(unsigned) * This->base.level_count);
(void) nine_format_get_size_and_offsets(pf, level_offsets,
Width, Height,
info->last_level);
This->base.level_count-1);
} else if (Pool != D3DPOOL_DEFAULT) {
/* TODO: For D3DUSAGE_AUTOGENMIPMAP, it is likely we only have to
* allocate only for the first level, since it is the only lockable
* level. Check apps don't crash if we allocate smaller buffer (some
* apps access sublevels of texture even if they locked only first
* level) */
level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1));
level_offsets = alloca(sizeof(unsigned) * This->base.level_count);
user_buffer = align_calloc(
nine_format_get_size_and_offsets(pf, level_offsets,
Width, Height,
info->last_level), 32);
This->base.level_count-1), 32);
This->managed_buffer = user_buffer;
if (!This->managed_buffer)
return E_OUTOFMEMORY;
}
This->surfaces = CALLOC(info->last_level + 1, sizeof(*This->surfaces));
This->surfaces = CALLOC(This->base.level_count, sizeof(*This->surfaces));
if (!This->surfaces)
return E_OUTOFMEMORY;
hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, D3DRTYPE_TEXTURE, Format, Pool, Usage);
if (FAILED(hr))
return hr;
This->base.pstype = (Height == 1) ? 1 : 0;
/* Create all the surfaces right away.
* They manage backing storage, and transfers (LockRect) are deferred
* to them.
@@ -191,7 +186,7 @@ NineTexture9_ctor( struct NineTexture9 *This,
sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE;
sfdesc.MultiSampleQuality = 0;
for (l = 0; l <= info->last_level; ++l) {
for (l = 0; l < This->base.level_count; ++l) {
sfdesc.Width = u_minify(Width, l);
sfdesc.Height = u_minify(Height, l);
/* Some apps expect the memory to be allocated in
@@ -228,7 +223,7 @@ NineTexture9_dtor( struct NineTexture9 *This )
if (This->surfaces) {
/* The surfaces should have 0 references and be unbound now. */
for (l = 0; l <= This->base.base.info.last_level; ++l)
for (l = 0; l < This->base.level_count; ++l)
if (This->surfaces[l])
NineUnknown_Destroy(&This->surfaces[l]->base.base);
FREE(This->surfaces);
@@ -247,9 +242,7 @@ NineTexture9_GetLevelDesc( struct NineTexture9 *This,
{
DBG("This=%p Level=%d pDesc=%p\n", This, Level, pDesc);
user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
D3DERR_INVALIDCALL);
user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
*pDesc = This->surfaces[Level]->desc;
@@ -263,9 +256,7 @@ NineTexture9_GetSurfaceLevel( struct NineTexture9 *This,
{
DBG("This=%p Level=%d ppSurfaceLevel=%p\n", This, Level, ppSurfaceLevel);
user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
D3DERR_INVALIDCALL);
user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
NineUnknown_AddRef(NineUnknown(This->surfaces[Level]));
*ppSurfaceLevel = (IDirect3DSurface9 *)This->surfaces[Level];
@@ -283,9 +274,7 @@ NineTexture9_LockRect( struct NineTexture9 *This,
DBG("This=%p Level=%u pLockedRect=%p pRect=%p Flags=%d\n",
This, Level, pLockedRect, pRect, Flags);
user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP),
D3DERR_INVALIDCALL);
user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
return NineSurface9_LockRect(This->surfaces[Level], pLockedRect,
pRect, Flags);
@@ -297,7 +286,7 @@ NineTexture9_UnlockRect( struct NineTexture9 *This,
{
DBG("This=%p Level=%u\n", This, Level);
user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
return NineSurface9_UnlockRect(This->surfaces[Level]);
}

View File

@@ -100,9 +100,6 @@ NineVolumeTexture9_ctor( struct NineVolumeTexture9 *This,
DBG("Application asked for Software Vertex Processing, "
"but this is unimplemented\n");
This->volumes = CALLOC(info->last_level + 1, sizeof(*This->volumes));
if (!This->volumes)
return E_OUTOFMEMORY;
This->base.pstype = 3;
hr = NineBaseTexture9_ctor(&This->base, pParams, NULL,
@@ -110,11 +107,15 @@ NineVolumeTexture9_ctor( struct NineVolumeTexture9 *This,
if (FAILED(hr))
return hr;
This->volumes = CALLOC(This->base.level_count, sizeof(*This->volumes));
if (!This->volumes)
return E_OUTOFMEMORY;
voldesc.Format = Format;
voldesc.Type = D3DRTYPE_VOLUME;
voldesc.Usage = Usage;
voldesc.Pool = Pool;
for (l = 0; l <= info->last_level; ++l) {
for (l = 0; l < This->base.level_count; ++l) {
voldesc.Width = u_minify(Width, l);
voldesc.Height = u_minify(Height, l);
voldesc.Depth = u_minify(Depth, l);
@@ -140,7 +141,7 @@ NineVolumeTexture9_dtor( struct NineVolumeTexture9 *This )
DBG("This=%p\n", This);
if (This->volumes) {
for (l = 0; l <= This->base.base.info.last_level; ++l)
for (l = 0; l < This->base.level_count; ++l)
if (This->volumes[l])
NineUnknown_Destroy(&This->volumes[l]->base);
FREE(This->volumes);
@@ -154,7 +155,7 @@ NineVolumeTexture9_GetLevelDesc( struct NineVolumeTexture9 *This,
UINT Level,
D3DVOLUME_DESC *pDesc )
{
user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
*pDesc = This->volumes[Level]->desc;
@@ -166,7 +167,7 @@ NineVolumeTexture9_GetVolumeLevel( struct NineVolumeTexture9 *This,
UINT Level,
IDirect3DVolume9 **ppVolumeLevel )
{
user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
NineUnknown_AddRef(NineUnknown(This->volumes[Level]));
*ppVolumeLevel = (IDirect3DVolume9 *)This->volumes[Level];
@@ -184,7 +185,7 @@ NineVolumeTexture9_LockBox( struct NineVolumeTexture9 *This,
DBG("This=%p Level=%u pLockedVolume=%p pBox=%p Flags=%d\n",
This, Level, pLockedVolume, pBox, Flags);
user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
return NineVolume9_LockBox(This->volumes[Level], pLockedVolume, pBox,
Flags);
@@ -196,7 +197,7 @@ NineVolumeTexture9_UnlockBox( struct NineVolumeTexture9 *This,
{
DBG("This=%p Level=%u\n", This, Level);
user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL);
user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
return NineVolume9_UnlockBox(This->volumes[Level]);
}