Compare commits

..

No commits in common. "fc6516cbb2d35eb431b3b397c88ec38067302036" and "36e46d3780a972ca314388ec249eaa4289490803" have entirely different histories.

7 changed files with 344 additions and 416 deletions

View File

@ -1,6 +1,6 @@
{ {
"recommendations": [ "recommendations": [
"rust-lang.rust-analyzer", "matklad.rust-analyzer",
"tamasfe.even-better-toml", "tamasfe.even-better-toml",
"serayuzgur.crates", "serayuzgur.crates",
"vadimcn.vscode-lldb", "vadimcn.vscode-lldb",

628
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -10,9 +10,12 @@ edition = "2021"
anyhow = "1.0" anyhow = "1.0"
bitfield = "0.13" bitfield = "0.13"
clap = { version = "3.1", features = ["cargo"] } clap = { version = "3.1", features = ["cargo"] }
gilrs = "0.9" gilrs = "0.8"
egui-wgpu = "0.18" winit = "0.26"
egui-winit = "0.18" egui = "0.15"
wgpu = "0.11"
egui_wgpu_backend = "0.14"
egui_winit_platform = "0.12"
pollster = "0.2" pollster = "0.2"
rodio = "0.15" rodio = "0.15"
rtrb = "0.2" rtrb = "0.2"
@ -20,7 +23,7 @@ directories-next = "2.0"
tracing = "0.1" tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["std", "env-filter"] } tracing-subscriber = { version = "0.3", features = ["std", "env-filter"] }
thiserror = "1.0" thiserror = "1.0"
once_cell = "1.12" once_cell = "1.10"
[profile.release] [profile.release]
debug = true debug = true

View File

@ -4,14 +4,14 @@ use crate::cartridge::Cartridge;
use crate::cpu::Cpu; use crate::cpu::Cpu;
use crate::{Cycle, GB_HEIGHT, GB_WIDTH}; use crate::{Cycle, GB_HEIGHT, GB_WIDTH};
use clap::crate_name; use clap::crate_name;
use egui_winit::winit::event::KeyboardInput;
use egui_winit::winit::event_loop::ControlFlow;
use gilrs::Gilrs; use gilrs::Gilrs;
use std::fs::File; use std::fs::File;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::time::Duration; use std::time::Duration;
use thiserror::Error; use thiserror::Error;
use winit::event::KeyboardInput;
use winit::event_loop::ControlFlow;
pub const SM83_CYCLE_TIME: Duration = Duration::from_nanos(1_000_000_000 / SM83_CLOCK_SPEED); pub const SM83_CYCLE_TIME: Duration = Duration::from_nanos(1_000_000_000 / SM83_CLOCK_SPEED);
pub const CYCLES_IN_FRAME: Cycle = 456 * 154; // 456 Cycles times 154 scanlines pub const CYCLES_IN_FRAME: Cycle = 456 * 154; // 456 Cycles times 154 scanlines

View File

@ -1,9 +1,6 @@
use egui_wgpu::wgpu; use egui::{ClippedMesh, CtxRef, TextureId};
use egui_winit::egui; use egui_wgpu_backend::{BackendError, RenderPass, ScreenDescriptor};
use egui_winit::winit; use egui_winit_platform::Platform;
use egui::{ClippedPrimitive, Context, TextureId};
use egui_wgpu::renderer::{RenderPass, ScreenDescriptor};
use wgpu::{ use wgpu::{
Adapter, CommandEncoder, Device, Extent3d, FilterMode, Instance, Queue, RequestDeviceError, Adapter, CommandEncoder, Device, Extent3d, FilterMode, Instance, Queue, RequestDeviceError,
Surface, SurfaceConfiguration, SurfaceTexture, Texture, TextureFormat, TextureUsages, Surface, SurfaceConfiguration, SurfaceTexture, Texture, TextureFormat, TextureUsages,
@ -124,6 +121,20 @@ pub fn surface_config(window: &Window, format: TextureFormat) -> SurfaceConfigur
} }
} }
pub fn platform_desc(window: &Window) -> Platform {
use egui::FontDefinitions;
use egui_winit_platform::PlatformDescriptor;
let size = window.inner_size();
Platform::new(PlatformDescriptor {
physical_width: size.width as u32,
physical_height: size.height as u32,
scale_factor: window.scale_factor(),
font_definitions: FontDefinitions::default(),
..Default::default()
})
}
pub fn texture_size() -> Extent3d { pub fn texture_size() -> Extent3d {
Extent3d { Extent3d {
width: GB_WIDTH as u32, width: GB_WIDTH as u32,
@ -173,6 +184,14 @@ pub fn write_to_texture(
); );
} }
pub fn expose_texture_to_egui(
render_pass: &mut RenderPass,
device: &Device,
texture: &Texture,
) -> TextureId {
render_pass.egui_texture_from_wgpu_texture(device, texture, FILTER_MODE)
}
#[inline] #[inline]
pub fn create_view(frame: &SurfaceTexture) -> TextureView { pub fn create_view(frame: &SurfaceTexture) -> TextureView {
use wgpu::TextureViewDescriptor; use wgpu::TextureViewDescriptor;
@ -189,19 +208,31 @@ pub fn create_command_encoder(device: &Device) -> CommandEncoder {
}) })
} }
car#[inline] #[inline]
pub fn create_screen_descriptor(
window: &Window,
config: &SurfaceConfiguration,
) -> ScreenDescriptor {
ScreenDescriptor {
physical_width: config.width,
physical_height: config.height,
scale_factor: window.scale_factor() as f32,
}
}
#[inline]
pub fn execute_render_pass( pub fn execute_render_pass(
render_pass: &mut RenderPass, render_pass: &mut RenderPass,
encoder: &mut CommandEncoder, encoder: &mut CommandEncoder,
view: &TextureView, view: &TextureView,
jobs: Vec<ClippedPrimitive>, jobs: Vec<ClippedMesh>,
descriptor: &ScreenDescriptor, descriptor: &ScreenDescriptor,
) { ) -> Result<(), BackendError> {
render_pass.execute(encoder, view, &jobs, descriptor, Some(wgpu::Color::BLACK)) render_pass.execute(encoder, view, &jobs, descriptor, Some(wgpu::Color::BLACK))
} }
#[inline] #[inline]
pub fn draw_egui(cpu: &Cpu, app: &mut GuiState, ctx: &Context, texture_id: TextureId) { pub fn draw_egui(cpu: &Cpu, app: &mut GuiState, ctx: &CtxRef, texture_id: TextureId) {
use crate::{cpu, instruction, ppu}; use crate::{cpu, instruction, ppu};
fn selectable_text(ui: &mut egui::Ui, mut text: &str) -> egui::Response { fn selectable_text(ui: &mut egui::Ui, mut text: &str) -> egui::Response {
@ -209,7 +240,7 @@ pub fn draw_egui(cpu: &Cpu, app: &mut GuiState, ctx: &Context, texture_id: Textu
} }
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
ui.menu_button("File", |ui| { egui::menu::menu(ui, "File", |ui| {
if ui.button("Quit").clicked() { if ui.button("Quit").clicked() {
app.quit = true; app.quit = true;
} }
@ -291,12 +322,9 @@ pub fn draw_egui(cpu: &Cpu, app: &mut GuiState, ctx: &Context, texture_id: Textu
ui.horizontal(|ui| { ui.horizontal(|ui| {
let ie = cpu.int_enable(); let ie = cpu.int_enable();
let style = ctx.style(); let r_len = ctx.fonts().glyph_width(egui::TextStyle::Body, 'R');
let font_id = egui::TextStyle::Body.resolve(&style); let e_len = ctx.fonts().glyph_width(egui::TextStyle::Body, 'E');
let q_len = ctx.fonts().glyph_width(egui::TextStyle::Body, 'Q');
let r_len = ctx.fonts().glyph_width(&font_id, 'R');
let e_len = ctx.fonts().glyph_width(&font_id, 'E');
let q_len = ctx.fonts().glyph_width(&font_id, 'Q');
ui.label("IE:"); ui.label("IE:");
ui.add_space(q_len - (e_len - r_len)); ui.add_space(q_len - (e_len - r_len));
@ -322,7 +350,7 @@ pub fn draw_egui(cpu: &Cpu, app: &mut GuiState, ctx: &Context, texture_id: Textu
} }
pub mod kbd { pub mod kbd {
use egui_winit::winit::event::{ElementState, KeyboardInput, VirtualKeyCode}; use winit::event::{ElementState, KeyboardInput, VirtualKeyCode};
pub fn space_released(input: &KeyboardInput) -> bool { pub fn space_released(input: &KeyboardInput) -> bool {
let keycode = input.virtual_keycode; let keycode = input.virtual_keycode;

View File

@ -1,5 +1,5 @@
use egui_winit::winit::event::{ElementState, KeyboardInput, VirtualKeyCode};
use gilrs::{Button, Event as GamepadEvent, EventType as GamepadEventType}; use gilrs::{Button, Event as GamepadEvent, EventType as GamepadEventType};
use winit::event::{ElementState, KeyboardInput, VirtualKeyCode};
#[derive(Debug)] #[derive(Debug)]
pub struct Joypad { pub struct Joypad {

View File

@ -1,16 +1,15 @@
use std::time::Instant; use std::time::Instant;
use clap::{crate_authors, crate_description, crate_name, crate_version, Arg, Command}; use clap::{crate_authors, crate_description, crate_name, crate_version, Arg, Command};
use egui_wgpu::renderer::RenderPass; use egui_wgpu_backend::RenderPass;
use gb::gui::EmuMode; use gb::gui::EmuMode;
use gb::{emu, gui}; use gb::{emu, gui};
use gilrs::Gilrs; use gilrs::Gilrs;
use gui::GuiState; use gui::GuiState;
use rodio::{OutputStream, Sink}; use rodio::{OutputStream, Sink};
use tracing_subscriber::EnvFilter; use tracing_subscriber::EnvFilter;
use winit::event::{Event, WindowEvent};
use egui_winit::winit::event::{Event, WindowEvent}; use winit::event_loop::EventLoop;
use egui_winit::winit::event_loop::{EventLoop, EventLoopProxy};
const AUDIO_ENABLED: bool = true; const AUDIO_ENABLED: bool = true;
@ -49,7 +48,7 @@ fn main() {
// --Here lies a lot of winit + wgpu Boilerplate-- // --Here lies a lot of winit + wgpu Boilerplate--
let event_loop: EventLoop<Event<()>> = EventLoop::with_user_event(); let event_loop: EventLoop<Event<()>> = EventLoop::with_user_event();
let window = gui::build_window(&event_loop).expect("create winit window"); let window = gui::build_window(&event_loop).expect("build window");
let (instance, surface) = gui::create_surface(&window); let (instance, surface) = gui::create_surface(&window);
let adapter = gui::request_adapter(&instance, &surface).expect("request adaptor"); let adapter = gui::request_adapter(&instance, &surface).expect("request adaptor");
@ -60,7 +59,7 @@ fn main() {
let mut config = gui::surface_config(&window, format); let mut config = gui::surface_config(&window, format);
surface.configure(&device, &config); surface.configure(&device, &config);
let mut state = egui_winit::State::new(8192, &window); let mut platform = gui::platform_desc(&window);
let mut render_pass = RenderPass::new(&device, format, 1); let mut render_pass = RenderPass::new(&device, format, 1);
// We interrupt your boiler plate to initialize the emulator so that // We interrupt your boiler plate to initialize the emulator so that
@ -80,9 +79,7 @@ fn main() {
let texture_size = gui::texture_size(); let texture_size = gui::texture_size();
let texture = gui::create_texture(&device, texture_size); let texture = gui::create_texture(&device, texture_size);
gui::write_to_texture(&queue, &texture, emu::pixel_buf(&cpu), texture_size); gui::write_to_texture(&queue, &texture, emu::pixel_buf(&cpu), texture_size);
let texture_id = todo!("Expose Texture ID to egui"); let texture_id = gui::expose_texture_to_egui(&mut render_pass, &device, &texture);
render_pass.
// Load ROM if filepath was provided // Load ROM if filepath was provided
if let Some(path) = m.value_of("rom") { if let Some(path) = m.value_of("rom") {
@ -119,13 +116,14 @@ fn main() {
// Set up state for the Immediate-mode GUI // Set up state for the Immediate-mode GUI
let mut app = GuiState::new(rom_title); let mut app = GuiState::new(rom_title);
let mut ctx = egui_winit::egui::Context::default();
let mut last_key = gui::unused_key(); let mut last_key = gui::unused_key();
// used for egui animations // used for egui animations
let start_time = Instant::now(); let start_time = Instant::now();
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
platform.handle_event(&event);
match event { match event {
Event::MainEventsCleared => { Event::MainEventsCleared => {
if app.quit { if app.quit {
@ -149,6 +147,8 @@ fn main() {
window.request_redraw(); window.request_redraw();
} }
Event::RedrawRequested(..) => { Event::RedrawRequested(..) => {
platform.update_time(start_time.elapsed().as_secs_f64());
let data = emu::pixel_buf(&cpu); let data = emu::pixel_buf(&cpu);
gui::write_to_texture(&queue, &texture, data, texture_size); gui::write_to_texture(&queue, &texture, data, texture_size);
@ -172,7 +172,7 @@ fn main() {
let screen_descriptor = gui::create_screen_descriptor(&window, &config); let screen_descriptor = gui::create_screen_descriptor(&window, &config);
// Upload all resources for the GPU. // Upload all resources for the GPU.
render_pass.update_texture(&device, &queue, todo!(), todo!()); render_pass.update_texture(&device, &queue, &platform.context().texture());
render_pass.update_user_textures(&device, &queue); render_pass.update_user_textures(&device, &queue);
render_pass.update_buffers(&device, &queue, &paint_jobs, &screen_descriptor); render_pass.update_buffers(&device, &queue, &paint_jobs, &screen_descriptor);
@ -192,10 +192,7 @@ fn main() {
// Redraw egui // Redraw egui
output_frame.present(); output_frame.present();
} }
Event::WindowEvent { event, .. } => { Event::WindowEvent { event, .. } => match event {
let exclusive_use = state.on_event(&ctx, &event);
if !exclusive_use {
match event {
WindowEvent::Resized(size) => { WindowEvent::Resized(size) => {
config.width = size.width; config.width = size.width;
config.height = size.height; config.height = size.height;
@ -206,9 +203,7 @@ fn main() {
} }
WindowEvent::KeyboardInput { input, .. } => last_key = input, WindowEvent::KeyboardInput { input, .. } => last_key = input,
_ => {} _ => {}
} },
}
}
_ => {} _ => {}
} }
}); });