Use one texture with two channels for video

This commit is contained in:
Simon Gellis 2024-11-03 13:25:20 -05:00
parent 8fdff927eb
commit b025f72604
5 changed files with 25 additions and 42 deletions

View File

@ -37,13 +37,13 @@ fn vs_main(
// Fragment shader // Fragment shader
@group(0) @binding(0) @group(0) @binding(0)
var u_textures: binding_array<texture_2d<f32>>; var u_texture: texture_2d<f32>;
@group(0) @binding(1) @group(0) @binding(1)
var u_sampler: sampler; var u_sampler: sampler;
@fragment @fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
return textureSample(u_textures[0], u_sampler, in.tex_coords); return textureSample(u_texture, u_sampler, in.tex_coords);
// return vec4<f32>(0.3, 0.2, 0.1, 1.0); // return vec4<f32>(0.3, 0.2, 0.1, 1.0);
} }

View File

@ -2,7 +2,7 @@ use imgui::*;
use imgui_wgpu::{Renderer, RendererConfig}; use imgui_wgpu::{Renderer, RendererConfig};
use imgui_winit_support::WinitPlatform; use imgui_winit_support::WinitPlatform;
use pollster::block_on; use pollster::block_on;
use std::{num::NonZero, sync::Arc, time::Instant}; use std::{sync::Arc, time::Instant};
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use winit::platform::windows::{CornerPreference, WindowAttributesExtWindows as _}; use winit::platform::windows::{CornerPreference, WindowAttributesExtWindows as _};
use winit::{ use winit::{
@ -69,27 +69,15 @@ impl AppWindow {
})) }))
.unwrap(); .unwrap();
let (device, queue) = block_on(adapter.request_device( let (device, queue) =
&wgpu::DeviceDescriptor { block_on(adapter.request_device(&wgpu::DeviceDescriptor::default(), None)).unwrap();
required_features: wgpu::Features::TEXTURE_BINDING_ARRAY,
..wgpu::DeviceDescriptor::default()
},
None,
))
.unwrap();
let queue = Arc::new(queue); let queue = Arc::new(queue);
let eyes = [ let eyes = Arc::new(GameRenderer::create_texture(&device, "eye"));
Arc::new(GameRenderer::create_texture(&device, "left eye")),
Arc::new(GameRenderer::create_texture(&device, "right eye")),
];
client.send_command(EmulatorCommand::SetRenderer(GameRenderer { client.send_command(EmulatorCommand::SetRenderer(GameRenderer {
queue: queue.clone(), queue: queue.clone(),
eyes: eyes.clone(), eyes: eyes.clone(),
})); }));
let eyes = [ let eyes = eyes.create_view(&wgpu::TextureViewDescriptor::default());
eyes[0].create_view(&wgpu::TextureViewDescriptor::default()),
eyes[1].create_view(&wgpu::TextureViewDescriptor::default()),
];
let sampler = device.create_sampler(&wgpu::SamplerDescriptor::default()); let sampler = device.create_sampler(&wgpu::SamplerDescriptor::default());
let texture_bind_group_layout = let texture_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@ -103,7 +91,7 @@ impl AppWindow {
view_dimension: wgpu::TextureViewDimension::D2, view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false, multisampled: false,
}, },
count: NonZero::new(2), count: None,
}, },
wgpu::BindGroupLayoutEntry { wgpu::BindGroupLayoutEntry {
binding: 1, binding: 1,
@ -119,7 +107,7 @@ impl AppWindow {
entries: &[ entries: &[
wgpu::BindGroupEntry { wgpu::BindGroupEntry {
binding: 0, binding: 0,
resource: wgpu::BindingResource::TextureViewArray(&[&eyes[0], &eyes[1]]), resource: wgpu::BindingResource::TextureView(&eyes),
}, },
wgpu::BindGroupEntry { wgpu::BindGroupEntry {
binding: 1, binding: 1,

View File

@ -33,7 +33,7 @@ impl Emulator {
} }
pub fn run(&mut self) { pub fn run(&mut self) {
let mut eye_contents = [vec![0u8; 384 * 224], vec![0u8; 384 * 224]]; let mut eye_contents = vec![0u8; 384 * 224 * 2];
loop { loop {
self.sim.emulate_frame(); self.sim.emulate_frame();
if let Some(renderer) = &mut self.renderer { if let Some(renderer) = &mut self.renderer {

View File

@ -8,18 +8,13 @@ use wgpu::{
#[derive(Debug)] #[derive(Debug)]
pub struct GameRenderer { pub struct GameRenderer {
pub queue: Arc<Queue>, pub queue: Arc<Queue>,
pub eyes: [Arc<Texture>; 2], pub eyes: Arc<Texture>,
} }
impl GameRenderer { impl GameRenderer {
pub fn render(&self, buffers: &[Vec<u8>; 2]) { pub fn render(&self, buffer: &[u8]) {
for (texture, buffer) in self.eyes.iter().zip(buffers) {
self.update_texture(texture, buffer);
}
}
fn update_texture(&self, texture: &Texture, buffer: &[u8]) {
let texture = ImageCopyTexture { let texture = ImageCopyTexture {
texture, texture: &self.eyes,
mip_level: 0, mip_level: 0,
origin: Origin3d::ZERO, origin: Origin3d::ZERO,
aspect: wgpu::TextureAspect::All, aspect: wgpu::TextureAspect::All,
@ -31,7 +26,7 @@ impl GameRenderer {
}; };
let data_layout = ImageDataLayout { let data_layout = ImageDataLayout {
offset: 0, offset: 0,
bytes_per_row: Some(384), bytes_per_row: Some(384 * 2),
rows_per_image: Some(224), rows_per_image: Some(224),
}; };
self.queue.write_texture(texture, buffer, data_layout, size); self.queue.write_texture(texture, buffer, data_layout, size);
@ -47,11 +42,11 @@ impl GameRenderer {
mip_level_count: 1, mip_level_count: 1,
sample_count: 1, sample_count: 1,
dimension: wgpu::TextureDimension::D2, dimension: wgpu::TextureDimension::D2,
format: TextureFormat::R8Unorm, format: TextureFormat::Rg8Unorm,
usage: TextureUsages::COPY_SRC usage: TextureUsages::COPY_SRC
| TextureUsages::COPY_DST | TextureUsages::COPY_DST
| TextureUsages::TEXTURE_BINDING, | TextureUsages::TEXTURE_BINDING,
view_formats: &[TextureFormat::R8Unorm], view_formats: &[TextureFormat::Rg8Unorm],
}; };
device.create_texture(&desc) device.create_texture(&desc)
} }

View File

@ -113,7 +113,7 @@ impl CoreVB {
unsafe { vb_emulate(self.sim, &mut cycles) }; unsafe { vb_emulate(self.sim, &mut cycles) };
} }
pub fn read_pixels(&mut self, buffers: &mut [Vec<u8>; 2]) -> bool { pub fn read_pixels(&mut self, buffers: &mut [u8]) -> bool {
// SAFETY: the *mut VB owns its userdata. // SAFETY: the *mut VB owns its userdata.
// There is no way for the userdata to be null or otherwise invalid. // There is no way for the userdata to be null or otherwise invalid.
let data: &mut VBState = unsafe { &mut *vb_get_user_data(self.sim).cast() }; let data: &mut VBState = unsafe { &mut *vb_get_user_data(self.sim).cast() };
@ -122,17 +122,17 @@ impl CoreVB {
} }
data.frame_seen = false; data.frame_seen = false;
assert_eq!(buffers[0].len(), 384 * 224); // the buffer must be big enough for our data
assert_eq!(buffers[1].len(), 384 * 224); assert!(buffers.len() >= 384 * 224 * 2);
unsafe { unsafe {
vb_get_pixels( vb_get_pixels(
self.sim, self.sim,
buffers[0].as_mut_ptr().cast(), buffers.as_mut_ptr().cast(),
1, 2,
384, 384 * 2,
buffers[1].as_mut_ptr().cast(), buffers.as_mut_ptr().offset(1).cast(),
1, 2,
384, 384 * 2,
); );
}; };
true true