Search code examples
c++webglwebassemblyemscripten

Emscripten fails to compile shader


I'm using emscripten with C++ 17 and WebGL 1.0 to try to draw some basic things in OpenGL. But I can't seem to go past shader compilation. I tried many different types of shaders to eliminate the possibility of shader being the issues.

My assumption is that it is the encoding of the shader text but I can't seem to figure it out. Maybe someone already faced this and can provide a solution.

Compiled with:

-s ENVIRONMENT=web
-s TOTAL_MEMORY=2147483648
-s MODULARIZE=1
-s EXPORT_ES6=1
-s DEMANGLE_SUPPORT=1
-s USE_PTHREADS=0
-s GL_ASSERTIONS=1
-s GL_DEBUG=1
--preload-file ./assets@/

If you're trying to build a minimal program, the file names in assets are standard.vert and standard.frag

Shaders

Vertex shader:

precision mediump float;

attribute vec2 vertPosition;
attribute vec3 vertColor;

varying vec3 fragColor;

void main() {
    fragColor = vertColor;
    gl_Position = vec4(vertPosition, 0.0, 1.0);
}

Fragment Shader:

precision mediump float;

varying vec3 fragColor;

void main() {
    gl_FragColor = vec4(fragColor, 1.0);
}

Loader

readFile

std::string readFile( FILE* file )
{
    fseek( file, 0L, SEEK_END );
    long buffSize = ftell( file );
    rewind( file );

    std::string buffer( buffSize, '\0' );

    fread( (void*)buffer.c_str(), 1, buffSize, file );

    return buffer;
}
GLenum ErrorCheckValue  = glGetError();
GLint  gl_shader_result = GL_FALSE;
int    InfoLogLength;

std::string vertex_src;
std::string frag_src;
FILE*       fp = nullptr;

fp = fopen( "/standard.vert", "r" );
if ( !fp )
{
    emscripten_console_error( "No file found for vertex shader" );
    return;
}

vertex_src = readFile( fp );
emscripten_console_logf( "Vertex Shader:\n%s", vertex_src.c_str() );
fclose( fp );

fp = fopen( "/standard.frag", "r" );
if ( !fp )
{
    emscripten_console_error( "No file found for fragment shader" );
    return;
}

frag_src = readFile( fp );
emscripten_console_logf( "Fragment Shader:\n%s", frag_src.c_str() );
fclose( fp );

const char* vertexCode = vertex_src.c_str();
const char* fragCode   = frag_src.c_str();

u32 vertexShaderId = glCreateShader( GL_VERTEX_SHADER );
glShaderSource( vertexShaderId, 1, (const GLchar* const*)vertexCode, NULL );
glCompileShader( vertexShaderId );

// check for vertex shader errors
glGetShaderiv( vertexShaderId, GL_COMPILE_STATUS, &gl_shader_result );
glGetShaderiv( vertexShaderId, GL_INFO_LOG_LENGTH, &InfoLogLength );

if ( InfoLogLength > 0 )
{
    std::string msg( InfoLogLength + 1, '\0' );

    glGetShaderInfoLog( vertexShaderId, InfoLogLength, NULL, (GLchar*)msg.c_str() );

    emscripten_console_error( ( "WASM:: Vertex shader error: " + msg ).c_str() );

    return;
}

u32 fragmentShaderId = glCreateShader( GL_FRAGMENT_SHADER );
glShaderSource( fragmentShaderId, 1, (const GLchar* const*)fragCode, NULL );
glCompileShader( fragmentShaderId );

// check for vertex shader errors
glGetShaderiv( fragmentShaderId, GL_COMPILE_STATUS, &gl_shader_result );
glGetShaderiv( fragmentShaderId, GL_INFO_LOG_LENGTH, &InfoLogLength );

if ( InfoLogLength > 0 )
{
    std::string msg( InfoLogLength + 1, '\0' );

    glGetShaderInfoLog( fragmentShaderId, InfoLogLength, NULL, (GLchar*)msg.c_str() );

    emscripten_console_error( ( "WASM:: Fragment shader error: " + msg ).c_str() );

    return;
}

u32 shaderProgramId = glCreateProgram();
glAttachShader( shaderProgramId, vertexShaderId );
glAttachShader( shaderProgramId, fragmentShaderId );
glLinkProgram( shaderProgramId );

// Check the program
glGetProgramiv( shaderProgramId, GL_LINK_STATUS, &gl_shader_result );
glGetProgramiv( shaderProgramId, GL_INFO_LOG_LENGTH, &InfoLogLength );
if ( InfoLogLength > 0 )
{
    std::string msg( InfoLogLength + 1, '\0' );

    glGetProgramInfoLog( shaderProgramId, InfoLogLength, NULL, (GLchar*)msg.c_str() );

    emscripten_console_error( ( "WASM:: Shader compilation error: " + msg ).c_str() );

    return;
}

emscripten_console_log( "WASM:: Compiled shaders" );

glDetachShader( shaderProgramId, vertexShaderId );
glDetachShader( shaderProgramId, fragmentShaderId );

glDeleteShader( vertexShaderId );
glDeleteShader( fragmentShaderId );

And ofcourse the error: glCompileShader: ERROR: 1:1: '' : syntax error

Thank you for your patience to read all this. Any comment, suggestion or solution are always better none so thank you.


Solution

  • I am not sure if this is due to WebGL 1.0/2.0 being OpenGL ES2/ES3, but in order for WebGL to correctly read the shader code, it needs to the pointer to the char[] pointer containing the shader code.

    The correction to be made for vertex and fragment shaders is:

    glShaderSource( vertexShaderId, 1, (const GLchar**)&vertexCode, NULL );
    
    glShaderSource( fragmentShaderId, 1, (const GLchar**)&fragCode, NULL );