0
\$\begingroup\$

I am trying to follow LearnOpenGL while coding in the Zig language, and something that is very odd is that sometimes my shader compilation fails even though I changed nothing between executing the app. I also don't understand the errors. By the way, I use mach-glfw and zigglgen.

Some errors I get:

error: [opengl] Failed to compile shader: assets/shaders/shader.frag
  0(8) : error C0000: syntax error, unexpected '=' at token "="

error: [opengl] Failed to link shader program:
  Fragment info
-------------
0(8) : error C0000: syntax error, unexpected '=' at token "="
(0) : error C2003: incompatible options for link
error: [opengl] Failed to compile shader: assets/shaders/shader.frag
  0(9) : error C0000: syntax error, unexpected '(', expecting ';' at token "("

error: [opengl] Failed to link shader program:
  Fragment info
-------------
0(9) : error C0000: syntax error, unexpected '(', expecting ';' at token "("
(0) : error C2003: incompatible options for link

error: [opengl] Failed to compile shaders/shader.vert:
0(6) : error C0000: syntax error, unexpected $undefined at token "<undefined>"

Here is the code:

// Vertex shader
#version 330 core
layout (location = 0) in vec3 aPos;

out vec4 vertexColor;

void main() {
    gl_Position = vec4(aPos.xyz, 1.0);
    vertexColor = vec4(0.5, 0.0, 0.0, 1.0);
}
// Fragment shader
#version 330 core
out vec4 FragColor;
  
in vec4 vertexColor;

void main() {
    FragColor = vertexColor;
}
// Shortened main code
const std = @import("std");
const builtin = @import("builtin");
const glfw = @import("glfw");
const gl = @import("gl");
const App = @import("App.zig");

var gl_procs: gl.ProcTable = undefined;

fn glfwErrorCallback(err: glfw.ErrorCode, desc: [:0]const u8) void {
    ...
}

fn glfwFramebufferSizeCallback(_: glfw.Window, w: u32, h: u32) void {
    gl.Viewport(0, 0, @intCast(w), @intCast(h));
}

pub fn main() !void {
    // GLFW initialization
    if (!glfw.init(.{})) {
        ...
    }
    defer glfw.terminate();

    // Window creation
    const window = glfw.Window.create(1280, 720, "example opengl app", null, null, .{
        ...
    }) orelse {
        ...
    };
    defer window.destroy();
    glfw.makeContextCurrent(window);

    // OpenGL preparation
    if (!gl_procs.init(glfw.getProcAddress)) {
        ...
    }
    gl.makeProcTableCurrent(&gl_procs);
    window.setFramebufferSizeCallback(glfwFramebufferSizeCallback);

    // App startup
    var app = App{
        .window = window,
    };
    app.run() catch |err| {
        ...
    };
}

// shortened App code
...

window: glfw.Window,
vertices: [12]f32 = [_]f32{
    0.5,  0.5,  0.0,
    0.5,  -0.5, 0.0,
    -0.5, -0.5, 0.0,
    -0.5, 0.5,  0.0,
},
indices: [6]gl.uint = [_]gl.uint{
    0, 1, 3,
    1, 2, 3,
},

fn createCompiledShader(file: []const u8, stype: Shader.ShaderType) !Shader {
    const shader = try Shader.fromFile(file, stype, std.heap.raw_c_allocator);
    if (shader.compile()) |msg| {
        std.log.err("[opengl] Failed to compile shader: {s}\n  {s}", .{ file, msg });
    }
    return shader;
}

pub fn run(this: App) !void {
    // == STARTUP

    // Create vertex array object
    ...

    // Create vertex buffer object
    ...

    // Create element buffer object
    ...

    // Vertex attributes
    ...

    // Create shaders
    const vertex_shader = try createCompiledShader("assets/shaders/shader.vert", .Vertex);
    const fragment_shader = try createCompiledShader("assets/shaders/shader.frag", .Fragment);

    // Create shader program
    const shader_program = ShaderProgram.init(&.{
        vertex_shader,
        fragment_shader,
    });
    if (shader_program.link()) |msg| {
        std.log.err("[opengl] Failed to link shader program:\n  {s}", .{msg});
    }
    // Activate program and delete shaders
    shader_program.use();
    vertex_shader.delete();
    fragment_shader.delete();

    // == RENDER LOOP

    while (!this.window.shouldClose()) {
        gl.ClearColor(0.5, 0.3, 0.1, 1.0);
        gl.Clear(gl.COLOR_BUFFER_BIT);

        shader_program.use();
        gl.BindVertexArray(vao);
        gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);

        this.window.swapBuffers();
        glfw.pollEvents();
    }
}
// shortened Shader class
...

pub const ShaderType = enum {
    Vertex,
    Fragment,
};

/// The source code of the shader.
source: []const u8,
gl_object: gl.uint,

fn createOpenglShader(src: []const u8, shader_type: ShaderType) gl.uint {
    const stype: gl.uint = switch (shader_type) {
        .Vertex => gl.VERTEX_SHADER,
        .Fragment => gl.FRAGMENT_SHADER,
    };
    const object: gl.uint = gl.CreateShader(stype);
    gl.ShaderSource(object, 1, @ptrCast(&src.ptr), null);
    return object;
}

/// Creates a `Shader` object from the source string.
pub fn fromString(src: []const u8, shader_type: ShaderType) Shader {
    ...
}

/// Creates a `Shader` object from the file contents of the given `path`.
/// The file path has to be relative to the folder where the executable resides.
/// If you want to use a file outside of that folder, open the file yourself and pass its' contents to `Shader.fromString`.
/// For some reason, you can't pass a `GeneralPurposeAllocator` since the program segfaults if you do.
pub fn fromFile(path: []const u8, shader_type: ShaderType, alloc: std.mem.Allocator) !Shader {
    var arena = std.heap.ArenaAllocator.init(alloc);
    defer arena.deinit();
    const allocator = arena.allocator();

    var root_dir = try std.fs.openDirAbsolute(try std.fs.selfExeDirPathAlloc(allocator), .{});
    defer root_dir.close();

    var file = try root_dir.openFile(path, .{});
    defer file.close();

    const buf = try allocator.alloc(u8, try file.getEndPos());
    _ = try file.readAll(buf);

    return .{
        .source = buf,
        .gl_object = createOpenglShader(buf, shader_type),
    };
}

/// Compiles the shader. If compilation succeeded, the return value will be null.
/// Otherwise, the return value will be the error message.
pub fn compile(self: Shader) ?[256]u8 {
    gl.CompileShader(self.gl_object);
    var success: gl.int = undefined;
    gl.GetShaderiv(self.gl_object, gl.COMPILE_STATUS, &success);
    if (success == 0) {
        var info_log = std.mem.zeroes([256]u8);
        gl.GetShaderInfoLog(self.gl_object, 256, null, &info_log);
        return info_log;
    }
    return null;
}

pub fn delete(self: Shader) void {
    ...
}
```
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Sounds like something could be corrupting the memory to which pointer to a string is pointing. Check what what really gets passed as the shader string to GLSL. \$\endgroup\$
    – Kromster
    Commented May 8 at 17:21
  • \$\begingroup\$ @Kromster I logged the shader source from the Shader.fromFile function as well as the Shader.compile function (before and after gl.CompileShader), and the source seems to be alright, even when I am getting errors. Maybe the corrupted parts are invisible characters... \$\endgroup\$
    – user171748
    Commented May 9 at 9:20
  • \$\begingroup\$ Sometimes I am also getting error messages from OpenGL saying something about unexpected $undefined, so maybe something is wrong when passing the source string to gl.CompileShader. \$\endgroup\$
    – user171748
    Commented May 9 at 9:24
  • \$\begingroup\$ Sounds very much like hardware problems (RAM on GPU or badly seated card) and could be due to many reasons. Use diagnostic software to check RAM, use latest drivers. Try on different hardware to eliminate possible software issues. If not software Fix by using a new device, or try new GPU, clean and reseat graphics card. \$\endgroup\$
    – Blindman67
    Commented May 9 at 18:05
  • \$\begingroup\$ @Blindman67 That would be pretty considering the fact that I'm working on a laptop (Acer Nitro AN517-41) \$\endgroup\$
    – user171748
    Commented May 10 at 10:31

0

You must log in to answer this question.