我正在寻找OpenCL和DirectCompute之间的比较,但我还没有找到任何东西.OpenCL的跨平台优势和支持更广泛的GPU对我来说无关紧要.我只能在Windows上针对DX11 GPU进行编码.假设,每个API的优点和缺点是什么?
我知道之前提出过这个问题,但我正在寻找更多细节.
我对CUDA不感兴趣,因为我不想仅限于Nvidia硬件.
到目前为止,我能找到的唯一教程是在directx11tutorials.com上,这些教程基本上是从现有的样本中推断出来的.有谁知道在哪里可以找到其他教程,或者更好的使用DirectX 11的开源项目?(使用DirectX 11的项目代码的额外点:))
我想知道我可以在GPU上发送的线程/线程组的"网格".我正在使用Direct Compute,所以我将使用该API给出一个具体的例子.例如,如果我调用Dispatch(2,2,2),我理解它总共调度2x2x2 = 8个线程组.但是,如果我调用Dispatch(8,1,1),它还调度8x1x1 = 8个线程组,那有什么区别?有任何性能差异吗?
PS与GPU上的线程相同的问题.在计算(.hlsl)文件中声明的numthreads(2,2,2)和numthreads(8,1,1)之间的区别是什么?
任何帮助,将不胜感激.
在计算着色器(使用Unity)中,我有一个光线投影查找与网格三角形的交叉点.在某些时候,我想返回找到多少个十字路口.
我可以通过标记像素清楚地看到有多少个交叉点,但是如果我只是为计算着色器中的每个交集增加一个全局int(并通过缓冲区返回),那么我得到的数字就没有意义了.我认为这是因为我正在制造竞争条件.
我看到opengl有"原子计数器":https://www.opengl.org/wiki/Atomic_Counter,这看起来就像我在这种情况下需要的那样.我没有在Unity和DirectCompute文档中找到这样的功能.有没有办法做到这一点?
我可以创建一个appendBuffer,但它看起来很傻,因为我确实只需要返回一个int.
我刚刚开始在DirectX 11中使用Compute着色器阶段,并且在Compute着色器中写入输出资源时遇到了一些不需要的行为.我似乎只得到零作为输出,据我的理解,这意味着已在Compute着色器中执行了越界读取.(越界写入导致无操作)
输入资源
首先,我创建一个ID3D11Buffer*输入数据.在创建用于输入Compute着色器阶段的SRV时,它将作为资源传递.如果输入数据永远不会改变,那么我们可以ID3D11Buffer*在创建SRV之后释放该对象,因为SRV将充当资源的句柄.
但是,我想每帧更新输入数据,所以我只是将缓冲区留给我处理以进行映射.
// Create a buffer to be bound as Compute Shader input (D3D11_BIND_SHADER_RESOURCE).
D3D11_BUFFER_DESC constantDataDesc;
constantDataDesc.Usage = D3D11_USAGE_DYNAMIC;
constantDataDesc.ByteWidth = sizeof(ParticleConstantData) * NUM_PARTICLES;
constantDataDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
constantDataDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
constantDataDesc.StructureByteStride = sizeof(ParticleConstantData);
constantDataDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
hr = device->CreateBuffer ( &constantDataDesc, 0, &mInputBuffer );
Run Code Online (Sandbox Code Playgroud)
使用新创建的缓冲区作为资源创建SRV
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
srvDesc.BufferEx.FirstElement = 0;
srvDesc.BufferEx.Flags = 0;
srvDesc.BufferEx.NumElements = NUM_PARTICLES;
hr = device->CreateShaderResourceView( mInputBuffer, &srvDesc, &mInputView );
Run Code Online (Sandbox Code Playgroud)
输出资源
现在我需要为Compute着色器创建一个要写入的资源.我还将创建一个系统内存版本的缓冲区来读取.我将使用ID3D11DeviceContext …
我是DirectCompute技术的新手,并且一直试图从msdn网站上的文档中学习,至少可以说是密集的.
我想制作一个基本的hlsl文件,它接受一个4x4矩阵和一个4xN矩阵并返回相乘的结果.但是花了一些时间玩代码之后,我发现了一些我不理解的奇怪的东西 - 主要是我传递的线程如何处理缓冲区和输出数据.
通过所有这些示例,我传入两个16浮点缓冲区并获得一个16浮点缓冲区,然后使用4x1x1分组调度 - 我可以向您显示代码,但老实说,我还不知道什么可以帮助您.如果您想看到我的C++代码的一部分,请告诉我.
使用以下代码:
StructuredBuffer<float4x4> base_matrix : register(t0); // byteWidth = 64
StructuredBuffer<float4> extended_matrix : register(t1); // byteWidth = 64
RWStructuredBuffer<float4> BufferOut : register(u0); // byteWidth = 64, zeroed out before reading from the GPU
[numthreads(1, 1, 1)]
void CSMain( uint3 DTid : SV_DispatchThreadID )
{
BufferOut[DTid.x].x = 1;
}
Run Code Online (Sandbox Code Playgroud)
我得到以下值:
1.000 0.000 0.000 0.000
1.000 0.000 0.000 0.000
1.000 0.000 0.000 0.000
1.000 0.000 0.000 0.000
Run Code Online (Sandbox Code Playgroud)
这对我来说很有意义 - 缓冲区被解析为4个线程,每个线程执行1个float4分组.
使用以下代码:
StructuredBuffer<float4x4> base_matrix : register(t0); // …Run Code Online (Sandbox Code Playgroud) 我最近一直在使用计算着色器,我正在尝试确定设置[numthreads(x,y,z)]和调度调用的最佳方法.我的演示窗口是800x600,我每像素启动1个线程.我正在进行2D纹理修改 - 没有太重.
我的第一次尝试是指定
[numthreads(32,32,1)]
Run Code Online (Sandbox Code Playgroud)
我的Dispatch()调用总是如此
Dispatch(ceil(screenWidth/numThreads.x),ceil(screenHeight/numThreads.y),1)
Run Code Online (Sandbox Code Playgroud)
因此,对于第一个实例
Dispatch(25,19,1)
Run Code Online (Sandbox Code Playgroud)
这个速度为25-26 fps.然后我减少到[numthreads(4,4,1)],运行速度为16 fps.将它增加到[numthreads(16,16,1)]开始了大约30 fps的良好结果.使用Y线程组编号[numthreads(16,8,1)]进行操作,设法将其推送到32 fps.
我的问题是有没有一种最佳的方法来确定线程数,这样我可以最有效地利用GPU,或者只是好的试验和错误?
我知道C++ AMP由支持DirectX 11的GPU加速.
但是,我的问题是,如果编译的C++ AMP程序在没有DirectX 11兼容GPU的机器上运行,会发生什么?
是否可以通过DirectCompute的某些软件实现来模拟?
它是否在CPU上执行(可能使用SSE样式指令)?
或者,它是否无法执行?
我尝试在计算着色器中实现自旋锁。但我的实现似乎没有锁定任何东西。
以下是我实现自旋锁的方法:
void LockAcquire()
{
uint Value = 1;
[allow_uav_condition]
while (Value) {
InterlockedCompareExchange(DataOutBuffer[0].Lock, 0, 1, Value);
};
}
void LockRelease()
{
uint Value;
InterlockedExchange(DataOutBuffer[0].Lock, 0, Value);
}
Run Code Online (Sandbox Code Playgroud)
背景:我需要一个自旋锁,因为我必须计算大型二维数组中的数据总和。总和是两倍。使用单线程和双循环计算总和会产生正确的结果。即使在计算总和时引入自旋锁以避免冲突,使用多线程计算总和也会产生错误的结果。
我无法使用 InterLockedAdd,因为总和不适合 32 位整数,而且我使用的是着色器模型 5(编译器 47)。
这是单线程版本,产生正确的结果:
[numthreads(1, 1, 1)]
void CSGrayAutoComputeSumSqr(
uint3 Gid : SV_GroupID,
uint3 DTid : SV_DispatchThreadID, // Coordinates in RawImage window
uint3 GTid : SV_GroupThreadID,
uint GI : SV_GroupIndex)
{
if ((DTid.x == 0) && (DTid.y == 0)) {
uint2 XY;
int Mean = (int)round(DataOutBuffer[0].GrayAutoResultMean);
for (XY.x …Run Code Online (Sandbox Code Playgroud) 我刚开始学习DirectX编程,使用F#和SharpDX作为.NET包装器.作为测试用例,我渲染了Mandelbrot集.使用2个计算着色器完成计算.
第一个着色器计算每个像素的深度(函数"CalcMandel"),结果存储在RWStructuredBuffer中.这种计算需要大量的单次或双次乘法,但它在我的GPU(AMD 7790)上的速度非常快."CalcMandel"具有该属性
[numthreads(16, 16, 1)]
Run Code Online (Sandbox Code Playgroud)
并通过发送
context.Dispatch (imageWidth / 16, imageHeight / 16, 1)
Run Code Online (Sandbox Code Playgroud)
这里没有问题 - "核心"Mandelbrot集的1000 x 800像素图像以超过1000 fps的速度运行(在GPU上使用单精度).
第二个着色器几乎没有做任何事情:它计算先前计算的最小值,最大值和平均值(函数"CalcMinMax")."CalcMinMax"具有该属性
[numthreads(1, 1, 1)]
Run Code Online (Sandbox Code Playgroud)
并被称为通过
context.Dispatch (1,1,1)
Run Code Online (Sandbox Code Playgroud)
对于当时给定的图像大小,单个GPU线程必须遍历超过800.000个整数的缓冲区以计算最小值,最大值和平均值.我使用单个线程,因为我不知道如何以并行方式实现此计算.
问题:"CalcMinMax"非常慢:帧速率从1000 fps下降到5 fps!
我的问题:这里有什么问题?我使用了错误的设置/参数(numthreads)吗?如何加快min-max计算?
我的想法:我的第一个假设是访问RWBuffer可能会很慢 - 事实并非如此.当我用常量替换缓冲区访问时,帧速率没有增加.
我的GPU有appr.900个着色器核心并使用数千个线程来计算Mandelbrot集合,而"CalcMinMax"仅使用一个线程.然而,我仍然不明白为什么事情变得如此缓慢.
我很感激任何建议!
================================================
// HLSL CONTENT(省略Mandelbrot集计算):
cbuffer cbCSMandel : register( b0 )
{
double a0, b0, da, db;
double ja0, jb0;
int max_iterations;
bool julia; int cycle;
int width; int height;
double colorFactor;
int algoIndex;
int step;
};
struct statistics
{
int minDepth;
int …Run Code Online (Sandbox Code Playgroud) 我有以下缓冲区:
RWTexture2D<float4> Output : register(u0);
Run Code Online (Sandbox Code Playgroud)
计算着色器使用此缓冲区来渲染计算图像。要在该纹理中写入像素,我只需使用类似于以下的代码:
Output[XY] = SomeFunctionReturningFloat4(SomeArgument);
Run Code Online (Sandbox Code Playgroud)
这工作得很好,我的计算图像正确地呈现在屏幕上。
现在,在计算着色器的某个阶段,我想读回已经计算的像素并再次处理它。
Output[XY] = SomeOtherFunctionReturningFloat4(Output[XY]);
Run Code Online (Sandbox Code Playgroud)
编译器返回错误:
error X3676: typed UAV loads are only allowed for single-component 32-bit element types
Run Code Online (Sandbox Code Playgroud)
任何帮助表示赞赏。
directcompute ×11
directx ×6
hlsl ×5
c++ ×4
directx-11 ×4
c++-amp ×1
direct3d ×1
dispatch ×1
gpgpu ×1
gpu ×1
opencl ×1
spinlock ×1
threadgroup ×1