mirror of
https://github.com/exoticorn/microw8.git
synced 2026-01-20 11:16:42 +01:00
add some command line switches for the gpu window
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -3171,6 +3171,8 @@ dependencies = [
|
||||
"anyhow",
|
||||
"cpal",
|
||||
"curlywas",
|
||||
"env_logger 0.9.0",
|
||||
"log",
|
||||
"notify",
|
||||
"pico-args",
|
||||
"rubato",
|
||||
@@ -3207,6 +3209,7 @@ dependencies = [
|
||||
"env_logger 0.9.0",
|
||||
"log",
|
||||
"minifb",
|
||||
"pico-args",
|
||||
"pollster",
|
||||
"wgpu",
|
||||
"winapi 0.3.9",
|
||||
|
||||
@@ -13,6 +13,8 @@ browser = ["warp", "tokio", "tokio-stream", "webbrowser"]
|
||||
[dependencies]
|
||||
wasmtime = { version = "0.37.0", optional = true }
|
||||
anyhow = "1"
|
||||
env_logger = "0.9"
|
||||
log = "0.4"
|
||||
uw8-window = { path = "uw8-window", optional = true }
|
||||
notify = "4"
|
||||
pico-args = "0.4"
|
||||
|
||||
21
README.md
21
README.md
@@ -43,6 +43,27 @@ Options:
|
||||
-l LEVEL, --level LEVEL : Compression level (0-9). Higher compression levels are really slow.
|
||||
-o FILE, --output FILE : Write the loaded and optionally packed cart back to disk.
|
||||
|
||||
when using the native runtime:
|
||||
|
||||
-m, --no-audio : Disable audio, also reduces cpu load a bit
|
||||
--no-gpu : Force old cpu-only window code
|
||||
--filter FILTER : Select an upscale filter at startup
|
||||
--fullscreen : Start in fullscreen mode
|
||||
|
||||
Note that the cpu-only window does not support fullscreen nor upscale filters.
|
||||
|
||||
Unless --no-gpu is given, uw8 will first try to open a gpu accelerated window, falling back to the old cpu-only window if that fails.
|
||||
Therefore you should rarely need to manually pass --no-gpu. If you prefer the old pixel doubling look to the now default crt filter,
|
||||
you can just pass "--filter nearest" or "--filter 1".
|
||||
|
||||
The upscale filter options are:
|
||||
1, nearest : Anti-aliased nearest filter
|
||||
2, fast_crt : Very simple, cheap crt filter, not very good below a window size of 960x720
|
||||
3, ss_crt : Super sampled crt filter, a little more demanding on the GPU but scales well to smaller window sizes
|
||||
4, chromatic_crt : Variant of fast_crt with a slight offset of the three color dots of a pixel, still pretty cheap
|
||||
5, auto_crt (default) : ss_crt below 960x720, chromatic_crt otherwise
|
||||
|
||||
You can switch the upscale filter at any time using the keys 1-5. You can toggle fullscreen with F.
|
||||
|
||||
uw8 pack [<options>] <infile> <outfile>
|
||||
|
||||
|
||||
@@ -436,6 +436,30 @@ and execution of the cart is stopped. Defaults to 30 (0.5s)
|
||||
* `-l LEVEL`, `--level LEVEL`: Compression level (0-9). Higher compression levels are really slow.
|
||||
* `-o FILE`, `--output FILE`: Write the loaded and optionally packed cart back to disk.
|
||||
|
||||
when using the native runtime:
|
||||
|
||||
* `-m`, `--no-audio`: Disable audio, also reduces cpu load a bit
|
||||
* `--no-gpu`: Force old cpu-only window code
|
||||
* `--filter FILTER`: Select an upscale filter at startup
|
||||
* `--fullscreen`: Start in fullscreen mode
|
||||
|
||||
Note that the cpu-only window does not support fullscreen nor upscale filters.
|
||||
|
||||
Unless --no-gpu is given, uw8 will first try to open a gpu accelerated window, falling back to the old cpu-only window if that fails.
|
||||
Therefore you should rarely need to manually pass --no-gpu. If you prefer the old pixel doubling look to the now default crt filter,
|
||||
you can just pass `--filter nearest` or `--filter 1`.
|
||||
|
||||
The upscale filter options are:
|
||||
```
|
||||
1, nearest : Anti-aliased nearest filter
|
||||
2, fast_crt : Very simple, cheap crt filter, not very good below a window size of 960x720
|
||||
3, ss_crt : Super sampled crt filter, a little more demanding on the GPU but scales well to smaller window sizes
|
||||
4, chromatic_crt : Variant of fast_crt with a slight offset of the three color dots of a pixel, still pretty cheap
|
||||
5, auto_crt (default) : ss_crt below 960x720, chromatic_crt otherwise
|
||||
```
|
||||
|
||||
You can switch the upscale filter at any time using the keys 1-5. You can toggle fullscreen with F.
|
||||
|
||||
## `uw8 pack`
|
||||
|
||||
Usage:
|
||||
|
||||
20
src/main.rs
20
src/main.rs
@@ -13,6 +13,7 @@ use uw8::RunWebServer;
|
||||
use uw8::Runtime;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
env_logger::Builder::from_env(env_logger::Env::default()).init();
|
||||
let mut args = Arguments::from_env();
|
||||
|
||||
// try to enable ansi support in win10 cmd shell
|
||||
@@ -35,7 +36,7 @@ fn main() -> Result<()> {
|
||||
println!();
|
||||
println!("Usage:");
|
||||
#[cfg(any(feature = "native", feature = "browser"))]
|
||||
println!(" uw8 run [-t/--timeout <frames>] [--no-gpu] [--b/--browser] [-w/--watch] [-p/--pack] [-u/--uncompressed] [-l/--level] [-o/--output <out-file>] <file>");
|
||||
println!(" uw8 run [-t/--timeout <frames>] [--b/--browser] [-w/--watch] [-p/--pack] [-u/--uncompressed] [-l/--level] [-o/--output <out-file>] <file>");
|
||||
println!(" uw8 pack [-u/--uncompressed] [-l/--level] <in-file> <out-file>");
|
||||
println!(" uw8 unpack <in-file> <out-file>");
|
||||
println!(" uw8 compile [-d/--debug] <in-file> <out-file>");
|
||||
@@ -54,8 +55,6 @@ fn run(mut args: Arguments) -> Result<()> {
|
||||
let watch_mode = args.contains(["-w", "--watch"]);
|
||||
#[allow(unused)]
|
||||
let timeout: Option<u32> = args.opt_value_from_str(["-t", "--timeout"])?;
|
||||
#[allow(unused)]
|
||||
let gpu = !args.contains("--no-gpu");
|
||||
|
||||
let mut config = Config::default();
|
||||
if args.contains(["-p", "--pack"]) {
|
||||
@@ -82,7 +81,16 @@ fn run(mut args: Arguments) -> Result<()> {
|
||||
#[cfg(not(feature = "native"))]
|
||||
let run_browser = args.contains(["-b", "--browser"]) || true;
|
||||
|
||||
let disable_audio = args.contains(["-m", "--disable-audio"]);
|
||||
let disable_audio = args.contains(["-m", "--no-audio"]);
|
||||
|
||||
#[cfg(feature = "native")]
|
||||
let window_config = {
|
||||
let mut config = WindowConfig::default();
|
||||
if !run_browser {
|
||||
config.parse_arguments(&mut args);
|
||||
}
|
||||
config
|
||||
};
|
||||
|
||||
let filename = args.free_from_os_str::<PathBuf, bool>(|s| Ok(s.into()))?;
|
||||
|
||||
@@ -90,12 +98,14 @@ fn run(mut args: Arguments) -> Result<()> {
|
||||
|
||||
use std::process::exit;
|
||||
|
||||
use uw8_window::WindowConfig;
|
||||
|
||||
let mut runtime: Box<dyn Runtime> = if !run_browser {
|
||||
#[cfg(not(feature = "native"))]
|
||||
unimplemented!();
|
||||
#[cfg(feature = "native")]
|
||||
{
|
||||
let mut microw8 = MicroW8::new(timeout, gpu)?;
|
||||
let mut microw8 = MicroW8::new(timeout, window_config)?;
|
||||
if disable_audio {
|
||||
microw8.disable_audio();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::{thread, time::Instant};
|
||||
use anyhow::{anyhow, Result};
|
||||
use cpal::traits::*;
|
||||
use rubato::Resampler;
|
||||
use uw8_window::Window;
|
||||
use uw8_window::{Window, WindowConfig};
|
||||
use wasmtime::{
|
||||
Engine, GlobalType, Memory, MemoryType, Module, Mutability, Store, TypedFunc, ValType,
|
||||
};
|
||||
@@ -45,7 +45,7 @@ struct UW8WatchDog {
|
||||
}
|
||||
|
||||
impl MicroW8 {
|
||||
pub fn new(timeout: Option<u32>, gpu: bool) -> Result<MicroW8> {
|
||||
pub fn new(timeout: Option<u32>, window_config: WindowConfig) -> Result<MicroW8> {
|
||||
let mut config = wasmtime::Config::new();
|
||||
config.cranelift_opt_level(wasmtime::OptLevel::Speed);
|
||||
if timeout.is_some() {
|
||||
@@ -56,7 +56,7 @@ impl MicroW8 {
|
||||
let loader_module =
|
||||
wasmtime::Module::new(&engine, include_bytes!("../platform/bin/loader.wasm"))?;
|
||||
|
||||
let window = Window::new(gpu)?;
|
||||
let window = Window::new(window_config)?;
|
||||
|
||||
Ok(MicroW8 {
|
||||
window,
|
||||
|
||||
7
uw8-window/Cargo.lock
generated
7
uw8-window/Cargo.lock
generated
@@ -986,6 +986,12 @@ version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
|
||||
[[package]]
|
||||
name = "pico-args"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
@@ -1296,6 +1302,7 @@ dependencies = [
|
||||
"env_logger",
|
||||
"log",
|
||||
"minifb",
|
||||
"pico-args",
|
||||
"pollster",
|
||||
"wgpu",
|
||||
"winapi",
|
||||
|
||||
@@ -9,6 +9,7 @@ edition = "2021"
|
||||
winit = "0.26.1"
|
||||
env_logger = "0.9"
|
||||
log = "0.4"
|
||||
pico-args = "0.4"
|
||||
wgpu = "0.13.1"
|
||||
pollster = "0.2"
|
||||
bytemuck = { version = "1.4", features = [ "derive" ] }
|
||||
|
||||
@@ -78,6 +78,6 @@ impl WindowImpl for Window {
|
||||
}
|
||||
|
||||
fn is_open(&self) -> bool {
|
||||
self.window.is_open()
|
||||
self.window.is_open() && !self.window.is_key_down(Key::Escape)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{Input, WindowImpl};
|
||||
use crate::{Input, WindowConfig, WindowImpl};
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::{num::NonZeroU32, time::Instant};
|
||||
|
||||
@@ -37,13 +37,18 @@ pub struct Window {
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub fn new() -> Result<Window> {
|
||||
async fn create() -> Result<Window> {
|
||||
pub fn new(window_config: WindowConfig) -> Result<Window> {
|
||||
async fn create(window_config: WindowConfig) -> Result<Window> {
|
||||
let event_loop = EventLoop::new();
|
||||
let window = WindowBuilder::new()
|
||||
.with_inner_size(PhysicalSize::new(640u32, 480))
|
||||
.with_min_inner_size(PhysicalSize::new(320u32, 240))
|
||||
.with_title("MicroW8")
|
||||
.with_fullscreen(if window_config.fullscreen {
|
||||
Some(Fullscreen::Borderless(None))
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.build(&event_loop)?;
|
||||
|
||||
window.set_cursor_visible(false);
|
||||
@@ -73,12 +78,13 @@ impl Window {
|
||||
present_mode: wgpu::PresentMode::AutoNoVsync,
|
||||
};
|
||||
|
||||
let filter: Box<dyn Filter> = Box::new(AutoCrtFilter::new(
|
||||
let filter: Box<dyn Filter> = create_filter(
|
||||
&device,
|
||||
&palette_screen_mode.screen_view,
|
||||
window.inner_size(),
|
||||
surface_config.format,
|
||||
));
|
||||
window_config.filter,
|
||||
);
|
||||
|
||||
surface.configure(&device, &surface_config);
|
||||
|
||||
@@ -95,12 +101,12 @@ impl Window {
|
||||
filter,
|
||||
gamepads: [0; 4],
|
||||
next_frame: Instant::now(),
|
||||
is_fullscreen: false,
|
||||
is_fullscreen: window_config.fullscreen,
|
||||
is_open: true,
|
||||
})
|
||||
}
|
||||
|
||||
pollster::block_on(create())
|
||||
pollster::block_on(create(window_config))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +115,7 @@ impl WindowImpl for Window {
|
||||
let mut reset = false;
|
||||
self.event_loop.run_return(|event, _, control_flow| {
|
||||
*control_flow = ControlFlow::WaitUntil(self.next_frame);
|
||||
let mut new_filter = None;
|
||||
match event {
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
WindowEvent::Resized(new_size) => {
|
||||
@@ -153,48 +160,11 @@ impl WindowImpl for Window {
|
||||
self.window.set_fullscreen(fullscreen);
|
||||
}
|
||||
Some(VirtualKeyCode::R) => reset = true,
|
||||
Some(VirtualKeyCode::Key1) => {
|
||||
self.filter = Box::new(SquareFilter::new(
|
||||
&self.device,
|
||||
&self.palette_screen_mode.screen_view,
|
||||
self.window.inner_size(),
|
||||
self.surface_config.format,
|
||||
))
|
||||
}
|
||||
Some(VirtualKeyCode::Key2) => {
|
||||
self.filter = Box::new(FastCrtFilter::new(
|
||||
&self.device,
|
||||
&self.palette_screen_mode.screen_view,
|
||||
self.window.inner_size(),
|
||||
self.surface_config.format,
|
||||
false,
|
||||
))
|
||||
}
|
||||
Some(VirtualKeyCode::Key3) => {
|
||||
self.filter = Box::new(CrtFilter::new(
|
||||
&self.device,
|
||||
&self.palette_screen_mode.screen_view,
|
||||
self.window.inner_size(),
|
||||
self.surface_config.format,
|
||||
))
|
||||
}
|
||||
Some(VirtualKeyCode::Key4) => {
|
||||
self.filter = Box::new(FastCrtFilter::new(
|
||||
&self.device,
|
||||
&self.palette_screen_mode.screen_view,
|
||||
self.window.inner_size(),
|
||||
self.surface_config.format,
|
||||
true,
|
||||
))
|
||||
}
|
||||
Some(VirtualKeyCode::Key5) => {
|
||||
self.filter = Box::new(AutoCrtFilter::new(
|
||||
&self.device,
|
||||
&self.palette_screen_mode.screen_view,
|
||||
self.window.inner_size(),
|
||||
self.surface_config.format,
|
||||
))
|
||||
}
|
||||
Some(VirtualKeyCode::Key1) => new_filter = Some(1),
|
||||
Some(VirtualKeyCode::Key2) => new_filter = Some(2),
|
||||
Some(VirtualKeyCode::Key3) => new_filter = Some(3),
|
||||
Some(VirtualKeyCode::Key4) => new_filter = Some(4),
|
||||
Some(VirtualKeyCode::Key5) => new_filter = Some(5),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@@ -215,6 +185,15 @@ impl WindowImpl for Window {
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
if let Some(new_filter) = new_filter {
|
||||
self.filter = create_filter(
|
||||
&self.device,
|
||||
&self.palette_screen_mode.screen_view,
|
||||
self.window.inner_size(),
|
||||
self.surface_config.format,
|
||||
new_filter,
|
||||
);
|
||||
}
|
||||
});
|
||||
Input {
|
||||
gamepads: self.gamepads,
|
||||
@@ -269,6 +248,49 @@ impl WindowImpl for Window {
|
||||
}
|
||||
}
|
||||
|
||||
fn create_filter(
|
||||
device: &wgpu::Device,
|
||||
screen_texture: &wgpu::TextureView,
|
||||
window_size: PhysicalSize<u32>,
|
||||
surface_format: wgpu::TextureFormat,
|
||||
filter: u32,
|
||||
) -> Box<dyn Filter> {
|
||||
match filter {
|
||||
1 => Box::new(SquareFilter::new(
|
||||
device,
|
||||
screen_texture,
|
||||
window_size,
|
||||
surface_format,
|
||||
)),
|
||||
2 => Box::new(FastCrtFilter::new(
|
||||
device,
|
||||
screen_texture,
|
||||
window_size,
|
||||
surface_format,
|
||||
false,
|
||||
)),
|
||||
3 => Box::new(CrtFilter::new(
|
||||
device,
|
||||
screen_texture,
|
||||
window_size,
|
||||
surface_format,
|
||||
)),
|
||||
4 => Box::new(FastCrtFilter::new(
|
||||
device,
|
||||
screen_texture,
|
||||
window_size,
|
||||
surface_format,
|
||||
true,
|
||||
)),
|
||||
_ => Box::new(AutoCrtFilter::new(
|
||||
device,
|
||||
screen_texture,
|
||||
window_size,
|
||||
surface_format,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
trait Filter {
|
||||
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>);
|
||||
fn render<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>);
|
||||
|
||||
@@ -7,9 +7,9 @@ mod gpu;
|
||||
pub struct Window(Box<dyn WindowImpl>);
|
||||
|
||||
impl Window {
|
||||
pub fn new(gpu: bool) -> Result<Window> {
|
||||
if gpu {
|
||||
match gpu::Window::new() {
|
||||
pub fn new(config: WindowConfig) -> Result<Window> {
|
||||
if config.enable_gpu {
|
||||
match gpu::Window::new(config) {
|
||||
Ok(window) => return Ok(Window(Box::new(window))),
|
||||
Err(err) => eprintln!(
|
||||
"Failed to create gpu window: {}\nFalling back tp cpu window",
|
||||
@@ -32,6 +32,43 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WindowConfig {
|
||||
enable_gpu: bool,
|
||||
filter: u32,
|
||||
fullscreen: bool,
|
||||
}
|
||||
|
||||
impl Default for WindowConfig {
|
||||
fn default() -> WindowConfig {
|
||||
WindowConfig {
|
||||
enable_gpu: true,
|
||||
filter: 5,
|
||||
fullscreen: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowConfig {
|
||||
pub fn parse_arguments(&mut self, args: &mut pico_args::Arguments) {
|
||||
self.enable_gpu = !args.contains("--no-gpu");
|
||||
if let Some(filter) = args.opt_value_from_str::<_, String>("--filter").unwrap() {
|
||||
self.filter = match filter.as_str() {
|
||||
"1" | "nearest" => 1,
|
||||
"2" | "fast_crt" => 2,
|
||||
"3" | "ss_crt" => 3,
|
||||
"4" | "chromatic" => 4,
|
||||
"5" | "auto_crt" => 5,
|
||||
o => {
|
||||
println!("Unknown --filter '{}'", o);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.fullscreen = args.contains("--fullscreen");
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Input {
|
||||
pub gamepads: [u8; 4],
|
||||
pub reset: bool,
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
use std::time::Instant;
|
||||
use uw8_window::WindowConfig;
|
||||
|
||||
fn main() {
|
||||
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
|
||||
|
||||
let mut args = pico_args::Arguments::from_env();
|
||||
|
||||
let mut framebuffer = vec![0u8; 320 * 240];
|
||||
let mut start_time = Instant::now();
|
||||
|
||||
@@ -18,7 +21,10 @@ fn main() {
|
||||
let mut fps_start = Instant::now();
|
||||
let mut fps_counter = 0;
|
||||
|
||||
let mut window = uw8_window::Window::new(true).unwrap();
|
||||
let mut window_config = WindowConfig::default();
|
||||
window_config.parse_arguments(&mut args);
|
||||
|
||||
let mut window = uw8_window::Window::new(window_config).unwrap();
|
||||
|
||||
while window.is_open() {
|
||||
let input = window.begin_frame();
|
||||
|
||||
Reference in New Issue
Block a user