【问题标题】:Win32 OpenGL Window in rust: unable to load certain function pointersWin32 OpenGL 窗口生锈:无法加载某些函数指针
【发布时间】:2018-02-28 03:23:05
【问题描述】:
#[cfg(windows)] extern crate winapi;

#[cfg(windows)] use winapi::shared::windef::HWND;
#[cfg(windows)] use winapi::shared::windef::HMENU;
#[cfg(windows)] use winapi::shared::windef::HBRUSH;
#[cfg(windows)] use winapi::shared::minwindef::HINSTANCE;

#[cfg(windows)] use winapi::shared::minwindef::UINT;
#[cfg(windows)] use winapi::shared::minwindef::DWORD;
#[cfg(windows)] use winapi::shared::minwindef::WPARAM;
#[cfg(windows)] use winapi::shared::minwindef::LPARAM;
#[cfg(windows)] use winapi::shared::minwindef::LRESULT;
#[cfg(windows)] use winapi::um::winnt::LPCWSTR;

#[cfg(windows)] use winapi::um::winuser::WS_OVERLAPPEDWINDOW;
#[cfg(windows)] use winapi::um::winuser::WS_VISIBLE;
#[cfg(windows)] use winapi::um::winuser::WNDCLASSW;

#[cfg(windows)] use std::os::windows::ffi::OsStrExt;
#[cfg(windows)] use std::ffi::OsStr;

#[cfg(windows)] use std::os::raw::c_void;
#[cfg(windows)] use winapi::um::libloaderapi::GetProcAddress;
#[cfg(windows)] use gl::types::*;

// Vertex data
static VERTEX_DATA: [GLfloat; 6] = [0.0, 0.5, 0.5, -0.5, -0.5, -0.5];

// Shader sources
static VS_SRC: &'static str = "
#version 150
in vec2 position;
void main() {
    gl_Position = vec4(position, 0.0, 1.0);
}";

static FS_SRC: &'static str = "
#version 150
out vec4 out_color;
void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
}";

mod gl
{
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

#[cfg(windows)]
fn to_wstring(str : &str) -> Vec<u16>
{
    let v : Vec<u16> =
            OsStr::new(str).encode_wide().chain(Some(0).into_iter()).collect();
    v
}

#[cfg(windows)]
pub unsafe extern "system" fn window_proc(h_wnd :HWND,
    msg :UINT, w_param :WPARAM, l_param :LPARAM) -> LRESULT
{
    if msg == winapi::um::winuser::WM_DESTROY {
        winapi::um::winuser::PostQuitMessage(0i32);
    }
    return winapi::um::winuser::DefWindowProcW(h_wnd, msg, w_param, l_param);
}

fn draw_gl_scene(window_width: i32, window_height: i32,
        h_dc: winapi::shared::windef::HDC)
{
    unsafe
    {
        let module = winapi::um::libloaderapi::LoadLibraryW(to_wstring("opengl32.dll")  .as_ptr());

        // gl::load_with(|s| GetProcAddress(module,
        //         s.as_ptr() as *const i8) as *const c_void);

        gl::Viewport::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        if gl::Viewport::is_loaded() {
            gl::Viewport(0, 0, window_width, window_height);
        } else {
            panic!("gl::Viewport was not loaded")
        }

        gl::ClearColor::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        if gl::ClearColor::is_loaded() {
            gl::ClearColor(0.12109375f32, 0.12109375f32, 0.12109375f32, 1.0f32);
        } else {
            panic!("gl::ClearColor was not loaded")
        }

        gl::GetError::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        let error_check_value: GLenum = gl::GetError();

        /*
        gl::CreateShader::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        let mut vertex_shader_id = 0u32;
        if gl::CreateShader::is_loaded() {
            vertex_shader_id = gl::CreateShader(gl::VERTEX_SHADER);
        } else {
            panic!("gl::CreateShader was not loaded")
        }
        */

        /*
        let c_str = std::ffi::CString::new(VS_SRC.as_bytes()).unwrap();
        gl::ShaderSource::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        if gl::ShaderSource::is_loaded() {
            gl::ShaderSource(vertex_shader_id, 1, &c_str.as_ptr(), std::ptr::null_mut());
        } else {
            // panic!("gl::ShaderSource was not loaded")
        }
        gl::CompileShader::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        if gl::CompileShader::is_loaded() {
            gl::CompileShader(vertex_shader_id);
        } else {
            // panic!("gl::CompileShader was not loaded")
        }
        let mut vertex_array_id: GLuint = 0u32;
        gl::GenVertexArrays::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        if gl::GenVertexArrays::is_loaded() {
            gl::GenVertexArrays(1, &mut vertex_array_id as *mut u32);
        } else {
            panic!("gl::GenVertexArrays was not loaded")
        }
        */

        gl::Clear::load_with(|s| GetProcAddress(module,
                s.as_ptr() as *const i8) as *const c_void);
        if gl::Clear::is_loaded() {
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT |     gl::STENCIL_BUFFER_BIT);
        } else {
            panic!("gl::Clear was not loaded")
        }
        winapi::um::wingdi::SwapBuffers(h_dc);
    }
}

fn main()
{
  unsafe
  {
    let class_name = to_wstring("OpenGL");

    let h_instance = winapi::um::libloaderapi::GetModuleHandleW(std::ptr::null_mut());
    let wnd = WNDCLASSW {
        style: 0,
        lpfnWndProc: Some(window_proc),
        cbClsExtra: 0,
        cbWndExtra: 0,
        hInstance: h_instance,
        hIcon: winapi::um::winuser::LoadIconW(0 as HINSTANCE,
                                              winapi::um::winuser::IDI_APPLICATION),
        hCursor: winapi::um::winuser::LoadCursorW(0 as HINSTANCE,
                                                  winapi::um::winuser::IDI_APPLICATION),
        hbrBackground: 16 as HBRUSH,
        lpszMenuName: 0 as LPCWSTR,
        lpszClassName: class_name.as_ptr(),
    };

    winapi::um::winuser::RegisterClassW(&wnd);

    let window_width = 640;
    let window_height = 480;
    let h_wnd_window = winapi::um::winuser::CreateWindowExW(0, class_name.as_ptr(),
                       to_wstring("OpenGL Example").as_ptr(), WS_OVERLAPPEDWINDOW |     WS_VISIBLE,
                       0, 0, window_width, window_height, 0 as HWND, 0 as HMENU,    h_instance,
                       std::ptr::null_mut());

    let mut msg = winapi::um::winuser::MSG {
        hwnd : 0 as HWND,
        message : 0 as UINT,
        wParam : 0 as WPARAM,
        lParam : 0 as LPARAM,
        time : 0 as DWORD,
        pt : winapi::shared::windef::POINT { x: 0, y: 0, },
    };

    let h_dc = winapi::um::winuser::GetDC(h_wnd_window);
    let pfd = winapi::um::wingdi::PIXELFORMATDESCRIPTOR {
        nSize: std::mem::size_of::<winapi::um::wingdi::PIXELFORMATDESCRIPTOR>() as u16,
        nVersion: 1,
        dwFlags: winapi::um::wingdi::PFD_DRAW_TO_WINDOW
                | winapi::um::wingdi::PFD_SUPPORT_OPENGL |  winapi::um::wingdi::PFD_DOUBLEBUFFER,
        iPixelType: winapi::um::wingdi::PFD_TYPE_RGBA,
        cColorBits: 64,
        cRedBits: 0,
        cRedShift: 0,
        cGreenBits: 0,
        cGreenShift: 0,
        cBlueBits: 0,
        cBlueShift: 0,
        cAlphaBits: 0,
        cAlphaShift: 0,
        cAccumBits: 0,
        cAccumRedBits: 0,
        cAccumGreenBits: 0,
        cAccumBlueBits: 0,
        cAccumAlphaBits: 0,
        cDepthBits: 32,
        cStencilBits: 8,
        cAuxBuffers: 0,
        iLayerType: winapi::um::wingdi::PFD_MAIN_PLANE,
        bReserved: 0,
        dwLayerMask: 0,
        dwVisibleMask: 0,
        dwDamageMask: 0,
    };

    let pixel_format = winapi::um::wingdi::ChoosePixelFormat(h_dc,
            &pfd as *const winapi::um::wingdi::PIXELFORMATDESCRIPTOR);
    winapi::um::wingdi::SetPixelFormat(h_dc, pixel_format,
            &pfd as *const winapi::um::wingdi::PIXELFORMATDESCRIPTOR);
    let h_rc = winapi::um::wingdi::wglCreateContext(h_dc);
    winapi::um::wingdi::wglMakeCurrent(h_dc, h_rc);
    winapi::um::winuser::ShowWindow(h_wnd_window, winapi::um::winuser::SW_SHOW);

    loop
    {
        if winapi::um::winuser::PeekMessageW(&mut msg, 0u32 as HWND, 0u32, 0u32,
                                             winapi::um::winuser::PM_REMOVE) > 0i32 {
            if msg.message == winapi::um::winuser::WM_QUIT {
                break;
            } else {
                winapi::um::winuser::TranslateMessage(&mut msg);
                winapi::um::winuser::DispatchMessageW(&mut msg);
            }

        } else {
            draw_gl_scene(window_width, window_height, h_dc);
        }
    }
  }
}

上面的代码是我执行的过时项目的版本,位于:https://www.codeproject.com/tips/1053658/win-gui-programming-in-rust-language/

使用最新版本的 winapi 和 gl_generator 作为唯一的两个依赖项,我扩展了启动代码以成功地呈现与 Win32 API 串联的 OpenGL 上下文,而不是货物箱 gl 的贡献者所建议的 glfw -rs。在 Windows 机器上运行时,该项目原样呈现黑屏,如 this link.

到目前为止,由于无法加载与着色器或顶点缓冲区对象相关的任何函数指针,任何进一步渲染更实质性内容的尝试都没有结果。

如果你梳理函数 draw_gl_scene,你会发现我有一个通用的“load_with”函数被注释掉了,还有一系列特定于函数的“load_with”函数以及执行代码或恐慌,具体取决于所讨论的函数“ is_loaded”。在编写特定于函数的“load-with”函数之前,我暂时限制了通用的“load_with”。

对于 CreateShader、ShaderSource、CompileShader 和 GenVertexArrays,如果我取消注释它们中的任何一个,它们都不会成功加载。我确定这是一个用户错误,winapi 和 gl-rs 之一或 winapi 和 gl_generator 之间的异常交互的可能性不大。我对如何解决这个问题束手无策。如果您读到这里,我很感激您抽出宝贵的时间。

【问题讨论】:

  • @ChrisBecke 这里的语言选择不太可能成为问题。没有理由如此不屑一顾。
  • 您的消息循环实现不太理想。它在渲染帧之间最多处理一条消息。现在这不是问题,但是一旦渲染帧成为一项昂贵的操作,您将观察到应用程序响应缓慢,因为消息的生成速度比它们发送的速度快。

标签: winapi opengl rust


【解决方案1】:

阅读 wikithis too 关于加载 OGL 指针的内容。

简而言之,对于 Windows:

  • GetProcAddress 仅对 OpenGL 有效
  • wglGetProcAddress 仅对 OpenGL > 1.1 有效

此外,使用着色器需要 OpenGL >= 2.0。最好使用 OGL >= 3.2 Core Profile。对于这种情况:

  • 您需要一个适合 OpenGL >= 3.0 的上下文,它是使用 wglCreateContextAttribsARB 创建的。
  • 您需要一个有效的当前上下文来获取指向 wglCreateContextAttribsARB 本身的指针,方法是使用 wglGetProcAddress
  • 此上下文可能是临时的。它可以使用wglCreateContext 创建。获得该指针后,您可以将其删除;并创建“真实”上下文。

.

【讨论】:

  • 感谢您的信息。在彻底阅读了这些材料之后,我了解到我将过去所学的内容与 OpenGL 2.x 教程与 gl_generator 默认的版本(即 4.3 版)混为一谈。此外,某些加载函数成功加载而其他加载函数未成功加载的原因是因为 GetProcAddress 对于源自 OpenGL
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-07
  • 2015-09-26
  • 1970-01-01
  • 2018-07-08
  • 2011-10-26
  • 1970-01-01
  • 2015-11-24
相关资源
最近更新 更多