vaiorabbit / ruby-opengl

Yet another OpenGL wrapper for Ruby (and wrapper code generator).
Other
88 stars 12 forks source link

How to use glDeleteVertexArrays #18

Closed cedlemo closed 9 years ago

cedlemo commented 9 years ago

here is the example:

=begin
  gtkglarea2.rb draw a triangle using shaders on a grey background
  this script need the opengl-bindings gem from :
  https://github.com/vaiorabbit/ruby-opengl

  gem install opengl-bindings

  sources:
  http://antongerdelan.net/opengl/hellotriangle.html
  opengl-bindings/sample/RedBook/varray
  opengl-bindings/sample/GLES/gles.rb
  http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/
  https://developer.gnome.org/gtk3/stable/GtkGLArea.html
  https://www.bassi.io/articles/2015/02/17/using-opengl-with-gtk/
  http://stackoverflow.com/questions/30337845/gldrawarrays-not-working-using-gtkglarea-in-gtk3
=end

require "gtk3"
require "opengl"

unless Gtk::Version.or_later?(3, 16, 0)
  puts "This sample requires GTK+ 3.16.0 or later: #{Gtk::Version::STRING}"
  exit
end

case OpenGL.get_platform
when :OPENGL_PLATFORM_WINDOWS
  OpenGL.load_lib('opengl32.dll', 'C:/Windows/System32')
when :OPENGL_PLATFORM_MACOSX
  OpenGL.load_lib('libGL.dylib', '/System/Library/Frameworks/OpenGL.framework/Libraries')
when :OPENGL_PLATFORM_LINUX
  OpenGL.load_lib('libGL.so', '/usr/lib')
else
  raise RuntimeError, "Unsupported platform."
end

include OpenGL

window = Gtk::Window.new("OpenGL widget shaders test")

window.set_size_request(400, 400)
glarea = Gtk::GLArea.new

window.add(glarea)

vertex_shader = <<EOF
#version 400
in vec3 vp;
void main () {
  gl_Position = vec4 (vp, 1.0);
};
EOF

fragment_shader = <<EOF
#version 400
out vec4 frag_colour;
void main () {
  frag_colour = vec4 (0.5, 0.0, 0.5, 1.0);
};
EOF

def setup_shaders(vertex, fragment)

  # Load the shaders sources
  vs_handle = glCreateShader(GL_VERTEX_SHADER)
  fs_handle = glCreateShader(GL_FRAGMENT_SHADER)

  glShaderSource(vs_handle, 1, [vertex].pack("p"), [vertex.bytesize].pack("I"))

  glShaderSource(fs_handle, 1, [fragment].pack("p"), [fragment.bytesize].pack("I"))

  # Compile the vertex shader
  glCompileShader(vs_handle)
  # Check the vertex shader compilation
  vertCompiled_buf = "    "
  glGetShaderiv(vs_handle, GL_COMPILE_STATUS, vertCompiled_buf)
  vertCompiled = vertCompiled_buf.unpack("L")[0]
  if vertCompiled == 0
    infoLog = " " * 1024
    glGetShaderInfoLog(vs_handle, 1023, nil, infoLog)
    puts "Shader InfoLog:\n#{infoLog}\n"
  end

  # Compile the fragment shader
  glCompileShader(fs_handle)
  # Check the fragment shader compilation
  fragCompiled_buf = "    "
  glGetShaderiv(fs_handle, GL_COMPILE_STATUS, fragCompiled_buf)
  fragCompiled = fragCompiled_buf.unpack('L')[0]
  if fragCompiled == 0
    infoLog = " " * 1024
    glGetShaderInfoLog(fs_handle, 1023, nil, infoLog)
    puts "Shader InfoLog:\n#{infoLog}\n"
  end
  return false if (vertCompiled == 0 || fragCompiled == 0)

  # Load those 2 shaders (vertex and fragment) into a GPU shader program
  prog_handle = glCreateProgram()
  glAttachShader(prog_handle,vs_handle)
  glAttachShader(prog_handle,fs_handle)

  glLinkProgram(prog_handle)

  # Check if the program is valid
  linked_buf = "    "
  glGetProgramiv(prog_handle, GL_LINK_STATUS, linked_buf)
  linked = linked_buf.unpack("L")[0]
  if linked == 0
    infoLog = " " * 1024
    glGetProgramInfoLog(prog_handle, 1023, nil, infoLog)
    puts "Program InfoLog:\n#{infoLog}\n"
  end
  return false if linked==0

  return true, prog_handle
end

shader_program = nil
gl_vao = nil

glarea.signal_connect("realize") do |widget|
  widget.make_current
  puts "realize"
  # Define a triangle in a vertex buffer ( Vertex Buffer Object)

  points = [
    0.0, 0.5, 0.0,  #x1, y1, z1
    0.5, -0.5, 0.0, #x2, y2, z2
    -0.5, -0.5, 0.0 #x3, y3, z3
  ]
  vao_buf = "    "
  glGenVertexArrays(1, vao_buf)
  gl_vao = vao_buf.unpack("L")[0]
  glBindVertexArray(gl_vao)
  # We copy those points onto the graphics card in a unit called vertex buffer object (vbo).
  # Create an empty buffer
  vbo_buf = "    "
  glGenBuffers(1, vbo_buf)
  g_vbo = vbo_buf.unpack("L")[0]
  # Set the empty buffer as the current OpenGL's state machine by "binding"
  glBindBuffer(GL_ARRAY_BUFFER, g_vbo)
  # Copy the points in the currently bound buffer
  glBufferData(GL_ARRAY_BUFFER,
               3 * 4 * Fiddle::SIZEOF_FLOAT,
               points.pack("F*"),
               GL_STATIC_DRAW
              )

  # First attribute buffer : vertices
  glEnableVertexAttribArray(0)
  glVertexAttribPointer(0,        # No particular reason for 0
                        3,        # size
                        GL_FLOAT, # type
                        GL_FALSE, # normalized?
                        0,        # stride
                        0         # array buffer offset
                       )

  glBindVertexArray(0)
  # Load the shaders:
  ok, shader_program = setup_shaders(vertex_shader, fragment_shader)
end

glarea.signal_connect("render") do |widget, context|
  puts "render"
  glClearColor(0.3, 0.3, 0.3, 1)
  glClear(GL_COLOR_BUFFER_BIT)
  # Set the created shader program as current
  glUseProgram(shader_program)
  glBindVertexArray(gl_vao)
  glDrawArrays(GL_TRIANGLES, 0, 3)
  true
end

glarea.signal_connect("unrealize") do |widget|
  puts "unrealize"
  widget.make_current
  glDeleteVertexArrays(1, gl_vao);
  glDeleteProgram(shader_program);
end

window.signal_connect("destroy") { Gtk.main_quit }

window.show_all

Gtk.main

For the signal "unrealize" of the widget I try to clean all the allocated data (vao and shader program).

The script works well unitl I close the window which trigger the "unrealize" event and the glVertexArrays result in a segfault:

ruby gtkglarea2.rb                                                                                                                                                            [10:10:49] 
realize
render
render
unrealize
/home/cedlemo/.gem/ruby/2.2.0/gems/opengl-bindings-1.3.14/lib/opengl_command.rb:4439: [BUG] Segmentation fault at 0x00000000000001
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]

-- Control frame information -----------------------------------------------
c:0008 p:---- s:0034 e:000033 CFUNC  :call
c:0007 p:0027 s:0029 e:000028 METHOD /home/cedlemo/.gem/ruby/2.2.0/gems/opengl-bindings-1.3.14/lib/opengl_command.rb:4439
c:0006 p:0025 s:0023 e:000022 BLOCK  gtkglarea2.rb:178 [FINISH]
c:0005 p:---- s:0020 e:000019 CFUNC  :call
c:0004 p:---- s:0018 e:000017 CFUNC  :invoke
c:0003 p:0058 s:0014 e:000013 LAMBDA /home/cedlemo/.gem/ruby/2.2.0/gems/gobject-introspection-2.2.6/lib/gobject-introspection/loader.rb:114 [FINISH]
c:0002 p:0327 s:0010 E:000430 EVAL   gtkglarea2.rb:186 [FINISH]
c:0001 p:0000 s:0002 E:000420 TOP    [FINISH]

-- Ruby level backtrace information ----------------------------------------
gtkglarea2.rb:186:in `<main>'
/home/cedlemo/.gem/ruby/2.2.0/gems/gobject-introspection-2.2.6/lib/gobject-introspection/loader.rb:114:in `block in define_singleton_method'
/home/cedlemo/.gem/ruby/2.2.0/gems/gobject-introspection-2.2.6/lib/gobject-introspection/loader.rb:114:in `invoke'
/home/cedlemo/.gem/ruby/2.2.0/gems/gobject-introspection-2.2.6/lib/gobject-introspection/loader.rb:114:in `call'
gtkglarea2.rb:178:in `block in <main>'
/home/cedlemo/.gem/ruby/2.2.0/gems/opengl-bindings-1.3.14/lib/opengl_command.rb:4439:in `glDeleteVertexArrays'
/home/cedlemo/.gem/ruby/2.2.0/gems/opengl-bindings-1.3.14/lib/opengl_command.rb:4439:in `call'

-- Machine register context ------------------------------------------------
 RIP: 0x00007f587e9de75e RBP: 0x0000000040279000 RSP: 0x00007fffaa4c9ac0
 RAX: 0x000000000476da90 RBX: 0x000000000476da90 RCX: 0x0000000000000001
 RDX: 0x0000000000000001 RDI: 0x0000000040279000 RSI: 0x00000000044e8660
  R8: 0x000000000476da90  R9: 0x0000000001c715f0 R10: 0x00007fffaa4c9a80
 R11: 0x00007f58812c4ac0 R12: 0x000000000476da90 R13: 0x0000000000000001
 R14: 0x00000000044e8660 R15: 0x0000000040279000 EFL: 0x0000000000010202

-- C level backtrace information -------------------------------------------
/usr/lib/libruby.so.2.2 [0x7f5887053915]
/usr/lib/libruby.so.2.2 [0x7f5887053b4c]
/usr/lib/libruby.so.2.2 [0x7f5886f2dd4b]
/usr/lib/libruby.so.2.2 [0x7f5886fe532e]
/usr/lib/libc.so.6 [0x7f5886b4f5b0]
/usr/lib/libnvidia-glcore.so.352.21 [0x7f587e9de75e]
/usr/lib/libnvidia-glcore.so.352.21 [0x7f587e931c6d]
/usr/lib/libffi.so.6(ffi_call_unix64+0x4c) [0x7f588471e1f0]
/usr/lib/libffi.so.6(ffi_call+0x2f8) [0x7f588471dc58]
/usr/lib/ruby/2.2.0/x86_64-linux/fiddle.so [0x7f587bf39979]
/usr/lib/libruby.so.2.2 [0x7f588703ad30]
/usr/lib/libruby.so.2.2 [0x7f588704b44d]
/usr/lib/libruby.so.2.2 [0x7f588703fcca]
/usr/lib/libruby.so.2.2 [0x7f5887044a28]
/usr/lib/libruby.so.2.2 [0x7f5887049e5f]
/usr/lib/libruby.so.2.2 [0x7f588704a020]
/usr/lib/libruby.so.2.2 [0x7f588704a108]
/usr/lib/libruby.so.2.2 [0x7f5886f38fb2]
/usr/lib/libruby.so.2.2 [0x7f58870463aa]
/usr/lib/libruby.so.2.2 [0x7f58870475f2]
/usr/lib/libruby.so.2.2(rb_apply+0xb2) [0x7f5887047a42]
/home/cedlemo/.gem/ruby/2.2.0/extensions/x86_64-linux/2.2.0/glib2-2.2.6/glib2.so(rclosure_marshal_do+0x5f) [0x7f588510b30f]
/usr/lib/libruby.so.2.2(rb_protect+0xfb) [0x7f5886f3327b]
/home/cedlemo/.gem/ruby/2.2.0/extensions/x86_64-linux/2.2.0/glib2-2.2.6/glib2.so(rbgutil_protect+0x27) [0x7f588510bf37]
/home/cedlemo/.gem/ruby/2.2.0/extensions/x86_64-linux/2.2.0/glib2-2.2.6/glib2.so(rbgutil_invoke_callback+0x44) [0x7f588510c034]
/home/cedlemo/.gem/ruby/2.2.0/extensions/x86_64-linux/2.2.0/glib2-2.2.6/glib2.so [0x7f588510b669]
/usr/lib/libgobject-2.0.so.0(g_closure_invoke+0x145) [0x7f5884eaf2f5]
/usr/lib/libgobject-2.0.so.0 [0x7f5884ec102c]
/usr/lib/libgobject-2.0.so.0(g_signal_emit_valist+0xfd8) [0x7f5884ec9688]
/usr/lib/libgobject-2.0.so.0(g_signal_emit+0x8f) [0x7f5884ec98ef]
/usr/lib/libgtk-3.so.0(gtk_widget_unrealize+0xc1) [0x7f58799e7fd1]
/usr/lib/libgtk-3.so.0 [0x7f58799f0c19]
/usr/lib/libgtk-3.so.0 [0x7f58799e7481]
/usr/lib/libgtk-3.so.0 [0x7f58799f46fe]
/usr/lib/libgobject-2.0.so.0(g_closure_invoke+0x145) [0x7f5884eaf2f5]
/usr/lib/libgobject-2.0.so.0 [0x7f5884ec0f22]
/usr/lib/libgobject-2.0.so.0(g_signal_emit_valist+0xfd8) [0x7f5884ec9688]
/usr/lib/libgobject-2.0.so.0(g_signal_emit+0x8f) [0x7f5884ec98ef]
/usr/lib/libgtk-3.so.0(gtk_widget_unrealize+0xc1) [0x7f58799e7fd1]
/usr/lib/libgtk-3.so.0 [0x7f58799e80e8]
/usr/lib/libgtk-3.so.0 [0x7f58799f7e20]
/usr/lib/libgobject-2.0.so.0(g_object_run_dispose+0x48) [0x7f5884eb5c28]
/usr/lib/libgtk-3.so.0(gtk_main_do_event+0x574) [0x7f58798a20a4]
/usr/lib/libgdk-3.so.0 [0x7f587ba4d7b2]
/usr/lib/libglib-2.0.so.0(g_main_context_dispatch+0x24d) [0x7f5884bda9fd]
/usr/lib/libglib-2.0.so.0 [0x7f5884bdace0]
/usr/lib/libglib-2.0.so.0(g_main_loop_run+0xc2) [0x7f5884bdb002]
/usr/lib/libgtk-3.so.0(gtk_main+0x85) [0x7f58798a1485]
/usr/lib/libffi.so.6(ffi_call_unix64+0x4c) [0x7f588471e1f0]
/usr/lib/libffi.so.6(ffi_call+0x2f8) [0x7f588471dc58]
/usr/lib/libgirepository-1.0.so.1(g_callable_info_invoke+0x4e9) [0x7f58842d3449]
/usr/lib/libgirepository-1.0.so.1(g_function_info_invoke+0x9a) [0x7f58842d479a]
/home/cedlemo/.gem/ruby/2.2.0/extensions/x86_64-linux/2.2.0/gobject-introspection-2.2.6/gobject_introspection.so(rb_gi_function_info_invoke_raw_call+0x2c) [0x7f5884507d0c]
/home/cedlemo/.gem/ruby/2.2.0/extensions/x86_64-linux/2.2.0/gobject-introspection-2.2.6/gobject_introspection.so(rb_gi_function_info_invoke_raw+0x9c2) [0x7f58845089e2]
/home/cedlemo/.gem/ruby/2.2.0/extensions/x86_64-linux/2.2.0/gobject-introspection-2.2.6/gobject_introspection.so [0x7f5884508e55]
/usr/lib/libruby.so.2.2 [0x7f588703ad30]
/usr/lib/libruby.so.2.2 [0x7f588704b44d]
/usr/lib/libruby.so.2.2 [0x7f588703fc1f]
/usr/lib/libruby.so.2.2 [0x7f5887044a28]
/usr/lib/libruby.so.2.2 [0x7f5887049c18]
/usr/lib/libruby.so.2.2 [0x7f588704a020]
/usr/lib/libruby.so.2.2 [0x7f588704a3f4]
/usr/lib/libruby.so.2.2 [0x7f588704b51d]
/usr/lib/libruby.so.2.2 [0x7f588703fcca]
/usr/lib/libruby.so.2.2 [0x7f5887044a28]
/usr/lib/libruby.so.2.2(rb_iseq_eval_main+0x7f) [0x7f588704618f]
/usr/lib/libruby.so.2.2 [0x7f5886f30ebf]
/usr/lib/libruby.so.2.2(ruby_exec_node+0x1d) [0x7f5886f32a2d]
/usr/lib/libruby.so.2.2(ruby_run_node+0x1e) [0x7f5886f348ae]
ruby [0x4008ab]
/usr/lib/libc.so.6(__libc_start_main+0xf0) [0x7f5886b3c790]
ruby(_start+0x29) [0x4008d9]

-- Other runtime information -----------------------------------------------

* Loaded script: gtkglarea2.rb

I don't really know how to use glDeleteVertexArrays and I haven't found any example in your sample scripts.

Regards

vaiorabbit commented 9 years ago

Though I haven't executed your script yet (sorry), generally speaking, OpenGL object handles created by `glGenXXXX(nElems, ptrToArray)'

ex.)
glGenVertexArrays(1, vao_buf)
gl_vao = vao_buf.unpack("L")[0] # `[0]' == The 1st element of array.

should be deleted by passing an array of handles like:

glDeleteVertexArrays( 1, [gl_vao].pack('L') )

Line 57 of /GLExcess/texture.rb may be helpful to understand. Thank you.

cedlemo commented 9 years ago

I didn't understand how it should work sorry. Now it is clear Thank a lot.

You can see the final script here : https://github.com/ruby-gnome2/ruby-gnome2/pull/500

vaiorabbit commented 9 years ago

Good. I've just released opengl-bindings 1.4.0. https://rubygems.org/gems/opengl-bindings Now you can safely commit your new sample scripts that use `load_lib'. Thank you.