先看一代没有用原子锁的代码及输出:
#include "vgl.h"
#include "vmath.h"
#include "LoadShaders.h"
#include "vbm.h"
#include <iostream>
using namespace std;
GLuint vbo;
GLuint ProgCompure;
GLuint tex;
void init()
{
glGenBuffers(1, &vbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLint) * 2, NULL, GL_DYNAMIC_COPY);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo);
GLint *tempP = (GLint *)glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_WRITE_ONLY);
for (int i = 0; i < 2; ++i)
{
*(tempP++) = 0;
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
ShaderInfo csi[] = {
{ GL_COMPUTE_SHADER, "Computer.comp" },
{GL_NONE, NULL}
};
ProgCompure = LoadShaders(csi);
}
void display()
{
glUseProgram(ProgCompure);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, vbo);
glDispatchCompute(20, 10, 10);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo);
GLint *tempP = (GLint *)glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
for (int j = 0; j < 2; ++j)
{
cout << *(tempP++) << " ";
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
}
void idle()
{
static unsigned int Time = GetTickCount();
unsigned int timeNow = GetTickCount();
if (timeNow - Time > 15)
{
Time = timeNow;
glutPostRedisplay();
}
else
{
Sleep(30);
}
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE | GLUT_STENCIL);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutInitContextVersion(4, 3);
glutInitWindowSize(400, 400);
glutCreateWindow("Test OpenGL");
if (glewInit() != 0)
{
cout << "Can not initilizate GLEW" << endl;
return 1;
}
init();
glutIdleFunc(idle);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
#version 430 core
layout(local_size_x = 4,local_size_y = 4,local_size_z = 4) in;
layout(binding = 0) buffer outBuf
{
int datas[];
}Out;
void main()
{
Out.datas[1] += 1;
}
计算着色器是执行了20101044*4次,每执行一次,内存变量加1,输出如下,结果显然是错误的。
修改着色器代码,实现一个原子锁:
#version 430 core
layout(local_size_x = 2,local_size_y = 1,local_size_z = 1) in;
layout(binding = 0) buffer outBuf
{
int datas[];
}Out;
void lock()
{
int lock_available;
do{
//0与内存中的值比较,等于0把1写入内存,并返回原先内存中的值0
//不等于0时返回内存中的值
//第一次执行时,内存中原先值为0,执行完毕值变成1,返回0,跳出循环
//第二次执行时,内存中原先值为1,返回1,继续循环,等待值0
lock_available = atomicCompSwap(Out.datas[0],0,1);
}while(lock_available != 0);
}
void unlock()
{
//内存中的值为1,把0写入
atomicCompSwap(Out.datas[0],1,0);
}
void main()
{
lock();
Out.datas[1] += 1;
unlock();
}
遇到问题了。。。。。。只执行一次时没问题,执行两次就会死循环、崩溃。。。。加上volatile也不管用。。
没有找到解决办法,说是个bug,http://ati.cchtml.com/show_bug.cgi?id=579,但这都是好久之前的了。。。。