Open GL ES 3.1 计算着色器的最小工作示例
Minimal working example of compute shader for Open GL ES 3.1
我想使用 Open GL ES 进行通用计算。
所以我到目前为止的理解是我需要创建一个 SSBO 并将我的数据传输到那里,将缓冲区绑定到着色器中的特殊点,运行 着色器并取回数据。
到目前为止我遇到了 3 个问题:
- 代码未编译:错误:未定义对 'glDispatchCompute' 的引用。我已经包含了GLES3/gl31.h,功能就在那里。来自 open gl es 的其他功能已正确导入;
- 我不明白如何从缓冲区取回数据;
- 代码中可能还有其他一些错误。我还没有在网上找到 Open GL ES 3.1 计算着色器代码的示例,所以我尝试将常用的 Open GL ES 代码(我是新手)和上面 link 中的计算着色器代码结合起来。
此外,我正在编写此代码以从 Android 应用程序启动,因此从那方面可能会出现一些问题。我的最终任务是在着色器和 return 到 Android 应用程序上计算一些东西。现在它只有 returns 用于调试的固定字符串。
这是我的代码:
#include <jni.h>
#include <string>
#include <GLES3/gl31.h>
//#include <GLES/egl.h>
static const char COMPUTE_SHADER[] =
"#version 310 es\n"
"layout(local_size_x = 128) in;\n"
"layout(std430) buffer;\n"
"layout(binding = 0) writeonly buffer Output {\n"
"vec4 elements[];\n"
"} output_data;\n"
"layout(binding = 1) readonly buffer Input0 {\n"
"vec4 elements[];\n"
"} input_data0;\n"
"void main()\n"
"{\n"
" uint ident = gl_GlobalInvocationID.x;\n"
"output_data.elements[ident] = input_data0.elements[ident] * input_data0.elements[ident];\n"
"}";
GLuint LoadShader(const char *shaderSrc)
{
GLuint shader;
GLint compiled;
// Create the shader object
shader = glCreateShader(GL_COMPUTE_SHADER);
if(shader == 0)
return shader;
// Load the shader source
glShaderSource(shader, 1, &shaderSrc, NULL);
// Compile the shader
glCompileShader(shader);
// Check the compile status
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if(!compiled)
{
GLint infoLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen > 1)
{
char* infoLog = (char*)malloc(sizeof(char) * infoLen);
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
//esLogMessage("Error compiling shader:\n%s\n", infoLog);
free(infoLog);
}
glDeleteShader(shader);
return 0;
}
return shader;
}
extern "C" JNIEXPORT jstring
JNICALL
Java_appname_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
// Maybe create a shader straight here
//prepare_data();
//GLuint tex[2];
char hello[100] = "hello";
GLuint data_buffer;
GLuint output_buffer;
uint32_t data[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
glGenBuffers(1, &data_buffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, data_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uint32_t) * 10, (void*)data, GL_STREAM_COPY);
glBindBufferBase( GL_SHADER_STORAGE_BUFFER, 1, data_buffer);
glGenBuffers(0, &output_buffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, output_buffer);
//glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uint32_t) * 10, (void*)calc_data, GL_STREAM_COPY);
glBindBufferBase( GL_SHADER_STORAGE_BUFFER, 0, output_buffer);
GLuint program = glCreateProgram();
GLuint shader = LoadShader(COMPUTE_SHADER);
glAttachShader(program, shader);
glLinkProgram(program);
glUseProgram(program);
glDispatchCompute(10,1,1);
GLuint *ptr = (GLuint *) glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 10, GL_READ_ONLY );
GLuint info = ptr[ 0 ];
glUnmapBuffer( GL_SHADER_STORAGE_BUFFER );
sprintf(hello, "%d ", info);
glMemoryBarrier( GL_SHADER_STORAGE_BARRIER_BIT );
return env->NewStringUTF(hello);
}
第一个问题是,您必须在缓冲区对象的规范中使用正确的数据类型 (uint
):
layout(binding = 0) writeonly buffer Output
{
uint elements[];
} output_data;
layout(binding = 1) readonly buffer Input0
{
uint elements[];
} input_data0;
此外,您还通过 glBufferData
:
创建并初始化了缓冲区对象的数据存储
glGenBuffers(0, &output_buffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, output_buffer);
glBindBufferBase( GL_SHADER_STORAGE_BUFFER, 0, output_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * 10, nullptr, GL_DYNAMIC_READ);
当你这样做时,如果你使用 GL_MAP_READ_BIT
(而不是枚举常量 GL_READ_ONLY
,那么 glMapBufferRange
的缓冲区映射将起作用,这是没有意义的在这种情况下):
GLuint *ptr = (GLuint*)glMapBufferRange(
GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * 10, GL_MAP_READ_BIT );
我想使用 Open GL ES 进行通用计算。
所以我到目前为止的理解是我需要创建一个 SSBO 并将我的数据传输到那里,将缓冲区绑定到着色器中的特殊点,运行 着色器并取回数据。
到目前为止我遇到了 3 个问题:
- 代码未编译:错误:未定义对 'glDispatchCompute' 的引用。我已经包含了GLES3/gl31.h,功能就在那里。来自 open gl es 的其他功能已正确导入;
- 我不明白如何从缓冲区取回数据;
- 代码中可能还有其他一些错误。我还没有在网上找到 Open GL ES 3.1 计算着色器代码的示例,所以我尝试将常用的 Open GL ES 代码(我是新手)和上面 link 中的计算着色器代码结合起来。
此外,我正在编写此代码以从 Android 应用程序启动,因此从那方面可能会出现一些问题。我的最终任务是在着色器和 return 到 Android 应用程序上计算一些东西。现在它只有 returns 用于调试的固定字符串。
这是我的代码:
#include <jni.h>
#include <string>
#include <GLES3/gl31.h>
//#include <GLES/egl.h>
static const char COMPUTE_SHADER[] =
"#version 310 es\n"
"layout(local_size_x = 128) in;\n"
"layout(std430) buffer;\n"
"layout(binding = 0) writeonly buffer Output {\n"
"vec4 elements[];\n"
"} output_data;\n"
"layout(binding = 1) readonly buffer Input0 {\n"
"vec4 elements[];\n"
"} input_data0;\n"
"void main()\n"
"{\n"
" uint ident = gl_GlobalInvocationID.x;\n"
"output_data.elements[ident] = input_data0.elements[ident] * input_data0.elements[ident];\n"
"}";
GLuint LoadShader(const char *shaderSrc)
{
GLuint shader;
GLint compiled;
// Create the shader object
shader = glCreateShader(GL_COMPUTE_SHADER);
if(shader == 0)
return shader;
// Load the shader source
glShaderSource(shader, 1, &shaderSrc, NULL);
// Compile the shader
glCompileShader(shader);
// Check the compile status
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if(!compiled)
{
GLint infoLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen > 1)
{
char* infoLog = (char*)malloc(sizeof(char) * infoLen);
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
//esLogMessage("Error compiling shader:\n%s\n", infoLog);
free(infoLog);
}
glDeleteShader(shader);
return 0;
}
return shader;
}
extern "C" JNIEXPORT jstring
JNICALL
Java_appname_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
// Maybe create a shader straight here
//prepare_data();
//GLuint tex[2];
char hello[100] = "hello";
GLuint data_buffer;
GLuint output_buffer;
uint32_t data[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
glGenBuffers(1, &data_buffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, data_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uint32_t) * 10, (void*)data, GL_STREAM_COPY);
glBindBufferBase( GL_SHADER_STORAGE_BUFFER, 1, data_buffer);
glGenBuffers(0, &output_buffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, output_buffer);
//glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uint32_t) * 10, (void*)calc_data, GL_STREAM_COPY);
glBindBufferBase( GL_SHADER_STORAGE_BUFFER, 0, output_buffer);
GLuint program = glCreateProgram();
GLuint shader = LoadShader(COMPUTE_SHADER);
glAttachShader(program, shader);
glLinkProgram(program);
glUseProgram(program);
glDispatchCompute(10,1,1);
GLuint *ptr = (GLuint *) glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 10, GL_READ_ONLY );
GLuint info = ptr[ 0 ];
glUnmapBuffer( GL_SHADER_STORAGE_BUFFER );
sprintf(hello, "%d ", info);
glMemoryBarrier( GL_SHADER_STORAGE_BARRIER_BIT );
return env->NewStringUTF(hello);
}
第一个问题是,您必须在缓冲区对象的规范中使用正确的数据类型 (uint
):
layout(binding = 0) writeonly buffer Output
{
uint elements[];
} output_data;
layout(binding = 1) readonly buffer Input0
{
uint elements[];
} input_data0;
此外,您还通过 glBufferData
:
glGenBuffers(0, &output_buffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, output_buffer);
glBindBufferBase( GL_SHADER_STORAGE_BUFFER, 0, output_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * 10, nullptr, GL_DYNAMIC_READ);
当你这样做时,如果你使用 GL_MAP_READ_BIT
(而不是枚举常量 GL_READ_ONLY
,那么 glMapBufferRange
的缓冲区映射将起作用,这是没有意义的在这种情况下):
GLuint *ptr = (GLuint*)glMapBufferRange(
GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * 10, GL_MAP_READ_BIT );