DirectX 11 — вычислительный шейдер: запись в выходной ресурс

Я только начал использовать этап шейдера Compute в DirectX 11 и столкнулся с некоторым нежелательным поведением при записи в выходной ресурс в шейдере Compute. Кажется, я получаю только нули в качестве вывода, что, насколько я понимаю, означает, что в шейдере Compute было выполнено внешнее чтение. (Вне записи записывается результат без операций)

Создание компонентов шейдера Compute

Входные ресурсы

Сначала я создаю ID3D11Buffer* для входных данных. Это передается как ресурс при создании SRV, используемого для ввода на этапе шейдера Compute. Если входные данные никогда не меняются, то мы могли бы выпустить ID3D11Buffer* объект после создания SRV, поскольку SRV будет действовать как дескриптор ресурса.

Тем не менее, я хочу обновлять входные данные каждый кадр, так что я просто буду держать буфер в моем распоряжении для отображения.

// Create a buffer to be bound as Compute Shader input (D3D11_BIND_SHADER_RESOURCE).
D3D11_BUFFER_DESC constantDataDesc;
constantDataDesc.Usage                  = D3D11_USAGE_DYNAMIC;
constantDataDesc.ByteWidth              = sizeof(ParticleConstantData) * NUM_PARTICLES;
constantDataDesc.BindFlags              = D3D11_BIND_SHADER_RESOURCE;
constantDataDesc.CPUAccessFlags         = D3D11_CPU_ACCESS_WRITE;
constantDataDesc.StructureByteStride    = sizeof(ParticleConstantData);
constantDataDesc.MiscFlags              = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;

hr =  device->CreateBuffer ( &constantDataDesc, 0, &mInputBuffer );

Создание SRV с использованием вновь созданного буфера в качестве ресурса

D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.Format                  = DXGI_FORMAT_UNKNOWN;
srvDesc.ViewDimension           = D3D11_SRV_DIMENSION_BUFFEREX;
srvDesc.BufferEx.FirstElement   = 0;
srvDesc.BufferEx.Flags          = 0;
srvDesc.BufferEx.NumElements    = NUM_PARTICLES;

hr = device->CreateShaderResourceView( mInputBuffer, &srvDesc, &mInputView );

Выходные ресурсы

Теперь мне нужно создать ресурс для шейдера Compute для записи. Я также создам версию буфера в системной памяти для чтения. Я буду использовать ID3D11DeviceContext :: CopyResource метод скопировать данные из выходного буфера Compute Shader, подключенного к БПЛА, в версию системной памяти для выполнения отображения и сохранить ее содержимое обратно в системную память.

Создайте буфер чтения-записи, в который может записывать вычислительный шейдер

(D3D11_BIND_UNORDERED_ACCESS).
D3D11_BUFFER_DESC outputDesc;
outputDesc.Usage                = D3D11_USAGE_DEFAULT;
outputDesc.ByteWidth            = sizeof(ParticleData) * NUM_PARTICLES;
outputDesc.BindFlags            = D3D11_BIND_UNORDERED_ACCESS;
outputDesc.CPUAccessFlags       = 0;
outputDesc.StructureByteStride  = sizeof(ParticleData);
outputDesc.MiscFlags            = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;

hr = ( device->CreateBuffer( &outputDesc, 0, &mOutputBuffer ) );

Создайте версию буфера в системной памяти для чтения результатов из

outputDesc.Usage            = D3D11_USAGE_STAGING;
outputDesc.BindFlags        = 0;
outputDesc.CPUAccessFlags   = D3D11_CPU_ACCESS_READ;

hr = ( device->CreateBuffer( &outputDesc, 0, &mOutputResultBuffer ) );

Создание БПЛА для вычислительных шейдеров для записи результатов

D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
uavDesc.Buffer.FirstElement     = 0;
uavDesc.Buffer.Flags            = 0;
uavDesc.Buffer.NumElements      = NUM_PARTICLES;
uavDesc.Format                  = DXGI_FORMAT_UNKNOWN;
uavDesc.ViewDimension           = D3D11_UAV_DIMENSION_BUFFER;

hr = device->CreateUnorderedAccessView( mOutputBuffer, &uavDesc, &mOutputUAV );

Выполнение шейдера Compute (каждый кадр)

C ++

mParticleSystem.FillConstantDataBuffer( mDeviceContext, mInputBuffer );// Enable Compute Shader
mDeviceContext->CSSetShader( mComputeShader, nullptr, 0 );

mDeviceContext->CSSetShaderResources( 0, 1, &mInputView );
mDeviceContext->CSSetUnorderedAccessViews( 0, 1, &mOutputUAV, 0 );// Dispatch
mDeviceContext->Dispatch( 1, 1, 1 );

// Unbind the input textures from the CS for good housekeeping
ID3D11ShaderResourceView* nullSRV[] = { NULL };
mDeviceContext->CSSetShaderResources( 0, 1, nullSRV );

// Unbind output from compute shader
ID3D11UnorderedAccessView* nullUAV[] = { NULL };
mDeviceContext->CSSetUnorderedAccessViews( 0, 1, nullUAV, 0 );

// Disable Compute Shader
mDeviceContext->CSSetShader( nullptr, nullptr, 0 );// Copy result
mDeviceContext->CopyResource( mOutputBuffer, mOutputResultBuffer );// Update particle system data with output from Compute Shader
D3D11_MAPPED_SUBRESOURCE mappedResource;
HRESULT hr = mDeviceContext->Map( mOutputResultBuffer, 0, D3D11_MAP_READ, 0, &mappedResource );

if( SUCCEEDED( hr ) )
{
ParticleData* dataView = reinterpret_cast<ParticleData*>(mappedResource.pData);

// Update particle positions and velocities
mParticleSystem.UpdatePositionAndVelocity( dataView );

mDeviceContext->Unmap( mOutputResultBuffer, 0 );
}

HLSL

struct ConstantParticleData
{
float3 position;
float3 velocity;
float3 initialVelocity;
};

struct ParticleData
{
float3 position;
float3 velocity;
};

StructuredBuffer<ConstantParticleData>  inputConstantParticleData   : register( t0 );
RWStructuredBuffer<ParticleData>        outputParticleData          : register( u0 );[numthreads(32, 1, 1)]
void CS_main( int3 dispatchThreadID : SV_DispatchThreadID )
{
outputParticleData[dispatchThreadID.x].position = inputConstantParticleData[dispatchThreadID.x].position;
}

Прошу прощения за количество контента в этом вопросе. Я структурировал это с осторожностью, чтобы вам было легче получить обзор.

Количество элементов, передаваемых в шейдер, равно 32.

Любые предложения по моей проблеме? Спасибо!

6

Решение

Вы неправильно указали источник и назначение в своем обращении к CopyResource.

2

Другие решения


По вопросам рекламы [email protected]