Direct3D9: Try to avoid crashing if unable to allocate vram or memory for managed texture

This commit is contained in:
UnknownShadow200 2022-02-26 23:29:22 +11:00
parent 4377c46826
commit 463d7cae5d
2 changed files with 31 additions and 17 deletions

View File

@ -213,7 +213,7 @@ GfxResourceID Gfx_CreateTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipm
if (!Math_IsPowOf2(bmp->width) || !Math_IsPowOf2(bmp->height)) { if (!Math_IsPowOf2(bmp->width) || !Math_IsPowOf2(bmp->height)) {
Logger_Abort("Textures must have power of two dimensions"); Logger_Abort("Textures must have power of two dimensions");
} }
if (Gfx.LostContext) return 0; if (Gfx.LostContext) return NULL;
D3D11_TEXTURE2D_DESC desc = { 0 }; D3D11_TEXTURE2D_DESC desc = { 0 };
desc.Width = bmp->width; desc.Width = bmp->width;
@ -242,10 +242,11 @@ GfxResourceID Gfx_CreateTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipm
while ((hr = ID3D11Device_CreateTexture2D(device, &desc, src, &tex))) while ((hr = ID3D11Device_CreateTexture2D(device, &desc, src, &tex)))
{ {
if (hr == E_OUTOFMEMORY) { if (hr == E_OUTOFMEMORY) {
// insufficient VRAM or RAM left // insufficient VRAM or RAM left to allocate texture, try to reduce the memory in use first
if (!Game_ReduceVRAM()) return NULL; // if can't reduce, return 'empty' texture so that at least the game will continue running
if (!Game_ReduceVRAM()) return 0;
} else { } else {
// unknown issue, do not even try to handle it // unknown issue, so don't even try to handle the error
Logger_Abort2(hr, "Failed to create texture"); Logger_Abort2(hr, "Failed to create texture");
} }
} }

View File

@ -307,13 +307,13 @@ static void D3D9_DoMipmaps(IDirect3DTexture9* texture, int x, int y, struct Bitm
if (prev != bmp->scan0) Mem_Free(prev); if (prev != bmp->scan0) Mem_Free(prev);
} }
static IDirect3DTexture9* DoCreateTexture(struct Bitmap* bmp, int levels, int usage, int pool, void** data) { static IDirect3DTexture9* DoCreateTexture(struct Bitmap* bmp, int levels, int pool) {
IDirect3DTexture9* tex; IDirect3DTexture9* tex;
cc_result res; cc_result res;
for (;;) { for (;;) {
res = IDirect3DDevice9_CreateTexture(device, bmp->width, bmp->height, levels, res = IDirect3DDevice9_CreateTexture(device, bmp->width, bmp->height, levels,
usage, D3DFMT_A8R8G8B8, pool, &tex, data); 0, D3DFMT_A8R8G8B8, pool, &tex, NULL);
if (D3D9_CheckResult(res, "D3D9_CreateTexture failed")) break; if (D3D9_CheckResult(res, "D3D9_CreateTexture failed")) break;
} }
return tex; return tex;
@ -322,7 +322,6 @@ static IDirect3DTexture9* DoCreateTexture(struct Bitmap* bmp, int levels, int us
GfxResourceID Gfx_CreateTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps) { GfxResourceID Gfx_CreateTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps) {
IDirect3DTexture9* tex; IDirect3DTexture9* tex;
IDirect3DTexture9* sys; IDirect3DTexture9* sys;
DWORD usage = 0;
cc_result res; cc_result res;
int mipmapsLevels = CalcMipmapsLevels(bmp->width, bmp->height); int mipmapsLevels = CalcMipmapsLevels(bmp->width, bmp->height);
@ -334,19 +333,33 @@ GfxResourceID Gfx_CreateTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipm
if (Gfx.LostContext) return 0; if (Gfx.LostContext) return 0;
if (flags & TEXTURE_FLAG_MANAGED) { if (flags & TEXTURE_FLAG_MANAGED) {
tex = DoCreateTexture(bmp, levels, 0, D3DPOOL_MANAGED, NULL); while ((res = IDirect3DDevice9_CreateTexture(device, bmp->width, bmp->height, levels,
0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &tex, NULL)))
{
if (res == D3DERR_OUTOFVIDEOMEMORY || res == E_OUTOFMEMORY) {
/* insufficient VRAM or RAM left to allocate texture, try to reduce the memory in use first */
/* if can't reduce, return 'empty' texture so that at least the game will continue running */
if (!Game_ReduceVRAM()) return 0;
} else {
/* unknown issue, so don't even try to handle the error */
Logger_Abort2(res, "D3D9_CreateManagedTexture failed");
}
}
D3D9_SetTextureData(tex, bmp, 0); D3D9_SetTextureData(tex, bmp, 0);
if (mipmaps) D3D9_DoMipmaps(tex, 0, 0, bmp, bmp->width, false); if (mipmaps) D3D9_DoMipmaps(tex, 0, 0, bmp, bmp->width, false);
} else { return tex;
sys = DoCreateTexture(bmp, levels, 0, D3DPOOL_SYSTEMMEM, NULL); }
sys = DoCreateTexture(bmp, levels, D3DPOOL_SYSTEMMEM);
D3D9_SetTextureData(sys, bmp, 0); D3D9_SetTextureData(sys, bmp, 0);
if (mipmaps) D3D9_DoMipmaps(sys, 0, 0, bmp, bmp->width, false); if (mipmaps) D3D9_DoMipmaps(sys, 0, 0, bmp, bmp->width, false);
tex = DoCreateTexture(bmp, levels, usage, D3DPOOL_DEFAULT, NULL); tex = DoCreateTexture(bmp, levels, D3DPOOL_DEFAULT);
res = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9*)sys, (IDirect3DBaseTexture9*)tex); res = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9*)sys, (IDirect3DBaseTexture9*)tex);
if (res) Logger_Abort2(res, "D3D9_CreateTexture - Update"); if (res) Logger_Abort2(res, "D3D9_CreateTexture - Update");
D3D9_FreeResource(&sys); D3D9_FreeResource(&sys);
}
return tex; return tex;
} }