我对D3D中的顶点缓存的概念感到迷惑,特别是其分配和锁定的操作,不知道这些名称的含义是什么(转载)?
当"allocating vertex buffers_分配顶点缓存"时:
当使用 STATIC(这个是.net 情况,对于非.net版本dx是没有指定D3DUSAGE_DYNAMIC)标识分配顶点缓存时,这块缓存位于显存中。它的典型应用是只写一次并不被读回内存的情况。
只有当标志 D3DUSAGE_DYNAMIC被设置时 D3DUSAGE_WRITEONLY标志才有意义。
如果使用DYNAMIC标志创建缓存 (使用D3DUSAGE_DYNAMIC创建的缓存) ,并且D3DUSAGE_WRITEONLY 被使用,缓存被分配到显存中。
如果使用DYNAMIC标志创建缓存 (使用D3DUSAGE_DYNAMIC创建的缓存) ,并且D3DUSAGE_WRITEONLY 不被使用, 缓存被分配到AGP 缓存中。(CPU从AGP缓存中读取的速度比显存中快,但比内存慢,是个很好的折中)
如果没有足够的显存,顶点缓存被分配到AGP缓存中;如果AGP缓存也不够时,创建失败,除非使用POOL_ MANAGED 创建。在这种情况下,D3D的运行库会释放足够多的显存,用来创建顶点缓存,并在内存中保存创建的缓存的一个拷贝。那些被运行库释放的显存,在需要它们时可以从内存中复制到显存中。注意标志POOL_ MANAGED 并不被发送到驱动程序,因为这是D3D的附加的功能。
对于NV1X 系列的GPUs, 在进行多数据流渲染得时候,如果有一个顶点缓存位于AGP缓存中,所有的其他位于显存中的顶点缓存会被移动到AGP缓存中。
当" locking vertex buffers_锁定顶点缓存"时:
如果顶点缓存的创建标志是POOL_DEFAULT:
如果没有指定任何标志,程序将被暂停,因为它强制程序和GPU同步操作。->低效
如果指定D3DLOCK_NOOVERWRITE 标志,应用程序不会改变缓存区已存在的内容,运行库会在以后继续使用这块缓存。当应用程序调用这个函数时,驱动程序立即返回。->高效
如果指定D3DLOCK_DISCARD 标志,程序将会更新整个缓存的值,实际上是分配一块新的缓存,即驱动程序重命名它。->高效
[注解:因为CPU和GPU是异步的操作,所以当CPU通过系统总线和GPU同步时,需要等到GPU把当前的工作做完。例如,当GPU正在对一块缓存进行DMA操作时,但往往CPU并不对GPU操作的那块缓存进行操作,所以CPU可以和GPU一起工作。当不指定操作标志时,CPU等待GPU完成绘制工作才更新顶点缓存,所以低效。如果指定D3DLOCK_NOOVERWRITE,表示CPU只更新顶点缓存中剩余的缓存,不考虑是否有其他图形绘制是正在使用这个的缓冲区段绘制图形,强制更新那段缓存并返回,而不像默认参数0那样等待前面的绘制结束,而不更新已经写入的顶点值,所以在CPU写入的时候,GPU可以并行的对那些已经存在的顶点值进行DMA等操作,所以高效;如果使用D3DLOCK_DISCARD 标志,说明当前分配的缓存大小不够了,需要重新使用缓存,CPU对这些新分配的缓存区域进行写操作,GPU这时可能还在异步处理旧的缓存区,所以这种调用也是高效的。调用完毕,收回释放的缓存。]
来自 GameRes 说明了 Lock 的标志含义,我改了一部分内容。因为 D3DLOCK_NOOVERWRITE 和 D3DLOCK_DISCARD 是要经常使用的。越熟练越好
NOOVERWRITE 并不是不覆盖数据,如果2个三角形在缓存中地址相同。后面定点内容会覆盖前面的。而前面的三角形将不能画出来。
如果缓冲区开的足够大,render 几帧才能使用完这个缓冲。可以一直使用NOOVERWRITE 就可以。当不够使用时在从头开始使用这个顶点缓冲。如果足够大。开头的顶点基本确定已经画完(都是前几帧的图形顶点内容了。被覆盖也无所谓),如果缓冲很小lock时可以调用DISCARD,表示丢弃缓冲区内容(被丢弃的内容如果在使用中还可以被GPU继续使用。NOOVERWRITE 不会保留,所以速度更好)。如下使用开头的6个顶点画2个四边形。但该用NOOVERWRITE 将之后后面的四边形
Quad->Lock(0, 6*sizeof(Vertex), (void**)&v, D3DLOCK_DISCARD);
// quad built from two triangles, note texture coordinates:
//v += 6;
v[0] = Vertex(0.0f, 0.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[1] = Vertex(0.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
v[2] = Vertex( 1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[3] = Vertex(0.0f, 0.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[4] = Vertex( 1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[5] = Vertex( 1.0f, 0.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
Quad->Unlock();
Device->SetTexture(0, Tex1);
Device->SetStreamSource(0, Quad, 0, sizeof(Vertex));
Device->SetFVF(Vertex::FVF);
Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
Quad->Lock(0, 6*sizeof(Vertex), (void**)&v, D3DLOCK_DISCARD);
// quad built from two triangles, note texture coordinates:
v[0] = Vertex(-1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[1] = Vertex(-1.0f, 0.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
v[2] = Vertex( 0.0f, 0.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[3] = Vertex(-1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
v[4] = Vertex( 0.0f, 0.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
v[5] = Vertex( 0.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
Quad->Unlock();
Device->SetTexture(0, Tex);
Device->SetStreamSource(0, Quad, 0, sizeof(Vertex));
Device->SetFVF(Vertex::FVF);
Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
当使用 D3DLOCK_NOOVERWRITE 标志时,似乎Lock 使用偏移地址没什么意义.或许可以提高性能