像素着色器可以访问结构化缓冲区而顶点着色器不能 - 这是DirectX规范吗?

时间:2013-11-14 15:44:11

标签: directx hlsl vertex-shader compute-shader

====================编辑:解决方案=====================

我终于找到了问题,因为对于正在学习DirectX的初学者来说,答案可能很重要,我在这里发布。 (我使用F#和SharpDX作为DirectX的.NET包装器)

在我的程序中,资源(缓冲区,视图等)仅在调整交换链的大小时才会更改。所以我将所有资源分配(IA,OM,VS,PS)放入函数switchTo2DLayout。如果交换链调整大小,switchTo2DLayout会立即返回(不做任何操作)。这由一面旗帜控制。

后来我发现这个标志从未被重置,因此资源分配在每次绘制调用之前完成。我纠正了这个错误,但现在只在第一次调用renderPixels时才渲染图像。事实证明,我必须在绘制调用之前设置ShaderresourceView 每次

let renderPixels () =
    switchTo2DLayout()

    // this line was missing:
    context.PixelShader.SetShaderResource(COUNT_COLOR_SLOT, countColorSRV_2D)

    context.ClearRenderTargetView (renderTargetView2D, Color.White.ToColor4())
    context.Draw(4,0)                                                
    swapChain.Present(1, PresentFlags.None)  

这对我来说完全出乎意料。关于我使用的DirectX的书籍从未明确说明可以分配哪些资源一次(只要设置不变),并且必须在每次抽奖调用上分配

对于网格渲染,我使用类似的设置(这里没有我提到的错误),同样缺少等效的行:

let draw3D() = 
    switchTo3DLayout()

     // this line was missing:
     context.VertexShader.SetShaderResource(TRIANGLE_SLOT, triangleSRV  ) 

     context.ClearDepthStencilView(depthView3D, DepthStencilClearFlags.Depth, 1.0f, 0uy
     context.ClearRenderTargetView(renderTargetView2D, Color4.Black )                                                            
     context.Draw(triangleCount, 0)
     swapChain.Present(1, PresentFlags.None)    

这解释了为什么2D渲染因为错误(像素着色器从缓冲区读取)而工作,而3D没有(顶点着色器从缓冲区读取)。

=======================我的原帖:=================

前几天我发布了一个问题[link:] How can I feed compute shader results into vertex shader w/o using a vertex buffer?,这个问题可能太复杂了,无法回答。与此同时,我将设置简化为更简单的情况:

struct PS_IN
{
float4 pos : SV_POSITION;
float4 col : COLOR;
};

RWStructuredBuffer<float4> colorOutputTable :  register (u5);
StructuredBuffer<float4> output2 :             register (t5);  

案例A:像素着色器设置颜色(工作)

// vertex shader A

PS_IN VS_A  ( uint vid : SV_VertexID )  
{
    PS_IN output = (PS_IN)0;   
    if (vid == 0) output.pos = float4(-1, -1, 0, 1);
    if (vid == 1) output.pos = float4( 1, -1, 0, 1);
    if (vid == 2) output.pos = float4(-1,  1, 0, 1);    
    if (vid == 3) output.pos = float4( 1,  1, 0, 1);    

    return output;  
}

// pixel shader A

float4  PS_A ( float4 input : SV_Position) : SV_Target
{        
  uint2 pixel =  uint2(input.x, input.y);       
  return output2[ pixel.y * width + pixel.x];   // PS accesses buffer (works)

}

案例B:顶点着色器设置颜色(不起作用)

// vertex shader B

PS_IN VS_B ( uint vid : SV_VertexID )   
{
    PS_IN output = (PS_IN)0;   
    if (vid == 0) output.pos = float4(-1, -1, 0, 1);
    if (vid == 1) output.pos = float4( 1, -1, 0, 1);
    if (vid == 2) output.pos = float4(-1,  1, 0, 1);    
    if (vid == 3) output.pos = float4( 1,  1, 0, 1);    
    output.col = output2[vid];  // VS accesses buffer (does not work)
    return output;  
}

// pixel shader B

float4 PS_B  (PS_IN input ) : SV_Target
{
    return input.col;
}

显然,像素着色器可以访问“output2”缓冲区,而顶点着色器不能(读取始终为零)。

搜索互联网我找不到任何有关此行为的解释。在我的“真实”应用程序中,计算着色器计算三角形列表并将其存储在RWStructuredBuffer中,因此我需要从顶点着色器(通过映射的插槽)访问此表。

我想许多使用计算着色器的人可能会遇到这个问题。不知道怎么解决这个问题? (我目前无法使用Level 11.1或11.2,我必须找到基于11.0的解决方案)

1 个答案:

答案 0 :(得分:1)

刚刚在这里试过,你的着色器似乎有效(从未遇到任何阶段无法访问StructuredBuffer的问题,功能级别11)。

示例来自SharpDX minicube(刚刚更换了着色器代码,并添加了一个缓冲区)。

我唯一要做的就是为你的三角形带来反转(我可以修改光栅化器)。

由于我知道调试管道存在问题,另一种有用的方法是查看是否有错误使用查询(在您的情况下主要是PipelineStatistics和Occlusion)。

某些错误的状态可能很容易产生问题,因此您可以通过查看写入/渲染的基元数量来立即查看是否有错误。

这里的着色器代码:

struct PS_IN
{
    float4 pos : SV_POSITION;
    float4 col : COLOR;
};

RWStructuredBuffer<float4> colorOutputTable :  register (u5);
StructuredBuffer<float4> output2 :             register (t5);

PS_IN VS_B(uint vid : SV_VertexID)
{
    PS_IN output = (PS_IN)0;
    if (vid == 1) output.pos = float4(-1, -1, 0, 1);
    if (vid == 0) output.pos = float4(1, -1, 0, 1);
    if (vid == 3) output.pos = float4(-1, 1, 0, 1);
    if (vid == 2) output.pos = float4(1, 1, 0, 1);
    output.col = output2[vid];  // VS accesses buffer (does not work)
    return output;
}

// pixel shader B

float4 PS_B(PS_IN input) : SV_Target
{
    return input.col;
}

代码是here(它非常笨重,所以我把它放在了pastebin上)