我知道OpenCL可以控制GPU的内存架构,因此可以实现更好的优化,但是,除此之外,我们可以使用Compute Shaders进行矢量运算(加法,乘法,反演等)吗?
我试图通过计算着色器在OpenGL中做一些光线跟踪,我遇到了一个奇怪的问题.目前我只想显示没有任何阴影的球体.我的计算着色器为每个像素启动一条光线,如下所示:
#version 430
struct Sphere{
vec4 position;
float radius;
};
struct Ray{
vec3 origin;
vec3 dir;
};
uniform image2D outputTexture;
uniform uint width;
uniform uint height;
float hitSphere(Ray r, Sphere s){
float s_vv = dot(r.dir, r.dir);
float s_ov = dot(r.origin, r.dir);
float s_mv = dot(s.position.xyz, r.dir);
float s_mm = dot(s.position.xyz, s.position.xyz);
float s_mo = dot(s.position.xyz, r.origin);
float s_oo = dot(r.origin, r.origin);
float d = s_ov*s_ov-2*s_ov*s_mv+s_mv*s_mv-s_vv*(s_mm-2*s_mo*s_oo-s.radius*s.radius);
if(d < 0){
return -1.0f;
} else if(d == 0){
return (s_mv-s_ov)/s_vv;
} else { …
Run Code Online (Sandbox Code Playgroud) 我想知道memoryBarrierShared的用处.
实际上,当我查看屏障功能的文档时:我读到:
对于计算着色器中任何给定的屏障静态实例,单个工作组中的所有调用必须在允许任何调用继续超出它之前输入.这确保了在调用相同的屏障静态实例之后,其他调用可以安全地读取在给定静态屏障实例之前由一次调用写入的值.因为调用可能在这些屏障调用之间以未定义的顺序执行,所以在许多情况下,每顶点或每个补丁输出变量或任何共享变量的值将是未定义的.
因此,如果我们可以在使用障碍后安全地读取值,为什么我们会在一些代码中看到
memoryBarrierShared();
barrier();
Run Code Online (Sandbox Code Playgroud)
或者像错误的东西
barrier();
memoryBarrierShared();
Run Code Online (Sandbox Code Playgroud)
所以,我的问题是:如果使用障碍足够,memoryBarrier {Shared,...}的目的是什么?
对于memoryBarrierBuffer/Image我可以理解,如果我们使用多个阶段,但对于共享,我不知道...
我目前正在使用UBO在OpenGL 4.3中进行渲染,以便在GPU上存储我的所有常量数据.(像材料描述,矩阵......).它的工作原理是小尺寸的UBO(在我的实现上为64kB)迫使我多次切换缓冲区以减慢渲染速度,我正在寻找类似的存储几MB的方法.
经过一番研究后,我发现SSBO恰好允许这样做,但也有不必要的"功能":它们可以从着色器中写入,并且读取速度可能较慢.
是否有比SSBO更好的解决方案为着色器提供大块数据?我觉得我错过了什么,为什么UBO限制在几KB,而存在一个更灵活的解决方案,能够处理更多的数据?如果着色器存储缓冲区是我正在寻找的,有没有办法确保它们不被着色器修改?
在计算着色器(使用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 …
我正在尝试在 Unity 的计算着色器中复制我的工作 2d 流体着色器玩具,希望尽快将其移至 3D。当我以同样的方式复制算法时,我得到了一些非常奇怪的行为(在我拍摄的这个视频中看到)。我试图调试我能想到的一切,但我不明白为什么它们不一样。我正在可视化此捕获中的矢量矩阵(与查看我的着色玩具时按 Space 相同)。
我用我用来执行驱动速度矩阵的 Navier-Stokes 方程的代码创建了一个pastebin。模拟的核心归结为:
float4 S(RWTexture2D<float4> target, uint2 id)
{
return target[(id.xy + resolution)%resolution];
}
void Fluid(RWTexture2D<float4> target, uint2 id, float2 offset, float4 values, inout float2 velocity, inout float pressure, inout float divergence, inout float neighbors)
{
float2 v = S(target, id.xy + offset);
float4 s = S(target, id.xy + offset.xy - v);
float2 o= normalize(offset);
velocity += o * (s.w …
Run Code Online (Sandbox Code Playgroud) 在 Apple 2018 年 WWDC 会议“Metal Shader 调试和分析”中,演讲者详细介绍了当时新的 Metal 调试工作流程。然而,他们在演示中并没有对计算着色器进行太多讨论,只是简单地提到了调试计算内核时出现的选项,并重点关注顶点和片段着色器调试。
当我们只将工作发送到 GPU 一次而不是每一帧时,我们如何调试计算着色器?请引导我参加您推荐的涵盖此主题和MTLCaptureManager
.
更新:此问题已解决,您可以在此处找到更多详细信息:https ://stackoverflow.com/a/64405505/1889253
之前曾提出过类似的问题,但该问题最初集中在使用多个命令缓冲区,并触发跨不同线程的提交以实现着色器的并行执行。大多数答案表明解决方案是使用多个队列。使用多个队列似乎也是各种博客文章和 Khronos 论坛答案的共识。我已经尝试了跨多个队列运行着色器执行的这些建议,但无法看到并行执行,所以我想问一下我可能做错了什么。正如所建议的,这个问题包括提交到多个队列的多个计算着色器的可运行代码,这希望对其他想要做同样事情的人有用(一旦这个问题得到解决)。
当前的实现是在这个 pull request/branch 中,但是我将介绍 Vulkan 的主要具体点,以确保只需要 Vulkan 知识来回答这个问题。还值得一提的是,当前的用例专门针对计算队列和计算着色器,而不是图形或传输队列(尽管跨这些队列实现并行性的见解/经验仍然非常有用,并且很可能也能找到答案)。
更具体地说,我有以下内容:
有几点在上面的示例中不可见但很重要:
基准测试中使用的测试可以在此处找到,但是需要了解的唯一关键事项是:
运行测试时,我们首先在同一队列上运行一组“同步”着色器执行(数量是可变的,但我们使用 6-16 进行了测试,后者是队列的最大数量)。然后我们以异步方式运行它们,运行所有它们并 evalAwait 直到它们完成。比较两种方法的结果时间时,即使它们运行在不同的计算队列上,它们也花费相同的时间。
我的问题是:
我尝试在各种网站上查找此内容,包括有关 DirectX 11 计算着色器类型的 MS Docs;但我还没有发现任何提到这些缓冲区类型的性能差异的内容。
它们的性能完全相同吗?
如果不是,在不同场景中使用每种方法的最佳方式是什么?
compute-shader ×10
opengl ×4
gpgpu ×3
c++ ×2
directx-11 ×2
glsl ×2
gpu ×2
c ×1
hlsl ×1
metal ×1
opencl ×1
performance ×1
raytracing ×1
shader ×1
swift ×1
vulkan ×1
xcode ×1