DirectX - запись в 3D текстуру, вызывающая сбой драйвера дисплея - PullRequest
0 голосов
/ 18 ноября 2018

Я тестирую запись в 2D и 3D текстуры в вычислительных шейдерах, выводя текстуру с градиентным шумом, состоящую из 32-битных чисел с плавающей точкой. Запись в 2D текстуру работает нормально, а запись в 3D текстуру - нет. Есть ли дополнительные соображения, которые необходимо учитывать при создании 3D-текстуры по сравнению с 2D-текстурой?

Код того, как я определяю 3D-текстуру ниже:

HRESULT BaseComputeShader::CreateTexture3D(UINT width, UINT height, UINT depth, DXGI_FORMAT format, ID3D11Texture3D** texture)
{

D3D11_TEXTURE3D_DESC textureDesc;
ZeroMemory(&textureDesc, sizeof(textureDesc));
textureDesc.Width = width;
textureDesc.Height = height;
textureDesc.Depth = depth;
textureDesc.MipLevels = 1;
textureDesc.Format = format;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
textureDesc.CPUAccessFlags = 0;
textureDesc.MiscFlags = 0;

return renderer->CreateTexture3D(&textureDesc, 0, texture);

}

HRESULT BaseComputeShader::CreateTexture3DUAV(UINT depth, DXGI_FORMAT format, ID3D11Texture3D** texture, ID3D11UnorderedAccessView** unorderedAccessView)
{

D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
ZeroMemory(&uavDesc, sizeof(uavDesc));
uavDesc.Format = format;
uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D;
uavDesc.Texture3D.MipSlice = 0;
uavDesc.Texture3D.FirstWSlice = 0;
uavDesc.Texture3D.WSize = depth;

return renderer->CreateUnorderedAccessView(*texture, &uavDesc, unorderedAccessView);

}

HRESULT BaseComputeShader::CreateTexture3DSRV(DXGI_FORMAT format, ID3D11Texture3D** texture, ID3D11ShaderResourceView** shaderResourceView)
{

D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = format;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
srvDesc.Texture3D.MostDetailedMip = 0;
srvDesc.Texture3D.MipLevels = 1;

return renderer->CreateShaderResourceView(*texture, &srvDesc, shaderResourceView);

}

И как я пишу это в вычислительном шейдере:

// The texture we're writing to
RWTexture3D<float> outputTexture : register(u0);

[numthreads(8, 8, 8)]
void main(uint3 DTid : SV_DispatchThreadID)
{

float noiseValue = 0.0f;
float value = 0.0f;
float localAmplitude = amplitude;
float localFrequency = frequency;

// Loop for the number of octaves, running the noise function as many times as desired (8 is usually sufficient)
for (int k = 0; k < octaves; k++)
{

    noiseValue = noise(float3(DTid.x * localFrequency, DTid.y * localFrequency, DTid.z * localFrequency)) * localAmplitude;

    value += noiseValue;

    // Calculate a new amplitude based on the input persistence/gain value
    // amplitudeLoop will get smaller as the number of layers (i.e. k) increases
    localAmplitude *= persistence;
    // Calculate a new frequency based on a lacunarity value of 2.0
    // This gives us 2^k as the frequency
    // i.e. Frequency at k = 4 will be f * 2^4 as we have looped 4 times
    localFrequency *= 2.0f;

}

// Output value to 2D index in the texture provided by thread indexing
outputTexture[DTid.xyz] = value;

}

И, наконец, как я запускаю шейдер:

// Set the shader
deviceContext->CSSetShader(computeShader, nullptr, 0);
// Set the shader's buffers and views
deviceContext->CSSetConstantBuffers(0, 1, &cBuffer);
deviceContext->CSSetUnorderedAccessViews(0, 1, &textureUAV, nullptr);

// Launch the shader
deviceContext->Dispatch(512, 512, 512);

// Reset the shader now we're done
deviceContext->CSSetShader(nullptr, nullptr, 0);

// Reset the shader views
ID3D11UnorderedAccessView* ppUAViewnullptr[1] = { nullptr };
deviceContext->CSSetUnorderedAccessViews(0, 1, ppUAViewnullptr, nullptr);

// Create the shader resource view for access in other shaders
HRESULT result = CreateTexture3DSRV(DXGI_FORMAT_R32_FLOAT, &texture, &textureSRV);
if (result != S_OK)
{

    MessageBox(NULL, L"Failed to create texture SRV after compute shader execution", L"Failed", MB_OK);
    exit(0);

}

Ответы [ 2 ]

0 голосов
/ 29 декабря 2018

Если вы создаете текстуру 512 * 512 * 512 (кажется, что вы пытаетесь достичь), ваша отправка должна быть разделена на группы:

deviceContext->Dispatch(512 / 8, 512 / 8, 512 / 8);

В вашем предыдущем случае отправкабыло: 512 * 8 * 512 * 8 * 512 * 8 = 68719476736 единиц

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

Также ограничение 65535 относится к измерениюв вашем случае вы абсолютно безопасны для запуска этого.

И последнее, вы можете создать как вид ресурса шейдера, так и неупорядоченный вид сразу после создания 3d-текстуры (до вызова диспетчеризации).

Как правило, рекомендуется избегать смешивания кода контекста и кода создания ресурса.

При создании ресурса ваша проверка недопустима:

if (result != S_OK)

Условие успеха HRESULT>> 0

вместо этого вы можете использовать встроенный макрос, например:

if (SUCCEEDED(result)) 
0 голосов
/ 18 ноября 2018

Моя плохая, простая ошибка.Количество вычислительных шейдерных потоков ограничено.В вычислительном шейдере вы ограничены 1024 потоками, и диспетчерский вызов не может отправить более 65535 групп потоков.Компилятор HLSL уловит первую проблему, но компилятор Visual C ++ не уловит последнюю проблему.

...