Question

I'm new to Julia and am trying to run a minimal OpenGL program, which I'm porting from some of my Python, using Julia's OpenGL and GLFW libs.

The problem I'm having is OpenGL tells me my shader is corrupt. The shader should be perfectly valid, I've used it in my Python code, albeit more complex in Python.

Unfortunately there is no shader driven OpenGL example that I can refer to, the provided examples on the GLUT repo and SDL only use older fixed-function rendering and don't use any shaders that I can see.

The code is below:

push!(Sys.DL_LOAD_PATH, "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/")

global OpenGLver="3.2"
using OpenGL
import GLFW

#
# Window Setup
#
GLFW.Init()

GLFW.OpenWindowHint(GLFW.OPENGL_VERSION_MAJOR, 3)
GLFW.OpenWindowHint(GLFW.OPENGL_VERSION_MINOR, 2)
GLFW.OpenWindowHint(GLFW.OPENGL_FORWARD_COMPAT, TRUE)
GLFW.OpenWindowHint(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE)

width, height = 1024, 768
GLFW.OpenWindow(
    width, height,
    8, 8, 8,
    8, 24, 0,
    GLFW.WINDOW
)


result = Cint[0]

#
# Mesh
#
glGenVertexArrays(1, result)
vao = result[1]
glBindVertexArray(vao)

vertices = Float32[
-1., 1.,-1.,
-1.,-1.,-1.,
 1., 1.,-1.,

-1.,-1.,-1.,
 1.,-1.,-1.,
 1., 1.,-1.,
]

glGenBuffers(1, result)
vbo = result[1]
glBindBuffer(ARRAY_BUFFER, vbo)
glBufferData(ARRAY_BUFFER, sizeof(vertices), vertices, STATIC_DRAW)


#
# Shader
#

vs_source = """
#version 150

// input
in vec3 in_position;

void main(void) 
{
    gl_Position = vec4(in_position, 1.0);
}
"""

fs_source = """
#version 150

// output
out vec4 out_frag_color;

void main(void) 
{
    out_frag_color = vec4(1.0, 0.0, 0.0, 1.0);
}
"""

println("VERTEX SHADER")
vs = glCreateShader(VERTEX_SHADER)
println("error:",glGetError())
if 0 == vs
    println("Failed to create vertex shader")
    exit(1)
end
#glShaderSource(vs, 1, [vs_source], [length(vs_source)])
glShaderSource(vs, 1, [vs_source], 0)
println("length:",length(vs_source))
println("error:",glGetError())
glCompileShader(vs)
println("error:",glGetError())
println("original")
println(vs_source)
println("returned")
glGetShaderiv(vs, SHADER_SOURCE_LENGTH, result)
println("size:", result[1])
s = Array(Uint8, result[1])
glGetShaderSource(vs, result[1], result, s)
println(s)
s = bytestring(convert(Ptr{Uint8}, s))
println(s)
glGetShaderiv(vs, COMPILE_STATUS, result)
if FALSE == result[1]
    println("Vertex shader failed to compile")
    glGetShaderiv(vs, INFO_LOG_LENGTH, result)
    s = Array(Uint8, result[1])
    glGetShaderInfoLog(vs, result[1], result, s)
    println("log:",bytestring(convert(Ptr{Uint8}, s)))
    exit(1)
end


println("FRAGMENT SHADER")
fs = glCreateShader(FRAGMENT_SHADER)
println("error:",glGetError())
if 0 == fs
    println("Failed to create fragment shader")
    exit(1)
end
#glShaderSource(fs, 1, [fs_source], [length(fs_source)])
glShaderSource(fs, 1, [fs_source], 0)
println("length:",length(fs_source))
println("error:",glGetError())
glCompileShader(fs)
println("error:",glGetError())
println("original")
println(fs_source)
println("returned")
glGetShaderiv(fs, SHADER_SOURCE_LENGTH, result)
println("size:", result[1])
s = Array(Uint8, result[1])
glGetShaderSource(fs, result[1], result, s)
println(s)
s = bytestring(convert(Ptr{Uint8}, s))
println(s)
glGetShaderiv(fs, COMPILE_STATUS, result)
if FALSE == result[1]
    println("Fragment shader failed to compile")
    glGetShaderiv(fs, INFO_LOG_LENGTH, result)
    s = Array(Uint8, result[1])
    glGetShaderInfoLog(fs, result[1], result, s)
    println("log:",bytestring(convert(Ptr{Uint8}, s)))
    exit(1)
end

println("SHADER PROGRAM")
p = glCreateProgram()
println("error:",glGetError())
glAttachShader(p, vs)
println("error:",glGetError())
glAttachShader(p, fs)
println("error:",glGetError())
s = Array(Int8, 2)
glGetAttachedShaders(p, length(s), result, s)
println("attached:",[vs, fs])
println("length:",result[1])
println("actual:",s)
glLinkProgram(p)
println("error:",glGetError())
glGetProgramiv(p, LINK_STATUS, result)
if FALSE == result[1]
    println("Shader program failed to link")
    glGetProgramiv(p, INFO_LOG_LENGTH, result)
    s = Array(Uint8, result[1])
    glGetProgramInfoLog(p, result[1], result, s)
    println("log:",bytestring(convert(Ptr{Uint8}, s)))
    exit(1)
end

glUseProgram(p)
in_position = glGetAttribLocation(p, "in_position")
println(in_position)
glEnableVertexAttribArray(in_position)
glVertexAttribPointer(in_position, 3, FLOAT, FALSE, sizeof(vertices)/2, 0)


#
# Render
#
glDisable(CULL_FACE)
glClearColor(0.2, 0.2, 0.2, 1.0)
glViewport(0, 0, width, height)
while GLFW.GetWindowParam(GLFW.OPENED) && !GLFW.GetKey(GLFW.KEY_ESC)
    glClear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT)
    glDrawArrays(TRIANGLES, 0, length(vertices))
    GLFW.SwapBuffers()
end
GLFW.CloseWindow()
GLFW.Terminate()

The output is as follows:

julia test.jl
VERTEX SHADER
error:0
length:164
error:0
error:0
original
#version 150

// input
in vec3 in_position;

void main(void)
{
    // apply projection and model view matrix to vertex
    gl_Position = vec4(in_position, 1.0);
}

returned
size:2
10
0



FRAGMENT SHADER
error:0
length:118
error:0
error:0
original
#version 150

// output
out vec4 out_frag_color;

void main(void)
{
    out_frag_color = vec4(1.0, 0.0, 0.0, 1.0);
}

returned
size:2
10
0



SHADER PROGRAM
error:0
error:0
error:0
attached:1
2

length:2
actual:1
0

error:0
Shader program failed to link
log:ERROR: Compiled vertex shader was corrupt.
ERROR: Compiled fragment shader was corrupt.

The OpenGL.jl source is here: https://github.com/rennis250/OpenGL.jl/blob/master/src/gl32/gl32.jl

glShaderSource has the following signature:

@getCFun "libGL" glShaderSource glShaderSource(shader::GLuint, count::GLsizei, string_::Ptr{Uint8}, length::Ptr{GLint})::Void
export glShaderSource

As you can see, much of the data I'm receiving back is not correct. glAttachedShaders returns 0, 1 instead of 1,2. glGetShader returns a shader size of 2 glShaderSource returns an empty string.

It's also frustrating because OpenGL reports no error uploading the shaders, which it should if it's receiving garbage or erronous shader code. This makes me believe that the data is not necessarily corrupt, but just... empty.

I believe the problem is either:

  1. I'm not passing the data correctly
  2. There is an issue with the OpenGL bindings

I'm leaning toward the first one =)

Was it helpful?

Solution

It seems I needed an extra conversion step which I haven't seen required for passing strings as pointers in the doc examples.

The old code was

glShaderSource(vs, 1, [vs_source], 0)

The fix is to add a convert call.

glShaderSource(vs, 1, [convert(Ptr{Uint8}, vs_source)], 0)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top