2

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

我终于找到了问题所在,因为答案对于正在学习 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 没有(顶点着色器从缓冲区读取)。

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

几天前,我发布了一个问题 [链接:]如何使用顶点缓冲区将计算着色器结果输入到顶点着色器中?这可能太复杂而无法回答。同时,我将设置简化为一个更简单的情况:

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的解决方案)

4

1 回答 1

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;
}

代码在这里(它很笨重,所以我把它放在 pastebin 上)

于 2013-11-14T17:19:58.143 回答