Merge pull request #22811 from hrydgard/misc-logic-fixes

Misc logic fixes from a Claude code review
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-10-27 12:35:59 +01:00
commit 2ee1a0bea7
24 files changed
+204 -88

No files matched your search

+5 -3
View File
@@ -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;
+2
View File
@@ -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,
+13 -5
View File
@@ -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.
+9 -1
View File
@@ -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
View File
@@ -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', "" },
};
+9
View File
@@ -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();
+1 -33
View File
@@ -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
View File
@@ -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);
}
+14
View File
@@ -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);
}
+3 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+12 -4
View File
@@ -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;
}
+3 -1
View File
@@ -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
View File
@@ -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;
}
}
+4
View File
@@ -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
View File
@@ -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(&currentTime);
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
View File
@@ -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.
+7 -2
View File
@@ -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_);
+4 -2
View File
@@ -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
View File
@@ -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;
}
+3 -1
View File
@@ -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);
+2
View File
@@ -173,6 +173,8 @@ tests_good = [
"audio/blocking/vaudio",
"audio/sceaudio/reserve",
"audio/sceaudio/datalen",
"audio/sceaudio/input",
"audio/sceaudio/routing",
"audio/output2/changelength",
"audio/output2/release",
"audio/output2/reserve",