1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-01 22:30:03 -04:00

eframe support for wgpu on the web (#2107)

* basic working wgpu @ webgl on websys

* fix glow compile error

* introduced WebPainter trait, provide wgpu renderstate

* WebPainterWgpu destroy implemented

* make custom3d demo work on wgpu backend

* changelog entry for wgpu support eframe wasm

* remove temporary logging hack

* stop using pollster for web
we're actually not allowed to block - this only worked because wgpu on webgl doesn't actually cause anything blocking. However, when trying webgpu this became an issue

* revert cargo update

* compile error if neither glow nor wgpu features are enabled

* code cleanup

* Error handling

* Update changelog with link

* Make sure --all-features work

* Select best framebuffer format from the available ones

* update to wasm-bindgen 0.2.83

* Fix typo

* Clean up Cargo.toml

* Log about using the wgpu painter

* fixup wgpu labels

* fix custom3d_wgpu_shader ub padding

* remove duplicated uniforms struct in wgsl shader for custom3d

* Update docs: add async/await to the web 'start' function

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
Andreas Reich
2022-10-05 20:14:18 +02:00
committed by GitHub
parent c441f33ecf
commit c2a37f4bd8
20 changed files with 432 additions and 211 deletions

View File

@@ -1,4 +1,4 @@
use std::sync::Arc;
use std::{num::NonZeroU64, sync::Arc};
use eframe::{
egui_wgpu::{self, wgpu},
@@ -18,32 +18,32 @@ impl Custom3d {
let device = &wgpu_render_state.device;
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: None,
label: Some("custom3d"),
source: wgpu::ShaderSource::Wgsl(include_str!("./custom3d_wgpu_shader.wgsl").into()),
});
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: None,
label: Some("custom3d"),
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
min_binding_size: NonZeroU64::new(16),
},
count: None,
}],
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: None,
label: Some("custom3d"),
bind_group_layouts: &[&bind_group_layout],
push_constant_ranges: &[],
});
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: None,
label: Some("custom3d"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
@@ -62,15 +62,15 @@ impl Custom3d {
});
let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(&[0.0]),
usage: wgpu::BufferUsages::COPY_DST
| wgpu::BufferUsages::MAP_WRITE
| wgpu::BufferUsages::UNIFORM,
label: Some("custom3d"),
contents: bytemuck::cast_slice(&[0.0_f32; 4]), // 16 bytes aligned!
// Mapping at creation (as done by the create_buffer_init utility) doesn't require us to to add the MAP_WRITE usage
// (this *happens* to workaround this bug )
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM,
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: None,
label: Some("custom3d"),
layout: &bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
@@ -165,7 +165,11 @@ struct TriangleRenderResources {
impl TriangleRenderResources {
fn prepare(&self, _device: &wgpu::Device, queue: &wgpu::Queue, angle: f32) {
// Update our uniform buffer with the angle from the UI
queue.write_buffer(&self.uniform_buffer, 0, bytemuck::cast_slice(&[angle]));
queue.write_buffer(
&self.uniform_buffer,
0,
bytemuck::cast_slice(&[angle, 0.0, 0.0, 0.0]),
);
}
fn paint<'rp>(&'rp self, render_pass: &mut wgpu::RenderPass<'rp>) {

View File

@@ -4,7 +4,7 @@ struct VertexOut {
};
struct Uniforms {
angle: f32,
@size(16) angle: f32, // pad to 16 bytes
};
@group(0) @binding(0)

View File

@@ -62,13 +62,14 @@ pub fn init_wasm_hooks() {
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn start_separate(canvas_id: &str) -> Result<WebHandle, wasm_bindgen::JsValue> {
pub async fn start_separate(canvas_id: &str) -> Result<WebHandle, wasm_bindgen::JsValue> {
let web_options = eframe::WebOptions::default();
let handle = eframe::start_web(
canvas_id,
web_options,
Box::new(|cc| Box::new(WrapApp::new(cc))),
)
.await
.map(|handle| WebHandle { handle });
handle
@@ -80,7 +81,7 @@ pub fn start_separate(canvas_id: &str) -> Result<WebHandle, wasm_bindgen::JsValu
/// You can add more callbacks like this if you want to call in to your code.
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn start(canvas_id: &str) -> Result<WebHandle, wasm_bindgen::JsValue> {
pub async fn start(canvas_id: &str) -> Result<WebHandle, wasm_bindgen::JsValue> {
init_wasm_hooks();
start_separate(canvas_id)
start_separate(canvas_id).await
}