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 (line 42)
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
Hide additional examples
examples/hello.rs (line 19)
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}
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 127-131)
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(&para, 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
Hide additional examples
examples/hello.rs (lines 40-44)
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}
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-24)
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}
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 28)
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}
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 46)
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}
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

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.