为啥我在 emscripten 使用“#version 300 es”得到“不支持的着色器版本”?

Posted

技术标签:

【中文标题】为啥我在 emscripten 使用“#version 300 es”得到“不支持的着色器版本”?【英文标题】:Why do I get "unsupported shader version" using "#version 300 es" at emscripten?为什么我在 emscripten 使用“#version 300 es”得到“不支持的着色器版本”? 【发布时间】:2020-05-12 15:46:55 【问题描述】:

我不知道为什么我在使用最新 emscripten 1.39 的顶点着色器中使用 #version 300 es 会收到“不支持的着色器版本”错误消息。使用#version 100 可以正常工作。

const GLchar* vertex_shader_code[] = 
      "#version 300 es\n"
      "precision mediump float; \n"

      "void main()  \n"
           "gl_Position = vec4(0.0, 0.0, 0.0, 1.0); \n"
      " \n"
;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);

SDL_version compiled;
SDL_version linked;

SDL_VERSION(&compiled);
SDL_GetVersion(&linked);
printf("Compiled SDL version: %d.%d.%d\n", compiled.major, compiled.minor, compiled.patch);
printf("Linked SDL version: %d.%d.%d\n", linked.major, linked.minor, linked.patch);

SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(CANVAS_WIDTH, CANVAS_HEIGHT, 0, &window, &renderer);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);

GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, vertex_shader_code, 0);
glCompileShader(vertex_shader);

auto compile_success = 0;
auto compile_info_lenght = 0;
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &compile_success);

if(compile_success == GL_FALSE) 
   glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &compile_info_lenght);
   std::string vertex_shader_log(compile_info_lenght, ' ');

   glGetShaderInfoLog(vertex_shader, compile_info_lenght, NULL, &vertex_shader_log[0]);
   int n = vertex_shader_log.length();
   char char_array[n + 1];
   strcpy(char_array, vertex_shader_log.c_str());
   printf("%s\n", char_array);

   glDeleteShader(vertex_shader);
   return 0;

对于构建我使用emcc -s main.cpp -o index.html --shell-file shell.html -s USE_SDL=2 -s FULL_ES3=1

消息:

Compiled SDL version: 2.0.9
Linked SDL version: 2.0.9
ERROR: unsupported shader version

我做错了什么?

【问题讨论】:

你为什么在SDL_Init()之前打电话给SDL_GL_SetAttribute() 嗨@genpfault,我现在直接在 SDL_Init() 之后尝试了它,但不幸的是同样的错误。 另外,如果您要使用 OpenGL ES,为什么还要靠近 SDL_Renderer 的东西?您不能(正式)在两者之间进行互操作,无法查询 SDL_Renderer 的 GL 状态,它可能会或可能不会破坏。 如果您还指定-s MAX_WEBGL_VERSION=2,有什么变化吗? 可能还需要SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES) 来强制 SDL 使用更多 EGL-y/GLES-y 代码路径。 可能。取决于 Emscripten 端口人员在这一周对 SDL 做了多少暴力 :) 【参考方案1】:

如果没有完整的程序,就很难看到所有错误。您需要使用正确的选项进行构建,从 javascript 正确调用您的 WASM 模块,并在 SDL 和 OpenGL 中正确设置所有内容。

这是一个工作示例:

//  main.cpp
#include <stdio.h>
#include <stdarg.h>
#include <emscripten.h>
#include <SDL.h>
#include <SDL_opengles2.h>

SDL_Window *sdlWindow;

static const char *vertexShaderSource[] = 
    "#version 300 es\n"
    "in vec4 position;\n"
    "void main(void) \n"
    "  gl_Position = vec4(position.xyz, 1.0);\n"
    "\n"
;

static const char *fragmentShaderSource[] = 
    "#version 300 es\n"
    "precision mediump float;\n"
    "out vec4 fragColor;\n"
    "void main(void) \n"
    "  fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
    "\n"
;

static void
fatal(const char *const fmt, ...)

    va_list args;
    va_start(args, fmt);
    vprintf(fmt, args);
    printf("\n");
    va_end(args);
    for (;;) 
        SDL_Delay(1000);
    


static GLuint
compileShader(GLenum shaderType, const char **shaderSource)

    GLuint shdr = glCreateShader(shaderType);
    glShaderSource(shdr, 1, shaderSource, nullptr);
    glCompileShader(shdr);
    GLint isCompiled = 0;
    glGetShaderiv(shdr, GL_COMPILE_STATUS, &isCompiled);
    if (isCompiled == GL_FALSE) 
        GLint maxLength = 0;
        glGetShaderiv(shdr, GL_INFO_LOG_LENGTH, &maxLength);
        char *errorString = (char *) malloc(maxLength + 1);
        glGetShaderInfoLog(shdr, maxLength, &maxLength, errorString);
        fatal("Compile failed: %s", errorString);
    
    return shdr;


static void
_set_SDL_Attribute(SDL_GLattr attr, int value, const char *attrName)
#define set_SDL_Attribute(x, v) _set_SDL_Attribute(x, v, #x)

    if (SDL_GL_SetAttribute(attr, value) != 0) 
        fatal("SDL set attrib failed: %s, %s", attrName, SDL_GetError());
    


static void
setupSDL(void)

    if (SDL_Init(SDL_INIT_VIDEO) != 0) 
        fatal("Unable to init SDL: %s", SDL_GetError());
    
    SDL_version compiled;
    SDL_version linked;
    SDL_VERSION(&compiled);
    SDL_GetVersion(&linked);
    printf("Compiled SDL version: %d.%d.%d\n",
           compiled.major, compiled.minor, compiled.patch);
    printf("Linked SDL version: %d.%d.%d\n",
           linked.major, linked.minor, linked.patch);
    set_SDL_Attribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
    set_SDL_Attribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    set_SDL_Attribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
    set_SDL_Attribute(SDL_GL_DOUBLEBUFFER, 1);
    set_SDL_Attribute(SDL_GL_DEPTH_SIZE, 24);
    SDL_Renderer *renderer;
    if (SDL_CreateWindowAndRenderer(400, 400, SDL_WINDOW_OPENGL,
                                    &sdlWindow, &renderer) < 0) 
        fatal("Unable to create windown: %s", SDL_GetError());
    
    SDL_GLContext glContext = SDL_GL_CreateContext(sdlWindow);
    if (glContext == NULL) 
        fatal("Unable to create context: %s", SDL_GetError());
    
    printf("GL Version=%s\n", glGetString(GL_VERSION));
    printf("GLSL Version=%s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));


static void
setupOpenGL(void)

    GLuint shaderProgram = glCreateProgram();
    GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource);
    GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER,
                                          fragmentShaderSource);
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);
    static const GLfloat vertices[] =  0.0f, 0.5f, 0.5f, -0.5f, -0.5f, -0.5f ;
    GLuint vbo;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof (vertices), vertices,
                 GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);       // Input offset is zero.
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);       // Black


static void
mainLoop(void)

    glClear(GL_COLOR_BUFFER_BIT);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    SDL_GL_SwapWindow(sdlWindow);


int
main(void)

    setupSDL();
    setupOpenGL();
    emscripten_set_main_loop(mainLoop, 0, true);
    return 0;

使用这些选项进行编译:

emcc main.cpp -O3 -Wall -Wextra -Werror -s WASM=1 -s USE_SDL=2 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -o foo.js

像这样从 HTML 启动:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
    <h1>Wasm Test Page</h1>
    <canvas id=canvas width=400 height=400 oncontextmenu="event.preventDefault()"></canvas>
    <script>var Module =  canvas: document.getElementById('canvas') ; </script>
    <script src="foo.js"></script>
</body>
</html>

如果一切正常,您应该会在浏览器窗口中看到黑色背景上的红色三角形。

HTH。

【讨论】:

【参考方案2】:

对于有同样问题的人,解决方案是 SDL_WINDOW_OPENGL。

SDL_CreateWindowAndRenderer(CANVAS_WIDTH, CANVAS_HEIGHT, SDL_WINDOW_OPENGL, &window, &renderer);

【讨论】:

以上是关于为啥我在 emscripten 使用“#version 300 es”得到“不支持的着色器版本”?的主要内容,如果未能解决你的问题,请参考以下文章

将 emscripten 与 opengl 着色器一起使用

emscripten:我该如何解决 UnboundTypeError

为啥 LLVM 窗口中缺少 LLC.exe?

您如何在 emscripten 中迭代 Box2D 中的实体列表?

如何使用 Socket.io 和 emscripten 使用 javascript 库?

防止 Emscripten 编译的 JavaScript 阻止某些关键输入