From 9b2c18f8e8bdaf3ccf26da3f827c25bb1fd0b89c Mon Sep 17 00:00:00 2001 From: Daniel Bauer Date: Thu, 26 Dec 2019 13:58:14 +0100 Subject: [PATCH] use GlyphBrush for more efficient rendering --- Cargo.lock | 9 +- Cargo.toml | 6 +- src/main.rs | 423 +++++++++++++++++++++++--------------------------- src/render.rs | 42 ----- 4 files changed, 199 insertions(+), 281 deletions(-) delete mode 100644 src/render.rs diff --git a/Cargo.lock b/Cargo.lock index 2fa2b34..e1d712c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,11 +8,11 @@ dependencies = [ "gfx_core 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_device_gl 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", "gfx_glyph 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "piston2d-opengl_graphics 0.70.0 (registry+https://github.com/rust-lang/crates.io-index)", "piston_window 0.105.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "simple_logger 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -232,9 +232,10 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1104,7 +1105,7 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1532,7 +1533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" "checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" -"checksum crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfd6515864a82d2f877b42813d4553292c6659498c9a2aa31bab5a15243c2700" +"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" "checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" "checksum deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4" "checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" diff --git a/Cargo.toml b/Cargo.toml index 9dd26e5..846b935 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,9 +12,9 @@ log = "0.4.*" simple_logger = "1.3.*" phf = { version = "0.8", features = ['macros'] } failure = "0.1.*" +lazy_static = "1.4.*" piston_window = "0.105.*" piston2d-opengl_graphics = "0.70.*" gfx_core = "0.9.2" -gfx_device_gl = "*" -gfx_glyph = "*" -rand = "*" \ No newline at end of file +gfx_device_gl = "0.16.*" +gfx_glyph = "0.16.*" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 8072930..e3657e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,11 @@ #[macro_use] extern crate log; #[macro_use] extern crate failure; +#[macro_use] extern crate lazy_static; extern crate simple_logger; extern crate phf; extern crate piston_window; mod nes; -mod render; use std::path::Path; use piston_window::*; @@ -16,20 +16,19 @@ use nes::cartridge::*; use nes::disasm::*; use opengl_graphics::OpenGL; use log::Level; -use piston_window::Text; -use render::*; - -use gfx_glyph::{Section, GlyphBrushBuilder,GlyphBrush}; -use gfx_device_gl::{Factory,Resources}; +use gfx_glyph::{Section, GlyphBrushBuilder,GlyphBrush, Scale}; +use gfx_device_gl::{Resources,Factory}; // font options -const FT_SIZE_PT: u32 = 6; -const FT_SIZE_PX: f64 = 8.0; +const FT_SIZE_PX: f32 = 11.0; const FT_COLOR_WHITE: [f32; 4] = [1.0; 4]; const FT_COLOR_RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0]; const FT_COLOR_GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0]; -const FT_LINE_DISTANCE: f64 = FT_SIZE_PX * 0.5; +const FT_LINE_DISTANCE: f32 = FT_SIZE_PX * 0.5; +lazy_static! { + static ref FT_SCALE: Scale = Scale::uniform(FT_SIZE_PX); +} fn main() { simple_logger::init_with_level(Level::Error).unwrap(); @@ -39,7 +38,6 @@ fn main() { let cartridge = Cartridge::new(cartridge).unwrap(); bus.insert_cartrige(cartridge); - // Load little test program into ram // let test_prog: [Byte; 28] = [0xA2, 0x0A, 0x8E, 0x00, 0x00, 0xA2, 0x03, 0x8E, 0x01, 0x00, 0xAC, 0x00, 0x00, 0xA9, // 0x00, 0x18, 0x6D, 0x01, 0x00, 0x88, 0xD0, 0xFA, 0x8D, 0x02, 0x00, 0xEA, 0xEA, 0xEA]; @@ -63,7 +61,6 @@ fn main() { // Create and reset CPU let mut cpu: CPU = CPU::new(); cpu.find_pc_addr(&bus); - // cpu.reset(&bus); // Prepare window and drawing resources @@ -73,27 +70,24 @@ fn main() { event_settings.max_fps = 60; event_settings.ups = 107400; let mut events = Events::new(event_settings); - let ft: &[u8] = include_bytes!("../resources/fonts/PressStart2P.ttf"); - let mut glyphs = GlyphBrushBuilder::using_font_bytes(ft) - .initial_cache_size((256, 256)) + // let mut glyphs = get_glyphs(&mut window); + let font: &[u8] = include_bytes!("../resources/fonts/PressStart2P.ttf"); + let mut glyph_brush: GlyphBrush = GlyphBrushBuilder::using_font_bytes(font) + .initial_cache_size((1024, 1024)) .build(window.factory.clone()); - let mut cpu_renderer = CPURenderer::new(&cpu); + // Main loop let mut run = false; while let Some(event) = events.next(&mut window) { - if let Some(_) = event.render_args() { - cpu_renderer.update(&cpu); - render(&mut window, &event, &mut glyphs, &mut cpu_renderer, &bus, &disasm); - } if let Some(_) = event.update_args() { if run { cpu.clock(&mut bus); - // while cpu.is_ahead() { - // cpu.clock(&mut bus); - // } } } + if let Some(_) = event.render_args() { + render(&mut window, &event, &mut glyph_brush, &cpu, &bus, &disasm); + } if let Some(Button::Keyboard(key)) = event.press_args() { match key { Key::C => cpu.clock(&mut bus), // advance one clock @@ -123,231 +117,196 @@ fn main() { fn render(window: &mut PistonWindow, event: &Event, glyphs: &mut GlyphBrush, - cpu_renderer: &mut CPURenderer, bus: &MemoryBus, disasm: &Disasm) { + cpu: &CPU, bus: &MemoryBus, disasm: &Disasm) { window.draw_2d(event, |c, g, d| { clear([0.0, 0.0, 1.0, 1.0], g); - // let debug_offset = [10.0, 10.0]; - // render_cpu(&c, g, glyphs, cpu, debug_offset); - // render_disasm(&c, g, glyphs, disasm, cpu.regs.pc, - // [debug_offset[0], debug_offset[1] + (7.0 * (FT_LINE_DISTANCE+FT_SIZE_PX))]); - // render_memory(&c, g, glyphs, bus, - // [debug_offset[0] + 300.0, debug_offset[1]]); + let debug_offset = [10.0, 10.0]; + render_cpu(glyphs, cpu, debug_offset); + render_disasm(glyphs, disasm, cpu.regs.pc, + [debug_offset[0], debug_offset[1] + (7.0 * (FT_LINE_DISTANCE+FT_SIZE_PX))]); + render_memory(glyphs, bus, + [debug_offset[0] + 400.0, debug_offset[1]]); - // glyphs.factory.encoder.flush(d); }); - cpu_renderer.draw(glyphs); - glyphs.use_queue().draw(&mut window.encoder, &window.output_color); + glyphs.use_queue().draw(&mut window.encoder, &window.output_color).unwrap(); window.encoder.flush(&mut window.device); } -// fn render_cpu(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, cpu: &CPU, offset: [f64; 2]) { -// let mut transform = c.transform -// .trans(offset[0], offset[1] + FT_SIZE_PX); -// let text_white = Text::new_color(FT_COLOR_WHITE, FT_SIZE_PT); -// let text_on = Text::new_color(FT_COLOR_GREEN, FT_SIZE_PT); -// let text_off = Text::new_color(FT_COLOR_RED, FT_SIZE_PT); - -// let mut text = text_white; -// text.draw( -// &"Flags:", -// glyphs, -// &c.draw_state, -// transform, -// g -// ).unwrap(); +fn render_cpu(glyphs: &mut GlyphBrush, cpu: &CPU, offset: [f32; 2]) { + // draw flags + let mut position = (offset[0], offset[1] + FT_SIZE_PX); + glyphs.queue(Section { + text: "Flags:", + scale: *FT_SCALE, + screen_position: position, + color: FT_COLOR_WHITE, + ..Section::default() + }); -// transform = transform.trans(70.0, 0.0); -// text = if cpu.get_flag(NEGATIVE) == 1 { text_on } else { text_off }; -// text.draw( -// &"N", -// glyphs, -// &c.draw_state, -// transform, -// g -// ).unwrap(); -// transform = transform.trans(16.0, 0.0); -// text = if cpu.get_flag(OVERFLOW) == 1 { text_on } else { text_off }; -// text.draw( -// &"V", -// glyphs, -// &c.draw_state, -// transform, -// g -// ).unwrap(); -// transform = transform.trans(16.0, 0.0); -// text_white.draw( -// &"-", -// glyphs, -// &c.draw_state, -// transform, -// g -// ).unwrap(); -// transform = transform.trans(16.0, 0.0); -// text = if cpu.get_flag(BREAK) == 1 { text_on } else { text_off }; -// text.draw( -// &"B", -// glyphs, -// &c.draw_state, -// transform, -// g -// ).unwrap(); -// transform = transform.trans(16.0, 0.0); -// text = if cpu.get_flag(DECIMAL) == 1 { text_on } else { text_off }; -// text.draw( -// &"D", -// glyphs, -// &c.draw_state, -// transform, -// g -// ).unwrap(); -// transform = transform.trans(16.0, 0.0); -// text = if cpu.get_flag(IRQ) == 1 { text_on } else { text_off }; -// text.draw( -// &"I", -// glyphs, -// &c.draw_state, -// transform, -// g -// ).unwrap(); -// transform = transform.trans(16.0, 0.0); -// text = if cpu.get_flag(ZERO) == 1 { text_on } else { text_off }; -// text.draw( -// &"Z", -// glyphs, -// &c.draw_state, -// transform, -// g -// ).unwrap(); -// transform = transform.trans(16.0, 0.0); -// text = if cpu.get_flag(CARRY) == 1 { text_on } else { text_off }; -// text.draw( -// &"C", -// glyphs, -// &c.draw_state, -// transform, -// g -// ).unwrap(); -// transform = transform.trans(16.0, 0.0); -// text_white.draw( -// &format!("({:#4x})", cpu.regs.flags), -// glyphs, -// &c.draw_state, -// transform, -// g -// ).unwrap(); + position.0 += 70.0; + let color = if cpu.get_flag(NEGATIVE) == 1 { FT_COLOR_GREEN } else { FT_COLOR_RED }; + glyphs.queue(Section { + text: "N", + scale: *FT_SCALE, + screen_position: position, + color: color, + ..Section::default() + }); + position.0 += 16.0; + let color = if cpu.get_flag(OVERFLOW) == 1 { FT_COLOR_GREEN } else { FT_COLOR_RED }; + glyphs.queue(Section { + text: "V", + scale: *FT_SCALE, + screen_position: position, + color: color, + ..Section::default() + }); + position.0 += 16.0; + let color = FT_COLOR_WHITE; + glyphs.queue(Section { + text: "-", + scale: *FT_SCALE, + screen_position: position, + color: color, + ..Section::default() + }); + position.0 += 16.0; + let color = if cpu.get_flag(BREAK) == 1 { FT_COLOR_GREEN } else { FT_COLOR_RED }; + glyphs.queue(Section { + text: "B", + scale: *FT_SCALE, + screen_position: position, + color: color, + ..Section::default() + }); + position.0 += 16.0; + let color = if cpu.get_flag(DECIMAL) == 1 { FT_COLOR_GREEN } else { FT_COLOR_RED }; + glyphs.queue(Section { + text: "D", + scale: *FT_SCALE, + screen_position: position, + color: color, + ..Section::default() + }); + position.0 += 16.0; + let color = if cpu.get_flag(IRQ) == 1 { FT_COLOR_GREEN } else { FT_COLOR_RED }; + glyphs.queue(Section { + text: "I", + scale: *FT_SCALE, + screen_position: position, + color: color, + ..Section::default() + }); + position.0 += 16.0; + let color = if cpu.get_flag(ZERO) == 1 { FT_COLOR_GREEN } else { FT_COLOR_RED }; + glyphs.queue(Section { + text: "Z", + scale: *FT_SCALE, + screen_position: position, + color: color, + ..Section::default() + }); + position.0 += 16.0; + let color = if cpu.get_flag(CARRY) == 1 { FT_COLOR_GREEN } else { FT_COLOR_RED }; + glyphs.queue(Section { + text: "C", + scale: *FT_SCALE, + screen_position: position, + color: color, + ..Section::default() + }); + let cpu_register_texts = [ + &format!("A: {0:#x} ({0})", cpu.regs.a), + &format!("X: {0:#x} ({0})", cpu.regs.x), + &format!("Y: {0:#x} ({0})", cpu.regs.y), + &format!("Stack P: {0:#x} ({0})", cpu.regs.sp), + &format!("Program P: {:#x}", cpu.regs.pc), + ]; -// let cpu_register_texts = [ -// &format!("A: {0:#x} ({0})", cpu.regs.a), -// &format!("X: {0:#x} ({0})", cpu.regs.x), -// &format!("Y: {0:#x} ({0})", cpu.regs.y), -// &format!("Stack P: {0:#x} ({0})", cpu.regs.sp), -// &format!("Program P: {:#x}", cpu.regs.pc), -// ]; + for (i, &text) in cpu_register_texts.iter().enumerate() { + let y_offset = (i+2) as f32 * (FT_LINE_DISTANCE + FT_SIZE_PX); + let position = (offset[0], offset[1] + y_offset); + glyphs.queue(Section { + text: text, + scale: *FT_SCALE, + screen_position: position, + color: FT_COLOR_WHITE, + ..Section::default() + }); + } +} -// for (i, &text) in cpu_register_texts.iter().enumerate() { -// let y_offset = (i+2) as f64 * (FT_LINE_DISTANCE + FT_SIZE_PX); -// let transform = c.transform.trans(offset[0], offset[1] + y_offset); -// text_white.draw( -// &text, -// glyphs, -// &c.draw_state, -// transform, -// g -// ).unwrap(); -// } -// } +fn render_disasm(glyphs: &mut GlyphBrush, + disasm: &Disasm, pc: Addr, offset: [f32; 2]) { + let pc_position = disasm.addresses.iter().position(|&pos| pos == pc); + if let None = pc_position { + return; + } + let pc_position = pc_position.unwrap(); + let lines_above_below: usize = 12; -// fn render_disasm(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, disasm: &Disasm, pc: Addr, offset: [f64; 2]) { -// let pc_position = disasm.addresses.iter().position(|&pos| pos == pc); -// if let None = pc_position { -// return; -// } -// let pc_position = pc_position.unwrap(); -// let lines_above_below: usize = 12; + let start = if (pc_position as i32 - lines_above_below as i32) < 0 { + 0 + } else { + pc_position - lines_above_below + }; -// let start = if (pc_position as i32 - lines_above_below as i32) < 0 { -// 0 -// } else { -// pc_position - lines_above_below -// }; + let text_position_x = offset[0]; + let mut text_position_y = offset[1]; + for i in (start..disasm.addresses.len()).take(lines_above_below*2+1) { + let txt = &disasm.instructions[i]; + text_position_y += FT_LINE_DISTANCE + FT_SIZE_PX; + let color = if i == pc_position { + FT_COLOR_RED + } else { + FT_COLOR_WHITE + }; + glyphs.queue(Section { + text: txt, + scale: *FT_SCALE, + screen_position: (text_position_x, text_position_y), + color: color, + ..Section::default() + }); + } +} -// let mut transform = c.transform.trans(offset[0], offset[1]); -// let text_current = Text::new_color(FT_COLOR_RED, FT_SIZE_PT); -// let text_other = Text::new_color(FT_COLOR_WHITE, FT_SIZE_PT); - -// for i in (start..disasm.addresses.len()).take(lines_above_below*2+1) { -// let addr = disasm.addresses[i]; -// let txt = &disasm.instructions[i]; - -// transform = transform.trans(0.0, FT_LINE_DISTANCE + FT_SIZE_PX); -// let text = if addr == pc { -// text_current -// } else { -// text_other -// }; -// text.draw( -// txt, -// glyphs, -// &c.draw_state, -// transform, -// g -// ).unwrap(); -// } +fn render_memory(glyphs: &mut GlyphBrush, bus: &MemoryBus, offset: [f32; 2]) { + let mut position_y = (offset[0], offset[1]); + for page in (0x0100..0x01FF).step_by(16) { + position_y.1 += FT_LINE_DISTANCE + FT_SIZE_PX; + let mut line = format!("{:#06x}:", page); + (0u16..16u16).map(|offset| offset + page) + .map(|addr| bus.readb(addr)) + .map(|val| format!(" {:02x}", val)) + .for_each(|s| line.push_str(&s)); + glyphs.queue(Section { + text: &line, + scale: *FT_SCALE, + screen_position: position_y, + color: FT_COLOR_WHITE, + ..Section::default() + }); + } - -// } - -// fn render_memory(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, bus: &MemoryBus, offset: [f64; 2]) { -// let mut transform_y = c.transform.trans(offset[0], offset[1]); -// let text = Text::new_color(FT_COLOR_WHITE, FT_SIZE_PT); -// for page in (0x0000..0x01FF).step_by(16) { -// transform_y = transform_y.trans(0.0, FT_LINE_DISTANCE+FT_SIZE_PX); -// text.draw( -// &format!("{:#06x}:", page), -// glyphs, -// &c.draw_state, -// transform_y, -// g -// ).unwrap(); -// let mut transform_x = transform_y.trans(40.0, 0.0); -// for offset in 0u16..16u16 { -// transform_x = transform_x.trans(20.0, 0.0); -// let addr = page + offset; -// text.draw( -// &format!("{:02x}", bus.readb(addr)), -// glyphs, -// &c.draw_state, -// transform_x, -// g -// ).unwrap(); -// } -// } - -// transform_y = transform_y.trans(0.0, (FT_LINE_DISTANCE+FT_SIZE_PX) * 1.5); -// for page in (0x6000..0x6030).step_by(16) { -// transform_y = transform_y.trans(0.0, (FT_LINE_DISTANCE+FT_SIZE_PX)); -// text.draw( -// &format!("{:#06x}:", page), -// glyphs, -// &c.draw_state, -// transform_y, -// g -// ).unwrap(); -// let mut transform_x = transform_y.trans(40.0, 0.0); -// for offset in 0u16..16u16 { -// transform_x = transform_x.trans(20.0, 0.0); -// let addr = page + offset; -// text.draw( -// &format!("{:02x}", bus.readb(addr)), -// glyphs, -// &c.draw_state, -// transform_x, -// g -// ).unwrap(); -// } -// } -// } \ No newline at end of file + position_y.1 += FT_LINE_DISTANCE+FT_SIZE_PX * 1.5; + for page in (0x6000..0x60FF).step_by(16) { + position_y.1 += FT_LINE_DISTANCE + FT_SIZE_PX; + let mut line = format!("{:#06x}:", page); + (0u16..16u16).map(|offset| offset + page) + .map(|addr| bus.readb(addr)) + .map(|val| format!(" {:02x}", val)) + .for_each(|s| line.push_str(&s)); + glyphs.queue(Section { + text: &line, + scale: *FT_SCALE, + screen_position: position_y, + color: FT_COLOR_WHITE, + ..Section::default() + }); + } +} \ No newline at end of file diff --git a/src/render.rs b/src/render.rs deleted file mode 100644 index b9b392a..0000000 --- a/src/render.rs +++ /dev/null @@ -1,42 +0,0 @@ -use gfx_device_gl::Factory; -use gfx_device_gl::Resources; -use crate::nes::cpu::CPU; -use gfx_glyph::{Section,GlyphBrush}; - -pub trait Draw { - fn draw(&mut self, glyphs: &mut GlyphBrush); -} - -pub struct CPURenderer<'a> { - registers_text: String, - registers_section: Section<'a>, -} - -impl<'a> CPURenderer<'a> { - pub fn new(cpu: &CPU) -> Self { - let registers_text = String::from("A: 0x00 (000)"); - let registers_section = Section { - text: "xxx", - screen_position: (100.0, 100.0), - color: [1.0; 4], - ..Section::default() - }; - CPURenderer { - registers_text: registers_text, - registers_section: registers_section, - } - } -} - -impl<'a> CPURenderer<'a> { - pub fn update(&mut self, cpu: &CPU) { - self.registers_text.replace_range(3..7, "txtx"); - // self.registers_section.text = &self.registers_text; - } -} - -impl<'a> Draw for CPURenderer<'a> { - fn draw(&mut self, glyphs: &mut GlyphBrush) { - glyphs.queue(self.registers_section); - } -} \ No newline at end of file