mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-06 06:48:12 +08:00
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 <dennis@kobert.dev>
This commit is contained in:
Generated
+1
@@ -1834,6 +1834,7 @@ dependencies = [
|
|||||||
name = "graphite-desktop"
|
name = "graphite-desktop"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
"cef",
|
"cef",
|
||||||
"dirs",
|
"dirs",
|
||||||
"futures",
|
"futures",
|
||||||
|
|||||||
+2
-1
@@ -28,4 +28,5 @@ cef = { workspace = true }
|
|||||||
include_dir = { workspace = true }
|
include_dir = { workspace = true }
|
||||||
tracing-subscriber = { workspace = true }
|
tracing-subscriber = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
dirs = {workspace = true}
|
dirs = { workspace = true }
|
||||||
|
bytemuck = { workspace = true }
|
||||||
|
|||||||
+1
-1
@@ -83,7 +83,7 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
|
|||||||
match event {
|
match event {
|
||||||
CustomEvent::UiUpdate(texture) => {
|
CustomEvent::UiUpdate(texture) => {
|
||||||
if let Some(graphics_state) = self.graphics_state.as_mut() {
|
if let Some(graphics_state) = self.graphics_state.as_mut() {
|
||||||
graphics_state.bind_texture(&texture);
|
graphics_state.bind_ui_texture(&texture);
|
||||||
graphics_state.resize(texture.width(), texture.height());
|
graphics_state.resize(texture.width(), texture.height());
|
||||||
}
|
}
|
||||||
if let Some(window) = &self.window {
|
if let Some(window) = &self.window {
|
||||||
|
|||||||
+73
-14
@@ -1,5 +1,6 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use bytemuck::{Pod, Zeroable};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use winit::window::Window;
|
use winit::window::Window;
|
||||||
|
|
||||||
@@ -79,13 +80,15 @@ impl WgpuContext {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let required_limits = adapter.limits();
|
||||||
|
|
||||||
let (device, queue) = adapter
|
let (device, queue) = adapter
|
||||||
.request_device(&wgpu::DeviceDescriptor {
|
.request_device(&wgpu::DeviceDescriptor {
|
||||||
required_features: wgpu::Features::empty(),
|
|
||||||
required_limits: wgpu::Limits::default(),
|
|
||||||
label: None,
|
label: None,
|
||||||
|
required_features: wgpu::Features::PUSH_CONSTANTS,
|
||||||
|
required_limits,
|
||||||
memory_hints: Default::default(),
|
memory_hints: Default::default(),
|
||||||
..Default::default()
|
trace: wgpu::Trace::Off,
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -99,10 +102,13 @@ pub(crate) struct GraphicsState {
|
|||||||
surface: wgpu::Surface<'static>,
|
surface: wgpu::Surface<'static>,
|
||||||
context: WgpuContext,
|
context: WgpuContext,
|
||||||
config: wgpu::SurfaceConfiguration,
|
config: wgpu::SurfaceConfiguration,
|
||||||
texture: Option<wgpu::Texture>,
|
|
||||||
bind_group: Option<wgpu::BindGroup>,
|
|
||||||
render_pipeline: wgpu::RenderPipeline,
|
render_pipeline: wgpu::RenderPipeline,
|
||||||
sampler: wgpu::Sampler,
|
sampler: wgpu::Sampler,
|
||||||
|
viewport_scale: [f32; 2],
|
||||||
|
viewport_offset: [f32; 2],
|
||||||
|
viewport_texture: Option<wgpu::Texture>,
|
||||||
|
ui_texture: Option<wgpu::Texture>,
|
||||||
|
bind_group: Option<wgpu::BindGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GraphicsState {
|
impl GraphicsState {
|
||||||
@@ -156,6 +162,16 @@ impl GraphicsState {
|
|||||||
wgpu::BindGroupLayoutEntry {
|
wgpu::BindGroupLayoutEntry {
|
||||||
binding: 1,
|
binding: 1,
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Texture {
|
||||||
|
multisampled: false,
|
||||||
|
view_dimension: wgpu::TextureViewDimension::D2,
|
||||||
|
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 2,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
||||||
count: None,
|
count: None,
|
||||||
},
|
},
|
||||||
@@ -166,7 +182,10 @@ impl GraphicsState {
|
|||||||
let render_pipeline_layout = context.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
let render_pipeline_layout = context.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
label: Some("Render Pipeline Layout"),
|
label: Some("Render Pipeline Layout"),
|
||||||
bind_group_layouts: &[&texture_bind_group_layout],
|
bind_group_layouts: &[&texture_bind_group_layout],
|
||||||
push_constant_ranges: &[],
|
push_constant_ranges: &[wgpu::PushConstantRange {
|
||||||
|
stages: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
range: 0..size_of::<Constants>() as u32,
|
||||||
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
let render_pipeline = context.device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
let render_pipeline = context.device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
@@ -211,10 +230,13 @@ impl GraphicsState {
|
|||||||
surface,
|
surface,
|
||||||
context,
|
context,
|
||||||
config,
|
config,
|
||||||
texture: None,
|
|
||||||
bind_group: None,
|
|
||||||
render_pipeline,
|
render_pipeline,
|
||||||
sampler,
|
sampler,
|
||||||
|
viewport_scale: [1.0, 1.0],
|
||||||
|
viewport_offset: [0.0, 0.0],
|
||||||
|
viewport_texture: None,
|
||||||
|
ui_texture: None,
|
||||||
|
bind_group: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,25 +248,47 @@ impl GraphicsState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn bind_texture(&mut self, texture: &wgpu::Texture) {
|
pub(crate) fn bind_ui_texture(&mut self, texture: &wgpu::Texture) {
|
||||||
let bind_group = self.create_bindgroup(texture);
|
let bind_group = self.create_bindgroup(texture, &self.viewport_texture.clone().unwrap_or(texture.clone()));
|
||||||
self.texture = Some(texture.clone());
|
|
||||||
|
self.ui_texture = Some(texture.clone());
|
||||||
|
|
||||||
self.bind_group = Some(bind_group);
|
self.bind_group = Some(bind_group);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_bindgroup(&self, texture: &wgpu::Texture) -> wgpu::BindGroup {
|
pub(crate) fn bind_viewport_texture(&mut self, texture: &wgpu::Texture) {
|
||||||
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
let bind_group = self.create_bindgroup(&self.ui_texture.clone().unwrap_or(texture.clone()), texture);
|
||||||
|
|
||||||
|
self.viewport_texture = Some(texture.clone());
|
||||||
|
|
||||||
|
self.bind_group = Some(bind_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_viewport_scale(&mut self, scale: [f32; 2]) {
|
||||||
|
self.viewport_scale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_viewport_offset(&mut self, offset: [f32; 2]) {
|
||||||
|
self.viewport_offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_bindgroup(&self, ui_texture: &wgpu::Texture, viewport_texture: &wgpu::Texture) -> wgpu::BindGroup {
|
||||||
|
let ui_texture_view = ui_texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
let viewport_texture_view = viewport_texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
self.context.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
self.context.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
layout: &self.render_pipeline.get_bind_group_layout(0),
|
layout: &self.render_pipeline.get_bind_group_layout(0),
|
||||||
entries: &[
|
entries: &[
|
||||||
wgpu::BindGroupEntry {
|
wgpu::BindGroupEntry {
|
||||||
binding: 0,
|
binding: 0,
|
||||||
resource: wgpu::BindingResource::TextureView(&texture_view),
|
resource: wgpu::BindingResource::TextureView(&ui_texture_view),
|
||||||
},
|
},
|
||||||
wgpu::BindGroupEntry {
|
wgpu::BindGroupEntry {
|
||||||
binding: 1,
|
binding: 1,
|
||||||
|
resource: wgpu::BindingResource::TextureView(&viewport_texture_view),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 2,
|
||||||
resource: wgpu::BindingResource::Sampler(&self.sampler),
|
resource: wgpu::BindingResource::Sampler(&self.sampler),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -275,6 +319,14 @@ impl GraphicsState {
|
|||||||
});
|
});
|
||||||
|
|
||||||
render_pass.set_pipeline(&self.render_pipeline);
|
render_pass.set_pipeline(&self.render_pipeline);
|
||||||
|
render_pass.set_push_constants(
|
||||||
|
wgpu::ShaderStages::FRAGMENT,
|
||||||
|
0,
|
||||||
|
bytemuck::bytes_of(&Constants {
|
||||||
|
viewport_scale: self.viewport_scale,
|
||||||
|
viewport_offset: self.viewport_offset,
|
||||||
|
}),
|
||||||
|
);
|
||||||
if let Some(bind_group) = &self.bind_group {
|
if let Some(bind_group) = &self.bind_group {
|
||||||
render_pass.set_bind_group(0, bind_group, &[]);
|
render_pass.set_bind_group(0, bind_group, &[]);
|
||||||
render_pass.draw(0..6, 0..1); // Draw 3 vertices for fullscreen triangle
|
render_pass.draw(0..6, 0..1); // Draw 3 vertices for fullscreen triangle
|
||||||
@@ -288,3 +340,10 @@ impl GraphicsState {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Pod, Zeroable)]
|
||||||
|
struct Constants {
|
||||||
|
viewport_scale: [f32; 2],
|
||||||
|
viewport_offset: [f32; 2],
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,12 +25,27 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Constants {
|
||||||
|
viewport_scale: vec2<f32>,
|
||||||
|
viewport_offset: vec2<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
var<push_constant> constants: Constants;
|
||||||
|
|
||||||
@group(0) @binding(0)
|
@group(0) @binding(0)
|
||||||
var t_diffuse: texture_2d<f32>;
|
var t_ui: texture_2d<f32>;
|
||||||
@group(0) @binding(1)
|
@group(0) @binding(1)
|
||||||
|
var t_viewport: texture_2d<f32>;
|
||||||
|
@group(0) @binding(2)
|
||||||
var s_diffuse: sampler;
|
var s_diffuse: sampler;
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
return textureSample(t_diffuse, s_diffuse, in.tex_coords);
|
let ui_color: vec4<f32> = textureSample(t_ui, s_diffuse, in.tex_coords);
|
||||||
|
if (ui_color.a == 1.0) {
|
||||||
|
return ui_color;
|
||||||
|
}
|
||||||
|
let viewport_tex_coords = (in.tex_coords - constants.viewport_offset) * constants.viewport_scale;
|
||||||
|
let viewport_color: vec4<f32> = textureSample(t_viewport, s_diffuse, viewport_tex_coords);
|
||||||
|
return ui_color * ui_color.a + viewport_color * (1.0 - ui_color.a);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user