Skip to main content

Context

Struct Context 

Source
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

Source

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?
examples/common.rs (lines 43-48)
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
Hide additional examples
examples/hello.rs (lines 19-24)
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}
Source

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?
examples/common.rs (lines 140-144)
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(&para, 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
Hide additional examples
examples/hello.rs (lines 53-57)
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}
Source

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?
examples/backdrop_blur.rs (line 22)
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
Hide additional examples
examples/star_clip.rs (line 13)
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}
Source

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.

Source

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.

Source

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?
examples/glfw_vulkan.rs (lines 18-23)
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}
Source

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?
examples/glfw_vulkan.rs (line 27)
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}
Source

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?
examples/glfw_vulkan.rs (line 47)
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}
Source

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.

Source

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

Source

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

Trait Implementations§

Source§

impl Debug for Context

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for Context

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.