在详细介绍之前,我想概述一下问题:
我使用 RWStructuredBuffers 来存储我的计算着色器 (CS) 的输出。由于顶点和像素着色器无法从 RWStructuredBuffers 中读取,我将一个 StructuredBuffer 映射到同一插槽 (u0/t0) 和 (u4/t4):
cbuffer cbWorld : register (b1)
{
float4x4 worldViewProj;
int dummy;
}
struct VS_IN
{
float4 pos : POSITION;
float4 col : COLOR;
};
struct PS_IN
{
float4 pos : SV_POSITION;
float4 col : COLOR;
};
RWStructuredBuffer<float4> colorOutputTable : register (u0); // 2D color data
StructuredBuffer<float4> output2 : register (t0); // same as u0
RWStructuredBuffer<int> counterTable : register (u1); // depth data for z values
RWStructuredBuffer<VS_IN>vertexTable : register (u4); // triangle list
StructuredBuffer<VS_IN>vertexTable2 : register (t4); // same as u4
我使用 ShaderRecourceView 授予像素和/或顶点着色器访问缓冲区的权限。这个概念适用于我的像素着色器,但顶点着色器似乎只读取 0 值(我使用 SV_VertexID 作为缓冲区的索引):
PS_IN VS_3DA ( uint vid : SV_VertexID )
{
PS_IN output = (PS_IN)0;
PS_IN input = vertexTable2[vid];
output.pos = mul(input.pos, worldViewProj);
output.col = input.col;
return output;
}
没有来自 hlsl 编译器的错误消息或警告,renderloop 以 60 fps(使用 vsync)运行,但屏幕仍然是黑色的。由于我在调用 Draw(..) 之前使用 Color.White 将屏幕空白,因此渲染管道似乎处于事件状态。
当我通过 UAView 从 GPU 读取三角形数据内容到“vertArray”并将其反馈到顶点缓冲区时,一切正常:
程序:
let vertices = Buffer.Create(device, BindFlags.VertexBuffer, vertArray)
context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertices, Utilities.SizeOf<Vector4>() * 2, 0))
HLSL:
PS_IN VS_3D (VS_IN input )
{
PS_IN output = (PS_IN)0;
output.pos = mul(input.pos, worldViewProj);
output.col = input.col;
return output;
}
这里定义了 2D - Vertex/Pixelshaders。请注意,PS_2D 访问插槽 t0 中的缓冲区“output2” - 这正是我想要为 3D 顶点着色器“VS_3DA”复制的“技巧”:
float4 PS_2D ( float4 input : SV_Position) : SV_Target
{
uint2 pixel = uint2(input.x, input.y);
return output2[ pixel.y * width + pixel.x];
}
float4 VS_2D ( uint vid : SV_VertexID ) : SV_POSITION
{
if (vid == 0)
return float4(-1, -1, 0, 1);
if (vid == 1)
return float4( 1, -1, 0, 1);
if (vid == 2)
return float4(-1, 1, 0, 1);
return float4( 1, 1, 0, 1);
}
三天来,我一直在寻找和尝试,但无济于事。我收集的所有信息似乎都证实了我使用 SV_VertexID 的方法应该有效。
有人可以给建议吗?感谢您阅读我的帖子!
==================================================== ====================
细节:
我非常喜欢 DirectX 11 计算着色器的概念,我想将它用于代数计算。作为一个测试用例,我在 3D 中渲染分形(Mandelbrot 集)。一切都按预期工作——除了墙上的最后一 block 砖不见了。
计算采取以下步骤:
对于编程,我使用 F# 3.0 和 SharpDX 作为 .NET 包装器。
两个着色器(像素和顶点)的 ShaderRessourceView 设置为使用相同的参数(大小参数除外):
let mutable descr = new BufferDescription()
descr.BindFlags <- BindFlags.UnorderedAccess ||| BindFlags.ShaderResource
descr.Usage <- ResourceUsage.Default
descr.CpuAccessFlags <- CpuAccessFlags.None
descr.StructureByteStride <- xxx / / depends on shader
descr.SizeInBytes <- yyy / / depends on shader
descr.OptionFlags <- ResourceOptionFlags.BufferStructured
这里没什么特别的。
创建 2D 缓冲区(绑定(bind)到插槽 t0 中的缓冲区“output2”):
outputBuffer2D <- new Buffer(device, descr)
outputView2D <- new UnorderedAccessView (device, outputBuffer2D)
shaderResourceView2D <- new ShaderResourceView (device, outputBuffer2D)
创建 3D 缓冲区(绑定(bind)到插槽 t4 中的“vertexTable2”):
vertexBuffer3D <- new Buffer(device, descr)
shaderResourceView3D <- new ShaderResourceView (device, vertexBuffer3D)
// UAView not required here
为 2D 设置资源:
context.InputAssembler.PrimitiveTopology <- PrimitiveTopology.TriangleStrip
context.OutputMerger.SetRenderTargets(renderTargetView2D)
context.OutputMerger.SetDepthStencilState(depthStencilState2D)
context.VertexShader.Set (vertexShader2D)
context.PixelShader.Set (pixelShader2D)
渲染 2D:
context.PixelShader.SetShaderResource(COLOR_OUT_SLOT, shaderResourceView2D)
context.PixelShader.SetConstantBuffer(CONSTANT_SLOT_GLOBAL, constantBuffer2D )
context.ClearRenderTargetView (renderTargetView2D, Color.White.ToColor4())
context.Draw(4,0)
swapChain.Present(1, PresentFlags.None)
为 3D 设置资源:
context.InputAssembler.PrimitiveTopology <- PrimitiveTopology.TriangleList
context.OutputMerger.SetTargets(depthView3D, renderTargetView2D)
context.VertexShader.SetShaderResource(TRIANGLE_SLOT, shaderResourceView3D )
context.VertexShader.SetConstantBuffer(CONSTANT_SLOT_3D, constantBuffer3D)
context.VertexShader.Set(vertexShader3D)
context.PixelShader.Set(pixelShader3D)
渲染 3D(不起作用 - 黑屏作为输出结果)
context.ClearDepthStencilView(depthView3D, DepthStencilClearFlags.Depth, 1.0f, 0uy)
context.Draw(dataXsize * dataYsize * 6, 0)
swapChain.Present(1, PresentFlags.None)
最后是插槽号:
static let CONSTANT_SLOT_GLOBAL = 0
static let CONSTANT_SLOT_3D = 1
static let COLOR_OUT_SLOT = 0
static let COUNTER_SLOT = 1
static let COLOR_SLOT = 2
static let TRIANGLE_SLOT = 4
最佳答案
好的,我建议的第一件事是打开调试层(在创 build 备时使用调试标志),然后转到项目属性、调试选项卡,然后勾选“启用非托管代码调试”或“启用 native 代码调试”。
当您开始调试程序时,如果管道状态出现问题,运行时会给您潜在的警告。
一个潜在问题(从您发布的内容中看起来最有可能):
确保在调度后清理您的计算着色器 UAV 插槽。如果您尝试将 vertexTable2 绑定(bind)到您的顶点着色器,但该资源仍被绑定(bind)为计算着色器输出,则运行时将自动将您的 ShaderView 设置为 null(当您尝试读取它时将返回 0)。
要清理您的计算着色器,请在您完成调度的设备上下文中调用它:
ComputeShader.SetUnorderedAccessView(TRIANGLE_SLOT, null)
另请注意,PixelShader 可以访问 RWStructuredBuffer(从技术上讲,如果您的功能级别为 11.1,则可以将 RWStructuredBuffer 用于任何着色器类型,这意味着最近的 ATI 卡和 Windows 8+)。
关于hlsl - 如何使用顶点缓冲区将计算着色器结果输入顶点着色器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19907062/