use super::device::{DCGuard, Device, HiddenWindow};
use super::surface::{Surface, Win32Objects};
use crate::context::{self, CREATE_CONTEXT_MUTEX};
use crate::surface::Framebuffer;
use crate::{ContextAttributeFlags, ContextAttributes, ContextID, Error, GLVersion};
use crate::{SurfaceInfo, WindowingApiError};
use crate::gl;
type GLenum = c_uint;
type GLint = c_int;
type GLuint = c_uint;
use crate::Gl;
use glow::HasContext;
use std::borrow::Cow;
use std::ffi::{CStr, CString};
use std::mem;
use std::os::raw::{c_char, c_int, c_uint, c_void};
use std::ptr;
use std::sync::LazyLock;
use std::thread;
use winapi::shared::minwindef::{BOOL, FALSE, FLOAT, HMODULE, LPARAM, LPVOID, LRESULT, UINT};
use winapi::shared::minwindef::{WORD, WPARAM};
use winapi::shared::ntdef::{HANDLE, LPCSTR};
use winapi::shared::windef::{HBRUSH, HDC, HGLRC, HWND};
use winapi::um::libloaderapi;
use winapi::um::wingdi::{self, PFD_DOUBLEBUFFER, PFD_DRAW_TO_WINDOW, PFD_MAIN_PLANE};
use winapi::um::wingdi::{wglCreateContext, wglDeleteContext, wglGetCurrentContext};
use winapi::um::wingdi::{wglGetCurrentDC, wglGetProcAddress, wglMakeCurrent};
use winapi::um::wingdi::{PFD_SUPPORT_OPENGL, PFD_TYPE_RGBA, PIXELFORMATDESCRIPTOR};
use winapi::um::winuser::{self, COLOR_BACKGROUND, CREATESTRUCTA, CS_OWNDC, WM_CREATE, WNDCLASSA};
use winapi::um::winuser::{WS_OVERLAPPEDWINDOW, WS_VISIBLE};
const WGL_DRAW_TO_WINDOW_ARB: GLenum = 0x2001;
const WGL_ACCELERATION_ARB: GLenum = 0x2003;
const WGL_SUPPORT_OPENGL_ARB: GLenum = 0x2010;
const WGL_DOUBLE_BUFFER_ARB: GLenum = 0x2011;
const WGL_PIXEL_TYPE_ARB: GLenum = 0x2013;
const WGL_COLOR_BITS_ARB: GLenum = 0x2014;
const WGL_ALPHA_BITS_ARB: GLenum = 0x201b;
const WGL_DEPTH_BITS_ARB: GLenum = 0x2022;
const WGL_STENCIL_BITS_ARB: GLenum = 0x2023;
const WGL_FULL_ACCELERATION_ARB: GLenum = 0x2027;
const WGL_TYPE_RGBA_ARB: GLenum = 0x202b;
const WGL_CONTEXT_MAJOR_VERSION_ARB: GLenum = 0x2091;
const WGL_CONTEXT_MINOR_VERSION_ARB: GLenum = 0x2092;
const WGL_CONTEXT_PROFILE_MASK_ARB: GLenum = 0x9126;
const WGL_CONTEXT_CORE_PROFILE_BIT_ARB: GLenum = 0x00000001;
const WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: GLenum = 0x00000002;
#[allow(non_snake_case)]
#[derive(Default)]
pub(crate) struct WGLExtensionFunctions {
CreateContextAttribsARB: Option<
unsafe extern "C" fn(hDC: HDC, shareContext: HGLRC, attribList: *const c_int) -> HGLRC,
>,
GetExtensionsStringARB: Option<unsafe extern "C" fn(hdc: HDC) -> *const c_char>,
pub(crate) pixel_format_functions: Option<WGLPixelFormatExtensionFunctions>,
pub(crate) dx_interop_functions: Option<WGLDXInteropExtensionFunctions>,
}
#[allow(non_snake_case)]
pub(crate) struct WGLPixelFormatExtensionFunctions {
ChoosePixelFormatARB: unsafe extern "C" fn(
hdc: HDC,
piAttribIList: *const c_int,
pfAttribFList: *const FLOAT,
nMaxFormats: UINT,
piFormats: *mut c_int,
nNumFormats: *mut UINT,
) -> BOOL,
GetPixelFormatAttribivARB: unsafe extern "C" fn(
hdc: HDC,
iPixelFormat: c_int,
iLayerPlane: c_int,
nAttributes: UINT,
piAttributes: *const c_int,
piValues: *mut c_int,
) -> BOOL,
}
#[allow(non_snake_case)]
pub(crate) struct WGLDXInteropExtensionFunctions {
pub(crate) DXCloseDeviceNV: unsafe extern "C" fn(hDevice: HANDLE) -> BOOL,
pub(crate) DXLockObjectsNV:
unsafe extern "C" fn(hDevice: HANDLE, count: GLint, hObjects: *mut HANDLE) -> BOOL,
pub(crate) DXOpenDeviceNV: unsafe extern "C" fn(dxDevice: *mut c_void) -> HANDLE,
pub(crate) DXRegisterObjectNV: unsafe extern "C" fn(
hDevice: HANDLE,
dxResource: *mut c_void,
name: GLuint,
object_type: GLenum,
access: GLenum,
) -> HANDLE,
pub(crate) DXSetResourceShareHandleNV:
unsafe extern "C" fn(dxResource: *mut c_void, shareHandle: HANDLE) -> BOOL,
pub(crate) DXUnlockObjectsNV:
unsafe extern "C" fn(hDevice: HANDLE, count: GLint, hObjects: *mut HANDLE) -> BOOL,
pub(crate) DXUnregisterObjectNV: unsafe extern "C" fn(hDevice: HANDLE, hObject: HANDLE) -> BOOL,
}
#[derive(Clone)]
pub struct ContextDescriptor {
pixel_format: c_int,
gl_version: GLVersion,
compatibility_profile: bool,
}
pub struct Context {
pub(crate) glrc: HGLRC,
pub(crate) id: ContextID,
pub(crate) gl: Gl,
hidden_window: Option<HiddenWindow>,
pub(crate) framebuffer: Framebuffer<Surface, ()>,
status: ContextStatus,
}
#[derive(Clone, Copy, Debug, PartialEq)]
enum ContextStatus {
Owned,
Referenced,
Destroyed,
}
#[derive(Clone)]
pub struct NativeContext(pub HGLRC);
thread_local! {
static OPENGL_LIBRARY: HMODULE = {
unsafe {
libloaderapi::LoadLibraryA(c"opengl32.dll".as_ptr())
}
};
}
pub(crate) static WGL_EXTENSION_FUNCTIONS: LazyLock<WGLExtensionFunctions> =
LazyLock::new(|| thread::spawn(extension_loader_thread).join().unwrap());
impl Device {
#[allow(non_snake_case)]
pub fn create_context_descriptor(
&self,
attributes: &ContextAttributes,
) -> Result<ContextDescriptor, Error> {
let flags = attributes.flags;
let alpha_bits = if flags.contains(ContextAttributeFlags::ALPHA) {
8
} else {
0
};
let depth_bits = if flags.contains(ContextAttributeFlags::DEPTH) {
24
} else {
0
};
let stencil_bits = if flags.contains(ContextAttributeFlags::STENCIL) {
8
} else {
0
};
let compatibility_profile = flags.contains(ContextAttributeFlags::COMPATIBILITY_PROFILE);
let attrib_i_list = [
WGL_DRAW_TO_WINDOW_ARB as c_int,
gl::TRUE as c_int,
WGL_SUPPORT_OPENGL_ARB as c_int,
gl::TRUE as c_int,
WGL_DOUBLE_BUFFER_ARB as c_int,
gl::TRUE as c_int,
WGL_PIXEL_TYPE_ARB as c_int,
WGL_TYPE_RGBA_ARB as c_int,
WGL_ACCELERATION_ARB as c_int,
WGL_FULL_ACCELERATION_ARB as c_int,
WGL_COLOR_BITS_ARB as c_int,
32,
WGL_ALPHA_BITS_ARB as c_int,
alpha_bits,
WGL_DEPTH_BITS_ARB as c_int,
depth_bits,
WGL_STENCIL_BITS_ARB as c_int,
stencil_bits,
0,
];
let wglChoosePixelFormatARB = match WGL_EXTENSION_FUNCTIONS.pixel_format_functions {
None => return Err(Error::RequiredExtensionUnavailable),
Some(ref pixel_format_functions) => pixel_format_functions.ChoosePixelFormatARB,
};
let hidden_window_dc = self.hidden_window.get_dc();
unsafe {
let (mut pixel_format, mut pixel_format_count) = (0, 0);
let ok = wglChoosePixelFormatARB(
hidden_window_dc.dc,
attrib_i_list.as_ptr(),
ptr::null(),
1,
&mut pixel_format,
&mut pixel_format_count,
);
if ok == FALSE {
return Err(Error::PixelFormatSelectionFailed(WindowingApiError::Failed));
}
if pixel_format_count == 0 {
return Err(Error::NoPixelFormatFound);
}
Ok(ContextDescriptor {
pixel_format,
gl_version: attributes.version,
compatibility_profile,
})
}
}
#[allow(non_snake_case)]
pub fn create_context(
&self,
descriptor: &ContextDescriptor,
share_with: Option<&Context>,
) -> Result<Context, Error> {
let wglCreateContextAttribsARB = match WGL_EXTENSION_FUNCTIONS.CreateContextAttribsARB {
None => return Err(Error::RequiredExtensionUnavailable),
Some(wglCreateContextAttribsARB) => wglCreateContextAttribsARB,
};
let mut next_context_id = CREATE_CONTEXT_MUTEX.lock().unwrap();
unsafe {
let (glrc, gl);
let hidden_window = HiddenWindow::new();
{
let hidden_window_dc = hidden_window.get_dc();
let dc = hidden_window_dc.dc;
set_dc_pixel_format(dc, descriptor.pixel_format);
let profile_mask = if descriptor.compatibility_profile {
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
} else {
WGL_CONTEXT_CORE_PROFILE_BIT_ARB
};
let wgl_attributes = [
WGL_CONTEXT_MAJOR_VERSION_ARB as c_int,
descriptor.gl_version.major as c_int,
WGL_CONTEXT_MINOR_VERSION_ARB as c_int,
descriptor.gl_version.minor as c_int,
WGL_CONTEXT_PROFILE_MASK_ARB as c_int,
profile_mask as c_int,
0,
];
glrc = wglCreateContextAttribsARB(
dc,
share_with.map_or(ptr::null_mut(), |ctx| ctx.glrc),
wgl_attributes.as_ptr(),
);
if glrc.is_null() {
return Err(Error::ContextCreationFailed(WindowingApiError::Failed));
}
let _guard = CurrentContextGuard::new();
let ok = wglMakeCurrent(dc, glrc);
assert_ne!(ok, FALSE);
gl = Gl::from_loader_function(get_proc_address);
}
let context = Context {
glrc,
id: *next_context_id,
gl,
hidden_window: Some(hidden_window),
framebuffer: Framebuffer::None,
status: ContextStatus::Owned,
};
next_context_id.0 += 1;
Ok(context)
}
}
pub unsafe fn create_context_from_native_context(
&self,
native_context: NativeContext,
) -> Result<Context, Error> {
let mut next_context_id = CREATE_CONTEXT_MUTEX.lock().unwrap();
let hidden_window = HiddenWindow::new();
let gl = {
let hidden_window_dc = hidden_window.get_dc();
let dc = hidden_window_dc.dc;
let _guard = CurrentContextGuard::new();
let ok = wglMakeCurrent(dc, native_context.0);
assert_ne!(ok, FALSE);
Gl::from_loader_function(get_proc_address)
};
let context = Context {
glrc: native_context.0,
id: *next_context_id,
gl,
hidden_window: Some(hidden_window),
framebuffer: Framebuffer::External(()),
status: ContextStatus::Referenced,
};
next_context_id.0 += 1;
Ok(context)
}
pub fn destroy_context(&self, context: &mut Context) -> Result<(), Error> {
if context.status == ContextStatus::Destroyed {
return Ok(());
}
if let Ok(Some(mut surface)) = self.unbind_surface_from_context(context) {
self.destroy_surface(context, &mut surface)?;
}
unsafe {
if wglGetCurrentContext() == context.glrc {
wglMakeCurrent(ptr::null_mut(), ptr::null_mut());
}
if context.status == ContextStatus::Owned {
wglDeleteContext(context.glrc);
}
}
context.glrc = ptr::null_mut();
context.status = ContextStatus::Destroyed;
Ok(())
}
pub fn context_descriptor(&self, context: &Context) -> ContextDescriptor {
unsafe {
let dc_guard = self.get_context_dc(context);
let pixel_format = wingdi::GetPixelFormat(dc_guard.dc);
let _guard = self.temporarily_make_context_current(context);
let gl_version = GLVersion::current(&context.gl);
let compatibility_profile =
context::current_context_uses_compatibility_profile(&context.gl);
ContextDescriptor {
pixel_format,
gl_version,
compatibility_profile,
}
}
}
#[allow(non_snake_case)]
pub fn context_descriptor_attributes(
&self,
context_descriptor: &ContextDescriptor,
) -> ContextAttributes {
let wglGetPixelFormatAttribivARB = WGL_EXTENSION_FUNCTIONS
.pixel_format_functions
.as_ref()
.expect(
"How did you make a context descriptor without \
pixel format extensions?",
)
.GetPixelFormatAttribivARB;
let dc_guard = self.hidden_window.get_dc();
unsafe {
let attrib_name_i_list = [
WGL_ALPHA_BITS_ARB as c_int,
WGL_DEPTH_BITS_ARB as c_int,
WGL_STENCIL_BITS_ARB as c_int,
];
let mut attrib_value_i_list = [0; 3];
let ok = wglGetPixelFormatAttribivARB(
dc_guard.dc,
context_descriptor.pixel_format,
0,
attrib_name_i_list.len() as UINT,
attrib_name_i_list.as_ptr(),
attrib_value_i_list.as_mut_ptr(),
);
assert_ne!(ok, FALSE);
let (alpha_bits, depth_bits, stencil_bits) = (
attrib_value_i_list[0],
attrib_value_i_list[1],
attrib_value_i_list[2],
);
let mut attributes = ContextAttributes {
version: context_descriptor.gl_version,
flags: ContextAttributeFlags::empty(),
};
if alpha_bits > 0 {
attributes.flags.insert(ContextAttributeFlags::ALPHA);
}
if depth_bits > 0 {
attributes.flags.insert(ContextAttributeFlags::DEPTH);
}
if stencil_bits > 0 {
attributes.flags.insert(ContextAttributeFlags::STENCIL);
}
attributes
}
}
pub(crate) fn temporarily_bind_framebuffer<'a>(
&self,
context: &'a Context,
framebuffer: Option<glow::Framebuffer>,
) -> FramebufferGuard<'a> {
unsafe {
let guard = FramebufferGuard::new(context);
context.gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer);
guard
}
}
pub(crate) fn temporarily_make_context_current(
&self,
context: &Context,
) -> Result<CurrentContextGuard, Error> {
let guard = CurrentContextGuard::new();
self.make_context_current(context)?;
Ok(guard)
}
pub fn make_context_current(&self, context: &Context) -> Result<(), Error> {
unsafe {
let dc_guard = self.get_context_dc(context);
let ok = wglMakeCurrent(dc_guard.dc, context.glrc);
if ok != FALSE {
Ok(())
} else {
Err(Error::MakeCurrentFailed(WindowingApiError::Failed))
}
}
}
#[inline]
pub fn make_no_context_current(&self) -> Result<(), Error> {
unsafe {
let ok = wglMakeCurrent(ptr::null_mut(), ptr::null_mut());
if ok != FALSE {
Ok(())
} else {
Err(Error::MakeCurrentFailed(WindowingApiError::Failed))
}
}
}
#[inline]
pub fn get_proc_address(&self, _: &Context, symbol_name: &str) -> *const c_void {
get_proc_address(symbol_name)
}
#[inline]
fn context_is_current(&self, context: &Context) -> bool {
unsafe { wglGetCurrentContext() == context.glrc }
}
pub fn bind_surface_to_context(
&self,
context: &mut Context,
surface: Surface,
) -> Result<(), (Error, Surface)> {
if context.id != surface.context_id {
return Err((Error::IncompatibleSurface, surface));
}
match context.framebuffer {
Framebuffer::None => {}
Framebuffer::External(()) => return Err((Error::ExternalRenderTarget, surface)),
Framebuffer::Surface(_) => return Err((Error::SurfaceAlreadyBound, surface)),
}
let is_current = self.context_is_current(context);
self.lock_surface(&surface);
context.framebuffer = Framebuffer::Surface(surface);
if is_current {
drop(self.make_context_current(context));
}
Ok(())
}
pub fn unbind_surface_from_context(
&self,
context: &mut Context,
) -> Result<Option<Surface>, Error> {
match mem::replace(&mut context.framebuffer, Framebuffer::None) {
Framebuffer::Surface(surface) => {
self.unlock_surface(&surface);
Ok(Some(surface))
}
Framebuffer::External(()) => Err(Error::ExternalRenderTarget),
Framebuffer::None => Ok(None),
}
}
pub(crate) fn get_context_dc<'a>(&self, context: &'a Context) -> DCGuard<'a> {
unsafe {
match context.framebuffer {
Framebuffer::Surface(Surface {
win32_objects: Win32Objects::Widget { window_handle },
..
}) => DCGuard::new(winuser::GetDC(window_handle), Some(window_handle)),
Framebuffer::Surface(Surface {
win32_objects: Win32Objects::Texture { .. },
..
})
| Framebuffer::External(())
| Framebuffer::None => context.hidden_window.as_ref().unwrap().get_dc(),
}
}
}
#[inline]
pub fn context_id(&self, context: &Context) -> ContextID {
context.id
}
pub fn context_surface_info(&self, context: &Context) -> Result<Option<SurfaceInfo>, Error> {
match context.framebuffer {
Framebuffer::None => Ok(None),
Framebuffer::External(()) => Err(Error::ExternalRenderTarget),
Framebuffer::Surface(ref surface) => Ok(Some(self.surface_info(surface))),
}
}
#[inline]
pub fn native_context(&self, context: &Context) -> NativeContext {
NativeContext(context.glrc)
}
}
impl NativeContext {
#[inline]
pub fn current() -> Result<NativeContext, Error> {
unsafe {
let glrc = wglGetCurrentContext();
if glrc != ptr::null_mut() {
Ok(NativeContext(glrc))
} else {
Err(Error::NoCurrentContext)
}
}
}
}
fn extension_loader_thread() -> WGLExtensionFunctions {
unsafe {
let instance = libloaderapi::GetModuleHandleA(ptr::null_mut());
let window_class_name = c"SurfmanFalseWindow".as_ptr();
let window_class = WNDCLASSA {
style: CS_OWNDC,
lpfnWndProc: Some(extension_loader_window_proc),
cbClsExtra: 0,
cbWndExtra: 0,
hInstance: instance,
hIcon: ptr::null_mut(),
hCursor: ptr::null_mut(),
hbrBackground: COLOR_BACKGROUND as HBRUSH,
lpszMenuName: ptr::null_mut(),
lpszClassName: window_class_name,
};
let window_class_atom = winuser::RegisterClassA(&window_class);
assert_ne!(window_class_atom, 0);
let mut extension_functions = WGLExtensionFunctions::default();
let lpClassName = window_class_atom as LPCSTR;
let window = winuser::CreateWindowExA(
0,
lpClassName,
window_class_name,
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0,
0,
640,
480,
ptr::null_mut(),
ptr::null_mut(),
instance,
&mut extension_functions as *mut WGLExtensionFunctions as LPVOID,
);
winuser::DestroyWindow(window);
extension_functions
}
}
#[allow(non_snake_case)]
extern "system" fn extension_loader_window_proc(
hwnd: HWND,
uMsg: UINT,
wParam: WPARAM,
lParam: LPARAM,
) -> LRESULT {
unsafe {
match uMsg {
WM_CREATE => {
let pixel_format_descriptor = PIXELFORMATDESCRIPTOR {
nSize: mem::size_of::<PIXELFORMATDESCRIPTOR>() as WORD,
nVersion: 1,
dwFlags: PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
iPixelType: PFD_TYPE_RGBA,
cColorBits: 32,
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: 24,
cStencilBits: 8,
cAuxBuffers: 0,
iLayerType: PFD_MAIN_PLANE,
bReserved: 0,
dwLayerMask: 0,
dwVisibleMask: 0,
dwDamageMask: 0,
};
let dc = winuser::GetDC(hwnd);
let pixel_format = wingdi::ChoosePixelFormat(dc, &pixel_format_descriptor);
assert_ne!(pixel_format, 0);
let mut ok = wingdi::SetPixelFormat(dc, pixel_format, &pixel_format_descriptor);
assert_ne!(ok, FALSE);
let gl_context = wglCreateContext(dc);
assert!(!gl_context.is_null());
ok = wglMakeCurrent(dc, gl_context);
assert_ne!(ok, FALSE);
let create_struct = lParam as *mut CREATESTRUCTA;
let wgl_extension_functions =
(*create_struct).lpCreateParams as *mut WGLExtensionFunctions;
(*wgl_extension_functions).GetExtensionsStringARB =
mem::transmute(wglGetProcAddress(c"wglGetExtensionsStringARB".as_ptr()));
let extensions = match (*wgl_extension_functions).GetExtensionsStringARB {
Some(wglGetExtensionsStringARB) => {
CStr::from_ptr(wglGetExtensionsStringARB(dc)).to_string_lossy()
}
None => Cow::Borrowed(""),
};
for extension in extensions.split(' ') {
if extension == "WGL_ARB_pixel_format" {
(*wgl_extension_functions).pixel_format_functions =
Some(WGLPixelFormatExtensionFunctions {
ChoosePixelFormatARB: mem::transmute(wglGetProcAddress(
c"wglChoosePixelFormatARB".as_ptr(),
)),
GetPixelFormatAttribivARB: mem::transmute(wglGetProcAddress(
c"wglGetPixelFormatAttribivARB".as_ptr(),
)),
});
continue;
}
if extension == "WGL_ARB_create_context" {
(*wgl_extension_functions).CreateContextAttribsARB = mem::transmute(
wglGetProcAddress(c"wglCreateContextAttribsARB".as_ptr()),
);
continue;
}
if extension == "WGL_NV_DX_interop" {
(*wgl_extension_functions).dx_interop_functions =
Some(WGLDXInteropExtensionFunctions {
DXCloseDeviceNV: mem::transmute(wglGetProcAddress(
c"wglDXCloseDeviceNV".as_ptr(),
)),
DXLockObjectsNV: mem::transmute(wglGetProcAddress(
c"wglDXLockObjectsNV".as_ptr(),
)),
DXOpenDeviceNV: mem::transmute(wglGetProcAddress(
c"wglDXOpenDeviceNV".as_ptr(),
)),
DXRegisterObjectNV: mem::transmute(wglGetProcAddress(
c"wglDXRegisterObjectNV".as_ptr(),
)),
DXSetResourceShareHandleNV: mem::transmute(wglGetProcAddress(
c"wglDXSetResourceShareHandleNV".as_ptr(),
)),
DXUnlockObjectsNV: mem::transmute(wglGetProcAddress(
c"wglDXUnlockObjectsNV".as_ptr(),
)),
DXUnregisterObjectNV: mem::transmute(wglGetProcAddress(
c"wglDXUnregisterObjectNV".as_ptr(),
)),
});
continue;
}
}
wglDeleteContext(gl_context);
0
}
_ => winuser::DefWindowProcA(hwnd, uMsg, wParam, lParam),
}
}
}
#[must_use]
pub(crate) struct FramebufferGuard<'a> {
context: &'a Context,
old_read_framebuffer: Option<glow::Framebuffer>,
old_draw_framebuffer: Option<glow::Framebuffer>,
}
impl<'a> Drop for FramebufferGuard<'a> {
#[inline]
fn drop(&mut self) {
unsafe {
self.context
.gl
.bind_framebuffer(gl::READ_FRAMEBUFFER, self.old_read_framebuffer);
self.context
.gl
.bind_framebuffer(gl::DRAW_FRAMEBUFFER, self.old_draw_framebuffer);
}
}
}
impl<'a> FramebufferGuard<'a> {
fn new(context: &'a Context) -> FramebufferGuard<'a> {
unsafe {
let current_draw_framebuffer = context
.gl
.get_parameter_framebuffer(gl::DRAW_FRAMEBUFFER_BINDING);
let current_read_framebuffer = context
.gl
.get_parameter_framebuffer(gl::READ_FRAMEBUFFER_BINDING);
FramebufferGuard {
context,
old_draw_framebuffer: current_draw_framebuffer,
old_read_framebuffer: current_read_framebuffer,
}
}
}
}
#[must_use]
pub(crate) struct CurrentContextGuard {
old_dc: HDC,
old_glrc: HGLRC,
}
impl Drop for CurrentContextGuard {
#[inline]
fn drop(&mut self) {
unsafe {
wglMakeCurrent(self.old_dc, self.old_glrc);
}
}
}
impl CurrentContextGuard {
#[inline]
fn new() -> CurrentContextGuard {
unsafe {
CurrentContextGuard {
old_dc: wglGetCurrentDC(),
old_glrc: wglGetCurrentContext(),
}
}
}
}
fn get_proc_address(symbol_name: &str) -> *const c_void {
unsafe {
let symbol_name: CString = CString::new(symbol_name).unwrap();
let symbol_ptr = symbol_name.as_ptr();
let addr = wglGetProcAddress(symbol_ptr) as *const c_void;
if !addr.is_null() {
return addr;
}
OPENGL_LIBRARY.with(|opengl_library| {
libloaderapi::GetProcAddress(*opengl_library, symbol_ptr) as *const c_void
})
}
}
pub(crate) fn set_dc_pixel_format(dc: HDC, pixel_format: c_int) {
unsafe {
let mut pixel_format_descriptor = mem::zeroed();
let pixel_format_count = wingdi::DescribePixelFormat(
dc,
pixel_format,
mem::size_of::<PIXELFORMATDESCRIPTOR>() as UINT,
&mut pixel_format_descriptor,
);
assert_ne!(pixel_format_count, 0);
let ok = wingdi::SetPixelFormat(dc, pixel_format, &mut pixel_format_descriptor);
assert_ne!(ok, FALSE);
}
}