Compare commits

...
7 Commits
5 changed files with 62 additions and 24 deletions
Generated
+1 -1
View File
@@ -2165,7 +2165,7 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "lemur" name = "lemur"
version = "0.7.3" version = "0.8.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"atoi", "atoi",
+1 -1
View File
@@ -4,7 +4,7 @@ description = "An emulator for the Virtual Boy."
repository = "https://git.virtual-boy.com/PVB/lemur" repository = "https://git.virtual-boy.com/PVB/lemur"
publish = false publish = false
license = "MIT" license = "MIT"
version = "0.7.3" version = "0.8.2"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
+1
View File
@@ -41,6 +41,7 @@ ENV PATH="/osxcross/bin:$PATH" \
SHROOMS_CFLAGS_x86_64-unknown-linux-gnu="-flto" \ SHROOMS_CFLAGS_x86_64-unknown-linux-gnu="-flto" \
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" \ CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" \
SHROOMS_CFLAGS_x86_64-pc-windows-msvc="-flto" \ SHROOMS_CFLAGS_x86_64-pc-windows-msvc="-flto" \
CFLAGS_x86_64-pc-windows-msvc="-I/xwin/crt/include -I/xwin/sdk/include/ucrt -I/xwin/sdk/include/um -I/xwin/sdk/include/shared" \
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS="-Lnative=/xwin/crt/lib/x86_64 -Lnative=/xwin/sdk/lib/um/x86_64 -Lnative=/xwin/sdk/lib/ucrt/x86_64 -Clinker-plugin-lto -Clink-arg=-fuse-ld=lld" \ CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS="-Lnative=/xwin/crt/lib/x86_64 -Lnative=/xwin/sdk/lib/um/x86_64 -Lnative=/xwin/sdk/lib/ucrt/x86_64 -Clinker-plugin-lto -Clink-arg=-fuse-ld=lld" \
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER="lld-link-20" \ CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER="lld-link-20" \
CARGO_TARGET_X86_64_APPLE_DARWIN_LINKER="o64-clang" \ CARGO_TARGET_X86_64_APPLE_DARWIN_LINKER="o64-clang" \
+4 -3
View File
@@ -86,12 +86,13 @@ fn parse_elf_program<Elf: object::read::elf::FileHeader<Endian = object::Endiann
let mut bytes = vec![]; let mut bytes = vec![];
let mut pstart = None; let mut pstart = None;
for phdr in header.program_headers(endian, data).ok()? { for phdr in header.program_headers(endian, data).ok()? {
if phdr.p_filesz(endian).into() == 0 { let pma = phdr.p_paddr(endian).into();
if pma < 0x07000000 || phdr.p_filesz(endian).into() == 0 {
continue; continue;
} }
let start = pstart.unwrap_or(phdr.p_paddr(endian).into()); let start = pstart.unwrap_or(pma);
pstart = Some(start); pstart = Some(start);
bytes.resize((phdr.p_paddr(endian).into() - start) as usize, 0); bytes.resize((pma - start) as usize, 0);
let data = phdr.data(endian, data).ok()?; let data = phdr.data(endian, data).ok()?;
bytes.extend_from_slice(data); bytes.extend_from_slice(data);
} }
+55 -19
View File
@@ -1,17 +1,18 @@
use std::{fs, time::Duration}; use std::{fs, time::Duration};
use anyhow::Result; use anyhow::Result;
use egui::{Button, CentralPanel, Checkbox, ViewportBuilder, ViewportId}; use egui::{Button, CentralPanel, Checkbox, Label, ViewportBuilder, ViewportId};
use egui_notify::{Anchor, Toast, Toasts}; use egui_notify::{Anchor, Toast, Toasts};
use crate::{ use crate::{
emulator::{EmulatorClient, SimId}, emulator::{EmulatorClient, EmulatorCommand, EmulatorState, SimId},
profiler::{Profiler, ProfilerStatus}, profiler::{Profiler, ProfilerStatus},
window::AppWindow, window::AppWindow,
}; };
pub struct ProfileWindow { pub struct ProfileWindow {
sim_id: SimId, sim_id: SimId,
client: EmulatorClient,
profiler: Profiler, profiler: Profiler,
toasts: Toasts, toasts: Toasts,
} }
@@ -20,6 +21,7 @@ impl ProfileWindow {
pub fn new(sim_id: SimId, client: EmulatorClient) -> Self { pub fn new(sim_id: SimId, client: EmulatorClient) -> Self {
Self { Self {
sim_id, sim_id,
client: client.clone(),
profiler: Profiler::new(sim_id, client), profiler: Profiler::new(sim_id, client),
toasts: Toasts::new() toasts: Toasts::new()
.with_anchor(Anchor::BottomLeft) .with_anchor(Anchor::BottomLeft)
@@ -33,6 +35,10 @@ impl ProfileWindow {
} }
fn finish_recording(&mut self) { fn finish_recording(&mut self) {
let pause = matches!(self.client.emulator_state(), EmulatorState::Running);
if pause {
self.client.send_command(EmulatorCommand::Pause);
}
match self.try_finish_recording() { match self.try_finish_recording() {
Ok(Some(path)) => { Ok(Some(path)) => {
let mut toast = Toast::info(format!("Saved to {path}")); let mut toast = Toast::info(format!("Saved to {path}"));
@@ -46,6 +52,9 @@ impl ProfileWindow {
self.toasts.add(toast); self.toasts.add(toast);
} }
} }
if pause {
self.client.send_command(EmulatorCommand::Resume);
}
} }
fn try_finish_recording(&mut self) -> Result<Option<String>> { fn try_finish_recording(&mut self) -> Result<Option<String>> {
@@ -84,8 +93,32 @@ impl AppWindow for ProfileWindow {
let status = self.profiler.status(); let status = self.profiler.status();
let recording = matches!(status, ProfilerStatus::Recording); let recording = matches!(status, ProfilerStatus::Recording);
CentralPanel::default().show(ctx, |ui| { CentralPanel::default().show(ctx, |ui| {
ui.horizontal_wrapped(|ui| {
ui.spacing_mut().item_spacing.x = 0.0;
ui.add(
Label::new(
"Use this tool to record performance profiles of your game, for use in ",
)
.wrap_mode(egui::TextWrapMode::Wrap),
);
ui.hyperlink("https://profiler.firefox.com");
ui.label(".");
});
ui.horizontal_wrapped(|ui| {
ui.spacing_mut().item_spacing.x = 0.0;
ui.add(
Label::new("For more instructions, see ").wrap_mode(egui::TextWrapMode::Wrap),
);
ui.hyperlink_to(
"the Lemur wiki",
"https://git.virtual-boy.com/PVB/lemur/wiki/Profiling-with-Lemur",
);
ui.label(".");
});
ui.separator();
let mut enabled = status.enabled(); let mut enabled = status.enabled();
let enabled_checkbox = Checkbox::new(&mut enabled, "Profiling enabled?"); let enabled_checkbox = Checkbox::new(&mut enabled, "Enable profiling");
if ui.add_enabled(!recording, enabled_checkbox).changed() { if ui.add_enabled(!recording, enabled_checkbox).changed() {
if enabled { if enabled {
self.profiler.enable(); self.profiler.enable();
@@ -93,23 +126,26 @@ impl AppWindow for ProfileWindow {
self.profiler.disable(); self.profiler.disable();
} }
} }
if !enabled {
ui.horizontal(|ui| { ui.label("Enabling profiling will restart your current game.");
if !recording { } else {
let record_button = Button::new("Record"); ui.horizontal(|ui| {
let can_record = matches!(status, ProfilerStatus::Enabled); if !recording {
if ui.add_enabled(can_record, record_button).clicked() { let record_button = Button::new("Record");
self.profiler.start_recording(); let can_record = matches!(status, ProfilerStatus::Enabled);
if ui.add_enabled(can_record, record_button).clicked() {
self.profiler.start_recording();
}
} else {
if ui.button("Finish recording").clicked() {
self.finish_recording();
}
if ui.button("Cancel recording").clicked() {
self.profiler.cancel_recording();
}
} }
} else { });
if ui.button("Finish recording").clicked() { }
self.finish_recording();
}
if ui.button("Cancel recording").clicked() {
self.profiler.cancel_recording();
}
}
});
match &status { match &status {
ProfilerStatus::Recording => { ProfilerStatus::Recording => {