mirror of
https://github.com/FranLMSP/rmg-001.git
synced 2024-11-13 21:51:33 +00:00
Compare commits
2 Commits
7bfe760a57
...
4b47ae96a1
Author | SHA1 | Date | |
---|---|---|---|
4b47ae96a1 | |||
76a930385d |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
/target
|
||||
*.log
|
||||
/ignore
|
||||
.vscode
|
||||
|
175
src/bus.rs
175
src/bus.rs
@ -1,3 +1,4 @@
|
||||
use std::env;
|
||||
use std::ops::RangeInclusive;
|
||||
use crate::utils::join_bytes;
|
||||
use crate::rom::{ROM, load_rom};
|
||||
@ -29,6 +30,21 @@ pub const IO_REGISTERS: RangeInclusive<u16> = 0xFF00..=0xFF7F;
|
||||
pub const HIGH_RAM: RangeInclusive<u16> = 0xFF80..=0xFFFE;
|
||||
pub const PREPARE_SPEED_SWITCH_ADDRESS: u16 = 0xFF4D;
|
||||
|
||||
enum MemoryMap {
|
||||
BankZero,
|
||||
BankSwitchable,
|
||||
VideoRam,
|
||||
ExternalRam,
|
||||
WorkRam1,
|
||||
WorkRam2,
|
||||
EchoRam,
|
||||
SpriteAttributeTable,
|
||||
NotUsable,
|
||||
IoRegisters,
|
||||
HighRam,
|
||||
InterruptEnable,
|
||||
}
|
||||
|
||||
pub struct Bus {
|
||||
data: [u8; 0x10000],
|
||||
pub rom: Box<dyn ROM>,
|
||||
@ -59,7 +75,8 @@ impl Bus {
|
||||
},
|
||||
};
|
||||
let info = rom.info().clone();
|
||||
let cgb_mode = info.cgb_features() || info.cgb_only();
|
||||
let force_dmg_mode = !env::var("FORCE_DMG").is_err();
|
||||
let cgb_mode = (info.cgb_features() || info.cgb_only()) && !force_dmg_mode;
|
||||
let mut bus = Self {
|
||||
data: [0x00; 0x10000],
|
||||
rom,
|
||||
@ -103,34 +120,53 @@ impl Bus {
|
||||
bus
|
||||
}
|
||||
|
||||
pub fn read(&self, address: u16) -> u8 {
|
||||
if BANK_ZERO.contains(&address) || BANK_SWITCHABLE.contains(&address) || EXTERNAL_RAM.contains(&address) {
|
||||
return self.rom.read(address);
|
||||
} else if WORK_RAM_1.contains(&address) || WORK_RAM_2.contains(&address) || address == WRAM_BANK_SELECT_ADDRESS {
|
||||
return self.ram.read(address);
|
||||
} else if ECHO_RAM.contains(&address) {
|
||||
return self.ram.read(WORK_RAM_1.min().unwrap() + ((address - ECHO_RAM.min().unwrap()) & 0x1FFF));
|
||||
} else if address == INTERRUPT_ENABLE_ADDRESS || address == INTERRUPT_FLAG_ADDRESS {
|
||||
return self.interrupts.read(address);
|
||||
} else if VIDEO_RAM.contains(&address) {
|
||||
return self.ppu.read_vram_external(address);
|
||||
} else if SPRITE_ATTRIBUTE_TABLE.contains(&address) {
|
||||
return self.ppu.read_oam(address);
|
||||
} else if PPU::is_io_register(address) {
|
||||
return self.ppu.get_register(address);
|
||||
} else if Sound::is_io_register(address) {
|
||||
return self.sound.get_register(address);
|
||||
} else if address == JOYPAD_ADDRESS {
|
||||
return self.joypad.read(self.data[address as usize]);
|
||||
} else if Timer::is_io_register(address) {
|
||||
return self.timer.get_register(address);
|
||||
} else if address == PREPARE_SPEED_SWITCH_ADDRESS && self.cgb_mode {
|
||||
let byte = self.data[address as usize];
|
||||
let current_speed = (self.double_speed_mode as u8) << 7;
|
||||
let prepare_speed_switch = self.prepare_double_speed_mode as u8;
|
||||
return (byte & 0b0111_1110) | current_speed | prepare_speed_switch;
|
||||
fn map_address(address: u16) -> MemoryMap {
|
||||
match address {
|
||||
0x0000..=0x3FFF => MemoryMap::BankZero,
|
||||
0x4000..=0x7FFF => MemoryMap::BankSwitchable,
|
||||
0x8000..=0x9FFF => MemoryMap::VideoRam,
|
||||
0xA000..=0xBFFF => MemoryMap::ExternalRam,
|
||||
0xC000..=0xCFFF => MemoryMap::WorkRam1,
|
||||
0xD000..=0xDFFF => MemoryMap::WorkRam2,
|
||||
0xE000..=0xFDFF => MemoryMap::EchoRam,
|
||||
0xFE00..=0xFE9F => MemoryMap::SpriteAttributeTable,
|
||||
0xFEA0..=0xFEFF => MemoryMap::NotUsable,
|
||||
0xFF00..=0xFF7F => MemoryMap::IoRegisters,
|
||||
0xFF80..=0xFFFE => MemoryMap::HighRam,
|
||||
INTERRUPT_ENABLE_ADDRESS => MemoryMap::InterruptEnable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self, address: u16) -> u8 {
|
||||
match Bus::map_address(address) {
|
||||
MemoryMap::BankZero | MemoryMap::BankSwitchable | MemoryMap::ExternalRam => self.rom.read(address),
|
||||
MemoryMap::WorkRam1 | MemoryMap::WorkRam2 | MemoryMap::EchoRam => self.ram.read(address),
|
||||
MemoryMap::VideoRam => self.ppu.read_vram_external(address),
|
||||
MemoryMap::SpriteAttributeTable => self.ppu.read_oam(address),
|
||||
MemoryMap::IoRegisters => {
|
||||
if self.cgb_mode && address == PREPARE_SPEED_SWITCH_ADDRESS {
|
||||
let byte = self.data[address as usize];
|
||||
let current_speed = (self.double_speed_mode as u8) << 7;
|
||||
let prepare_speed_switch = self.prepare_double_speed_mode as u8;
|
||||
return (byte & 0b0111_1110) | current_speed | prepare_speed_switch;
|
||||
} else if address == WRAM_BANK_SELECT_ADDRESS {
|
||||
return self.ram.read(address);
|
||||
} else if address == INTERRUPT_FLAG_ADDRESS {
|
||||
return self.interrupts.read(address);
|
||||
} else if PPU::is_io_register(address) {
|
||||
return self.ppu.get_register(address);
|
||||
} else if Sound::is_io_register(address) {
|
||||
return self.sound.get_register(address);
|
||||
} else if Timer::is_io_register(address) {
|
||||
return self.timer.get_register(address);
|
||||
} else if address == JOYPAD_ADDRESS {
|
||||
return self.joypad.read(self.data[address as usize]);
|
||||
}
|
||||
return self.data[address as usize];
|
||||
},
|
||||
MemoryMap::InterruptEnable => self.interrupts.read(address),
|
||||
_ => self.data[address as usize],
|
||||
}
|
||||
self.data[address as usize]
|
||||
}
|
||||
|
||||
pub fn read_16bit(&self, address: u16) -> u16 {
|
||||
@ -138,47 +174,48 @@ impl Bus {
|
||||
}
|
||||
|
||||
pub fn write(&mut self, address: u16, data: u8) {
|
||||
if address == 0xFF01 {
|
||||
// print!("{}", data as char);
|
||||
}
|
||||
|
||||
if BANK_ZERO.contains(&address) || BANK_SWITCHABLE.contains(&address) || EXTERNAL_RAM.contains(&address) {
|
||||
self.rom.write(address, data);
|
||||
} else if address == INTERRUPT_ENABLE_ADDRESS || address == INTERRUPT_FLAG_ADDRESS {
|
||||
self.interrupts.write(address, data);
|
||||
} else if WORK_RAM_1.contains(&address) || WORK_RAM_2.contains(&address) || address == WRAM_BANK_SELECT_ADDRESS {
|
||||
self.ram.write(address, data);
|
||||
} else if EXTERNAL_RAM.contains(&address) {
|
||||
self.rom.write(address, data);
|
||||
} else if ECHO_RAM.contains(&address) {
|
||||
self.ram.write(WORK_RAM_1.min().unwrap() + ((address - ECHO_RAM.min().unwrap()) & 0x1FFF), data);
|
||||
} else if Timer::is_io_register(address) {
|
||||
self.timer.set_register(address, data);
|
||||
} else if Sound::is_io_register(address) {
|
||||
self.sound.set_register(address, data);
|
||||
} else if address == JOYPAD_ADDRESS {
|
||||
let byte = self.data[address as usize];
|
||||
self.data[address as usize] = (data & 0b11110000) | (byte & 0b00001111);
|
||||
} else if VIDEO_RAM.contains(&address) {
|
||||
return self.ppu.write_vram_external(address, data);
|
||||
} else if SPRITE_ATTRIBUTE_TABLE.contains(&address) {
|
||||
return self.ppu.write_oam(address, data);
|
||||
} else if address == DMA_ADDRESS {
|
||||
self.ppu.set_register(address, data);
|
||||
self.dma_transfer(data);
|
||||
} else if address == HDMA5_ADDRESS {
|
||||
self.ppu.set_register(address, data);
|
||||
self.hdma_transfer(data);
|
||||
} else if PPU::is_io_register(address) {
|
||||
self.ppu.set_register(address, data);
|
||||
} else if address == PREPARE_SPEED_SWITCH_ADDRESS && self.cgb_mode {
|
||||
let current_byte = self.data[address as usize];
|
||||
self.prepare_double_speed_mode = (data & 1) == 1;
|
||||
// bit 7 is read only on cgb mode
|
||||
self.data[address as usize] = (current_byte & 0b1000_0000) | (data & 0b0111_1111);
|
||||
} else {
|
||||
self.data[address as usize] = data;
|
||||
}
|
||||
match Bus::map_address(address) {
|
||||
MemoryMap::BankZero | MemoryMap::BankSwitchable | MemoryMap::ExternalRam => self.rom.write(address, data),
|
||||
MemoryMap::WorkRam1 | MemoryMap::WorkRam2 | MemoryMap::EchoRam => self.ram.write(address, data),
|
||||
MemoryMap::VideoRam => self.ppu.write_vram_external(address, data),
|
||||
MemoryMap::SpriteAttributeTable => self.ppu.write_oam(address, data),
|
||||
MemoryMap::IoRegisters => {
|
||||
if self.cgb_mode && address == PREPARE_SPEED_SWITCH_ADDRESS {
|
||||
let current_byte = self.data[address as usize];
|
||||
self.prepare_double_speed_mode = (data & 1) == 1;
|
||||
// bit 7 is read only on cgb mode
|
||||
self.data[address as usize] = (current_byte & 0b1000_0000) | (data & 0b0111_1111);
|
||||
} else if address == WRAM_BANK_SELECT_ADDRESS {
|
||||
self.ram.write(address, data);
|
||||
} else if address == INTERRUPT_FLAG_ADDRESS {
|
||||
self.interrupts.write(address, data);
|
||||
} else if PPU::is_io_register(address) {
|
||||
self.ppu.set_register(address, data);
|
||||
match address {
|
||||
DMA_ADDRESS => {
|
||||
self.ppu.set_register(address, data);
|
||||
self.dma_transfer(data);
|
||||
},
|
||||
HDMA5_ADDRESS => {
|
||||
self.ppu.set_register(address, data);
|
||||
self.hdma_transfer(data);
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
} else if Sound::is_io_register(address) {
|
||||
self.sound.set_register(address, data);
|
||||
} else if Timer::is_io_register(address) {
|
||||
self.timer.set_register(address, data);
|
||||
} else if address == JOYPAD_ADDRESS {
|
||||
let byte = self.data[address as usize];
|
||||
self.data[address as usize] = (data & 0b11110000) | (byte & 0b00001111);
|
||||
} else {
|
||||
self.data[address as usize] = data;
|
||||
}
|
||||
},
|
||||
MemoryMap::InterruptEnable => self.interrupts.write(address, data),
|
||||
_ => self.data[address as usize] = data,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn write_16bit(&mut self, address: u16, data: u16) {
|
||||
|
@ -920,7 +920,6 @@ impl CPU {
|
||||
}
|
||||
|
||||
pub fn handle_interrupt(&mut self, bus: &mut Bus, interrupt: Interrupt) {
|
||||
// println!("Interrupt: {:?}", interrupt);
|
||||
bus.interrupts.set(interrupt, false);
|
||||
self.ime = false;
|
||||
self.registers.decrement(Register::PC, 3);
|
||||
|
120
src/ppu.rs
120
src/ppu.rs
@ -394,85 +394,83 @@ impl PPU {
|
||||
}
|
||||
|
||||
pub fn get_register(&self, address: u16) -> u8 {
|
||||
if address >= HDMA1_ADDRESS && address <= HDMA5_ADDRESS {
|
||||
return match address {
|
||||
match address {
|
||||
HDMA1_ADDRESS..=HDMA5_ADDRESS => match address {
|
||||
HDMA1_ADDRESS => self.hdma_source.to_be_bytes()[0],
|
||||
HDMA2_ADDRESS => self.hdma_source.to_be_bytes()[1],
|
||||
HDMA3_ADDRESS => self.hdma_destination.to_be_bytes()[0],
|
||||
HDMA4_ADDRESS => self.hdma_destination.to_be_bytes()[1],
|
||||
HDMA5_ADDRESS => self.hdma_start,
|
||||
_ => 0x00,
|
||||
}
|
||||
} else if address >= 0xFF68 && address <= 0xFF6B {
|
||||
return self.cram_registers[(address as usize) - 0xFF68];
|
||||
} else if address == VRAM_BANK_SELECT_ADDRESS {
|
||||
return self.get_vram_bank();
|
||||
} else if address == LCD_CONTROL_ADDRESS {
|
||||
return self.lcd_control;
|
||||
} else if address == LCD_Y_ADDRESS {
|
||||
return self.lcd_y;
|
||||
},
|
||||
0xFF68..=0xFF6B => self.cram_registers[(address as usize) - 0xFF68],
|
||||
VRAM_BANK_SELECT_ADDRESS => self.get_vram_bank(),
|
||||
LCD_CONTROL_ADDRESS => self.lcd_control,
|
||||
LCD_Y_ADDRESS => self.lcd_y,
|
||||
_ => self.io_registers[(address - 0xFF40) as usize],
|
||||
}
|
||||
self.io_registers[(address - 0xFF40) as usize]
|
||||
}
|
||||
|
||||
pub fn set_register(&mut self, address: u16, data: u8) {
|
||||
if address >= HDMA1_ADDRESS && address <= HDMA5_ADDRESS {
|
||||
match address {
|
||||
match address {
|
||||
HDMA1_ADDRESS..=HDMA5_ADDRESS => match address {
|
||||
HDMA1_ADDRESS => self.hdma_source = (self.hdma_source & 0xFF) | ((data as u16) << 8),
|
||||
HDMA2_ADDRESS => self.hdma_source = (self.hdma_source & 0xFF00) | (data as u16),
|
||||
HDMA3_ADDRESS => self.hdma_destination = (self.hdma_destination & 0xFF) | ((data as u16) << 8),
|
||||
HDMA4_ADDRESS => self.hdma_destination = (self.hdma_destination & 0xFF00) | (data as u16),
|
||||
HDMA5_ADDRESS => self.hdma_start = data,
|
||||
_ => (),
|
||||
};
|
||||
} else if address >= 0xFF68 && address <= 0xFF6B {
|
||||
self.cram_registers[(address as usize) - 0xFF68] = data;
|
||||
|
||||
if address == BCPD_BGPD_ADDRESS {
|
||||
if self.get_lcd_status(LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD)) {
|
||||
return;
|
||||
},
|
||||
0xFF68..=0xFF6B => {
|
||||
self.cram_registers[(address as usize) - 0xFF68] = data;
|
||||
match address {
|
||||
BCPD_BGPD_ADDRESS => {
|
||||
if self.get_lcd_status(LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD)) {
|
||||
return;
|
||||
}
|
||||
let byte = self.cram_registers[(BCPS_BGPI_ADDRESS as usize) - 0xFF68];
|
||||
let auto_increment = get_bit(byte, BitIndex::I7);
|
||||
let cram_address = byte & 0b111111;
|
||||
self.bg_cram[cram_address as usize] = data;
|
||||
if auto_increment {
|
||||
self.cram_registers[(BCPS_BGPI_ADDRESS as usize) - 0xFF68] = ((byte + 1) & 0b111111) | ((auto_increment as u8) << 7);
|
||||
}
|
||||
},
|
||||
OCPD_OBPD_ADDRESS => {
|
||||
if self.get_lcd_status(LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD)) {
|
||||
return;
|
||||
}
|
||||
let byte = self.cram_registers[(OCPS_OBPI_ADDRESS as usize) - 0xFF68];
|
||||
let auto_increment = get_bit(byte, BitIndex::I7);
|
||||
let cram_address = byte & 0b111111;
|
||||
self.obj_cram[cram_address as usize] = data;
|
||||
if auto_increment {
|
||||
self.cram_registers[(OCPS_OBPI_ADDRESS as usize) - 0xFF68] = ((byte + 1) & 0b111111) | ((auto_increment as u8) << 7);
|
||||
}
|
||||
}
|
||||
_ => {},
|
||||
}
|
||||
let byte = self.cram_registers[(BCPS_BGPI_ADDRESS as usize) - 0xFF68];
|
||||
let auto_increment = get_bit(byte, BitIndex::I7);
|
||||
let cram_address = byte & 0b111111;
|
||||
self.bg_cram[cram_address as usize] = data;
|
||||
if auto_increment {
|
||||
self.cram_registers[(BCPS_BGPI_ADDRESS as usize) - 0xFF68] = ((byte + 1) & 0b111111) | ((auto_increment as u8) << 7);
|
||||
},
|
||||
VRAM_BANK_SELECT_ADDRESS => self.set_vram_bank(data),
|
||||
LCD_Y_ADDRESS => {},
|
||||
LCD_CONTROL_ADDRESS => {
|
||||
self.lcd_control = data;
|
||||
// Check if LCD is being turned on or off
|
||||
self.lcd_enable = get_bit(data, BitIndex::I7);
|
||||
if !get_bit(data, BitIndex::I7) || (get_bit(data, BitIndex::I7) && !get_bit(self.lcd_control, BitIndex::I7)) {
|
||||
self.lcd_y = 0x00;
|
||||
// Set Hblank
|
||||
let byte = self.io_registers[LCD_STATUS_ADDRESS as usize - 0xFF40];
|
||||
self.io_registers[LCD_STATUS_ADDRESS as usize - 0xFF40] = byte & 0b11111100;
|
||||
}
|
||||
} else if address == OCPD_OBPD_ADDRESS {
|
||||
if self.get_lcd_status(LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD)) {
|
||||
return;
|
||||
}
|
||||
let byte = self.cram_registers[(OCPS_OBPI_ADDRESS as usize) - 0xFF68];
|
||||
let auto_increment = get_bit(byte, BitIndex::I7);
|
||||
let cram_address = byte & 0b111111;
|
||||
self.obj_cram[cram_address as usize] = data;
|
||||
if auto_increment {
|
||||
self.cram_registers[(OCPS_OBPI_ADDRESS as usize) - 0xFF68] = ((byte + 1) & 0b111111) | ((auto_increment as u8) << 7);
|
||||
}
|
||||
}
|
||||
} else if address == VRAM_BANK_SELECT_ADDRESS {
|
||||
return self.set_vram_bank(data);
|
||||
} else if address == LCD_Y_ADDRESS {
|
||||
return;
|
||||
} else if address == LCD_CONTROL_ADDRESS {
|
||||
self.lcd_control = data;
|
||||
// Check if LCD is being turned on or off
|
||||
self.lcd_enable = get_bit(data, BitIndex::I7);
|
||||
if !get_bit(data, BitIndex::I7) || (get_bit(data, BitIndex::I7) && !get_bit(self.lcd_control, BitIndex::I7)) {
|
||||
self.lcd_y = 0x00;
|
||||
// Set Hblank
|
||||
let byte = self.io_registers[LCD_STATUS_ADDRESS as usize - 0xFF40];
|
||||
self.io_registers[LCD_STATUS_ADDRESS as usize - 0xFF40] = byte & 0b11111100;
|
||||
}
|
||||
return;
|
||||
} else if address == LCD_STATUS_ADDRESS {
|
||||
let address = address - 0xFF40;
|
||||
let byte = self.io_registers[address as usize];
|
||||
self.io_registers[address as usize] = (data & 0b11111000) | (byte & 0b00000111);
|
||||
} else {
|
||||
self.io_registers[address as usize - 0xFF40] = data;
|
||||
}
|
||||
},
|
||||
LCD_STATUS_ADDRESS => {
|
||||
let address = address - 0xFF40;
|
||||
let byte = self.io_registers[address as usize];
|
||||
self.io_registers[address as usize] = (data & 0b11111000) | (byte & 0b00000111);
|
||||
},
|
||||
_ => self.io_registers[address as usize - 0xFF40] = data,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn force_set_register(&mut self, address: u16, data: u8) {
|
||||
|
17
src/ram.rs
17
src/ram.rs
@ -1,3 +1,5 @@
|
||||
use crate::bus::{ECHO_RAM, WORK_RAM_1};
|
||||
|
||||
pub const WRAM_BANK_SELECT_ADDRESS: u16 = 0xFF70;
|
||||
|
||||
pub trait RAM {
|
||||
@ -17,11 +19,20 @@ impl DMGRAM {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_echo_ram_address(address: u16) -> u16 {
|
||||
let mut address = address;
|
||||
if ECHO_RAM.contains(&address) {
|
||||
address = WORK_RAM_1.min().unwrap() + ((address - ECHO_RAM.min().unwrap()) & 0x1FFF);
|
||||
}
|
||||
address
|
||||
}
|
||||
|
||||
impl RAM for DMGRAM {
|
||||
fn read(&self, address: u16) -> u8 {
|
||||
if address == WRAM_BANK_SELECT_ADDRESS {
|
||||
return 0xFF;
|
||||
}
|
||||
let address = parse_echo_ram_address(address);
|
||||
self.data[(address - 0xC000) as usize]
|
||||
}
|
||||
|
||||
@ -29,6 +40,7 @@ impl RAM for DMGRAM {
|
||||
if address == WRAM_BANK_SELECT_ADDRESS {
|
||||
return;
|
||||
}
|
||||
let address = parse_echo_ram_address(address);
|
||||
self.data[(address - 0xC000) as usize] = value;
|
||||
}
|
||||
}
|
||||
@ -63,6 +75,7 @@ impl RAM for CGBRAM {
|
||||
if address == WRAM_BANK_SELECT_ADDRESS {
|
||||
return self.bank;
|
||||
}
|
||||
let address = parse_echo_ram_address(address);
|
||||
if address <= 0xCFFF {
|
||||
return self.data[(address - 0xC000) as usize];
|
||||
}
|
||||
@ -72,7 +85,9 @@ impl RAM for CGBRAM {
|
||||
fn write(&mut self, address: u16, value: u8) {
|
||||
if address == WRAM_BANK_SELECT_ADDRESS {
|
||||
return self.switch_bank(value);
|
||||
} else if address <= 0xCFFF {
|
||||
}
|
||||
let address = parse_echo_ram_address(address);
|
||||
if address <= 0xCFFF {
|
||||
return self.data[(address - 0xC000) as usize] = value;
|
||||
}
|
||||
self.data[((address - 0xD000) as usize) + (4096 * (self.bank as usize))] = value;
|
||||
|
@ -2,6 +2,7 @@ use crate::emulator::Emulator;
|
||||
use crate::frames::Frames;
|
||||
use crate::ppu::{WIDTH, HEIGHT};
|
||||
|
||||
use std::env;
|
||||
use log::error;
|
||||
use pixels::{wgpu, Pixels, PixelsBuilder, SurfaceTexture};
|
||||
use winit::dpi::LogicalSize;
|
||||
@ -10,10 +11,13 @@ use winit::event_loop::{ControlFlow, EventLoop};
|
||||
use winit::window::{Window, WindowBuilder};
|
||||
use winit_input_helper::WinitInputHelper;
|
||||
|
||||
fn is_fps_unlocked() -> bool {
|
||||
!env::var("UNLOCK_FPS").is_err()
|
||||
}
|
||||
|
||||
pub fn create_pixels(width: u32, height: u32, window: &Window) -> Pixels {
|
||||
let window_size = window.inner_size();
|
||||
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, window);
|
||||
// Pixels::new(width, height, surface_texture).unwrap()
|
||||
PixelsBuilder::new(width, height, surface_texture)
|
||||
.device_descriptor(wgpu::DeviceDescriptor {
|
||||
limits: wgpu::Limits {
|
||||
@ -24,7 +28,7 @@ pub fn create_pixels(width: u32, height: u32, window: &Window) -> Pixels {
|
||||
},
|
||||
..wgpu::DeviceDescriptor::default()
|
||||
})
|
||||
.enable_vsync(false)
|
||||
.enable_vsync(!is_fps_unlocked())
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
@ -88,7 +92,9 @@ pub fn start_eventloop() {
|
||||
frame_counter.reset_timer();
|
||||
}
|
||||
window.request_redraw();
|
||||
frame_limit.limit();
|
||||
if !is_fps_unlocked() {
|
||||
frame_limit.limit();
|
||||
}
|
||||
frame_limit.reset_timer();
|
||||
},
|
||||
Event::RedrawRequested(_) => {
|
||||
|
Loading…
Reference in New Issue
Block a user