D3DPOOL详解

部署运行你感兴趣的模型镜像


定义资源缓存的存储位置。

 

VIDEO MEMORY(VM)

显卡上的显存,CPU只能通过AGP或PCI-E总线访问,读写速度都是非常慢的,CPU连续写VM稍微快于读,因为CPU写VM时会在CACHE中分配32或64个字节(取决于CACHE LINE长度)的写缓冲,当缓冲满后会一次性写入VM。

SYSTEM MEMORY(SM):

就是系统内存,存放在System Memory上的Resource是不能直接被GPU访问的,对于GPU来说是不可见的,这种资源CPU读写都很快,但必须经过拷贝到VMAM中才能在GPU中渲染

AGP MEMORY(AM):

实际也存在于系统内存中,只是这部分内存已经被Mapping为显存的一部分,不但CPU可以访问这部分内存,而且GPU也可以通过PCI-E/AGP总线透明访问这部分内存,就像显存一样,但GPU访问速度比显存慢,毕竟经过映射,而且还要走PCI-E总线进行读写。

CPU连续的写会稍微快于读,原因就是CPU写AM使用了“writecombining”,GPU访问AM内存比较慢

D3DUSAGE_DYNAMIC会将资源放置在AM中。

 

D3DPOOL_DEFAULT:

此类资源不由D3D管理,常驻在显存或者AGP内存中渲染效率高;丢失需要重新创建;锁定读比较麻烦,一般设置为D3DUSAGE_WRITEONLY

   资源放置在显存或者AGP内存中,D3DPOOL_DEFAULT和D3DPOOL_MANAGED、D3DPOOL_SYSTEMMEM是不能同时存在的。

当设备丢失了(可能发生在窗口和全屏模式切换,或者不切换但修改分辨率),被D3DPOOL_DEFAULT创建的资源,在IDirect3DDevice9::Reset调用之前,必须被用release释放掉。使用D3DPOOL_DEFAULT创建资源时,如果内存不够用,那么managedresource会释放一些内存空间来满足需要。

   D3DPOOL_DEFAULT内存池中的纹理是不能锁定的,除非是D3DUSAGE_DYNAMIC使用方式的纹理或者是私有、FOURCC、

驱动格式的纹理。一些使用driver特有的像素格式创建的纹理,无法被Direct3D runtime识别,也是可以锁定的。

与texture不同的是,swapchain back buffers, render targets, vertex buffers和indexbuffers都是可以锁定的,

   去访问没有成功锁定的纹理,你必须使用IDirect3DDevice9::UpdateSurface, IDirect3DDevice9::UpdateTexture,

IDirect3DDevice9::GetFrontBufferData,and IDirect3DDevice9::GetRenderTargetData.

   D3DPOOL_MANAGED is probably a better choicethan D3DPOOL_DEFAULT for most applications.

 

适用情况:有时候我们希望将某些资源一直放在显存里,以提高访问速度。同时使用D3DUSAGE_WRITEONLY标记会提高效率。

例子:游戏中使用的光标贴图,在游戏运行过程中一直要使用,可以直接创建在显存中。
 如果数据需要高频率更新(不断的Lock, Unlock),也需要使用D3DPOOL_DEFAULT,同时使用D3DUSAGE_DYNAMIC标记。这意味着此资源会被创建在AGP Memory中。
 例子:使用CPU进行物理运算的粒子系统、使用CPU计算蒙皮的骨骼动画

 

注意:

   D3DPOOL_MANAGED 不一定会将贴图资源放到显卡里面,换句话说通常只有在贴图被使用的时候才会交换到显存中。

所以用D3DPOOL_MANAGED创建的时候数据大多数情况只是内存之间的传输(如果显卡总线忙也不影响继续加载),

而D3DPOOL_DEFAULT则在创建的时候就要不断的向显存中传输数据。如果你的资源是一起创建的,很容易造成了显卡

总线满载,后面的贴图要等待前面的贴图完全传送到显卡上了,才能开始传输。这种排队可能是造成你过慢的原因。

   我原来也尝试过 用D3DPOOL_DEFAULT,总觉得丢失回复的速度太慢了。另外显存交换也非常麻烦,

综合起来还不如D3DPOOL_MANAGED,所以贴图资源不建议使用D3DPOOL_DEFAULT

 

D3DPOOL_MANAGED

交给D3D托管,渲染效率一般(系统RAM/AGP内存/显存中都有); 设备丢失会自动恢复; 锁定读写效率较高。

资源交给D3D自动管理,资源会在系统内存中备份一份,在资源需要渲染的时候,会自动拷贝一份到AGP内存、显存中进行渲染。

当设备丢失时,D3D会自动恢复显存中的数据。

D3DPOOL_MANAGED的资源可以自由的锁定。

但是只有系统内存中的副本资源数据可以直接的修改,当需要渲染的时候D3D会自动的拷贝到AGP内存和显存中。

 

适用情况:由于D3D自己的资源管理方案很高效、使用简单,游戏中大部分资源都可以使用此标识创建

例子:游戏中使用的大部分纹理贴图,静态模型

 

D3DPOOL_SYSTEMMEM:

直接放置在系统中,渲染效率较差需要用UpdateSurface或UpdateTexture拷贝到D3DPOOL_DEFAULT创建的资源,

设备丢失时候不需要重新创建资源,锁定很方便CPU处理较快。

资源放置在系统RAM,但是不会减少RAM的可访问页,不能够被Direct3D 设备直接访问。当设备丢失的时候,这些资源不需要

重新创建。这些资源可以被锁定(读写),可以通过IDirect3DDevice9::UpdateSurfaceor IDirect3DDevice9::

UpdateTexture函数,将该类型的资源数据,设置为用D3DPOOL_DEFAULT创建的资源的数据来源。

使用:

对于需要高频CPU读写处理的数据,推荐使用这种方式。

 

D3DPOOL_SCRATCH:

    直接放置在系统中,不能直接的交给D3D渲染,设备丢失时候不需要创建资源,不被设备像素格式限制可以创建锁定拷贝。

这些资源放置在系统RAM中,当设备丢失时不需要重新创建数据。这些数据不被设备大小和像素格式的限制。正因为如此,

这些资源不能被Direct3D访问,不能够设置为纹理或者设置为渲染目标。然而,这些资源之间总是可以被创建,锁定和拷贝。

使用:

Directx 9引入这种内存池的原因是由于它从API中删除了CreateImageSurface()的函数。通常,D3DPOOL_SCRATCH是连同CreateOffscreenPlainSurface()一起使用的,后者将返回一个与之前通过CreateImageSurface()来创建的、具有相同特征的表面。因此,它主要用于创建图像表面

 

D3DPOOL_FORCE_DWORD:

强制编译器将本参数类型编译为32bit,如果没有使用这个值,一些编译器将会把本参数编译为一个大于或小于32bit的值。

这个值现在是没有使用的。

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think>我们正在讨论的是Direct3D9中的纹理管理问题。用户之前询问了关于D3DPOOL_MANAGED内存池的纹理复制可行性。在Direct3D9中,D3DPOOL_MANAGED是一种内存池类型,它表示纹理资源由Direct3D运行时管理,通常会在显存不足时将纹理存储在系统内存中,并在需要时自动上传到显存。对于使用D3DPOOL_MANAGED创建的纹理,我们同样可以使用StretchRect进行复制,但要注意以下几点:1.D3DPOOL_MANAGED纹理可以复制到另一个D3DPOOL_MANAGED纹理,也可以复制到其他内存池的纹理(如D3DPOOL_DEFAULT),但需要满足格式兼容性。2.使用StretchRect复制时,源纹理和目标纹理必须都是纹理的表面(即通过GetSurfaceLevel获取的表面),并且设备必须支持这种操作。3.由于D3DPOOL_MANAGED纹理由Direct3D管理,所以在复制时,如果源纹理在系统内存中有更新(比如通过LockRect修改),Direct3D会确保在复制前将最新的数据上传到显存(如果当前在显存中不存在,则先上传到显存再进行复制?)或者,实际上,StretchRect是设备操作,它要求源纹理必须位于显存中(对于D3DPOOL_MANAGED,在调用StretchRect时,如果纹理在系统内存中,那么需要先上传到显存,然后才能复制)。这可能导致一次上传的开销。但是,用户的问题是关于复制的可行性:答案是可行的。同时,我们也可以使用LockRect和memcpy来复制纹理数据,但这样效率较低,因为涉及到CPU读写数据。因此,推荐的方法是使用StretchRect进行硬件加速的复制,即使是D3DPOOL_MANAGED纹理也可以使用,但要注意可能存在一次上传的额外开销。下面我们将给出使用StretchRect复制两个D3DPOOL_MANAGED纹理的示例代码,并讨论注意事项。步骤:1.创建两个D3DPOOL_MANAGED纹理(注意:必须创建为纹理表面,即使用CreateTexture)。2.使用GetSurfaceLevel获取这两个纹理的顶级表面(或指定mip层级的表面)。3.调用StretchRect进行复制。注意:StretchRect要求纹理是能够被设备访问的,即必须使用同一个设备创建的纹理。代码示例:```cpp//假设g_pd3dDevice是有效的Direct3D设备IDirect3DTexture9*pSrcManagedTexture=NULL;IDirect3DTexture9*pDstManagedTexture=NULL;//创建源纹理(D3DPOOL_MANAGED)g_pd3dDevice->CreateTexture(width,height,1,0,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,&pSrcManagedTexture,NULL);//创建目标纹理(同样使用D3DPOOL_MANAGED)g_pd3dDevice->CreateTexture(width,height,1,0,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,&pDstManagedTexture,NULL);//获取表面IDirect3DSurface9*pSrcSurface=NULL;IDirect3DSurface9*pDstSurface=NULL;pSrcManagedTexture->GetSurfaceLevel(0,&pSrcSurface);pDstManagedTexture->GetSurfaceLevel(0,&pDstSurface);//复制g_pd3dDevice->StretchRect(pSrcSurface,NULL,pDstSurface,NULL,D3DTEXF_NONE);//释放表面pSrcSurface->Release();pDstSurface->Release();//使用完毕后释放纹理pSrcManagedTexture->Release();pDstManagedTexture->Release();```注意事项:-此操作是在GPU上进行的,但由于D3DPOOL_MANAGED纹理的存储位置可能变化,所以在复制前可能会有一个上传源纹理到显存的过程(如果当前不在显存中)。这会导致复制操作的延迟略高。-如果源纹理之前被LockRect修改过,那么在下一次使用StretchRect时,Direct3D会确保使用最新的数据。但是,LockRect操作在D3DPOOL_MANAGED纹理上是直接修改系统内存备份,然后在需要时上传到显存(例如渲染时使用,或者StretchRect时使用)。因此,在调用StretchRect之前,最好确保源纹理的最新数据已经可用(通过锁定后解锁,然后由Direct3D管理上传,但通常我们不需要显式上传,因为StretchRect操作会触发上传)。-复制后,目标纹理(也是D3DPOOL_MANAGED)的显存部分被更新,同时系统内存备份也会被更新吗?答案是不会立即更新。D3DPOOL_MANAGED纹理在显存中的备份被更新后,系统内存备份不会立即更新。系统内存备份会在需要时(例如设备丢失后恢复)从显存中回读,或者由应用程序通过LockRect读取。但是注意,StretchRect操作的目标纹理如果是D3DPOOL_MANAGED,那么它更新的是显存中的纹理,而系统内存备份并不会更新(除非使用LockRect回读)。如果应用程序需要读取修改后的目标纹理数据,则必须使用LockRect将数据从显存回读到系统内存(这会导致一次回读操作,影响性能)。因此,如果目标纹理是用于后续的渲染操作,则没有问题,因为后续渲染操作会使用显存中的纹理。综上所述,使用StretchRect复制D3DPOOL_MANAGED纹理是可行的,但需要注意其内存管理的特点可能带来额外的上传和回读开销。另外,如果用户需要频繁更新纹理,或者需要频繁复制,使用D3DPOOL_DEFAULT纹理配合D3DPOOL_SYSTEMMEM纹理作为暂存可能更高效,因为这样可以避免管理上传和回读的开销。但是具体选择需要根据应用场景。相关问题:1.D3DPOOL_MANAGED纹理与D3DPOOL_DEFAULT纹理在性能上有什么区别?2.在Direct3D9中,如何高效地更新D3DPOOL_MANAGED纹理?3.使用StretchRect复制纹理时,如何处理不同格式的纹理?4.如何通过LockRect和memcpy复制D3DPOOL_MANAGED纹理?有什么性能影响?5.在设备丢失后,D3DPOOL_MANAGED纹理如何恢复?请根据这些思路组织答案。</think> ### 📌 使用`D3DPOOL_MANAGED`进行纹理复制的可行性分析 在 Direct3D 9 中,**`D3DPOOL_MANAGED`纹理支持复制操作,但有特定限制和要求**。以下是关键要点: #### ✅ 支持复制的场景 1. **同内存池复制 (MANAGED → MANAGED)** 使用 `StretchRect` 可高效复制: ```cpp IDirect3DSurface9 *pSrcSurface, *pDstSurface; pSrcTexture->GetSurfaceLevel(0, &pSrcSurface); // MANAGED池纹理 pDstTexture->GetSurfaceLevel(0, &pDstSurface); // MANAGED池纹理 g_pd3dDevice->StretchRect(pSrcSurface, NULL, pDstSurface, NULL, D3DTEXF_NONE); ``` - **优势**:GPU硬件加速,避免CPU复制开销[^3] - **条件**:纹理尺寸、格式、mip层级需完全匹配 2. **跨池复制 (MANAGED → DEFAULT/SYSTEMMEM)** 需通过中转: ```cpp // 创建临时DEFAULT池纹理 IDirect3DTexture9* pTempTex; g_pd3dDevice->CreateTexture(..., D3DPOOL_DEFAULT, &pTempTex); // MANAGED → DEFAULT 复制 g_pd3dDevice->UpdateTexture(pSrcManagedTex, pTempTex); // DEFAULT → 目标池 复制 g_pd3dDevice->StretchRect(..., pFinalSurface); ``` - **性能开销**:增加一次内存传输[^1] #### ⚠️ 直接复制的限制 1. **不支持 `memcpy` 直接操作** ```cpp // 错误做法!会破坏纹理内存结构 D3DLOCKED_RECT srcRect, dstRect; pSrcTex->LockRect(0, &srcRect, NULL, 0); pDstTex->LockRect(0, &dstRect, NULL, 0); memcpy(dstRect.pBits, srcRect.pBits, dataSize); // ✘ 潜在崩溃风险 ``` - **原因**:MANAGED池纹理有内部内存对齐机制(如128字节边界) - **风险**:可能破坏纹理数据,导致渲染异常或设备丢失[^2] 2. **异步操作限制** 在 `BeginScene()`/`EndScene()` 外部执行复制: ```cpp // 正确执行位置 g_pd3dDevice->EndScene(); // 先结束场景 g_pd3dDevice->StretchRect(...); // 执行复制 g_pd3dDevice->BeginScene(); // 重启场景 ``` #### 📊 性能优化建议 | 操作类型 | 适用场景 | 带宽开销 | |---------|----------|----------| | `StretchRect` (同池) | 实时渲染 | 显存→显存 (0.5-5ms/帧) | | `UpdateTexture` | 静态资源初始化 | CPU→显存 (20-100ms) | | `LockRect`+`memcpy` | 像素级修改 | 双倍带宽 (不推荐) | > **最佳实践**:优先使用 `StretchRect` 进行MANAGED池内复制,跨池操作时通过 `UpdateTexture` 中转[^4]。 #### ⚙️ 设备状态检查 ```cpp // 验证设备支持复制操作 D3DCAPS9 caps; g_pd3dDevice->GetDeviceCaps(&caps); if(!(caps.Caps2 & D3DCAPS2_CANMANAGERESOURCE)) { // 处理设备不支持的情况 } ``` --- ### 📚 相关问题 1. `D3DPOOL_MANAGED`与`D3DPOOL_DEFAULT`在纹理复制时有何性能差异? 2. 如何安全修改`D3DPOOL_MANAGED`纹理的像素数据? 3. DX11中是否保留了`D3DPOOL_MANAGED`的内存管理机制? 4. 设备丢失后`D3DPOOL_MANAGED`纹理如何自动恢复? 5. 多层级Mipmap纹理如何进行跨池复制?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值