mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
Add audio debug stats dev tool. Increase audio buffer low watermark a bit, hopefully helping #7370.
This commit is contained in:
parent
f3c3a2ddb4
commit
86cee103f3
@ -206,7 +206,9 @@ public:
|
||||
// UI
|
||||
bool bShowDebuggerOnLoad;
|
||||
int iShowFPSCounter;
|
||||
|
||||
bool bShowDebugStats;
|
||||
bool bShowAudioDebug;
|
||||
|
||||
//Analog stick tilting
|
||||
//the base x and y tilt. this inclination is treated as (0,0) and the tilt input
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "Core/Util/AudioFormat.h"
|
||||
|
||||
StereoResampler resampler;
|
||||
AudioDebugStats g_AudioDebugStats;
|
||||
|
||||
// Should be used to lock anything related to the outAudioQueue.
|
||||
// atomic locks are used on the lock. TODO: make this lock-free
|
||||
@ -93,6 +94,7 @@ static void __AudioCPUMHzChange() {
|
||||
|
||||
|
||||
void __AudioInit() {
|
||||
memset(&g_AudioDebugStats, 0, sizeof(g_AudioDebugStats));
|
||||
mixFrequency = 44100;
|
||||
|
||||
switch (g_Config.iAudioLatency) {
|
||||
@ -371,3 +373,8 @@ int __AudioMix(short *outstereo, int numFrames, int sampleRate) {
|
||||
resampler.Mix(outstereo, numFrames, false, sampleRate);
|
||||
return numFrames;
|
||||
}
|
||||
|
||||
const AudioDebugStats *__AudioGetDebugStats() {
|
||||
resampler.GetAudioDebugStats(&g_AudioDebugStats);
|
||||
return &g_AudioDebugStats;
|
||||
}
|
@ -19,6 +19,16 @@
|
||||
|
||||
#include "sceAudio.h"
|
||||
|
||||
struct AudioDebugStats {
|
||||
int buffered;
|
||||
int watermark;
|
||||
int bufsize;
|
||||
int underrunCount;
|
||||
int overrunCount;
|
||||
int instantSampleRate;
|
||||
int lastPushSize;
|
||||
};
|
||||
|
||||
// Easy interface for sceAudio to write to, to keep the complexity in check.
|
||||
|
||||
void __AudioInit();
|
||||
@ -33,3 +43,4 @@ void __AudioWakeThreads(AudioChannel &chan, int result, int step);
|
||||
void __AudioWakeThreads(AudioChannel &chan, int result);
|
||||
|
||||
int __AudioMix(short *outstereo, int numSamples, int sampleRate);
|
||||
const AudioDebugStats *__AudioGetDebugStats();
|
@ -25,6 +25,8 @@
|
||||
#include "Common/MathUtil.h"
|
||||
#include "Common/Atomics.h"
|
||||
#include "Core/HW/StereoResampler.h"
|
||||
#include "Core/HLE/__sceAudio.h"
|
||||
#include "Core/System.h"
|
||||
#include "Globals.h"
|
||||
|
||||
#ifdef _M_SSE
|
||||
@ -94,7 +96,7 @@ unsigned int StereoResampler::MixerFifo::Mix(short* samples, unsigned int numSam
|
||||
if (offset > MAX_FREQ_SHIFT) offset = MAX_FREQ_SHIFT;
|
||||
if (offset < -MAX_FREQ_SHIFT) offset = -MAX_FREQ_SHIFT;
|
||||
|
||||
float aid_sample_rate = m_input_sample_rate + offset;
|
||||
aid_sample_rate_ = m_input_sample_rate + offset;
|
||||
|
||||
/* Hm?
|
||||
u32 framelimit = SConfig::GetInstance().m_Framelimit;
|
||||
@ -102,7 +104,7 @@ unsigned int StereoResampler::MixerFifo::Mix(short* samples, unsigned int numSam
|
||||
aid_sample_rate = aid_sample_rate * (framelimit - 1) * 5 / 59.994;
|
||||
}*/
|
||||
|
||||
const u32 ratio = (u32)(65536.0f * aid_sample_rate / (float)sample_rate);
|
||||
const u32 ratio = (u32)(65536.0f * aid_sample_rate_ / (float)sample_rate);
|
||||
|
||||
// TODO: consider a higher-quality resampling algorithm.
|
||||
// TODO: Add a fast path for 1:1.
|
||||
@ -114,8 +116,8 @@ unsigned int StereoResampler::MixerFifo::Mix(short* samples, unsigned int numSam
|
||||
s16 r2 = m_buffer[(indexR2 + 1) & INDEX_MASK]; //next
|
||||
int sampleL = ((l1 << 16) + (l2 - l1) * (u16)m_frac) >> 16;
|
||||
int sampleR = ((r1 << 16) + (r2 - r1) * (u16)m_frac) >> 16;
|
||||
samples[currentSample] = clamp_s16(sampleL); // Do we even need to clamp after interpolation?
|
||||
samples[currentSample + 1] = clamp_s16(sampleR);
|
||||
samples[currentSample] = sampleL;
|
||||
samples[currentSample + 1] = sampleR;
|
||||
m_frac += ratio;
|
||||
indexR += 2 * (u16)(m_frac >> 16);
|
||||
m_frac &= 0xffff;
|
||||
@ -123,6 +125,9 @@ unsigned int StereoResampler::MixerFifo::Mix(short* samples, unsigned int numSam
|
||||
|
||||
int realSamples = currentSample;
|
||||
|
||||
if (currentSample < numSamples * 2)
|
||||
underrunCount_++;
|
||||
|
||||
// Padding with the last value to reduce clicking
|
||||
short s[2];
|
||||
s[0] = clamp_s16(m_buffer[(indexR - 1) & INDEX_MASK]);
|
||||
@ -138,6 +143,7 @@ unsigned int StereoResampler::MixerFifo::Mix(short* samples, unsigned int numSam
|
||||
//if (realSamples != numSamples * 2) {
|
||||
// ILOG("Underrun! %i / %i", realSamples / 2, numSamples);
|
||||
//}
|
||||
lastBufSize_ = (m_indexW - m_indexR) & INDEX_MASK;
|
||||
|
||||
return realSamples / 2;
|
||||
}
|
||||
@ -155,14 +161,20 @@ void StereoResampler::MixerFifo::PushSamples(const s32 *samples, unsigned int nu
|
||||
// needs to get updates to not deadlock.
|
||||
u32 indexW = Common::AtomicLoad(m_indexW);
|
||||
|
||||
u32 cap = MAX_SAMPLES * 2;
|
||||
// If unthottling, no need to fill up the entire buffer, just screws up timing after releasing unthrottle.
|
||||
if (PSP_CoreParameter().unthrottle)
|
||||
cap = LOW_WATERMARK * 2;
|
||||
|
||||
// Check if we have enough free space
|
||||
// indexW == m_indexR results in empty buffer, so indexR must always be smaller than indexW
|
||||
if (num_samples * 2 + ((indexW - Common::AtomicLoad(m_indexR)) & INDEX_MASK) >= MAX_SAMPLES * 2)
|
||||
if (num_samples * 2 + ((indexW - Common::AtomicLoad(m_indexR)) & INDEX_MASK) >= cap) {
|
||||
if (!PSP_CoreParameter().unthrottle)
|
||||
overrunCount_++;
|
||||
// TODO: "Timestretch" by doing a windowed overlap with existing buffer content?
|
||||
return;
|
||||
}
|
||||
|
||||
// AyuanX: Actual re-sampling work has been moved to sound thread
|
||||
// to alleviate the workload on main thread
|
||||
// and we simply store raw data here to make fast mem copy
|
||||
int over_bytes = num_samples * 4 - (MAX_SAMPLES * 2 - (indexW & INDEX_MASK)) * sizeof(short);
|
||||
if (over_bytes > 0) {
|
||||
ClampBufferToS16(&m_buffer[indexW & INDEX_MASK], samples, (num_samples * 4 - over_bytes) / 2);
|
||||
@ -172,6 +184,19 @@ void StereoResampler::MixerFifo::PushSamples(const s32 *samples, unsigned int nu
|
||||
}
|
||||
|
||||
Common::AtomicAdd(m_indexW, num_samples * 2);
|
||||
lastPushSize_ = num_samples;
|
||||
}
|
||||
|
||||
void StereoResampler::MixerFifo::GetAudioDebugStats(AudioDebugStats *stats) {
|
||||
stats->buffered = lastBufSize_;
|
||||
stats->underrunCount += underrunCount_;
|
||||
underrunCount_ = 0;
|
||||
stats->overrunCount += overrunCount_;
|
||||
overrunCount_ = 0;
|
||||
stats->watermark = LOW_WATERMARK;
|
||||
stats->bufsize = MAX_SAMPLES * 2;
|
||||
stats->instantSampleRate = aid_sample_rate_;
|
||||
stats->lastPushSize = lastPushSize_;
|
||||
}
|
||||
|
||||
void StereoResampler::PushSamples(const int *samples, unsigned int num_samples) {
|
||||
@ -187,3 +212,7 @@ void StereoResampler::DoState(PointerWrap &p) {
|
||||
if (!s)
|
||||
return;
|
||||
}
|
||||
|
||||
void StereoResampler::GetAudioDebugStats(AudioDebugStats *stats) {
|
||||
m_dma_mixer.GetAudioDebugStats(stats);
|
||||
}
|
||||
|
@ -26,12 +26,14 @@
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
struct AudioDebugStats;
|
||||
|
||||
// 16 bit Stereo
|
||||
|
||||
#define MAX_SAMPLES (2*(1024 * 2)) // 2*64ms - had to double it for nVidia Shield which has huge buffers
|
||||
#define INDEX_MASK (MAX_SAMPLES * 2 - 1)
|
||||
|
||||
#define LOW_WATERMARK 1280 // 40 ms
|
||||
#define LOW_WATERMARK 1680 // 40 ms
|
||||
#define MAX_FREQ_SHIFT 200 // per 32000 Hz
|
||||
#define CONTROL_FACTOR 0.2f // in freq_shift per fifo size offset
|
||||
#define CONTROL_AVG 32
|
||||
@ -56,7 +58,10 @@ public:
|
||||
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
void GetAudioDebugStats(AudioDebugStats *stats);
|
||||
|
||||
protected:
|
||||
// TODO: Unlike Dolphin we only mix one stream so this inner class can be merged into the outer one.
|
||||
class MixerFifo {
|
||||
public:
|
||||
MixerFifo(StereoResampler *mixer, unsigned sample_rate)
|
||||
@ -66,6 +71,10 @@ protected:
|
||||
, m_indexR(0)
|
||||
, m_numLeftI(0.0f)
|
||||
, m_frac(0)
|
||||
, underrunCount_(0)
|
||||
, overrunCount_(0)
|
||||
, aid_sample_rate_(0.0f)
|
||||
, lastBufSize_(0)
|
||||
{
|
||||
memset(m_buffer, 0, sizeof(m_buffer));
|
||||
}
|
||||
@ -73,6 +82,7 @@ protected:
|
||||
unsigned int Mix(short* samples, unsigned int numSamples, bool consider_framelimit, int sample_rate);
|
||||
void SetInputSampleRate(unsigned int rate);
|
||||
void Clear();
|
||||
void GetAudioDebugStats(AudioDebugStats *stats);
|
||||
|
||||
private:
|
||||
StereoResampler *m_mixer;
|
||||
@ -82,6 +92,11 @@ protected:
|
||||
volatile u32 m_indexR;
|
||||
float m_numLeftI;
|
||||
u32 m_frac;
|
||||
int underrunCount_;
|
||||
int overrunCount_;
|
||||
float aid_sample_rate_;
|
||||
int lastBufSize_;
|
||||
int lastPushSize_;
|
||||
};
|
||||
|
||||
MixerFifo m_dma_mixer;
|
||||
|
@ -63,6 +63,7 @@ void DevMenu::CreatePopupContents(UI::ViewGroup *parent) {
|
||||
parent->Add(new Choice(de->T("Jit Compare")))->OnClick.Handle(this, &DevMenu::OnJitCompare);
|
||||
parent->Add(new Choice(de->T("Toggle Freeze")))->OnClick.Handle(this, &DevMenu::OnFreezeFrame);
|
||||
parent->Add(new Choice(de->T("Dump Frame GPU Commands")))->OnClick.Handle(this, &DevMenu::OnDumpFrame);
|
||||
parent->Add(new Choice(de->T("Toggle Audio Debug")))->OnClick.Handle(this, &DevMenu::OnToggleAudioDebug);
|
||||
|
||||
RingbufferLogListener *ring = LogManager::GetInstance()->GetRingbufferListener();
|
||||
if (ring) {
|
||||
@ -70,6 +71,12 @@ void DevMenu::CreatePopupContents(UI::ViewGroup *parent) {
|
||||
}
|
||||
}
|
||||
|
||||
UI::EventReturn DevMenu::OnToggleAudioDebug(UI::EventParams &e) {
|
||||
g_Config.bShowAudioDebug = !g_Config.bShowAudioDebug;
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
|
||||
UI::EventReturn DevMenu::OnLogView(UI::EventParams &e) {
|
||||
UpdateUIState(UISTATE_PAUSEMENU);
|
||||
screenManager()->push(new LogScreen());
|
||||
@ -109,6 +116,7 @@ UI::EventReturn DevMenu::OnDumpFrame(UI::EventParams &e) {
|
||||
}
|
||||
|
||||
void DevMenu::dialogFinished(const Screen *dialog, DialogResult result) {
|
||||
UpdateUIState(UISTATE_INGAME);
|
||||
// Close when a subscreen got closed.
|
||||
// TODO: a bug in screenmanager causes this not to work here.
|
||||
// screenManager()->finishDialog(this, DR_OK);
|
||||
|
@ -42,6 +42,7 @@ protected:
|
||||
UI::EventReturn OnFreezeFrame(UI::EventParams &e);
|
||||
UI::EventReturn OnDumpFrame(UI::EventParams &e);
|
||||
UI::EventReturn OnDeveloperTools(UI::EventParams &e);
|
||||
UI::EventReturn OnToggleAudioDebug(UI::EventParams &e);
|
||||
};
|
||||
|
||||
class LogConfigScreen : public UIDialogScreenWithBackground {
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "Core/Debugger/SymbolMap.h"
|
||||
#include "Core/SaveState.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/HLE/__sceAudio.h"
|
||||
|
||||
#include "UI/ui_atlas.h"
|
||||
#include "UI/OnScreenDisplay.h"
|
||||
@ -681,6 +682,56 @@ void EmuScreen::checkPowerDown() {
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawDebugStats(DrawBuffer *draw2d) {
|
||||
char statbuf[4096] = { 0 };
|
||||
__DisplayGetDebugStats(statbuf, sizeof(statbuf));
|
||||
draw2d->SetFontScale(.7f, .7f);
|
||||
draw2d->DrawText(UBUNTU24, statbuf, 11, 31, 0xc0000000, FLAG_DYNAMIC_ASCII);
|
||||
draw2d->DrawText(UBUNTU24, statbuf, 10, 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
|
||||
draw2d->SetFontScale(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
static void DrawAudioDebugStats(DrawBuffer *draw2d) {
|
||||
char statbuf[1024] = { 0 };
|
||||
const AudioDebugStats *stats = __AudioGetDebugStats();
|
||||
snprintf(statbuf, sizeof(statbuf),
|
||||
"Audio buffer: %d/%d (low watermark: %d)\n"
|
||||
"Underruns: %d\n"
|
||||
"Overruns: %d\n"
|
||||
"Sample rate: %d\n"
|
||||
"Push size: %d\n",
|
||||
stats->buffered, stats->bufsize, stats->watermark,
|
||||
stats->underrunCount,
|
||||
stats->overrunCount,
|
||||
stats->instantSampleRate,
|
||||
stats->lastPushSize);
|
||||
draw2d->SetFontScale(0.7f, 0.7f);
|
||||
draw2d->DrawText(UBUNTU24, statbuf, 11, 31, 0xc0000000, FLAG_DYNAMIC_ASCII);
|
||||
draw2d->DrawText(UBUNTU24, statbuf, 10, 30, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
|
||||
draw2d->SetFontScale(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
static void DrawFPS(DrawBuffer *draw2d, const Bounds &bounds) {
|
||||
float vps, fps, actual_fps;
|
||||
__DisplayGetFPS(&vps, &fps, &actual_fps);
|
||||
char fpsbuf[256];
|
||||
switch (g_Config.iShowFPSCounter) {
|
||||
case 1:
|
||||
snprintf(fpsbuf, sizeof(fpsbuf), "Speed: %0.1f%%", vps / (59.94f / 100.0f)); break;
|
||||
case 2:
|
||||
snprintf(fpsbuf, sizeof(fpsbuf), "FPS: %0.1f", actual_fps); break;
|
||||
case 3:
|
||||
snprintf(fpsbuf, sizeof(fpsbuf), "%0.0f/%0.0f (%0.1f%%)", actual_fps, fps, vps / (59.94f / 100.0f)); break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
draw2d->SetFontScale(0.7f, 0.7f);
|
||||
draw2d->DrawText(UBUNTU24, fpsbuf, bounds.x2() - 8, 12, 0xc0000000, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
|
||||
draw2d->DrawText(UBUNTU24, fpsbuf, bounds.x2() - 10, 10, 0xFF3fFF3f, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
|
||||
draw2d->SetFontScale(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void EmuScreen::render() {
|
||||
if (invalid_) {
|
||||
// It's possible this might be set outside PSP_RunLoopFor().
|
||||
@ -725,7 +776,7 @@ void EmuScreen::render() {
|
||||
if (useBufferedRendering && g_Config.iGPUBackend == GPU_BACKEND_OPENGL)
|
||||
fbo_unbind();
|
||||
|
||||
if (!osm.IsEmpty() || g_Config.bShowDebugStats || g_Config.iShowFPSCounter || g_Config.bShowTouchControls || g_Config.bShowDeveloperMenu) {
|
||||
if (!osm.IsEmpty() || g_Config.bShowDebugStats || g_Config.iShowFPSCounter || g_Config.bShowTouchControls || g_Config.bShowDeveloperMenu || g_Config.bShowAudioDebug) {
|
||||
|
||||
Thin3DContext *thin3d = screenManager()->getThin3DContext();
|
||||
|
||||
@ -750,34 +801,15 @@ void EmuScreen::render() {
|
||||
}
|
||||
|
||||
if (g_Config.bShowDebugStats) {
|
||||
char statbuf[4096] = {0};
|
||||
__DisplayGetDebugStats(statbuf, sizeof(statbuf));
|
||||
draw2d->SetFontScale(.7f, .7f);
|
||||
draw2d->DrawText(UBUNTU24, statbuf, 11, 11, 0xc0000000, FLAG_DYNAMIC_ASCII);
|
||||
draw2d->DrawText(UBUNTU24, statbuf, 10, 10, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
|
||||
draw2d->SetFontScale(1.0f, 1.0f);
|
||||
DrawDebugStats(draw2d);
|
||||
}
|
||||
|
||||
if (g_Config.bShowAudioDebug) {
|
||||
DrawAudioDebugStats(draw2d);
|
||||
}
|
||||
|
||||
if (g_Config.iShowFPSCounter) {
|
||||
float vps, fps, actual_fps;
|
||||
__DisplayGetFPS(&vps, &fps, &actual_fps);
|
||||
char fpsbuf[256];
|
||||
switch (g_Config.iShowFPSCounter) {
|
||||
case 1:
|
||||
snprintf(fpsbuf, sizeof(fpsbuf), "Speed: %0.1f%%", vps / (59.94f / 100.0f)); break;
|
||||
case 2:
|
||||
snprintf(fpsbuf, sizeof(fpsbuf), "FPS: %0.1f", actual_fps); break;
|
||||
case 3:
|
||||
snprintf(fpsbuf, sizeof(fpsbuf), "%0.0f/%0.0f (%0.1f%%)", actual_fps, fps, vps / (59.94f / 100.0f)); break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
const Bounds &bounds = screenManager()->getUIContext()->GetBounds();
|
||||
draw2d->SetFontScale(0.7f, 0.7f);
|
||||
draw2d->DrawText(UBUNTU24, fpsbuf, bounds.x2() - 8, 12, 0xc0000000, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
|
||||
draw2d->DrawText(UBUNTU24, fpsbuf, bounds.x2() - 10, 10, 0xFF3fFF3f, ALIGN_TOPRIGHT | FLAG_DYNAMIC_ASCII);
|
||||
draw2d->SetFontScale(1.0f, 1.0f);
|
||||
DrawFPS(draw2d, screenManager()->getUIContext()->GetBounds());
|
||||
}
|
||||
|
||||
screenManager()->getUIContext()->End();
|
||||
|
2
native
2
native
@ -1 +1 @@
|
||||
Subproject commit 813c12e40fa241c3097b541de4cb68f16a45af53
|
||||
Subproject commit 1467753c35eaf57be5610d756a3071e4badc1b69
|
Loading…
Reference in New Issue
Block a user