Skip to content

Commit 45e29b4

Browse files
committed
Add the entire tree from raw-gl-handle
Including @prokopyl's PR that adds more X11 error handling: micahrj/raw-gl-context#15 Commit: prokopyl@raw-gl-context@98cd3cf1104ee254a67e3fed30e4e6b2ae2b6821 (with `cargo fmt`) Branch base: b68a05b
1 parent d76b02d commit 45e29b4

5 files changed

Lines changed: 921 additions & 0 deletions

File tree

src/gl/lib.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use raw_window_handle::HasRawWindowHandle;
2+
3+
use std::ffi::c_void;
4+
use std::marker::PhantomData;
5+
6+
#[cfg(target_os = "windows")]
7+
mod win;
8+
#[cfg(target_os = "windows")]
9+
use win as platform;
10+
11+
#[cfg(target_os = "linux")]
12+
mod x11;
13+
#[cfg(target_os = "linux")]
14+
use crate::x11 as platform;
15+
16+
#[cfg(target_os = "macos")]
17+
mod macos;
18+
#[cfg(target_os = "macos")]
19+
use macos as platform;
20+
21+
#[derive(Clone, Debug)]
22+
pub struct GlConfig {
23+
pub version: (u8, u8),
24+
pub profile: Profile,
25+
pub red_bits: u8,
26+
pub blue_bits: u8,
27+
pub green_bits: u8,
28+
pub alpha_bits: u8,
29+
pub depth_bits: u8,
30+
pub stencil_bits: u8,
31+
pub samples: Option<u8>,
32+
pub srgb: bool,
33+
pub double_buffer: bool,
34+
pub vsync: bool,
35+
}
36+
37+
impl Default for GlConfig {
38+
fn default() -> Self {
39+
GlConfig {
40+
version: (3, 2),
41+
profile: Profile::Core,
42+
red_bits: 8,
43+
blue_bits: 8,
44+
green_bits: 8,
45+
alpha_bits: 8,
46+
depth_bits: 24,
47+
stencil_bits: 8,
48+
samples: None,
49+
srgb: true,
50+
double_buffer: true,
51+
vsync: false,
52+
}
53+
}
54+
}
55+
56+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
57+
pub enum Profile {
58+
Compatibility,
59+
Core,
60+
}
61+
62+
#[derive(Debug)]
63+
pub enum GlError {
64+
InvalidWindowHandle,
65+
VersionNotSupported,
66+
CreationFailed(platform::CreationFailedError),
67+
}
68+
69+
pub struct GlContext {
70+
context: platform::GlContext,
71+
phantom: PhantomData<*mut ()>,
72+
}
73+
74+
impl GlContext {
75+
pub unsafe fn create(
76+
parent: &impl HasRawWindowHandle,
77+
config: GlConfig,
78+
) -> Result<GlContext, GlError> {
79+
platform::GlContext::create(parent, config).map(|context| GlContext {
80+
context,
81+
phantom: PhantomData,
82+
})
83+
}
84+
85+
pub unsafe fn make_current(&self) {
86+
self.context.make_current();
87+
}
88+
89+
pub unsafe fn make_not_current(&self) {
90+
self.context.make_not_current();
91+
}
92+
93+
pub fn get_proc_address(&self, symbol: &str) -> *const c_void {
94+
self.context.get_proc_address(symbol)
95+
}
96+
97+
pub fn swap_buffers(&self) {
98+
self.context.swap_buffers();
99+
}
100+
}

src/gl/macos.rs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
use std::ffi::c_void;
2+
use std::str::FromStr;
3+
4+
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
5+
6+
use cocoa::appkit::{
7+
NSOpenGLContext, NSOpenGLContextParameter, NSOpenGLPFAAccelerated, NSOpenGLPFAAlphaSize,
8+
NSOpenGLPFAColorSize, NSOpenGLPFADepthSize, NSOpenGLPFADoubleBuffer, NSOpenGLPFAMultisample,
9+
NSOpenGLPFAOpenGLProfile, NSOpenGLPFASampleBuffers, NSOpenGLPFASamples, NSOpenGLPFAStencilSize,
10+
NSOpenGLPixelFormat, NSOpenGLProfileVersion3_2Core, NSOpenGLProfileVersion4_1Core,
11+
NSOpenGLProfileVersionLegacy, NSOpenGLView, NSView,
12+
};
13+
use cocoa::base::{id, nil, YES};
14+
15+
use core_foundation::base::TCFType;
16+
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};
17+
use core_foundation::string::CFString;
18+
19+
use objc::{msg_send, sel, sel_impl};
20+
21+
use crate::{GlConfig, GlError, Profile};
22+
23+
pub type CreationFailedError = ();
24+
pub struct GlContext {
25+
view: id,
26+
context: id,
27+
}
28+
29+
impl GlContext {
30+
pub unsafe fn create(
31+
parent: &impl HasRawWindowHandle,
32+
config: GlConfig,
33+
) -> Result<GlContext, GlError> {
34+
let handle = if let RawWindowHandle::MacOS(handle) = parent.raw_window_handle() {
35+
handle
36+
} else {
37+
return Err(GlError::InvalidWindowHandle);
38+
};
39+
40+
if handle.ns_view.is_null() {
41+
return Err(GlError::InvalidWindowHandle);
42+
}
43+
44+
let parent_view = handle.ns_view as id;
45+
46+
let version = if config.version < (3, 2) && config.profile == Profile::Compatibility {
47+
NSOpenGLProfileVersionLegacy
48+
} else if config.version == (3, 2) && config.profile == Profile::Core {
49+
NSOpenGLProfileVersion3_2Core
50+
} else if config.version > (3, 2) && config.profile == Profile::Core {
51+
NSOpenGLProfileVersion4_1Core
52+
} else {
53+
return Err(GlError::VersionNotSupported);
54+
};
55+
56+
#[rustfmt::skip]
57+
let mut attrs = vec![
58+
NSOpenGLPFAOpenGLProfile as u32, version as u32,
59+
NSOpenGLPFAColorSize as u32, (config.red_bits + config.blue_bits + config.green_bits) as u32,
60+
NSOpenGLPFAAlphaSize as u32, config.alpha_bits as u32,
61+
NSOpenGLPFADepthSize as u32, config.depth_bits as u32,
62+
NSOpenGLPFAStencilSize as u32, config.stencil_bits as u32,
63+
NSOpenGLPFAAccelerated as u32,
64+
];
65+
66+
if config.samples.is_some() {
67+
#[rustfmt::skip]
68+
attrs.extend_from_slice(&[
69+
NSOpenGLPFAMultisample as u32,
70+
NSOpenGLPFASampleBuffers as u32, 1,
71+
NSOpenGLPFASamples as u32, config.samples.unwrap() as u32,
72+
]);
73+
}
74+
75+
if config.double_buffer {
76+
attrs.push(NSOpenGLPFADoubleBuffer as u32);
77+
}
78+
79+
attrs.push(0);
80+
81+
let pixel_format = NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(&attrs);
82+
83+
if pixel_format == nil {
84+
return Err(GlError::CreationFailed(()));
85+
}
86+
87+
let view =
88+
NSOpenGLView::alloc(nil).initWithFrame_pixelFormat_(parent_view.frame(), pixel_format);
89+
90+
if view == nil {
91+
return Err(GlError::CreationFailed(()));
92+
}
93+
94+
view.setWantsBestResolutionOpenGLSurface_(YES);
95+
96+
let () = msg_send![view, retain];
97+
NSOpenGLView::display_(view);
98+
parent_view.addSubview_(view);
99+
100+
let context: id = msg_send![view, openGLContext];
101+
let () = msg_send![context, retain];
102+
103+
context.setValues_forParameter_(
104+
&(config.vsync as i32),
105+
NSOpenGLContextParameter::NSOpenGLCPSwapInterval,
106+
);
107+
108+
let () = msg_send![pixel_format, release];
109+
110+
Ok(GlContext { view, context })
111+
}
112+
113+
pub unsafe fn make_current(&self) {
114+
self.context.makeCurrentContext();
115+
}
116+
117+
pub unsafe fn make_not_current(&self) {
118+
NSOpenGLContext::clearCurrentContext(self.context);
119+
}
120+
121+
pub fn get_proc_address(&self, symbol: &str) -> *const c_void {
122+
let symbol_name = CFString::from_str(symbol).unwrap();
123+
let framework_name = CFString::from_str("com.apple.opengl").unwrap();
124+
let framework =
125+
unsafe { CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef()) };
126+
let addr = unsafe {
127+
CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
128+
};
129+
addr as *const c_void
130+
}
131+
132+
pub fn swap_buffers(&self) {
133+
unsafe {
134+
self.context.flushBuffer();
135+
let () = msg_send![self.view, setNeedsDisplay: YES];
136+
}
137+
}
138+
}
139+
140+
impl Drop for GlContext {
141+
fn drop(&mut self) {
142+
unsafe {
143+
let () = msg_send![self.context, release];
144+
let () = msg_send![self.view, release];
145+
}
146+
}
147+
}

0 commit comments

Comments
 (0)