簡単な Go プログラムを書きました。その目標は、OpenGl を使用して画面上の三角形を回転させることです。
編集: メイン ループが原因のようです。OpenGl は問題ありませんが、ゴルーチンやチャネルに何か問題があります。この投稿の下部を参照してください。この質問のタイトルを適切に変更しています。
プログラムはほぼ動作します。想定どおりに回転することと、何も描画せずに2つのOpenGlバッファをフラッシュすることを交互に繰り返します。レンダリングしようとしているフレームの約 3 分の 2 が、黙って失敗します。その理由がわかりません。
これは私のフレームレートには依存しません。50 FPS で更新するか 1 FPS で更新するかに関係なく、長い一連の乱れたフレームの後に短い一連の動作フレームが続きます。OpenGl にあまりにも速く動作するように要求しているとは思いません (glFinish()
とにかく呼び出します)。
実験を始めたところ、奇妙な動作が見つかりました。glGetUniformLocation
最初のステップとして、新しい回転行列を頂点バッファーに送信します。シェーダーには明らかに存在しないパラメーターであるglGetUniformLocation
をどこで見つけることができるかを尋ねた場合、期待どおりに常に -1 が返されるとは限らないことに気付きました。"dummy"
0 を返すこともあります。そのダミー属性は問題の原因ではなく、単なる症状です。
OpenGl 呼び出しのたびに glGetError をチェックすると、常に NO_ERROR が返されます。
ここに私のコードを貼り付けています。もっと短くできればよかったのに。私の実際のコードは、OpenGl を呼び出すたびに glError をチェックし、0 バッファまたは -1 ロケーションも調べます。このバージョンは軽量です。 func main
が一番上にあり、回転を処理するループが続きます。
package main
import (
"fmt"
"github.com/0xe2-0x9a-0x9b/Go-SDL/sdl"
gl "github.com/chsc/gogl/gl33"
"math"
"time"
"unsafe"
)
const DEG_TO_RAD = math.Pi / 180
type GoMatrix [16]float64
type GlMatrix [16]gl.Float
var good_frames, bad_frames, sdl_events int
func main() {
//=================================================================
// Just opening a window, skip to the next part.
if status := sdl.Init(sdl.INIT_VIDEO); status != 0 {
panic("Could not initialize SDL: " + sdl.GetError())
}
defer sdl.Quit()
sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1)
const FLAGS = sdl.OPENGL
if screen := sdl.SetVideoMode(640, 480, 32, FLAGS); screen == nil {
panic("Could not open SDL window: " + sdl.GetError())
}
if err := gl.Init(); err != nil {
panic(err)
}
gl.Viewport(0, 0, 640, 480)
gl.ClearColor(.5, .5, .5, 1)
//=================================================================
// Simplest shaders ever.
// A matrix to move the model, nothing else.
vertex_code := gl.GLString(`
#version 330 core
in vec3 vpos;
uniform mat4 MVP;
void main() {
gl_Position = MVP * vec4(vpos, 1);
}
`)
// Everything is red.
fragment_code := gl.GLString(`
#version 330 core
void main(){
gl_FragColor = vec4(1,0,0,1);
}
`)
vs := gl.CreateShader(gl.VERTEX_SHADER)
fs := gl.CreateShader(gl.FRAGMENT_SHADER)
gl.ShaderSource(vs, 1, &vertex_code, nil)
gl.ShaderSource(fs, 1, &fragment_code, nil)
gl.CompileShader(vs)
gl.CompileShader(fs)
prog := gl.CreateProgram()
gl.AttachShader(prog, vs)
gl.AttachShader(prog, fs)
gl.LinkProgram(prog)
// Did it compile?
var link_status gl.Int
gl.GetProgramiv(prog, gl.LINK_STATUS, &link_status)
if link_status == gl.FALSE {
var info_log_length gl.Int
gl.GetProgramiv(prog, gl.INFO_LOG_LENGTH, &info_log_length)
if info_log_length == 0 {
panic("Program linking failed but OpenGL has no log about it.")
} else {
info_log_gl := gl.GLStringAlloc(gl.Sizei(info_log_length))
defer gl.GLStringFree(info_log_gl)
gl.GetProgramInfoLog(prog, gl.Sizei(info_log_length), nil, info_log_gl)
info_log := gl.GoString(info_log_gl)
panic(info_log)
}
}
gl.UseProgram(prog)
attrib_vpos := gl.Uint(gl.GetAttribLocation(prog, gl.GLString("vpos")))
//=================================================================
// One triangle.
positions := [...]gl.Float{-.5, -.5, 0, .5, -.5, 0, 0, .5, 0}
var vao gl.Uint
gl.GenVertexArrays(1, &vao)
gl.BindVertexArray(vao)
var vbo gl.Uint
gl.GenBuffers(1, &vbo)
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
gl.BufferData(gl.ARRAY_BUFFER,
gl.Sizeiptr(unsafe.Sizeof(positions)),
gl.Pointer(&positions[0]),
gl.STATIC_DRAW)
gl.EnableVertexAttribArray(attrib_vpos)
gl.VertexAttribPointer(attrib_vpos, 3, gl.FLOAT, gl.FALSE, 0, gl.Pointer(nil))
//=================================================================
Loop(prog)
fmt.Println("Good frames", good_frames)
fmt.Println("Bad frames ", bad_frames)
fmt.Println("SDL events ", sdl_events)
}
func Loop(program gl.Uint) {
start_time := time.Now()
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
running := true
for running {
select {
case tick_time := <-ticker.C:
OnTick(start_time, tick_time, program)
case event := <-sdl.Events:
running = OnSdlEvent(event)
}
}
}
func OnSdlEvent(event interface{}) bool {
sdl_events++
switch event.(type) {
case sdl.QuitEvent:
return false // Stop the main loop.
}
return true // Do not stop the main loop.
}
func OnTick(start_time, tick_time time.Time, program gl.Uint) {
duration := tick_time.Sub(start_time).Seconds()
speed := 10.
angle := math.Mod(duration*speed, 360)
gom := RotZ(angle)
MVP := ToGlMatrix(gom)
/* HERE, SOMETHING FISHY HAPPENS.
Problem: sometimes, actually often, OpenGl returns 0 instead of -1 for
the dummy parameter. This is entirely correlated to the stuttering.
With my implementation of OpenGl, swap buffer does a real swap.
That means I get to see the last two pictures rendered.
Thing is, I can see the swap, that means the pictures are different.
That means that the call to DrawArrays is ignored.
OpenGl is just crapping its pants.
*/
matrix_loc := gl.GetUniformLocation(program, gl.GLString("MVP"))
dummy_matrix_loc := gl.GetUniformLocation(program, gl.GLString("dummy"))
if gl.GetError() != gl.NO_ERROR {
fmt.Println("Error get location") // Never happens.
}
if dummy_matrix_loc == -1 {
good_frames++ // Because is SHOULD fail.
} else {
bad_frames++ // That's not normal.
}
gl.UniformMatrix4fv(matrix_loc, 16, gl.TRUE, &MVP[0])
if gl.GetError() != gl.NO_ERROR {
fmt.Println("Error send matrix") // Never happens.
}
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
if gl.GetError() != gl.NO_ERROR {
fmt.Println("Error clearing") // Never happens.
}
gl.DrawArrays(gl.TRIANGLES, 0, 3)
if gl.GetError() != gl.NO_ERROR {
fmt.Println("Error drawing") // Never happens.
}
gl.Finish() // Does not seem to make anything work better.
sdl.GL_SwapBuffers()
}
func RotZ(angle float64) GoMatrix {
var gom GoMatrix
a := angle * DEG_TO_RAD
c := math.Cos(a)
s := math.Sin(a)
gom[0] = c
gom[1] = s
gom[4] = -s
gom[5] = c
gom[10] = 1
gom[15] = 1
return gom
}
func ToGlMatrix(gom GoMatrix) GlMatrix {
var glm GlMatrix
glm[0] = gl.Float(gom[0])
glm[1] = gl.Float(gom[1])
glm[2] = gl.Float(gom[2])
glm[3] = gl.Float(gom[3])
glm[4] = gl.Float(gom[4])
glm[5] = gl.Float(gom[5])
glm[6] = gl.Float(gom[6])
glm[7] = gl.Float(gom[7])
glm[8] = gl.Float(gom[8])
glm[9] = gl.Float(gom[9])
glm[10] = gl.Float(gom[10])
glm[11] = gl.Float(gom[11])
glm[12] = gl.Float(gom[12])
glm[13] = gl.Float(gom[13])
glm[14] = gl.Float(gom[14])
glm[15] = gl.Float(gom[15])
return glm
}
要求どおり、 の出力glxinfo
。
> glxinfo
name of display: :0
display: :0 screen: 0
direct rendering: Yes
server glx vendor string: ATI
server glx version string: 1.4
server glx extensions:
GLX_ARB_multisample, GLX_EXT_import_context, GLX_EXT_texture_from_pixmap,
GLX_EXT_visual_info, GLX_EXT_visual_rating, GLX_OML_swap_method,
GLX_SGI_make_current_read, GLX_SGI_swap_control, GLX_SGIS_multisample,
GLX_SGIX_fbconfig, GLX_SGIX_pbuffer, GLX_SGIX_visual_select_group
client glx vendor string: ATI
client glx version string: 1.4
client glx extensions:
GLX_ARB_create_context, GLX_ARB_create_context_profile,
GLX_ARB_get_proc_address, GLX_ARB_multisample, GLX_EXT_import_context,
GLX_EXT_visual_info, GLX_EXT_visual_rating, GLX_MESA_allocate_memory,
GLX_MESA_copy_sub_buffer, GLX_MESA_swap_control,
GLX_MESA_swap_frame_usage, GLX_NV_swap_group, GLX_OML_swap_method,
GLX_SGI_make_current_read, GLX_SGI_swap_control, GLX_SGI_video_sync,
GLX_SGIS_multisample, GLX_SGIX_fbconfig, GLX_SGIX_pbuffer,
GLX_SGIX_swap_barrier, GLX_SGIX_swap_group, GLX_SGIX_visual_select_group,
GLX_EXT_texture_from_pixmap, GLX_EXT_framebuffer_sRGB,
GLX_ARB_fbconfig_float, GLX_AMD_gpu_association
GLX version: 1.4
GLX extensions:
GLX_ARB_create_context, GLX_ARB_create_context_profile,
GLX_ARB_get_proc_address, GLX_ARB_multisample, GLX_EXT_import_context,
GLX_EXT_visual_info, GLX_EXT_visual_rating, GLX_MESA_swap_control,
GLX_NV_swap_group, GLX_OML_swap_method, GLX_SGI_make_current_read,
GLX_SGI_swap_control, GLX_SGI_video_sync, GLX_SGIS_multisample,
GLX_SGIX_fbconfig, GLX_SGIX_pbuffer, GLX_SGIX_swap_barrier,
GLX_SGIX_swap_group, GLX_SGIX_visual_select_group,
GLX_EXT_texture_from_pixmap
OpenGL vendor string: ATI Technologies Inc.
OpenGL renderer string: ATI Mobility Radeon HD 4500 Series
OpenGL version string: 3.3.11005 Compatibility Profile Context
OpenGL shading language version string: 3.30
OpenGL extensions:
GL_AMDX_debug_output, GL_AMDX_vertex_shader_tessellator,
GL_AMD_conservative_depth, GL_AMD_debug_output,
GL_AMD_depth_clamp_separate, GL_AMD_draw_buffers_blend,
GL_AMD_name_gen_delete, GL_AMD_performance_monitor, GL_AMD_pinned_memory,
GL_AMD_sample_positions, GL_AMD_seamless_cubemap_per_texture,
GL_AMD_shader_stencil_export, GL_AMD_texture_cube_map_array,
GL_AMD_texture_texture4, GL_AMD_vertex_shader_tessellator,
GL_ARB_ES2_compatibility, GL_ARB_blend_func_extended,
GL_ARB_color_buffer_float, GL_ARB_copy_buffer, GL_ARB_depth_buffer_float,
GL_ARB_depth_clamp, GL_ARB_depth_texture, GL_ARB_draw_buffers,
GL_ARB_draw_buffers_blend, GL_ARB_draw_elements_base_vertex,
GL_ARB_draw_instanced, GL_ARB_explicit_attrib_location,
GL_ARB_fragment_coord_conventions, GL_ARB_fragment_program,
GL_ARB_fragment_program_shadow, GL_ARB_fragment_shader,
GL_ARB_framebuffer_object, GL_ARB_framebuffer_sRGB,
GL_ARB_geometry_shader4, GL_ARB_get_program_binary,
GL_ARB_half_float_pixel, GL_ARB_half_float_vertex, GL_ARB_imaging,
GL_ARB_instanced_arrays, GL_ARB_map_buffer_range, GL_ARB_multisample,
GL_ARB_multitexture, GL_ARB_occlusion_query, GL_ARB_occlusion_query2,
GL_ARB_pixel_buffer_object, GL_ARB_point_parameters, GL_ARB_point_sprite,
GL_ARB_provoking_vertex, GL_ARB_sample_shading, GL_ARB_sampler_objects,
GL_ARB_seamless_cube_map, GL_ARB_separate_shader_objects,
GL_ARB_shader_bit_encoding, GL_ARB_shader_objects,
GL_ARB_shader_precision, GL_ARB_shader_stencil_export,
GL_ARB_shader_texture_lod, GL_ARB_shading_language_100, GL_ARB_shadow,
GL_ARB_shadow_ambient, GL_ARB_sync, GL_ARB_texture_border_clamp,
GL_ARB_texture_buffer_object, GL_ARB_texture_buffer_object_rgb32,
GL_ARB_texture_compression, GL_ARB_texture_compression_rgtc,
GL_ARB_texture_cube_map, GL_ARB_texture_cube_map_array,
GL_ARB_texture_env_add, GL_ARB_texture_env_combine,
GL_ARB_texture_env_crossbar, GL_ARB_texture_env_dot3,
GL_ARB_texture_float, GL_ARB_texture_gather,
GL_ARB_texture_mirrored_repeat, GL_ARB_texture_multisample,
GL_ARB_texture_non_power_of_two, GL_ARB_texture_query_lod,
GL_ARB_texture_rectangle, GL_ARB_texture_rg, GL_ARB_texture_rgb10_a2ui,
GL_ARB_texture_snorm, GL_ARB_timer_query, GL_ARB_transform_feedback2,
GL_ARB_transform_feedback3, GL_ARB_transpose_matrix,
GL_ARB_uniform_buffer_object, GL_ARB_vertex_array_bgra,
GL_ARB_vertex_array_object, GL_ARB_vertex_buffer_object,
GL_ARB_vertex_program, GL_ARB_vertex_shader,
GL_ARB_vertex_type_2_10_10_10_rev, GL_ARB_viewport_array,
GL_ARB_window_pos, GL_ATI_draw_buffers, GL_ATI_envmap_bumpmap,
GL_ATI_fragment_shader, GL_ATI_meminfo, GL_ATI_separate_stencil,
GL_ATI_texture_compression_3dc, GL_ATI_texture_env_combine3,
GL_ATI_texture_float, GL_ATI_texture_mirror_once, GL_EXT_abgr,
GL_EXT_bgra, GL_EXT_bindable_uniform, GL_EXT_blend_color,
GL_EXT_blend_equation_separate, GL_EXT_blend_func_separate,
GL_EXT_blend_minmax, GL_EXT_blend_subtract, GL_EXT_compiled_vertex_array,
GL_EXT_copy_buffer, GL_EXT_copy_texture, GL_EXT_direct_state_access,
GL_EXT_draw_buffers2, GL_EXT_draw_instanced, GL_EXT_draw_range_elements,
GL_EXT_fog_coord, GL_EXT_framebuffer_blit, GL_EXT_framebuffer_multisample,
GL_EXT_framebuffer_object, GL_EXT_framebuffer_sRGB,
GL_EXT_geometry_shader4, GL_EXT_gpu_program_parameters,
GL_EXT_gpu_shader4, GL_EXT_histogram, GL_EXT_multi_draw_arrays,
GL_EXT_packed_depth_stencil, GL_EXT_packed_float, GL_EXT_packed_pixels,
GL_EXT_pixel_buffer_object, GL_EXT_point_parameters,
GL_EXT_provoking_vertex, GL_EXT_rescale_normal, GL_EXT_secondary_color,
GL_EXT_separate_specular_color, GL_EXT_shadow_funcs, GL_EXT_stencil_wrap,
GL_EXT_subtexture, GL_EXT_texgen_reflection, GL_EXT_texture3D,
GL_EXT_texture_array, GL_EXT_texture_buffer_object,
GL_EXT_texture_compression_latc, GL_EXT_texture_compression_rgtc,
GL_EXT_texture_compression_s3tc, GL_EXT_texture_cube_map,
GL_EXT_texture_edge_clamp, GL_EXT_texture_env_add,
GL_EXT_texture_env_combine, GL_EXT_texture_env_dot3,
GL_EXT_texture_filter_anisotropic, GL_EXT_texture_integer,
GL_EXT_texture_lod, GL_EXT_texture_lod_bias, GL_EXT_texture_mirror_clamp,
GL_EXT_texture_object, GL_EXT_texture_rectangle, GL_EXT_texture_sRGB,
GL_EXT_texture_shared_exponent, GL_EXT_texture_snorm,
GL_EXT_texture_swizzle, GL_EXT_timer_query, GL_EXT_transform_feedback,
GL_EXT_vertex_array, GL_EXT_vertex_array_bgra,
GL_IBM_texture_mirrored_repeat, GL_KTX_buffer_region, GL_NV_blend_square,
GL_NV_conditional_render, GL_NV_copy_depth_to_color,
GL_NV_explicit_multisample, GL_NV_float_buffer, GL_NV_half_float,
GL_NV_primitive_restart, GL_NV_texgen_reflection, GL_NV_texture_barrier,
GL_SGIS_generate_mipmap, GL_SGIS_texture_edge_clamp, GL_SGIS_texture_lod,
GL_SUN_multi_draw_arrays, GL_WIN_swap_hint, WGL_EXT_swap_control
編集: メイン ループが原因のようです。OpenGl は問題ありませんが、ゴルーチンやチャネルに何か問題があります。
メインループをチャネルとゴルーチンに依存しないものに置き換えると、OpenGl は完全に動作します。
func Loop(program gl.Uint) {
start_time := time.Now()
stop_time := start_time.Add(time.Duration(30 * time.Second))
running := true
for running {
tick_time := time.Now()
OnTick(start_time, tick_time, program)
time.Sleep(10 * time.Millisecond)
if tick_time.After(stop_time) {
running = false
}
}
}
私の問題は、OpenGl がメインのゴルーチンにあり、チャネルがティックまたは SDL イベントを配信するのを待っている間にブロックするという事実に起因する可能性があります。わかりません、混乱しています。
タイトルを glGetUniformLocation から変更すると、存在しない属性に対して -1 ではなく 0 が返されることがよくあります。これは、メイン ループがチャネルのティックとイベントの配信を待機している間、OpenGl にスタックしているように見えます。