Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Custom Shader Widget #2085

Merged
merged 26 commits into from
Nov 14, 2023
Merged

Conversation

bungoboingo
Copy link
Contributor

🌈 Custom Shader Widget

iced_cubes_dot_mp4.mov

This PR implements RFC #23 and adds support for a new type of widget which allows for the use of custom pipelines & shaders embedded directly into your Iced application, using Iced's existing iced_wgpu crate! 🥳

🎨 Creating a custom shader

If you have the wgpu feature enabled for Iced, a custom shader can be created very similarly to a Canvas:

iced::widget::Shader::new(program);

Each shader widget requires a widget::shader::Program which holds internal state, provides ways to update the widget based on input events, and defines a special associated type called Primitive.

pub trait Program<Message> {
    type State;

    type Primitive: shader::Primitive;

    fn update(..) -> (event::Status, Option<Message>);

    fn draw(..) -> Self::Primitive;

    fn mouse_interaction(..) -> mouse::Interaction;
}

🔺 Primitives

A Primitive must implement a new trait, shader::Primitive. This trait defines how a the Primitive will be uploaded to the GPU, and how it will be rendered.

pub trait Primitive {
    fn prepare(
        &self,
        format: wgpu::TextureFormat,
        device: &wgpu::Device,
        queue: &wgpu::Queue,
        target_size: Size<u32>,
        scale_factor: f32,
        transform: Transformation,
        storage: &mut Storage,
    );

    fn render(
        &self,
        storage: &Storage,
        bounds: Rectangle<u32>,
        target: &wgpu::TextureView,
        target_size: Size<u32>,
        encoder: &mut wgpu::CommandEncoder,
    );
}

This trait gives unique widget-level access to necessary wgpu reference needed to render primitives! Note that due to not knowing the nature of what a custom shader might contain, every render call gets access to the CommandEncoder and must start its own render pass.

The Primitive trait has access to the underlying custom pipeline storage, appropriately named Storage, where users can store & fetch their pipelines to prepare & render their primitives, referenced by TypeID.

//for example..
fn prepare(
        &self,
        format: wgpu::TextureFormat,
        device: &wgpu::Device,
        queue: &wgpu::Queue,
        target_size: Size<u32>,
        _scale_factor: f32,
        _transform: Transformation,
        storage: &mut shader::Storage,
    ) {
        if !storage.has::<MyPipeline>() {
            storage.store(MyPipeline::new(device, queue, format, target_size))
        }

        let pipeline = storage.get_mut::<MyPipeline>().unwrap();

        //upload data to GPU!
        pipeline.update(
            device,
            queue,
            target_size,
            &self.uniforms,
            self.cubes.len(),
            &self.cubes,
        );
    }

Let me know what you think! I've tried to work through few different use cases and hope I've covered all bases. Go forth and shade! 🔢 🌈

core/src/rectangle.rs Outdated Show resolved Hide resolved
Copy link
Member

@hecrj hecrj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome stuff, @bungoboingo!

I made a bunch of changes here and there, moved some stuff around, and renamed some things. Check out the commit history and let me know what you think!

@0x7CFE
Copy link
Contributor

0x7CFE commented Nov 14, 2023

Amazing progress! Any estimates on when this would be merged?

@hecrj
Copy link
Member

hecrj commented Nov 14, 2023

@0x7CFE Today or tomorrow, most likely!

@bungoboingo
Copy link
Contributor Author

Changes all LGTM! Let's 🚢!

@hecrj hecrj merged commit b474a2b into iced-rs:master Nov 14, 2023
13 checks passed
@bungoboingo bungoboingo deleted the shader-widget branch November 14, 2023 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants