Skip to content

Commit 6119dea

Browse files
Desktop add viewport texture (#2953)
* Allow rendering viewport texture beneath ui texture * Add viewport scale * Update desktop/src/render/fullscreen_texture.wgsl --------- Co-authored-by: Dennis Kobert <[email protected]>
1 parent 83d39fb commit 6119dea

File tree

5 files changed

+94
-18
lines changed

5 files changed

+94
-18
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

desktop/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@ cef = { workspace = true }
2828
include_dir = { workspace = true }
2929
tracing-subscriber = { workspace = true }
3030
tracing = { workspace = true }
31-
dirs = {workspace = true}
31+
dirs = { workspace = true }
32+
bytemuck = { workspace = true }

desktop/src/app.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
8383
match event {
8484
CustomEvent::UiUpdate(texture) => {
8585
if let Some(graphics_state) = self.graphics_state.as_mut() {
86-
graphics_state.bind_texture(&texture);
86+
graphics_state.bind_ui_texture(&texture);
8787
graphics_state.resize(texture.width(), texture.height());
8888
}
8989
if let Some(window) = &self.window {

desktop/src/render.rs

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::sync::Arc;
22

3+
use bytemuck::{Pod, Zeroable};
34
use thiserror::Error;
45
use winit::window::Window;
56

@@ -79,13 +80,15 @@ impl WgpuContext {
7980
.await
8081
.unwrap();
8182

83+
let required_limits = adapter.limits();
84+
8285
let (device, queue) = adapter
8386
.request_device(&wgpu::DeviceDescriptor {
84-
required_features: wgpu::Features::empty(),
85-
required_limits: wgpu::Limits::default(),
8687
label: None,
88+
required_features: wgpu::Features::PUSH_CONSTANTS,
89+
required_limits,
8790
memory_hints: Default::default(),
88-
..Default::default()
91+
trace: wgpu::Trace::Off,
8992
})
9093
.await
9194
.unwrap();
@@ -99,10 +102,13 @@ pub(crate) struct GraphicsState {
99102
surface: wgpu::Surface<'static>,
100103
context: WgpuContext,
101104
config: wgpu::SurfaceConfiguration,
102-
texture: Option<wgpu::Texture>,
103-
bind_group: Option<wgpu::BindGroup>,
104105
render_pipeline: wgpu::RenderPipeline,
105106
sampler: wgpu::Sampler,
107+
viewport_scale: [f32; 2],
108+
viewport_offset: [f32; 2],
109+
viewport_texture: Option<wgpu::Texture>,
110+
ui_texture: Option<wgpu::Texture>,
111+
bind_group: Option<wgpu::BindGroup>,
106112
}
107113

108114
impl GraphicsState {
@@ -156,6 +162,16 @@ impl GraphicsState {
156162
wgpu::BindGroupLayoutEntry {
157163
binding: 1,
158164
visibility: wgpu::ShaderStages::FRAGMENT,
165+
ty: wgpu::BindingType::Texture {
166+
multisampled: false,
167+
view_dimension: wgpu::TextureViewDimension::D2,
168+
sample_type: wgpu::TextureSampleType::Float { filterable: true },
169+
},
170+
count: None,
171+
},
172+
wgpu::BindGroupLayoutEntry {
173+
binding: 2,
174+
visibility: wgpu::ShaderStages::FRAGMENT,
159175
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
160176
count: None,
161177
},
@@ -166,7 +182,10 @@ impl GraphicsState {
166182
let render_pipeline_layout = context.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
167183
label: Some("Render Pipeline Layout"),
168184
bind_group_layouts: &[&texture_bind_group_layout],
169-
push_constant_ranges: &[],
185+
push_constant_ranges: &[wgpu::PushConstantRange {
186+
stages: wgpu::ShaderStages::FRAGMENT,
187+
range: 0..size_of::<Constants>() as u32,
188+
}],
170189
});
171190

172191
let render_pipeline = context.device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
@@ -211,10 +230,13 @@ impl GraphicsState {
211230
surface,
212231
context,
213232
config,
214-
texture: None,
215-
bind_group: None,
216233
render_pipeline,
217234
sampler,
235+
viewport_scale: [1.0, 1.0],
236+
viewport_offset: [0.0, 0.0],
237+
viewport_texture: None,
238+
ui_texture: None,
239+
bind_group: None,
218240
}
219241
}
220242

@@ -226,25 +248,47 @@ impl GraphicsState {
226248
}
227249
}
228250

229-
pub(crate) fn bind_texture(&mut self, texture: &wgpu::Texture) {
230-
let bind_group = self.create_bindgroup(texture);
231-
self.texture = Some(texture.clone());
251+
pub(crate) fn bind_ui_texture(&mut self, texture: &wgpu::Texture) {
252+
let bind_group = self.create_bindgroup(texture, &self.viewport_texture.clone().unwrap_or(texture.clone()));
253+
254+
self.ui_texture = Some(texture.clone());
232255

233256
self.bind_group = Some(bind_group);
234257
}
235258

236-
fn create_bindgroup(&self, texture: &wgpu::Texture) -> wgpu::BindGroup {
237-
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
259+
pub(crate) fn bind_viewport_texture(&mut self, texture: &wgpu::Texture) {
260+
let bind_group = self.create_bindgroup(&self.ui_texture.clone().unwrap_or(texture.clone()), texture);
261+
262+
self.viewport_texture = Some(texture.clone());
263+
264+
self.bind_group = Some(bind_group);
265+
}
266+
267+
pub(crate) fn set_viewport_scale(&mut self, scale: [f32; 2]) {
268+
self.viewport_scale = scale;
269+
}
270+
271+
pub(crate) fn set_viewport_offset(&mut self, offset: [f32; 2]) {
272+
self.viewport_offset = offset;
273+
}
274+
275+
fn create_bindgroup(&self, ui_texture: &wgpu::Texture, viewport_texture: &wgpu::Texture) -> wgpu::BindGroup {
276+
let ui_texture_view = ui_texture.create_view(&wgpu::TextureViewDescriptor::default());
277+
let viewport_texture_view = viewport_texture.create_view(&wgpu::TextureViewDescriptor::default());
238278

239279
self.context.device.create_bind_group(&wgpu::BindGroupDescriptor {
240280
layout: &self.render_pipeline.get_bind_group_layout(0),
241281
entries: &[
242282
wgpu::BindGroupEntry {
243283
binding: 0,
244-
resource: wgpu::BindingResource::TextureView(&texture_view),
284+
resource: wgpu::BindingResource::TextureView(&ui_texture_view),
245285
},
246286
wgpu::BindGroupEntry {
247287
binding: 1,
288+
resource: wgpu::BindingResource::TextureView(&viewport_texture_view),
289+
},
290+
wgpu::BindGroupEntry {
291+
binding: 2,
248292
resource: wgpu::BindingResource::Sampler(&self.sampler),
249293
},
250294
],
@@ -275,6 +319,14 @@ impl GraphicsState {
275319
});
276320

277321
render_pass.set_pipeline(&self.render_pipeline);
322+
render_pass.set_push_constants(
323+
wgpu::ShaderStages::FRAGMENT,
324+
0,
325+
bytemuck::bytes_of(&Constants {
326+
viewport_scale: self.viewport_scale,
327+
viewport_offset: self.viewport_offset,
328+
}),
329+
);
278330
if let Some(bind_group) = &self.bind_group {
279331
render_pass.set_bind_group(0, bind_group, &[]);
280332
render_pass.draw(0..6, 0..1); // Draw 3 vertices for fullscreen triangle
@@ -288,3 +340,10 @@ impl GraphicsState {
288340
Ok(())
289341
}
290342
}
343+
344+
#[repr(C)]
345+
#[derive(Copy, Clone, Pod, Zeroable)]
346+
struct Constants {
347+
viewport_scale: [f32; 2],
348+
viewport_offset: [f32; 2],
349+
}

desktop/src/render/fullscreen_texture.wgsl

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,27 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
2525
return out;
2626
}
2727

28+
struct Constants {
29+
viewport_scale: vec2<f32>,
30+
viewport_offset: vec2<f32>,
31+
};
32+
33+
var<push_constant> constants: Constants;
34+
2835
@group(0) @binding(0)
29-
var t_diffuse: texture_2d<f32>;
36+
var t_ui: texture_2d<f32>;
3037
@group(0) @binding(1)
38+
var t_viewport: texture_2d<f32>;
39+
@group(0) @binding(2)
3140
var s_diffuse: sampler;
3241

3342
@fragment
3443
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
35-
return textureSample(t_diffuse, s_diffuse, in.tex_coords);
44+
let ui_color: vec4<f32> = textureSample(t_ui, s_diffuse, in.tex_coords);
45+
if (ui_color.a == 1.0) {
46+
return ui_color;
47+
}
48+
let viewport_tex_coords = (in.tex_coords - constants.viewport_offset) * constants.viewport_scale;
49+
let viewport_color: vec4<f32> = textureSample(t_viewport, s_diffuse, viewport_tex_coords);
50+
return ui_color * ui_color.a + viewport_color * (1.0 - ui_color.a);
3651
}

0 commit comments

Comments
 (0)