pub struct Context(/* private fields */);Expand description
An Impeller graphics context. Contexts are platform and client-rendering-API specific.
Contexts are thread-safe objects (not thread-safe with openGL) that are expensive to create. Most applications will only ever create a single context during their lifetimes. Once setup, Impeller is ready to render frames as performantly as possible.
During setup, context create the underlying graphics pipelines, allocators, worker threads, etc…
The general guidance is to create as few contexts as possible (typically just one) and share them as much as possible.
Implementations§
Source§impl Context
impl Context
Sourcepub unsafe fn new_opengl_es<F: FnMut(&str) -> *mut c_void>(
gl_proc_address: F,
) -> Result<Context, &'static str>
pub unsafe fn new_opengl_es<F: FnMut(&str) -> *mut c_void>( gl_proc_address: F, ) -> Result<Context, &'static str>
Create an OpenGL(ES) Impeller context.
@param
- gl_proc_address: A closure that returns the address of GL fn pointers
@return The context or error if the context could not be created.
fn create_impeller_ctx(window: &mut glfw::PWindow) {
// as easy as it gets
let impeller_ctx = unsafe {
// safety: drop all objects created from this context
// before `window` is dropped
impellers::Context::new_opengl_es( |name| {
window.get_proc_address(name) as _
})
};
}§Safety
- The context must be dropped before the underlying window is dropped.
- The context may only be used while the underlying context is current on the thread.
- Any object (like texture or surface) that you create using this context must be dropped before the context is dropped.
- Unlike other context types, the OpenGL ES context can only be created, used, and collected on the calling thread. This restriction may be lifted in the future once reactor workers are exposed in the API. No other context types have threading restrictions. Till reactor workers can be used, using the context on a background thread will cause a stall of OpenGL operations.
Examples found in repository?
26 pub fn new() -> Self {
27 // initialize window
28 let mut gtx = init(fail_on_errors).expect("failed to init glfw");
29 gtx.window_hint(WindowHint::ContextVersionMajor(4));
30 gtx.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
31 gtx.window_hint(WindowHint::SRgbCapable(true));
32 gtx.window_hint(WindowHint::StencilBits(Some(8)));
33 gtx.window_hint(WindowHint::ScaleToMonitor(true));
34
35 let (mut window, ev_receiver) = gtx
36 .create_window(800, 600, "glfw opengl impeller", WindowMode::Windowed)
37 .unwrap();
38 window.make_current();
39 window.set_all_polling(true);
40
41 // initialize impeller context using opengl fn pointers
42 let itx = unsafe {
43 impellers::Context::new_opengl_es(|s| {
44 window
45 .get_proc_address(s)
46 .map(|f| f as _)
47 .unwrap_or(std::ptr::null_mut())
48 })
49 }
50 .unwrap();
51 let glow_ctx = unsafe {
52 glow::Context::from_loader_function(|s| {
53 window
54 .get_proc_address(s)
55 .map(|f| f as _)
56 .unwrap_or(std::ptr::null_mut())
57 })
58 };
59 unsafe {
60 let (width, height) = window.get_framebuffer_size();
61 glow_ctx.viewport(0, 0, width, height);
62 }
63 let ttx = TypographyContext::default();
64 let mut style = ParagraphStyle::default();
65 style.set_font_size(24.0);
66 style.set_font_family("Roboto");
67 style.set_font_weight(FontWeight::Bold);
68 let mut paint = Paint::default();
69 paint.set_color(Color::LIGHT_SKY_BLUE);
70 style.set_foreground(&paint);
71 Self {
72 ttx,
73 style,
74 glow_ctx,
75 itx,
76 window,
77 receiver: ev_receiver,
78 gtx,
79 events: vec![],
80 }
81 }More examples
5pub fn main() {
6 let mut gtx = init(fail_on_errors).unwrap();
7 gtx.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
8 gtx.window_hint(WindowHint::ContextVersionMajor(4));
9 gtx.window_hint(WindowHint::SRgbCapable(true));
10 gtx.window_hint(WindowHint::ScaleToMonitor(true));
11 let (mut window, ev_receiver) = gtx
12 .create_window(800, 600, "rust-glfw-impeller demo", WindowMode::Windowed)
13 .expect("failed to create window");
14 window.set_all_polling(true);
15 window.make_current();
16
17 // initialize impeller context using opengl fn pointers
18 let mut itx = unsafe {
19 impellers::Context::new_opengl_es(|s| {
20 window
21 .get_proc_address(s)
22 .map(|f| f as _)
23 .unwrap_or(std::ptr::null_mut())
24 })
25 }
26 .unwrap();
27 let glow_ctx: glow::Context = unsafe {
28 glow::Context::from_loader_function(|s| {
29 window
30 .get_proc_address(s)
31 .map(|f| f as _)
32 .unwrap_or(std::ptr::null_mut())
33 })
34 };
35 // enter event loop
36 while !window.should_close() {
37 // check events
38 gtx.poll_events();
39 for (_, event) in flush_messages(&ev_receiver) {
40 match event {
41 WindowEvent::Close => {
42 window.set_should_close(true);
43 }
44 WindowEvent::FramebufferSize(_, _) => {
45 // glViewPort here
46 }
47 _ => {}
48 }
49 }
50
51 let (width, height) = window.get_framebuffer_size();
52 let mut surface = unsafe {
53 itx.wrap_fbo(
54 0,
55 PixelFormat::RGBA8888,
56 ISize::new(width.into(), height.into()),
57 )
58 }
59 .expect("failed to wrap window's framebuffer");
60 // create a display list
61 let clear_display_list = {
62 // create a display list builder
63 let mut builder = DisplayListBuilder::new(None);
64 // paint controls the properties of draw commands
65 let mut paint = Paint::default();
66 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
67 paint.set_color(Color::BLACKBERRY);
68 // fill the bounds with a color (^^that we set above)
69 builder.draw_paint(&paint);
70 let current_time = gtx.get_time(); // time in seconds since start of the program
71 // lets set the color to a color that changes with time.
72 // sin/cos/tan will always be in the range of -1 to 1, so lets use abs to keep it in between 0 and 1.
73 paint.set_color(Color::new_srgb(
74 current_time.sin().abs() as _,
75 current_time.cos().abs() as _,
76 current_time.tan().abs() as _,
77 ));
78 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
79 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
80 builder.build().expect("failed to build a display_list")
81 };
82 let animating_dl = {
83 // create a display list builder
84 let mut builder = DisplayListBuilder::new(None);
85 // paint controls the properties of draw commands
86 let mut paint = Paint::default();
87 let current_time = gtx.get_time(); // time in seconds since start of the program
88 // lets set the color to a color that changes with time.
89 // sin/cos/tan will always be in the range of -1 to 1, so lets use abs to keep it in between 0 and 1.
90 paint.set_color(Color::new_srgb(
91 current_time.sin().abs() as _,
92 current_time.cos().abs() as _,
93 current_time.tan().abs() as _,
94 ));
95 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
96 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
97 builder.build().expect("failed to build a display_list")
98 };
99 let oval_dl = {
100 // create a display list builder
101 let mut builder = DisplayListBuilder::new(None);
102 // paint controls the properties of draw commands
103 let mut paint = Paint::default();
104 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
105 paint.set_color(Color::GRANNY_APPLE);
106 builder.draw_oval(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
107 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
108 builder.build().expect("failed to build a display_list")
109 };
110 let main_display_list = {
111 let mut builder = DisplayListBuilder::new(None);
112 builder.draw_display_list(&clear_display_list, 1.0);
113 builder.draw_display_list(&animating_dl, 1.0);
114 builder.draw_display_list(&oval_dl, 1.0);
115 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
116 builder.build().expect("failed to build a display_list")
117 };
118 // Now, draw the display_list on the surface. All the commands we recorded in the display_list will be drawn.
119 // you can redraw the display_list multiple times to animate it on any number of surfaces.
120 unsafe {
121 glow_ctx.clear_color(1.0, 0.0, 0.0, 1.0);
122 glow_ctx.clear(glow::COLOR_BUFFER_BIT);
123 }
124 surface
125 .draw_display_list(&main_display_list)
126 .expect("failed to draw on surface");
127 // submit frame and wait for vsync
128 window.swap_buffers();
129 }
130
131 // drop the window/sdl or whatever
132}Sourcepub unsafe fn wrap_fbo(
&mut self,
fbo: u64,
format: PixelFormat,
size: ISize,
) -> Option<Surface>
pub unsafe fn wrap_fbo( &mut self, fbo: u64, format: PixelFormat, size: ISize, ) -> Option<Surface>
Create a new surface by wrapping an existing framebuffer object. The surface is just a cheap use-and-throw object. Create it, draw to it (once) and drop it .
- fbo The framebuffer object handle.
- format The format of the framebuffer.
- size The size of the framebuffer is texels.
@return The surface if once can be created, NULL otherwise.
§Safety
- The surface must be properly configured (eg: no pending resizes)
- must be drawn to only once and then dropped (presented if vulkan).
- must be dropped before the context is dropped
- The framebuffer must be complete as determined by
glCheckFramebufferStatus. The framebuffer is still owned by the caller and it must be collected once the surface is collected.
Examples found in repository?
88 pub fn enter_event_loop(
89 mut self,
90 dl: Option<DisplayList>,
91 mut user_callback: Option<UserCallback>,
92 ) {
93 let mut previous_instant = std::time::Instant::now();
94 let mut current_frame = 0;
95 let mut fps = 0;
96 let mut vsync = true;
97 // enter event loop
98 while !self.window.should_close() {
99 {
100 // record fps
101 if previous_instant.elapsed().as_secs_f64() >= 1.0 {
102 fps = current_frame;
103 current_frame = 0;
104 previous_instant = std::time::Instant::now();
105 }
106 current_frame += 1;
107 }
108 self.events.clear();
109 // check events
110 self.gtx.poll_events();
111 for (_, event) in flush_messages(&self.receiver) {
112 match &event {
113 WindowEvent::Close => {
114 self.window.set_should_close(true);
115 }
116 WindowEvent::FramebufferSize(w, h) => {
117 unsafe {
118 self.glow_ctx.viewport(0, 0, *w, *h);
119 }
120 println!("window resized to {}x{}", w, h);
121 }
122 WindowEvent::Key(Key::Space, _, Action::Release, _) => {
123 vsync = !vsync;
124 println!("setting vsync to {vsync}");
125
126 self.gtx.set_swap_interval(if vsync {
127 SwapInterval::Sync(1)
128 } else {
129 SwapInterval::None
130 });
131 }
132 _ => {}
133 }
134 self.events.push(event);
135 }
136
137 let (width, height) = self.window.get_framebuffer_size();
138 // init surface by wrapping default framebuffer (fbo = 0)
139 let mut surface = unsafe {
140 self.itx.wrap_fbo(
141 0,
142 PixelFormat::RGBA8888,
143 ISize::new(width.into(), height.into()),
144 )
145 }
146 .expect("failed to wrap window's framebuffer");
147 let mut dl_builder = DisplayListBuilder::new(Some(&Rect::from_size(
148 [width as f32, height as f32].into(),
149 )));
150
151 if let Some(dl) = dl.as_ref() {
152 dl_builder.draw_display_list(dl, 1.0);
153 }
154 // call user callback
155 if let Some(cb) = user_callback.as_mut() {
156 if let Some(display_list) = cb(&mut self) {
157 dl_builder.draw_display_list(&display_list, 1.0);
158 }
159 }
160 {
161 let mut para_builder = ParagraphBuilder::new(&self.ttx).unwrap();
162 para_builder.push_style(&self.style);
163 para_builder.add_text(&format!("avg fps: {fps}"));
164 let para = para_builder.build(1000.0).unwrap();
165 dl_builder.draw_paragraph(¶, Point::origin());
166 }
167 surface
168 .draw_display_list(&dl_builder.build().unwrap())
169 .unwrap();
170
171 // submit frame and wait for vsync
172 self.window.swap_buffers();
173 }
174 }More examples
5pub fn main() {
6 let mut gtx = init(fail_on_errors).unwrap();
7 gtx.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
8 gtx.window_hint(WindowHint::ContextVersionMajor(4));
9 gtx.window_hint(WindowHint::SRgbCapable(true));
10 gtx.window_hint(WindowHint::ScaleToMonitor(true));
11 let (mut window, ev_receiver) = gtx
12 .create_window(800, 600, "rust-glfw-impeller demo", WindowMode::Windowed)
13 .expect("failed to create window");
14 window.set_all_polling(true);
15 window.make_current();
16
17 // initialize impeller context using opengl fn pointers
18 let mut itx = unsafe {
19 impellers::Context::new_opengl_es(|s| {
20 window
21 .get_proc_address(s)
22 .map(|f| f as _)
23 .unwrap_or(std::ptr::null_mut())
24 })
25 }
26 .unwrap();
27 let glow_ctx: glow::Context = unsafe {
28 glow::Context::from_loader_function(|s| {
29 window
30 .get_proc_address(s)
31 .map(|f| f as _)
32 .unwrap_or(std::ptr::null_mut())
33 })
34 };
35 // enter event loop
36 while !window.should_close() {
37 // check events
38 gtx.poll_events();
39 for (_, event) in flush_messages(&ev_receiver) {
40 match event {
41 WindowEvent::Close => {
42 window.set_should_close(true);
43 }
44 WindowEvent::FramebufferSize(_, _) => {
45 // glViewPort here
46 }
47 _ => {}
48 }
49 }
50
51 let (width, height) = window.get_framebuffer_size();
52 let mut surface = unsafe {
53 itx.wrap_fbo(
54 0,
55 PixelFormat::RGBA8888,
56 ISize::new(width.into(), height.into()),
57 )
58 }
59 .expect("failed to wrap window's framebuffer");
60 // create a display list
61 let clear_display_list = {
62 // create a display list builder
63 let mut builder = DisplayListBuilder::new(None);
64 // paint controls the properties of draw commands
65 let mut paint = Paint::default();
66 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
67 paint.set_color(Color::BLACKBERRY);
68 // fill the bounds with a color (^^that we set above)
69 builder.draw_paint(&paint);
70 let current_time = gtx.get_time(); // time in seconds since start of the program
71 // lets set the color to a color that changes with time.
72 // sin/cos/tan will always be in the range of -1 to 1, so lets use abs to keep it in between 0 and 1.
73 paint.set_color(Color::new_srgb(
74 current_time.sin().abs() as _,
75 current_time.cos().abs() as _,
76 current_time.tan().abs() as _,
77 ));
78 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
79 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
80 builder.build().expect("failed to build a display_list")
81 };
82 let animating_dl = {
83 // create a display list builder
84 let mut builder = DisplayListBuilder::new(None);
85 // paint controls the properties of draw commands
86 let mut paint = Paint::default();
87 let current_time = gtx.get_time(); // time in seconds since start of the program
88 // lets set the color to a color that changes with time.
89 // sin/cos/tan will always be in the range of -1 to 1, so lets use abs to keep it in between 0 and 1.
90 paint.set_color(Color::new_srgb(
91 current_time.sin().abs() as _,
92 current_time.cos().abs() as _,
93 current_time.tan().abs() as _,
94 ));
95 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
96 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
97 builder.build().expect("failed to build a display_list")
98 };
99 let oval_dl = {
100 // create a display list builder
101 let mut builder = DisplayListBuilder::new(None);
102 // paint controls the properties of draw commands
103 let mut paint = Paint::default();
104 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
105 paint.set_color(Color::GRANNY_APPLE);
106 builder.draw_oval(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
107 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
108 builder.build().expect("failed to build a display_list")
109 };
110 let main_display_list = {
111 let mut builder = DisplayListBuilder::new(None);
112 builder.draw_display_list(&clear_display_list, 1.0);
113 builder.draw_display_list(&animating_dl, 1.0);
114 builder.draw_display_list(&oval_dl, 1.0);
115 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
116 builder.build().expect("failed to build a display_list")
117 };
118 // Now, draw the display_list on the surface. All the commands we recorded in the display_list will be drawn.
119 // you can redraw the display_list multiple times to animate it on any number of surfaces.
120 unsafe {
121 glow_ctx.clear_color(1.0, 0.0, 0.0, 1.0);
122 glow_ctx.clear(glow::COLOR_BUFFER_BIT);
123 }
124 surface
125 .draw_display_list(&main_display_list)
126 .expect("failed to draw on surface");
127 // submit frame and wait for vsync
128 window.swap_buffers();
129 }
130
131 // drop the window/sdl or whatever
132}Sourcepub unsafe fn create_texture_with_rgba8(
&self,
contents: Cow<'static, [u8]>,
width: u32,
height: u32,
) -> Result<Texture, &'static str>
pub unsafe fn create_texture_with_rgba8( &self, contents: Cow<'static, [u8]>, width: u32, height: u32, ) -> Result<Texture, &'static str>
Create a texture with decompressed bytes.
@warning Do not supply compressed image data directly (PNG, JPEG, etc…). This function only works with tightly packed decompressed data. @param
- contents texture bytes. contiguously laid out as RGBA8888
- width width of texture
- height height of texture
@return The texture if one can be created using the provided data, NULL otherwise.
§Safety
- The texture must be dropped before the context is dropped
Examples found in repository?
4fn main() {
5 let framework = common::SdlGlImpellerFrameWork::new();
6 let (width, height) = framework.window.get_framebuffer_size();
7 // we resize the image so that it fits within our window
8 let pixels = image::load_from_memory(common::DOG_BYTES)
9 .unwrap()
10 .resize(
11 width as _,
12 height as _,
13 image::imageops::FilterType::Triangle,
14 )
15 .into_rgba8();
16
17 let (width, height) = pixels.dimensions();
18 let contents = pixels.into_raw();
19 let tex = unsafe {
20 framework
21 .itx
22 .create_texture_with_rgba8(contents.into(), width, height)
23 .unwrap()
24 };
25 let dl = {
26 let mut builder = DisplayListBuilder::new(None);
27 let paint = Paint::default();
28 builder.draw_texture(&tex, Point::zero(), TextureSampling::Linear, &paint);
29
30 let rect = Rect::new(Point::zero(), Size::new(width as f32, height as f32 / 2.0));
31 builder.clip_rect(&rect, ClipOperation::Intersect);
32 // the backdrop will be blurred by this (within the clip area set above)
33 builder.save_layer(
34 &rect,
35 None,
36 Some(&ImageFilter::new_blur(8.0, 8.0, TileMode::Clamp)),
37 );
38 // no need to do anything
39 builder.restore();
40 builder.build().unwrap()
41 };
42 framework.enter_event_loop(Some(dl), None);
43}More examples
5fn main() {
6 let framework = common::SdlGlImpellerFrameWork::new();
7 let pixels = image::load_from_memory(IMAGE_BYTES).unwrap().to_rgba8();
8 let (width, height) = pixels.dimensions();
9 let contents = pixels.into_raw();
10 let tex = unsafe {
11 framework
12 .itx
13 .create_texture_with_rgba8(contents.into(), width, height)
14 .unwrap()
15 };
16 let dl = {
17 let mut builder = DisplayListBuilder::new(None);
18
19 // the rect inside image that contains the dog.
20 let dog_rect = Rect::new([700.0, 500.0].into(), [600.0, 500.0].into());
21 // where on canvas we will be drawing the above rect's texture contents
22 // always a good idea to keep the scaling proportional.
23 // the width and height are 600x500 from src_rect, so, we use widthxheight of 300x250 for dst_rect
24 // The scaling will be uniform. The reason for 250 height is that our star will also roughly be 256x256 sized.
25 let dst_rect = Rect::from_size([300.0, 250.0].into());
26
27 let path = {
28 // build a star path
29 let mut path_builder = PathBuilder::default();
30 path_builder.move_to([128.0, 0.0].into());
31 path_builder.line_to([168.0, 80.0].into());
32 path_builder.line_to([256.0, 93.0].into());
33 path_builder.line_to([192.0, 155.0].into());
34 path_builder.line_to([207.0, 244.0].into());
35 path_builder.line_to([128.0, 202.0].into());
36 path_builder.line_to([49.0, 244.0].into());
37 path_builder.line_to([64.0, 155.0].into());
38 path_builder.line_to([0.0, 93.0].into());
39 path_builder.line_to([88.0, 80.0].into());
40 path_builder.line_to([128.0, 0.0].into());
41 path_builder.close();
42 path_builder.take_path_new(FillType::NonZero)
43 };
44 {
45 // clear screen
46 let mut paint = Paint::default();
47 paint.set_color(Color::BLACK);
48 builder.draw_paint(&paint);
49 }
50 // first, lets clip so that only contents *inside* will be visible.
51 {
52 // always a good idea to push a new stack and work there.
53 // Then, pop after you are done drawing.
54 builder.save();
55 // intersect ensures that only the inside of the clip is drawn (if it overlaps with the clips down the stack)
56 builder.clip_path(&path, ClipOperation::Intersect);
57 builder.draw_texture_rect(&tex, &dog_rect, &dst_rect, TextureSampling::Linear, None);
58 builder.restore(); // clip is gone here.
59 }
60 {
61 builder.save();
62 // lets move to right, so we don't draw over the previous contents.
63 builder.translate(300.0, 0.0);
64 // difference ensures that the clip is inverted and nothing will be drawn *inside*
65 builder.clip_path(&path, ClipOperation::Difference);
66 builder.draw_texture_rect(&tex, &dog_rect, &dst_rect, TextureSampling::Linear, None);
67 builder.restore(); // clip and translate are popped off stack
68 }
69 builder.build().unwrap()
70 };
71 framework.enter_event_loop(Some(dl), None);
72}Sourcepub unsafe fn adopt_opengl_texture(
&self,
width: u32,
height: u32,
mip_count: u32,
handle: u64,
) -> Option<Texture>
pub unsafe fn adopt_opengl_texture( &self, width: u32, height: u32, mip_count: u32, handle: u64, ) -> Option<Texture>
Create a texture with an externally created OpenGL texture handle.
- width width of texture
- height height of texture
- mip_count mipcount of texture
- handle The handle
@return The texture if one could be created by adopting the supplied texture handle, NULL otherwise.
§Safety
-
The texture must be dropped before the context is dropped
-
Ownership of the handle is transferred over to Impeller after a successful call to this method. Impeller is responsible for calling glDeleteTextures on this handle. Do not collect this handle yourself as this will lead to a double-free.
-
The handle must be created in the same context as the one used by Impeller. If a different context is used, that context must be in the same sharegroup as Impellers OpenGL context and all synchronization of texture contents must already be complete.
If the context is not an OpenGL context, this call will always fail.
Sourcepub unsafe fn new_metal() -> Result<Context, &'static str>
pub unsafe fn new_metal() -> Result<Context, &'static str>
Create a Metal context using the system default Metal device.
§Safety
I don’t know much about Metal, so I will leave the work of figuring out the safety to users. good luck :)
@return The Metal context or NULL if one cannot be created.
Sourcepub unsafe fn new_vulkan<F: FnMut(*mut c_void, *const c_char) -> *mut c_void>(
enable_validation: bool,
proc_address_callback: F,
) -> Result<Context, &'static str>
pub unsafe fn new_vulkan<F: FnMut(*mut c_void, *const c_char) -> *mut c_void>( enable_validation: bool, proc_address_callback: F, ) -> Result<Context, &'static str>
Create a Vulkan context using the provided Vulkan Settings.
- enable_validation Enable Vulkan validation layers
- proc_address_callback A callback to query the address of Vulkan function pointers. The first argument is a pointer to vulkan instance. The second argument is a pointer to the function name.
@return The Vulkan context or NULL if one cannot be created.
§Safety
Don’t know much vulkan either, so users will have to figure out the safety invariants.
Just look at vulkan docs for how your proc_address_callback should work. Don’t hold on to any pointers given to your closure (instance pointer or char pointer).
Examples found in repository?
5pub fn main() {
6 let mut gtx = init(fail_on_errors).unwrap();
7 gtx.window_hint(WindowHint::ClientApi(ClientApiHint::NoApi));
8 gtx.window_hint(WindowHint::ScaleToMonitor(true));
9 let (mut window, ev_receiver) = gtx
10 .create_window(800, 600, "rust-glfw-impeller demo", WindowMode::Windowed)
11 .expect("failed to create window");
12 window.set_all_polling(true);
13
14 // initialize impeller context by loading vulkan fn pointers
15 let itx = unsafe {
16 assert!(gtx.vulkan_supported());
17 // create context using callback
18 impellers::Context::new_vulkan(false, |vk_instance, vk_proc_name| {
19 let proc_name = std::ffi::CStr::from_ptr(vk_proc_name).to_str().unwrap();
20 gtx.get_instance_proc_address_raw(vk_instance as _, proc_name)
21 .map(|f| f as _)
22 .unwrap_or(std::ptr::null_mut())
23 })
24 }
25 .expect("failed to create impeller context");
26 // lets see what's in here
27 let vk_info = itx.get_vulkan_info().expect("failed to get vulkan info");
28 dbg!(vk_info);
29 assert!(
30 !vk_info.vk_instance.is_null(),
31 "instance pointer from vulkan info is null"
32 );
33
34 let mut vulkan_surface_khr: ash::vk::SurfaceKHR = ash::vk::SurfaceKHR::null();
35 let result = unsafe {
36 window.create_window_surface(
37 vk_info.vk_instance as _,
38 std::ptr::null(),
39 &raw mut vulkan_surface_khr as _,
40 )
41 };
42 if result != 0 {
43 panic!("failed to create vk surface khr");
44 }
45 assert!(!vulkan_surface_khr.is_null(), "surface pointer is null");
46 let mut vk_swapchain =
47 unsafe { itx.create_new_vulkan_swapchain(vulkan_surface_khr.as_raw() as _) }
48 .expect("failed to create vk swapchain");
49
50 // enter event loop
51 while !window.should_close() {
52 // check events
53 gtx.poll_events();
54 for (_, event) in flush_messages(&ev_receiver) {
55 if event == WindowEvent::Close {
56 window.set_should_close(true);
57 }
58 }
59
60 let clear_display_list = {
61 // create a display list builder
62 let mut builder = DisplayListBuilder::new(None);
63 // paint controls the properties of draw commands
64 let mut paint = Paint::default();
65 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
66 paint.set_color(Color::BLACKBERRY);
67 // fill the bounds with a color (^^that we set above)
68 builder.draw_paint(&paint);
69 let current_time = gtx.get_time(); // time in seconds since start of the program
70 // lets set the color to a color that changes with time.
71 // sin/cos/tan will always be in the range of -1 to 1, so lets use abs to keep it in between 0 and 1.
72 paint.set_color(Color::new_srgb(
73 current_time.sin().abs() as _,
74 current_time.cos().abs() as _,
75 current_time.tan().abs() as _,
76 ));
77 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
78 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
79 builder.build().expect("failed to build a display_list")
80 };
81 let animating_dl = {
82 // create a display list builder
83 let mut builder = DisplayListBuilder::new(None);
84 // paint controls the properties of draw commands
85 let mut paint = Paint::default();
86 let current_time = gtx.get_time(); // time in seconds since start of the program
87 // lets set the color to a color that changes with time.
88 // sin/cos/tan will always be in the range of -1 to 1, so lets use abs to keep it in between 0 and 1.
89 paint.set_color(Color::new_srgb(
90 current_time.sin().abs() as _,
91 current_time.cos().abs() as _,
92 current_time.tan().abs() as _,
93 ));
94 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
95 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
96 builder.build().expect("failed to build a display_list")
97 };
98 let oval_dl = {
99 // create a display list builder
100 let mut builder = DisplayListBuilder::new(None);
101 // paint controls the properties of draw commands
102 let mut paint = Paint::default();
103 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
104 paint.set_color(Color::GRANNY_APPLE);
105 builder.draw_oval(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
106 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
107 builder.build().expect("failed to build a display_list")
108 };
109 let main_display_list = {
110 let mut builder = DisplayListBuilder::new(None);
111 builder.draw_display_list(&clear_display_list, 1.0);
112 builder.draw_display_list(&animating_dl, 1.0);
113 builder.draw_display_list(&oval_dl, 1.0);
114 builder.build().expect("failed to build a display_list")
115 };
116 let mut surface = vk_swapchain.acquire_next_surface_new().unwrap();
117 // Now, draw the display_list on the surface. All the commands we recorded in the display_list will be drawn.
118 // you can redraw the display_list multiple times to animate it on any number of surfaces.
119
120 surface
121 .draw_display_list(&main_display_list)
122 .expect("failed to draw on surface");
123 // submit frame and wait for vsync
124 surface.present().unwrap();
125 }
126
127 // drop the window/sdl or whatever
128}Sourcepub fn get_vulkan_info(&self) -> Result<VulkanInfo, &'static str>
pub fn get_vulkan_info(&self) -> Result<VulkanInfo, &'static str>
Get internal Vulkan handles managed by the given Vulkan context. Ownership of the handles is still maintained by Impeller. This accessor is just available so embedders can create resources using the same device and instance as Impeller for interop.
@warning If the context is not a Vulkan context, this will return Err.
Examples found in repository?
5pub fn main() {
6 let mut gtx = init(fail_on_errors).unwrap();
7 gtx.window_hint(WindowHint::ClientApi(ClientApiHint::NoApi));
8 gtx.window_hint(WindowHint::ScaleToMonitor(true));
9 let (mut window, ev_receiver) = gtx
10 .create_window(800, 600, "rust-glfw-impeller demo", WindowMode::Windowed)
11 .expect("failed to create window");
12 window.set_all_polling(true);
13
14 // initialize impeller context by loading vulkan fn pointers
15 let itx = unsafe {
16 assert!(gtx.vulkan_supported());
17 // create context using callback
18 impellers::Context::new_vulkan(false, |vk_instance, vk_proc_name| {
19 let proc_name = std::ffi::CStr::from_ptr(vk_proc_name).to_str().unwrap();
20 gtx.get_instance_proc_address_raw(vk_instance as _, proc_name)
21 .map(|f| f as _)
22 .unwrap_or(std::ptr::null_mut())
23 })
24 }
25 .expect("failed to create impeller context");
26 // lets see what's in here
27 let vk_info = itx.get_vulkan_info().expect("failed to get vulkan info");
28 dbg!(vk_info);
29 assert!(
30 !vk_info.vk_instance.is_null(),
31 "instance pointer from vulkan info is null"
32 );
33
34 let mut vulkan_surface_khr: ash::vk::SurfaceKHR = ash::vk::SurfaceKHR::null();
35 let result = unsafe {
36 window.create_window_surface(
37 vk_info.vk_instance as _,
38 std::ptr::null(),
39 &raw mut vulkan_surface_khr as _,
40 )
41 };
42 if result != 0 {
43 panic!("failed to create vk surface khr");
44 }
45 assert!(!vulkan_surface_khr.is_null(), "surface pointer is null");
46 let mut vk_swapchain =
47 unsafe { itx.create_new_vulkan_swapchain(vulkan_surface_khr.as_raw() as _) }
48 .expect("failed to create vk swapchain");
49
50 // enter event loop
51 while !window.should_close() {
52 // check events
53 gtx.poll_events();
54 for (_, event) in flush_messages(&ev_receiver) {
55 if event == WindowEvent::Close {
56 window.set_should_close(true);
57 }
58 }
59
60 let clear_display_list = {
61 // create a display list builder
62 let mut builder = DisplayListBuilder::new(None);
63 // paint controls the properties of draw commands
64 let mut paint = Paint::default();
65 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
66 paint.set_color(Color::BLACKBERRY);
67 // fill the bounds with a color (^^that we set above)
68 builder.draw_paint(&paint);
69 let current_time = gtx.get_time(); // time in seconds since start of the program
70 // lets set the color to a color that changes with time.
71 // sin/cos/tan will always be in the range of -1 to 1, so lets use abs to keep it in between 0 and 1.
72 paint.set_color(Color::new_srgb(
73 current_time.sin().abs() as _,
74 current_time.cos().abs() as _,
75 current_time.tan().abs() as _,
76 ));
77 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
78 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
79 builder.build().expect("failed to build a display_list")
80 };
81 let animating_dl = {
82 // create a display list builder
83 let mut builder = DisplayListBuilder::new(None);
84 // paint controls the properties of draw commands
85 let mut paint = Paint::default();
86 let current_time = gtx.get_time(); // time in seconds since start of the program
87 // lets set the color to a color that changes with time.
88 // sin/cos/tan will always be in the range of -1 to 1, so lets use abs to keep it in between 0 and 1.
89 paint.set_color(Color::new_srgb(
90 current_time.sin().abs() as _,
91 current_time.cos().abs() as _,
92 current_time.tan().abs() as _,
93 ));
94 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
95 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
96 builder.build().expect("failed to build a display_list")
97 };
98 let oval_dl = {
99 // create a display list builder
100 let mut builder = DisplayListBuilder::new(None);
101 // paint controls the properties of draw commands
102 let mut paint = Paint::default();
103 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
104 paint.set_color(Color::GRANNY_APPLE);
105 builder.draw_oval(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
106 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
107 builder.build().expect("failed to build a display_list")
108 };
109 let main_display_list = {
110 let mut builder = DisplayListBuilder::new(None);
111 builder.draw_display_list(&clear_display_list, 1.0);
112 builder.draw_display_list(&animating_dl, 1.0);
113 builder.draw_display_list(&oval_dl, 1.0);
114 builder.build().expect("failed to build a display_list")
115 };
116 let mut surface = vk_swapchain.acquire_next_surface_new().unwrap();
117 // Now, draw the display_list on the surface. All the commands we recorded in the display_list will be drawn.
118 // you can redraw the display_list multiple times to animate it on any number of surfaces.
119
120 surface
121 .draw_display_list(&main_display_list)
122 .expect("failed to draw on surface");
123 // submit frame and wait for vsync
124 surface.present().unwrap();
125 }
126
127 // drop the window/sdl or whatever
128}Sourcepub unsafe fn create_new_vulkan_swapchain(
&self,
vulkan_surface_khr: *mut c_void,
) -> Option<VkSwapChain>
pub unsafe fn create_new_vulkan_swapchain( &self, vulkan_surface_khr: *mut c_void, ) -> Option<VkSwapChain>
Create a new Vulkan swapchain using a VkSurfaceKHR instance. Ownership of the surface is transferred over to Impeller.
- vulkan_surface_khr The vulkan surface.
@return The vulkan swapchain.
§Safety
The Vulkan instance the surface is created from must the same as the context provided.
The context must be a Vulkan context whose instance is the same used to create the surface passed into the next argument.
The surface pointer must be valid (and kept alive until this swapchain is dropped).
Examples found in repository?
5pub fn main() {
6 let mut gtx = init(fail_on_errors).unwrap();
7 gtx.window_hint(WindowHint::ClientApi(ClientApiHint::NoApi));
8 gtx.window_hint(WindowHint::ScaleToMonitor(true));
9 let (mut window, ev_receiver) = gtx
10 .create_window(800, 600, "rust-glfw-impeller demo", WindowMode::Windowed)
11 .expect("failed to create window");
12 window.set_all_polling(true);
13
14 // initialize impeller context by loading vulkan fn pointers
15 let itx = unsafe {
16 assert!(gtx.vulkan_supported());
17 // create context using callback
18 impellers::Context::new_vulkan(false, |vk_instance, vk_proc_name| {
19 let proc_name = std::ffi::CStr::from_ptr(vk_proc_name).to_str().unwrap();
20 gtx.get_instance_proc_address_raw(vk_instance as _, proc_name)
21 .map(|f| f as _)
22 .unwrap_or(std::ptr::null_mut())
23 })
24 }
25 .expect("failed to create impeller context");
26 // lets see what's in here
27 let vk_info = itx.get_vulkan_info().expect("failed to get vulkan info");
28 dbg!(vk_info);
29 assert!(
30 !vk_info.vk_instance.is_null(),
31 "instance pointer from vulkan info is null"
32 );
33
34 let mut vulkan_surface_khr: ash::vk::SurfaceKHR = ash::vk::SurfaceKHR::null();
35 let result = unsafe {
36 window.create_window_surface(
37 vk_info.vk_instance as _,
38 std::ptr::null(),
39 &raw mut vulkan_surface_khr as _,
40 )
41 };
42 if result != 0 {
43 panic!("failed to create vk surface khr");
44 }
45 assert!(!vulkan_surface_khr.is_null(), "surface pointer is null");
46 let mut vk_swapchain =
47 unsafe { itx.create_new_vulkan_swapchain(vulkan_surface_khr.as_raw() as _) }
48 .expect("failed to create vk swapchain");
49
50 // enter event loop
51 while !window.should_close() {
52 // check events
53 gtx.poll_events();
54 for (_, event) in flush_messages(&ev_receiver) {
55 if event == WindowEvent::Close {
56 window.set_should_close(true);
57 }
58 }
59
60 let clear_display_list = {
61 // create a display list builder
62 let mut builder = DisplayListBuilder::new(None);
63 // paint controls the properties of draw commands
64 let mut paint = Paint::default();
65 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
66 paint.set_color(Color::BLACKBERRY);
67 // fill the bounds with a color (^^that we set above)
68 builder.draw_paint(&paint);
69 let current_time = gtx.get_time(); // time in seconds since start of the program
70 // lets set the color to a color that changes with time.
71 // sin/cos/tan will always be in the range of -1 to 1, so lets use abs to keep it in between 0 and 1.
72 paint.set_color(Color::new_srgb(
73 current_time.sin().abs() as _,
74 current_time.cos().abs() as _,
75 current_time.tan().abs() as _,
76 ));
77 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
78 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
79 builder.build().expect("failed to build a display_list")
80 };
81 let animating_dl = {
82 // create a display list builder
83 let mut builder = DisplayListBuilder::new(None);
84 // paint controls the properties of draw commands
85 let mut paint = Paint::default();
86 let current_time = gtx.get_time(); // time in seconds since start of the program
87 // lets set the color to a color that changes with time.
88 // sin/cos/tan will always be in the range of -1 to 1, so lets use abs to keep it in between 0 and 1.
89 paint.set_color(Color::new_srgb(
90 current_time.sin().abs() as _,
91 current_time.cos().abs() as _,
92 current_time.tan().abs() as _,
93 ));
94 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
95 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
96 builder.build().expect("failed to build a display_list")
97 };
98 let oval_dl = {
99 // create a display list builder
100 let mut builder = DisplayListBuilder::new(None);
101 // paint controls the properties of draw commands
102 let mut paint = Paint::default();
103 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
104 paint.set_color(Color::GRANNY_APPLE);
105 builder.draw_oval(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
106 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
107 builder.build().expect("failed to build a display_list")
108 };
109 let main_display_list = {
110 let mut builder = DisplayListBuilder::new(None);
111 builder.draw_display_list(&clear_display_list, 1.0);
112 builder.draw_display_list(&animating_dl, 1.0);
113 builder.draw_display_list(&oval_dl, 1.0);
114 builder.build().expect("failed to build a display_list")
115 };
116 let mut surface = vk_swapchain.acquire_next_surface_new().unwrap();
117 // Now, draw the display_list on the surface. All the commands we recorded in the display_list will be drawn.
118 // you can redraw the display_list multiple times to animate it on any number of surfaces.
119
120 surface
121 .draw_display_list(&main_display_list)
122 .expect("failed to draw on surface");
123 // submit frame and wait for vsync
124 surface.present().unwrap();
125 }
126
127 // drop the window/sdl or whatever
128}Sourcepub unsafe fn wrap_metal_drawable(
&self,
metal_drawable: *mut c_void,
) -> Option<Surface>
pub unsafe fn wrap_metal_drawable( &self, metal_drawable: *mut c_void, ) -> Option<Surface>
Create a surface by wrapping a Metal drawable. This is useful during WSI when the drawable is the backing store of the Metal layer being drawn to.
§Safety
The Metal layer must be using the same device managed by the underlying context.
The Metal device managed by this context must be the same used to create the drawable that is being wrapped.
- metal_drawable The drawable to wrap as a surface.
@return The surface if one could be wrapped, NULL otherwise.
Sourcepub unsafe fn new_color_source_from_fragment_program(
&self,
frag_program: &FragmentProgram,
samplers: &[Texture],
uniform_data: &[u8],
) -> ColorSource
pub unsafe fn new_color_source_from_fragment_program( &self, frag_program: &FragmentProgram, samplers: &[Texture], uniform_data: &[u8], ) -> ColorSource
Create a color source whose pixels are shaded by a fragment program.
https://docs.flutter.dev/ui/design/graphics/fragment-shaders
§Safety
Make sure the uniform data is laid out according to the fragment program’s requirements
TODO: add an example and better docs
Sourcepub unsafe fn new_image_filter_from_fragment_program(
&self,
frag_program: &FragmentProgram,
samplers: &[Texture],
uniform_data: &[u8],
) -> ImageFilter
pub unsafe fn new_image_filter_from_fragment_program( &self, frag_program: &FragmentProgram, samplers: &[Texture], uniform_data: &[u8], ) -> ImageFilter
Create an image filter where each pixel is shaded by a fragment program.
https://docs.flutter.dev/ui/design/graphics/fragment-shaders
§Safety
Make sure the uniform data is laid out according to the fragment program’s requirements
TODO: add an example and better docs