PIX 中的自定义纹理/网格可视化工具

使用自定义可视化工具,主要可以执行两项操作:

  1. 扩展管道视图纹理查看器以运行自定义计算着色器,而该着色器可读取绑定到管道的任意阶段的任何资源,并输出查看器中显示的 2D 纹理。

  2. 扩展管道视图缓冲区查看器以运行自定义计算着色器,而该着色器可读取绑定到管道的任意阶段的任何资源,并输出会在网格查看器中显示的索引缓冲区和顶点缓冲区。

PIX 扩展性设置

通过使用扩展性路径,可为 PIX 指定任意数量的文件夹来搜索可视化工具(*.hlsl 文件)。

如果可视化工具着色器#include不在主 HLSL 可视化工具文件旁的任意文件,则可使用扩展性包括搜索路径设置来为这些文件加载搜索路径。

在 PIX 中修改扩展路径的位置

自定义纹理可视化工具

假设已在设置中配置可视化工具着色器的路径,现在则可在可视化效果面板中看到列出的可视化工具。

下拉菜单中某些可视化工具的示例

“可视化效果”面板

可视化效果面板中的列表选择自定义可视化工具后,将显示自定义可视化效果部分。 在此处,可选择替代可视化工具输出的默认纹理格式。 默认情况下,选定的输出格式将与管道视图的当前选定纹理兼容。 这也是任何着色器编译警告/错误将显示的地方。

自定义扩展编译器错误示例

创建自定义纹理可视化工具

可视化工具是一个针对所选事件(即绘制、调度、调度网格)运行的计算着色器,输出将显示在纹理查看器中,以代替当前选定的纹理/呈现目标。 为了 PIX 能成功识别,入口点必须命名为 main

可通过将计算着色器指定为某一属性(例如,[numthreads(8, 8, 1)])来选择计算着色器的线程组大小,就像使用任何计算着色器一样。 PIX 将调用计算着色器,以便每个像素均有一个线程可执行。

例如,如果纹理大小为 512x512 像素,而计算着色器使用的线程组大小为 (8, 8, 1),则 PIX 引擎在内部完成的调用结果为 Dispatch(64, 64, 1)。 如果纹理大小不是线程组大小的倍数,则会调用比像素更多的线程来覆盖所有线程。

计算着色器生成的输出纹理将反映它通过 HLSL API 输出的最大坐标(例如 PixExt_StorePixel_Float(uint2 offset, float4 pixel))。

在 PIX 引擎中编译着色器代码时,使用的根签名是所选事件中绑定的根签名的修改版本。 这意味着(通过 PIX HLSL API)你可访问该事件可用的所有资源,以及绑定到 IA 和 OM 阶段的所有资源。

如果着色器中有错误(显示在可视化效果面板的 >文本框中的自定义可视化效果部分),则只需编辑文件以更正错误,并使用纹理查看器中的刷新按钮来重新生成,并重新执行可视化工具。

示例

可视化工具着色器的基本示例如下。

Texture2D<float4> SelectedTexture : PixExt_SelectedResourceRegister;

// For the custom PSO to successfully build, the root signature 
// of the selected event must have a valid binding for t0.
Texture2D<float4> SRV0 : register(t0);

[numthreads(8, 8, 1)]
void main(PixExt_ComputeInput input)
{
    uint2 selSize, srvSize;
    SelectedTexture.GetDimensions(selSize.x, selSize.y);
    SRV0.GetDimensions(srvSize.x, srvSize.y);

    float2 uvs = input.dispatchThreadId.xy / (float2)selSize;
    int2 srvCoords = (int2)(srvSize * uvs);
	
    float4 selectedValue = SelectedTexture.Load(int3(input.dispatchThreadId.xy, 0));
    float4 srv0Value = SRV0.Load(int3(srvCoords, 0)); 
    float4 finalValue = selectedValue * srv0Value.yzxw;

    PixExt_StorePixel_Float(input.dispatchThreadId.xy, finalValue);
}

在以上示例中,我们使用 PIX HLSL API 特殊寄存器 SelectedTexture 来声明 PixExt_SelectedResourceRegister 以指向管道视图的当前选定纹理。 我们还在 t0 中声明了 SRV0,知道它将出现在我们正在处理的 GPU 捕获的根签名中。 始终可以根据用例的要求,将扩展设置为通用扩展或特定扩展。 最后,我们使用 PixExt_StorePixel_Float 函数向纹理查看器输出,该函数将像素位置和值作为参数。

若要获取有关 API 的详细信息,请参阅 HLSL API 部分。

以上纹理可视化工具的示例输出

自定义缓冲区可视化工具

假设已设置路径以指向设置中的可视化工具着色器,现在则可在自定义可视化效果面板中看到可视化工具,且可使用以下缓冲区查看器工具栏图标打开该可视化工具:{}

自定义可视化面板

在该面板中,可选择任意可用的自定义可视化工具,并查看着色器编译器的任意警告/错误消息。

缓冲区可视化工具中的示例错误

创建自定义缓冲区可视化工具

可视化工具是一个针对所选事件运行的计算着色器,其输出将显示在网格查看器中,以代替显示当前所选缓冲区数据的缓冲区查看器。 为使 PIX 能成功识别,入口点必须命名为 main

可通过将计算着色器指定为某一属性(例如 [numthreads(32, 1, 1)])来选择计算着色器的线程组大小,就像处理任何计算着色器一样。 PIX 将调用计算着色器,因此每个缓冲区元素均有一个线程可执行。

例如,如果你有一个 100 个元素的缓冲区,而你的计算着色器使用的线程组大小为 (32, 1, 1),那么 PIX 引擎在内部完成的调用结果为 Dispatch(4, 1, 1)。 如果缓冲区大小不是线程组大小的倍数,则会调用比缓冲区元素更多的线程来覆盖所有线程。

分配给计算着色器的输出索引和顶点缓冲区会动态增长,以适应输出的所有数据。 可以根据需要输出尽可能多的数据。 索引为 32 位,而顶点仅允许为 float4 位置。

在 PIX 引擎中编译着色器代码时,使用的根签名是所选事件中绑定的根签名的修改版本。 这意味着(通过 PIX HLSL API)你可访问该事件可用的所有资源,以及绑定到 IA 和 OM 阶段的所有资源。

如果着色器中有错误(显示在自定义可视化效果面板的 >DXC 输出文本框中),则只需编辑文件以更正错误,并点击网格查看器中的刷新按钮来重新生成,并重新执行可视化工具。

示例

可视化工具着色器的基本示例如下

struct Vertex
{
    float3 position;
    float2 uv;
};

StructuredBuffer<Vertex> Vertices : PixExt_VertexBufferRegister0;

[numthreads(32, 1, 1)]
void main(PixExt_ComputeInput input)
{
    const uint vertexCount = PixExt_GetVertexCountPerInstance();

    if (input.dispatchThreadId.x < vertexCount)
    {
        const uint vertexStart = PixExt_GetStartVertexLocation();

        uint vertexOffset = input.dispatchThreadId.x + vertexStart;
        Vertex vertex = Vertices[vertexOffset];
        float4 newPosition = float4(vertex.position, 1.f);
        PixExt_StoreIndex(input.dispatchThreadId.x, input.dispatchThreadId.x);
        PixExt_StoreVertex(input.dispatchThreadId.x, newPosition);
    }
}

在以上示例中,我们使用 PIX HLSL API 特殊寄存器 Vertices 来访问声明 PixExt_VertexBufferRegister0 的顶点,以指向管道视图的当前绑定的顶点缓冲区 0。 然后,我们将使用 PixExt_StoreIndexPixExt_StoreVertex 函数将结果输出到网格查看器,这两个函数分别接受缓冲区偏移量和索引值以及顶点值作为参数。

若要获取有关 API 的详细信息,请参阅 HLSL API 部分。

以上缓冲区可视化工具的示例输出

将缓冲区可视化为纹理

可以选择缓冲区,并将自定义可视化工具的输出设置为纹理。 在这种情况下,将由纹理查看器代替常规缓冲区查看器来显示结果。

用户常量

可以添加可从 UI 为每个可视化工具调用设置其值的常量。 所有自定义可视化工具类型都支持它们。

HLSL 示例

PixExt_Declare_UserConstants_Start
    PixExt_UserConstant_Int(int_constant_name);
    PixExt_UserConstant_Uint(uint_constant_name);
    PixExt_UserConstant_Float(float_constant_name);
PixExt_Declare_UserConstants_End

允许在可视化工具中使用单个用户常量块(PixExt_Declare_UserConstants_Start / PixExt_Declare_UserConstants_End 对)。 可以添加 3 种不同类型的任意数量的常量,即 intuintfloat。 对于声明的每个条目,可视化面板中将显示一个新条目以输入所需的值。 0 是所有常量的默认值。

用户常量示例

PIX HLSL API

为了向你提供所有资源的访问权限,并有一个向查看器输出数据的标准方法,PIX 将在编译着色器时注入内部实现代码。 实现总是会发生变化,但以下记录的 API 在 PIX 版本中是稳定的。

资源访问

API 定义了一组特殊的寄存器,你可使用这些寄存器访问不同管道阶段的资源,而这些资源本身是不可访问的。

所选资源

PixExt_SelectedResourceRegister:授予对管道视图中当前所选资源的访问权限。

呈现器目标

PixExt_RenderTargetRegister0
PixExt_RenderTargetRegister1
PixExt_RenderTargetRegister2
PixExt_RenderTargetRegister3
PixExt_RenderTargetRegister4
PixExt_RenderTargetRegister5
PixExt_RenderTargetRegister6
PixExt_RenderTargetRegister7

深度/模具

PixExt_DepthRegister
PixExt_StencilRegister

输入程序集阶段资源

PixExt_IndexBufferRegister
PixExt_VertexBufferRegister0
PixExt_VertexBufferRegister1
PixExt_VertexBufferRegister2
PixExt_VertexBufferRegister3
PixExt_VertexBufferRegister4
PixExt_VertexBufferRegister5
PixExt_VertexBufferRegister6
PixExt_VertexBufferRegister7
PixExt_VertexBufferRegister8
PixExt_VertexBufferRegister9
PixExt_VertexBufferRegister10
PixExt_VertexBufferRegister11
PixExt_VertexBufferRegister12
PixExt_VertexBufferRegister13
PixExt_VertexBufferRegister14
PixExt_VertexBufferRegister15
PixExt_VertexBufferRegister16
PixExt_VertexBufferRegister17
PixExt_VertexBufferRegister18
PixExt_VertexBufferRegister19
PixExt_VertexBufferRegister20
PixExt_VertexBufferRegister21
PixExt_VertexBufferRegister22
PixExt_VertexBufferRegister23
PixExt_VertexBufferRegister24
PixExt_VertexBufferRegister25
PixExt_VertexBufferRegister26
PixExt_VertexBufferRegister27
PixExt_VertexBufferRegister28
PixExt_VertexBufferRegister29
PixExt_VertexBufferRegister30
PixExt_VertexBufferRegister31

可变速率着色

PixExt_ShadingRateImageRegister

着色器输入

可以将结构 PixExt_ComputeInput 用作主着色器函数的输入。 它是一个辅助功能,而并非强制功能。

struct PixExt_ComputeInput
{
    uint3 dispatchThreadId : SV_DispatchThreadID;
    uint3 groupId : SV_GroupID;
    uint3 groupThreadId : SV_GroupThreadID;
    uint groupIndex : SV_GroupIndex;
};

选定的纹理信息

// Returns the currently selected sample.
uint PixExt_GetSelectedSample();

// Returns the currently selected mip.
uint PixExt_GetSelectedMip();

// Returns the currently selected slice.
uint PixExt_GetSelectedSlice();

选定的事件参数

// For a DrawIndexedInstanced event,
// returns the IndexCountPerInstance.
uint PixExt_GetIndexCountPerInstance();

// For a DrawIndexedInstanced event,
// returns the StartIndexLocation
uint PixExt_GetStartIndexLocation();

// For a DrawInstanced event,
// returns the VertexCountPerInstance.
uint PixExt_GetVertexCountPerInstance();

// For a DrawInstanced event,
// returns the StartVertexLocation.
uint PixExt_GetStartVertexLocation();

// For a DrawInstanced or DrawIndexedInstanced event,
// returns the InstanceCount.
uint PixExt_GetInstanceCount();

// For a DrawInstanced or DrawIndexedInstanced event,
// returns the StartInstanceLocation.
uint PixExt_GetStartInstanceLocation();

// For a Dispatch or DispatchMesh event,
// returns the ThreadGroupCountX.
uint PixExt_GetThreadGroupCountX();

// For a Dispatch or DispatchMesh event,
// returns the ThreadGroupCountY.
uint PixExt_GetThreadGroupCountY();

// For a Dispatch or DispatchMesh event,
// returns the ThreadGroupCountZ.
uint PixExt_GetThreadGroupCountZ();

可变速率着色

// Returns the screen-space VRS image pixel tile size.
uint PixExt_GetShadingRateImageTileSize();

按资源名称绑定

你可以使用 PixExt_BindByName 特殊寄存器按名称来显式绑定到资源。 在自定义可视化工具资源声明中使用时,它会指示 PIX 在所选事件中找到要绑定到的同名资源。 例如,在自定义可视化工具中使用以下代码将导致绑定到在所选事件着色器中找到的名为 g_texture 的资源。

Texture2D<float4> g_texture : PixExt_BindByName;

着色器输出

可以使用以下函数向查看器输出数据。

纹理

// Stores the given INT pixel data for texture viewer display.
//
// offset: Pixel position to write to.
// pixel: Pixel data to write.
void PixExt_StorePixel_Int(uint2 offset, int4 pixel);

// Stores the given UINT pixel data for texture viewer display.
//
// offset: Pixel position to write to.
// pixel: Pixel data to write.
void PixExt_StorePixel_Uint(uint2 offset, uint4 pixel);

// Stores the given FLOAT pixel data for texture viewer display.
//
// offset: Pixel position to write to.
// pixel: Pixel data to write.
void PixExt_StorePixel_Float(uint2 offset, float4 pixel);

网格

// Stores the given index for mesh viewer display.
//
// offset: Offset into the index buffer to write to.
// index: Index to write.
void PixExt_StoreIndex(uint offset, uint index);

// Stores the given vertex position for mesh viewer display.
//
// offset: Offset into the vertex buffer to write to.
// vertex: Vertex position to write.
void PixExt_StoreVertex(uint offset, float4 vertex);

要求

将使用着色器模型 6.6(即 cs_6_6)和 HLSL 版本 2021 编译自定义可视化工具着色器。 我们计划支持较新的着色器模型,并在将来的版本中放宽对 HLSL 2021 的限制。