我得到了一个与新计算着色器相关的问题.我目前正在研究粒子系统.我将所有粒子存储在着色器存储缓冲区中,以便在计算着色器中访问它们.然后我派遣一个一维工作组.
#define WORK_GROUP_SIZE 128
_shaderManager->useProgram("computeProg");
glDispatchCompute((_numParticles/WORK_GROUP_SIZE), 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
Run Code Online (Sandbox Code Playgroud)
我的计算着色器:
#version 430
struct particle{
vec4 currentPos;
vec4 oldPos;
};
layout(std430, binding=0) buffer particles{
struct particle p[];
};
layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in;
void main(){
uint gid = gl_GlobalInvocationID.x;
p[gid].currentPos.x += 100;
}
Run Code Online (Sandbox Code Playgroud)
但不知何故并非所有粒子都受到影响.我这样做就像在这个例子中一样,但它不起作用.http://education.siggraph.org/media/conference/S2012_Materials/ComputeShader_6pp.pdf
编辑:
在我调用glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT)后,我继续这样:
_shaderManager->useProgram("shaderProg");
glBindBuffer(GL_ARRAY_BUFFER, shaderStorageBufferID);
glVertexPointer(4,GL_FLOAT,sizeof(glm::vec4), (void*)0);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_POINTS, 0, _numParticles);
glDisableClientState(GL_VERTEX_ARRAY);
Run Code Online (Sandbox Code Playgroud)
那么在这种情况下哪个位适合使用?
我正在用 iOS 版 Metal 制作一个小游戏。在我的一个内核着色器中(在我的 .metal 文件中)。我正在定义一个结构来保存游戏部分的一些元数据。
该结构如下所示:
struct ColorSetup {
float4 color;
float4 degradationColor;
float degradationRate;
};
Run Code Online (Sandbox Code Playgroud)
这工作得很好,但是当我尝试向结构中添加更多字段时,例如:
struct ColorSetup {
float4 color;
float4 degradationColor;
float4 threshholdColor;
float degradationRate;
};
Run Code Online (Sandbox Code Playgroud)
该代码行为不当,似乎无法使用某些字段。此时新字段尚未被使用。我的第一个想法是它与结构的内存对齐有关。我的印象是编译器会添加正确的填充,但仍然继续尝试自己正确调整结构的大小(按降序排列字段并将结构对齐到 48 和 64 字节),但没有任何成功。我还尝试使用打包数据类型来避免对齐问题,但仍然没有成功。
我知道逻辑是正确的,因为我在不使用结构的情况下编写了相同的逻辑,然后将其移植到使用结构来保存具有完全相同行为的数据。但此时添加任何字段都会破坏它。此外,保留原始结构但使用打包数据类型也会以类似的方式破坏它。
struct ColorSetup {
packed_float4 color;
packed_float4 degradationColor;
float degradationRate;
};
Run Code Online (Sandbox Code Playgroud)
所以这看起来肯定是一个内存布局问题,但我不清楚如何在不解决该问题的情况下解决它。
我可以尝试什么想法或想法吗?
编辑:
数据不会通过 MTLBuffer 传递到我的计算着色器中,而是简单地在 .metal 文件中内联的常量内存空间中定义,如下所示:
constant ColorSetup redColor = {
.color = red,
.degradationColor = white,
.degradationRate = 0.0035
};
Run Code Online (Sandbox Code Playgroud)
编辑2:
尝试描述更多发现以及代码实际执行的操作。
所讨论的中断函数是一种根据该结构中提供的值来淡化颜色的方法。
float4 degrade(float4 color, ColorSetup colorSetup, ColorLimit colorLimit) …Run Code Online (Sandbox Code Playgroud) 我有我的体素化场景的颜色、法线和其他数据的 3D 纹理,因为其中一些数据不能只是平均,我需要自己计算 mip 级别。3D 纹理大小为 (128+64) x 128 x 128,额外的 64 x 128 x 128 用于 mip 级别。
因此,当我取第一个 mip 级别,即 (0, 0, 0) 大小为 128 x 128 x 128 并将体素复制到第二级时,即 (128, 0, 0) 数据出现在那里,但是一旦我将 (128, 0, 0) 的第二级复制到 (128, 0, 64) 的第三级,数据就不会出现在第三级。
着色器代码:
#version 450 core
layout (local_size_x = 1,
local_size_y = 1,
local_size_z = 1) in;
layout (location = 0) uniform unsigned int resolution;
layout (binding = 0, rgba32f) uniform image3D voxel_texture;
void main()
{
ivec3 index …Run Code Online (Sandbox Code Playgroud) 任何人都知道在金属内核中使用随机浮点数计算缓冲区平均值的正确方法吗?
在计算命令编码器上分派工作:
threadsPerGroup = MTLSizeMake(1, 1, inputTexture.arrayLength);
numThreadGroups = MTLSizeMake(1, 1, inputTexture.arrayLength / threadsPerGroup.depth);
[commandEncoder dispatchThreadgroups:numThreadGroups
threadsPerThreadgroup:threadsPerGroup];
Run Code Online (Sandbox Code Playgroud)
内核代码:
kernel void mean(texture2d_array<float, access::read> inTex [[ texture(0) ]],
device float *means [[ buffer(1) ]],
uint3 id [[ thread_position_in_grid ]]) {
if (id.x == 0 && id.y == 0) {
float mean = 0.0;
for (uint i = 0; i < inTex.get_width(); ++i) {
for (uint j = 0; j < inTex.get_height(); ++j) {
mean += inTex.read(uint2(i, j), id.z)[0];
}
}
float textureArea …Run Code Online (Sandbox Code Playgroud) 我阅读了一些关于如何在opengl 4.3计算着色器中实现光线跟踪器的教程,这让我想到了一段时间以来困扰我的事情.GPU究竟如何处理实现类似内容所需的大量随机访问读取?每个流处理器都有自己的数据副本吗?似乎系统会因内存访问而变得非常拥挤,但这只是我自己的,可能是不正确的直觉.
我正在编写一个框架,需要提供一些在 image2D 类型上定义的函数。
但要做到这一点似乎有点困难,而且我找不到任何有关将 an 传递image2D给函数的文档。
这是我的问题的一个最小示例:
#version 440
layout (local_size_x = 16, local_size_y = 16) in;
struct Test
{
bool empty;
};
// Version 1:
// fails with 0:11: '' : imageLoad function cannot access the image defined
// without layout format qualifier or with writeonly memory qualifier
float kernel1(image2D x, Test arg1){
return imageLoad(x, ivec2(1, 1)).x;
}
// Version 2:
// fails with ERROR: 0:16: 'Test' : syntax error syntax error
// doesn't fail without the …Run Code Online (Sandbox Code Playgroud) 简短的问题
为什么我从带有浮动的Metal 2.1中得到未定义的行为simd_min并simd_max在其中起作用?
更新:似乎仅在Radeon Pro 560X GPU上发生,而在Intel UHD Graphics 630上则没有。
背景
根据金属着色语言指南第5.14节,simd_min和simd_max功能被支持以便共同标量或矢量,整数或浮点类型。
对于simd_max,规范指出:
T simd_max(T data)返回SIMD组中所有活动线程中数据的最大值,并将结果广播到SIMD组中所有活动线程。
测试用例
为了测试这一点,我正在执行以下测试内核,其输入缓冲区为0..100范围内的128个随机浮点数:
kernel void simdMaxDebugKernel(
const device float *buffer [[ buffer(0) ]],
device float *output [[ buffer(1) ]],
uint id [[ thread_position_in_grid ]])
{
output[id] = simd_max(buffer[id]);
}
Run Code Online (Sandbox Code Playgroud)
通过检查,将128值的缓冲区分为两个64值的SIMD组。因此,我希望输出中的前64个值将分别设置为第一个和最后一个SIMD组的最大值。
检测结果
我得到了一些意外的结果:
inputs [simd_float1] 128 values
[0] Float 94.3006362
[1] Float 98.1107177
[2] Float 85.3725891
[3] Float 45.1457863
...
[63] Float 36.5486336 …Run Code Online (Sandbox Code Playgroud) 我想使用计算着色器来修改我的顶点,然后将它们传递给顶点着色器.我找不到任何这样的例子或解释,除了这里似乎提到:金属模拟使用计算着色器的几何着色器.这对我没有帮助,因为它没有解释它的CPU部分.
我已经看过许多在计算着色器中读取和写入纹理缓冲区的示例,但我需要读取和修改顶点缓冲区,其中包含带法线的自定义顶点结构,并由MDLMesh创建.我将永远感谢一些示例代码!
背景
我真正想要实现的是能够修改GPU上的顶点法线.另一种选择是,如果我可以从顶点着色器访问整个三角形,就像在链接的答案中一样.出于某种原因,我只能使用stage_in属性访问单个顶点.在这种特殊情况下,使用整个缓冲区对我来说不起作用,这可能与使用Model I/O和MDLMesh提供的网格有关.当我手动创建顶点时,我能够访问顶点缓冲区数组.话虽如此,使用该解决方案,我将不得不为每个三角形计算新的顶点法线向量三次,这似乎是浪费,并且无论如何我希望能够将计算着色器应用于顶点缓冲区!
假设我想使用计算着色器来运行 Kernel_X,线程尺寸为 (8, 1, 1)。
我可以将其设置为:
在脚本中:
Shader.Dispatch(Kernel_X, 8, 1, 1);
Run Code Online (Sandbox Code Playgroud)
在着色器中:
[numthreads(1,1,1)]
void Kernel_X(uint id : SV_DispatchThreadID) { ... }
Run Code Online (Sandbox Code Playgroud)
或者我可以这样设置:
在脚本中:
Shader.Dispatch(Kernel_X, 1, 1, 1);
Run Code Online (Sandbox Code Playgroud)
在着色器中:
[numthreads(8,1,1)]
void Kernel_X(uint id : SV_DispatchThreadID) { ... }
Run Code Online (Sandbox Code Playgroud)
据我所知,在这段代码的末尾,维度将是 (8, 1, 1); 然而,我想知道交换数字实际上有何不同。我的猜测是,运行 Dispatch (Kernel_X, 8, 1, 1) 会“运行”1x1x1 内核 8 次,而运行 numthreads(8,1,1) 将运行 8x1x1 内核一次。
我正在尝试设置和执行计算内核,并将其输出提交给MTKView进行绘制。但是我得到以下崩溃:
-[MTLDebugCommandBuffer computeCommandEncoder]:889: failed assertion `encoding in progress'
Run Code Online (Sandbox Code Playgroud)
以下代码有什么问题?使用同一commandBuffer是否不支持将计算着色器的输出馈送到渲染管道?
func computeKernel(_ texture:MTLTexture, commandBuffer:MTLCommandBuffer) {
let computeEncoder = commandBuffer.makeComputeCommandEncoder()
computeEncoder?.setComputePipelineState(computePipelineState!)
computeEncoder?.setTexture(texture, index: 0)
computeEncoder?.setTexture(texture, index: 1)
computeEncoder?.dispatchThreadgroups(threadgroupCount, threadsPerThreadgroup: threadgroupSize)
computeEncoder?.endEncoding()
/*
commandBuffer.commit()
commandBuffer.waitUntilCompleted()
*/
}
override func draw(_ rect: CGRect) {
guard let drawable = currentDrawable,
let currentRenderPassDescriptor = currentRenderPassDescriptor
else {
return
}
// Set up command buffer and encoder
guard let commandQueue = commandQueue else {
print("Failed to create Metal command queue")
return
}
guard let commandBuffer = commandQueue.makeCommandBuffer() …Run Code Online (Sandbox Code Playgroud)