Dbg render fix#2
Open
alfishe wants to merge 81 commits into
Open
Conversation
Fix case-only mismatches in #include directives that fail on case-sensitive filesystems (default on Linux, configurable on macOS). Windows is unaffected due to case-insensitive filesystem. Changes: color.h -> Color.h, EFlow.h -> eFlow.h, tribool.h -> Tribool.h, Point2.h -> point2.h
The app would hang on exit because the UAE CPU thread never received the quit signal when the debugger was not active (Live mode). Root cause: m68k_go() only checked quit_program AFTER run_func() completed a full CPU execution round. If the CPU was running without debugger interaction, it would never exit the inner loop. Fixes: - uae_quit(): add set_special(SPCFLAG_MODE_CHANGE) to force the CPU loop to break out of run_func() - m68k_go(): move quit_program check to TOP of the for(;;) loop, before run_func() call, so quit is detected immediately - console_get(): remove infinite for(;;) loop that blocked the UAE thread when no console command was available - UaeServerThread::destroy(): call uae_quit() before sending console quit command, add m_isDestroying flag - popConsoleCmdWait(): change timeout from 100ms to 0ms (non-blocking poll) to prevent blocking during shutdown
- qsr_main.cpp: wrap CLI11 parse in try/catch to handle --help and invalid arguments gracefully instead of crashing - qsr_main_wnd_client_app.cpp: use SDL_GetRendererOutputSize() instead of SDL_GetWindowSize() to get correct pixel dimensions on HiDPI and Retina displays - drawing.cpp: add null check for amiga2aspect_line_map before dereferencing in draw_frame2 render loop - fnvHash.h: add missing #include <cstddef> for size_t used in hash function signatures
- CMakeLists.txt: remove -Werror from GCC and Clang blocks to prevent build failures from warnings in vAmiga's upstream code - FSStorage.cpp: replace std::ranges::sort with std::sort for broader compiler support (std::ranges requires full C++20 library support)
- Skip render entirely when no new frame from emulator - Prevents black frame flicker between emulator frames
… + span overrun fix - Add -force_load (macOS) and --whole-archive (Linux) for amDebugger static library so TS_BEGIN_REFLECT_CLASS auto-registered debugger windows (Blitter, Console, Copper, Registers, Memory, Screen, etc.) are not stripped by the linker. Previously only MSVC WHOLEARCHIVE was configured. - Fix off-by-one buffer overrun in createPredefinedShortcuts: span was sized with EId::MAX_COUNT (13) but g_shortcuts_list only has 12 entries. On ARM64 the garbage function pointer caused SIGBUS.
Add POSIX sigaction handler (macOS/Linux) and SEH handler (Windows) that captures signal info, registers, and backtrace on SIGSEGV/SIGABRT. Writes crash log to /tmp/quaesar_crash_*.log for post-mortem debugging. - crashhandler.h/cpp: platform detection and install API - crashhandler_macos.cpp: POSIX sigaction + backtrace_symbols - crashhandler_linux.cpp: same with Linux-specific signal codes - crashhandler_windows.cpp: SEH exception filter + StackWalk64 - Integrated via installCrashHandler() in qsr_main.cpp - CMakeLists.txt: added crashhandler sources to quaesar-dbg target
The createWindowCb_ template expects UiViewCreateCtx* but was receiving a copy by value, causing the callback to interpret stack garbage as a pointer. This corrupted the ui member in all debugger windows, leading to crashes when activating the debugger (Shift+F12).
…Timing) Copper (Gaps 4.1-4.2): - fetch() caches agnus.copper.getInfo() into m_copInfo - getCopperAddr() returns cop1lc/cop2lc/coppc0 from cached CopperInfo Blitter (Gaps 4.3-4.4): - isBlitterActive() queries agnus.blitter.getInfo().bbusy - getScreenPixBuf() returns VAmServerThread display buffer Floppy (Gaps 5.1-5.4): - getEnabled() reads df[n]->getConfig().connected - setEnabled() uses emu->set(Opt::DRIVE_CONNECT, ...) - getAdfPath()/setAdfPath() track path and insert/eject disk - getWriteProtect()/setWriteProtect() use DiskFlags::PROTECTED Timing (Gaps 6.1-6.5): - getVPos()/getHPos() read amiga.getInfo() vpos/hpos - getCurCycle() returns horizontal position as cycle count - isDebugActivated() checks isPaused() - isDebugActivatedFull() checks isPaused() && debug mode
Build default dock layout programmatically on first frame when no existing layout is loaded from ini. Places Disassembly, Registers, Screen, Memory, Console and other windows in a sensible arrangement.
- Add 15 FPS frame throttling to reduce excessive refresh rate - Fix disassembly table empty on init when nReqLine is -1 (cast to size_t overflow) - Skip ImGui frames when window is hidden or throttled
- Scale frame preview to fit window while preserving aspect ratio - GPU-accelerated scaling via SDL texture linear filtering - Force redraw during window resize via SDL event watcher - Show placeholder frame during resize to avoid distortion - Scale VPos/HPos indicator lines accordingly - Remove unnecessary scrollbar from screen widget
- Scale frame preview to fit window while preserving aspect ratio - GPU-accelerated scaling via SDL texture linear filtering - Force redraw during window resize via SDL event watcher - Show placeholder frame during resize to avoid distortion - Scale VPos/HPos indicator lines accordingly - Remove unnecessary scrollbar from screen widget
- Change DockingEmptyBg from red to dark gray - Clear framebuffer to gray on window creation and show - Defer menu/toolbar drawing until fully initialized - Add m_bFullyInitialized flag to avoid layout jumps during init
- Save layout to debugger_layout.ini on window close and app exit - Load saved layout on startup with explicit LoadIniSettingsFromDisk - Fallback to default layout if ini missing/empty/invalid (check on 2nd frame)
…into dbg-render-fix
- Draw toolbar before DockSpace to position it at top - Add NoScrollbar flag to prevent viewport scrollbar - Defer layout settings load until after GUI creation for proper tab restore
- Fix popConsoleCmdWait to use blocking wait() instead of non-blocking wait(0), which caused debug_1() to return immediately instead of blocking the emulation loop - Route step/continue commands via execConsoleCmd() when UAE debugger is active (debugger_active check), bypassing the stalled ops queue - Use activate_debugger_new_pc(0, 0xFFFFFFFF) to enter UAE's native debug_1() blocking console loop for pause - Mirror debug mode to dummy VM in forwarding callback for correct menu enable/disable state - Forward operations via DebuggerDesktop instead of Debugger to reach forwardOpToEmulator callback - Gate step/trace menu items on debugMode.isBreak() so they're only enabled when paused - Add null guards for pUae in UaeVmImp operation handlers - Add CONFIGURE_DEPENDS to file(GLOB) in amDebugger and qd CMakeLists with explanatory comments for reliable incremental builds - Add PauseEmulation operation and Ctrl+F8 shortcut
…n host mounted volume
…debugger Both the main window and debugger renderers had SDL_RENDERER_PRESENTVSYNC. Since the main loop renders both windows in one iteration, each iteration blocked on two independent vsync waits (~33ms at 60Hz), halving the effective frame rate to 30fps and starving the debugger screen preview. Now only the main window renderer has vsync (the sole vsync authority). The debugger renderer uses SDL_RENDERER_ACCELERATED only — its RenderPresent returns immediately. Also removes the manual 15fps rate limiter (kMinFrameIntervalMs=66ms) that was masking the vsync problem. The main window's vsync already paces the loop correctly.
The debugger starts with a dummy UaeVmImp (m_pUaeThread=nullptr) that cannot access the real emulator framebuffer. Previously this dummy instance was never replaced, causing the debugger screen preview to read from a dummy connection that returned no data. Now QuaesarApplication::onFrameUpdate() eagerly swaps the debugger's VM bridge to the real UaeVmImp every frame until it succeeds. Once the real VM is wired, the debugger reads the actual emulator framebuffer snapshot via getScreenPixBuf().
Adds comment explaining that write_log() routes through SDL_LogMessageV which triggers NSLog on macOS — extremely expensive (CoreFoundation + mutex + kdebug_trace syscall). The emulator generates thousands of log lines per second during boot, burning a full CPU core.
- ui_render_optimization.md: 10 sections covering pixel copy analysis, Metal buffer churn, texture inventory, frame-transport call graph, screen path consolidation, and multi-window vsync pacing - profiling_hotspots.md: post-vsync-fix profile data with emulator thread dominance (91.3%), _platform_memmove hot-spot, and three-copy pipeline analysis - timing_architecture_analysis.md: UAE timing architecture deficiency analysis showing show_screen()/framewait() spin loop behavior
All debugger widgets (registers, disassembly, memory, custom regs, screen preview) now refresh in lockstep through a single ~15fps tick on fetchVmState() in DebuggerApp::updateAppPart(). No per-widget flags or timers — between ticks every widget reads the same stale module caches. Key changes: - Add Cpu::fetch() override to snapshot all registers (D/A/PC/flags/intmask) so getters return stable values between fetches instead of reading the live UAE ::regs global which changes every instruction - Gate fetchVmState() on 66ms wall-clock interval (~15fps) - ImGui frame always renders at full loop rate; skipping RenderPresent on macOS Metal causes an implicit vsync stall that halves the FPS - Remove dead getFrameNo() from IVm::Blitter interface and both backends (UAE + vAmiga) — was unused after removing ScreenWnd frame-skip logic - Remove dead m_lastRenderedFrameNo from ScreenWnd
The main window skipped SDL_RenderPresent entirely when no new emulator frame existed (curFrame == m_renderedFrameNo). On macOS Metal, presenting without any preceding draw commands (RenderClear/RenderCopy) shows black, and skipping Present for 3+ vsync cycles causes CAMetalLayer to recycle its drawable. Fix: always run RenderClear + RenderCopy (using cached texture and dst rect from last frame) + RenderPresent. Only the texture upload (memcpy) is gated on new frames. The STREAMING texture retains pixel data between frames so RenderCopy redraws the correct last frame. Also fixes a pre-existing mutex deadlock: the old early return on zero bufWidth/bufHeight skipped unlockDisplayTexBuf(), permanently locking the display texture mutex and stalling the emulator thread.
Replaces tryLock with lock for emulator framebuffer access, and only marks the frame as rendered upon successful upload. This resolves the issue where a concurrent render lock by the emulator thread caused the UI thread to permanently skip uploading frames, resulting in micro-stutters during smooth scrolling.
Adds an SDL event watch to force window rendering while the main thread is blocked inside the OS modal resize loop (fixing the appearance of a paused emulator). Replaces the hardcoded frame delta with dynamic m_lastTick calculation shared with the main loop. Implements a 15ms rendering rate-limit inside the event watch to prevent vsync blocking from throttling the OS window manager's high-frequency resize events, which was causing choppy dragging.
- Added OS introspector to scan ExecBase and ROM tags. - Created OS Modules UI panel to display Libraries and ROM Tags. - Separated Load Base and LVO Base for accurate visualization. - Calculated module sizes from memory boundaries and endSkip. - Added dynamic auto-scanning logic.
- Prevent disassembly view from auto-snapping to PC when free-viewing - Anchor disassembly cleanly to the target address instead of the CPU PC when jumping - Change default behavior to not quit the application when Escape is pressed (to allow emulator to use it/ungrab mouse)
…ngine parameter (uae by default)
…copy, just provide native framebuffer format to SDL and GPU
- Fix shutdown hang: destroy() now sets m_bRequestToQuit directly and
calls powerOff() to stop vAmiga's internal thread, instead of using
execConsoleCmd("q") which was never read by the thread loop
- Fix resource leak: halt vAmiga and delete m_pVAmiga/m_pVm in the
thread function after the loop exits (was created with new but never
deleted), guarded against ROM load failure early-exit path
- Zero-copy pixel format: replace per-pixel CPU R/B swap with plain
memcpy scanline copy. SDL textures now use ABGR8888 (matching vAmiga's
native format) so the GPU handles channel conversion for free.
Override getDisplayPixelFormat()/getScreenPixelFormat() to return
SDL_PIXELFORMAT_ABGR8888
vAmiga could not boot from large VHD files (e.g. 30GB OS 3.2.3). Three root causes were identified and fixed: 1. Memory limitation: Large disk images were fully loaded into RAM via Buffer<u8>. Added initFileBacked() using std::fstream for on-demand sector I/O, reading only headers for RDB parsing. 2. Incorrect partition geometry: HdController::processInit() reported RDB-level geometry (255 heads, 63 sectors) instead of partition-level DOS Envec values (1 head, 16064 sectors/track). This caused AmigaOS to compute partition offsets 1024 bytes too high, missing boot blocks. 3. Missing de_SectorPerBlock: The DOS Envec field was hardcoded to 1 instead of being parsed from the RDB. With de_SectorPerBlock=8 the filesystem uses 4096-byte blocks; AmigaOS was reading 512-byte blocks, causing checksum failures and 'Not a DOS disk' errors. Additional fixes: - Parse actual partition names from RDB (e.g. GDH0 instead of DH0) - Report all DOS Envec values (numBuffers, bufMemType, maxTransfer, etc.) - Add .VHD/.IMG/.RAW extension support to HDFFile - Bypass oversized-disk rejection via HDR_ACCEPT_ALL debug flag - Skip empty mountconfig entries in config bridge - Connect HdController Zorro board for non-slot-0 drives via HDC_CONNECT - Queue hardReset after attaching drives for proper autoconf discovery - Add uae_lib dependency to VAmigaImpLib for config bridge - Add exter_int_helper case 7 for native2amiga trap callback
The vAmiga server thread's applySdlEventProc had completely empty event handling — no mouse events were forwarded to the vAmiga engine. Added SDL_MOUSEMOTION handling via controlPort1.mouse.setDxDy() and SDL_MOUSEBUTTONDOWN/UP handling via controlPort1.mouse.trigger() with appropriate GamePadAction values.
…tizen vAmiga server thread had empty SDL event handling and no CLI input support: 1. Keyboard: Added SDL scancode → Amiga raw keycode translation table (100+ entries covering all standard keys, numpad, modifiers, arrows) and SDL_KEYDOWN/UP forwarding to keyboard.press()/release(). 2. Floppy: Added g_cfg_startup.input handling — ADF/IMG/DMS files are inserted into df0 via df0.insert() on startup, matching UAE behavior. 3. Serial port: Documented as N/A — vAmiga uses internal serial devices (NULLMODEM, LOOPBACK), not host serial paths like UAE. With these changes vAmiga boots to Workbench from floppy, same as UAE.
Audio (va_server_thread): - SDL callback-mode audio device pulling F32 stereo from AudioPortAPI - Use copyStereo to feed SampleRateDetector for ASR correction - Set HOST_SAMPLE_RATE=44100, AUD_BUFFER_SIZE=8192, AUD_SAMPLING_METHOD=LINEAR - Fixes buttery smooth audio without stutter Input/features: - Drag-and-drop ADF/IMG/DMS mounting into df0 with auto-reboot - Ctrl+R global reboot hotkey via SDL_KEYDOWN handler (works without GUI) - Ctrl+R shortcut binding in shortcutsList.h for GUI overlay mode
…hing vAmiga's internal thread sleeps with a 50ms timeout between frames. Previously wakeUp() was only called when a new frame was detected, so when the emulator found 0 missing frames it went back to sleep without being woken again until its 50ms timeout fired. This caused it to batch-produce 2-3 frames per cycle, with our loop only catching the latest — effectively halving the visible frame rate to ~25fps. Fix: call wakeUp() unconditionally on every poll iteration, and reduce SDL_Delay from 5ms to 2ms for faster polling. This keeps missingFrames() evaluating at ~500Hz, producing exactly one frame per 20ms (50Hz) cadence.
…changes Remove three audio disruption paths in UAE core: - audio_reset(): remove reset_sound() that wiped output buffer on every hard/soft reset (caused ~40-60ms gap) - audio_deactivate(): remove pause_sound_buffer() on CPU halt so audio drains naturally instead of hard-stopping - Forced idle hack: lower threshold from 10 to 2 CYCLE_UNIT to prevent spurious channel resets in demos - graphics_leave(): remove redundant reset_sound() (close_sound() in do_leave_program handles shutdown) Also includes vAmiga DSKBYTR assertion fix and floppy mount fix: - DiskControllerRegs.cpp: replace assert(clock>=syncCycle) with safe if - FloppyDrive: eject existing disk before insert to avoid swap delay race with hard reset wiping Agnus event
…riant hoisting Replace per-pixel switch statement in HAM decode with table-driven branchless code using keep_mask/shift lookup tables. The mode ternary compiles to CMOV (x86) / CSEL (ARM), eliminating data-dependent branch mispredictions. Hoist invariant checks (bplham, aga_mode, bplplanecnt, bpldualpf) outside the pixel loop, producing 5 specialized inner loops dispatched once per call instead of re-tested per pixel. Profiling shows ~1-2 ticks/frame in release builds (was ~8-12 ticks/line), confirming HAM decode is no longer a measurable bottleneck.
…and resilience fixes Replace wall-clock frame timing with audio-callback-driven sync via SDL semaphore. The audio callback posts the semaphore at exactly 50Hz (PAL) or 60Hz (NTSC), locked to the sound card crystal oscillator for sub-frame precision. Key changes: - audio_callback_sync_wait_ms(): blocks on semaphore posted by the SDL audio callback, with 20ms timeout safety net. Falls back to wall-clock spin loop when audio is unavailable. - sdl2_audio_callback(): corrected to copy min(len, pullbufferlen) bytes and fill remainder with silence on underrun. Rate-limits semaphore posts to one per emulated frame via post_frame_sync_if_needed(). - finish_sound_buffer_pull(): handles overflow by resetting buffer and logging (AUDIO PULL OVERFLOW only). - framewait(): uses audio semaphore as primary pacing when cpu_thread is disabled, with wall-clock fallback preserved. - Remove all temporary frame over-budget diagnostics (phase timers, host CPU measurement, blitter/instruction counters). - Remove audio underrun periodic logging (keep overflow error only). - Add rate-limited AUDIO RESET/AUDIO DEACTIVATE/AUDIO prefs changed logging in audio.cpp. - Fix filesys.cpp UAE_TRAP_FUNC build error (removed dead code). - Minor vAmiga config and va_server_thread changes.
Replace fseeko64/fread with mmap (MAP_SHARED, PROT_READ, MADV_RANDOM) for hardfile I/O on POSIX platforms. The entire file is mapped into virtual address space and reads become direct memcpy from mapped pages. This eliminates the synchronous seek+read bottleneck during WHDLoad part transitions, where FFS reads hundreds of scattered 512-byte blocks from a 30GB VHD. Previously each block caused a cache-miss seek+16KB fread cycle (1-10ms each). With mmap, cached pages are ~microseconds and the OS page cache handles demand paging transparently. - mmap on hdf_open_target(), munmap on hdf_close_target() - Fast path in hdf_read_2() and hdf_read_target() bypasses cache loop - fflush after fwrite ensures MAP_SHARED consistency - hdf_resize_target() remaps to new size - Graceful fallback to fread if mmap fails (NULL check) - Cross-platform: Windows uses separate hardfile_win32.cpp
…builds Replace unconditional bin2c execute_process with a change-detection guard that only regenerates resources_inc.cpp when: - A resource file's mtime is newer than the output, OR - The resource list itself changed (added/removed/renamed files) Previously, every CMake re-configure (triggered by CONFIGURE_DEPENDS) regenerated resources_inc.cpp unconditionally, causing a full rebuild cascade on every incremental build.
Move 7 implemented/superseded design docs to doc/archive/: - ham_rendering_optimization (Phase 1 committed) - hunk_launcher_design (implemented) - inject_via_ramdisk (implemented) - profiling_hotspots (one-time analysis, completed) - timing_architecture_analysis (frame timing work done) - ui_render_optimization (one-time analysis, completed) - Runtime_Core_Switching (core switching implemented) Active designs remain in doc/: bsdsocket, snapshot, task_control, memory_tracker, uae-drawing-decomposition, user_guide
Analysis of the 5535-line monolithic drawing.cpp covering playfields, sprites, HAM, genlock, palette, and line drawing logic. Identifies module boundaries for potential future decomposition.
- Add MinGW SDL2 support via find_package and proper library linking - Fix crashhandler Windows include order (windows.h before dbghelp.h) - Wrap mmap/munmap calls with #ifndef _WIN32 for Windows compatibility - Fix undefined behavior in union initialization (float.h, Color.h) - Add matching operator new to RefCounted to fix mismatched new/delete warning - Fix EASTL tuple.h tautological compare warning - Add [[maybe_unused]] to g_shortcuts_list to suppress unused variable warning - Fix cfgfile_searchconfig bounds check for empty input strings - Remove hardcoded NDEBUG from ADFlib source files (CMake handles this) - Guard GCC-specific pragmas with compiler checks for cross-platform compatibility - Fix calc.cpp switch on high-bit TCHAR operators with proper cast - Add ws2_32 library linking for network functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tested on Windows (MSVC2019), MacOS (clang) and Linux (GCC 15)