You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,&params);
  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);
}

解决办法

错误原因解析

  1. 在标准GLSL 4.3中,sampler2D这类不透明类型只能声明为全局uniform或函数参数,不能在函数内直接初始化构造。
  2. 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类型:

  1. 创建数组纹理时指定GL_TEXTURE_2D_ARRAY类型。
  2. 用glTexImage3D分配内存,高度设为单张纹理高度,深度设为纹理总数。
  3. 用glTexSubImage3D将每张纹理数据传入对应层。
  4. 将数组纹理绑定到采样器单元1,确保Shader中的sampler2DArray能正确采样。

内容的提问来源于stack exchange,提问作者Bertrand125

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 01:49:55