From 019d9067235eca64d8d725b440502f860be9ca96 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Thu, 16 Jul 2009 19:25:37 +0300 Subject: [PATCH] imported winuaesrc1620b1.zip --- audio.c | 50 +- custom.c | 511 ++++++++----------- debug.c | 93 +++- drawing.c | 8 +- include/debug.h | 1 + include/drawing.h | 3 +- include/options.h | 2 + od-win32/direct3d.c | 10 +- od-win32/resources/resource | 2 + od-win32/resources/winuae.rc | 23 +- od-win32/sounddep/sound.c | 640 ++++++++++++++++++++++-- od-win32/sounddep/sound.h | 42 +- od-win32/win32.c | 40 +- od-win32/win32.h | 5 +- od-win32/win32_scale2x.c | 11 - od-win32/win32gui.c | 39 +- od-win32/winuae_msvc/winuae_msvc.vcproj | 12 +- od-win32/winuaechangelog.txt | 77 ++- 18 files changed, 1081 insertions(+), 488 deletions(-) diff --git a/audio.c b/audio.c index b1b338f8..70bdd30d 100644 --- a/audio.c +++ b/audio.c @@ -29,6 +29,7 @@ #include "zfile.h" #include "uae.h" #include "gui.h" +#include "xwin.h" #ifdef AVIOUTPUT #include "avioutput.h" #endif @@ -554,8 +555,9 @@ static void sample16i_sinc_handler (void) samplexx_sinc_handler (datas); data1 = datas[0] + datas[3] + datas[1] + datas[2]; data1 = FINISH_DATA (data1, 16, 2); + set_sound_buffers (); PUT_SOUND_WORD_MONO (data1); - check_sound_buffers (outputsample, doublesample); + check_sound_buffers (); } void sample16_handler (void) @@ -579,8 +581,9 @@ void sample16_handler (void) data0 += data3; data = SBASEVAL16(2) + data0; data = FINISH_DATA (data, 16, 2); + set_sound_buffers (); PUT_SOUND_WORD_MONO (data); - check_sound_buffers (outputsample, doublesample); + check_sound_buffers (); } /* This interpolator examines sample points when Paula switches the output @@ -592,8 +595,9 @@ static void sample16i_anti_handler (void) samplexx_anti_handler (datas); data1 = datas[0] + datas[3] + datas[1] + datas[2]; data1 = FINISH_DATA (data1, 16, 2); + set_sound_buffers (); PUT_SOUND_WORD_MONO (data1); - check_sound_buffers (outputsample, doublesample); + check_sound_buffers (); } static void sample16i_rh_handler (void) @@ -643,8 +647,9 @@ static void sample16i_rh_handler (void) data0 += (data3 * (256 - ratio) + data3p * ratio) >> 8; data = SBASEVAL16(2) + data0; data = FINISH_DATA (data, 16, 2); + set_sound_buffers (); PUT_SOUND_WORD_MONO (data); - check_sound_buffers (outputsample, doublesample); + check_sound_buffers (); } static void sample16i_crux_handler (void) @@ -714,8 +719,9 @@ static void sample16i_crux_handler (void) data0 += data1; data = SBASEVAL16(2) + data0; data = FINISH_DATA (data, 16, 2); + set_sound_buffers (); PUT_SOUND_WORD_MONO (data); - check_sound_buffers (outputsample, doublesample); + check_sound_buffers (); } #ifdef HAVE_STEREO_SUPPORT @@ -747,13 +753,14 @@ void sample16ss_handler (void) data1 = FINISH_DATA (data1, 16, 0); data2 = FINISH_DATA (data2, 16, 0); data3 = FINISH_DATA (data3, 16, 0); + set_sound_buffers (); put_sound_word_left (data0); put_sound_word_right (data1); if (currprefs.sound_stereo == SND_6CH) make6ch (data0, data1, data2, data3); put_sound_word_left2 (data3); put_sound_word_right2 (data2); - check_sound_buffers (outputsample, doublesample); + check_sound_buffers (); } /* This interpolator examines sample points when Paula switches the output @@ -769,13 +776,14 @@ void sample16ss_anti_handler (void) data1 = FINISH_DATA (datas[1], 16, 0); data2 = FINISH_DATA (datas[2], 16, 0); data3 = FINISH_DATA (datas[3], 16, 0); + set_sound_buffers (); put_sound_word_left (data0); put_sound_word_right (data1); if (currprefs.sound_stereo == SND_6CH) make6ch (data0, data1, data2, data3); put_sound_word_left2 (data3); put_sound_word_right2 (data2); - check_sound_buffers (outputsample, doublesample); + check_sound_buffers (); } static void sample16si_anti_handler (void) @@ -787,9 +795,10 @@ static void sample16si_anti_handler (void) data2 = datas[1] + datas[2]; data1 = FINISH_DATA (data1, 16, 1); data2 = FINISH_DATA (data2, 16, 1); + set_sound_buffers (); put_sound_word_left (data1); put_sound_word_right (data2); - check_sound_buffers (outputsample, doublesample); + check_sound_buffers (); } void sample16ss_sinc_handler (void) @@ -802,13 +811,14 @@ void sample16ss_sinc_handler (void) data1 = FINISH_DATA (datas[1], 16, 0); data2 = FINISH_DATA (datas[2], 16, 0); data3 = FINISH_DATA (datas[3], 16, 0); + set_sound_buffers (); put_sound_word_left (data0); put_sound_word_right (data1); if (currprefs.sound_stereo == SND_6CH) make6ch (data0, data1, data2, data3); put_sound_word_left2 (data3); put_sound_word_right2 (data2); - check_sound_buffers (outputsample, doublesample); + check_sound_buffers (); } static void sample16si_sinc_handler (void) @@ -820,9 +830,10 @@ static void sample16si_sinc_handler (void) data2 = datas[1] + datas[2]; data1 = FINISH_DATA (data1, 16, 1); data2 = FINISH_DATA (data2, 16, 1); + set_sound_buffers (); put_sound_word_left (data1); put_sound_word_right (data2); - check_sound_buffers (outputsample, doublesample); + check_sound_buffers (); } void sample16s_handler (void) @@ -847,9 +858,10 @@ void sample16s_handler (void) data2 = FINISH_DATA (data2, 16, 1); data3 = SBASEVAL16(1) + data1; data3 = FINISH_DATA (data3, 16, 1); + set_sound_buffers (); put_sound_word_left (data2); put_sound_word_right (data3); - check_sound_buffers (outputsample, doublesample); + check_sound_buffers (); } static void sample16si_crux_handler (void) @@ -919,9 +931,10 @@ static void sample16si_crux_handler (void) data2 = FINISH_DATA (data2, 16, 1); data3 = SBASEVAL16(1) + data1; data3 = FINISH_DATA (data3, 16, 1); + set_sound_buffers (); put_sound_word_left (data2); put_sound_word_right (data3); - check_sound_buffers (outputsample, doublesample); + check_sound_buffers (); } static void sample16si_rh_handler (void) @@ -972,9 +985,10 @@ static void sample16si_rh_handler (void) data2 = FINISH_DATA (data2, 16, 1); data3 = SBASEVAL16(1) + data1; data3 = FINISH_DATA (data3, 16, 1); + set_sound_buffers (); put_sound_word_left (data2); put_sound_word_right (data3); - check_sound_buffers (outputsample, doublesample); + check_sound_buffers (); } #else @@ -1287,6 +1301,7 @@ STATIC_INLINE int sound_prefs_changed (void) { if (changed_prefs.produce_sound != currprefs.produce_sound || changed_prefs.win32_soundcard != currprefs.win32_soundcard + || changed_prefs.win32_soundexclusive != currprefs.win32_soundexclusive || changed_prefs.sound_stereo != currprefs.sound_stereo || changed_prefs.sound_maxbsiz != currprefs.sound_maxbsiz || changed_prefs.sound_freq != currprefs.sound_freq @@ -1360,6 +1375,7 @@ void set_audio (void) currprefs.produce_sound = changed_prefs.produce_sound; currprefs.win32_soundcard = changed_prefs.win32_soundcard; + currprefs.win32_soundexclusive = changed_prefs.win32_soundexclusive; currprefs.sound_stereo = changed_prefs.sound_stereo; currprefs.sound_auto = changed_prefs.sound_auto; currprefs.sound_freq = changed_prefs.sound_freq; @@ -1530,7 +1546,7 @@ void update_audio (void) next_sample_evtime += scaled_sample_evtime; doublesample = 0; if (--samplecounter <= 0) { - samplecounter = currprefs.sound_freq / 100; + samplecounter = currprefs.sound_freq / 1000; if (extrasamples > 0) { outputsample = 1; doublesample = 1; @@ -1853,11 +1869,12 @@ uae_u8 *save_audio (int i, int *len, uae_u8 *dstptr) void audio_vsync (void) { +#if 0 int i, max, min; static int lastdir; - min = -5 * 10; - max = 5 * 10; + min = -10 * 10; + max = (isfullscreen () > 0 && currprefs.gfx_avsync) ? 10 * 10 : 20 * 10; extrasamples = 0; if (gui_data.sndbuf < min) { // add extra sample @@ -1881,4 +1898,5 @@ void audio_vsync (void) extrasamples = 10; if (extrasamples < -10) extrasamples = -10; +#endif } diff --git a/custom.c b/custom.c index 2a46ba5a..70144caf 100644 --- a/custom.c +++ b/custom.c @@ -55,17 +55,14 @@ #define SPRITE_DEBUG 0 #define SPRITE_DEBUG_MINY 0xb0 #define SPRITE_DEBUG_MAXY 0xf8 -#ifdef NEWHSYNC -#define SPR0_HPOS 0x19 -#else #define SPR0_HPOS 0x15 -#endif #define MAX_SPRITES 8 #define SPRITE_COLLISIONS #define SPEEDUP #define AUTOSCALE_SPRITES 1 #define NEW_BPL 1 +#define NEW_BPLX 0 #define SPRBORDER 0 @@ -227,6 +224,7 @@ uae_u8 cycle_line[256]; #endif static uae_u16 bplxdat[8]; +static int bpl1dat_written; static uae_s16 bpl1mod, bpl2mod; static uaecptr prevbpl[2][MAXVPOS][8]; static uaecptr bplpt[8], bplptx[8], f_bplpt[8]; @@ -237,11 +235,12 @@ int bpl_off[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; static struct color_entry current_colors; static unsigned int bplcon0, bplcon1, bplcon2, bplcon3, bplcon4; -static unsigned int ta_bplcon0_res, td_bplcon0_res, t_bplcon0_planes, t_bplcon0_planes_limit; +static unsigned int bplcon0d, bplcon0_res, bplcon0_planes, bplcon0_planes_limit; static unsigned int diwstrt, diwstop, diwhigh; static int diwhigh_written; static unsigned int ddfstrt, ddfstop, ddfstrt_old_hpos, ddfstrt_old_vpos; static int ddf_change, badmode; +static int fmode; /* The display and data fetch windows */ @@ -300,14 +299,6 @@ struct copper { static struct copper cop_state; static int copper_enabled_thisline; static int cop_min_waittime; - -static uae_u16 f_bplcon0, f_fmode; -static int fa_bplcon0_res, fd_bplcon0_res, f_bplcon0_planes, f_bplcon0_planes_limit; -static int f_fetchunit, f_fetchunit_mask; -static int f_fetchstart, f_fetchstart_mask, f_fetchstart_shift; -static int f_fm_maxplane_shift, f_fm_maxplane; -static int f_fetch_modulo_cycle, f_fetchmode; - /* * Statistics */ @@ -364,7 +355,7 @@ static uae_u32 thisline_changed; #endif static struct decision thisline_decision; -static int fetch_cycle; +static int fetch_cycle, fetch_modulo_cycle; enum plfstate { @@ -388,7 +379,7 @@ enum fetchstate { STATIC_INLINE int ecsshres(void) { - return fd_bplcon0_res == RES_SUPERHIRES && (currprefs.chipset_mask & CSMASK_ECS_DENISE) && !(currprefs.chipset_mask & CSMASK_AGA); + return bplcon0_res == RES_SUPERHIRES && (currprefs.chipset_mask & CSMASK_ECS_DENISE) && !(currprefs.chipset_mask & CSMASK_AGA); } STATIC_INLINE int nodraw (void) @@ -601,23 +592,18 @@ STATIC_INLINE int GET_PLANES_LIMIT (uae_u16 bc0) { int res = GET_RES_AGNUS (bc0); int planes = GET_PLANES (bc0); - return real_bitplane_number[f_fetchmode][res][planes]; + return real_bitplane_number[fetchmode][res][planes]; } -#ifdef NEWHSYNC -#define HARD_DDF_STOP 0xd8 -#define HARD_DDF_START 0x18 -#else /* The HRM says 0xD8, but that can't work... */ #define HARD_DDF_STOP 0xd4 #define HARD_DDF_START 0x18 -#endif static void add_modulos (void) { int m1, m2; - if (f_fmode & 0x4000) { + if (fmode & 0x4000) { if (((diwstrt >> 8) ^ vpos) & 1) m1 = m2 = bpl2mod; else @@ -627,7 +613,7 @@ static void add_modulos (void) m2 = bpl2mod; } - switch (f_bplcon0_planes_limit) { + switch (bplcon0_planes_limit) { #ifdef AGA case 8: bplpt[7] += m2; bplptx[7] += m2; case 7: bplpt[6] += m1; bplptx[6] += m1; @@ -668,18 +654,18 @@ static void finish_playfield_line (void) are contained in an indivisible block during which ddf is active. E.g. if DDF starts at 0x30, and fetchunit is 8, then possible DDF stops are 0x30 + n * 8. */ -static int t_fetchunit, t_fetchunit_mask; +static int fetchunit, fetchunit_mask; /* The delay before fetching the same bitplane again. Can be larger than the number of bitplanes; in that case there are additional empty cycles with no data fetch (this happens for high fetchmodes and low resolutions). */ -static int t_fetchstart, t_fetchstart_shift, t_fetchstart_mask; +static int fetchstart, fetchstart_shift, fetchstart_mask; /* fm_maxplane holds the maximum number of planes possible with the current fetch mode. This selects the cycle diagram: 8 planes: 73516240 4 planes: 3120 2 planes: 10. */ -static int f_fm_maxplane, f_fm_maxplane_shift; +static int fm_maxplane, fm_maxplane_shift; /* The corresponding values, by fetchmode and display resolution. */ static const int fetchunits[] = { 8,8,8,0, 16,8,8,0, 32,16,8,0 }; @@ -689,7 +675,7 @@ static const int fm_maxplanes[] = { 3,2,1,0, 3,3,2,0, 3,3,3,0 }; static int cycle_diagram_table[3][3][9][32]; static int cycle_diagram_free_cycles[3][3][9]; static int cycle_diagram_total_cycles[3][3][9]; -static int *curr_diagram, curr_diagram_change; +static int *curr_diagram; static const int cycle_sequences[3 * 8] = { 2,1,2,1,2,1,2,1, 4,2,3,1,4,2,3,1, 8,4,6,2,7,3,5,1 }; static void debug_cycle_diagram (void) @@ -766,21 +752,21 @@ static int cycle_diagram_shift; static void estimate_last_fetch_cycle (int hpos) { - int fetchunit = fetchunits[f_fetchmode * 4 + fa_bplcon0_res]; + int fetchunit = fetchunits[fetchmode * 4 + bplcon0_res]; if (plfstate < plf_passed_stop) { int stop = plfstop < hpos || plfstop > HARD_DDF_STOP ? HARD_DDF_STOP : plfstop; /* We know that fetching is up-to-date up until hpos, so we can use fetch_cycle. */ int fetch_cycle_at_stop = fetch_cycle + (stop - hpos); - int starting_last_block_at = (fetch_cycle_at_stop + f_fetchunit - 1) & ~(f_fetchunit - 1); + int starting_last_block_at = (fetch_cycle_at_stop + fetchunit - 1) & ~(fetchunit - 1); - estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + f_fetchunit; + estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit; } else { - int starting_last_block_at = (fetch_cycle + f_fetchunit - 1) & ~(f_fetchunit - 1); + int starting_last_block_at = (fetch_cycle + fetchunit - 1) & ~(fetchunit - 1); if (plfstate == plf_passed_stop2) starting_last_block_at -= fetchunit; - estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + f_fetchunit; + estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit; } } @@ -810,12 +796,7 @@ static int delayoffset; STATIC_INLINE void compute_delay_offset (void) { -#ifdef NEWHSYNC - int v = 4; -#else - int v = 0; -#endif - delayoffset = (16 << f_fetchmode) - (((plfstrt - v - HARD_DDF_START) & f_fetchstart_mask) << 1); + delayoffset = (16 << fetchmode) - (((plfstrt - HARD_DDF_START) & fetchstart_mask) << 1); #if 0 /* maybe we can finally get rid of this stupid table.. */ if (tmp == 4) @@ -846,75 +827,51 @@ static void record_color_change2 (int hpos, int regno, unsigned long value) curr_color_changes[next_color_change].regno = -1; } -// OCS/ECS, lores, 7 planes = 4 "real" planes + BPL5DAT and BPL6DAT as 5th and 6th plane -STATIC_INLINE int isocs7planes (void) +static int isehb (uae_u16 bplcon0, uae_u16 bplcon2) { - return !(currprefs.chipset_mask & CSMASK_AGA) && fa_bplcon0_res == 0 && f_bplcon0_planes == 7; + int bplehb; + if (currprefs.chipset_mask & CSMASK_AGA) + bplehb = (bplcon0 & 0x7010) == 0x6000; + else if (currprefs.chipset_mask & CSMASK_ECS_DENISE) + bplehb = ((bplcon0 & 0xFC00) == 0x6000 || (bplcon0 & 0xFC00) == 0x7000); + else + bplehb = ((bplcon0 & 0xFC00) == 0x6000 || (bplcon0 & 0xFC00) == 0x7000) && !currprefs.cs_denisenoehb; + return bplehb; } -static uae_u16 tmp_bplcon0, tmp_fmode; -STATIC_INLINE fetch_bpl_params (void) +// OCS/ECS, lores, 7 planes = 4 "real" planes + BPL5DAT and BPL6DAT as 5th and 6th plane +STATIC_INLINE int isocs7planes (void) { - tmp_bplcon0 = bplcon0; - tmp_fmode = fmode; + return !(currprefs.chipset_mask & CSMASK_AGA) && bplcon0_res == 0 && bplcon0_planes == 7; } -static void copy_bpl_params (int pos) -{ - int changed = 0; - int fm; - - if (f_bplcon0 != tmp_bplcon0) - changed = 1; - if (f_fmode != tmp_fmode) - changed = 1; - - if (changed) - record_color_change2 (pos + 4, 0x100 + 0x1000, tmp_bplcon0); - f_bplcon0 = tmp_bplcon0; - f_fmode = tmp_fmode; - fm = fmode & 3; - if (fm == 0) - f_fetchmode = 0; - else if (fm == 1 || fm == 2) - f_fetchmode = 1; - else - f_fetchmode = 2; - fa_bplcon0_res = GET_RES_AGNUS (f_bplcon0); - fd_bplcon0_res = GET_RES_DENISE (f_bplcon0); - f_bplcon0_planes = GET_PLANES (f_bplcon0); - f_bplcon0_planes_limit = GET_PLANES_LIMIT (f_bplcon0); - f_fetchunit = fetchunits[fetchmode * 4 + fa_bplcon0_res]; - f_fetchunit_mask = t_fetchunit - 1; - f_fetchstart_shift = fetchstarts[f_fetchmode * 4 + fa_bplcon0_res]; - f_fetchstart = 1 << t_fetchstart_shift; - f_fetchstart_mask = t_fetchstart - 1; - f_fm_maxplane_shift = fm_maxplanes[f_fetchmode * 4 + fa_bplcon0_res]; - f_fm_maxplane = 1 << f_fm_maxplane_shift; - curr_diagram = cycle_diagram_table[f_fetchmode][fa_bplcon0_res][f_bplcon0_planes_limit]; - f_fetch_modulo_cycle = t_fetchunit - f_fetchstart; - if (toscr_nr_planes < f_bplcon0_planes_limit) - toscr_nr_planes = f_bplcon0_planes_limit; +static void update_denise (int hpos) +{ + toscr_res = GET_RES_DENISE (bplcon0d); + record_color_change2 (hpos, 0x100 + 0x1000, bplcon0d); + toscr_nr_planes = GET_PLANES (bplcon0d); if (isocs7planes ()) { if (toscr_nr_planes2 < 6) toscr_nr_planes2 = 6; } else { toscr_nr_planes2 = toscr_nr_planes; } - toscr_res = fd_bplcon0_res; } static void expand_fmodes (void) { - ta_bplcon0_res = GET_RES_AGNUS (bplcon0); - td_bplcon0_res = GET_RES_DENISE (bplcon0); - t_bplcon0_planes = GET_PLANES (bplcon0); - t_bplcon0_planes_limit = GET_PLANES_LIMIT (bplcon0); - t_fetchunit = fetchunits[fetchmode * 4 + ta_bplcon0_res]; - t_fetchunit_mask = t_fetchunit - 1; - t_fetchstart_shift = fetchstarts[fetchmode * 4 + ta_bplcon0_res]; - t_fetchstart = 1 << t_fetchstart_shift; - t_fetchstart_mask = t_fetchstart - 1; + bplcon0_res = GET_RES_AGNUS (bplcon0); + bplcon0_planes = GET_PLANES (bplcon0); + bplcon0_planes_limit = GET_PLANES_LIMIT (bplcon0); + fetchunit = fetchunits[fetchmode * 4 + bplcon0_res]; + fetchunit_mask = fetchunit - 1; + fetchstart_shift = fetchstarts[fetchmode * 4 + bplcon0_res]; + fetchstart = 1 << fetchstart_shift; + fetchstart_mask = fetchstart - 1; + fm_maxplane_shift = fm_maxplanes[fetchmode * 4 + bplcon0_res]; + fm_maxplane = 1 << fm_maxplane_shift; + fetch_modulo_cycle = fetchunit - fetchstart; + curr_diagram = cycle_diagram_table[fetchmode][bplcon0_res][bplcon0_planes_limit]; } /* Expand bplcon0/bplcon1 into the toscr_xxx variables. */ @@ -925,7 +882,7 @@ static void compute_toscr_delay_1 (void) int shdelay1 = (bplcon1 >> 12) & 3; int shdelay2 = (bplcon1 >> 8) & 3; int delaymask; - int fetchwidth = 16 << f_fetchmode; + int fetchwidth = 16 << fetchmode; delay1 += delayoffset; delay2 += delayoffset; @@ -938,9 +895,7 @@ static void compute_toscr_delay_1 (void) static void compute_toscr_delay (int hpos) { - toscr_res = fd_bplcon0_res; - toscr_nr_planes = f_bplcon0_planes_limit; - toscr_nr_planes2 = f_bplcon0_planes; + update_denise (hpos); compute_toscr_delay_1 (); } @@ -953,14 +908,16 @@ STATIC_INLINE void maybe_first_bpl1dat (int hpos) } } -STATIC_INLINE void fetch (int nr, int fm) +STATIC_INLINE void fetch (int nr, int fm, int hpos) { - if (nr < toscr_nr_planes) { -#if NEW_BPL - uaecptr p = f_bplpt[nr] + bpl_off[nr]; -#else - uaecptr p = bplpt[nr]; + if (nr < bplcon0_planes_limit) { + uaecptr p = bplpt[nr] + bpl_off[nr]; bplpt[nr] += 2 << fm; + if (nr == 0) + bpl1dat_written = 1; +#ifdef DEBUGGER + if (debug_copper) + record_copper_otherdma (0x110 + nr * 2, chipmem_agnus_wget (p), hpos, vpos); #endif switch (fm) { @@ -979,9 +936,9 @@ STATIC_INLINE void fetch (int nr, int fm) break; #endif } - if (plfstate == plf_passed_stop2 && fetch_cycle >= (fetch_cycle & ~f_fetchunit_mask) + f_fetch_modulo_cycle) { + if (plfstate == plf_passed_stop2 && fetch_cycle >= (fetch_cycle & ~fetchunit_mask) + fetch_modulo_cycle) { int mod; - if (f_fmode & 0x4000) { + if (fmode & 0x4000) { if (((diwstrt >> 8) ^ vpos) & 1) mod = bpl2mod; else @@ -993,15 +950,11 @@ STATIC_INLINE void fetch (int nr, int fm) bplpt[nr] += mod; bplptx[nr] += mod; } - } else if (isocs7planes ()) { + } else { + // use whatever left in BPLxDAT if no DMA + // normally useless but "7-planes" feature won't work without this fetched[nr] = bplxdat[nr]; } - if (nr == 0) - fetch_state = fetch_was_plane0; -#if NEW_BPL - else if (nr == 1 && ta_bplcon0_res > fa_bplcon0_res) - fetch_state = fetch_was_plane0; -#endif } static void clear_fetchbuffer (uae_u32 *ptr, int nwords) @@ -1024,10 +977,6 @@ static void update_toscr_planes (void) int j; for (j = thisline_decision.nr_planes; j < toscr_nr_planes2; j++) clear_fetchbuffer ((uae_u32 *)(line_data[next_lineno] + 2 * MAX_WORDS_PER_LINE * j), out_offs); -#if 0 - if (thisline_decision.nr_planes > 0) - printf ("Planes from %d to %d\n", thisline_decision.nr_planes, toscr_nr_planes2); -#endif thisline_decision.nr_planes = toscr_nr_planes2; } } @@ -1221,7 +1170,7 @@ STATIC_INLINE void flush_display (int fm) toscr_nbits = 0; } -STATIC_INLINE void fetch_start (int hpoa) +STATIC_INLINE void fetch_start (int hpos) { fetch_state = fetch_started; } @@ -1229,14 +1178,15 @@ STATIC_INLINE void fetch_start (int hpoa) /* Called when all planes have been fetched, i.e. when a new block of data is available to be displayed. The data in fetched[] is moved into todisplay[]. */ -STATIC_INLINE void beginning_of_plane_block (int pos, int fm) +STATIC_INLINE void beginning_of_plane_block (int hpos, int fm) { int i; flush_display (fm); if (fm == 0) - for (i = 0; i < MAX_PLANES; i++) + for (i = 0; i < MAX_PLANES; i++) { todisplay[i][0] |= fetched[i]; + } #ifdef AGA else for (i = 0; i < MAX_PLANES; i++) { @@ -1245,9 +1195,11 @@ STATIC_INLINE void beginning_of_plane_block (int pos, int fm) todisplay[i][0] = fetched_aga0[i]; } #endif - maybe_first_bpl1dat (pos); + update_denise (hpos); + maybe_first_bpl1dat (hpos); toscr_delay1 = toscr_delay1x; toscr_delay2 = toscr_delay2x; + compute_toscr_delay (hpos); } #ifdef SPEEDUP @@ -1463,32 +1415,12 @@ static void finish_final_fetch (int pos, int fm) finish_playfield_line (); } -/* current theory: bitplane operation is pipelined, bitplane pointer is copied - * to backup registers -4 to -1 cycles before fetch is done and pointer is - * increased during this time, not when real DMA fetch is done, this makes some - * sense to demos that change bitplane pointers during display - * (this code is not really emulating above behavior yet..) - */ -STATIC_INLINE void inc_bpl (int fm, int oe) -{ -#if NEW_BPL - int i; - for (i = 0; i < f_bplcon0_planes; i++) { - if ((oe == 0) || (oe < 0 && (i & 1)) || (oe > 0 && !(i & 1))) { - f_bplpt[i] = bplpt[i]; - bplpt[i] += 2 << fm; - bplptx[i] += 2 << fm; - } - } -#endif -} - STATIC_INLINE int one_fetch_cycle_0 (int pos, int ddfstop_to_test, int dma, int fm) { if (plfstate < plf_passed_stop && pos == ddfstop_to_test) plfstate = plf_passed_stop; - if ((fetch_cycle & f_fetchunit_mask) == 0) { + if ((fetch_cycle & fetchunit_mask) == 0) { if (plfstate == plf_passed_stop2) { finish_final_fetch (pos, fm); return 1; @@ -1501,36 +1433,46 @@ STATIC_INLINE int one_fetch_cycle_0 (int pos, int ddfstop_to_test, int dma, int /* fetchstart_mask can be larger than fm_maxplane if FMODE > 0. This means that the remaining cycles are idle; we'll fall through the whole switch without doing anything. */ - int cycle_start = fetch_cycle & f_fetchstart_mask; - switch (f_fm_maxplane) { + int cycle_start = fetch_cycle & fetchstart_mask; + switch (fm_maxplane) { case 8: switch (cycle_start) { - case 0: inc_bpl (fm, -1); fetch (7, fm); break; - case 1: fetch (3, fm); break; - case 2: fetch (5, fm); break; - case 3: fetch (1, fm); break; - case 4: inc_bpl (fm, 1); fetch (6, fm); break; - case 5: fetch (2, fm); break; - case 6: fetch (4, fm); break; - case 7: fetch (0, fm); break; + case 0: fetch (7, fm, pos); break; + case 1: fetch (3, fm, pos); break; + case 2: fetch (5, fm, pos); break; + case 3: fetch (1, fm, pos); break; + case 4: fetch (6, fm, pos); break; + case 5: fetch (2, fm, pos); break; + case 6: fetch (4, fm, pos); break; + case 7: fetch (0, fm, pos); break; } break; case 4: switch (cycle_start) { - case 0: inc_bpl (fm, -1); fetch (3, fm); break; - case 1: fetch (1, fm); break; - case 2: inc_bpl (fm, 1); fetch (2, fm); break; - case 3: fetch (0, fm); break; + case 0: fetch (3, fm, pos); break; + case 1: fetch (1, fm, pos); break; + case 2: fetch (2, fm, pos); break; + case 3: fetch (0, fm, pos); break; } break; case 2: switch (cycle_start) { - case 0: inc_bpl (fm, 0); fetch (1, fm); break; - case 1: fetch (0, fm); break; + case 0: fetch (1, fm, pos); break; + case 1: fetch (0, fm, pos); break; } break; } } + + if (bpl1dat_written) { + // do this here because if program plays with BPLCON0 during scanline + // it is possible that one DMA BPL1DAT write is completely missed + // -> do not draw anything at all in next dma block + // (Disposable Hero titlescreen) + fetch_state = fetch_was_plane0; + bpl1dat_written = 0; + } + fetch_cycle++; toscr_nbits += 2 << toscr_res; @@ -1577,7 +1519,6 @@ STATIC_INLINE void update_fetch (int until, int fm) if (ddfstop >= last_fetch_hpos && plfstop < ddfstop_to_test) ddfstop_to_test = plfstop; - compute_toscr_delay (last_fetch_hpos); update_toscr_planes (); pos = last_fetch_hpos; @@ -1608,7 +1549,7 @@ STATIC_INLINE void update_fetch (int until, int fm) /* Unrolled version of the for loop below. */ if (plfstate < plf_passed_stop && ddf_change != vpos && ddf_change + 1 != vpos && dma - && (fetch_cycle & f_fetchstart_mask) == (f_fm_maxplane & f_fetchstart_mask) + && (fetch_cycle & fetchstart_mask) == (fm_maxplane & fetchstart_mask) && toscr_delay1 == toscr_delay1x && toscr_delay2 == toscr_delay2x && !badmode # if 0 /* @@@ We handle this case, but the code would be simpler if we @@ -1618,16 +1559,16 @@ STATIC_INLINE void update_fetch (int until, int fm) # endif && toscr_nr_planes == thisline_decision.nr_planes) { - int offs = (pos - fetch_cycle) & f_fetchunit_mask; - int ddf2 = ((ddfstop_to_test - offs + f_fetchunit - 1) & ~f_fetchunit_mask) + offs; - int ddf3 = ddf2 + f_fetchunit; + int offs = (pos - fetch_cycle) & fetchunit_mask; + int ddf2 = ((ddfstop_to_test - offs + fetchunit - 1) & ~fetchunit_mask) + offs; + int ddf3 = ddf2 + fetchunit; int stop = until < ddf2 ? until : until < ddf3 ? ddf2 : ddf3; int count; count = stop - pos; - if (count >= f_fetchstart) { - count &= ~f_fetchstart_mask; + if (count >= fetchstart) { + count &= ~fetchstart_mask; if (thisline_decision.plfleft == -1) { compute_delay_offset (); @@ -1645,7 +1586,7 @@ STATIC_INLINE void update_fetch (int until, int fm) plfstate = plf_passed_stop; if (pos <= ddfstop_to_test && pos + count > ddf2) plfstate = plf_passed_stop2; - if (pos <= ddf2 && pos + count >= ddf2 + f_fm_maxplane) + if (pos <= ddf2 && pos + count >= ddf2 + fm_maxplane) add_modulos (); pos += count; fetch_cycle += count; @@ -1657,8 +1598,6 @@ STATIC_INLINE void update_fetch (int until, int fm) #endif for (; pos < until; pos++) { if (fetch_state == fetch_was_plane0) { - fetch_bpl_params (); - copy_bpl_params (pos); beginning_of_plane_block (pos, fm); estimate_last_fetch_cycle (pos); } @@ -1681,7 +1620,7 @@ static void update_fetch_2 (int hpos) { update_fetch (hpos, 2); } STATIC_INLINE void decide_fetch (int hpos) { if (fetch_state != fetch_not_started && hpos > last_fetch_hpos) { - switch (f_fetchmode) { + switch (fetchmode) { case 0: update_fetch_0 (hpos); break; #ifdef AGA case 1: update_fetch_1 (hpos); break; @@ -1709,15 +1648,13 @@ static void start_bpl_dma (int hpos, int hstart) } } - fetch_bpl_params (); - copy_bpl_params (hpos); fetch_start (hpos); fetch_cycle = 0; last_fetch_hpos = hstart; out_nbits = 0; out_offs = 0; toscr_nbits = 0; - thisline_decision.bplres = fd_bplcon0_res; + thisline_decision.bplres = bplcon0_res; ddfstate = DIW_waiting_stop; compute_toscr_delay (last_fetch_hpos); @@ -1749,7 +1686,7 @@ static void maybe_start_bpl_dma (int hpos) return; if (hpos <= plfstrt) return; - if (hpos > plfstop - t_fetchunit) + if (hpos > plfstop - fetchunit) return; if (ddfstate != DIW_waiting_start) plfstate = plf_passed_stop; @@ -1846,15 +1783,12 @@ static void record_color_change (int hpos, int regno, unsigned long value) static void record_register_change (int hpos, int regno, unsigned long value) { - if (regno == 0x100) { - if (plfstate >= plf_end) - return; + if (regno == 0x100) { // BPLCON0 if (value & 0x800) thisline_decision.ham_seen = 1; - if (hpos < HARD_DDF_START || hpos < plfstrt + 0x20) { - thisline_decision.bplcon0 = value; - thisline_decision.bplres = GET_RES_DENISE (value); - } + thisline_decision.ehb_seen = !! isehb (value, bplcon2); + } else if (regno == 0x104) { // BPLCON2 + thisline_decision.ehb_seen = !! isehb (value, bplcon2); } record_color_change (hpos, regno + 0x1000, value); } @@ -1896,7 +1830,7 @@ static int expand_sprres (uae_u16 con0, uae_u16 con3) /* handle very rarely needed playfield collision (CLXDAT bit 0) */ static void do_playfield_collisions (void) { - int bplres = td_bplcon0_res; + int bplres = bplcon0_res; hwres_t ddf_left = thisline_decision.plfleft * 2 << bplres; hwres_t hw_diwlast = coord_window_to_diw_x (thisline_decision.diwlastword); hwres_t hw_diwfirst = coord_window_to_diw_x (thisline_decision.diwfirstword); @@ -1965,7 +1899,7 @@ static void do_sprite_collisions (void) int first = curr_drawinfo[next_lineno].first_sprite_entry; int i; unsigned int collision_mask = clxmask[clxcon >> 12]; - int bplres = td_bplcon0_res; + int bplres = bplcon0_res; hwres_t ddf_left = thisline_decision.plfleft * 2 << bplres; hwres_t hw_diwlast = coord_window_to_diw_x (thisline_decision.diwlastword); hwres_t hw_diwfirst = coord_window_to_diw_x (thisline_decision.diwfirstword); @@ -2462,14 +2396,15 @@ static void reset_decisions (void) if (nodraw ()) return; - curr_diagram_change = -1; toscr_nr_planes = toscr_nr_planes2 = 0; - thisline_decision.bplres = td_bplcon0_res; + thisline_decision.bplres = bplcon0_res; thisline_decision.nr_planes = 0; + bpl1dat_written = 0; thisline_decision.plfleft = -1; thisline_decision.plflinelen = -1; thisline_decision.ham_seen = !! (bplcon0 & 0x800); + thisline_decision.ehb_seen = !! isehb (bplcon0, bplcon2); thisline_decision.ham_at_start = !! (bplcon0 & 0x800); /* decided_res shouldn't be touched before it's initialized by decide_line(). */ @@ -2710,10 +2645,6 @@ static void calcdiw (void) plfstrt = ddfstrt; plfstop = ddfstop; -#ifdef NEWHSYNC - plfstrt += 4; - plfstop += 4; -#endif /* probably not the correct place.. should use plfstate instead */ if (currprefs.chipset_mask & CSMASK_ECS_AGNUS) { /* ECS/AGA and ddfstop > maxhpos == always-on display */ @@ -3173,11 +3104,7 @@ int is_bitplane_dma (int hpos) if ((plfstate == plf_end && hpos >= thisline_decision.plfright) || hpos >= estimated_last_fetch_cycle) return 0; - if (curr_diagram_change >= 0 && hpos >= curr_diagram_change) { - curr_diagram = cycle_diagram_table[fetchmode][ta_bplcon0_res][t_bplcon0_planes_limit]; - curr_diagram_change = -1; - } - return curr_diagram[(hpos - cycle_diagram_shift) & f_fetchstart_mask]; + return curr_diagram[(hpos - cycle_diagram_shift) & fetchstart_mask]; } STATIC_INLINE int is_bitplane_dma_inline (int hpos) @@ -3187,11 +3114,7 @@ STATIC_INLINE int is_bitplane_dma_inline (int hpos) if ((plfstate == plf_end && hpos >= thisline_decision.plfright) || hpos >= estimated_last_fetch_cycle) return 0; - if (curr_diagram_change >= 0 && hpos >= curr_diagram_change) { - curr_diagram = cycle_diagram_table[fetchmode][ta_bplcon0_res][t_bplcon0_planes_limit]; - curr_diagram_change = -1; - } - return curr_diagram[(hpos - cycle_diagram_shift) & f_fetchstart_mask]; + return curr_diagram[(hpos - cycle_diagram_shift) & fetchstart_mask]; } static void BPLxPTH (int hpos, uae_u16 v, int num) @@ -3204,38 +3127,45 @@ static void BPLxPTH (int hpos, uae_u16 v, int num) } static void BPLxPTL (int hpos, uae_u16 v, int num) { - int delta = 0; decide_line (hpos); decide_fetch (hpos); - /* fix for "bitplane dma fetch at the same time while updating BPLxPTL" */ - /* fixes "3v Demo" by Cave and "New Year Demo" by Phoenix */ - if (is_bitplane_dma (hpos) == num + 1 || is_bitplane_dma (hpos - 1) == num + 1) { - delta = 2 << f_fetchmode; - } - - // hack until bitplane pipelin is properly emulated - if (fetchmode == 0 && fetch_state != fetch_not_started && diwstate == DIW_waiting_stop && f_fm_maxplane == 8 && t_bplcon0_planes > 1 && td_bplcon0_res == 0) { - if (hpos > plfstrt && hpos <= plfstrt + 7) { - if (num == 1 && hpos <= plfstrt + 2) - delta = 2; - } - } - - f_bplpt[num] = bplpt[num] = (bplpt[num] & 0xffff0000) | ((v + delta) & 0x0000fffe); - bplptx[num] = (bplptx[num] & 0xffff0000) | ((v + delta) & 0x0000fffe); + f_bplpt[num] = bplpt[num] = (bplpt[num] & 0xffff0000) | (v & 0x0000fffe); + bplptx[num] = (bplptx[num] & 0xffff0000) | (v & 0x0000fffe); //write_log (L"%d:%d:BPL%dPTL %08X COP=%08x\n", hpos, vpos, num, bplpt[num], cop_state.ip); } -static int isehb (uae_u16 bplcon0, uae_u16 bplcon2) +static void BPLCON0_Denise (int hpos, uae_u16 v) { - int bplehb; - if (currprefs.chipset_mask & CSMASK_AGA) - bplehb = (bplcon0 & 0x7010) == 0x6000; - else if (currprefs.chipset_mask & CSMASK_ECS_DENISE) - bplehb = ((bplcon0 & 0xFC00) == 0x6000 || (bplcon0 & 0xFC00) == 0x7000); - else - bplehb = ((bplcon0 & 0xFC00) == 0x6000 || (bplcon0 & 0xFC00) == 0x7000) && !currprefs.cs_denisenoehb; - return bplehb; + if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE)) + v &= ~0x00F1; + else if (! (currprefs.chipset_mask & CSMASK_AGA)) + v &= ~0x00B1; + v &= ~(0x0200 | 0x0100 | 0x0080 | 0x0020); +#if SPRBORDER + v |= 1; +#endif + + if (bplcon0d == v) + return; + + // fake unused 0x0080 bit as an EHB bit (see below) + if (isehb (bplcon0d, bplcon2)) + v |= 0x80; + + // Denise reacts to HAM/EHB/DPF changes instantly + if ((bplcon0d & (0x800 | 0x400 | 0x80)) != (v & (0x800 | 0x400 | 0x80))) + record_register_change (hpos, 0x100, (bplcon0d & ~(0x800 | 0x400 | 0x80)) | (v & (0x0800 | 0x400 | 0x80))); + + bplcon0d = v & ~0x80; + +#ifdef ECS_DENISE + if (currprefs.chipset_mask & CSMASK_ECS_DENISE) { + decide_sprites (hpos); + sprres = expand_sprres (v, bplcon3); + } +#endif + if (thisline_decision.plfleft == -1) + update_denise (hpos); } static void BPLCON0 (int hpos, uae_u16 v) @@ -3262,51 +3192,23 @@ static void BPLCON0 (int hpos, uae_u16 v) decide_fetch (hpos); decide_blitter (hpos); - badmode = GET_RES_AGNUS (v) != GET_RES_DENISE (v); + bplcon0 = v; - // fake unused 0x0080 bit as an EHB bit (see below) - if (isehb (v, bplcon2)) + badmode = GET_RES_AGNUS (bplcon0) != GET_RES_DENISE (bplcon0); + + // fake unused 0x0080 bit as an EHB bit (see above) + if (isehb (bplcon0, bplcon2)) v |= 0x80; - if ((bplcon0 & (0x800 | 0x400 | 0x80)) != (v & (0x800 | 0x400 | 0x80))) // HAM/EBH/DPF change is instant - record_register_change (hpos, 0x100, (bplcon0 & ~(0x800 | 0x400 | 0x80)) | (v & (0x0800 | 0x400 | 0x80))); + BPLCON0_Denise (hpos, v); - // don't ask.. - if (GET_PLANES (v) > GET_PLANES (bplcon0) && GET_RES_AGNUS (v) >= GET_RES_AGNUS (bplcon0) && fetch_state != fetch_not_started) - fetch_state = fetch_was_plane0; + expand_fmodes (); - bplcon0 = v; + record_register_change (hpos, 0x100, v | 0x80); -#ifdef ECS_DENISE - if (currprefs.chipset_mask & CSMASK_ECS_DENISE) { - decide_sprites (hpos); - sprres = expand_sprres (bplcon0, bplcon3); - } -#endif - expand_fmodes (); -#if NEW_BPL - if (fetch_state == fetch_not_started || diwstate != DIW_waiting_stop) { - record_register_change (hpos, 0x100, v); - fetch_bpl_params (); - copy_bpl_params (hpos); - } else if (fetch_state != fetch_not_started && diwstate == DIW_waiting_stop && (hpos >= plfstrt && hpos <= plfstrt + 1)) { - fetch_bpl_params (); - copy_bpl_params (hpos); - } -#else - fetch_bpl_params (); - copy_bpl_params (hpos); -#endif calcdiw (); estimate_last_fetch_cycle (hpos); - curr_diagram_change = -1; - if (fetch_state == fetch_started && diwstate == DIW_waiting_stop) { - curr_diagram_change = hpos - 2 + f_fm_maxplane - (fetch_cycle & f_fetchstart_mask); - } else { - curr_diagram = cycle_diagram_table[fetchmode][ta_bplcon0_res][t_bplcon0_planes_limit]; - } - } STATIC_INLINE void BPLCON1 (int hpos, uae_u16 v) @@ -3390,19 +3292,22 @@ static void BPL2MOD (int hpos, uae_u16 v) static void BPL5DAT (int hpos, uae_u16 v) { decide_line (hpos); + decide_fetch (hpos); bplxdat[4] = v; } static void BPL6DAT (int hpos, uae_u16 v) { decide_line (hpos); + decide_fetch (hpos); bplxdat[5] = v; } STATIC_INLINE void BPL1DAT (int hpos, uae_u16 v) { decide_line (hpos); + decide_fetch (hpos); + bpl1dat_written = 1; bplxdat[0] = v; - maybe_first_bpl1dat (hpos); } @@ -3444,8 +3349,6 @@ static void DDFSTRT (int hpos, uae_u16 v) v &= 0xfe; if (!(currprefs.chipset_mask & CSMASK_ECS_AGNUS)) v &= 0xfc; - if (ddfstrt == v && hpos != plfstrt - 2) - return; ddf_change = vpos; decide_line (hpos); ddfstrt_old_hpos = hpos; @@ -3896,13 +3799,8 @@ static void COLOR_WRITE (int hpos, uae_u16 v, int num) STATIC_INLINE int copper_cant_read (int hpos) { -#ifdef NEWHSYNC - if (hpos == 0) - return 1; -#else if (hpos + 1 >= maxhpos) return 1; -#endif return is_bitplane_dma_inline (hpos); } @@ -3923,13 +3821,8 @@ static int custom_wput_copper (int hpos, uaecptr addr, uae_u32 value, int noget) return custom_wput_1 (hpos, addr, value, noget); } -static void perform_copper_write (int old_hpos, int address, int data) +static void perform_copper_write (int hpos, int address, int data) { -#ifdef DEBUGGER - if (debug_copper) - record_copper (cop_state.saved_ip - 4, old_hpos, vpos); -#endif - if (test_copper_dangerous (address)) return; if (address == 0x88) { @@ -3939,27 +3832,37 @@ static void perform_copper_write (int old_hpos, int address, int data) cop_state.ip = cop2lc; cop_state.state = COP_strobe_delay1; } else { - custom_wput_copper (old_hpos, address, data, 0); + custom_wput_copper (hpos, address, data, 0); cop_state.last_write = address; - cop_state.last_write_hpos = old_hpos; - old_hpos++; - if (!nocustom () && address >= 0x140 && address < 0x180 && old_hpos >= SPR0_HPOS && old_hpos < SPR0_HPOS + 4 * MAX_SPRITES) { - //write_log (L"%d:%d %04X:%04X\n", vpos, old_hpos, cop_state.saved_i1, cop_state.saved_i2); - do_sprites (old_hpos); + cop_state.last_write_hpos = hpos; + hpos++; + if (!nocustom () && address >= 0x140 && address < 0x180 && hpos >= SPR0_HPOS && hpos < SPR0_HPOS + 4 * MAX_SPRITES) { + //write_log (L"%d:%d %04X:%04X\n", vpos, hpos, cop_state.saved_i1, cop_state.saved_i2); + do_sprites (hpos); } } } -static int isagnus[]= { +static void dump_copper (TCHAR *error, int until_hpos) +{ + write_log (L"%s: vpos=%d until_hpos=%d\n", + error, vpos, until_hpos); + write_log (L"cvcmp=%d chcmp=%d chpos=%d cvpos=%d ci1=%04X ci2=%04X\n", + cop_state.vcmp,cop_state.hcmp,cop_state.hpos,cop_state.vpos,cop_state.saved_i1,cop_state.saved_i2); + write_log (L"cstate=%d ip=%x SPCFLAGS=%x\n", + cop_state.state, cop_state.ip, regs.spcflags); +} + +static int customdelay[]= { 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 32 0x00 - 0x3e */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 27 0x40 - 0x74 */ 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, /* 21 */ 1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0, /* 32 0xa0 - 0xde */ /* BPLxPTH/BPLxPTL */ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 16 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16 */ /* BPLCON0-3,BPLMOD1-2 */ - 0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0, /* 16 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16 */ /* SPRxPTH/SPRxPTL */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 16 */ /* SPRxPOS/SPRxCTL/SPRxDATA/SPRxDATB */ @@ -3970,16 +3873,6 @@ static int isagnus[]= { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -static void dump_copper (TCHAR *error, int until_hpos) -{ - write_log (L"%s: vpos=%d until_hpos=%d\n", - error, vpos, until_hpos); - write_log (L"cvcmp=%d chcmp=%d chpos=%d cvpos=%d ci1=%04X ci2=%04X\n", - cop_state.vcmp,cop_state.hcmp,cop_state.hpos,cop_state.vpos,cop_state.saved_i1,cop_state.saved_i2); - write_log (L"cstate=%d ip=%x SPCFLAGS=%x\n", - cop_state.state, cop_state.ip, regs.spcflags); -} - static void update_copper (int until_hpos) { int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80); @@ -4010,9 +3903,14 @@ static void update_copper (int until_hpos) /* So we know about the fetch state. */ decide_line (c_hpos); + decide_fetch (c_hpos); if (cop_state.movedelay > 0) { cop_state.movedelay--; + if (cop_state.movedelay == 1 && cop_state.moveaddr == 0x100) { + // Denise reacts to BPLCON0 change a bit earlier than Agnus + BPLCON0_Denise (old_hpos, cop_state.movedata); + } if (cop_state.movedelay == 0) { perform_copper_write (old_hpos, cop_state.moveaddr, cop_state.movedata); if (! copper_enabled_thisline) @@ -4098,13 +3996,20 @@ static void update_copper (int until_hpos) cop_state.ip = cop2lc; cop_state.state = COP_strobe_delay1; } else { - cop_state.movedelay = isagnus[reg >> 1] ? 1 : 2; + if (cop_state.moveaddr == 0x100) { + // special case BPLCON0 BPL DMA sequency delay + cop_state.movedelay = 2; + } else if (customdelay[cop_state.moveaddr / 2]) { + cop_state.movedelay = customdelay[cop_state.moveaddr / 2]; + } else { + perform_copper_write (old_hpos, cop_state.moveaddr, cop_state.movedata); + } } - } #ifdef DEBUGGER - if (debug_copper) - record_copper (cop_state.ip - 4, old_hpos, vpos); + if (debug_copper) + record_copper (cop_state.ip - 4, old_hpos, vpos); #endif + } break; case COP_wait1: @@ -4734,7 +4639,7 @@ static void vsync_handler (void) } if (debug_copper) - record_copper_reset(); + record_copper_reset (); vsync_handle_redraw (lof, lof_changed); @@ -4941,16 +4846,16 @@ static void hsync_handler (void) if (currprefs.cpu_cycle_exact || currprefs.blitter_cycle_exact) { decide_blitter (hpos); memset (cycle_line, 0, sizeof cycle_line); -#ifdef NEWHSYNC - alloc_cycle (3, CYCLE_REFRESH); /* strobe */ +#if 1 + alloc_cycle (1, CYCLE_REFRESH); /* strobe */ + alloc_cycle (3, CYCLE_REFRESH); alloc_cycle (5, CYCLE_REFRESH); alloc_cycle (7, CYCLE_REFRESH); - alloc_cycle (9, CYCLE_REFRESH); #else - alloc_cycle (1, CYCLE_REFRESH); /* strobe */ + alloc_cycle (maxhpos - 1, CYCLE_REFRESH); /* strobe */ + alloc_cycle (1, CYCLE_REFRESH); alloc_cycle (3, CYCLE_REFRESH); alloc_cycle (5, CYCLE_REFRESH); - alloc_cycle (7, CYCLE_REFRESH); #endif } #endif @@ -4986,9 +4891,9 @@ static void hsync_handler (void) if (!nocustom()) { if (!currprefs.blitter_cycle_exact && bltstate != BLT_done && dmaen (DMA_BITPLANE) && diwstate == DIW_waiting_stop) { - blitter_slowdown (thisline_decision.plfleft, thisline_decision.plfright - (16 << f_fetchmode), - cycle_diagram_total_cycles[f_fetchmode][GET_RES_AGNUS (f_bplcon0)][GET_PLANES_LIMIT (f_bplcon0)], - cycle_diagram_free_cycles[f_fetchmode][GET_RES_AGNUS (f_bplcon0)][GET_PLANES_LIMIT (f_bplcon0)]); + blitter_slowdown (thisline_decision.plfleft, thisline_decision.plfright - (16 << fetchmode), + cycle_diagram_total_cycles[fetchmode][GET_RES_AGNUS (bplcon0)][GET_PLANES_LIMIT (bplcon0)], + cycle_diagram_free_cycles[fetchmode][GET_RES_AGNUS (bplcon0)][GET_PLANES_LIMIT (bplcon0)]); } hardware_line_completed (next_lineno); if (doflickerfix () && interlace_seen) diff --git a/debug.c b/debug.c index a96d4198..a4bca941 100644 --- a/debug.c +++ b/debug.c @@ -43,7 +43,7 @@ static int memwatch_enabled, memwatch_triggered; static uae_u16 sr_bpmask, sr_bpvalue; int debugging; int exception_debugging; -int debug_copper; +int debug_copper = 0; int debug_sprite_mask = 0xff; static uaecptr processptr; @@ -680,38 +680,56 @@ static void disassemble_wait (FILE *file, unsigned long insn) console_out (L", ignore horizontal"); } - console_out_f (L".\n \t; VP %02x, VE %02x; HP %02x, HE %02x; BFD %d\n", + console_out_f (L"\n \t; VP %02x, VE %02x; HP %02x, HE %02x; BFD %d\n", vp, ve, hp, he, bfd); } -#define NR_COPPER_RECORDS 100000 +#define NR_COPPER_RECORDS 1000000 /* Record copper activity for the debugger. */ -struct cop_record +struct cop_rec { int hpos, vpos; + uae_u16 reg, dat; uaecptr addr; }; -static struct cop_record *cop_record[2]; +static struct cop_rec *cop_record[2]; static int nr_cop_records[2], curr_cop_set; -void record_copper_reset(void) +void record_copper_reset (void) { /* Start a new set of copper records. */ curr_cop_set ^= 1; nr_cop_records[curr_cop_set] = 0; } +void record_copper_otherdma (uae_u16 bpl, uae_u16 dat, int hpos, int vpos) +{ + int t = nr_cop_records[curr_cop_set]; + if (!cop_record[0]) + return; + if (t >= NR_COPPER_RECORDS) + return; + cop_record[curr_cop_set][t].addr = 0xffffffff; + cop_record[curr_cop_set][t].hpos = hpos; + cop_record[curr_cop_set][t].vpos = vpos; + cop_record[curr_cop_set][t].reg = bpl; + cop_record[curr_cop_set][t].dat = dat; + nr_cop_records[curr_cop_set] = t + 1; +} + void record_copper (uaecptr addr, int hpos, int vpos) { int t = nr_cop_records[curr_cop_set]; if (!cop_record[0]) { - cop_record[0] = xmalloc (NR_COPPER_RECORDS * sizeof (struct cop_record)); - cop_record[1] = xmalloc (NR_COPPER_RECORDS * sizeof (struct cop_record)); + cop_record[0] = xmalloc (NR_COPPER_RECORDS * sizeof (struct cop_rec)); + cop_record[1] = xmalloc (NR_COPPER_RECORDS * sizeof (struct cop_rec)); } if (t < NR_COPPER_RECORDS) { cop_record[curr_cop_set][t].addr = addr; cop_record[curr_cop_set][t].hpos = hpos; cop_record[curr_cop_set][t].vpos = vpos; + cop_record[curr_cop_set][t].reg = 0xffff; + cop_record[curr_cop_set][t].dat = 0xffff; nr_cop_records[curr_cop_set] = t + 1; } if (debug_copper & 2) { /* trace */ @@ -724,17 +742,14 @@ void record_copper (uaecptr addr, int hpos, int vpos) } } -static int find_copper_record (uaecptr addr, int *phpos, int *pvpos) +static struct cop_rec *find_copper_records (uaecptr addr) { int s = curr_cop_set ^ 1; int t = nr_cop_records[s]; int i; for (i = 0; i < t; i++) { - if (cop_record[s][i].addr == addr) { - *phpos = cop_record[s][i].hpos; - *pvpos = cop_record[s][i].vpos; - return 1; - } + if (cop_record[s][i].addr == addr) + return &cop_record[s][i]; } return 0; } @@ -742,12 +757,14 @@ static int find_copper_record (uaecptr addr, int *phpos, int *pvpos) /* simple decode copper by Mark Cox */ static void decode_copper_insn (FILE* file, unsigned long insn, unsigned long addr) { + struct cop_rec *cr = NULL; uae_u32 insn_type = insn & 0x00010001; - int hpos, vpos; TCHAR here = ' '; TCHAR record[] = L" "; - if (find_copper_record (addr, &hpos, &vpos)) { - _stprintf (record, L" [%03x %03x]", vpos, hpos); + int cnt; + + if ((cr = find_copper_records (addr))) { + _stprintf (record, L" [%03x %03x]", cr->vpos, cr->hpos); } if (get_copper_address (-1) >= addr && get_copper_address(-1) <= addr + 3) @@ -791,6 +808,32 @@ static void decode_copper_insn (FILE* file, unsigned long insn, unsigned long ad abort (); } + if (!cr) + return; + cr++; + cnt = 0; + while (cr->addr == 0xffffffff) { + int addr = cr->reg; + int i = 0; + while (custd[i].name) { + if (custd[i].adr == addr + 0xdff000) + break; + i++; + } + _stprintf (record, L" [%03x %03x]", cr->vpos, cr->hpos); + console_out_f (L" %04lx %04lx%s\t; ", addr, cr->dat, record); + if (custd[i].name) + console_out_f (L"%s := 0x%04lx\n", custd[i].name, cr->dat); + else + console_out_f (L"%04x := 0x%04lx\n", addr, cr->dat); + cr++; + if (cnt++ >= 10) { + console_out_f (L" ...\n"); + break; + } + + } + } static uaecptr decode_copperlist (FILE* file, uaecptr address, int nolines) @@ -814,27 +857,27 @@ static int copper_debugger (TCHAR **c) int lines; if (**c == 'd') { - next_char(c); + next_char (c); if (debug_copper) debug_copper = 0; else debug_copper = 1; console_out_f (L"Copper debugger %s.\n", debug_copper ? L"enabled" : L"disabled"); - } else if(**c == 't') { + } else if (**c == 't') { debug_copper = 1|2; return 1; - } else if(**c == 'b') { + } else if (**c == 'b') { (*c)++; debug_copper = 1|4; - if (more_params(c)) { - debug_copper_pc = readhex(c); + if (more_params (c)) { + debug_copper_pc = readhex (c); console_out_f (L"Copper breakpoint @0x%08x\n", debug_copper_pc); } else { debug_copper &= ~4; } } else { - if (more_params(c)) { - maddr = readhex(c); + if (more_params (c)) { + maddr = readhex (c); if (maddr == 1 || maddr == 2) maddr = get_copper_address (maddr); else if (maddr == 0) @@ -2921,7 +2964,7 @@ static void debug_1 (void) break; case 'o': { - if (copper_debugger(&inptr)) { + if (copper_debugger (&inptr)) { debugger_active = 0; debugging = 0; return; diff --git a/drawing.c b/drawing.c index 3e361fa1..b32a0b3c 100644 --- a/drawing.c +++ b/drawing.c @@ -438,7 +438,7 @@ int get_custom_limits (int *pw, int *ph, int *pdx, int *pdy) *pdy = dy; write_log (L"Display Size: %dx%d Offset: %dx%d\n", w, h, dx, dy); - write_log (L"first: %d last: %d minv: %d maxv: %d min: %d\n", + write_log (L"First: %d Last: %d MinV: %d MaxV: %d Min: %d\n", plffirstline_total, plflastline_total, first_planes_vpos, last_planes_vpos, minfirstline); return 1; @@ -1805,6 +1805,9 @@ static void pfield_expand_dp_bplcon (void) bplres = dp_for_drawing->bplres; bplplanecnt = dp_for_drawing->nr_planes; bplham = dp_for_drawing->ham_seen; + bplehb = dp_for_drawing->ehb_seen; + if ((currprefs.chipset_mask & CSMASK_AGA) && (dp_for_drawing->bplcon2 & 0x0200)) + bplehb = 0; issprites = dip_for_drawing->nr_sprites; #ifdef ECS_DENISE ecsshres = bplres == RES_SUPERHIRES && (currprefs.chipset_mask & CSMASK_ECS_DENISE) && !(currprefs.chipset_mask & CSMASK_AGA); @@ -1815,9 +1818,6 @@ static void pfield_expand_dp_bplcon (void) if (bplres > 0) can_use_lores = 0; - bplehb = (dp_for_drawing->bplcon0 & 0x80) == 0x80; - if ((currprefs.chipset_mask & CSMASK_AGA) && (dp_for_drawing->bplcon2 & 0x0200)) - bplehb = 0; plf1pri = dp_for_drawing->bplcon2 & 7; plf2pri = (dp_for_drawing->bplcon2 >> 3) & 7; plf_sprite_mask = 0xFFFF0000 << (4 * plf2pri); diff --git a/include/debug.h b/include/debug.h index 6bcb36c7..37ba89f5 100644 --- a/include/debug.h +++ b/include/debug.h @@ -26,6 +26,7 @@ extern void deactivate_debugger (void); extern int notinrom (void); extern const TCHAR *debuginfo (int); extern void record_copper (uaecptr addr, int hpos, int vpos); +extern void record_copper_otherdma (uae_u16 bpl, uae_u16 dat, int hpos, int vpos); extern void record_copper_reset(void); extern int mmu_init(int,uaecptr,uaecptr); extern void mmu_do_hit(void); diff --git a/include/drawing.h b/include/drawing.h index 0ec95ae7..37c7ab36 100644 --- a/include/drawing.h +++ b/include/drawing.h @@ -27,7 +27,7 @@ #else /* According to the HRM, pixel data spends a couple of cycles somewhere in the chips before it appears on-screen. */ -#define DIW_DDF_OFFSET 9 +#define DIW_DDF_OFFSET 1 /* this many cycles starting from hpos=0 are visible on right border */ #define HBLANK_OFFSET 9 /* We ignore that many lores pixels at the start of the display. These are @@ -228,6 +228,7 @@ struct decision { #endif uae_u8 nr_planes; uae_u8 bplres; + unsigned int ehb_seen; unsigned int ham_seen; unsigned int ham_at_start; }; diff --git a/include/options.h b/include/options.h index db902ac4..3ee00028 100644 --- a/include/options.h +++ b/include/options.h @@ -343,11 +343,13 @@ struct uae_prefs { int win32_midiindev; int win32_uaescsimode; int win32_soundcard; + int win32_soundexclusive; int win32_norecyclebin; int win32_specialkey; int win32_guikey; int win32_kbledmode; int win32_fscodepage; + TCHAR win32_commandpath[MAX_DPATH]; int curses_reverse_video; diff --git a/od-win32/direct3d.c b/od-win32/direct3d.c index b428cfe4..67ace781 100644 --- a/od-win32/direct3d.c +++ b/od-win32/direct3d.c @@ -1108,7 +1108,7 @@ const TCHAR *D3D_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth D3DCAPS9 d3dCaps; int adapter; DWORD flags; - HINSTANCE d3dDLL; + HINSTANCE d3dDLL, d3dx; D3D_free (); D3D_canshaders (); @@ -1117,6 +1117,14 @@ const TCHAR *D3D_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth _tcscpy (errmsg, L"D3D: not enabled"); return errmsg; } + d3dx = LoadLibrary (L"d3dx9_41.dll"); + if (d3dx == NULL) { + _tcscpy (errmsg, L"Direct3D: March 2009 or newer DirectX Runtime required.\n\nhttp://go.microsoft.com/fwlink/?linkid=56513"); + if (isfullscreen () <= 0) + ShellExecute(NULL, L"open", L"http://go.microsoft.com/fwlink/?linkid=56513", NULL, NULL, SW_SHOWNORMAL); + return errmsg; + } + FreeLibrary (d3dx); d3d_ex = FALSE; d3dDLL = LoadLibrary (L"D3D9.DLL"); diff --git a/od-win32/resources/resource b/od-win32/resources/resource index 64b879a9..31d7e2e9 100644 --- a/od-win32/resources/resource +++ b/od-win32/resources/resource @@ -893,6 +893,8 @@ #define IDC_SOUND_AUTO 1709 #define IDC_FILTERKEEPASPECT 1709 #define IDC_CS_RTC 1710 +#define IDC_SOUND_AUTO2 1710 +#define IDC_SOUND_EXCLUSIVE 1710 #define IDC_CS_CIAA_TOD1 1711 #define IDC_CS_CIAA_TOD2 1712 #define IDC_CS_EXT 1712 diff --git a/od-win32/resources/winuae.rc b/od-win32/resources/winuae.rc index 15a93713..ff763611 100644 --- a/od-win32/resources/winuae.rc +++ b/od-win32/resources/winuae.rc @@ -298,17 +298,17 @@ STYLE DS_LOCALEDIT | DS_SETFONT | DS_3DLOOK | DS_CONTROL | WS_CHILD FONT 8, "MS Sans Serif", 0, 0, 0x1 BEGIN COMBOBOX IDC_SOUNDCARDLIST,5,9,291,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Sound Emulation",IDC_SOUNDSETTINGS,5,30,120,81 - CONTROL "Disabled",IDC_SOUND0,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,13,45,101,10 - CONTROL "Disabled, but emulated",IDC_SOUND1,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,13,57,102,10 - CONTROL "Enabled",IDC_SOUND2,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,13,69,102,10 - CONTROL "Enabled, 100% accurate",IDC_SOUND3,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,13,81,101,10 - GROUPBOX "Volume",IDC_STATIC,132,36,164,31 - CONTROL "",IDC_SOUNDVOLUME,"msctls_trackbar32",TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,137,44,105,20 - EDITTEXT IDC_SOUNDVOLUME2,247,47,40,12,ES_CENTER | ES_READONLY - GROUPBOX "Sound Buffer Size",IDC_STATIC,132,73,164,31 - CONTROL "Slider1",IDC_SOUNDBUFFERRAM,"msctls_trackbar32",TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,137,81,105,19 - EDITTEXT IDC_SOUNDBUFFERMEM,247,84,40,12,ES_CENTER | ES_READONLY + GROUPBOX "Sound Emulation",IDC_SOUNDSETTINGS,5,26,120,85 + CONTROL "Disabled",IDC_SOUND0,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,13,41,101,10 + CONTROL "Disabled, but emulated",IDC_SOUND1,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,13,54,102,10 + CONTROL "Enabled",IDC_SOUND2,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,13,67,102,10 + CONTROL "Enabled, 100% accurate",IDC_SOUND3,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,13,80,101,10 + GROUPBOX "Volume",IDC_STATIC,132,42,164,31 + CONTROL "",IDC_SOUNDVOLUME,"msctls_trackbar32",TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,137,50,105,20 + EDITTEXT IDC_SOUNDVOLUME2,247,53,40,12,ES_CENTER | ES_READONLY + GROUPBOX "Sound Buffer Size",IDC_STATIC,132,79,164,31 + CONTROL "Slider1",IDC_SOUNDBUFFERRAM,"msctls_trackbar32",TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,137,87,105,19 + EDITTEXT IDC_SOUNDBUFFERMEM,247,90,40,12,ES_CENTER | ES_READONLY GROUPBOX "Settings",IDC_SOUNDINTERPOLATION2,6,114,290,60 LTEXT "Frequency:",IDC_SOUNDFREQTXT,11,148,53,8,SS_CENTERIMAGE COMBOBOX IDC_SOUNDFREQ,13,157,51,75,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP @@ -330,6 +330,7 @@ BEGIN COMBOBOX IDC_SOUNDSWAP,73,157,62,75,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP LTEXT "Swap channels:",IDC_SOUNDSWAPTXT,74,148,61,8,SS_CENTERIMAGE CONTROL "Automatic switching",IDC_SOUND_AUTO,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,14,95,103,10 + CONTROL "Exclusive mode",IDC_SOUND_EXCLUSIVE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,137,31,154,10 END IDD_LOADSAVE DIALOGEX 0, 0, 302, 241 diff --git a/od-win32/sounddep/sound.c b/od-win32/sounddep/sound.c index 96bb9cf0..74ff760d 100644 --- a/od-win32/sounddep/sound.c +++ b/od-win32/sounddep/sound.c @@ -34,6 +34,9 @@ #include #include #include +#include +#include +#include #include #include @@ -82,6 +85,24 @@ struct sound_dp HANDLE paevent; int opacounter; int pablocking; + +// wasapi + + IMMDevice *pDevice; + IAudioClient *pAudioClient; + IAudioRenderClient *pRenderClient; + IMMDeviceEnumerator *pEnumerator; + IAudioClock *pAudioClock; + REFERENCE_TIME hnsRequestedDuration; + HANDLE wasapihandle; + int bufferFrameCount; + UINT64 wasapiclock; + UINT64 wasapiframes; + int wasapiexclusive; + int framecounter; + int sndbuf; + int wasapigoodsize; + int sndbufframes; }; #define ADJUST_SIZE 30 @@ -94,6 +115,7 @@ int sound_debug = 0; int sound_mode_skip = 0; static int have_sound; +static int statuscnt; #define SND_MAX_BUFFER2 524288 #define SND_MAX_BUFFER 8192 @@ -169,6 +191,48 @@ static void clearbuffer (struct sound_data *sd) clearbuffer_ds (sd); } +static void pause_audio_wasapi (struct sound_data *sd) +{ + struct sound_dp *s = sd->data; + HRESULT hr; + + hr = s->pAudioClient->lpVtbl->Stop (s->pAudioClient); + if (FAILED (hr)) + write_log (L"WASAPI: Stop() %08X\n", hr); +} +static void resume_audio_wasapi (struct sound_data *sd) +{ + struct sound_dp *s = sd->data; + HRESULT hr; + BYTE *pData; + int framecnt; + + ResetEvent (s->wasapihandle); + hr = s->pAudioClient->lpVtbl->Reset (s->pAudioClient); + if (FAILED (hr)) + write_log (L"WASAPI: Reset() %08X\n", hr); + if (s->wasapiexclusive) + framecnt = s->bufferFrameCount; + else + framecnt = s->wasapigoodsize; + hr = s->pRenderClient->lpVtbl->GetBuffer (s->pRenderClient, framecnt, &pData); + if (FAILED (hr)) + return; + hr = s->pRenderClient->lpVtbl->ReleaseBuffer (s->pRenderClient, framecnt, AUDCLNT_BUFFERFLAGS_SILENT); + hr = s->pAudioClient->lpVtbl->Start (s->pAudioClient); + if (FAILED (hr)) + write_log (L"WASAPI: Start() %08X\n", hr); + if (s->wasapiexclusive) { + WaitForSingleObject (s->wasapihandle, 5 * 1000); + hr = s->pRenderClient->lpVtbl->GetBuffer (s->pRenderClient, framecnt, &pData); + if (SUCCEEDED (hr)) + hr = s->pRenderClient->lpVtbl->ReleaseBuffer (s->pRenderClient, framecnt, AUDCLNT_BUFFERFLAGS_SILENT); + } + s->wasapiframes = 0; + s->framecounter = 0; + s->sndbuf = 0; +} + static void pause_audio_ds (struct sound_data *sd) { struct sound_dp *s = sd->data; @@ -610,6 +674,283 @@ error: return 0; } +static void close_audio_wasapi (struct sound_data *sd) +{ + struct sound_dp *s = sd->data; + + if (s->pRenderClient) + s->pRenderClient->lpVtbl->Release (s->pRenderClient); + if (s->pAudioClock) + s->pAudioClock->lpVtbl->Release (s->pAudioClock); + if (s->pAudioClient) + s->pAudioClient->lpVtbl->Release (s->pAudioClient); + if (s->pDevice) + s->pDevice->lpVtbl->Release (s->pDevice); + if (s->pEnumerator) + s->pEnumerator->lpVtbl->Release (s->pEnumerator); + if (s->wasapihandle) + CloseHandle (s->wasapihandle); +} + +const static GUID XIID_IAudioClient = {0x1CB9AD4C,0xDBFA,0x4c32,{0xB1,0x78,0xC2,0xF5,0x68,0xA7,0x03,0xB2}}; +const static GUID XIID_IAudioRenderClient = {0xF294ACFC,0x3146,0x4483,{0xA7,0xBF,0xAD,0xDC,0xA7,0xC2,0x60,0xE2}}; +const static GUID XIID_IMMDeviceEnumerator = {0xA95664D2,0x9614,0x4F35,{0xA7,0x46,0xDE,0x8D,0xB6,0x36,0x17,0xE6}}; +const static GUID XCLSID_MMDeviceEnumerator = {0xBCDE0395,0xE52F,0x467C,{0x8E,0x3D,0xC4,0x57,0x92,0x91,0x69,0x2E}}; +const static GUID XIID_IAudioClock = {0xCD63314F,0x3FBA,0x4a1b,{0x81,0x2C,0xEF,0x96,0x35,0x87,0x28,0xE7}}; + +static int open_audio_wasapi (struct sound_data *sd, int index, int exclusive) +{ + HRESULT hr; + struct sound_dp *s = sd->data; + WAVEFORMATEX *pwfx; + WAVEFORMATEXTENSIBLE wavfmt; + int final; + LPWSTR name = NULL; + int rn[4], rncnt; + AUDCLNT_SHAREMODE sharemode; + int size; + + sd->devicetype = SOUND_DEVICE_WASAPI; + s->wasapiexclusive = exclusive; + + if (s->wasapiexclusive) + sharemode = AUDCLNT_SHAREMODE_EXCLUSIVE; + else + sharemode = AUDCLNT_SHAREMODE_SHARED; + + hr = CoCreateInstance (&XCLSID_MMDeviceEnumerator, NULL, + CLSCTX_ALL, &XIID_IMMDeviceEnumerator, + (void**)&s->pEnumerator); + if (FAILED (hr)) { + write_log (L"WASAPI: %d\n", hr); + goto error; + } + + if (sound_devices[index].alname == NULL) + hr = s->pEnumerator->lpVtbl->GetDefaultAudioEndpoint (s->pEnumerator, eRender, eMultimedia, &s->pDevice); + else + hr = s->pEnumerator->lpVtbl->GetDevice (s->pEnumerator, sound_devices[index].alname, &s->pDevice); + if (FAILED (hr)) { + write_log (L"WASAPI: GetDevice(%s) %08X\n", sound_devices[index].alname ? sound_devices[index].alname : L"NULL", hr); + goto error; + } + + hr = s->pDevice->lpVtbl->GetId (s->pDevice, &name); + if (FAILED (hr)) { + write_log (L"WASAPI: GetId() %08X\n", hr); + goto error; + } + + hr = s->pDevice->lpVtbl->Activate (s->pDevice, &XIID_IAudioClient, CLSCTX_ALL, NULL, (void**)&s->pAudioClient); + if (FAILED (hr)) { + write_log (L"WASAPI: Activate() %d\n", hr); + goto error; + } + + hr = s->pAudioClient->lpVtbl->GetMixFormat (s->pAudioClient, &pwfx); + if (FAILED (hr)) { + write_log (L"WASAPI: GetMixFormat() %08X\n", hr); + goto error; + } + + hr = s->pAudioClient->lpVtbl->GetDevicePeriod (s->pAudioClient, NULL, &s->hnsRequestedDuration); + if (FAILED (hr)) { + write_log (L"WASAPI: GetDevicePeriod() %08X\n", hr); + goto error; + } + + final = 0; + rncnt = 0; + for (;;) { + + if (sd->channels == 6) { + rn[0] = KSAUDIO_SPEAKER_5POINT1; + rn[1] = KSAUDIO_SPEAKER_5POINT1_SURROUND; + rn[2] = 0; + } else if (sd->channels == 4) { + rn[0] = KSAUDIO_SPEAKER_QUAD; + rn[1] = KSAUDIO_SPEAKER_QUAD_SURROUND; + rn[2] = KSAUDIO_SPEAKER_SURROUND; + rn[3] = 0; + } else if (sd->channels == 2) { + rn[0] = KSAUDIO_SPEAKER_STEREO; + rn[1] = 0; + } else { + rn[0] = KSAUDIO_SPEAKER_MONO; + rn[1] = 0; + } + + memset (&wavfmt, 0, sizeof wavfmt); + wavfmt.Format.nChannels = sd->channels; + wavfmt.Format.nSamplesPerSec = sd->freq; + wavfmt.Format.wBitsPerSample = 16; + wavfmt.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wavfmt.Format.cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX); + wavfmt.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + wavfmt.Samples.wValidBitsPerSample = 16; + wavfmt.dwChannelMask = rn[rncnt]; + wavfmt.Format.nBlockAlign = wavfmt.Format.wBitsPerSample / 8 * wavfmt.Format.nChannels; + wavfmt.Format.nAvgBytesPerSec = wavfmt.Format.nBlockAlign * wavfmt.Format.nSamplesPerSec; + CoTaskMemFree (pwfx); + pwfx = NULL; + hr = s->pAudioClient->lpVtbl->IsFormatSupported (s->pAudioClient, sharemode, &wavfmt.Format, &pwfx); + if (SUCCEEDED (hr) && hr != S_FALSE) + break; + write_log (L"WASAPI: IsFormatSupported(%d,%08X,%d) %08X\n", sd->channels, rn[rncnt], sd->freq, hr); + if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT) + goto error; + rncnt++; + if (rn[rncnt]) + continue; + if (final) + goto error; + rncnt = 0; + if (sd->freq < 44100) { + sd->freq = 44100; + continue; + } + if (sd->freq < 48000) { + sd->freq = 48000; + continue; + } + if (sd->channels != 2) { + sd->channels = 2; + continue; + } + final = 1; + if (pwfx == NULL) + goto error; + sd->channels = pwfx->nChannels; + sd->freq = pwfx->nSamplesPerSec; + } + + if (!s->wasapiexclusive) { + size = sd->sndbufsize * sd->channels * 16 / 8; + s->snd_configsize = size; + sd->sndbufsize = size / 32; + size /= (sd->channels * 16 / 8); + } else { + s->hnsRequestedDuration *= sd->sndbufsize / 512; + } + + s->bufferFrameCount = (UINT32)( // frames = + 1.0 * s->hnsRequestedDuration * // hns * + wavfmt.Format.nSamplesPerSec / // (frames / s) / + 1000 / // (ms / s) / + 10000 // (hns / s) / + + 0.5); // rounding + + if (!s->wasapiexclusive) { + if (s->bufferFrameCount < size) { + s->bufferFrameCount = size; + s->hnsRequestedDuration = // hns = + (REFERENCE_TIME)( + 10000.0 * // (hns / ms) * + 1000 * // (ms / s) * + s->bufferFrameCount / // frames / + wavfmt.Format.nSamplesPerSec // (frames / s) + + 0.5 // rounding + ); + } + } + + hr = s->pAudioClient->lpVtbl->Initialize (s->pAudioClient, + sharemode, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + s->hnsRequestedDuration, s->wasapiexclusive ? s->hnsRequestedDuration : 0, &wavfmt.Format, NULL); + if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) { + hr = s->pAudioClient->lpVtbl->GetBufferSize (s->pAudioClient, &s->bufferFrameCount); + if (FAILED (hr)) { + write_log (L"WASAPI: GetBufferSize() %08X\n", hr); + goto error; + } + s->pAudioClient->lpVtbl->Release (s->pAudioClient); + s->hnsRequestedDuration = // hns = + (REFERENCE_TIME)( + 10000.0 * // (hns / ms) * + 1000 * // (ms / s) * + s->bufferFrameCount / // frames / + wavfmt.Format.nSamplesPerSec // (frames / s) + + 0.5 // rounding + ); + s->hnsRequestedDuration *= sd->sndbufsize / 512; + hr = s->pDevice->lpVtbl->Activate (s->pDevice, &XIID_IAudioClient, CLSCTX_ALL, NULL, (void**)&s->pAudioClient); + if (FAILED (hr)) { + write_log (L"WASAPI: Activate() %08X\n", hr); + goto error; + } + hr = s->pAudioClient->lpVtbl->Initialize (s->pAudioClient, + sharemode, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + s->hnsRequestedDuration, s->wasapiexclusive ? s->hnsRequestedDuration : 0, &wavfmt.Format, NULL); + } + if (FAILED (hr)) { + write_log (L"WASAPI: Initialize() %08X\n", hr); + goto error; + } + + s->wasapihandle = CreateEvent(NULL, FALSE, FALSE, NULL); + hr = s->pAudioClient->lpVtbl->SetEventHandle (s->pAudioClient, s->wasapihandle); + if (FAILED (hr)) { + write_log (L"WASAPI: SetEventHandle() %08X\n", hr); + goto error; + } + + hr = s->pAudioClient->lpVtbl->GetBufferSize (s->pAudioClient, &s->bufferFrameCount); + if (FAILED (hr)) { + write_log (L"WASAPI: GetBufferSize() %08X\n", hr); + goto error; + } + + s->hnsRequestedDuration = // hns = + (REFERENCE_TIME)( + 10000.0 * // (hns / ms) * + 1000 * // (ms / s) * + s->bufferFrameCount / // frames / + wavfmt.Format.nSamplesPerSec // (frames / s) + + 0.5 // rounding + ); + + hr = s->pAudioClient->lpVtbl->GetService (s->pAudioClient, &XIID_IAudioRenderClient, (void**)&s->pRenderClient); + if (FAILED (hr)) { + write_log (L"WASAPI: GetService(IID_IAudioRenderClient) %08X\n", hr); + goto error; + } + + hr = s->pAudioClient->lpVtbl->GetService (s->pAudioClient, &XIID_IAudioClock, (void**)&s->pAudioClock); + if (FAILED (hr)) { + write_log (L"WASAPI: GetService(IID_IAudioClock) %08X\n", hr); + } else { + hr = s->pAudioClock->lpVtbl->GetFrequency (s->pAudioClock, &s->wasapiclock); + if (FAILED (hr)) { + write_log (L"WASAPI: GetFrequency() %08X\n", hr); + } + } + + if (s->wasapiexclusive) { + sd->sndbufsize = s->bufferFrameCount * sd->channels * 16 / 8; + } else { + int v = s->bufferFrameCount * sd->channels * 16 / 8; + v /= 2; + if (sd->sndbufsize > v) + sd->sndbufsize = v; + s->wasapigoodsize =s->bufferFrameCount / 2; + } + s->sndbufframes = sd->sndbufsize / (sd->channels * 16 / 8); + + write_log(L"WASAPI: '%s'\nWASAPI: EX=%d CH=%d FREQ=%d BUF=%d (%d)\n", + name, s->wasapiexclusive, sd->channels, sd->freq, sd->sndbufsize, s->bufferFrameCount); + + CoTaskMemFree (pwfx); + CoTaskMemFree (name); + + return 1; + +error: + CoTaskMemFree (pwfx); + CoTaskMemFree (name); + close_audio_wasapi (sd); + return 0; +} + static int open_audio_ds (struct sound_data *sd, int index) { struct sound_dp *s = sd->data; @@ -759,7 +1100,7 @@ error: return 0; } -int open_sound_device (struct sound_data *sd, int index, int bufsize, int freq, int channels) +int open_sound_device (struct sound_data *sd, int index, int exclusive, int bufsize, int freq, int channels) { int ret = 0; struct sound_dp *sdp = xcalloc (sizeof (struct sound_dp), 1); @@ -774,6 +1115,8 @@ int open_sound_device (struct sound_data *sd, int index, int bufsize, int freq, ret = open_audio_ds (sd, index); else if (sound_devices[index].type == SOUND_DEVICE_PA) ret = open_audio_pa (sd, index); + else if (sound_devices[index].type == SOUND_DEVICE_WASAPI) + ret = open_audio_wasapi (sd, index, exclusive); sd->samplesize = sd->channels * 2; return ret; } @@ -786,6 +1129,8 @@ void close_sound_device (struct sound_data *sd) close_audio_ds (sd); else if (sd->devicetype == SOUND_DEVICE_PA) close_audio_pa (sd); + else if (sd->devicetype == SOUND_DEVICE_WASAPI) + close_audio_wasapi (sd); xfree (sd->data); sd->data = NULL; } @@ -798,6 +1143,8 @@ void pause_sound_device (struct sound_data *sd) pause_audio_ds (sd); else if (sd->devicetype == SOUND_DEVICE_PA) pause_audio_pa (sd); + else if (sd->devicetype == SOUND_DEVICE_WASAPI) + pause_audio_wasapi (sd); } void resume_sound_device (struct sound_data *sd) { @@ -807,6 +1154,8 @@ void resume_sound_device (struct sound_data *sd) resume_audio_ds (sd); else if (sd->devicetype == SOUND_DEVICE_PA) resume_audio_pa (sd); + else if (sd->devicetype == SOUND_DEVICE_WASAPI) + resume_audio_wasapi (sd); sd->paused = 0; } @@ -833,7 +1182,7 @@ static int open_sound (void) if (currprefs.win32_soundcard >= num) currprefs.win32_soundcard = changed_prefs.win32_soundcard = 0; ch = get_audio_nativechannels (currprefs.sound_stereo); - ret = open_sound_device (sdp, currprefs.win32_soundcard, size, currprefs.sound_freq, ch); + ret = open_sound_device (sdp, currprefs.win32_soundcard, currprefs.win32_soundexclusive, size, currprefs.sound_freq, ch); if (!ret) return 0; currprefs.sound_freq = changed_prefs.sound_freq = sdp->freq; @@ -930,6 +1279,8 @@ void sound_setadjust (double v) v = 0; mult = (1000.0 + v); + if (avioutput_audio) + mult = 1000.0; if (isvsync () || (avioutput_audio && !compiled_code)) { vsynctime = vsynctime_orig; scaled_sample_evtime = scaled_sample_evtime_orig * mult / 1000.0; @@ -1098,8 +1449,7 @@ static void finish_sound_buffer_al (struct sound_data *sd, uae_u16 *sndbuffer) if ((0 || sound_debug) && !(tfprev % 10)) write_log (L"s=%+02.1f\n", skipmode); tfprev = timeframes; - if (!avioutput_audio) - sound_setadjust (skipmode); + sound_setadjust (skipmode); } } @@ -1111,6 +1461,7 @@ int blocking_sound_device (struct sound_data *sd) struct sound_dp *s = sd->data; if (sd->devicetype == SOUND_DEVICE_DS) { + HRESULT hr; DWORD playpos, safepos; int diff; @@ -1130,6 +1481,7 @@ int blocking_sound_device (struct sound_data *sd) return 0; } else if (sd->devicetype == SOUND_DEVICE_AL) { + int v = 0; alGetError (); alGetSourcei (s->al_Source, AL_BUFFERS_QUEUED, &v); @@ -1138,6 +1490,13 @@ int blocking_sound_device (struct sound_data *sd) if (v < AL_BUFFERS) return 0; return 1; + + } else if (sd->devicetype == SOUND_DEVICE_WASAPI) { + + if (WaitForSingleObject (s->wasapihandle, 0) == WAIT_TIMEOUT) + return 0; + return 1; + } return -1; } @@ -1168,6 +1527,130 @@ int get_offset_sound_device (struct sound_data *sd) return -1; } +static double sync_sound (double m) +{ + double skipmode; + if (isvsync ()) { + + skipmode = pow (m < 0 ? -m : m, EXP) / 8; + if (m < 0) + skipmode = -skipmode; + if (skipmode < -ADJUST_VSSIZE) + skipmode = -ADJUST_VSSIZE; + if (skipmode > ADJUST_VSSIZE) + skipmode = ADJUST_VSSIZE; + + } else if (1) { + + skipmode = pow (m < 0 ? -m : m, EXP) / 2; + if (m < 0) + skipmode = -skipmode; + if (skipmode < -ADJUST_SIZE) + skipmode = -ADJUST_SIZE; + if (skipmode > ADJUST_SIZE) + skipmode = ADJUST_SIZE; + } + + return skipmode; +} + +static void finish_sound_buffer_wasapi (struct sound_data *sd, uae_u16 *sndbuffer) +{ + struct sound_dp *s = sd->data; + HRESULT hr; + BYTE *pData; + DWORD v; + double skipmode; + + if (sd->paused) + return; + + s->framecounter++; + if (s->framecounter > 50) { + s->sndbuf = s->sndbuf / s->framecounter; + s->framecounter = 2; + } + if (s->wasapiexclusive) { + + v = WaitForSingleObject (s->wasapihandle, 0); + if (v == WAIT_OBJECT_0) { + gui_data.sndbuf_status = -1; + statuscnt = SND_STATUSCNT; + pause_audio_wasapi (sd); + resume_audio_wasapi (sd); + return; + } else if (v == WAIT_TIMEOUT) { + if (WaitForSingleObject (s->wasapihandle, 2000) != WAIT_OBJECT_0) { + write_log (L"WASAPI: event timed out\n"); + return; + } + } else { + return; + } + + if (s->wasapiclock) { + + double v, v2; + UINT64 pos; + hr = s->pAudioClock->lpVtbl->GetPosition (s->pAudioClock, &pos, NULL); + if (FAILED (hr)) + return; + v = (double)pos; + v /= s->wasapiclock; + v2 = s->wasapiframes / (double)sd->freq; + v = v2 - v; + v2 = v * 10000.0 / ((double)s->bufferFrameCount / (double)sd->freq); + s->sndbuf += v2 + 10000.0; + gui_data.sndbuf = s->sndbuf / s->framecounter; + if ((s->framecounter & 7) == 7) { + skipmode = sync_sound (gui_data.sndbuf / 70.0); + sound_setadjust (skipmode); + } + + } + + hr = s->pRenderClient->lpVtbl->GetBuffer (s->pRenderClient, s->bufferFrameCount, &pData); + if (FAILED (hr)) { + write_log (L"WASAPI: GetBuffer() %08X\n", hr); + return; + } + memcpy (pData, sndbuffer, s->bufferFrameCount * sd->channels * 16 / 8); + hr = s->pRenderClient->lpVtbl->ReleaseBuffer (s->pRenderClient, s->bufferFrameCount, 0); + s->wasapiframes += s->bufferFrameCount; + + } else { + + int numFramesPadding, avail; + + for (;;) { + hr = s->pAudioClient->lpVtbl->GetCurrentPadding (s->pAudioClient, &numFramesPadding); + if (FAILED (hr)) { + write_log (L"WASAPI: GetCurrentPadding() %08X\n", hr); + return; + } + avail = s->bufferFrameCount - numFramesPadding; + if (avail >= s->sndbufframes) + break; + gui_data.sndbuf_status = 1; + statuscnt = SND_STATUSCNT; + sleep_millis (1); + } + s->sndbuf += (s->wasapigoodsize - avail) * 1000 / s->wasapigoodsize; + gui_data.sndbuf = s->sndbuf / s->framecounter; + if (s->framecounter == 2) { + skipmode = sync_sound (gui_data.sndbuf / 70.0); + sound_setadjust (skipmode); + } + hr = s->pRenderClient->lpVtbl->GetBuffer (s->pRenderClient, s->sndbufframes, &pData); + if (SUCCEEDED (hr)) { + memcpy (pData, sndbuffer, sd->sndbufsize); + s->pRenderClient->lpVtbl->ReleaseBuffer (s->pRenderClient, s->sndbufframes, 0); + } + + } + +} + static void finish_sound_buffer_ds (struct sound_data *sd, uae_u16 *sndbuffer) { struct sound_dp *s = sd->data; @@ -1178,22 +1661,9 @@ static void finish_sound_buffer_ds (struct sound_data *sd, uae_u16 *sndbuffer) DWORD s1, s2; int diff; int counter; - static int statuscnt; - - if (sd == sdp) { - if (statuscnt > 0) { - statuscnt--; - if (statuscnt == 0) - gui_data.sndbuf_status = 0; - } - if (gui_data.sndbuf_status == 3) - gui_data.sndbuf_status = 0; - } if (!sd->waiting_for_buffer) return; - if (savestate_state) - return; if (sd->waiting_for_buffer == 1) { hr = IDirectSoundBuffer_Play (s->lpDSBsecondary, 0, 0, DSBPLAY_LOOPING); @@ -1339,38 +1809,16 @@ static void finish_sound_buffer_ds (struct sound_data *sd, uae_u16 *sndbuffer) vdiff = diff - s->snd_writeoffset; m = 100.0 * vdiff / s->max_sndbufsize; - - if (isvsync ()) { - - skipmode = pow (m < 0 ? -m : m, EXP) / 8; - if (m < 0) - skipmode = -skipmode; - if (skipmode < -ADJUST_VSSIZE) - skipmode = -ADJUST_VSSIZE; - if (skipmode > ADJUST_VSSIZE) - skipmode = ADJUST_VSSIZE; - - } else { - - skipmode = pow (m < 0 ? -m : m, EXP) / 2; - if (m < 0) - skipmode = -skipmode; - if (skipmode < -ADJUST_SIZE) - skipmode = -ADJUST_SIZE; - if (skipmode > ADJUST_SIZE) - skipmode = ADJUST_SIZE; - - } + skipmode = sync_sound (m); if (tfprev != timeframes) { + gui_data.sndbuf = vdiff * 1000 / (s->snd_maxoffset - s->snd_writeoffset); if ((0 || sound_debug) && !(tfprev % 10)) write_log (L"b=%4d,%5d,%5d,%5d d=%5d vd=%5.0f s=%+02.1f\n", sd->sndbufsize / sd->samplesize, s->snd_configsize / sd->samplesize, s->max_sndbufsize / sd->samplesize, s->dsoundbuf / sd->samplesize, diff / sd->samplesize, vdiff, skipmode); tfprev = timeframes; - if (!avioutput_audio) - sound_setadjust (skipmode); - gui_data.sndbuf = vdiff * 1000 / (s->snd_maxoffset - s->snd_writeoffset); + sound_setadjust (skipmode); } } @@ -1404,12 +1852,16 @@ static void channelswap6 (uae_s16 *sndbuffer, int len) void send_sound (struct sound_data *sd, uae_u16 *sndbuffer) { + if (savestate_state) + return; if (sd->devicetype == SOUND_DEVICE_AL) finish_sound_buffer_al (sd, sndbuffer); else if (sd->devicetype == SOUND_DEVICE_DS) finish_sound_buffer_ds (sd, sndbuffer); else if (sd->devicetype == SOUND_DEVICE_PA) finish_sound_buffer_pa (sd, sndbuffer); + else if (sd->devicetype == SOUND_DEVICE_WASAPI) + finish_sound_buffer_wasapi (sd, sndbuffer); } void finish_sound_buffer (void) @@ -1433,6 +1885,13 @@ void finish_sound_buffer (void) #endif if (!have_sound) return; + if (statuscnt > 0) { + statuscnt--; + if (statuscnt == 0) + gui_data.sndbuf_status = 0; + } + if (gui_data.sndbuf_status == 3) + gui_data.sndbuf_status = 0; send_sound (sdp, paula_sndbuffer); } @@ -1455,6 +1914,82 @@ static BOOL CALLBACK DSEnumProc (LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDr return TRUE; } +static void wasapi_enum (struct sound_device *sd) +{ + HRESULT hr; + IMMDeviceEnumerator *enumerator; + IMMDeviceCollection *col; + int i, cnt; + + write_log (L"Enumerating WASAPI devices...\n"); + for (cnt = 0; cnt < MAX_SOUND_DEVICES; cnt++) { + if (sd->name == NULL) + break; + sd++; + } + if (cnt >= MAX_SOUND_DEVICES) + return; + + hr = CoCreateInstance (&XCLSID_MMDeviceEnumerator, NULL, + CLSCTX_ALL, &XIID_IMMDeviceEnumerator, + (void**)&enumerator); + if (SUCCEEDED (hr)) { + hr = enumerator->lpVtbl->EnumAudioEndpoints (enumerator, eRender, DEVICE_STATE_ACTIVE, &col); + if (SUCCEEDED (hr)) { + UINT num; + hr = col->lpVtbl->GetCount (col, &num); + if (SUCCEEDED (hr)) { + for (i = 0; i < num && cnt < MAX_SOUND_DEVICES; i++) { + IMMDevice *dev; + LPWSTR devid = NULL; + LPWSTR devname = NULL; + hr = col->lpVtbl->Item (col, i, &dev); + if (SUCCEEDED (hr)) { + IPropertyStore *prop; + dev->lpVtbl->GetId (dev, &devid); + hr = dev->lpVtbl->OpenPropertyStore (dev, STGM_READ, &prop); + if (SUCCEEDED (hr)) { + PROPVARIANT pv; + PropVariantInit (&pv); + hr = prop->lpVtbl->GetValue (prop, &PKEY_Device_FriendlyName, &pv); + if (SUCCEEDED (hr)) { + devname = my_strdup (pv.pwszVal); + } + PropVariantClear (&pv); + prop->lpVtbl->Release (prop); + } + dev->lpVtbl->Release (dev); + } + if (devid && devname) { + TCHAR tmp[MAX_DPATH]; + if (i == 0) { + sd->cfgname = my_strdup (L"WASAPI:Default Audio Device"); + sd->type = SOUND_DEVICE_WASAPI; + sd->name = my_strdup (L"Default Audio Device"); + sd->alname = NULL; + sd++; + cnt++; + } + if (cnt < MAX_SOUND_DEVICES) { + _stprintf (tmp, L"WASAPI:%s", devname); + sd->cfgname = my_strdup (tmp); + sd->type = SOUND_DEVICE_WASAPI; + sd->name = my_strdup (devname); + sd->alname = my_strdup (devid); + sd++; + cnt++; + } + } + xfree (devname); + CoTaskMemFree (devid); + } + } + col->lpVtbl->Release (col); + } + enumerator->lpVtbl->Release (enumerator); + } +} + static void OpenALEnumerate (struct sound_device *sds, const char *pDeviceNames, const char *ppDefaultDevice, int skipdetect) { struct sound_device *sd; @@ -1494,9 +2029,9 @@ static void OpenALEnumerate (struct sound_device *sds, const char *pDeviceNames, ok = 1; } if (ok) { + TCHAR tmp[MAX_DPATH]; sd->type = SOUND_DEVICE_AL; if (ppDefaultDevice) { - TCHAR tmp[MAX_DPATH]; TCHAR *tdevname = au (devname); _stprintf (tmp, L"Default [%s]", tdevname); xfree (tdevname); @@ -1506,7 +2041,8 @@ static void OpenALEnumerate (struct sound_device *sds, const char *pDeviceNames, sd->alname = my_strdup_ansi (pDeviceNames); sd->name = my_strdup_ansi (pDeviceNames); } - sd->cfgname = my_strdup (sd->alname); + _stprintf (tmp, L"OPENAL:%s", sd->alname); + sd->cfgname = my_strdup (tmp); } if (ppDefaultDevice) ppDefaultDevice = NULL; @@ -1551,7 +2087,7 @@ static void PortAudioEnumerate (struct sound_device *sds) struct sound_device *sd; int num; int i, j; - TCHAR tmp[MAX_DPATH], *s1, *s2; + TCHAR tmp[MAX_DPATH], tmp2[MAX_DPATH], *s1, *s2; num = Pa_GetDeviceCount (); if (num < 0) { @@ -1585,7 +2121,8 @@ static void PortAudioEnumerate (struct sound_device *sds) xfree (s1); sd->type = SOUND_DEVICE_PA; sd->name = my_strdup (tmp); - sd->cfgname = my_strdup (tmp); + _stprintf (tmp2, L"PORTAUDIO:%s", tmp); + sd->cfgname = my_strdup (tmp2); sd->panum = j; } } @@ -1596,13 +2133,18 @@ static LONG WINAPI ExceptionFilter (struct _EXCEPTION_POINTERS * pExceptionPoint return EXCEPTION_EXECUTE_HANDLER; } +int force_directsound; int enumerate_sound_devices (void) { if (!num_sound_devices) { HMODULE l = NULL; write_log (L"Enumerating DirectSound devices..\n"); - DirectSoundEnumerate ((LPDSENUMCALLBACK)DSEnumProc, sound_devices); - DirectSoundCaptureEnumerate ((LPDSENUMCALLBACK)DSEnumProc, record_devices); + if (os_vista) + wasapi_enum (sound_devices); + if (1 || force_directsound || !os_vista) { + DirectSoundEnumerate ((LPDSENUMCALLBACK)DSEnumProc, sound_devices); + //DirectSoundCaptureEnumerate ((LPDSENUMCALLBACK)DSEnumProc, record_devices); + } __try { if (isdllversion (L"openal32.dll", 6, 14, 357, 22)) { write_log (L"Enumerating OpenAL devices..\n"); @@ -1675,8 +2217,6 @@ int enumerate_sound_devices (void) */ const static GUID XIID_MMDeviceEnumerator = {0xBCDE0395,0xE52F,0x467C, {0x8E,0x3D,0xC4,0x57,0x92,0x91,0x69,0x2E}}; -const static GUID XIID_IMMDeviceEnumerator = {0xA95664D2,0x9614,0x4F35, - {0xA7,0x46,0xDE,0x8D,0xB6,0x36,0x17,0xE6}}; const static GUID XIID_IAudioEndpointVolume = {0x5CDF2C82, 0x841E,0x4546, {0x97,0x22,0x0C,0xF7,0x40,0x78,0x22,0x9A}}; diff --git a/od-win32/sounddep/sound.h b/od-win32/sounddep/sound.h index bddbcfea..3bbef36c 100644 --- a/od-win32/sounddep/sound.h +++ b/od-win32/sounddep/sound.h @@ -42,7 +42,7 @@ struct sound_data void send_sound (struct sound_data *sd, uae_u16 *sndbuffer); -int open_sound_device (struct sound_data *sd, int index, int bufsize, int freq, int channels); +int open_sound_device (struct sound_data *sd, int index, int exclusive, int bufsize, int freq, int channels); void close_sound_device (struct sound_data *sd); void pause_sound_device (struct sound_data *sd); void resume_sound_device (struct sound_data *sd); @@ -50,14 +50,22 @@ void set_volume_sound_device (struct sound_data *sd, int volume, int mute); int get_offset_sound_device (struct sound_data *sd); int blocking_sound_device (struct sound_data *sd); +static uae_u16 *paula_sndbufpt_prev, *paula_sndbufpt_start; -STATIC_INLINE void check_sound_buffers (int outputsample, int doublesample) +STATIC_INLINE void set_sound_buffers (void) { - static uae_u16 *paula_sndbufpt_prev; - uae_u16 *start; +#if 0 + paula_sndbufpt_prev = paula_sndbufpt_start; + paula_sndbufpt_start = paula_sndbufpt; +#endif +} + +STATIC_INLINE void check_sound_buffers (void) +{ +#if 0 int len; +#endif - start = paula_sndbufpt; if (currprefs.sound_stereo == SND_4CH_CLONEDSTEREO) { ((uae_u16*)paula_sndbufpt)[0] = ((uae_u16*)paula_sndbufpt)[-2]; ((uae_u16*)paula_sndbufpt)[1] = ((uae_u16*)paula_sndbufpt)[-1]; @@ -72,30 +80,34 @@ STATIC_INLINE void check_sound_buffers (int outputsample, int doublesample) p[1] = sum >> 3; paula_sndbufpt = (uae_u16 *)(((uae_u8 *)paula_sndbufpt) + 4 * 2); } - if (outputsample == 0) { - paula_sndbufpt_prev = start; +#if 0 + if (outputsample == 0) return; - } - len = paula_sndbufpt - start; + len = paula_sndbufpt - paula_sndbufpt_start; if (outputsample < 0) { int i; uae_s16 *p1 = (uae_s16*)paula_sndbufpt_prev; - uae_s16 *p2 = (uae_s16*)start; - for (i = 0; i < len; i++) - p1[i] = (p1[i] + p2[i]) / 2; - paula_sndbufpt -= len; + uae_s16 *p2 = (uae_s16*)paula_sndbufpt_start; + for (i = 0; i < len; i++) { + *p1 = (*p1 + *p2) / 2; + } + paula_sndbufpt = paula_sndbufpt_start; } +#endif if ((uae_u8*)paula_sndbufpt - (uae_u8*)paula_sndbuffer >= paula_sndbufsize) { finish_sound_buffer (); paula_sndbufpt = paula_sndbuffer; } - if (doublesample) { - memcpy (paula_sndbufpt, start, len * 2); +#if 0 + while (doublesample-- > 0) { + memcpy (paula_sndbufpt, paula_sndbufpt_start, len * 2); + paula_sndbufpt += len; if ((uae_u8*)paula_sndbufpt - (uae_u8*)paula_sndbuffer >= paula_sndbufsize) { finish_sound_buffer (); paula_sndbufpt = paula_sndbuffer; } } +#endif } STATIC_INLINE void clear_sound_buffers (void) diff --git a/od-win32/win32.c b/od-win32/win32.c index ed52b64f..cc138e41 100644 --- a/od-win32/win32.c +++ b/od-win32/win32.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "resource" @@ -87,6 +88,7 @@ #endif extern int harddrive_dangerous, do_rdbdump, aspi_allow_all, no_rawinput, rawkeyboard; +extern int force_directsound; int log_scsi, log_net, uaelib_debug; int pissoff_value = 25000; unsigned int fpucontrol; @@ -117,6 +119,7 @@ static int start_data = 0; static void *tablet; HCURSOR normalcursor; static HWND hwndNextViewer; +static HANDLE AVTask; TCHAR VersionStr[256]; TCHAR BetaStr[64]; @@ -649,6 +652,10 @@ static void winuae_active (HWND hWnd, int minimized) lcd_priority (1); #endif clipboard_active (hAmigaWnd, 1); + if (os_vista && AVTask == NULL) { + DWORD taskIndex = 0; + AVTask = AvSetMmThreadCharacteristics (TEXT("Pro Audio"), &taskIndex); + } } static void winuae_inactive (HWND hWnd, int minimized) @@ -657,6 +664,9 @@ static void winuae_inactive (HWND hWnd, int minimized) int wasfocus = focus; write_log (L"winuae_inactive(%d)\n", minimized); + if (AVTask) + AvRevertMmThreadCharacteristics (AVTask); + AVTask = NULL; if (minimized) exit_gui (0); focus = 0; @@ -1807,7 +1817,7 @@ HMODULE language_load (WORD language) if (vsFileInfo && HIWORD(vsFileInfo->dwProductVersionMS) == UAEMAJOR && LOWORD(vsFileInfo->dwProductVersionMS) == UAEMINOR - && (HIWORD(vsFileInfo->dwProductVersionLS) == UAESUBREV || HIWORD(vsFileInfo->dwProductVersionLS) == UAESUBREV - 1)) { + && (HIWORD(vsFileInfo->dwProductVersionLS) == UAESUBREV)) { success = TRUE; write_log (L"Translation DLL '%s' loaded and enabled\n", dllbuf); } else { @@ -2109,6 +2119,7 @@ void target_default_options (struct uae_prefs *p, int type) p->win32_inactive_pause = 0; p->win32_ctrl_F11_is_quit = 0; p->win32_soundcard = 0; + p->win32_soundexclusive = 0; p->win32_active_priority = 1; p->win32_inactive_priority = 2; p->win32_iconified_priority = 3; @@ -2132,6 +2143,7 @@ void target_default_options (struct uae_prefs *p, int type) p->win32_rtgscaleaspectratio = -1; p->win32_rtgvblankrate = 0; p->win32_fscodepage = 0; + p->win32_commandpath[0] = 0; } if (type == 1 || type == 0) { p->win32_uaescsimode = get_aspi (p->win32_uaescsimode); @@ -2188,6 +2200,7 @@ void target_save_options (struct zfile *f, struct uae_prefs *p) cfgfile_target_dwrite (f, L"soundcard", L"%d", p->win32_soundcard); if (sound_devices[p->win32_soundcard].cfgname) cfgfile_target_dwrite_str (f, L"soundcardname", sound_devices[p->win32_soundcard].cfgname); + cfgfile_target_dwrite_bool (f, L"soundcard_exclusive", p->win32_soundexclusive); cfgfile_target_dwrite (f, L"cpu_idle", L"%d", p->cpu_idle); cfgfile_target_dwrite_bool (f, L"notaskbarbutton", p->win32_notaskbarbutton); cfgfile_target_dwrite_bool (f, L"always_on_top", p->win32_alwaysontop); @@ -2198,6 +2211,7 @@ void target_save_options (struct zfile *f, struct uae_prefs *p) cfgfile_target_dwrite (f, L"kbledmode", L"%d", p->win32_kbledmode); cfgfile_target_dwrite_bool (f, L"powersavedisabled", p->win32_powersavedisabled); cfgfile_target_dwrite (f, L"filesystem_codepage", L"%d", p->win32_fscodepage); + cfgfile_target_dwrite_str (f, L"exec", p->win32_commandpath); } @@ -2242,9 +2256,11 @@ int target_parse_option (struct uae_prefs *p, TCHAR *option, TCHAR *value) || cfgfile_intval (option, value, L"midiout_device", &p->win32_midioutdev, 1) || cfgfile_intval (option, value, L"midiin_device", &p->win32_midiindev, 1) || cfgfile_intval (option, value, L"soundcard", &p->win32_soundcard, 1) + || cfgfile_yesno (option, value, L"soundcard_exclusive", &p->win32_soundexclusive) || cfgfile_yesno (option, value, L"notaskbarbutton", &p->win32_notaskbarbutton) || cfgfile_yesno (option, value, L"always_on_top", &p->win32_alwaysontop) || cfgfile_yesno (option, value, L"powersavedisabled", &p->win32_powersavedisabled) + || cfgfile_string (option, value, L"exec", p->win32_commandpath, sizeof p->win32_commandpath / sizeof (TCHAR)) || cfgfile_intval (option, value, L"specialkey", &p->win32_specialkey, 1) || cfgfile_intval (option, value, L"guikey", &p->win32_guikey, 1) || cfgfile_intval (option, value, L"kbledmode", &p->win32_kbledmode, 1) @@ -3531,6 +3547,10 @@ static int parseargs (const TCHAR *arg, const TCHAR *np, const TCHAR *np2) rawkeyboard = 1; return 1; } + if (!_tcscmp (arg, L"-directsound")) { + force_directsound = 1; + return 1; + } if (!_tcscmp (arg, L"-scsilog")) { log_scsi = 1; return 1; @@ -3689,7 +3709,7 @@ static int parseargs (const TCHAR *arg, const TCHAR *np, const TCHAR *np2) static TCHAR **parseargstring (TCHAR *s) { - int cnt; + int cnt, i; TCHAR **args; if (_tcslen (s) == 0) @@ -3698,6 +3718,7 @@ static TCHAR **parseargstring (TCHAR *s) cnt = 0; for (;;) { TCHAR *p = s; + TCHAR *d, prev; int skip = 0; while (*p && _istspace (*p)) p++; @@ -3714,8 +3735,19 @@ static TCHAR **parseargstring (TCHAR *s) while (*p && !_istspace (*p)) p++; } - args[cnt] = xcalloc (p - s + 1, sizeof (TCHAR)); - memcpy (args[cnt++], s, (p - s) * sizeof (TCHAR)); + args[cnt] = d = xcalloc (p - s + 1, sizeof (TCHAR)); + memcpy (d, s, (p - s) * sizeof (TCHAR)); + prev = 0; + for (i = 0; d[i]; i++) { + TCHAR c = d[i]; + if (c == '\"' || c == '\'') { + memmove (&d[i], &d[i + 1], (_tcslen (&d[i + 1]) + 1) * sizeof (TCHAR)); + i--; + continue; + } + prev = c; + } + cnt++; p += skip; while (*p && _istspace (*p)) p++; diff --git a/od-win32/win32.h b/od-win32/win32.h index a2da725f..ed086bb8 100644 --- a/od-win32/win32.h +++ b/od-win32/win32.h @@ -17,8 +17,8 @@ #define WINUAEPUBLICBETA 1 -#define WINUAEBETA L"Beta 0" -#define WINUAEDATE MAKEBD(2009, 7, 9) +#define WINUAEBETA L"Beta 1" +#define WINUAEDATE MAKEBD(2009, 7, 16) #define WINUAEEXTRA L"" #define WINUAEREV L"" @@ -156,6 +156,7 @@ extern LONG WINAPI WIN32_ExceptionFilter (struct _EXCEPTION_POINTERS *pException #define SOUND_DEVICE_DS 1 #define SOUND_DEVICE_AL 2 #define SOUND_DEVICE_PA 3 +#define SOUND_DEVICE_WASAPI 4 struct sound_device { diff --git a/od-win32/win32_scale2x.c b/od-win32/win32_scale2x.c index e573de40..8268eb35 100644 --- a/od-win32/win32_scale2x.c +++ b/od-win32/win32_scale2x.c @@ -133,17 +133,6 @@ static void sizeoffset (RECT *dr, RECT *zr, int w, int h) OffsetRect (zr, w / 2, h / 2); } -static void xymult (int *x, int *y) -{ - int mult = currprefs.gfx_resolution - (currprefs.gfx_linedbl ? 1 : 0); - if (mult < 0) - *x *= 1 << (-mult); - else - *y *= 1 << mult; -} - -static int ppp = 320; - void getfilterrect2 (RECT *sr, RECT *dr, RECT *zr, int dst_width, int dst_height, int aw, int ah, int scale, int temp_width, int temp_height) { float srcratio, dstratio; diff --git a/od-win32/win32gui.c b/od-win32/win32gui.c index d3ad1a3f..e9b0f81c 100644 --- a/od-win32/win32gui.c +++ b/od-win32/win32gui.c @@ -5991,7 +5991,6 @@ static INT_PTR CALLBACK RTGDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM l static INT_PTR CALLBACK MemoryDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { - int v; static int recursive = 0; switch (msg) @@ -7050,20 +7049,27 @@ extern int soundpercent; static void update_soundgui (HWND hDlg) { - int bufsize; + int bufsize, canexc; TCHAR txt[20]; bufsize = exact_log2 (workprefs.sound_maxbsiz / 1024); _stprintf (txt, L"%d", bufsize); SetDlgItemText (hDlg, IDC_SOUNDBUFFERMEM, txt); - SendDlgItemMessage( hDlg, IDC_SOUNDVOLUME, TBM_SETPOS, TRUE, 100 - workprefs.sound_volume); + SendDlgItemMessage (hDlg, IDC_SOUNDVOLUME, TBM_SETPOS, TRUE, 100 - workprefs.sound_volume); _stprintf (txt, L"%d%%", 100 - workprefs.sound_volume); SetDlgItemText (hDlg, IDC_SOUNDVOLUME2, txt); - SendDlgItemMessage( hDlg, IDC_SOUNDDRIVEVOLUME, TBM_SETPOS, TRUE, 100 - workprefs.dfxclickvolume); + SendDlgItemMessage (hDlg, IDC_SOUNDDRIVEVOLUME, TBM_SETPOS, TRUE, 100 - workprefs.dfxclickvolume); _stprintf (txt, L"%d%%", 100 - workprefs.dfxclickvolume); SetDlgItemText (hDlg, IDC_SOUNDDRIVEVOLUME2, txt); + + canexc = sound_devices[workprefs.win32_soundcard].type == SOUND_DEVICE_WASAPI; + ew (hDlg, IDC_SOUND_EXCLUSIVE, canexc); + if (!canexc) + workprefs.win32_soundexclusive = 0; + CheckDlgButton (hDlg, IDC_SOUND_EXCLUSIVE, workprefs.win32_soundexclusive); + } static int soundfreqs[] = { 11025, 15000, 22050, 32000, 44100, 48000, 0 }; @@ -7243,6 +7249,7 @@ static void values_from_sounddlg (HWND hDlg) { TCHAR txt[10]; LRESULT idx; + int soundcard; idx = SendDlgItemMessage (hDlg, IDC_SOUNDFREQ, CB_GETCURSEL, 0, 0); if (idx >= 0) { @@ -7280,7 +7287,13 @@ static void values_from_sounddlg (HWND hDlg) } workprefs.sound_interpol = SendDlgItemMessage (hDlg, IDC_SOUNDINTERPOLATION, CB_GETCURSEL, 0, 0); - workprefs.win32_soundcard = SendDlgItemMessage (hDlg, IDC_SOUNDCARDLIST, CB_GETCURSEL, 0, 0L); + workprefs.win32_soundexclusive = IsDlgButtonChecked (hDlg, IDC_SOUND_EXCLUSIVE) ? 1 : 0; + soundcard = SendDlgItemMessage (hDlg, IDC_SOUNDCARDLIST, CB_GETCURSEL, 0, 0L); + if (soundcard != workprefs.win32_soundcard && soundcard != CB_ERR) { + workprefs.win32_soundcard = soundcard; + update_soundgui (hDlg); + } + switch (SendDlgItemMessage (hDlg, IDC_SOUNDFILTER, CB_GETCURSEL, 0, 0)) { case 0: @@ -7338,7 +7351,7 @@ static INT_PTR CALLBACK SoundDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM switch (msg) { case WM_INITDIALOG: { - int gotnonds = 0; + recursive++; sound_loaddrivesamples (); SendDlgItemMessage (hDlg, IDC_SOUNDBUFFERRAM, TBM_SETRANGE, TRUE, MAKELONG (MIN_SOUND_MEM, MAX_SOUND_MEM)); SendDlgItemMessage (hDlg, IDC_SOUNDBUFFERRAM, TBM_SETPAGESIZE, 0, 1); @@ -7354,18 +7367,12 @@ static INT_PTR CALLBACK SoundDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM SendDlgItemMessage (hDlg, IDC_SOUNDCARDLIST, CB_RESETCONTENT, 0, 0L); numdevs = enumerate_sound_devices (); - for (card = 0; card < numdevs; card++) { - if (sound_devices[card].type != SOUND_DEVICE_DS) - gotnonds = 1; - } for (card = 0; card < numdevs; card++) { TCHAR tmp[MAX_DPATH]; int type = sound_devices[card].type; - if (gotnonds) - _stprintf (tmp, L"%s: %s", type == SOUND_DEVICE_DS ? L"DS" : (type == SOUND_DEVICE_AL ? L"AL" : L"PA"), - sound_devices[card].name); - else - _tcscpy (tmp, sound_devices[card].name); + _stprintf (tmp, L"%s: %s", + type == SOUND_DEVICE_DS ? L"DSOUND" : (type == SOUND_DEVICE_AL ? L"OpenAL" : (type == SOUND_DEVICE_PA ? L"PortAudio" : L"WASAPI")), + sound_devices[card].name); SendDlgItemMessage (hDlg, IDC_SOUNDCARDLIST, CB_ADDSTRING, 0, (LPARAM)tmp); } if (numdevs == 0) @@ -7373,6 +7380,8 @@ static INT_PTR CALLBACK SoundDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM pages[SOUND_ID] = hDlg; currentpage = SOUND_ID; + update_soundgui (hDlg); + recursive--; } case WM_USER: recursive++; diff --git a/od-win32/winuae_msvc/winuae_msvc.vcproj b/od-win32/winuae_msvc/winuae_msvc.vcproj index 54970a00..cebc8744 100644 --- a/od-win32/winuae_msvc/winuae_msvc.vcproj +++ b/od-win32/winuae_msvc/winuae_msvc.vcproj @@ -87,13 +87,13 @@ " and all keyboard layouts with keyboard layout A (old bug) -- portaudio fallback code added, unsupported samplerate = try 44000, - 48000 and default reported before disabling sound. Same with number - of channels, unsupported channels = fall back to stereo +- "Add PC drives at startup" does not anymore mount drives that are + also configured as real harddrives - real harddrive safetycheck modified, now all drives can be mounted as long as drive does not have any Windows mounted partitions. Any drive with one or more Windows mounted partitions are only available in read @@ -27,34 +22,68 @@ Beta 1: read-write mode. - SCSI (RDB hdf emulation) write commands return proper write protected sense status if hdf is read-only +- A590/A2091 SCSI ROM 7.0 was not accepted (debugging code..) +- RDB filesystem loader still had fse_PatchFlags hack instead of + handling it 100% correctly (no functional change, at least with any + popular filesystem) +- accept also partition type 0x30 (another Amithlon like RDB drive + inside real PC partition) +- added new RTG configuration panel, more space for future options, also + old RTG setting panel was not really in correct place anymore +- command line parsing didn't handle quotes inside strings as Windows + does when running from command line + +- added bitplane DMA fetches to copper debugger (there will be separate + DMA sequence "disassembler" in future) +- Agnus bitplane DMA behavior correctly emulated when number of planes + or resolution changes mid screen. Old code was totally wrong and too + complex.. Now all my test statefiles work 100% correctly: + Disposable Hero, Bass-O-Matic/Crusaders, Innovation Part 2/Axxis + Brian The Lion "dialog" screen is corrupted again but this seems to be + AGA specific feature (SMD chips = no logic analyzer) + - CD32 CD controller emulation improved, CDXL animations should run more smoothly now, previously emulation couldn't load more than few sectors - before cd driver decided to read some previously loaded sectors again + before cd driver detected error condition and retried - added seek delays to CD32 emulation (CD32 drive has really slow seeks) -- CD32 Lotus Trilogy's Lotus 3 finally loads (stupid loader overwriting - already loaded data if CD DMA sequence is not identical to real - hardware) +- CD32 Lotus Trilogy's Lotus 3 finally loads (stupid loader partially + overwriting already loaded data if CD DMA "slot" sequencing is not + exactly correct) - CD32 CD audio moved to separate thread, no more emulator pausing when CD audio starts or track changes (possibly introduces other issues..) -- distortion in sound was possible with short square wave samples (160) -- final 16-bit sound samples always had lowest bit (or two lowest bits) - zero, now lowest bit(s) are duplicated from real lowest significant - bit(s) -- A590/A2091 SCSI ROM 7.0 was not accepted (debugging code..) -- added new RTG configuration panel, more space for future options, also - old RTG setting panel was not really in correct place anymore -- RDB filesystem loader still had fse_PatchFlags hack instead of - handling it 100% correctly (no functional change, at least with any - popular filesystem) -- D3D 2D sprites (ID3DXSPrite) used in D3D filter onscreen leds, correct + +- D3D 2D sprites (ID3DXSprite) used in D3D filter onscreen leds, correct positioning, no scaling and free transparency. Scanline texture also converted to 2D sprite, now works correctly with D3D filters (future plan: convert all DirectDraw code to D3D 2D sprites) -- accept also partition type 0x30 (another Amithlon like RDB drive - inside real PC partition) - OpenGL filter removed, totally obsolete now. Gone forever unless someone updates it. (includes correct positioning and scaling) +- built-in WASAPI sound driver implemented. Replaces DirectSound if + running on Vista or newer. WASAPI has two modes, shared and + exclusive. Shared roughly equals old DirectSound, exclusive means + sound card is exclusively used by WinUAE. Exclusive mode has lowest + possibly latency but note that there may be only one or two + supported sample rates (for example 48000). NOTE: buffer sizes + can not be directly compared between different modes. PortAudio + is now considered very unsupported (that didn't last long..) + Needs tuning, not good enough yet (especially exclusive mode) +- distortion in sound was possible with short square wave samples (160) +- final 16-bit sound samples always had lowest bit (or two lowest bits) + zero, now lowest bit(s) are duplicated from real lowest significant + bit(s) +- programmed display modes had bad sound (161b4 sound update was not + fully complete.. most stupid 1.6.1 bug so far) +- portaudio fallback code added, unsupported samplerate = try 44000, + 48000 and default reported before disabling sound. Same with number + of channels, unsupported channels = fall back to stereo + +- Vista or newer: AvSetMmThreadCharacteristics() is used to enable + task scheduling better suited for multimedia applications = more + CPU time given without slowing down lower priority tasks (which + can happen with normal priority settings) + + 1.6.1 Beta 5: (1.6.1 RC) -- 2.47.3