Merge branch 'master' into extdata

This commit is contained in:
wheremyfoodat 2025-02-09 23:01:12 +02:00
commit 701fd0f446
30 changed files with 286 additions and 58 deletions

View file

@ -0,0 +1,9 @@
#pragma once
#if defined(__LIBRETRO__) && defined(USE_LIBRETRO_AUDIO_DEVICE)
#include "audio/libretro_audio_device.hpp"
using AudioDevice = LibretroAudioDevice;
#else
#include "audio/miniaudio_device.hpp"
using AudioDevice = MiniAudioDevice;
#endif

View file

@ -0,0 +1,36 @@
#pragma once
#include <array>
#include "config.hpp"
#include "helpers.hpp"
#include "ring_buffer.hpp"
class AudioDeviceInterface {
protected:
static constexpr usize maxFrameCount = 0x2000;
using Samples = Common::RingBuffer<s16, maxFrameCount * 2>;
using RenderBatchCallback = usize (*)(const s16*, usize);
Samples* samples = nullptr;
const AudioDeviceConfig& audioSettings;
// Store the last stereo sample we output. We play this when underruning to avoid pops.
std::array<s16, 2> lastStereoSample{};
public:
AudioDeviceInterface(Samples* samples, const AudioDeviceConfig& audioSettings) : samples(samples), audioSettings(audioSettings) {}
bool running = false;
Samples* getSamples() { return samples; }
// If safe is on, we create a null audio device
virtual void init(Samples& samples, bool safe = false) = 0;
virtual void close() = 0;
virtual void start() = 0;
virtual void stop() = 0;
// Only used for audio devices that render multiple audio frames in one go, eg the libretro audio device.
virtual void renderBatch(RenderBatchCallback callback) {}
};

View file

@ -0,0 +1,61 @@
#pragma once
#include <cstring>
#include "audio/audio_device_interface.hpp"
class LibretroAudioDevice final : public AudioDeviceInterface {
bool initialized = false;
public:
LibretroAudioDevice(const AudioDeviceConfig& audioSettings) : AudioDeviceInterface(nullptr, audioSettings), initialized(false) {
running = false;
}
void init(Samples& samples, bool safe = false) override {
this->samples = &samples;
initialized = true;
running = false;
}
void close() override {
initialized = false;
running = false;
};
void start() override { running = true; }
void stop() override { running = false; };
void renderBatch(RenderBatchCallback callback) override {
if (running) {
static constexpr usize sampleRate = 32768; // 3DS samples per second
static constexpr usize frameCount = sampleRate / 60; // 3DS samples per video frame
static constexpr usize channelCount = 2;
static s16 audioBuffer[frameCount * channelCount];
usize samplesWritten = 0;
samplesWritten += samples->pop(audioBuffer, frameCount * channelCount);
// Get the last sample for underrun handling
if (samplesWritten != 0) {
std::memcpy(&lastStereoSample[0], &audioBuffer[(samplesWritten - 1) * 2], sizeof(lastStereoSample));
}
// If underruning, copy the last output sample
{
s16* pointer = &audioBuffer[samplesWritten * 2];
s16 l = lastStereoSample[0];
s16 r = lastStereoSample[1];
for (usize i = samplesWritten; i < frameCount; i++) {
*pointer++ = l;
*pointer++ = r;
}
}
callback(audioBuffer, sizeof(audioBuffer) / (channelCount * sizeof(s16)));
}
}
bool isInitialized() const { return initialized; }
};

View file

@ -3,39 +3,31 @@
#include <string>
#include <vector>
#include "config.hpp"
#include "helpers.hpp"
#include "audio/audio_device_interface.hpp"
#include "miniaudio.h"
#include "ring_buffer.hpp"
class MiniAudioDevice {
using Samples = Common::RingBuffer<ma_int16, 0x2000 * 2>;
class MiniAudioDevice final : public AudioDeviceInterface {
static constexpr ma_uint32 sampleRate = 32768; // 3DS sample rate
static constexpr ma_uint32 channelCount = 2; // Audio output is stereo
bool initialized = false;
ma_device device;
ma_context context;
ma_device_config deviceConfig;
Samples* samples = nullptr;
const AudioDeviceConfig& audioSettings;
bool initialized = false;
bool running = false;
// Store the last stereo sample we output. We play this when underruning to avoid pops.
std::array<s16, 2> lastStereoSample;
std::vector<std::string> audioDevices;
public:
MiniAudioDevice(const AudioDeviceConfig& audioSettings);
// If safe is on, we create a null audio device
void init(Samples& samples, bool safe = false);
void close();
void init(Samples& samples, bool safe = false) override;
void close() override;
void start();
void stop();
void start() override;
void stop() override;
bool isInitialized() const { return initialized; }
};

View file

@ -181,5 +181,7 @@ class CPU {
void addTicks(u64 ticks) { env.AddTicks(ticks); }
void clearCache() { jit->ClearCache(); }
void clearCacheRange(u32 start, u32 size) { jit->InvalidateCacheRange(start, size); }
void runFrame();
};

View file

@ -7,8 +7,8 @@
#include <span>
#include "PICA/gpu.hpp"
#include "audio/audio_device.hpp"
#include "audio/dsp_core.hpp"
#include "audio/miniaudio_device.hpp"
#include "cheats.hpp"
#include "config.hpp"
#include "cpu.hpp"
@ -48,14 +48,14 @@ class Emulator {
Scheduler scheduler;
Crypto::AESEngine aesEngine;
MiniAudioDevice audioDevice;
AudioDevice audioDevice;
Cheats cheats;
public:
static constexpr u32 width = 400;
static constexpr u32 height = 240 * 2; // * 2 because 2 screens
ROMType romType = ROMType::None;
bool running = false; // Is the emulator running a game?
bool running = false; // Is the emulator running a game?
private:
#ifdef PANDA3DS_ENABLE_HTTP_SERVER
@ -126,6 +126,7 @@ class Emulator {
LuaManager& getLua() { return lua; }
Scheduler& getScheduler() { return scheduler; }
Memory& getMemory() { return memory; }
AudioDeviceInterface& getAudioDevice() { return audioDevice; }
RendererType getRendererType() const { return config.rendererType; }
Renderer* getRenderer() { return gpu.getRenderer(); }

View file

@ -175,6 +175,8 @@ public:
void svcSignalEvent();
void svcSetTimer();
void svcSleepThread();
void svcInvalidateInstructionCacheRange();
void svcInvalidateEntireInstructionCache();
void connectToPort();
void outputDebugString();
void waitSynchronization1();
@ -250,4 +252,6 @@ public:
void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); }
void clearInstructionCache();
void clearInstructionCacheRange(u32 start, u32 size);
u32 getSharedFontVaddr();
};

View file

@ -19,7 +19,7 @@ struct ResourceLimitValues {
// APPLICATION resource limit
static constexpr ResourceLimitValues appResourceLimits = {
.maxPriority = 0x18,
.maxCommit = 0x4000000,
.maxCommit = 64_MB + 16_MB, // We're currently giving 80MB to all apps. TODO: Implement extended memory properly
.maxThreads = 0x20,
.maxEvents = 0x20,
.maxMutexes = 0x20,
@ -33,7 +33,7 @@ static constexpr ResourceLimitValues appResourceLimits = {
// SYS_APPLET resource limit
static constexpr ResourceLimitValues sysAppletResourceLimits = {
.maxPriority = 0x4,
.maxCommit = 0x5E00000,
.maxCommit = 0x5E00000 - 16_MB,
.maxThreads = 0x1D,
.maxEvents = 0xB,
.maxMutexes = 0x8,

View file

@ -132,7 +132,7 @@ public:
static constexpr u32 totalPageCount = 1 << (32 - pageShift);
static constexpr u32 FCRAM_SIZE = u32(128_MB);
static constexpr u32 FCRAM_APPLICATION_SIZE = u32(64_MB);
static constexpr u32 FCRAM_APPLICATION_SIZE = u32(80_MB);
static constexpr u32 FCRAM_PAGE_COUNT = FCRAM_SIZE / pageSize;
static constexpr u32 FCRAM_APPLICATION_PAGE_COUNT = FCRAM_APPLICATION_SIZE / pageSize;

View file

@ -53,6 +53,7 @@ class Renderer {
EmulatorConfig* emulatorConfig = nullptr;
void doSoftwareTextureCopy(u32 inputAddr, u32 outputAddr, u32 copySize, u32 inputWidth, u32 inputGap, u32 outputWidth, u32 outputGap);
public:
Renderer(GPU& gpu, const std::array<u32, regNum>& internalRegs, const std::array<u32, extRegNum>& externalRegs);
virtual ~Renderer();