Directx 10:使用CopySubresourceRegion更新顶点缓冲区

时间:2014-01-05 04:31:35

标签: c++ dynamic vertex-buffer directx-10

我创建了一个顶点缓冲区,如下所示:

ID3D10Buffer * VertexBuffer;
Vertex_PosCol * Vertices;
D3D10_SUBRESOURCE_DATA VertexData;


    Vertices = new Vertex_PosCol[VerticeCount];

    Vertices[0].Position = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
    Vertices[0].Color = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);

    Vertices[1].Position = D3DXVECTOR3(-1.0f, 2.0f, 0.0f);
    Vertices[1].Color = D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f);

    Vertices[2].Position = D3DXVECTOR3(1.0f, 2.0f, 0.0f);
    Vertices[2].Color = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f);

    Vertices[3].Position = D3DXVECTOR3(2.0f, 1.0f, 0.0f);
    Vertices[3].Color = D3DXVECTOR4(0.0f, 0.0f, 1.0f, 1.0f);

    Vertices[4].Position = D3DXVECTOR3(2.0f, -1.0f, 0.0f);
    Vertices[4].Color = D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0f);

    Vertices[5].Position = D3DXVECTOR3(1.0f, -2.0f, 0.0f);
    Vertices[5].Color = D3DXVECTOR4(0.0f, 1.0f, 1.0f, 1.0f);

    Vertices[6].Position = D3DXVECTOR3(-1.0f, -2.0f, 0.0f);
    Vertices[6].Color = D3DXVECTOR4(1.0f, 0.0f, 1.0f, 1.0f);

    Vertices[7].Position = D3DXVECTOR3(-2.0f, -1.0f, 0.0f);
    Vertices[7].Color = D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f);

    Vertices[8].Position = D3DXVECTOR3(-2.0f, 1.0f, 0.0f);
    Vertices[8].Color = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f);

    D3D10_BUFFER_DESC vbd;
    vbd.Usage = D3D10_USAGE_DYNAMIC;
    vbd.ByteWidth = sizeof(Vertex_PosCol) * VerticeCount;
    vbd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
    vbd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
    vbd.MiscFlags = 0;


    VertexData.pSysMem = Vertices;

    HRESULT result = this->GDM.Device->CreateBuffer(&vbd, &VertexData, &VertexBuffer);

我目前正在使用ID3D10Buffer :: Map()更新我的顶点,现在工作正常。这个问题是我的应用程序将来可能需要大量的顶点更新,但不是每个网格/缓冲区中的每个顶点(一天,缓冲区将保存多个网格)。据我所知,到处都说使用ID3D10Device :: CopySubresourceRegion()。这正是我想要做的!除了我不能让它工作。我根本不明白它是如何工作的。我在上面阅读了微软的页面,并没有针对顶点缓冲区。我希望有人可以向我解释如何在顶点缓冲区方面实现它和/或将我链接到一些有用的资源来做同样的事情。

2 个答案:

答案 0 :(得分:11)

您要问的是什么并不十分清楚,因为您无法使用ID3D10Device::CopySubresourceRegion()更新缓冲区。我想在答案中澄清资源复制和资源更新。

更新资源

通过“更新”资源,我们通常意味着将数据从系统内存传输到GPU内存 1 ,并进行覆盖。 要更新资源,请使用ID3D10Buffer::Map() / ID3D10Buffer::Unmap()对或ID3D10Device::UpdateSubresource()方法。哪个更好用,取决于资源属性和更新频率(阅读Nvidia's "canonical" paper)。

用法非常简单。这是一个简单的1D缓冲区的例子,例如顶点缓冲区。

// Source array/vector (srcData): [xxxxDATADATADATADATADATAxxxxxxxxxxx]
//                                     ^                   ^
//                                 srcBegin        (srcBegin+bytesToCopy)
//
// Destination buffer (pBuffer):  [xxDATADATADATADATADATAxxxxxxxxxxxxx]  
//                                   ^                   ^
//                              destinationBegin  (destinationBegin+bytesToCopy)
D3D11_BOX box{};
box.left = destinationBegin;
box.right = destinationBegin + bytesToCopy;
box.top = 0;
box.bottom = 1;
box.front = 0;
box.back = 1;
Device->UpdateSubresource(pBuffer, 0, &box, (uint8_t*)srcData+srcBegin, 0, 0);

复制资源

正如名称所述,ID3D10Device::CopySubresourceRegion()方法适用于在两个资源之间复制数据(例如缓冲区或纹理)。简化,您可以将其视为在视频卡的内存中复制数据块(但并非总是如此)。您不能使用该方法“更新”GPU内存,因为数据已经被复制了。

这是一个简单的例子:

D3D11_BOX srcBox{};
srcBox.left = srcBegin;
srcBox.right = srcBegin + size;
srcBox.top = 0;
srcBox.bottom = 1;
srcBox.front = 0;
srcBox.back = 1;
Device->CopySubresourceRegion(pDst, 0, dstBegin, 0, 0, pSrc, 0, &srcBox);

希望它有所帮助。

BTW,没有任何理由在2013年学习DirectX 10.您可以从DirectX 11开始,它的API几乎相同,但功能更多。


1 此解释过于简化。我们永远无法确定给定资源所在的位置(GPU,系统内存,任何存储),因为驱动程序实现者需要决定何时以及何种类型的资源存储。

答案 1 :(得分:1)

提示:size是每个字节大小的顶点数量

    D3D11_BOX srcBox{};
    srcBox.left = srcBegin;
    srcBox.right = srcBegin + size;   <-here
    srcBox.top = 0;
    srcBox.bottom = 1;
    srcBox.front = 0;
    srcBox.back = 1;
    Device->CopySubresourceRegion(pDst, 0, dstBegin, 0, 0, pSrc, 0, &srcBox);