在进入细节之前,我想概述一下问题:
我使用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集)。一切都按预期工作 - 除了墙上的最后一块砖丢失了。
计算采取以下步骤:
使用CS计算2D纹理(输出为“counterTable”和“colorOutbutTable”(有效)
可选择将此纹理渲染到屏幕(工作)
使用另一个CS生成网格(三角形列表)。该CS从步骤1获取x,y和颜色值,计算z坐标,最后为每个像素创建一个四边形。结果存储在“vertexTable”中。 (作品)
将三角形列表提供给顶点着色器(问题!!!)
渲染到屏幕(工作 - 使用顶点缓冲区)。
对于编程我使用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缓冲区(绑定到插槽t0中的缓冲区“output2”):
outputBuffer2D <- new Buffer(device, descr)
outputView2D <- new UnorderedAccessView (device, outputBuffer2D)
shaderResourceView2D <- new ShaderResourceView (device, outputBuffer2D)
创建3D缓冲区(在插槽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
答案 0 :(得分:2)
首先我要建议的是打开调试层(在创建设备时使用Debug标志),然后转到项目属性,调试选项卡,并勾选“启用非托管代码调试”或“启用本机代码调试” ”
当你开始调试程序时,如果管道状态有问题,运行时会给你潜在的警告。
一个潜在的问题(看起来最有可能是你发布的内容): 确保在调度后清理计算着色器无人机插槽。如果您尝试将vertexTable2绑定到顶点着色器,但资源仍然绑定为计算着色器输出,则运行时将自动将ShaderView设置为null(当您尝试读取时,它将返回0)。
要清理您的Compute Shader,请在设备上下文中调用此功能:
ComputeShader.SetUnorderedAccessView(TRIANGLE_SLOT, null)
另请注意,PixelShader可以访问RWStructuredBuffer(从技术上讲,如果您具有功能级别11.1,则可以将RWStructuredBuffer用于任何着色器类型,这意味着最近的ATI卡和Windows 8 +。)
答案 1 :(得分:0)
将三角形列表送入顶点着色器(问题!!!)
我会考虑使用原始缓冲区,而不是使用结构化缓冲区(不允许你绑定为vb)。它需要在着色器中进行转换,但允许您在cs和vs。
中使用相同的缓冲区创建缓冲区时,请执行以下操作:
D3D11_BUFFER_DESC desc = {};
desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_VERTEX_BUFFER;
desc.ByteWidth = byteSize;
desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
然后您可以绑定为着色器资源:
D3D11_SHADER_RESOURCE_VIEW_DESC desc = {};
desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
desc.BufferEx.FirstElement = 0;
desc.Format = DXGI_FORMAT_R32_TYPELESS;
desc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW;
desc.BufferEx.NumElements = descBuf.ByteWidth / 4;
或无序访问视图:
D3D11_UNORDERED_ACCESS_VIEW_DESC desc = {};
desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
desc.Buffer.FirstElement = 0;
desc.Format = DXGI_FORMAT_R32_TYPELESS; // Format must be DXGI_FORMAT_R32_TYPELESS, when creating Raw Unordered Access View
desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
desc.Buffer.NumElements = descBuf.ByteWidth / 4;
在着色器中,您可以使用以下内容:
ByteAddressBuffer Buffer0 : register(t0);
ByteAddressBuffer Buffer1 : register(t1);
RWByteAddressBuffer BufferOut : register(u0);
int i0 = asint( Buffer0.Load( DTid.x*8 ) );
float f0 = asfloat( Buffer0.Load( DTid.x*8+4 ) );
int i1 = asint( Buffer1.Load( DTid.x*8 ) );
float f1 = asfloat( Buffer1.Load( DTid.x*8+4 ) );
BufferOut.Store( DTid.x*8, asuint(i0 + i1) );
BufferOut.Store( DTid.x*8+4, asuint(f0 + f1) );
上面的示例代码取自DirectX June 2010 SDK的BasicCompute11示例。它演示了使用结构化缓冲区和原始缓冲区。