- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试在 GLSL 中实现自旋锁。它将在 Voxel Cone Tracing 的上下文中使用。我尝试将存储锁定状态的信息移动到允许原子操作的单独 3D 纹理。为了不浪费内存,我不使用完整的整数来存储锁定状态,而是只使用一个位。问题是在不限制最大迭代次数的情况下,循环永远不会终止。我在 C# 中实现了完全相同的机制,创建了很多在共享资源上工作的任务,并且在那里工作得很好。Euro Par 2017:并行处理第 274 页(可在 Google 上找到)一书提到了在 SIMT 设备上使用锁时可能需要注意的事项。我认为代码应该绕过这些警告。
有问题的 GLSL 代码:
void imageAtomicRGBA8Avg(layout(RGBA8) volatile image3D image, layout(r32ui) volatile uimage3D lockImage,
ivec3 coords, vec4 value)
{
ivec3 lockCoords = coords;
uint bit = 1<<(lockCoords.z & (4)); //1<<(coord.z % 32)
lockCoords.z = lockCoords.z >> 5; //Division by 32
uint oldValue = 0;
//int counter=0;
bool goOn = true;
while (goOn /*&& counter < 10000*/)
//while(true)
{
uint newValue = oldValue | bit;
uint result = imageAtomicCompSwap(lockImage, lockCoords, oldValue, newValue);
//Writing is allowed if could write our value and if the bit indicating the lock is not already set
if (result == oldValue && (result & bit) == 0)
{
vec4 rval = imageLoad(image, coords);
rval.rgb = (rval.rgb * rval.a); // Denormalize
vec4 curValF = rval + value; // Add
curValF.rgb /= curValF.a; // Renormalize
imageStore(image, coords, curValF);
//Release the lock and set the flag such that the loops terminate
bit = ~bit;
oldValue = 0;
while (goOn)
{
newValue = oldValue & bit;
result = imageAtomicCompSwap(lockImage, lockCoords, oldValue, newValue);
if (result == oldValue)
goOn = false; //break;
oldValue = result;
}
//break;
}
oldValue = result;
//++counter;
}
}
具有相同功能的工作 C# 代码
public static void Test()
{
int buffer = 0;
int[] resource = new int[2];
Action testA = delegate ()
{
for (int i = 0; i < 100000; ++i)
imageAtomicRGBA8Avg(ref buffer, 1, resource);
};
Action testB = delegate ()
{
for (int i = 0; i < 100000; ++i)
imageAtomicRGBA8Avg(ref buffer, 2, resource);
};
Task[] tA = new Task[100];
Task[] tB = new Task[100];
for (int i = 0; i < tA.Length; ++i)
{
tA[i] = new Task(testA);
tA[i].Start();
tB[i] = new Task(testB);
tB[i].Start();
}
for (int i = 0; i < tA.Length; ++i)
tA[i].Wait();
for (int i = 0; i < tB.Length; ++i)
tB[i].Wait();
}
public static void imageAtomicRGBA8Avg(ref int lockImage, int bit, int[] resource)
{
int oldValue = 0;
int counter = 0;
bool goOn = true;
while (goOn /*&& counter < 10000*/)
{
int newValue = oldValue | bit;
int result = Interlocked.CompareExchange(ref lockImage, newValue, oldValue); //imageAtomicCompSwap(lockImage, lockCoords, oldValue, newValue);
if (result == oldValue && (result & bit) == 0)
{
//Now we hold the lock and can write safely
resource[bit - 1]++;
bit = ~bit;
oldValue = 0;
while (goOn)
{
newValue = oldValue & bit;
result = Interlocked.CompareExchange(ref lockImage, newValue, oldValue); //imageAtomicCompSwap(lockImage, lockCoords, oldValue, newValue);
if (result == oldValue)
goOn = false; //break;
oldValue = result;
}
//break;
}
oldValue = result;
++counter;
}
}
锁定机制的工作方式应该与 Cyril Crassin 和 Simon Green 在 OpenGL Insigts 第 22 章使用 GPU 硬件光栅器进行基于八叉树的稀疏体素化中描述的机制完全相同。他们只使用整数纹理来存储我想避免的每个体素的颜色,因为这会使 Mip 映射和其他事情复杂化。我希望帖子是可以理解的,我觉得它已经变得太长了......
为什么 GLSL 实现没有终止?
最佳答案
如果我理解得很好,你可以使用 lockImage
作为线程锁:确定坐标处的确定值意味着“只有此着色器实例可以执行下一步操作”(在该坐标处更改其他图像中的数据)。正确的。
关键是imageAtomicCompSwap
.我们知道它完成了这项工作,因为它能够存储确定的值(假设 0
表示“免费”,1
表示“锁定”)。我们知道它是因为返回值(原始值)是“免费的”(即交换操作发生了):
bool goOn = true;
unit oldValue = 0; //free
uint newValue = 1; //locked
//Wait for other shader instance to free the simulated lock
while ( goON )
{
uint result = imageAtomicCompSwap(lockImage, lockCoords, oldValue, newValue);
if ( result == oldValue ) //it was free, now it's locked
{
//Just this shader instance executes next lines now.
//Other instances will find a "locked" value in 'lockImage' and will wait
...
//release our simulated lock
imageAtomicCompSwap(lockImage, lockCoords, newValue, oldValue);
goOn = false;
}
}
我认为你的代码永远循环,因为你用 bit
复杂化了你的生活var 并错误地使用了 oldVale
和 newValue
编辑:
如果 lockImage
的 'z'是 32 的倍数(只是一个理解的提示,不需要精确的倍数),您尝试将 32 个体素锁打包成一个整数。我们称这个整数为32C
.
着色器实例(“SI”)可能想要更改其在 32C
中的位,锁定或解锁。因此,您必须 (A) 获取当前值并且 (B) 仅更改您的位。
其他 SI 正在尝试更改其位。有些位相同,有些位不同。
两次调用 imageAtomicCompSwap
之间在一个 SI 中,其他 SI 可能改变的不是你的位(它被锁定了,不是吗?),而是同一 32C
中的其他位。值(value)。你不知道哪个是当前值,你只知道你的位。因此,您在 imageAtomicCompSwap
中没有任何东西(或旧的错误值)可以比较称呼。它可能无法设置新值。几个 SI 失败会导致“死锁”并且 while 循环永远不会结束。
您尝试通过 oldValue = result
避免使用旧的错误值并再次尝试 imageAtomicCompSwap
.这是我之前写的(A)-(B)。但是在 (A) 和 (B) 之间还有其他 SI 可能已经改变了 result= 32C
值(value),毁了你的想法。
想法:您可以使用我的简单方法(仅 0
或 1
中的值 lockImage
),无需 bits
事物。结果是 lockImage
更小。但是所有着色器实例都试图更新 32 个 image
中的任何与 32C
相关的坐标lockImage
中的值将等到锁定该值的人释放它。
使用另一个lockImage2
只是为了锁定-解锁 32C
有点更新的值(value),似乎旋转太多。
关于c# - GLSL 自旋锁永远阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46632261/
我试图让我的 SCNNode 自动水平旋转。这是我到目前为止的代码: box.scale = SCNVector3(x: 0.26, y: 0.26, z: 0.26) box.position =
我试图让我的 SCNNode 自动水平旋转。这是我到目前为止的代码: box.scale = SCNVector3(x: 0.26, y: 0.26, z: 0.26) box.position =
我试图让 unicode 三 Angular 形 (▵) 在页面加载时和用户将鼠标悬停在跨度上时旋转 360 度。我已经设置了一个 jsFiddle解释我想要什么。 ULTR▵ 我对 CS
我是一名优秀的程序员,十分优秀!