Как читать вершины из буфера вершин в Direct3d11

У меня вопрос по поводу буферов вершин. Как читать вершины из буфера вершин в D3D11? Я хочу получить конкретную позицию вершины для вычислений, если этот подход неверен, как бы это сделать? Следующий код (очевидно) не работает.

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

Спасибо.


person Ma Sa    schedule 01.07.2013    source источник


Ответы (3)


Если ваш код неправильный:

  • Вы просите GPU дать вам адрес своей памяти (Map()),
  • Сохраняя этот адрес (operator=()),
  • Затем говорю: «Спасибо, мне это больше не нужно» (Unmap()).

После отмены сопоставления вы не можете точно сказать, куда теперь указывает ваш указатель. Он может указывать на место в памяти, где уже размещено другое содержимое, или на память ноутбука вашей девушки (шучу =)). Вы должны копировать данные (все или их часть), а не указатель между Map() Unmap(): используйте memcopy, for loop, что угодно. Поместите это в массив, std::vector, BST, все.

Типичные ошибки, которые могут сделать новички здесь:

  1. Не проверять HRESULT возвращаемое значение из ID3D11DeviceContext::Map. Если карта не работает, она может вернуть любой указатель, который ей нравится. Разыменование такого указателя приводит к неопределенному поведению. Итак, лучше проверьте любое возвращаемое значение функции DirectX.
  2. Не проверять отладочную информацию D3D11. Он может четко сказать, что не так и что делать, простым хорошим английским языком (явно лучше, чем мой английский =)). Таким образом, вы можете исправить ошибку практически мгновенно.
  3. Вы можете читать только из ID3D11Buffer если он был создан с помощью D3D11_CPU_ACCESS_READ < / a> флаг доступа к ЦП, что означает, что вы также должны установить _ 11_ использование fag.

Как мы обычно читаем из буфера:

  • Мы не используем промежуточные буферы для рендеринга / вычислений: это медленно.
  • Вместо этого мы копируем из основного буфера (не промежуточный и не читаемый ЦП) в промежуточный (_ 12_ или _ 13_), а затем копирование данных в системную память (memcopy()).
  • Мы не делаем этого слишком много в сборках релизов, это повредит производительности.
  • Есть два основных практических использования промежуточных буферов: отладка (посмотрите, содержит ли буфер неправильные данные и исправьте ошибку в алгоритме) и чтение окончательных непиксельных данных (например, если вы вычисляете научные данные в вычислительном шейдере).
  • В большинстве случаев вы можете вообще избежать промежуточных буферов, хорошо спроектировав свой код. Подумайте, как если бы CPU ‹-> GPU был подключен только одним способом: CPU-> GPU.
person Ivan Aksamentov - Drop    schedule 03.07.2013
comment
Спасибо за объяснение. Поскольку новичок в DirectX не понимал, что я могу просто умножить матрицу окончательного преобразования на вершину, чтобы получить ее позицию в коде C ++, то есть вне шейдера. Это все, что я хотел, поэтому использование выходного потока из конвейера было серьезным излишеством. - person Ma Sa; 03.07.2013

Следующий код получает только адрес сопоставленного ресурса, вы ничего не читали до Unmap.

vert = (VERTEX*) ms.pData;

Если вы хотите читать данные из сопоставленного ресурса, сначала выделите достаточно памяти, а затем используйте memcpy для копирования данных, я не знаю вашу структуру VERTEX, поэтому я полагаю, что vert недействителен *, вы можете преобразовать его самостоятельно

vert = new BYTE[ms.DepthPitch];
memcpy(vert, ms.pData, ms.DepthPitch];
person zdd    schedule 02.07.2013
comment
Спасибо за объяснение! - person Ma Sa; 03.07.2013
comment
После копирования памяти, как на самом деле получить доступ к вершинам? - person junfanbl; 25.06.2020

Ответ 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;

Я согласен, это снижение производительности, я хотел это сделать, просто чтобы иметь возможность отлаживать значения!

Спасибо, в любом случае! знак равно

person Rushabh    schedule 28.09.2014