DirectX计算着色器(Compute Shader)线程组相关参数详解(SV_GroupIndex,SV_DispatchThreadID,SV_GroupThreadID,SV_GroupID)

        在DirectX 11之前,着色器是与具体的渲染步骤绑定的,例如像素着色器,顶点着色器等等。而从DirectX11开始,DirectX增加了一种计算着色器(Compute Shader),它是专门为与图形无关的通用计算设计的。因此DirectX就变成了一个通用GPU计算的平台。鉴于GPU拥有极其强大的并行运算能力,学习使用DirectCompute是很有意义的。   

        计算着色器的计算能力和处理器数量有关,比如如果你的GPU有16个多处理器,那么就可以开启16个线程组。每个线程组,可以有n个线程。NVIDIA显卡基于SIMD32,n必须是一个warp(即32)的倍数。而ATI显卡是基于一个wavefront(即64)的倍数。一个线程组可以互相共享内存,而且等待每个线程同步,但是不同线程组是没有该能力的。

   下面是一个计算着色器案例

//numthreads(N, 1, 1),代表着线程的数量,是三维的

//groupThreadID,线程在线程组中的ID,用三维向量的形式表示如(3,1,1)

//dispatchThreadID,在一次dispatch线程中的ID,表示的是该线程在整个分发的线程组中的ID,用三维形式表示。

#define N 256
#define CacheSize (N + 2*gBlurRadius)
groupshared float4 gCache[CacheSize];


[numthreads(N, 1, 1)]
void HorzBlurCS(int3 groupThreadID : SV_GroupThreadID,
int3 dispatchThreadID : SV_DispatchThreadID)
{
//
// Fill local thread storage to reduce bandwidth.  To blur 
// N pixels, we will need to load N + 2*BlurRadius pixels
// due to the blur radius.
//

// This thread group runs N threads.  To get the extra 2*BlurRadius pixels, 
// have 2*BlurRadius threads sample an extra pixel.
if(groupThreadID.x < gBlurRadius)
{
// Clamp out of bound samples that occur at image borders.
int x = max(dispatchThreadID.x - gBlurRadius, 0);
gCache[groupThreadID.x] = gInput[int2(x, dispatchThreadID.y)];
}
if(groupThreadID.x >= N-gBlurRadius)
{
// Clamp out of bound samples that occur at image borders.
int x = min(dispatchThreadID.x + gBlurRadius, gInput.Length.x-1);
gCache[groupThreadID.x+2*gBlurRadius] = gInput[int2(x, dispatchThreadID.y)];
}


// Clamp out of bound samples that occur at image borders.
gCache[groupThreadID.x+gBlurRadius] = gInput[min(dispatchThreadID.xy, gInput.Length.xy-1)];


// Wait for all threads to finish.
GroupMemoryBarrierWithGroupSync();

//
// Now blur each pixel.
//


float4 blurColor = float4(0, 0, 0, 0);

[unroll]
for(int i = -gBlurRadius; i <= gBlurRadius; ++i)
{
int k = groupThreadID.x + gBlurRadius + i;

blurColor += gWeights[i+gBlurRadius]*gCache[k];
}

gOutput[dispatchThreadID.xy] = blurColor;

}

下图是线程和线程组,线程组和分发的总线程组之间的关系。


          线程组里有若干线程,我们可以通过三维向量的形式指定一个线程组的规格数量,比如前面的计算着色器前需要指定的 [numthreads(N, 1, 1)],一个组分配了N个线程(y,z维度都是1),比如一个256x256的纹理做模糊处理,那么N可以是256,256个线程可以每个对应纹理第一行的256个像素,256个线程同时运行上面的计算着色器 void HorzBlurCS( ),对256个像素做模糊并行计算。如果把第一个线程组的256个线程覆盖处理的第一行256像素看成一个整体“1”,将256x256的纹理数组看成1x256的列数组,一个线程组可以覆盖这个列数组一行 的像素,那么我们需要分发256个线程组,就可以覆盖整个1x256数组的256行。即需要1(256)x256个线程组(ID3D11DeviceContext->Dispatch(1,256,1)),这样256x256个像素全部覆盖到了,每个线程处理一个像素,256x256个线程同时计算,大大提高了计算时间。

        理解了上面的这段话我们依据上图对SV_GroupIndex,SV_DispatchThreadID,SV_GroupThreadID,SV_GroupID解释。

SV_GroupThreadID:一个线程组中用来唯一表示这个线程的ID,这个唯一性只在本组内有效,表示形式为三维向量的形式,如上面的在一个线程组中的(7,5,0)

SV_GroupIndex:一个线程在本线程组中的索引,用整数表示,从0开始,从第一行从左往右累计,然后是第二,三,,,,行,如上面计算出来的57(其实是第58个线程,但对应索引为57,因为起始0占一个)。

SV_GroupID:一个线程组在整个分发的线程组中的ID,在所有线程组中具有唯一性,表现形式也是三维向量形式,如上面的(2,1,0)。

SV_DispatchThreadID:是用来表示一个线程在整个分发的全部线程组中的ID,在所有分发的线程中唯一,表示形式为三维向量形式,计算方式:SV_GroupID x 一个线程组的规格+SV_GroupThreadID。线程组规格为如上图的(10,8,3)或一致的代码中对应的numthreads(x,y,z)。

学习过程中的浅见,如有错误恳请指正。



  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的Unity Compute Shader示例,用于将输入纹理的红色通道值乘以一个常数系数,并将结果输出到目标纹理的绿色通道中: ``` // 声明输入和输出纹理 Texture2D inputTex; RenderTexture outputTex; // 声明Compute Shader ComputeShader computeShader; int kernelID; void Start() { // 获取输入纹理 inputTex = Resources.Load<Texture2D>("InputTexture"); // 创建输出Render Texture outputTex = new RenderTexture(inputTex.width, inputTex.height, 0, RenderTextureFormat.ARGB32); outputTex.enableRandomWrite = true; outputTex.Create(); // 获取Compute Shader computeShader = Resources.Load<ComputeShader>("ComputeShader"); kernelID = computeShader.FindKernel("CSMain"); // 设置纹理参数 computeShader.SetTexture(kernelID, "InputTex", inputTex); computeShader.SetTexture(kernelID, "OutputTex", outputTex); // 设置常数系数参数 float coefficient = 2.0f; computeShader.SetFloat("Coefficient", coefficient); // 计算输出 computeShader.Dispatch(kernelID, inputTex.width / 8, inputTex.height / 8, 1); // 显示输出 GetComponent<Renderer>().material.mainTexture = outputTex; } void OnDestroy() { // 释放Render Texture outputTex.Release(); } ``` 在这个示例中,我们首先声明了输入和输出纹理,以及Compute Shader和内核ID。然后,我们在Start函数中加载输入纹理,创建输出Render Texture,并获取Compute Shader。接下来,我们设置Compute Shader的纹理和常数系数参数,并计算输出。最后,我们将输出纹理设置为场景中的对象材质的主纹理,并在结束时释放输出Render Texture。 要使用Compute Shader,您需要将其保存为.compute文件,并将其放在Unity项目的Assets文件夹中。您还需要将您的Compute Shader添加到资源中,以便您可以在代码中加载它。请注意,Compute Shader只能用于支持Compute Shader 5.0或更高版本的显卡上运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值