From 643a4313868afebb539ac52a8a03345e45092dfe Mon Sep 17 00:00:00 2001 From: Aaron Culliney Date: Sun, 11 Jan 2015 12:27:39 -0800 Subject: [PATCH] first cut at auto fast-loading of disk images - automatically adjusts cpu timing to fastest if drive motor accessed recently and no audio/video - TODO: audio output clipping issue when (un)pausing audio outpu --- src/display.c | 17 +++++++++++++++++ src/timing.c | 34 ++++++++++++++++++++++++++++++---- src/timing.h | 1 + src/video/glvideo.c | 4 ++++ src/video/video.h | 5 +++++ 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/display.c b/src/display.c index 6347074f..3252d675 100644 --- a/src/display.c +++ b/src/display.c @@ -53,6 +53,8 @@ static uint8_t video__int_font[3][0x4000]; int video__current_page; // current visual page int video__strictcolors = 1;// refactor : should be static +extern volatile bool _vid_dirty; + // Video constants -- sourced from AppleWin static const bool bVideoScannerNTSC = true; static const int kHBurstClock = 53; // clock when Color Burst starts @@ -571,6 +573,7 @@ static inline void _plot_lores(uint8_t **d, const uint32_t val) { #ifdef INTERFACE_CLASSIC void video_plotchar( int x, int y, int scheme, uint8_t c ) { + _vid_dirty = true; uint8_t *d; uint8_t *s; @@ -653,11 +656,13 @@ static inline void _plot_character(const unsigned int font_off, uint8_t *fb_ptr) static inline void _plot_character0(uint16_t ea, uint8_t b) { + _vid_dirty = (video__current_page == 0); _plot_character(b<<7/* *128 */, video__fb1+video__screen_addresses[ea-0x0400]); } static inline void _plot_character1(uint16_t ea, uint8_t b) { + _vid_dirty = (video__current_page == 1); _plot_character(b<<7/* *128 */, video__fb2+video__screen_addresses[ea-0x0800]); } @@ -676,6 +681,7 @@ static inline void _plot_80character(const unsigned int font_off, uint8_t *fb_pt // FIXME TODO NOTE : dup'ing work here? static inline void _plot_80character0(uint16_t ea, uint8_t b) { + _vid_dirty = (video__current_page == 0); b = apple_ii_64k[1][ea]; _plot_80character(b<<6/* *64 */, video__fb1+video__screen_addresses[ea-0x0400]); b = apple_ii_64k[0][ea]; @@ -684,6 +690,7 @@ static inline void _plot_80character0(uint16_t ea, uint8_t b) static inline void _plot_80character1(uint16_t ea, uint8_t b) { + _vid_dirty = (video__current_page == 1); b = apple_ii_64k[1][ea]; _plot_80character(b<<6/* *64 */, video__fb2+video__screen_addresses[ea-0x0800]); b = apple_ii_64k[0][ea]; @@ -718,11 +725,13 @@ static inline void _plot_block(const uint32_t val, uint8_t *fb_ptr) { /* plot lores block first page */ static inline void _plot_block0(uint16_t ea, uint8_t b) { + _vid_dirty = (video__current_page == 0); _plot_block(b, video__fb1+video__screen_addresses[ea-0x0400]); } static inline void _plot_block1(uint16_t ea, uint8_t b) { + _vid_dirty = (video__current_page == 1); _plot_block(b, video__fb2+video__screen_addresses[ea-0x0800]); } @@ -803,6 +812,7 @@ static inline void _plot_dhires_pixels(uint8_t idx, uint8_t *fb_ptr) { // PlotDHires static inline void _plot_dhires(uint16_t base, uint16_t ea, uint8_t *fb_base) { + _vid_dirty = true; ea &= ~0x1; uint16_t memoff = ea - base; @@ -927,6 +937,7 @@ static inline void _plot_hires_pixels(uint8_t *dst, const uint8_t *src) { // PlotByte static inline void _plot_hires(uint16_t ea, uint8_t b, bool is_even, uint8_t *fb_ptr) { + uint8_t _buf[DYNAMIC_SZ] = { 0 }; uint8_t *color_buf = (uint8_t *)_buf; // <--- work around for -Wstrict-aliasing uint8_t *apple2_vmem = (uint8_t *)apple_ii_64k[0]; @@ -1025,8 +1036,10 @@ static inline void _draw_hires_graphics(uint16_t ea, uint8_t b, bool is_even, ui uint8_t *fb_base = NULL; if (page) { off -= 0x2000; + _vid_dirty = (video__current_page == 1); fb_base = video__fb2; } else { + _vid_dirty = (video__current_page == 0); fb_base = video__fb1; } _plot_hires(ea, b, is_even, fb_base+video__screen_addresses[off]); @@ -1080,6 +1093,10 @@ GLUE_C_WRITE(video__write_2e_odd1_mixed) _draw_hires_graphics(ea, b, /*even*/false, 1, (SS_TEXT|SS_MIXED)); } +bool video_dirty(void) { + return _vid_dirty; +} + void video_redraw(void) { // temporarily reset softswitches diff --git a/src/timing.c b/src/timing.c index bb50f813..c3280443 100644 --- a/src/timing.c +++ b/src/timing.c @@ -47,6 +47,7 @@ static bool alt_speed_enabled = false; double cpu_scale_factor = 1.0; double cpu_altscale_factor = 1.0; +bool auto_adjust_speed = true; int gc_cycles_timer_0 = 0; int gc_cycles_timer_1 = 0; @@ -54,7 +55,7 @@ int gc_cycles_timer_1 = 0; volatile uint8_t emul_reinitialize = 0; pthread_t cpu_thread_id = 0; -static unsigned int g_nCyclesExecuted; // # of cycles executed up to last IO access +static unsigned int g_nCyclesExecuted = 0; // # of cycles executed up to last IO access // ----------------------------------------------------------------------------- @@ -245,21 +246,24 @@ void *cpu_thread(void *dummyptr) { #if DEBUG_TIMING dbg_cycles_executed += cpu65_cycle_count; #endif -#ifdef AUDIO_ENABLED unsigned int uActualCyclesExecuted = cpu65_cycle_count; g_dwCyclesThisFrame += uActualCyclesExecuted; +#ifdef AUDIO_ENABLED MB_UpdateCycles(uActualCyclesExecuted); // Update 6522s (NB. Do this before updating g_nCumulativeCycles below) +#endif // N.B.: IO calls that depend on accurate timing will update g_nCyclesExecuted - const unsigned int nRemainingCycles = uActualCyclesExecuted - g_nCyclesExecuted; + const int nRemainingCycles = uActualCyclesExecuted - g_nCyclesExecuted; + assert(nRemainingCycles >= 0); g_nCumulativeCycles += nRemainingCycles; if (!g_bFullSpeed) { +#ifdef AUDIO_ENABLED SpkrUpdate(uActualCyclesExecuted); // play audio - } #endif + } if (g_dwCyclesThisFrame >= dwClksPerFrame) { @@ -274,6 +278,28 @@ void *cpu_thread(void *dummyptr) { pthread_mutex_unlock(&interface_mutex); // -UNLOCK--------------------------------------------------------------------------------------- SAMPLE tj + if (auto_adjust_speed) { + deltat = timespec_diff(disk6.motor_time, tj, &negative); + assert(!negative); + if (!g_bFullSpeed && +#ifdef AUDIO_ENABLED + !Spkr_IsActive() && +#endif + !video_dirty() && (!disk6.motor_off && (deltat.tv_sec || deltat.tv_nsec > DISK_MOTOR_QUIET_NSECS)) ) + { + TIMING_LOG("auto switching to full speed"); + _switch_to_fullspeed(); + } else if (g_bFullSpeed && ( +#ifdef AUDIO_ENABLED + Spkr_IsActive() || +#endif + video_dirty() || (disk6.motor_off && (deltat.tv_sec || deltat.tv_nsec > DISK_MOTOR_QUIET_NSECS))) ) + { + TIMING_LOG("auto switching to regular speed"); + _switch_to_regular_speed(alt_speed_enabled ? cpu_altscale_factor : cpu_scale_factor); + } + } + if (!g_bFullSpeed) { deltat = timespec_diff(ti, tj, &negative); assert(!negative); diff --git a/src/timing.h b/src/timing.h index 1b60c0bc..c63269ff 100644 --- a/src/timing.h +++ b/src/timing.h @@ -45,6 +45,7 @@ extern int g_nCpuCyclesFeedback; extern double cpu_scale_factor; extern double cpu_altscale_factor; +extern bool auto_adjust_speed; extern pthread_t cpu_thread_id; diff --git a/src/video/glvideo.c b/src/video/glvideo.c index 1036c8c6..04f37aba 100644 --- a/src/video/glvideo.c +++ b/src/video/glvideo.c @@ -34,6 +34,8 @@ enum { bool safe_to_do_opengl_logging = false; +volatile bool _vid_dirty = true; + static int windowWidth = SCANWIDTH*1.5; static int windowHeight = SCANHEIGHT*1.5; @@ -649,6 +651,8 @@ static void gldriver_render(void) { // Draw the CRT object glDrawElements(GL_TRIANGLES, crtNumElements, crtElementType, 0); + _vid_dirty = false; + #if USE_GLUT glutSwapBuffers(); #endif diff --git a/src/video/video.h b/src/video/video.h index b728274b..e8797124 100644 --- a/src/video/video.h +++ b/src/video/video.h @@ -116,6 +116,11 @@ void video_plotchar(int row, int col, int color, uint8_t code); */ const uint8_t * const video_current_framebuffer(); +/* + * True if anything changed in framebuffer and not yet drawn + */ +bool video_dirty(void); + /* * VBL routines */