D3DLOCK写纹理遇到的问题

来源:互联网 发布:ubuntu 桥接网络配置 编辑:程序博客网 时间:2024/05/16 18:18

现象:以D3D_DISCARD方式来LockRect写入的显存数据在UnLock过后拷贝出来就崩溃,在一些机器出现而在某些机器就不会出现。

解决:判断游戏写纹理数据LockRect方式是D3D_DISCARD的话,在UnLockRect写完数据过后,就不对原来显存数据进行拷贝操作。由于游戏只有在第一个纹理是这样写的,而其他任何时候方式都是0,所以不会影响我们之后对显存数据的拷贝,从而进行逻辑操作。

 

 原因:

从D3D对D3D_DISCARD的解释说得通:即D3DLOCK_DISCARD表示不会取资源,只会全写资源,这样能立即返回给应用程序另外块显存地址指针,而原指针在本次UNLOCK之后被丢弃不再使用。

而引进D3D_DISCARD目的在于一般LOCK需要等待COMMAND BUFFER前面的绘制指令全部执行完毕才能返回,否则很可能修改正在使用的资源,从LOCK修改完毕到UNLock这段时间GPU是空闲的,于是为了解决空闲而引入这个标志。这样在GPU继续处理旧数据的同时,我们程序可以修改lock出来的新数据在unLock过后,GPU自动丢弃原数据,从而使用我们修改过的新数据。

 

由于在我们程序中是在UnLockRect过后然后对原来的显存数据进行操作,而这些数据是丢弃的原数据,可能在一些机器上会被销毁,进行访问操作就会出现这个问题。

 

在解决问题过程中发现一些有用的知识点:

D3DPOOL_DEFAULT   在显存中创建对象,这里的显存包括真正的显存和AGP内存,配合使用D3DUSAGE_WRITEONLY标记会提高效率,而提高效率的原因是DEFAULT资源可能在VM或AM中,如果在VM中,必须在系统内容中开辟一个临时缓冲返回给数据,当应用程序将数据填充到临时缓冲后,UNLOCK的时候,RUNTIME会将临时缓冲的数据传回到VM中去,如果资源D3DUSAGE属性不是WRITEONLY的,则系统还需要先从VM里拷贝一份原始数据到临时缓冲区。

当设备丢失,不可恢复,因为没有备份。

使用场景:游戏中使用的光标贴图,因为游戏运行会一直使用,所以创建到显存。

如果使用D3DPOOL_DEFAULT再加上 D3DUSAGE_DYNAMIC,那么系统就会强制把对象创建到AGP中。AGP本身就是内存的一部分,程序访问起来和内存对象没有什么区别,而且GPU访问的时候速度还很快,所以适合于创建频繁更新的数据,可能最多的是渲染到贴图的贴图对象。

使用场景:粒子系统

另外D3DPOOL_DEFAULT是不能Lock的,除非是动态的。

 

D3DPOOL_MANAGED   在显存中创建对象,同时在内存中创建一个备份。

当设备丢失,可恢复。因为有备份。

 

D3DPOOL_SYSTEMMEM 只在系统内存中创建对象。  

 

D3D_DISCARD和D3DLOCK_NOOVERWRITE的区别:

[注解:因为CPU和GPU是异步的操作,所以当CPU通过系统总线和GPU同步时,需要等到GPU把当前的工作做完。例如,当GPU正在对一块缓存进行DMA操作时,但往往CPU并不对GPU操作的那块缓存进行操作,所以CPU可以和GPU一起工作。当不指定操作标志时,CPU等待GPU完成绘制工作才更新顶点缓存,所以低效。如果指定D3DLOCK_NOOVERWRITE,表示CPU只更新顶点缓存中剩余的缓存,不考虑是否有其他图形绘制是正在使用这个的缓冲区段绘制图形,强制更新那段缓存并返回,而不像默认参数0那样等待前面的绘制结束,而不更新已经写入的顶点值,所以在CPU写入的时候,GPU可以并行的对那些已经存在的顶点值进行DMA等操作,所以高效;如果使用D3DLOCK_DISCARD 标志,说明当前分配的缓存大小不够了,需要重新使用缓存,CPU对这些新分配的缓存区域进行写操作,GPU这时可能还在异步处理旧的缓存区,所以这种调用也是高效的。调用完毕,收回释放的缓存。]

 

原创粉丝点击