运行 带有 SharpDX 的 DX11 计算着色器 - 无法获得结果
Running a DX11 compute shader with SharpDX - cannot get results
我正在尝试 运行 计算着色器并使用 SharpDX 获取生成的纹理。
据我了解,我需要:
1. 创建纹理以设置为着色器的输出。
2. 将上面的纹理设置为无序访问视图,以便我可以写入它。
3. 运行 着色器
4. 将 UAV 纹理复制到暂存纹理,以便 CPU 可以访问它
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);
}
}
}
我对着色器还很陌生,所以这可能是显而易见的...
首先,您将无人机创建为本地 :
UnorderedAccessView view = new UnorderedAccessView(....
所以该字段为空,替换为
view = new UnorderedAccessView(....
将解决第一个问题。
其次,运行时很可能会抱怨类型(调试会给你类似的东西:
着色器代码 (FLOAT) 中声明的组件 0 的资源 return 类型与绑定到计算着色器单元 (UNORM) 的无序访问视图插槽 0 的资源类型不兼容。
有些卡片可能会做一些事情(静默修复),有些可能什么都不做,有些可能会崩溃:)
问题是 RWTexture2D 与 UNORM 格式不匹配(因为您在此处指定了平点格式)。
您需要强制您的 RWTexture 为 unorm 格式,例如(是的,运行时可能很挑剔):
RWTexture2D<unorm float4> Output : register(u0);
然后你的整个设置应该工作(PS:我没有检查位图代码,但我仔细检查了着色器 运行 没有错误并且第一个像素匹配)
我正在尝试 运行 计算着色器并使用 SharpDX 获取生成的纹理。
据我了解,我需要: 1. 创建纹理以设置为着色器的输出。 2. 将上面的纹理设置为无序访问视图,以便我可以写入它。 3. 运行 着色器 4. 将 UAV 纹理复制到暂存纹理,以便 CPU 可以访问它 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);
}
}
}
我对着色器还很陌生,所以这可能是显而易见的...
首先,您将无人机创建为本地 :
UnorderedAccessView view = new UnorderedAccessView(....
所以该字段为空,替换为
view = new UnorderedAccessView(....
将解决第一个问题。
其次,运行时很可能会抱怨类型(调试会给你类似的东西:
着色器代码 (FLOAT) 中声明的组件 0 的资源 return 类型与绑定到计算着色器单元 (UNORM) 的无序访问视图插槽 0 的资源类型不兼容。
有些卡片可能会做一些事情(静默修复),有些可能什么都不做,有些可能会崩溃:)
问题是 RWTexture2D 与 UNORM 格式不匹配(因为您在此处指定了平点格式)。
您需要强制您的 RWTexture 为 unorm 格式,例如(是的,运行时可能很挑剔):
RWTexture2D<unorm float4> Output : register(u0);
然后你的整个设置应该工作(PS:我没有检查位图代码,但我仔细检查了着色器 运行 没有错误并且第一个像素匹配)