3

我有一个关于顶点缓冲区的问题。如何从 D3D11 中的顶点缓冲区中读取顶点?我想得到一个特定顶点的位置进行计算,如果这种方法是错误的,人们会怎么做?以下代码(显然)不起作用。

VERTEX* vert;
D3D11_MAPPED_SUBRESOURCE ms;
devcon->Map(pVBufferSphere, NULL, D3D11_MAP_READ, NULL, &ms);
vert = (VERTEX*) ms.pData;
devcon->Unmap(pVBufferSphere, NULL);  

谢谢。

4

3 回答 3

8

您的代码错误的地方:

  • 你要求 GPU 给你一个内存地址(Map()),
  • 存储此地址 ( operator=()),
  • 然后说:“谢谢,我不再需要它了”(Unmap())。

取消映射后,您无法真正说出指针现在指向的位置。它可以指向已经分配了另一个东西的内存位置或你女朋友笔记本电脑的内存(开玩笑=))。您必须复制数据(全部或部分),而不是两者之间的指针Map() Unmap():使用 memcopy、for循环等。把它放在数组中std::vector,,,BST,一切。

新手在这里可能犯的典型错误:

  1. 不检查方法的HRESULT返回值ID3D11DeviceContext::Map。如果 map 失败,它可以返回它喜欢的任何指针。取消引用此类指针会导致未定义的行为。因此,最好检查任何 DirectX 函数的返回值。
  2. 不检查 D3D11 调试输出。它可以用通俗易懂的英语(显然比我的英语好=)清楚地说出什么是错的和做什么。因此,您几乎可以立即修复错误。
  3. 如果 ID3D11Buffer是使用CPU 访问标志创建的,则只能从ID3D11Buffer中读取,这意味着您还必须设置使用标志。D3D11_CPU_ACCESS_READD3D11_USAGE_STAGING

我们通常如何从缓冲区读取:

  • 我们不使用暂存缓冲区进行渲染/计算:它很慢。
  • 相反,我们从主缓冲区(非暂存且 CPU 不可读)复制到暂存缓冲区(ID3D11DeviceContext::CopyResource()ID3D11DeviceContext::CopySubresourceRegion()),然后将数据复制到系统内存(memcopy())。
  • 我们不会在发布版本中这样做太多,它会损害性能。
  • 暂存缓冲区有两个主要的实际用途:调试(查看缓冲区是否包含错误数据并修复算法中的一些错误)和读取最终的非像素数据(例如,如果您在计算着色器中计算科学数据)。
  • 在大多数情况下,您可以通过精心设计代码来完全避免暂存缓冲区。认为 CPU<->GPU 仅以一种方式连接:CPU->GPU。
于 2013-07-03T12:01:19.380 回答
2

以下代码仅获取映射资源的地址,您在 Unmap 之前没有读取任何内容。

vert = (VERTEX*) ms.pData;

如果要从映射的资源中读取数据,先分配足够的内存,然后使用memcpy复制数据,我不知道你的VERTEX结构,所以我假设vert是void*,你可以自己转换

vert = new BYTE[ms.DepthPitch];
memcpy(vert, ms.pData, ms.DepthPitch];
于 2013-07-02T02:24:17.403 回答
1

Drop的回答很有帮助。我认为我无法读取缓冲区的原因是因为我之前没有将 CPU_ACCESS_FLAG 设置为 D3D11_CPU_ACCESS_READ。这里

D3D11_BUFFER_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
bufferDesc.ByteWidth = iNumElements * sizeof(T);
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
bufferDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE ;
bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
bufferDesc.StructureByteStride = sizeof(T);

然后读取我所做的数据

    const ID3D11Device& device = *DXUTGetD3D11Device();
    ID3D11DeviceContext& deviceContext = *DXUTGetD3D11DeviceContext();
    D3D11_MAPPED_SUBRESOURCE ms;
    HRESULT hr = deviceContext.Map(g_pParticles, 0, D3D11_MAP_READ, 0, &ms);    

    Particle* p = (Particle*)malloc(sizeof(Particle*) * g_iNumParticles);
    ZeroMemory(p, sizeof(Particle*) * g_iNumParticles);
    memccpy(p, ms.pData, 0, sizeof(ms.pData));
    deviceContext.Unmap(g_pParticles, 0);

    delete[] p;

我同意这是性能下降,我想这样做,只是为了能够调试值!

不管怎么说,还是要谢谢你!=)

于 2014-09-28T21:24:33.750 回答