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 { impellers::Context::new_opengl_es(|s| window.get_proc_address(s) as _) }
43 .unwrap();
44 let glow_ctx =
45 unsafe { glow::Context::from_loader_function(|s| window.get_proc_address(s) as _) };
46 unsafe {
47 let (width, height) = window.get_framebuffer_size();
48 glow_ctx.viewport(0, 0, width, height);
49 }
50 let ttx = TypographyContext::default();
51 let mut style = ParagraphStyle::default();
52 style.set_font_size(24.0);
53 style.set_font_family("Roboto");
54 style.set_font_weight(FontWeight::Bold);
55 let mut paint = Paint::default();
56 paint.set_color(Color::LIGHT_SKY_BLUE);
57 style.set_foreground(&paint);
58 Self {
59 ttx,
60 style,
61 glow_ctx,
62 itx,
63 window,
64 receiver: ev_receiver,
65 gtx,
66 events: vec![],
67 }
68 }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 =
19 unsafe { impellers::Context::new_opengl_es(|s| window.get_proc_address(s) as _) }.unwrap();
20 let glow_ctx: glow::Context =
21 unsafe { glow::Context::from_loader_function(|s| window.get_proc_address(s)) as _ };
22 // enter event loop
23 while !window.should_close() {
24 // check events
25 gtx.poll_events();
26 for (_, event) in flush_messages(&ev_receiver) {
27 match event {
28 WindowEvent::Close => {
29 window.set_should_close(true);
30 }
31 WindowEvent::FramebufferSize(_, _) => {
32 // glViewPort here
33 }
34 _ => {}
35 }
36 }
37
38 let (width, height) = window.get_framebuffer_size();
39 let mut surface = unsafe {
40 itx.wrap_fbo(
41 0,
42 PixelFormat::RGBA8888,
43 ISize::new(width.into(), height.into()),
44 )
45 }
46 .expect("failed to wrap window's framebuffer");
47 // create a display list
48 let clear_display_list = {
49 // create a display list builder
50 let mut builder = DisplayListBuilder::new(None);
51 // paint controls the properties of draw commands
52 let mut paint = Paint::default();
53 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
54 paint.set_color(Color::BLACKBERRY);
55 // fill the bounds with a color (^^that we set above)
56 builder.draw_paint(&paint);
57 let current_time = gtx.get_time(); // time in seconds since start of the program
58 // lets set the color to a color that changes with time.
59 // 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.
60 paint.set_color(Color::new_srgb(
61 current_time.sin().abs() as _,
62 current_time.cos().abs() as _,
63 current_time.tan().abs() as _,
64 ));
65 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
66 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
67 builder.build().expect("failed to build a display_list")
68 };
69 let animating_dl = {
70 // create a display list builder
71 let mut builder = DisplayListBuilder::new(None);
72 // paint controls the properties of draw commands
73 let mut paint = Paint::default();
74 let current_time = gtx.get_time(); // time in seconds since start of the program
75 // lets set the color to a color that changes with time.
76 // 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.
77 paint.set_color(Color::new_srgb(
78 current_time.sin().abs() as _,
79 current_time.cos().abs() as _,
80 current_time.tan().abs() as _,
81 ));
82 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
83 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
84 builder.build().expect("failed to build a display_list")
85 };
86 let oval_dl = {
87 // create a display list builder
88 let mut builder = DisplayListBuilder::new(None);
89 // paint controls the properties of draw commands
90 let mut paint = Paint::default();
91 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
92 paint.set_color(Color::GRANNY_APPLE);
93 builder.draw_oval(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
94 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
95 builder.build().expect("failed to build a display_list")
96 };
97 let main_display_list = {
98 let mut builder = DisplayListBuilder::new(None);
99 builder.draw_display_list(&clear_display_list, 1.0);
100 builder.draw_display_list(&animating_dl, 1.0);
101 builder.draw_display_list(&oval_dl, 1.0);
102 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
103 builder.build().expect("failed to build a display_list")
104 };
105 // Now, draw the display_list on the surface. All the commands we recorded in the display_list will be drawn.
106 // you can redraw the display_list multiple times to animate it on any number of surfaces.
107 unsafe {
108 glow_ctx.clear_color(1.0, 0.0, 0.0, 1.0);
109 glow_ctx.clear(glow::COLOR_BUFFER_BIT);
110 }
111 surface
112 .draw_display_list(&main_display_list)
113 .expect("failed to draw on surface");
114 // submit frame and wait for vsync
115 window.swap_buffers();
116 }
117
118 // drop the window/sdl or whatever
119}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?
75 pub fn enter_event_loop(
76 mut self,
77 dl: Option<DisplayList>,
78 mut user_callback: Option<UserCallback>,
79 ) {
80 let mut previous_instant = std::time::Instant::now();
81 let mut current_frame = 0;
82 let mut fps = 0;
83 let mut vsync = true;
84 // enter event loop
85 while !self.window.should_close() {
86 {
87 // record fps
88 if previous_instant.elapsed().as_secs_f64() >= 1.0 {
89 fps = current_frame;
90 current_frame = 0;
91 previous_instant = std::time::Instant::now();
92 }
93 current_frame += 1;
94 }
95 self.events.clear();
96 // check events
97 self.gtx.poll_events();
98 for (_, event) in flush_messages(&self.receiver) {
99 match &event {
100 WindowEvent::Close => {
101 self.window.set_should_close(true);
102 }
103 WindowEvent::FramebufferSize(w, h) => {
104 unsafe {
105 self.glow_ctx.viewport(0, 0, *w, *h);
106 }
107 println!("window resized to {}x{}", w, h);
108 }
109 WindowEvent::Key(Key::Space, _, Action::Release, _) => {
110 vsync = !vsync;
111 println!("setting vsync to {vsync}");
112
113 self.gtx.set_swap_interval(if vsync {
114 SwapInterval::Sync(1)
115 } else {
116 SwapInterval::None
117 });
118 }
119 _ => {}
120 }
121 self.events.push(event);
122 }
123
124 let (width, height) = self.window.get_framebuffer_size();
125 // init surface by wrapping default framebuffer (fbo = 0)
126 let mut surface = unsafe {
127 self.itx.wrap_fbo(
128 0,
129 PixelFormat::RGBA8888,
130 ISize::new(width.into(), height.into()),
131 )
132 }
133 .expect("failed to wrap window's framebuffer");
134 let mut dl_builder = DisplayListBuilder::new(Some(&Rect::from_size(
135 [width as f32, height as f32].into(),
136 )));
137
138 if let Some(dl) = dl.as_ref() {
139 dl_builder.draw_display_list(dl, 1.0);
140 }
141 // call user callback
142 if let Some(cb) = user_callback.as_mut() {
143 if let Some(display_list) = cb(&mut self) {
144 dl_builder.draw_display_list(&display_list, 1.0);
145 }
146 }
147 {
148 let mut para_builder = ParagraphBuilder::new(&self.ttx).unwrap();
149 para_builder.push_style(&self.style);
150 para_builder.add_text(&format!("avg fps: {fps}"));
151 let para = para_builder.build(1000.0).unwrap();
152 dl_builder.draw_paragraph(¶, Point::origin());
153 }
154 surface
155 .draw_display_list(&dl_builder.build().unwrap())
156 .unwrap();
157
158 // submit frame and wait for vsync
159 self.window.swap_buffers();
160 }
161 }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 =
19 unsafe { impellers::Context::new_opengl_es(|s| window.get_proc_address(s) as _) }.unwrap();
20 let glow_ctx: glow::Context =
21 unsafe { glow::Context::from_loader_function(|s| window.get_proc_address(s)) as _ };
22 // enter event loop
23 while !window.should_close() {
24 // check events
25 gtx.poll_events();
26 for (_, event) in flush_messages(&ev_receiver) {
27 match event {
28 WindowEvent::Close => {
29 window.set_should_close(true);
30 }
31 WindowEvent::FramebufferSize(_, _) => {
32 // glViewPort here
33 }
34 _ => {}
35 }
36 }
37
38 let (width, height) = window.get_framebuffer_size();
39 let mut surface = unsafe {
40 itx.wrap_fbo(
41 0,
42 PixelFormat::RGBA8888,
43 ISize::new(width.into(), height.into()),
44 )
45 }
46 .expect("failed to wrap window's framebuffer");
47 // create a display list
48 let clear_display_list = {
49 // create a display list builder
50 let mut builder = DisplayListBuilder::new(None);
51 // paint controls the properties of draw commands
52 let mut paint = Paint::default();
53 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
54 paint.set_color(Color::BLACKBERRY);
55 // fill the bounds with a color (^^that we set above)
56 builder.draw_paint(&paint);
57 let current_time = gtx.get_time(); // time in seconds since start of the program
58 // lets set the color to a color that changes with time.
59 // 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.
60 paint.set_color(Color::new_srgb(
61 current_time.sin().abs() as _,
62 current_time.cos().abs() as _,
63 current_time.tan().abs() as _,
64 ));
65 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
66 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
67 builder.build().expect("failed to build a display_list")
68 };
69 let animating_dl = {
70 // create a display list builder
71 let mut builder = DisplayListBuilder::new(None);
72 // paint controls the properties of draw commands
73 let mut paint = Paint::default();
74 let current_time = gtx.get_time(); // time in seconds since start of the program
75 // lets set the color to a color that changes with time.
76 // 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.
77 paint.set_color(Color::new_srgb(
78 current_time.sin().abs() as _,
79 current_time.cos().abs() as _,
80 current_time.tan().abs() as _,
81 ));
82 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
83 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
84 builder.build().expect("failed to build a display_list")
85 };
86 let oval_dl = {
87 // create a display list builder
88 let mut builder = DisplayListBuilder::new(None);
89 // paint controls the properties of draw commands
90 let mut paint = Paint::default();
91 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
92 paint.set_color(Color::GRANNY_APPLE);
93 builder.draw_oval(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
94 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
95 builder.build().expect("failed to build a display_list")
96 };
97 let main_display_list = {
98 let mut builder = DisplayListBuilder::new(None);
99 builder.draw_display_list(&clear_display_list, 1.0);
100 builder.draw_display_list(&animating_dl, 1.0);
101 builder.draw_display_list(&oval_dl, 1.0);
102 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
103 builder.build().expect("failed to build a display_list")
104 };
105 // Now, draw the display_list on the surface. All the commands we recorded in the display_list will be drawn.
106 // you can redraw the display_list multiple times to animate it on any number of surfaces.
107 unsafe {
108 glow_ctx.clear_color(1.0, 0.0, 0.0, 1.0);
109 glow_ctx.clear(glow::COLOR_BUFFER_BIT);
110 }
111 surface
112 .draw_display_list(&main_display_list)
113 .expect("failed to draw on surface");
114 // submit frame and wait for vsync
115 window.swap_buffers();
116 }
117
118 // drop the window/sdl or whatever
119}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(
21 ash::vk::Instance::from_raw(vk_instance as _),
22 proc_name,
23 ) as _
24 })
25 }
26 .expect("failed to create impeller context");
27 // lets see what's in here
28 let vk_info = itx.get_vulkan_info().expect("failed to get vulkan info");
29 dbg!(vk_info);
30 assert!(
31 !vk_info.vk_instance.is_null(),
32 "instance pointer from vulkan info is null"
33 );
34
35 let mut vulkan_surface_khr: ash::vk::SurfaceKHR = ash::vk::SurfaceKHR::null();
36 window
37 .create_window_surface(
38 ash::vk::Instance::from_raw(vk_info.vk_instance as _),
39 std::ptr::null(),
40 &raw mut vulkan_surface_khr,
41 )
42 .result()
43 .expect("failed to create vk surface khr");
44 assert!(!vulkan_surface_khr.is_null(), "surface pointer is null");
45 let mut vk_swapchain =
46 unsafe { itx.create_new_vulkan_swapchain(vulkan_surface_khr.as_raw() as _) }
47 .expect("failed to create vk swapchain");
48
49 // enter event loop
50 while !window.should_close() {
51 // check events
52 gtx.poll_events();
53 for (_, event) in flush_messages(&ev_receiver) {
54 if event == WindowEvent::Close {
55 window.set_should_close(true);
56 }
57 }
58
59 let clear_display_list = {
60 // create a display list builder
61 let mut builder = DisplayListBuilder::new(None);
62 // paint controls the properties of draw commands
63 let mut paint = Paint::default();
64 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
65 paint.set_color(Color::BLACKBERRY);
66 // fill the bounds with a color (^^that we set above)
67 builder.draw_paint(&paint);
68 let current_time = gtx.get_time(); // time in seconds since start of the program
69 // lets set the color to a color that changes with time.
70 // 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.
71 paint.set_color(Color::new_srgb(
72 current_time.sin().abs() as _,
73 current_time.cos().abs() as _,
74 current_time.tan().abs() as _,
75 ));
76 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
77 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
78 builder.build().expect("failed to build a display_list")
79 };
80 let animating_dl = {
81 // create a display list builder
82 let mut builder = DisplayListBuilder::new(None);
83 // paint controls the properties of draw commands
84 let mut paint = Paint::default();
85 let current_time = gtx.get_time(); // time in seconds since start of the program
86 // lets set the color to a color that changes with time.
87 // 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.
88 paint.set_color(Color::new_srgb(
89 current_time.sin().abs() as _,
90 current_time.cos().abs() as _,
91 current_time.tan().abs() as _,
92 ));
93 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
94 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
95 builder.build().expect("failed to build a display_list")
96 };
97 let oval_dl = {
98 // create a display list builder
99 let mut builder = DisplayListBuilder::new(None);
100 // paint controls the properties of draw commands
101 let mut paint = Paint::default();
102 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
103 paint.set_color(Color::GRANNY_APPLE);
104 builder.draw_oval(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
105 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
106 builder.build().expect("failed to build a display_list")
107 };
108 let main_display_list = {
109 let mut builder = DisplayListBuilder::new(None);
110 builder.draw_display_list(&clear_display_list, 1.0);
111 builder.draw_display_list(&animating_dl, 1.0);
112 builder.draw_display_list(&oval_dl, 1.0);
113 builder.build().expect("failed to build a display_list")
114 };
115 let mut surface = vk_swapchain.acquire_next_surface_new().unwrap();
116 // Now, draw the display_list on the surface. All the commands we recorded in the display_list will be drawn.
117 // you can redraw the display_list multiple times to animate it on any number of surfaces.
118
119 surface
120 .draw_display_list(&main_display_list)
121 .expect("failed to draw on surface");
122 // submit frame and wait for vsync
123 surface.present().unwrap();
124 }
125
126 // drop the window/sdl or whatever
127}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(
21 ash::vk::Instance::from_raw(vk_instance as _),
22 proc_name,
23 ) as _
24 })
25 }
26 .expect("failed to create impeller context");
27 // lets see what's in here
28 let vk_info = itx.get_vulkan_info().expect("failed to get vulkan info");
29 dbg!(vk_info);
30 assert!(
31 !vk_info.vk_instance.is_null(),
32 "instance pointer from vulkan info is null"
33 );
34
35 let mut vulkan_surface_khr: ash::vk::SurfaceKHR = ash::vk::SurfaceKHR::null();
36 window
37 .create_window_surface(
38 ash::vk::Instance::from_raw(vk_info.vk_instance as _),
39 std::ptr::null(),
40 &raw mut vulkan_surface_khr,
41 )
42 .result()
43 .expect("failed to create vk surface khr");
44 assert!(!vulkan_surface_khr.is_null(), "surface pointer is null");
45 let mut vk_swapchain =
46 unsafe { itx.create_new_vulkan_swapchain(vulkan_surface_khr.as_raw() as _) }
47 .expect("failed to create vk swapchain");
48
49 // enter event loop
50 while !window.should_close() {
51 // check events
52 gtx.poll_events();
53 for (_, event) in flush_messages(&ev_receiver) {
54 if event == WindowEvent::Close {
55 window.set_should_close(true);
56 }
57 }
58
59 let clear_display_list = {
60 // create a display list builder
61 let mut builder = DisplayListBuilder::new(None);
62 // paint controls the properties of draw commands
63 let mut paint = Paint::default();
64 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
65 paint.set_color(Color::BLACKBERRY);
66 // fill the bounds with a color (^^that we set above)
67 builder.draw_paint(&paint);
68 let current_time = gtx.get_time(); // time in seconds since start of the program
69 // lets set the color to a color that changes with time.
70 // 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.
71 paint.set_color(Color::new_srgb(
72 current_time.sin().abs() as _,
73 current_time.cos().abs() as _,
74 current_time.tan().abs() as _,
75 ));
76 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
77 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
78 builder.build().expect("failed to build a display_list")
79 };
80 let animating_dl = {
81 // create a display list builder
82 let mut builder = DisplayListBuilder::new(None);
83 // paint controls the properties of draw commands
84 let mut paint = Paint::default();
85 let current_time = gtx.get_time(); // time in seconds since start of the program
86 // lets set the color to a color that changes with time.
87 // 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.
88 paint.set_color(Color::new_srgb(
89 current_time.sin().abs() as _,
90 current_time.cos().abs() as _,
91 current_time.tan().abs() as _,
92 ));
93 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
94 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
95 builder.build().expect("failed to build a display_list")
96 };
97 let oval_dl = {
98 // create a display list builder
99 let mut builder = DisplayListBuilder::new(None);
100 // paint controls the properties of draw commands
101 let mut paint = Paint::default();
102 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
103 paint.set_color(Color::GRANNY_APPLE);
104 builder.draw_oval(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
105 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
106 builder.build().expect("failed to build a display_list")
107 };
108 let main_display_list = {
109 let mut builder = DisplayListBuilder::new(None);
110 builder.draw_display_list(&clear_display_list, 1.0);
111 builder.draw_display_list(&animating_dl, 1.0);
112 builder.draw_display_list(&oval_dl, 1.0);
113 builder.build().expect("failed to build a display_list")
114 };
115 let mut surface = vk_swapchain.acquire_next_surface_new().unwrap();
116 // Now, draw the display_list on the surface. All the commands we recorded in the display_list will be drawn.
117 // you can redraw the display_list multiple times to animate it on any number of surfaces.
118
119 surface
120 .draw_display_list(&main_display_list)
121 .expect("failed to draw on surface");
122 // submit frame and wait for vsync
123 surface.present().unwrap();
124 }
125
126 // drop the window/sdl or whatever
127}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(
21 ash::vk::Instance::from_raw(vk_instance as _),
22 proc_name,
23 ) as _
24 })
25 }
26 .expect("failed to create impeller context");
27 // lets see what's in here
28 let vk_info = itx.get_vulkan_info().expect("failed to get vulkan info");
29 dbg!(vk_info);
30 assert!(
31 !vk_info.vk_instance.is_null(),
32 "instance pointer from vulkan info is null"
33 );
34
35 let mut vulkan_surface_khr: ash::vk::SurfaceKHR = ash::vk::SurfaceKHR::null();
36 window
37 .create_window_surface(
38 ash::vk::Instance::from_raw(vk_info.vk_instance as _),
39 std::ptr::null(),
40 &raw mut vulkan_surface_khr,
41 )
42 .result()
43 .expect("failed to create vk surface khr");
44 assert!(!vulkan_surface_khr.is_null(), "surface pointer is null");
45 let mut vk_swapchain =
46 unsafe { itx.create_new_vulkan_swapchain(vulkan_surface_khr.as_raw() as _) }
47 .expect("failed to create vk swapchain");
48
49 // enter event loop
50 while !window.should_close() {
51 // check events
52 gtx.poll_events();
53 for (_, event) in flush_messages(&ev_receiver) {
54 if event == WindowEvent::Close {
55 window.set_should_close(true);
56 }
57 }
58
59 let clear_display_list = {
60 // create a display list builder
61 let mut builder = DisplayListBuilder::new(None);
62 // paint controls the properties of draw commands
63 let mut paint = Paint::default();
64 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
65 paint.set_color(Color::BLACKBERRY);
66 // fill the bounds with a color (^^that we set above)
67 builder.draw_paint(&paint);
68 let current_time = gtx.get_time(); // time in seconds since start of the program
69 // lets set the color to a color that changes with time.
70 // 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.
71 paint.set_color(Color::new_srgb(
72 current_time.sin().abs() as _,
73 current_time.cos().abs() as _,
74 current_time.tan().abs() as _,
75 ));
76 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
77 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
78 builder.build().expect("failed to build a display_list")
79 };
80 let animating_dl = {
81 // create a display list builder
82 let mut builder = DisplayListBuilder::new(None);
83 // paint controls the properties of draw commands
84 let mut paint = Paint::default();
85 let current_time = gtx.get_time(); // time in seconds since start of the program
86 // lets set the color to a color that changes with time.
87 // 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.
88 paint.set_color(Color::new_srgb(
89 current_time.sin().abs() as _,
90 current_time.cos().abs() as _,
91 current_time.tan().abs() as _,
92 ));
93 builder.draw_rect(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
94 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
95 builder.build().expect("failed to build a display_list")
96 };
97 let oval_dl = {
98 // create a display list builder
99 let mut builder = DisplayListBuilder::new(None);
100 // paint controls the properties of draw commands
101 let mut paint = Paint::default();
102 // eg: lets set the color to black. So, any drawing command with this paint will use that color.
103 paint.set_color(Color::GRANNY_APPLE);
104 builder.draw_oval(&Rect::from_size(Size::new(200.0, 200.0)), &paint);
105 // finish recording the drawing commands. This is only a "list" and we haven't drawn anything yet.
106 builder.build().expect("failed to build a display_list")
107 };
108 let main_display_list = {
109 let mut builder = DisplayListBuilder::new(None);
110 builder.draw_display_list(&clear_display_list, 1.0);
111 builder.draw_display_list(&animating_dl, 1.0);
112 builder.draw_display_list(&oval_dl, 1.0);
113 builder.build().expect("failed to build a display_list")
114 };
115 let mut surface = vk_swapchain.acquire_next_surface_new().unwrap();
116 // Now, draw the display_list on the surface. All the commands we recorded in the display_list will be drawn.
117 // you can redraw the display_list multiple times to animate it on any number of surfaces.
118
119 surface
120 .draw_display_list(&main_display_list)
121 .expect("failed to draw on surface");
122 // submit frame and wait for vsync
123 surface.present().unwrap();
124 }
125
126 // drop the window/sdl or whatever
127}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