mirror of https://github.com/xemu-project/xemu.git
mcpx: Cleanup monitor
This commit is contained in:
parent
829ec66757
commit
395d136364
|
@ -110,9 +110,9 @@ static void se_frame(MCPXAPUState *d)
|
|||
g_dbg.gp_realtime = d->gp.realtime;
|
||||
g_dbg.ep_realtime = d->ep.realtime;
|
||||
|
||||
qemu_spin_lock(&d->vp.out_buf_lock);
|
||||
int num_bytes_free = fifo8_num_free(&d->vp.out_buf);
|
||||
qemu_spin_unlock(&d->vp.out_buf_lock);
|
||||
qemu_spin_lock(&d->monitor.fifo_lock);
|
||||
int num_bytes_free = fifo8_num_free(&d->monitor.fifo);
|
||||
qemu_spin_unlock(&d->monitor.fifo_lock);
|
||||
|
||||
/* A rudimentary calculation to determine approximately how taxed the APU
|
||||
* thread is, by measuring how much time we spend waiting for FIFO to drain
|
||||
|
@ -120,7 +120,7 @@ static void se_frame(MCPXAPUState *d)
|
|||
* =1: thread is not sleeping and likely falling behind realtime
|
||||
* <1: thread is able to complete work on time
|
||||
*/
|
||||
if (num_bytes_free < sizeof(d->apu_fifo_output)) {
|
||||
if (num_bytes_free < sizeof(d->monitor.frame_buf)) {
|
||||
int64_t sleep_start = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
|
||||
qemu_cond_wait(&d->cond, &d->lock);
|
||||
int64_t sleep_end = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
|
||||
|
@ -157,18 +157,18 @@ static void se_frame(MCPXAPUState *d)
|
|||
if (0 <= g_config.audio.volume_limit && g_config.audio.volume_limit < 1) {
|
||||
float f = pow(g_config.audio.volume_limit, M_E);
|
||||
for (int i = 0; i < 256; i++) {
|
||||
d->apu_fifo_output[i][0] *= f;
|
||||
d->apu_fifo_output[i][1] *= f;
|
||||
d->monitor.frame_buf[i][0] *= f;
|
||||
d->monitor.frame_buf[i][1] *= f;
|
||||
}
|
||||
}
|
||||
|
||||
qemu_spin_lock(&d->vp.out_buf_lock);
|
||||
num_bytes_free = fifo8_num_free(&d->vp.out_buf);
|
||||
assert(num_bytes_free >= sizeof(d->apu_fifo_output));
|
||||
fifo8_push_all(&d->vp.out_buf, (uint8_t *)d->apu_fifo_output,
|
||||
sizeof(d->apu_fifo_output));
|
||||
qemu_spin_unlock(&d->vp.out_buf_lock);
|
||||
memset(d->apu_fifo_output, 0, sizeof(d->apu_fifo_output));
|
||||
qemu_spin_lock(&d->monitor.fifo_lock);
|
||||
num_bytes_free = fifo8_num_free(&d->monitor.fifo);
|
||||
assert(num_bytes_free >= sizeof(d->monitor.frame_buf));
|
||||
fifo8_push_all(&d->monitor.fifo, (uint8_t *)d->monitor.frame_buf,
|
||||
sizeof(d->monitor.frame_buf));
|
||||
qemu_spin_unlock(&d->monitor.fifo_lock);
|
||||
memset(d->monitor.frame_buf, 0, sizeof(d->monitor.frame_buf));
|
||||
}
|
||||
|
||||
d->ep_frame_div++;
|
||||
|
@ -189,7 +189,7 @@ static void sleep_ns(int64_t ns)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void mcpx_vp_out_cb(void *opaque, uint8_t *stream, int free_b)
|
||||
static void monitor_sink_cb(void *opaque, uint8_t *stream, int free_b)
|
||||
{
|
||||
MCPXAPUState *s = MCPX_APU_DEVICE(opaque);
|
||||
|
||||
|
@ -200,9 +200,9 @@ static void mcpx_vp_out_cb(void *opaque, uint8_t *stream, int free_b)
|
|||
|
||||
int avail = 0;
|
||||
while (avail < free_b) {
|
||||
qemu_spin_lock(&s->vp.out_buf_lock);
|
||||
avail = fifo8_num_used(&s->vp.out_buf);
|
||||
qemu_spin_unlock(&s->vp.out_buf_lock);
|
||||
qemu_spin_lock(&s->monitor.fifo_lock);
|
||||
avail = fifo8_num_used(&s->monitor.fifo);
|
||||
qemu_spin_unlock(&s->monitor.fifo_lock);
|
||||
if (avail < free_b) {
|
||||
sleep_ns(1000000);
|
||||
qemu_cond_broadcast(&s->cond);
|
||||
|
@ -212,10 +212,10 @@ static void mcpx_vp_out_cb(void *opaque, uint8_t *stream, int free_b)
|
|||
int to_copy = MIN(free_b, avail);
|
||||
while (to_copy > 0) {
|
||||
uint32_t chunk_len = 0;
|
||||
qemu_spin_lock(&s->vp.out_buf_lock);
|
||||
chunk_len = fifo8_pop_buf(&s->vp.out_buf, stream, to_copy);
|
||||
qemu_spin_lock(&s->monitor.fifo_lock);
|
||||
chunk_len = fifo8_pop_buf(&s->monitor.fifo, stream, to_copy);
|
||||
assert(chunk_len <= to_copy);
|
||||
qemu_spin_unlock(&s->vp.out_buf_lock);
|
||||
qemu_spin_unlock(&s->monitor.fifo_lock);
|
||||
stream += chunk_len;
|
||||
to_copy -= chunk_len;
|
||||
}
|
||||
|
@ -223,6 +223,35 @@ static void mcpx_vp_out_cb(void *opaque, uint8_t *stream, int free_b)
|
|||
qemu_cond_broadcast(&s->cond);
|
||||
}
|
||||
|
||||
static void monitor_init(MCPXAPUState *d)
|
||||
{
|
||||
qemu_spin_init(&d->monitor.fifo_lock);
|
||||
fifo8_create(&d->monitor.fifo, 3 * (256 * 2 * 2));
|
||||
|
||||
struct SDL_AudioSpec sdl_audio_spec = {
|
||||
.freq = 48000,
|
||||
.format = AUDIO_S16LSB,
|
||||
.channels = 2,
|
||||
.samples = 512,
|
||||
.callback = monitor_sink_cb,
|
||||
.userdata = d,
|
||||
};
|
||||
|
||||
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
|
||||
fprintf(stderr, "Failed to initialize SDL audio subsystem: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SDL_AudioDeviceID sdl_audio_dev;
|
||||
sdl_audio_dev = SDL_OpenAudioDevice(NULL, 0, &sdl_audio_spec, NULL, 0);
|
||||
if (sdl_audio_dev == 0) {
|
||||
fprintf(stderr, "SDL_OpenAudioDevice failed: %s\n", SDL_GetError());
|
||||
assert(!"SDL_OpenAudioDevice failed");
|
||||
exit(1);
|
||||
}
|
||||
SDL_PauseAudioDevice(sdl_audio_dev, 0);
|
||||
}
|
||||
|
||||
static void mcpx_apu_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
MCPXAPUState *d = MCPX_APU_DEVICE(dev);
|
||||
|
@ -519,32 +548,6 @@ void mcpx_apu_init(PCIBus *bus, int devfn, MemoryRegion *ram)
|
|||
d->set_irq = false;
|
||||
d->exiting = false;
|
||||
|
||||
struct SDL_AudioSpec sdl_audio_spec = {
|
||||
.freq = 48000,
|
||||
.format = AUDIO_S16LSB,
|
||||
.channels = 2,
|
||||
.samples = 512,
|
||||
.callback = mcpx_vp_out_cb,
|
||||
.userdata = d,
|
||||
};
|
||||
|
||||
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
|
||||
fprintf(stderr, "Failed to initialize SDL audio subsystem: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SDL_AudioDeviceID sdl_audio_dev;
|
||||
sdl_audio_dev = SDL_OpenAudioDevice(NULL, 0, &sdl_audio_spec, NULL, 0);
|
||||
if (sdl_audio_dev == 0) {
|
||||
fprintf(stderr, "SDL_OpenAudioDevice failed: %s\n", SDL_GetError());
|
||||
assert(!"SDL_OpenAudioDevice failed");
|
||||
exit(1);
|
||||
}
|
||||
SDL_PauseAudioDevice(sdl_audio_dev, 0);
|
||||
|
||||
qemu_spin_init(&d->vp.out_buf_lock);
|
||||
fifo8_create(&d->vp.out_buf, 3 * (256 * 2 * 2));
|
||||
|
||||
qemu_mutex_init(&d->lock);
|
||||
qemu_cond_init(&d->cond);
|
||||
qemu_add_vm_change_state_handler(mcpx_apu_vm_state_change, d);
|
||||
|
@ -552,4 +555,6 @@ void mcpx_apu_init(PCIBus *bus, int devfn, MemoryRegion *ram)
|
|||
mcpx_apu_vp_init(d);
|
||||
qemu_thread_create(&d->apu_thread, "mcpx.apu_thread", mcpx_apu_frame_thread,
|
||||
d, QEMU_THREAD_JOINABLE);
|
||||
|
||||
monitor_init(d);
|
||||
}
|
||||
|
|
|
@ -23,13 +23,13 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum McpxApuDebugMon {
|
||||
typedef enum McpxApuDebugMonitorPoint {
|
||||
MCPX_APU_DEBUG_MON_AC97,
|
||||
MCPX_APU_DEBUG_MON_VP,
|
||||
MCPX_APU_DEBUG_MON_GP,
|
||||
MCPX_APU_DEBUG_MON_EP,
|
||||
MCPX_APU_DEBUG_MON_GP_OR_EP
|
||||
};
|
||||
} McpxApuDebugMonitorPoint;
|
||||
|
||||
struct McpxApuDebugVoice
|
||||
{
|
||||
|
@ -81,8 +81,8 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
const struct McpxApuDebug *mcpx_apu_get_debug_info(void);
|
||||
int mcpx_apu_debug_get_monitor(void);
|
||||
void mcpx_apu_debug_set_monitor(int mon);
|
||||
McpxApuDebugMonitorPoint mcpx_apu_debug_get_monitor(void);
|
||||
void mcpx_apu_debug_set_monitor(McpxApuDebugMonitorPoint monitor);
|
||||
void mcpx_apu_debug_isolate_voice(uint16_t v);
|
||||
void mcpx_apu_debug_clear_isolations(void);
|
||||
void mcpx_apu_debug_toggle_mute(uint16_t v);
|
||||
|
|
|
@ -93,12 +93,17 @@ typedef struct MCPXAPUState {
|
|||
|
||||
uint32_t regs[0x20000];
|
||||
|
||||
int mon;
|
||||
int ep_frame_div;
|
||||
int sleep_acc;
|
||||
int frame_count;
|
||||
int64_t frame_count_time;
|
||||
int16_t apu_fifo_output[256][2]; // 1 EP frame (0x400 bytes), 8 buffered
|
||||
|
||||
struct {
|
||||
McpxApuDebugMonitorPoint point;
|
||||
int16_t frame_buf[256][2]; // 1 EP frame (0x400 bytes), 8 buffered
|
||||
QemuSpin fifo_lock;
|
||||
Fifo8 fifo;
|
||||
} monitor;
|
||||
} MCPXAPUState;
|
||||
|
||||
extern MCPXAPUState *g_state; // Used via debug handlers
|
||||
|
|
|
@ -53,14 +53,14 @@ void mcpx_apu_debug_set_ep_realtime_enabled(bool run)
|
|||
g_state->ep.realtime = run;
|
||||
}
|
||||
|
||||
int mcpx_apu_debug_get_monitor(void)
|
||||
McpxApuDebugMonitorPoint mcpx_apu_debug_get_monitor(void)
|
||||
{
|
||||
return g_state->mon;
|
||||
return g_state->monitor.point;
|
||||
}
|
||||
|
||||
void mcpx_apu_debug_set_monitor(int new_mon)
|
||||
void mcpx_apu_debug_set_monitor(McpxApuDebugMonitorPoint monitor)
|
||||
{
|
||||
g_state->mon = new_mon;
|
||||
g_state->monitor.point = monitor;
|
||||
}
|
||||
|
||||
void mcpx_apu_debug_isolate_voice(uint16_t v)
|
||||
|
|
|
@ -32,11 +32,11 @@ void mcpx_apu_update_dsp_preference(MCPXAPUState *d)
|
|||
}
|
||||
|
||||
if (g_config.audio.use_dsp) {
|
||||
d->mon = MCPX_APU_DEBUG_MON_GP_OR_EP;
|
||||
d->monitor.point = MCPX_APU_DEBUG_MON_GP_OR_EP;
|
||||
d->gp.realtime = true;
|
||||
d->ep.realtime = true;
|
||||
} else {
|
||||
d->mon = MCPX_APU_DEBUG_MON_VP;
|
||||
d->monitor.point = MCPX_APU_DEBUG_MON_VP;
|
||||
d->gp.realtime = false;
|
||||
d->ep.realtime = false;
|
||||
}
|
||||
|
@ -180,12 +180,12 @@ static void gp_fifo_rw(void *opaque, uint8_t *ptr, unsigned int index,
|
|||
|
||||
static bool ep_sink_samples(MCPXAPUState *d, uint8_t *ptr, size_t len)
|
||||
{
|
||||
if (d->mon == MCPX_APU_DEBUG_MON_AC97) {
|
||||
if (d->monitor.point == MCPX_APU_DEBUG_MON_AC97) {
|
||||
return false;
|
||||
} else if ((d->mon == MCPX_APU_DEBUG_MON_EP) ||
|
||||
(d->mon == MCPX_APU_DEBUG_MON_GP_OR_EP)) {
|
||||
assert(len == sizeof(d->apu_fifo_output));
|
||||
memcpy(d->apu_fifo_output, ptr, len);
|
||||
} else if ((d->monitor.point == MCPX_APU_DEBUG_MON_EP) ||
|
||||
(d->monitor.point == MCPX_APU_DEBUG_MON_GP_OR_EP)) {
|
||||
assert(len == sizeof(d->monitor.frame_buf));
|
||||
memcpy(d->monitor.frame_buf, ptr, len);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -461,15 +461,15 @@ void mcpx_apu_dsp_frame(MCPXAPUState *d, float mixbins[NUM_MIXBINS][NUM_SAMPLES_
|
|||
} while (!d->gp.dsp->core.is_idle && d->gp.realtime);
|
||||
g_dbg.gp.cycles = d->gp.dsp->core.cycle_count;
|
||||
|
||||
if ((d->mon == MCPX_APU_DEBUG_MON_GP) ||
|
||||
(d->mon == MCPX_APU_DEBUG_MON_GP_OR_EP && !ep_enabled)) {
|
||||
if ((d->monitor.point == MCPX_APU_DEBUG_MON_GP) ||
|
||||
(d->monitor.point == MCPX_APU_DEBUG_MON_GP_OR_EP && !ep_enabled)) {
|
||||
int off = (d->ep_frame_div % 8) * NUM_SAMPLES_PER_FRAME;
|
||||
for (int i = 0; i < NUM_SAMPLES_PER_FRAME; i++) {
|
||||
uint32_t l = dsp_read_memory(d->gp.dsp, 'X', 0x1400 + i);
|
||||
d->apu_fifo_output[off + i][0] = l >> 8;
|
||||
d->monitor.frame_buf[off + i][0] = l >> 8;
|
||||
uint32_t r =
|
||||
dsp_read_memory(d->gp.dsp, 'X', 0x1400 + 1 * 0x20 + i);
|
||||
d->apu_fifo_output[off + i][1] = r >> 8;
|
||||
d->monitor.frame_buf[off + i][1] = r >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1477,7 +1477,7 @@ static void voice_process(MCPXAPUState *d,
|
|||
}
|
||||
}
|
||||
|
||||
if (d->mon == MCPX_APU_DEBUG_MON_VP) {
|
||||
if (d->monitor.point == MCPX_APU_DEBUG_MON_VP) {
|
||||
/* For VP mon, simply mix all voices together here, selecting the
|
||||
* maximal volume used for any given mixbin as the overall volume for
|
||||
* this voice.
|
||||
|
@ -1599,7 +1599,7 @@ static void *voice_worker_thread(void *arg)
|
|||
|
||||
// Process queued voices
|
||||
memset(self->mixbins, 0, sizeof(self->mixbins));
|
||||
if (d->mon == MCPX_APU_DEBUG_MON_VP) {
|
||||
if (d->monitor.point == MCPX_APU_DEBUG_MON_VP) {
|
||||
memset(self->sample_buf, 0, sizeof(self->sample_buf));
|
||||
}
|
||||
for (int i = 0; i < self->queue_len; i++) {
|
||||
|
@ -1615,7 +1615,7 @@ static void *voice_worker_thread(void *arg)
|
|||
vwd->mixbins[b][s] += self->mixbins[b][s];
|
||||
}
|
||||
}
|
||||
if (d->mon == MCPX_APU_DEBUG_MON_VP) {
|
||||
if (d->monitor.point == MCPX_APU_DEBUG_MON_VP) {
|
||||
for (int i = 0; i < NUM_SAMPLES_PER_FRAME; i++) {
|
||||
d->vp.sample_buf[i][0] += self->sample_buf[i][0];
|
||||
d->vp.sample_buf[i][1] += self->sample_buf[i][1];
|
||||
|
@ -1827,15 +1827,15 @@ void mcpx_apu_vp_frame(MCPXAPUState *d, float mixbins[NUM_MIXBINS][NUM_SAMPLES_P
|
|||
}
|
||||
voice_work_dispatch(d, mixbins);
|
||||
|
||||
if (d->mon == MCPX_APU_DEBUG_MON_VP) {
|
||||
if (d->monitor.point == MCPX_APU_DEBUG_MON_VP) {
|
||||
/* Mix all voices together to hear any audible voice */
|
||||
int16_t isamp[NUM_SAMPLES_PER_FRAME * 2];
|
||||
src_float_to_short_array((float *)d->vp.sample_buf, isamp,
|
||||
NUM_SAMPLES_PER_FRAME * 2);
|
||||
int off = (d->ep_frame_div % 8) * NUM_SAMPLES_PER_FRAME;
|
||||
for (int i = 0; i < NUM_SAMPLES_PER_FRAME; i++) {
|
||||
d->apu_fifo_output[off + i][0] += isamp[2*i];
|
||||
d->apu_fifo_output[off + i][1] += isamp[2*i+1];
|
||||
d->monitor.frame_buf[off + i][0] += isamp[2*i];
|
||||
d->monitor.frame_buf[off + i][1] += isamp[2*i+1];
|
||||
}
|
||||
|
||||
memset(d->vp.sample_buf, 0, sizeof(d->vp.sample_buf));
|
||||
|
|
|
@ -79,8 +79,6 @@ typedef struct {
|
|||
MemoryRegion mmio;
|
||||
VoiceWorkDispatch voice_work_dispatch;
|
||||
MCPXAPUVoiceFilter filters[MCPX_HW_MAX_VOICES];
|
||||
QemuSpin out_buf_lock;
|
||||
Fifo8 out_buf;
|
||||
|
||||
// FIXME: Where are these stored?
|
||||
int ssl_base_page;
|
||||
|
|
|
@ -201,9 +201,9 @@ void DebugApuWindow::Draw()
|
|||
ImGui::NextColumn();
|
||||
|
||||
static int mon = 0;
|
||||
mon = mcpx_apu_debug_get_monitor();
|
||||
mon = (int)mcpx_apu_debug_get_monitor();
|
||||
if (ImGui::Combo("Monitor", &mon, "AC97\0VP Only\0GP Only\0EP Only\0GP/EP if enabled\0")) {
|
||||
mcpx_apu_debug_set_monitor(mon);
|
||||
mcpx_apu_debug_set_monitor((McpxApuDebugMonitorPoint)mon);
|
||||
}
|
||||
|
||||
static bool gp_realtime;
|
||||
|
|
Loading…
Reference in New Issue