GLSL Compute Shader跨平台编译错误求助:sampler2D使用问题
问题:Windows程序移植到Linux后Compute Shader编译失败
背景
将Windows程序移植到GNU/Linux平台时,Compute Shader无法编译,以下是最小复现示例:
Compute Shader代码
#version 430 core #extension GL_ARB_gpu_shader_int64 : enable //#extension GL_ARB_bindless_texture : enable layout(binding = 1) uniform TextureHandles { uvec2 texture_handles[512]; }; vec3 SampleTexture(uint texture_index, vec2 uv) { uv.y = 1.f - uv.y; sampler2D tex_sampler = sampler2D(texture_handles[texture_index]); return textureLod(tex_sampler, uv, 0.0f).xyz; } void main() { }
编译错误信息
0:11(2): error: image/sampler variables may only be declared as function parameters or uniform-qualified global variables 0:11(2): error: opaque variables must be declared uniform 0:11(26): error: cannot initialize tex_sampler variable opaque 0:11(26): error: cannot construct opaque type `sampler2D' 0:12(20): warning: `tex_sampler' used uninitialized
尝试启用GL_ARB_bindless_texture扩展后,出现“该扩展在Compute Shader中不被支持”的错误。
测试程序(GLEW+GLFW)
#define GLFW_INCLUDE_NONE #include <GLFW/glfw3.h> #define GLEW_STATIC #include <GL/glew.h> #include <stdlib.h> #include <stdio.h> ///////////////////////////////////////////////////////// // // Shader programs for core profile: // const char * csprog_core = "#version 430 core\n\ #extension GL_ARB_gpu_shader_int64 : enable\n\ //#extension GL_ARB_bindless_texture : enable\n\ \n\ layout(binding = 1) uniform TextureHandles {\n\ uvec2 texture_handles[512];\n\ };\n\ \n\ vec3 SampleTexture(uint texture_index, vec2 uv) {\n\ uv.y = 1.f - uv.y;\n\ sampler2D tex_sampler = sampler2D(texture_handles[texture_index]);\n\ return textureLod(tex_sampler, uv, 0.0f).xyz;\n\ }\n\ \n\ void main() {\n\ }\n\ \n"; int width, height; void error_callback(int error, const char* description) { fprintf(stderr, "Error: %s\n", description); } int main( int argc, char *argv[ ], char *envp[ ] ) { if(!glfwInit()) { exit(EXIT_FAILURE); } glfwSetErrorCallback(error_callback); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); GLFWwindow* window = glfwCreateWindow(640, 480, "Program", NULL, NULL); if(!window) { exit(EXIT_FAILURE); } glfwMakeContextCurrent(window); glfwSwapInterval(1); glfwGetFramebufferSize(window, &width, &height); // get version info const GLubyte* renderer; const GLubyte* version; /////////////////////////////////////////////////////////////////////// // // start GLEW extension handler // glewExperimental = GL_TRUE; GLenum err = glewInit(); if(GLEW_OK != err) { fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); return(-1); } fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); // get version info renderer = glGetString(GL_RENDERER); // get renderer string version = glGetString(GL_VERSION); // version as a string printf("\nRenderer: %s", renderer); printf("\nOpenGL version supported %s\n", version); fflush(stdout); // tell GL to only draw onto a pixel if the shape is closer to the viewer glEnable(GL_DEPTH_TEST); // enable depth-testing glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer" ////////////////////////////////////////////////////////// // // Shaders: // GLint params; GLint len; GLuint cscore = glCreateShader(GL_COMPUTE_SHADER); glShaderSource(cscore, 1, &csprog_core, NULL); glCompileShader(cscore); glGetShaderiv(cscore,GL_COMPILE_STATUS,¶ms); if(params == GL_FALSE) { GLchar log[100000]; glGetShaderInfoLog(cscore,100000,&len,log); printf("\n\n%s\n\n",log); exit(EXIT_FAILURE); } // ////////////////////////////////////////////////////////// glfwDestroyWindow(window); glfwTerminate(); exit(EXIT_SUCCESS); }
解决办法
错误原因解析
- 在标准GLSL 4.3中,
sampler2D这类不透明类型只能声明为全局uniform或函数参数,不能在函数内直接初始化构造。 GL_ARB_bindless_texture扩展允许从64位句柄构造sampler,但GLSL 4.3的Compute Shader并不支持该扩展——直到GLSL 4.6核心规范才将bindless texture纳入Compute Shader的支持范围。
方案一:升级到GLSL 4.6核心版本
如果硬件驱动支持OpenGL 4.6,可直接升级Shader版本并使用bindless texture:
修改后的Compute Shader代码:
#version 460 core #extension GL_ARB_gpu_shader_int64 : enable // GLSL 4.6核心已原生支持bindless texture,无需额外扩展声明 layout(binding = 1) uniform TextureHandles { // 用uint64_t直接存储64位纹理句柄,比uvec2更直观 uint64_t texture_handles[512]; }; vec3 SampleTexture(uint texture_index, vec2 uv) { uv.y = 1.f - uv.y; // 直接从64位句柄构造sampler2D sampler2D tex_sampler = sampler2D(texture_handles[texture_index]); return textureLod(tex_sampler, uv, 0.0f).xyz; } void main() { }
同时修改测试程序中的GLFW版本配置:
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
方案二:使用纹理数组替代Bindless Texture
若无法升级OpenGL版本,可改用纹理数组(sampler2DArray),将所有需采样的纹理打包到一个数组纹理中:
修改后的Compute Shader代码
#version 430 core // 声明全局uniform纹理数组 layout(binding = 1) uniform sampler2DArray tex_array; vec3 SampleTexture(uint texture_index, vec2 uv) { uv.y = 1.f - uv.y; // 用vec3(uv, 索引)访问数组纹理的对应层 return textureLod(tex_array, vec3(uv, texture_index), 0.0f).xyz; } void main() { }
CPU端对应修改
需将多个单独纹理合并为GL_TEXTURE_2D_ARRAY类型:
- 创建数组纹理时指定
GL_TEXTURE_2D_ARRAY类型。 - 用
glTexImage3D分配内存,高度设为单张纹理高度,深度设为纹理总数。 - 用
glTexSubImage3D将每张纹理数据传入对应层。 - 将数组纹理绑定到采样器单元1,确保Shader中的
sampler2DArray能正确采样。
内容的提问来源于stack exchange,提问作者Bertrand125
相关产品推荐
相关产品推荐

