Запуск вычислительного шейдера DX11 с SharpDX — не удается получить результаты

Я пытаюсь запустить вычислительный шейдер и получить результирующую текстуру с помощью SharpDX.

Насколько я понял, мне нужно: 1. Создать текстуру для установки в качестве вывода в шейдер. 2. Установите приведенную выше текстуру как представление с неупорядоченным доступом, чтобы я мог писать в нее. 3. Запустите шейдер. 4. Скопируйте текстуру БПЛА в промежуточную текстуру, чтобы ЦП мог получить к ней доступ. 5. Считайте промежуточную текстуру в растровое изображение.

Проблема в том, что что бы я ни делал, результатом будет черное растровое изображение. Я не думаю, что ошибка в коде преобразования Texture2D -> Bitmap, поскольку печать первого пикселя непосредственно из промежуточной текстуры также дает я 0.

Это мой код шейдера:

RWTexture2D<float4> Output : register(u0);

[numthreads(32, 32, 1)]
void main(uint3 id : SV_DispatchThreadID) {
    Output[id.xy] = float4(0, 1.0, 0, 1.0);
}

Используя документы и блоги MS DX11, я собрал этот код для запуска текстуры:

public class GPUScreenColor {
    private int adapterIndex = 0;

    private Adapter1 gpu;
    private Device device;
    private ComputeShader computeShader;

    private Texture2D texture;
    private Texture2D stagingTexture;
    private UnorderedAccessView view;

    public GPUScreenColor() {
        initializeDirectX();
    }

    private void initializeDirectX() {
        using (var factory = new Factory1()) {
            gpu = factory.GetAdapter1(adapterIndex);
        }

        device = new Device(gpu, DeviceCreationFlags.Debug, FeatureLevel.Level_11_1);

        var compilationResult = ShaderBytecode.CompileFromFile("test.hlsl", "main", "cs_5_0", ShaderFlags.Debug);
        computeShader = new ComputeShader(device, compilationResult.Bytecode);

        texture = new Texture2D(device, new Texture2DDescription() {
            BindFlags = BindFlags.UnorderedAccess | BindFlags.ShaderResource,
            Format = Format.R8G8B8A8_UNorm,
            Width = 1024,
            Height = 1024,
            OptionFlags = ResourceOptionFlags.None,
            MipLevels = 1,
            ArraySize = 1,
            SampleDescription = { Count = 1, Quality = 0 }
        });

        UnorderedAccessView view = new UnorderedAccessView(device, texture, new UnorderedAccessViewDescription() {
            Format = Format.R8G8B8A8_UNorm,
            Dimension = UnorderedAccessViewDimension.Texture2D,
            Texture2D = { MipSlice = 0 }
        });

        stagingTexture = new Texture2D(device, new Texture2DDescription {
            CpuAccessFlags = CpuAccessFlags.Read,
            BindFlags = BindFlags.None,
            Format = Format.R8G8B8A8_UNorm,
            Width = 1024,
            Height = 1024,
            OptionFlags = ResourceOptionFlags.None,
            MipLevels = 1,
            ArraySize = 1,
            SampleDescription = { Count = 1, Quality = 0 },
            Usage = ResourceUsage.Staging
        });
    }

    public Bitmap getBitmap() {
        device.ImmediateContext.ComputeShader.Set(computeShader);
        device.ImmediateContext.ComputeShader.SetUnorderedAccessView(0, view);

        device.ImmediateContext.Dispatch(32, 32, 1);
        device.ImmediateContext.CopyResource(texture, stagingTexture);
        var mapSource = device.ImmediateContext.MapSubresource(stagingTexture, 0, MapMode.Read, MapFlags.None);

        Console.WriteLine(Marshal.ReadInt32(IntPtr.Add(mapSource.DataPointer, 0)));

        try {
            // Copy pixels from screen capture Texture to GDI bitmap
            Bitmap bitmap = new Bitmap(1024, 1024, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
            BitmapData mapDest = bitmap.LockBits(new Rectangle(0, 0, 1024, 1024), ImageLockMode.ReadWrite, bitmap.PixelFormat);

            try {
                var sourcePtr = mapSource.DataPointer;
                var destPtr = mapDest.Scan0;
                for (int y = 0; y < 1024; y++) {
                    // Copy a single line
                    Utilities.CopyMemory(destPtr, sourcePtr, 1024 * 4);

                    // Advance pointers
                    sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch);
                    destPtr = IntPtr.Add(destPtr, mapDest.Stride);
                }

                return bitmap;
            } finally {
                bitmap.UnlockBits(mapDest);
            }
        } finally {
            device.ImmediateContext.UnmapSubresource(stagingTexture, 0);
        }
    }
}

Я новичок в шейдерах, так что это может быть что-то очевидное...


person stormbreaker    schedule 03.06.2017    source источник
comment
Вы запускали с отладкой D3D11 (с включенной небезопасной отладкой и проверкой выходных окон отладки VS), чтобы убедиться, что в вашем потоке нет ничего плохого? Вы пробовали отладчик графики? (например, Рендердок)   -  person xoofx    schedule 04.06.2017


Ответы (1)


Прежде всего, вы создаете свой БПЛА как локальный:

UnorderedAccessView view = new UnorderedAccessView(....

Таким образом, поле становится нулевым, заменяя его на

view = new UnorderedAccessView(....

решит первую проблему.

Во-вторых, вполне вероятно, что среда выполнения будет жаловаться на типы (отладка даст вам что-то вроде:

Тип возвращаемого ресурса для компонента 0, объявленный в коде шейдера (FLOAT), несовместим с типом ресурса, привязанным к слоту 0 представления неупорядоченного доступа модуля вычислительного шейдера (UNORM).

Какие-то карты могут что-то делать (починить молча), какие-то ничего не делать, какие-то могут вылетать :)

Проблема в том, что RWTexture2D не соответствует формату UNORM (поскольку вы указываете здесь формат точки сглаживания).

Вам нужно, чтобы ваша RWTexture была конкретно в формате unorm, например (да, время выполнения может быть таким придирчивым):

RWTexture2D<unorm float4> Output : register(u0);

Тогда вся ваша настройка должна работать (PS: я не проверял растровый код, но дважды проверил, что шейдер работает без ошибок и первый пиксель совпадает)

person mrvux    schedule 11.06.2017
comment
Я был уверен, что это была какая-то глупость, которую я пропустил. Спасибо! Перепроверю, решит ли это проблему, когда вернусь домой (конец недели), и отмечу ответ. Тем временем я заставил его работать в новом проекте, не обнаружив, в чем проблема. - person stormbreaker; 12.06.2017