GLSL自旋锁永不终止 [英] GLSL Spinlock Never Terminates

查看:89
本文介绍了GLSL自旋锁永不终止的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现GLSL自旋锁,以便能够实现单遍深度剥离.我遇到麻烦了,因为很少使用锁定纹理的示例.我不得不承认,在这里我真的不知道我在做什么,所以为了安全起见,我描述的上下文可能比必要的更多.

I'm trying to implement a GLSL spinlock to be able to implement single-pass depth peeling. I'm having trouble because examples of locking texture use are scarce. I have to admit that I don't really know what I'm doing, here, so I describe probably more context than is necessary, just to be safe.

我写了一个片段程序,该程序实际上什么也不做:

I wrote a fragment program which should do effectively nothing:

#version 420 core

//The lock texture holds either 0 or 1.
//0 means that the texture is available.
//1 means that the texture is locked.  
layout(r32ui) coherent uniform uimage2D img2D_0; //locking texture

layout(RGBA32F) coherent uniform image2D img2D_1; //data texture (currently unused)

void main() {
    ivec2 coord = ivec2(gl_FragCoord.xy);

    //The loop's exchange function swaps out the old value with 1.

    //If the locking texture was 0, 0 will be returned, terminating the loop;
    //the locking texture will now contain 1, indicating that the locking
    //texture is now locked.

    //Conversely, if the locking texture contains 1, then the exchange function
    //will write a 1 (so the texture is still locked), and return 1, indicating
    //that the texture is locked and unavailable.
    while (imageAtomicExchange(img2D_0,coord,1u)==1u);

    //The locking texture is locked.  More code would go here

    //This unlocks the texture.
    imageAtomicExchange(img2D_0,coord,0);
}

创建锁定纹理的方式如下:

The locking texture is created like so:

//data is an array initialized to all 0.
glTexImage2D(GL_TEXTURE_2D,0,GL_R32UI,size_x,size_y,0,GL_RED_INTEGER,GL_UNSIGNED_INT,data);

要执行该算法,我将使用带有彩色RGBA F32渲染附件的FBO并将其启用.我绑定了上面的着色器,然后使用以下代码将锁定纹理传递给img2D_0并将颜色附件传递给img2D_1:

To execute the algorithm, I take a FBO, with a color RGBA F32 render attachment and enable it. I bind the above shader, then pass the locking texture to img2D_0 and the color attachment to img2D_1, using this code:

glBindImageTextureEXT(
    /* 0, 1, respectively */,
    texture_id, 0,GL_FALSE,0, GL_READ_WRITE,
    /* GL_R32UI, GL_RGBA32F, respectively */
);

然后使用VBO渲染对象,并且一些辅助过程显示数据的内容.

The object is then rendered with a VBO, and some secondary passes show the contents of the data.

问题是给定的片段程序会使视频驱动程序崩溃(因为它永远不会终止).我的问题是为什么?纹理被初始化为0,并且我很确定交换函数的逻辑是有效的.我的设置和方法基本正确吗?

The problem is that the fragment program given crashes the video driver (because it never terminates). My question is why? The texture is initialized to 0, and I'm pretty sure my logic for the exchange functions is valid. Is my setup and methodology basically correct?

推荐答案

一个问题是,如果同一线程束中的两个线程命中相同的锁定位置,那么该线程束将死锁,因为一个线程将获得该锁,而另一个线程将循环,warp将继续执行循环线程,这将阻止带有锁的线程取得任何进展.

One issue is that if two threads in the same warp hit the same lock location, that warp will deadlock as one thread will acquire the lock and the other thread will loop, and the warp will continue executing the looping thread, which prevents the thread with the lock from ever making any progress.

修改

根据您修改后的pastebin,我建议如下:

based on your revised pastebin, I would suggest something like:

bool done = false;
while (!done) {
    if ((done = (imageAtomicExchange(img2D_0,coord,1u)==0))) {
        // guarded operations
                 :
        imageStore(img2D_0, coord, 0);
    }
}

这避免了翘曲循环死锁,因为遗漏的线程是那些已经完成其锁定修改的线程.如果只有一个线程可以获取其锁,则该线程将取得进展.

This avoids the warp loop deadlock as the threads left out are those that have already completed their locked modification. If only one thread can acquire its lock, that thread will make progress.

这篇关于GLSL自旋锁永不终止的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆