mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-11 16:49:27 +01:00
Merge pull request #22811 from hrydgard/misc-logic-fixes
Misc logic fixes from a Claude code review
This commit is contained in:
24 files changed
+204
-88
No files matched your search
@@ -55,9 +55,11 @@ public:
|
||||
// Read first, then regenerate that word in place - done in index order this is the
|
||||
// same as twisting the whole array in one go, and it matches what hardware leaves
|
||||
// behind in the context after each draw.
|
||||
uint32_t y = mt_[index_];
|
||||
twist(index_);
|
||||
index_ = (index_ + 1) % MT_SIZE;
|
||||
// The context can live in emulated memory, so don't trust the index.
|
||||
const uint32_t i = index_ % MT_SIZE;
|
||||
uint32_t y = mt_[i];
|
||||
twist(i);
|
||||
index_ = (i + 1) % MT_SIZE;
|
||||
y ^= y >> 11;
|
||||
y ^= (y << 7) & 2636928640UL;
|
||||
y ^= (y << 15) & 4022730752UL;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
enum PSPErrorCode : u32 {
|
||||
SCE_KERNEL_ERROR_OK = 0,
|
||||
SCE_KERNEL_ERROR_NOT_INITIALIZED = 0x80000001, // Name guessed, from sceAudioInput before init.
|
||||
SCE_KERNEL_ERROR_BAD_ARGUMENT = 0x80000004, // Maybe
|
||||
SCE_KERNEL_ERROR_ALREADY = 0x80000020,
|
||||
SCE_KERNEL_ERROR_BUSY = 0x80000021,
|
||||
@@ -373,6 +374,7 @@ enum PSPErrorCode : u32 {
|
||||
SCE_ERROR_AUDIO_INVALID_FREQUENCY = 0x8026000A,
|
||||
SCE_ERROR_AUDIO_INVALID_VOLUME = 0x8026000B,
|
||||
SCE_ERROR_AUDIO_CHANNEL_ALREADY_RESERVED = 0x80268002,
|
||||
SCE_ERROR_AUDIO_ROUTING_INVALID_MODE = 0x802C01FE,
|
||||
|
||||
SCE_ERROR_USBMIC_INVALID_MAX_SAMPLES = 0x80243806,
|
||||
SCE_ERROR_USBMIC_INVALID_SAMPLERATE = 0x8024380A,
|
||||
|
||||
@@ -294,10 +294,15 @@ static int Replace_memcpy_swizzled(MIPSState *mips) {
|
||||
gpu->PerformReadbackToMemory(srcPtr, pitch * h);
|
||||
}
|
||||
}
|
||||
u8 *dstp = Memory::GetPointerWriteRangeOrException(destPtr, pitch * h);
|
||||
const u8 *srcp = Memory::GetPointerRangeOrException(srcPtr, pitch * h);
|
||||
// The loops go in whole 16x8 blocks, so they can touch more than pitch * h.
|
||||
const u64 rows = ((u64)h + 7) & ~7ULL;
|
||||
const u64 cols = ((u64)pitch + 15) & ~15ULL;
|
||||
const u64 dstSize = rows * cols;
|
||||
const u64 srcSize = rows ? (rows - 1) * pitch + cols : 0;
|
||||
u8 *dstp = dstSize <= 0xFFFFFFFF ? Memory::GetPointerWriteRangeOrException(destPtr, (u32)dstSize) : nullptr;
|
||||
const u8 *srcp = srcSize <= 0xFFFFFFFF ? Memory::GetPointerRangeOrException(srcPtr, (u32)srcSize) : nullptr;
|
||||
|
||||
if (dstp && srcp) {
|
||||
if (dstp && srcp && h != 0 && pitch != 0) {
|
||||
const u8 *ysrcp = srcp;
|
||||
for (u32 y = 0; y < h; y += 8) {
|
||||
const u8 *xsrcp = ysrcp;
|
||||
@@ -761,12 +766,15 @@ static int Hook_godseaterburst_depthmask_5551(MIPSState *mips) {
|
||||
uint32_t depthBuffer = mips->r[MIPS_REG_T2];
|
||||
uint32_t byteStride = mips->r[MIPS_REG_A2];
|
||||
uint32_t height = mips->r[MIPS_REG_T1];
|
||||
uint32_t size = byteStride * height;
|
||||
const u64 size64 = (u64)byteStride * height;
|
||||
if (size64 > 0xFFFFFFFF)
|
||||
return 0;
|
||||
uint32_t size = (uint32_t)size64;
|
||||
|
||||
if (!Memory::IsVRAMAddress(colorBuffer) || !Memory::IsValidRange(colorBuffer, size))
|
||||
return 0;
|
||||
if (depthBuffer != 0) {
|
||||
if (!Memory::IsVRAMAddress(colorBuffer) || !Memory::IsValidRange(depthBuffer, size))
|
||||
if (!Memory::IsVRAMAddress(depthBuffer) || !Memory::IsValidRange(depthBuffer, size))
|
||||
return 0;
|
||||
|
||||
// This is added to read from the linearized mirror.
|
||||
|
||||
@@ -112,6 +112,8 @@ void __AudioInit() {
|
||||
g_audioChans[i].clear();
|
||||
}
|
||||
g_audioSRC.clear();
|
||||
__AudioRoutingInit();
|
||||
audioInputInited = false;
|
||||
|
||||
mixBuffer = new s32[hwBlockSize * 2];
|
||||
clampedMixBuffer = new s16[hwBlockSize * 2];
|
||||
@@ -121,7 +123,7 @@ void __AudioInit() {
|
||||
}
|
||||
|
||||
void __AudioDoState(PointerWrap &p) {
|
||||
auto s = p.Section("sceAudio", 1, 4);
|
||||
auto s = p.Section("sceAudio", 1, 5);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
@@ -197,6 +199,12 @@ void __AudioDoState(PointerWrap &p) {
|
||||
} else {
|
||||
mixerDMABusy = false;
|
||||
}
|
||||
if (s >= 5) {
|
||||
Do(p, audioInputInited);
|
||||
} else {
|
||||
// A game that was already capturing had initialized it.
|
||||
audioInputInited = true;
|
||||
}
|
||||
// For older states the routing modes were read back once per channel, above.
|
||||
|
||||
__AudioCPUMHzChange();
|
||||
|
||||
+59
-22
@@ -33,10 +33,11 @@
|
||||
|
||||
const u32 PSP_AUDIO_SAMPLE_MAX = 65536 - 64;
|
||||
const int PSP_AUDIO_ERROR_SRC_FORMAT_4 = 0x80000003;
|
||||
const int AUDIO_ROUTING_SPEAKER_OFF = 0;
|
||||
const int AUDIO_ROUTING_SPEAKER_ON = 1;
|
||||
int defaultRoutingMode = AUDIO_ROUTING_SPEAKER_ON;
|
||||
int defaultRoutingVolMode = AUDIO_ROUTING_SPEAKER_ON;
|
||||
// Both read 0 at boot on a PSP.
|
||||
int defaultRoutingMode = 0;
|
||||
int defaultRoutingVolMode = 0;
|
||||
// sceAudioInput fails until sceAudioInputInit.
|
||||
bool audioInputInited = false;
|
||||
|
||||
// Only still here to read savestates written before the channels held buffer pointers.
|
||||
struct AudioChannelWaitInfo {
|
||||
@@ -157,6 +158,11 @@ void AudioSRCChannel::DoState(PointerWrap &p) {
|
||||
Do(p, waitingThreads);
|
||||
}
|
||||
|
||||
void __AudioRoutingInit() {
|
||||
defaultRoutingMode = 0;
|
||||
defaultRoutingVolMode = 0;
|
||||
}
|
||||
|
||||
void __AudioRoutingDoState(PointerWrap &p) {
|
||||
auto s = p.Section("sceAudioRouting", 1);
|
||||
if (!s)
|
||||
@@ -543,7 +549,25 @@ static u32 sceAudioSRCOutputBlocking(u32 vol, u32 buf) {
|
||||
return hleLogDebug(Log::sceAudio, __AudioSRCEnqueueBlocking(g_audioSRC, buf, vol));
|
||||
}
|
||||
|
||||
// From pspautotests audio/sceaudio/input. The size is checked first.
|
||||
static int AudioInputCheck(u32 maxSamples, u32 sampleRate) {
|
||||
if (!audioInputInited) {
|
||||
return SCE_KERNEL_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (maxSamples == 0 || (maxSamples & 63) != 0 || maxSamples >= 0x80000000) {
|
||||
return SCE_ERROR_AUDIO_OUTPUT_SAMPLE_DATA_SIZE_NOT_ALIGNED;
|
||||
}
|
||||
if (sampleRate != 44100 && sampleRate != 22050 && sampleRate != 11025) {
|
||||
return SCE_ERROR_AUDIO_INVALID_FREQUENCY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sceAudioInputBlocking(u32 maxSamples, u32 sampleRate, u32 bufAddr) {
|
||||
int error = AudioInputCheck(maxSamples, sampleRate);
|
||||
if (error != 0) {
|
||||
return hleLogError(Log::HLE, error);
|
||||
}
|
||||
if (!Memory::IsValidAddress(bufAddr)) {
|
||||
return hleLogError(Log::HLE, -1, "invalid address");
|
||||
}
|
||||
@@ -551,6 +575,13 @@ static int sceAudioInputBlocking(u32 maxSamples, u32 sampleRate, u32 bufAddr) {
|
||||
}
|
||||
|
||||
static int sceAudioInput(u32 maxSamples, u32 sampleRate, u32 bufAddr) {
|
||||
int error = AudioInputCheck(maxSamples, sampleRate);
|
||||
if (error != 0) {
|
||||
return hleLogError(Log::HLE, error);
|
||||
}
|
||||
if (bufAddr == 0) {
|
||||
return hleLogWarning(Log::HLE, 0, "NULL buffer");
|
||||
}
|
||||
if (!Memory::IsValidAddress(bufAddr)) {
|
||||
return hleLogError(Log::HLE, -1, "invalid address");
|
||||
}
|
||||
@@ -561,11 +592,14 @@ static int sceAudioInput(u32 maxSamples, u32 sampleRate, u32 bufAddr) {
|
||||
|
||||
static int sceAudioInputInit(int unknown1, int gain, int unknown2) {
|
||||
ERROR_LOG(Log::HLE, "UNIMPL sceAudioInputInit: unknown1: %d, gain: %d, unknown2: %d", unknown1, gain, unknown2);
|
||||
return 0;
|
||||
audioInputInited = true;
|
||||
// Takes about 3ms on a PSP.
|
||||
return hleDelayResult(0, "audio input init", 3000);
|
||||
}
|
||||
|
||||
static int sceAudioInputInitEx(u32 paramAddr) {
|
||||
ERROR_LOG(Log::HLE, "UNIMPL sceAudioInputInitEx: paramAddr: %08x", paramAddr);
|
||||
audioInputInited = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -583,28 +617,31 @@ static int sceAudioGetInputLength() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 sceAudioRoutingSetMode(u32 mode) {
|
||||
ERROR_LOG(Log::sceAudio, "sceAudioRoutingSetMode(%08x)", mode);
|
||||
// Ranges and return values from pspautotests audio/sceaudio/routing. Also exported as sceAudioRouting.
|
||||
int sceAudioRoutingSetMode(int mode) {
|
||||
if (mode < 0 || mode > 3) {
|
||||
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_ROUTING_INVALID_MODE, "invalid mode");
|
||||
}
|
||||
int previousMode = defaultRoutingMode;
|
||||
defaultRoutingMode = mode;
|
||||
return previousMode;
|
||||
return hleLogInfo(Log::sceAudio, previousMode);
|
||||
}
|
||||
|
||||
static u32 sceAudioRoutingGetMode() {
|
||||
ERROR_LOG(Log::sceAudio, "sceAudioRoutingGetMode()");
|
||||
return defaultRoutingMode;
|
||||
int sceAudioRoutingGetMode() {
|
||||
return hleLogDebug(Log::sceAudio, defaultRoutingMode);
|
||||
}
|
||||
|
||||
static u32 sceAudioRoutingSetVolumeMode(u32 mode) {
|
||||
ERROR_LOG(Log::sceAudio, "sceAudioRoutingSetVolumeMode(%08x)", mode);
|
||||
int previousMode = defaultRoutingVolMode;
|
||||
// Unlike SetMode, this returns 0 rather than the previous mode.
|
||||
int sceAudioRoutingSetVolumeMode(int mode) {
|
||||
if (mode < 0 || mode > 1) {
|
||||
return hleLogError(Log::sceAudio, SCE_ERROR_AUDIO_ROUTING_INVALID_MODE, "invalid mode");
|
||||
}
|
||||
defaultRoutingVolMode = mode;
|
||||
return previousMode;
|
||||
return hleLogInfo(Log::sceAudio, 0);
|
||||
}
|
||||
|
||||
static u32 sceAudioRoutingGetVolumeMode() {
|
||||
ERROR_LOG(Log::sceAudio, "sceAudioRoutingGetVolumeMode()");
|
||||
return defaultRoutingVolMode;
|
||||
int sceAudioRoutingGetVolumeMode() {
|
||||
return hleLogDebug(Log::sceAudio, defaultRoutingVolMode);
|
||||
}
|
||||
|
||||
const HLEFunction sceAudio[] =
|
||||
@@ -653,10 +690,10 @@ const HLEFunction sceAudio[] =
|
||||
{0XA633048E, &WrapI_V<sceAudioPollInputEnd>, "sceAudioPollInputEnd", 'i', "" },
|
||||
{0X87B2E651, &WrapI_V<sceAudioWaitInputEnd>, "sceAudioWaitInputEnd", 'i', "" },
|
||||
|
||||
{0X36FD8AA9, &WrapU_U<sceAudioRoutingSetMode>, "sceAudioRoutingSetMode", 'x', "x" },
|
||||
{0X39240E7D, &WrapU_V<sceAudioRoutingGetMode>, "sceAudioRoutingGetMode", 'x', "" },
|
||||
{0XBB548475, &WrapU_U<sceAudioRoutingSetVolumeMode>, "sceAudioRoutingSetVolumeMode", 'x', "x" },
|
||||
{0X28235C56, &WrapU_V<sceAudioRoutingGetVolumeMode>, "sceAudioRoutingGetVolumeMode", 'x', "" },
|
||||
{0X36FD8AA9, &WrapI_I<sceAudioRoutingSetMode>, "sceAudioRoutingSetMode", 'i', "i" },
|
||||
{0X39240E7D, &WrapI_V<sceAudioRoutingGetMode>, "sceAudioRoutingGetMode", 'i', "" },
|
||||
{0XBB548475, &WrapI_I<sceAudioRoutingSetVolumeMode>, "sceAudioRoutingSetVolumeMode", 'i', "i" },
|
||||
{0X28235C56, &WrapI_V<sceAudioRoutingGetVolumeMode>, "sceAudioRoutingGetVolumeMode", 'i', "" },
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -114,7 +114,16 @@ extern AudioSRCChannel g_audioSRC;
|
||||
bool SRCFrequencyAllowed(int freq);
|
||||
|
||||
// The two routing modes are globals rather than per-channel; they get their own little block.
|
||||
void __AudioRoutingInit();
|
||||
|
||||
extern bool audioInputInited;
|
||||
void __AudioRoutingDoState(PointerWrap &p);
|
||||
|
||||
// sceAudioRouting exports the same four functions.
|
||||
int sceAudioRoutingSetMode(int mode);
|
||||
int sceAudioRoutingGetMode();
|
||||
int sceAudioRoutingSetVolumeMode(int mode);
|
||||
int sceAudioRoutingGetVolumeMode();
|
||||
|
||||
void Register_sceAudio();
|
||||
|
||||
@@ -17,39 +17,7 @@
|
||||
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HLE/FunctionWrappers.h"
|
||||
#include "Core/HLE/sceAudiocodec.h"
|
||||
|
||||
enum {
|
||||
AUDIO_ROUTING_SPEAKER_OFF = 0,
|
||||
AUDIO_ROUTING_SPEAKER_ON = 1,
|
||||
};
|
||||
|
||||
u32 audioRoutingMode = AUDIO_ROUTING_SPEAKER_ON;
|
||||
u32 audioRoutineVolumeMode = AUDIO_ROUTING_SPEAKER_ON;
|
||||
|
||||
static int sceAudioRoutingGetMode() {
|
||||
INFO_LOG(Log::sceAudio, "sceAudioRoutingGetMode");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sceAudioRoutingSetVolumeMode(int mode) {
|
||||
INFO_LOG(Log::sceAudio, "sceAudioRoutingSetVolumeMode %d", mode);
|
||||
int previousMode = audioRoutineVolumeMode;
|
||||
audioRoutineVolumeMode = audioRoutingMode;
|
||||
return previousMode;
|
||||
}
|
||||
|
||||
static int sceAudioRoutingGetVolumeMode() {
|
||||
INFO_LOG(Log::sceAudio, "sceAudioRoutingGetMode");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sceAudioRoutingSetMode(int mode) {
|
||||
INFO_LOG(Log::sceAudio, "sceAudioRoutingSetMode %d", mode);
|
||||
int previousMode = audioRoutingMode;
|
||||
audioRoutingMode = mode;
|
||||
return previousMode;
|
||||
}
|
||||
#include "Core/HLE/sceAudio.h"
|
||||
|
||||
const HLEFunction sceAudioRouting[] =
|
||||
{
|
||||
|
||||
+1
-1
@@ -373,7 +373,7 @@ static void sceCccEncodeUTF16(u32 dstAddrAddr, u32 ucs)
|
||||
}
|
||||
DEBUG_LOG(Log::sceMisc, "sceCccEncodeUTF16(%08x, U+%04x)", dstAddrAddr, ucs);
|
||||
// Anything above 0x10FFFF is unencodable, and 0xD800 - 0xDFFF are reserved for surrogate pairs.
|
||||
if (ucs > 0x10FFFF || (ucs & 0xD800) == 0xD800)
|
||||
if (ucs > 0x10FFFF || (ucs & 0xF800) == 0xD800)
|
||||
ucs = errorUTF16;
|
||||
*dstp += UTF16LE::encode(*dstp, ucs);
|
||||
}
|
||||
|
||||
@@ -140,8 +140,15 @@ static u32 sceHeapAllocHeapMemoryWithOption(u32 heapAddr, u32 memSize, u32 param
|
||||
}
|
||||
|
||||
// There's 8 bytes at the end of every block, reserved.
|
||||
if (memSize > 0xFFFFFF00) {
|
||||
return hleLogError(Log::HLE, 0, "invalid size %08x", memSize);
|
||||
}
|
||||
memSize += 8;
|
||||
u32 addr = heap->alloc.AllocAligned(memSize, grain, grain, true);
|
||||
// This returns a pointer, so failure is null rather than the allocator's -1 (like sceKernelAllocHeapMemory).
|
||||
if (addr == (u32)-1) {
|
||||
return hleLogError(Log::HLE, 0, "failed to allocate %d bytes", memSize);
|
||||
}
|
||||
return hleLogDebug(Log::HLE, addr);
|
||||
}
|
||||
|
||||
@@ -179,6 +186,7 @@ static int sceHeapDeleteHeap(u32 heapAddr) {
|
||||
}
|
||||
|
||||
heapList.erase(heapAddr);
|
||||
userMemory.Free(heap->address);
|
||||
delete heap;
|
||||
return hleLogDebug(Log::HLE, 0);
|
||||
}
|
||||
@@ -222,9 +230,15 @@ static u32 sceHeapAllocHeapMemory(u32 heapAddr, u32 memSize) {
|
||||
}
|
||||
|
||||
// There's 8 bytes at the end of every block, reserved.
|
||||
if (memSize > 0xFFFFFF00) {
|
||||
return hleLogError(Log::HLE, 0, "invalid size %08x", memSize);
|
||||
}
|
||||
memSize += 8;
|
||||
// Always goes down, regardless of whether the heap is high or low.
|
||||
u32 addr = heap->alloc.Alloc(memSize, true);
|
||||
if (addr == (u32)-1) {
|
||||
return hleLogError(Log::HLE, 0, "failed to allocate %d bytes", memSize);
|
||||
}
|
||||
return hleLogDebug(Log::HLE, addr);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,9 @@ static inline int getScaleValue(u32 channelsNum) {
|
||||
|
||||
// What is this??
|
||||
static u32 sceP3daBridgeCore(u32 p3daCoreAddr, u32 channelsNum, u32 samplesNum, u32 inputAddr, u32 outputAddr) {
|
||||
if (Memory::IsValidRange(inputAddr, channelsNum * 4) && Memory::IsValidRange(outputAddr, samplesNum * sizeof(s16) * 2)) {
|
||||
// The sizes could wrap in 32 bits.
|
||||
if ((u64)channelsNum * 4 <= 0xFFFFFFFF && (u64)samplesNum * sizeof(s16) * 2 <= 0xFFFFFFFF &&
|
||||
Memory::IsValidRange(inputAddr, channelsNum * 4) && Memory::IsValidRange(outputAddr, samplesNum * sizeof(s16) * 2)) {
|
||||
int scaleval = getScaleValue(channelsNum);
|
||||
s16_le *outbuf = (s16_le *)Memory::GetPointerWriteUnchecked(outputAddr);
|
||||
memset(outbuf, 0, samplesNum * sizeof(s16) * 2);
|
||||
|
||||
+6
-2
@@ -23,6 +23,8 @@
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <time.h>
|
||||
|
||||
#include "Common/Serialize/Serializer.h"
|
||||
@@ -998,7 +1000,8 @@ static int __RtcFormatRFC2822(u32 outPtr, u32 srcTickPtr, int tz) {
|
||||
local.tm_year += 400;
|
||||
while (local.tm_year >= 470)
|
||||
local.tm_year -= 400;
|
||||
local.tm_min += tz;
|
||||
// tz is from the game, keep the sum from overflowing.
|
||||
local.tm_min = (int)std::clamp<s64>((s64)local.tm_min + tz, INT_MIN / 2, INT_MAX / 2);
|
||||
rtc_timegm(&local);
|
||||
|
||||
char *out = (char *)Memory::GetPointerWriteUnchecked(outPtr);
|
||||
@@ -1029,7 +1032,8 @@ static int __RtcFormatRFC3339(u32 outPtr, u32 srcTickPtr, int tz) {
|
||||
local.tm_year += 400;
|
||||
while (local.tm_year >= 470)
|
||||
local.tm_year -= 400;
|
||||
local.tm_min += tz;
|
||||
// tz is from the game, keep the sum from overflowing.
|
||||
local.tm_min = (int)std::clamp<s64>((s64)local.tm_min + tz, INT_MIN / 2, INT_MAX / 2);
|
||||
rtc_timegm(&local);
|
||||
|
||||
char *out = (char *)Memory::GetPointerWriteUnchecked(outPtr);
|
||||
|
||||
+7
-2
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
@@ -77,7 +78,8 @@ static std::mutex sasWakeMutex;
|
||||
static std::mutex sasDoneMutex;
|
||||
static std::condition_variable sasWake;
|
||||
static std::condition_variable sasDone;
|
||||
static volatile int sasThreadState = SasThreadState::DISABLED;
|
||||
// Changed under sasWakeMutex (and sasDoneMutex for READY), but also read outside them.
|
||||
static std::atomic<int> sasThreadState{ SasThreadState::DISABLED };
|
||||
static SasThreadParams sasThreadParams;
|
||||
static int sasMixEvent = -1;
|
||||
|
||||
@@ -92,7 +94,10 @@ int __SasThread() {
|
||||
|
||||
std::unique_lock<std::mutex> guard(sasWakeMutex);
|
||||
while (sasThreadState != SasThreadState::DISABLED) {
|
||||
sasWake.wait(guard);
|
||||
// Check before sleeping, the mix may have been queued before we got here.
|
||||
while (sasThreadState == SasThreadState::READY) {
|
||||
sasWake.wait(guard);
|
||||
}
|
||||
if (sasThreadState == SasThreadState::QUEUED) {
|
||||
const bool mute = g_sasMuteFlag;
|
||||
sas->Mix(sasThreadParams.outAddr, sasThreadParams.inAddr, sasThreadParams.leftVol, sasThreadParams.rightVol, mute);
|
||||
|
||||
@@ -26,6 +26,12 @@
|
||||
#include "Core/HLE/sceSfmt19937.h"
|
||||
|
||||
|
||||
// The library indexes its state with idx, which lives in game memory.
|
||||
static bool ValidSfmtIndex(u32 sfmt) {
|
||||
const sfmt_t *psfmt = (const sfmt_t *)Memory::GetPointerUnchecked(sfmt);
|
||||
return psfmt->idx >= 0 && psfmt->idx <= SFMT_N32;
|
||||
}
|
||||
|
||||
static int sceSfmt19937InitGenRand(u32 sfmt, u32 seed) {
|
||||
if (!Memory::IsValidAddress(sfmt)) {
|
||||
ERROR_LOG(Log::HLE, "sceSfmt19937InitGenRand(sfmt=%08x, seed=%08x) - bad address(es)", sfmt, seed);
|
||||
@@ -54,7 +60,7 @@ static int sceSfmt19937InitByArray(u32 sfmt, u32 seeds, int seedslen) {
|
||||
}
|
||||
|
||||
static u32 sceSfmt19937GenRand32(u32 sfmt) {
|
||||
if (!Memory::IsValidAddress(sfmt)) {
|
||||
if (!Memory::IsValidAddress(sfmt) || !ValidSfmtIndex(sfmt)) {
|
||||
ERROR_LOG(Log::HLE, "sceSfmt19937GenRand32(sfmt=%08x) - bad address(es)", sfmt);
|
||||
return -1;
|
||||
}
|
||||
@@ -67,7 +73,7 @@ static u32 sceSfmt19937GenRand32(u32 sfmt) {
|
||||
}
|
||||
|
||||
static u64 sceSfmt19937GenRand64(u32 sfmt) {
|
||||
if (!Memory::IsValidAddress(sfmt)) {
|
||||
if (!Memory::IsValidAddress(sfmt) || !ValidSfmtIndex(sfmt)) {
|
||||
ERROR_LOG(Log::HLE, "sceSfmt19937GenRand64(sfmt=%08x) - bad address(es)", sfmt);
|
||||
return -1;
|
||||
}
|
||||
@@ -80,7 +86,8 @@ static u64 sceSfmt19937GenRand64(u32 sfmt) {
|
||||
}
|
||||
|
||||
static int sceSfmt19937FillArray32(u32 sfmt, u32 array, int arraylen) {
|
||||
if (!Memory::IsValidAddress(sfmt) || !Memory::IsValidAddress(array) || !Memory::IsValidAddress(array + 4 * (arraylen - 1))) {
|
||||
// The library fills whole blocks, and needs at least a state's worth of them.
|
||||
if (arraylen < SFMT_N32 || (arraylen % 4) != 0 || !Memory::IsValidAddress(sfmt) || !Memory::IsValidAddress(array) || !Memory::IsValidAddress(array + 4 * (arraylen - 1))) {
|
||||
ERROR_LOG(Log::HLE, "sceSfmt19937FillArray32(sfmt=%08x, ar=%08x, arlen=%08x) - bad address(es)", sfmt, array, arraylen);
|
||||
return -1;
|
||||
}
|
||||
@@ -94,7 +101,8 @@ static int sceSfmt19937FillArray32(u32 sfmt, u32 array, int arraylen) {
|
||||
}
|
||||
|
||||
static int sceSfmt19937FillArray64(u32 sfmt, u32 array, int arraylen) {
|
||||
if (!Memory::IsValidAddress(sfmt) || !Memory::IsValidAddress(array) || !Memory::IsValidAddress(array + 8 * (arraylen - 1))) {
|
||||
// The library fills whole blocks, and needs at least a state's worth of them.
|
||||
if (arraylen < SFMT_N64 || (arraylen % 2) != 0 || !Memory::IsValidAddress(sfmt) || !Memory::IsValidAddress(array) || !Memory::IsValidAddress(array + 8 * (arraylen - 1))) {
|
||||
ERROR_LOG(Log::HLE, "sceSfmt19937FillArray64(sfmt=%08x, ar=%08x, arlen=%08x) - bad address(es)", sfmt, array, arraylen);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -168,7 +168,9 @@ static int sceKernelUnregisterSysEventHandler(u32 handler) {
|
||||
if (!MeCore::g_meState)
|
||||
return hleLogWarning(Log::ME, 0, "no handlers");
|
||||
u32 *link = &MeCore::g_meState->sysEventHandlers;
|
||||
while (*link && Memory::IsValidRange(*link, 0x40)) {
|
||||
// The list is in guest memory, so a loop in it shouldn't hang us.
|
||||
int count = 0;
|
||||
while (*link && Memory::IsValid4AlignedRange(*link, 0x40) && count++ < 0x10000) {
|
||||
if (*link == handler) {
|
||||
*link = Memory::ReadUnchecked_U32(handler + 0x18);
|
||||
return hleLogDebug(Log::ME, 0);
|
||||
|
||||
+9
-1
@@ -76,6 +76,12 @@ static void UsbWaitExecTimeout(u64 userdata, int cycleslate) {
|
||||
u32 error;
|
||||
SceUID threadID = (SceUID)userdata;
|
||||
|
||||
// The thread may have stopped waiting on USB since (for example, released), keeping the event.
|
||||
if (__KernelGetWaitID(threadID, WAITTYPE_USB, error) == 0 || error != 0) {
|
||||
HLEKernel::RemoveWaitingThread(waitingThreads, threadID);
|
||||
return;
|
||||
}
|
||||
|
||||
PSPPointer<int> timeout = PSPPointer<int>::Create(__KernelGetWaitTimeoutPtr(threadID, error));
|
||||
if (timeout.IsValid())
|
||||
*timeout = 0;
|
||||
@@ -91,7 +97,8 @@ static void UsbUpdateState() {
|
||||
for (size_t i = 0; i < waitingThreads.size(); ++i) {
|
||||
SceUID threadID = waitingThreads[i];
|
||||
int state = __KernelGetWaitID(threadID, WAITTYPE_USB, error);
|
||||
if (error != 0)
|
||||
// 0 means it's not in a USB wait anymore. Waits always have a nonzero state.
|
||||
if (error != 0 || state == 0)
|
||||
continue;
|
||||
|
||||
u32 mode = __KernelGetWaitValue(threadID, error);
|
||||
@@ -109,6 +116,7 @@ static void UsbUpdateState() {
|
||||
}
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, UsbCurrentState());
|
||||
wokeThreads = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -94,6 +94,8 @@ void __UsbCamShutdown() {
|
||||
if (config->mode == Camera::Mode::Video) { // stillImage? TBD
|
||||
Camera::stopCapture();
|
||||
}
|
||||
// Capture can still deliver a frame after stopCapture(), on its own thread.
|
||||
std::lock_guard<std::mutex> lock(videoBufferMutex);
|
||||
delete[] videoBuffer;
|
||||
videoBuffer = nullptr;
|
||||
delete config;
|
||||
@@ -422,7 +424,9 @@ void Camera::onCameraDeviceChange() {
|
||||
}
|
||||
}
|
||||
|
||||
// Called from the capture thread.
|
||||
int Camera::getMaxFrameSize() {
|
||||
std::lock_guard<std::mutex> lock(videoBufferMutex);
|
||||
int framesize = 0;
|
||||
if (config) {
|
||||
if (config->type == Camera::ConfigType::CfVideoEx) {
|
||||
|
||||
+12
-3
@@ -16,6 +16,7 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <ctime>
|
||||
#include <mutex>
|
||||
|
||||
#include "Common/System/System.h"
|
||||
#include "Common/System/Request.h"
|
||||
@@ -39,6 +40,8 @@ GpsStatus gpsStatus = GPS_STATE_OFF;
|
||||
GpsData gpsData;
|
||||
SatData satData;
|
||||
time_t lastGPSTime;
|
||||
// The platform's location callbacks set these from their own thread.
|
||||
static std::recursive_mutex gpsLock;
|
||||
|
||||
void __UsbGpsInit() {
|
||||
gpsStatus = GPS_STATE_OFF;
|
||||
@@ -99,6 +102,7 @@ static int sceUsbGpsClose() {
|
||||
}
|
||||
|
||||
static int sceUsbGpsGetData(u32 gpsDataAddr, u32 satDataAddr) {
|
||||
std::lock_guard<std::recursive_mutex> guard(gpsLock);
|
||||
time_t currentTime;
|
||||
time(¤tTime);
|
||||
if (difftime(currentTime, lastGPSTime) > AUTO_UPDATE_GPSTIME)
|
||||
@@ -116,7 +120,7 @@ static int sceUsbGpsGetData(u32 gpsDataAddr, u32 satDataAddr) {
|
||||
auto satData = PSPPointer<SatData>::Create(satDataAddr);
|
||||
if (satData.IsValid()) {
|
||||
*satData = *GPS::getSatData();
|
||||
gpsData.NotifyWrite("UsbGpsGetData");
|
||||
satData.NotifyWrite("UsbGpsGetData");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -167,6 +171,7 @@ void GPS::init() {
|
||||
}
|
||||
|
||||
void GPS::setGpsTime(time_t *time) {
|
||||
std::lock_guard<std::recursive_mutex> guard(gpsLock);
|
||||
struct tm *gpsTime;
|
||||
gpsTime = gmtime(time);
|
||||
|
||||
@@ -179,8 +184,9 @@ void GPS::setGpsTime(time_t *time) {
|
||||
}
|
||||
|
||||
void GPS::setGpsData(long long gpsTime, float hdop, float latitude, float longitude, float altitude, float speed, float bearing) {
|
||||
lastGPSTime = gpsTime;
|
||||
setGpsTime((time_t*)&gpsTime);
|
||||
std::lock_guard<std::recursive_mutex> guard(gpsLock);
|
||||
lastGPSTime = (time_t)gpsTime;
|
||||
setGpsTime(&lastGPSTime);
|
||||
|
||||
gpsData.hdop = hdop;
|
||||
gpsData.latitude = latitude;
|
||||
@@ -191,6 +197,9 @@ void GPS::setGpsData(long long gpsTime, float hdop, float latitude, float longit
|
||||
}
|
||||
|
||||
void GPS::setSatInfo(short index, unsigned char id, unsigned char elevation, short azimuth, unsigned char snr, unsigned char good) {
|
||||
if (index < 0 || index >= (short)ARRAY_SIZE(satData.satInfo))
|
||||
return;
|
||||
std::lock_guard<std::recursive_mutex> guard(gpsLock);
|
||||
satData.satInfo[index].id = id;
|
||||
satData.satInfo[index].elevation = elevation;
|
||||
satData.satInfo[index].azimuth = azimuth;
|
||||
|
||||
+16
-2
@@ -168,6 +168,10 @@ void __UsbMicDoState(PointerWrap &p) {
|
||||
Do(p, waitingThreads);
|
||||
Do(p, isNeedInput);
|
||||
Do(p, curSampleRate);
|
||||
if (curSampleRate == 0) {
|
||||
// Old states could have one, from before __MicInput checked it.
|
||||
curSampleRate = 44100;
|
||||
}
|
||||
Do(p, curChannels);
|
||||
Do(p, micState);
|
||||
if (s > 1) {
|
||||
@@ -433,6 +437,14 @@ void Microphone::onMicDeviceChange() {
|
||||
}
|
||||
|
||||
u32 __MicInput(u32 maxSamples, u32 sampleRate, u32 bufAddr, MICTYPE type, bool block) {
|
||||
// The camera mic passes these straight through (sceAudioInput checks them first). The wait below
|
||||
// divides by the rate, and the size sizes a host buffer.
|
||||
if (sampleRate == 0) {
|
||||
return SCE_ERROR_USBMIC_INVALID_SAMPLERATE;
|
||||
}
|
||||
if (maxSamples == 0 || maxSamples > 0x100000) {
|
||||
return SCE_ERROR_USBMIC_INVALID_MAX_SAMPLES;
|
||||
}
|
||||
if (micPolling && curSampleRate != sampleRate) {
|
||||
Microphone::stopMic();
|
||||
}
|
||||
@@ -472,9 +484,11 @@ u32 __MicInput(u32 maxSamples, u32 sampleRate, u32 bufAddr, MICTYPE type, bool b
|
||||
MicWaitInfo waitInfo = { __KernelGetCurThread(), bufAddr, size, sampleRate };
|
||||
waitingThreads.push_back(waitInfo);
|
||||
DEBUG_LOG(Log::HLE, "MicInputBlocking: blocking thread(%d)", (int)__KernelGetCurThread());
|
||||
__KernelWaitCurThread(WAITTYPE_MICINPUT, 1, size, 0, false, "blocking microphone");
|
||||
// The wait value is what the thread gets back when it's woken.
|
||||
const u32 result = type == CAMERAMIC ? size : maxSamples;
|
||||
__KernelWaitCurThread(WAITTYPE_MICINPUT, 1, result, 0, false, "blocking microphone");
|
||||
|
||||
return type == CAMERAMIC ? size : maxSamples;
|
||||
return result;
|
||||
}
|
||||
|
||||
// A non-blocking input keeps filling its buffer from addAudioData() after it returns.
|
||||
|
||||
@@ -123,7 +123,8 @@ public:
|
||||
switch (offset) {
|
||||
case 0x008:
|
||||
{
|
||||
*value = (data_[dataIndex_] << 8) | data_[dataIndex_ + 1];
|
||||
// Writes can move the index anywhere.
|
||||
*value = (dataIndex_ >= 0 && dataIndex_ + 1 < DATA_SIZE) ? (data_[dataIndex_] << 8) | data_[dataIndex_ + 1] : 0;
|
||||
dataIndex_ += 2;
|
||||
if (dataIndex_ > responseLen_) {
|
||||
dataIndex_ = 0;
|
||||
@@ -162,7 +163,8 @@ public:
|
||||
data_[dataIndex_] = (value >> 8) & 0xFF;
|
||||
data_[dataIndex_ + 1] = value & 0xFF;
|
||||
}
|
||||
dataIndex_ += 2;
|
||||
if (dataIndex_ < DATA_SIZE)
|
||||
dataIndex_ += 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -184,6 +186,9 @@ public:
|
||||
return;
|
||||
DoArray(p, data_, DATA_SIZE);
|
||||
Do(p, dataIndex_);
|
||||
if (p.mode == PointerWrap::MODE_READ && (dataIndex_ < 0 || dataIndex_ > DATA_SIZE)) {
|
||||
dataIndex_ = 0;
|
||||
}
|
||||
Do(p, responseLen_);
|
||||
Do(p, dataExhausted_);
|
||||
Do(p, alarm_);
|
||||
|
||||
@@ -77,7 +77,8 @@ void GranularMixer::Mix(s16 *samples, u32 num_samples, int outSampleRate, float
|
||||
if (!samples)
|
||||
return;
|
||||
memset(samples, 0, num_samples * 2 * sizeof(s16));
|
||||
frameTimeEstimate_ = 1.0f / fpsEstimate;
|
||||
// The estimate is 0 until a second has gone by.
|
||||
frameTimeEstimate_ = 1.0f / std::max(fpsEstimate, 1.0f);
|
||||
|
||||
smoothedReadSize_ = smoothedReadSize_ == 0 ? num_samples : (smoothedReadSize_ * 0.95f + num_samples * 0.05f);
|
||||
|
||||
@@ -262,7 +263,8 @@ void GranularMixer::Dequeue(Granule *granule) {
|
||||
/*if (!looping && !smoothedQueueSize_ < granule_queue_size / 2) {
|
||||
// Repeat a single block occasionally to make sure we have a reasonably sized queue.
|
||||
next_tail = tail;
|
||||
} else*/ if (next_tail == head) {
|
||||
} else*/ if (next_tail == head || tail == head) {
|
||||
// Empty (or about to be). tail == head would read the granule being written next.
|
||||
// Only fill gaps when running to prevent stutter on pause.
|
||||
CoreState state = coreState;
|
||||
const bool is_running = state == CORE_RUNNING_CPU || state == CORE_RUNNING_GE;
|
||||
|
||||
+2
-1
@@ -289,7 +289,8 @@ private:
|
||||
const bool separate = (output & 1) != 0;
|
||||
d.csc[(0x160 - 0x120) / 4] &= ~1;
|
||||
d.intTCStatus |= 2;
|
||||
if (width == 0 || height == 0 || stride < width) {
|
||||
// A wider stride than any framebuffer would only overflow the size math below.
|
||||
if (width == 0 || height == 0 || stride < width || stride > 4096) {
|
||||
ERROR_LOG(Log::ME, "DMACplus: bad colour space conversion %dx%d, stride %d", width, height, stride);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -671,7 +671,9 @@ void SasInstance::Mix(u32 outAddr, u32 inAddr, int leftVol, int rightVol, bool m
|
||||
// Then mix the send buffer in with the rest.
|
||||
|
||||
// Alright, all voices mixed. Let's convert and clip, and at the same time, wipe mixBuffer for next time. Could also dither.
|
||||
s16 *outp = (s16 *)Memory::GetPointerWriteRangeOrException(outAddr, 4 * grainSize);
|
||||
// Raw mode writes four planes of grainSize samples, mixed mode two interleaved.
|
||||
const u32 outBytes = (outputMode == PSP_SAS_OUTPUTMODE_MIXED ? 4 : 8) * grainSize;
|
||||
s16 *outp = (s16 *)Memory::GetPointerWriteRangeOrException(outAddr, outBytes);
|
||||
const s16 *inp = inAddr ? (const s16 *)Memory::GetPointerRangeOrException(inAddr, 4 * grainSize) : 0;
|
||||
if (!outp) {
|
||||
WARN_LOG_REPORT(Log::sceSas, "Bad SAS Mix output address: %08x, grain=%d", outAddr, grainSize);
|
||||
|
||||
+1
-1
Submodule pspautotests updated: fab33ea469...e2d098fcf3.
Reference in new issue
Block a user