D3D9纹理内存释放问题
问题发生场景:用 CreateTexture
函数创建纹理,在纹理 Surface 上绘制图像,用完之后调用 Release
函数释放纹理,发现在多次创建纹理后内存暴增,texture->Release()
函数并未生效。
问题原因:在绘制图像时使用了 LPD3DXSPRITE, IDirect3DSurface9
2D绘制和渲染目标切换,但是没有释放这些绘制对象。
修改后基本代码如下:
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
HRESULT hr = S_FALSE;
// D3D文本绘制对象
LPD3DXFONT pFont = NULL;
// 2D绘制对象
LPD3DXSPRITE pSprite = NULL;
// 水印文本渲染目标纹理
LPDIRECT3DTEXTURE9 pRenderTexture = NULL;
// 水印文本渲染场景
IDirect3DSurface9* pRenderSurface = NULL;
// 原D3D渲染目标
IDirect3DSurface9 *pOldRenderTarget = NULL;
do
{
pFont = InitD3DFont(pDevice, conf->font_family, font_size);
if (!pFont)
{
logerr("[TextureBuilder.cpp] d3d字体初始化失败");
break;
}
hr = D3DXCreateSprite(pDevice, &pSprite);
if (FAILED(hr))
{
logerr("[TextureBuilder.cpp] 创建D3D 2D绘制对象失败");
break;
}
// 创建透明纹理,注意在设置参数的时候需要将usage设置为D3DUSAGE_RENDERTARGET,因为只有这样才能在纹理上渲染
hr = pDevice->CreateTexture(
t_width, t_height, 1,
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, &pRenderTexture, NULL);
if (FAILED(hr))
{
logerr("[TextureBuilder.cpp] 渲染目标纹理创建失败");
break;
}
// 取得纹理对应的Surface,以便在其上绘制场景
hr = pRenderTexture->GetSurfaceLevel(0, &pRenderSurface);
if (FAILED(hr))
{
logerr("[TextureBuilder.cpp] 获取纹理表面失败");
break;
}
// 向纹理的Surface中绘制场景,注意绘制时需要将纹理的表面设置为当前的RenderTarget,所以首先要保存原来的RenderTarget
hr = pDevice->GetRenderTarget(0, &pOldRenderTarget);
if (FAILED(hr))
{
logerr("[TextureBuilder.cpp] 获取原始渲染目标失败");
break;
}
// 设置当前纹理表面为渲染目标
hr = pDevice->SetRenderTarget(0, pRenderSurface);
if (FAILED(hr))
{
logerr("[TextureBuilder.cpp] 设置新渲染目标失败");
break;
}
hr = pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0);
if (FAILED(hr))
{
logerr("[TextureBuilder.cpp] D3D Clear 背景颜色错误");
break;
}
// 开始绘制
if (SUCCEEDED(pDevice->BeginScene()))
{
if (SUCCEEDED(pSprite->Begin(D3DXSPRITE_ALPHABLEND)))
{
// pSprite绘制,略
pSprite->End();
}
pDevice->EndScene();
}
//D3DXSaveTextureToFile(L"texture.png", D3DXIFF_PNG, g_pRenderTexture, NULL);
// 恢复原来的RenderTarget
pDevice->SetRenderTarget(0, pOldRenderTarget);
} while (false);
// 必须在绘制完成后释放这些对象,否则造成内存泄露
SAFE_RELEASE(pFont);
SAFE_RELEASE(pSprite);
SAFE_RELEASE(pRenderSurface);
SAFE_RELEASE(pOldRenderTarget);
// 返回给外部使用
return pRenderTexture;
注意
调用 GetSurfaceLevel
函数获得的 pRenderSurface
对象需要手动释放,GetRenderTarget
函数获得的 pOldRenderTarget
亦然,否则只释放目标纹理是无效的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探