> 技术文档 > window显示驱动开发—外壳着色器

window显示驱动开发—外壳着色器

外壳着色器每个补丁运行一次。 可以将外壳着色器与输入装配器中的修补程序一起使用。 外壳着色器可以将构成修补程序的输入控制点转换为输出控制点。 外壳着色器可以为固定函数细化器阶段执行其他设置。 例如,外壳着色器可以输出 tess 因子,这些因子是指示 tessellate 量的数字。

Direct3D 运行时调用以下驱动程序函数来创建、设置和销毁外壳着色器:

  • CalcPrivateShaderSize
  • CalcPrivateTessellationShaderSize
  • CreateHullShader
  • DestroyShader
  • HsSetShaderResources
  • HsSetShader
  • HsSetSamplers
  • HsSetConstantBuffers
  • HsSetShaderWithIfaces

外壳着色器核心机制

1. 执行特性
调用频率:每个补丁(Patch)运行一次,处理输入控制点 → 输出控制点 + 细分参数。

关键输出:

  • OutputControlPoints:转换后的控制点(传递给域着色器)。
  • TessFactors:细分因子(传递给固定函数细分器)。

2. 管线阶段依赖

驱动函数实现规范

1. 资源计算与创建

函数 职责 示例实现 CalcPrivateTessellationShaderSize 计算外壳着色器私有内存大小(考虑常量缓冲区、接口等)。 cpp return sizeof(DRIVER_HS_DATA) + NumInterfaces * sizeof(IFACE_PTR); CreateHullShader 编译/加载HS字节码,初始化硬件状态(如细分因子寄存器映射)。 [见下方代码块] DestroyShader 释放关联的GPU资源(如着色器缓存、临时内存)。 cpp pDriverHS->Release();

CreateHullShader 示例:

HRESULT CreateHullShader( D3D10DDI_HDEVICE hDevice, const UINT* pCode,// 着色器字节码 D3D10DDI_HSHADER hShader,  // 驱动句柄 D3D11DDIARG_TESSELLATION_HS_DESC* pDesc // 细分参数) { // 1. 编译为硬件指令 DRIVER_HS* pDriverHS = CompileHS(pCode, pDesc->OutputControlPoints); // 2. 配置细分因子寄存器 if (pDesc->pTessFactors) { WriteRegister(HS_TESS_FACTOR_REG, pDesc->pTessFactors); } // 3. 绑定驱动私有数据 hShader.pDrvPrivate = pDriverHS; return S_OK;}

2. 运行时绑定函数

函数 触发场景 硬件动作 HsSetShader 应用绑定新HS时调用。 更新着色器核心指令指针 + 细分因子寄存器基址。 HsSetShaderWithIfaces 绑定含动态接口的HS(如着色器链接)。 重定向接口表指针,刷新着色器缓存。 HsSetConstantBuffers 常量缓冲区更新时调用。 更新常量缓冲区GPU地址(如通过 pfnSetConstantBuffers 回调)。 HsSetShaderResources 输入资源(如SRV)变更时调用。 绑定纹理/SRV到指定槽位(需检查资源状态)。 HsSetSamplers 采样器状态更新时调用。 配置纹理采样器滤波模式(如 D3D11_DDI_SAMPLER_STATE)。

硬件交互要点

1. 细分因子传递
驱动需将 TessFactors 写入特定寄存器供固定函数单元读取:

void UpdateTessFactors(const float* pFactors) { WriteRegister(TESS_INNER_FACTOR_REG, pFactors[0]); // 内部分割因子 WriteRegister(TESS_OUTER_FACTOR_REG, pFactors[1]); // 外部分割因子}

2. 控制点数据流

  • 输入:从输入装配器获取原始控制点(如 D3D11_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST)。
  • 输出:通过片上缓存(On-Chip Cache)传递给域着色器,避免显存往返。

3. 动态接口处理

void HsSetShaderWithIfaces( D3D10DDI_HDEVICE hDevice, D3D10DDI_HSHADER hShader, const UINT* pIfaces // 接口函数指针数组) { DRIVER_HS* pDriverHS = (DRIVER_HS*)hShader.pDrvPrivate; for (UINT i = 0; i NumIfaces; i++) { pDriverHS->Ifaces[i] = pIfaces[i]; // 更新接口表 } FlushShaderCache(); // 确保新接口生效}

状态管理与验证

1. 资源冲突检查
当HS绑定资源(如SRV/UAV)时,驱动需验证:

bool CheckHSResourceConflict(D3D10DDI_HRESOURCE hResource) { D3D11_RESOURCE_STATES state = GetResourceState(hResource); return (state & D3D11_RESOURCE_STATE_COMPUTE_WRITE); // 计算管线写入冲突}

2. 细分能力报告
在 GetCaps 中声明硬件细分支持:

D3D11_FEATURE_DATA_D3D11_OPTIONS caps = {};caps.Tessellation = HardwareSupportsTessellation();pDeviceFuncs->pfnGetCaps(pDevice, &caps);

调试与性能优化

细分因子可视化

  • 通过 PIX 捕获 TessFactors 值,验证HS逻辑正确性。

控制点缓存命中率

  • 使用硬件性能计数器(如 NVIDIA NSIGHT)分析HS阶段缓存效率。

动态接口开销

  • 统计 HsSetShaderWithIfaces 调用频率,优化接口表更新机制。

错误处理

错误场景 返回码 恢复动作 无效细分因子(如NaN) DXGI_ERROR_INVALID_DATA 忽略该补丁,记录调试输出。 控制点输出越界 DXGI_ERROR_DEVICE_REMOVED 触发设备重置(如显存损坏)。 接口表不匹配 E_INVALIDARG 回退到默认接口,标记警告。

总结

  1. 补丁级处理:HS需高效处理控制点转换与细分参数生成。
  2. 硬件协作:通过寄存器配置与固定函数单元交互(细分器)。
  3. 状态隔离:严格管理资源绑定,避免绘图/计算管线冲突。
  4. 动态支持:正确处理着色器接口与运行时能力协商。