diff --git a/tetanes/assets/main.css b/tetanes/assets/main.css index da993709..3cbad5eb 100644 --- a/tetanes/assets/main.css +++ b/tetanes/assets/main.css @@ -125,6 +125,7 @@ canvas { #error { color: #ff3333; text-align: center; + margin: auto; } .version-download { diff --git a/tetanes/shaders/crt-easymode.wgsl b/tetanes/shaders/crt-easymode.wgsl index aab0bc37..a59b6ac5 100644 --- a/tetanes/shaders/crt-easymode.wgsl +++ b/tetanes/shaders/crt-easymode.wgsl @@ -54,7 +54,12 @@ fn vs_main( // Fragment shader -@group(0) @binding(0) var out_size: vec2; +struct Output { + size: vec2, + padding: vec2, +} + +@group(0) @binding(0) var out: Output; @group(0) @binding(1) var tex: texture_2d; @group(0) @binding(2) var tex_sampler: sampler; @@ -143,7 +148,7 @@ fn fs_main(@location(0) v_uv: vec2) -> @location(0) vec4 { let insize = dims; let mask = 1.0 - MASK_STRENGTH; - let mod_fac = floor(v_uv * out_size * dims / (insize * vec2(MASK_SIZE, MASK_DOT_HEIGHT * MASK_SIZE))); + let mod_fac = floor(v_uv * out.size * dims / (insize * vec2(MASK_SIZE, MASK_DOT_HEIGHT * MASK_SIZE))); let dot_no = i32(((mod_fac.x + (mod_fac.y % 2.0) * MASK_STAGGER) / MASK_DOT_WIDTH % 3.0)); var mask_weight: vec3; diff --git a/tetanes/src/nes/emulation.rs b/tetanes/src/nes/emulation.rs index 071efa8e..d2b80c36 100644 --- a/tetanes/src/nes/emulation.rs +++ b/tetanes/src/nes/emulation.rs @@ -850,9 +850,9 @@ impl State { duration.map(|duration| { // Parking thread is only required for Multi-threaded emulation to save CPU cycles. if self.threaded { - Duration::ZERO - } else { duration + } else { + Duration::ZERO } }) } @@ -881,6 +881,9 @@ impl State { viewport_id: ViewportId::ROOT, when: Instant::now() + park_timeout, }); + if self.control_deck.is_running() && self.run_state.paused() { + self.send_frame(); + } thread::park_timeout(park_timeout); return; } diff --git a/tetanes/src/nes/renderer.rs b/tetanes/src/nes/renderer.rs index 2dbfd300..55614e44 100644 --- a/tetanes/src/nes/renderer.rs +++ b/tetanes/src/nes/renderer.rs @@ -236,15 +236,7 @@ impl Renderer { Some("nes frame"), ); - if !matches!(cfg.renderer.shader, Shader::None) { - let frame_painter = - shader::Resources::new(&render_state, &texture.view, cfg.renderer.shader); - render_state - .renderer - .write() - .callback_resources - .insert(frame_painter); - } + Self::set_shader_resource(&render_state, &texture.view, cfg.renderer.shader); let gui = Rc::new(RefCell::new(Gui::new( tx.clone(), @@ -464,24 +456,7 @@ impl Renderer { } NesEvent::Config(ConfigEvent::Shader(shader)) => { if let Some(render_state) = &self.render_state { - if matches!(shader, Shader::None) { - render_state - .renderer - .write() - .callback_resources - .remove::(); - } else { - let frame_painter = shader::Resources::new( - render_state, - &self.texture.view, - cfg.renderer.shader, - ); - render_state - .renderer - .write() - .callback_resources - .insert(frame_painter); - } + Self::set_shader_resource(render_state, &self.texture.view, *shader); } } _ => (), @@ -1351,11 +1326,34 @@ impl Renderer { self.gui.borrow().aspect_ratio(cfg), ); self.gui.borrow_mut().texture = self.texture.sized_texture(); + + Self::set_shader_resource( + render_state, + &self.texture.view, + cfg.renderer.shader, + ); } self.gui.borrow_mut().resize_texture = false; } } } + + fn set_shader_resource(render_state: &RenderState, view: &wgpu::TextureView, shader: Shader) { + if matches!(shader, Shader::None) { + render_state + .renderer + .write() + .callback_resources + .remove::(); + } else { + let shader_resource = shader::Resources::new(render_state, view, shader); + render_state + .renderer + .write() + .callback_resources + .insert(shader_resource); + } + } } impl Viewport { diff --git a/tetanes/src/nes/renderer/shader.rs b/tetanes/src/nes/renderer/shader.rs index bb16b9fe..448c1dfc 100644 --- a/tetanes/src/nes/renderer/shader.rs +++ b/tetanes/src/nes/renderer/shader.rs @@ -69,7 +69,7 @@ impl egui_wgpu::CallbackTrait for Renderer { queue.write_buffer( &shader_res.size_uniform, 0, - bytemuck::cast_slice(&[self.rect.width(), self.rect.height()]), + bytemuck::cast_slice(&[self.rect.width(), self.rect.height(), 0.0, 0.0]), ); } Vec::new() @@ -99,9 +99,10 @@ pub struct Resources { impl Resources { pub fn new(render_state: &RenderState, view: &wgpu::TextureView, shader: Shader) -> Self { + let size_uniform_size = 16; let size_uniform = render_state.device.create_buffer(&wgpu::BufferDescriptor { label: Some("Frame Size Buffer"), - size: 8, + size: size_uniform_size, // 16-byte minimum alignment, even though we only need 8 bytes usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM, mapped_at_creation: false, }); @@ -118,7 +119,7 @@ impl Resources { ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, - min_binding_size: NonZeroU64::new(8), + min_binding_size: NonZeroU64::new(size_uniform_size), }, count: None, },