5

簡単な 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 にスタックしているように見えます。

4

1 に答える 1

3

この問題は、グラフィック ライブラリ SDL および OpenGl がスレッドの使用に制限を課しているという事実から生じます。Golang は、これらの制限を認識せずに、適切と思われるスレッド間でゴルーチンをシャッフルします。その結果、一部の呼び出しが失われ、予期しない動作が発生します。

OpenGl をメイン スレッドにロックすることで、ゴルーチンの使用をあきらめることなく、OpenGl を機能させることができました。

これは私が採用した解決策です: http://code.google.com/p/go-wiki/wiki/LockOSThread 関数にタイプミスがあることに注意してください:の代わりにdo読む必要があります。mainfuncch

私のメインファイルは次のようになります。

// Arrange that main.main runs on main thread.
func init() {
    runtime.LockOSThread()
}

// Queue of work to run in main thread.
var mainfunc = make(chan func())

// Run all the functions that need to run in the main thread.
func Main() {
    for f = range mainfunc {
        f()
    }
}

// Put the function f on the main thread function queue.
func do(f func()) {
    done := make(chan bool, 1)
    mainfunc <- func() {
        f()
        done <- true
    }
    <-done

// The real main function.
func main() {
    go Everything()
    Main()
}

// Your entire application comes here.
func Everything() {
    defer close(mainfunc)
    do(func(){
        // init SDL, OpenGl, all that.
    })
    defer sdl.Quit()

    var some_variable int // Starts at 0.
    do(func(){
        // OpenGl code
        some_variable = 42 // Closure allows for communication.
    })
    Loop(some_variable) // Now 42.
}
于 2013-02-07T16:21:28.130 に答える