From 3acca0f9412130bc7638569afaff793611139065 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 11 Nov 2012 17:05:44 -0800 Subject: [PATCH 01/13] Fix crash in sceKernelReferSemaStatus. This was crashing threads/semaphores, and also PQ2 (and maybe other games.) Note: threads/semaphores still not passing. --- Core/HLE/sceKernelSemaphore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 11d71ceaf6..6dec8ebd70 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -72,6 +72,7 @@ void sceKernelCreateSema() Semaphore *s = new Semaphore; SceUID id = kernelObjects.Create(s); + s->ns.size = sizeof(NativeSemaphore); strncpy(s->ns.name, name, 32); s->ns.attr = PARAM(1); s->ns.initCount = PARAM(2); @@ -101,8 +102,7 @@ void sceKernelReferSemaStatus() { DEBUG_LOG(HLE,"sceKernelReferSemaStatus(%i, %08x)", id, PARAM(1)); NativeSemaphore *outptr = (NativeSemaphore*)Memory::GetPointer(PARAM(1)); - int szToCopy = outptr->size - 4; - memcpy((char*)outptr + 4, (char*)s + 4, szToCopy); + memcpy((char*)outptr, (char*)&s->ns, s->ns.size); RETURN(0); } else From 8e2fff97bfe67e72a6bc7c34f5e913cb7af8106d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 11 Nov 2012 17:57:35 -0800 Subject: [PATCH 02/13] Wrap a few semaphore sceKernel* funcs. --- Core/HLE/FunctionWrappers.h | 5 +++ Core/HLE/sceKernel.cpp | 10 +++--- Core/HLE/sceKernelSemaphore.cpp | 57 +++++++++++++-------------------- Core/HLE/sceKernelSemaphore.h | 10 +++--- 4 files changed, 38 insertions(+), 44 deletions(-) diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index 6202100614..67faba3592 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -90,6 +90,11 @@ template void WrapI_III() { RETURN(retval); } +template void WrapI_IIU() { + int retval = func(PARAM(0), PARAM(1), PARAM(2)); + RETURN(retval); +} + template void WrapV_IU() { func(PARAM(0), PARAM(1)); } diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index e7ca6436dd..34431aa4e2 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -333,11 +333,11 @@ const HLEFunction ThreadManForUser[] = {0x8FFDF9A2,sceKernelCancelSema, "sceKernelCancelSema"}, {0xD6DA4BA1,sceKernelCreateSema, "sceKernelCreateSema"}, {0x28b6489c,sceKernelDeleteSema, "sceKernelDeleteSema"}, - {0x58b1f937,sceKernelPollSema, "sceKernelPollSema"}, - {0xBC6FEBC5,sceKernelReferSemaStatus,"sceKernelReferSemaStatus"}, - {0x3F53E640,sceKernelSignalSema, "sceKernelSignalSema"}, - {0x4E3A1105,sceKernelWaitSema, "sceKernelWaitSema"}, - {0x6d212bac,sceKernelWaitSemaCB, "sceKernelWaitSemaCB"}, + {0x58b1f937,&WrapI_II, "sceKernelPollSema"}, + {0xBC6FEBC5,&WrapI_IU, "sceKernelReferSemaStatus"}, + {0x3F53E640,&WrapI_II, "sceKernelSignalSema"}, + {0x4E3A1105,&WrapI_IIU, "sceKernelWaitSema"}, + {0x6d212bac,&WrapI_IIU, "sceKernelWaitSemaCB"}, {0x60107536,0,"sceKernelDeleteLwMutex"}, {0x19CFF145,0,"sceKernelCreateLwMutex"}, diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 6dec8ebd70..340696d4cc 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -93,31 +93,28 @@ void sceKernelDeleteSema() RETURN(kernelObjects.Destroy(id)); } -void sceKernelReferSemaStatus() +int sceKernelReferSemaStatus(SceUID id, u32 infoPtr) { - SceUID id = PARAM(0); u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { - DEBUG_LOG(HLE,"sceKernelReferSemaStatus(%i, %08x)", id, PARAM(1)); - NativeSemaphore *outptr = (NativeSemaphore*)Memory::GetPointer(PARAM(1)); + DEBUG_LOG(HLE,"sceKernelReferSemaStatus(%i, %08x)", id, infoPtr); + NativeSemaphore *outptr = (NativeSemaphore*)Memory::GetPointer(infoPtr); memcpy((char*)outptr, (char*)&s->ns, s->ns.size); - RETURN(0); + return 0; } else { ERROR_LOG(HLE,"Error %08x", error); - RETURN(error); + return error; } } //int sceKernelSignalSema(SceUID semaid, int signal); -void sceKernelSignalSema() +int sceKernelSignalSema(SceUID id, int signal) { //TODO: check that this thing really works :) - SceUID id = PARAM(0); - u32 signal = PARAM(1); u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) @@ -154,22 +151,18 @@ retry: // I don't think we should reschedule here //if (wokeThreads) // __KernelReSchedule("semaphore signalled"); - + return 0; } else { ERROR_LOG(HLE, "sceKernelSignalSema : Trying to signal invalid semaphore %i", id); - RETURN(error); + return error; } } //int sceKernelWaitSema(SceUID semaid, int signal, SceUInt *timeout); -void sceKernelWaitSema() +int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) { - SceUID id = PARAM(0); - int wantedCount = PARAM(1); - u32 timeoutPtr = PARAM(2); - u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) @@ -178,29 +171,27 @@ void sceKernelWaitSema() if (s->ns.currentCount >= wantedCount) //TODO fix { s->ns.currentCount -= wantedCount; - RETURN(0); + return 0; } else { s->waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, 0, false); - return; + return 0; } } else { ERROR_LOG(HLE, "sceKernelWaitSema : Trying to wait for invalid semaphore %i", id); - RETURN(error); + return error; } } //int sceKernelWaitSemaCB(SceUID semaid, int signal, SceUInt *timeout); -void sceKernelWaitSemaCB() +int sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr) { - SceUID id = PARAM(0); - int wantedCount = PARAM(1); - int timeout = PARAM(2); - DEBUG_LOG(HLE,"sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeout); + DEBUG_LOG(HLE,"sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr); + u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) @@ -214,26 +205,24 @@ void sceKernelWaitSemaCB() else { s->waitingThreads.push_back(__KernelGetCurThread()); + // TODO: timeoutPtr? __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, 0, true); __KernelCheckCallbacks(); - return; + return 0; } DEBUG_LOG(HLE,"After: CurrentCount: %i, Signal: %i", s->ns.currentCount, wantedCount); - RETURN(0); + return 0; } else { ERROR_LOG(HLE,"sceKernelWaitSemaCB - Bad semaphore"); - RETURN(error); + return error; } } // Should be same as WaitSema but without the wait, instead returning SCE_KERNEL_ERROR_SEMA_ZERO -void sceKernelPollSema() +int sceKernelPollSema(SceUID id, int wantedCount) { - SceUID id = PARAM(0); - int wantedCount = PARAM(1); - u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) @@ -242,17 +231,17 @@ void sceKernelPollSema() if (s->ns.currentCount >= wantedCount) //TODO fix { s->ns.currentCount -= wantedCount; - RETURN(0); + return 0; } else { - RETURN(SCE_KERNEL_ERROR_SEMA_ZERO); + return SCE_KERNEL_ERROR_SEMA_ZERO; } } else { ERROR_LOG(HLE, "sceKernelPollSema : Trying to poll invalid semaphore %i", id); - RETURN(error); + return error; } } diff --git a/Core/HLE/sceKernelSemaphore.h b/Core/HLE/sceKernelSemaphore.h index e3e5a2925b..65e7ffb3be 100644 --- a/Core/HLE/sceKernelSemaphore.h +++ b/Core/HLE/sceKernelSemaphore.h @@ -20,8 +20,8 @@ void sceKernelCancelSema(); void sceKernelCreateSema(); void sceKernelDeleteSema(); -void sceKernelPollSema(); -void sceKernelReferSemaStatus(); -void sceKernelSignalSema(); -void sceKernelWaitSema(); -void sceKernelWaitSemaCB(); +int sceKernelPollSema(SceUID id, int wantedCount); +int sceKernelReferSemaStatus(SceUID id, u32 infoPtr); +int sceKernelSignalSema(SceUID id, int signal); +int sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr); +int sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr); From deab1c21b73651afdab838dc6386a7c4693e82bb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 11 Nov 2012 17:59:15 -0800 Subject: [PATCH 03/13] Fix sceKernelSignalSema(). Handle numWaitThreads and currentCount more correctly. Well, I'm not 100% sure it's totally right now but it matches the test. --- Core/HLE/sceKernelSemaphore.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 340696d4cc..2cfe84a024 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -121,7 +121,10 @@ int sceKernelSignalSema(SceUID id, int signal) { int oldval = s->ns.currentCount; - s->ns.currentCount += signal; + if (s->ns.currentCount + signal > s->ns.maxCount) + s->ns.currentCount += s->ns.maxCount; + else + s->ns.currentCount += signal; DEBUG_LOG(HLE,"sceKernelSignalSema(%i, %i) (old: %i, new: %i)", id, signal, oldval, s->ns.currentCount); bool wokeThreads = false; @@ -130,12 +133,14 @@ retry: std::vector::iterator iter; for (iter = s->waitingThreads.begin(); iter!=s->waitingThreads.end(); s++) { - SceUID id = *iter; - int wVal = (int)__KernelGetWaitValue(id, error); + SceUID threadID = *iter; + int wVal = (int)__KernelGetWaitValue(threadID, error); if (wVal <= s->ns.currentCount) { - __KernelResumeThreadFromWait(id); s->ns.currentCount -= wVal; + s->ns.numWaitThreads--; + + __KernelResumeThreadFromWait(threadID); wokeThreads = true; s->waitingThreads.erase(iter); goto retry; @@ -175,6 +180,7 @@ int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) } else { + s->ns.numWaitThreads++; s->waitingThreads.push_back(__KernelGetCurThread()); __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, 0, false); return 0; @@ -204,6 +210,7 @@ int sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr) } else { + s->ns.numWaitThreads++; s->waitingThreads.push_back(__KernelGetCurThread()); // TODO: timeoutPtr? __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, 0, true); From 70809bf1f5b55a881f8de04aeb7c972006db771f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 11 Nov 2012 18:10:33 -0800 Subject: [PATCH 04/13] Make sceKernelDeleteSema() resume waiting threads. This makes threads/semaphores *almost* pass. It's now failing from sceKernelStartThread() or something, though. --- Core/HLE/sceKernelSemaphore.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 2cfe84a024..cba77384d9 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -90,7 +90,34 @@ void sceKernelDeleteSema() { SceUID id = PARAM(0); DEBUG_LOG(HLE,"sceKernelDeleteSema(%i)", id); - RETURN(kernelObjects.Destroy(id)); + + u32 error; + Semaphore *s = kernelObjects.Get(id, error); + if (s) + { + bool wokeThreads = false; + + std::vector::iterator iter; + for (iter = s->waitingThreads.begin(); iter!=s->waitingThreads.end(); iter++) + { + SceUID threadID = *iter; + + __KernelResumeThreadFromWait(threadID); + wokeThreads = true; + } + s->waitingThreads.empty(); + + // TODO: Should this reschedule? threads/semaphores fails if it doesn't. + if (wokeThreads) + __KernelReSchedule("semaphore signalled"); + + RETURN(kernelObjects.Destroy(id)); + } + else + { + ERROR_LOG(HLE, "sceKernelSignalSema : Trying to signal invalid semaphore %i", id); + RETURN(error); + } } int sceKernelReferSemaStatus(SceUID id, u32 infoPtr) From e7b6487c4e7aa066bd0724429566ba90b2e3e87b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 11 Nov 2012 18:21:33 -0800 Subject: [PATCH 05/13] Wrap sceKernel DeleteSema and CancelSema. Also fix copy/paste mistake from SignalSema func. --- Core/HLE/sceKernel.cpp | 6 +++--- Core/HLE/sceKernelSemaphore.cpp | 17 ++++++++--------- Core/HLE/sceKernelSemaphore.h | 4 ++-- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 34431aa4e2..43680610ff 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -330,9 +330,9 @@ const HLEFunction ThreadManForUser[] = {0xCD203292,sceKernelCancelEventFlag, "sceKernelCancelEventFlag"}, {0xA66B0120,sceKernelReferEventFlagStatus,"sceKernelReferEventFlagStatus"}, - {0x8FFDF9A2,sceKernelCancelSema, "sceKernelCancelSema"}, - {0xD6DA4BA1,sceKernelCreateSema, "sceKernelCreateSema"}, - {0x28b6489c,sceKernelDeleteSema, "sceKernelDeleteSema"}, + {0x8FFDF9A2,&WrapI_IIU, "sceKernelCancelSema"}, + {0xD6DA4BA1,sceKernelCreateSema, "sceKernelCreateSema"}, + {0x28b6489c,&WrapI_I, "sceKernelDeleteSema"}, {0x58b1f937,&WrapI_II, "sceKernelPollSema"}, {0xBC6FEBC5,&WrapI_IU, "sceKernelReferSemaStatus"}, {0x3F53E640,&WrapI_II, "sceKernelSignalSema"}, diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index cba77384d9..b8315593ec 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -57,11 +57,10 @@ struct Semaphore : public KernelObject std::vector waitingThreads; }; -void sceKernelCancelSema() +int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) { - SceUID id = PARAM(0); ERROR_LOG(HLE,"UNIMPL sceKernelCancelSema(%i)", id); - RETURN(0); + return 0; } //SceUID sceKernelCreateSema(const char *name, SceUInt attr, int initVal, int maxVal, SceKernelSemaOptParam *option); @@ -86,9 +85,8 @@ void sceKernelCreateSema() } //int sceKernelDeleteSema(SceUID semaid); -void sceKernelDeleteSema() +int sceKernelDeleteSema(SceUID id) { - SceUID id = PARAM(0); DEBUG_LOG(HLE,"sceKernelDeleteSema(%i)", id); u32 error; @@ -102,6 +100,7 @@ void sceKernelDeleteSema() { SceUID threadID = *iter; + // TODO: Set SCE_KERNEL_ERROR_WAIT_DELETE returnValue? __KernelResumeThreadFromWait(threadID); wokeThreads = true; } @@ -109,14 +108,14 @@ void sceKernelDeleteSema() // TODO: Should this reschedule? threads/semaphores fails if it doesn't. if (wokeThreads) - __KernelReSchedule("semaphore signalled"); + __KernelReSchedule("semaphore deleted"); - RETURN(kernelObjects.Destroy(id)); + return kernelObjects.Destroy(id); } else { - ERROR_LOG(HLE, "sceKernelSignalSema : Trying to signal invalid semaphore %i", id); - RETURN(error); + ERROR_LOG(HLE, "sceKernelDeleteSema : Trying to delete invalid semaphore %i", id); + return error; } } diff --git a/Core/HLE/sceKernelSemaphore.h b/Core/HLE/sceKernelSemaphore.h index 65e7ffb3be..1a92cc40ba 100644 --- a/Core/HLE/sceKernelSemaphore.h +++ b/Core/HLE/sceKernelSemaphore.h @@ -17,9 +17,9 @@ #pragma once -void sceKernelCancelSema(); +int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr); void sceKernelCreateSema(); -void sceKernelDeleteSema(); +int sceKernelDeleteSema(SceUID id); int sceKernelPollSema(SceUID id, int wantedCount); int sceKernelReferSemaStatus(SceUID id, u32 infoPtr); int sceKernelSignalSema(SceUID id, int signal); From a69fd56573a38c143f5b365360092d8464a3e24f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 11 Nov 2012 18:33:13 -0800 Subject: [PATCH 06/13] Implement sceKernelCancelSema() based on jpcsp. Don't have any tests/users, but this jpcsp's behavior seems sane. --- Core/HLE/sceKernelSemaphore.cpp | 43 +++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index b8315593ec..5c7246eb8c 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -59,8 +59,47 @@ struct Semaphore : public KernelObject int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) { - ERROR_LOG(HLE,"UNIMPL sceKernelCancelSema(%i)", id); - return 0; + DEBUG_LOG(HLE,"sceKernelCancelSema(%i)", id); + + u32 error; + Semaphore *s = kernelObjects.Get(id, error); + if (s) + { + if (numWaitThreadsPtr) + { + u32* numWaitThreads = (u32*)Memory::GetPointer(numWaitThreadsPtr); + *numWaitThreads = s->ns.numWaitThreads; + } + + if (newCount == -1) + s->ns.currentCount = s->ns.initCount; + else + s->ns.currentCount = newCount; + s->ns.numWaitThreads = 0; + + bool wokeThreads = false; + + std::vector::iterator iter; + for (iter = s->waitingThreads.begin(); iter!=s->waitingThreads.end(); iter++) + { + SceUID threadID = *iter; + + // TODO: Set SCE_KERNEL_ERROR_WAIT_CANCEL returnValue? + __KernelResumeThreadFromWait(threadID); + wokeThreads = true; + } + s->waitingThreads.empty(); + + if (wokeThreads) + __KernelReSchedule("semaphore cancelled"); + + return 0; + } + else + { + ERROR_LOG(HLE, "sceKernelCancelSema : Trying to cancel invalid semaphore %i", id); + return error; + } } //SceUID sceKernelCreateSema(const char *name, SceUInt attr, int initVal, int maxVal, SceKernelSemaOptParam *option); From b58032039b26dc281dbc1f3e5de0d6b4ecc2998d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 11 Nov 2012 18:54:06 -0800 Subject: [PATCH 07/13] Cleanup sceKernel semaphore funcs. Remove some duplication of code so it's cleaner. --- Core/HLE/sceKernelSemaphore.cpp | 114 +++++++++++++------------------- 1 file changed, 45 insertions(+), 69 deletions(-) diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 5c7246eb8c..1e2270eaa8 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -57,6 +57,26 @@ struct Semaphore : public KernelObject std::vector waitingThreads; }; +// Resume all waiting threads (for delete / cancel.) +// Returns true if it woke any threads. +bool __KernelClearSemaThreads(Semaphore *s, int reason) +{ + bool wokeThreads = false; + + std::vector::iterator iter; + for (iter = s->waitingThreads.begin(); iter!=s->waitingThreads.end(); iter++) + { + SceUID threadID = *iter; + + // TODO: Set returnValue = reason? + __KernelResumeThreadFromWait(threadID); + wokeThreads = true; + } + s->waitingThreads.empty(); + + return wokeThreads; +} + int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) { DEBUG_LOG(HLE,"sceKernelCancelSema(%i)", id); @@ -77,20 +97,8 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) s->ns.currentCount = newCount; s->ns.numWaitThreads = 0; - bool wokeThreads = false; - - std::vector::iterator iter; - for (iter = s->waitingThreads.begin(); iter!=s->waitingThreads.end(); iter++) - { - SceUID threadID = *iter; - - // TODO: Set SCE_KERNEL_ERROR_WAIT_CANCEL returnValue? - __KernelResumeThreadFromWait(threadID); - wokeThreads = true; - } - s->waitingThreads.empty(); - - if (wokeThreads) + // TODO: Should this reschedule? + if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_CANCEL)) __KernelReSchedule("semaphore cancelled"); return 0; @@ -132,21 +140,8 @@ int sceKernelDeleteSema(SceUID id) Semaphore *s = kernelObjects.Get(id, error); if (s) { - bool wokeThreads = false; - - std::vector::iterator iter; - for (iter = s->waitingThreads.begin(); iter!=s->waitingThreads.end(); iter++) - { - SceUID threadID = *iter; - - // TODO: Set SCE_KERNEL_ERROR_WAIT_DELETE returnValue? - __KernelResumeThreadFromWait(threadID); - wokeThreads = true; - } - s->waitingThreads.empty(); - // TODO: Should this reschedule? threads/semaphores fails if it doesn't. - if (wokeThreads) + if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE)) __KernelReSchedule("semaphore deleted"); return kernelObjects.Destroy(id); @@ -230,32 +225,39 @@ retry: } } -//int sceKernelWaitSema(SceUID semaid, int signal, SceUInt *timeout); -int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) +int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *badSemaMessage, bool processCallbacks) { u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { - DEBUG_LOG(HLE,"sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr); if (s->ns.currentCount >= wantedCount) //TODO fix - { s->ns.currentCount -= wantedCount; - return 0; - } else { s->ns.numWaitThreads++; s->waitingThreads.push_back(__KernelGetCurThread()); - __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, 0, false); - return 0; + // TODO: timeoutPtr? + __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, 0, processCallbacks); + if (processCallbacks) + __KernelCheckCallbacks(); } + + return 0; } else { - ERROR_LOG(HLE, "sceKernelWaitSema : Trying to wait for invalid semaphore %i", id); + ERROR_LOG(HLE, badSemaMessage, id); return error; } +} + +//int sceKernelWaitSema(SceUID semaid, int signal, SceUInt *timeout); +int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) +{ + DEBUG_LOG(HLE,"sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr); + + return __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSema: Trying to wait for invalid semaphore %i", false); } //int sceKernelWaitSemaCB(SceUID semaid, int signal, SceUInt *timeout); @@ -263,56 +265,30 @@ int sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr) { DEBUG_LOG(HLE,"sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr); - u32 error; - Semaphore *s = kernelObjects.Get(id, error); - if (s) - { - DEBUG_LOG(HLE,"CurrentCount: %i, Signal: %i", s->ns.currentCount, wantedCount); - if (s->ns.currentCount >= wantedCount) //TODO fix - { - DEBUG_LOG(HLE,"Subtracting"); - s->ns.currentCount -= wantedCount; - } - else - { - s->ns.numWaitThreads++; - s->waitingThreads.push_back(__KernelGetCurThread()); - // TODO: timeoutPtr? - __KernelWaitCurThread(WAITTYPE_SEMA, id, wantedCount, 0, true); - __KernelCheckCallbacks(); - return 0; - } - DEBUG_LOG(HLE,"After: CurrentCount: %i, Signal: %i", s->ns.currentCount, wantedCount); - return 0; - } - else - { - ERROR_LOG(HLE,"sceKernelWaitSemaCB - Bad semaphore"); - return error; - } + return __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSemaCB: Trying to wait for invalid semaphore %i", true); } // Should be same as WaitSema but without the wait, instead returning SCE_KERNEL_ERROR_SEMA_ZERO int sceKernelPollSema(SceUID id, int wantedCount) { + DEBUG_LOG(HLE,"sceKernelPollSema(%i, %i)", id, wantedCount); + u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { - DEBUG_LOG(HLE,"sceKernelPollSema(%i, %i)", id, wantedCount); if (s->ns.currentCount >= wantedCount) //TODO fix - { s->ns.currentCount -= wantedCount; - return 0; - } else { return SCE_KERNEL_ERROR_SEMA_ZERO; } + + return 0; } else { - ERROR_LOG(HLE, "sceKernelPollSema : Trying to poll invalid semaphore %i", id); + ERROR_LOG(HLE, "sceKernelPollSema: Trying to poll invalid semaphore %i", id); return error; } } From 33559d23db85bef5ceea5e6f8c32be2f45e69fc5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 11 Nov 2012 19:03:37 -0800 Subject: [PATCH 08/13] sceKernelDeleteSema() not returning 0? Seems to be a bug outside this func, adding a comment at least. --- Core/HLE/sceKernelSemaphore.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 1e2270eaa8..2b22f48c77 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -140,7 +140,9 @@ int sceKernelDeleteSema(SceUID id) Semaphore *s = kernelObjects.Get(id, error); if (s) { - // TODO: Should this reschedule? threads/semaphores fails if it doesn't. + // TODO: Should this reschedule? + // threads/semaphore doesn't get final threads if not, but gets wrong result if so. + // Probably it should and there's a bug with the registers? if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE)) __KernelReSchedule("semaphore deleted"); From f37dd7fefe31d0cd2b12a5fdb7d1f3779bfb4046 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 12 Nov 2012 07:24:40 -0800 Subject: [PATCH 09/13] Fix $v0 on wrong thread in semaphore funcs. Need to RETURN() prior to switching threads or it will write to the wrong thread, oops. --- Core/HLE/FunctionWrappers.h | 4 +++ Core/HLE/sceKernel.cpp | 10 +++--- Core/HLE/sceKernelSemaphore.cpp | 57 +++++++++++++++++++-------------- Core/HLE/sceKernelSemaphore.h | 10 +++--- 4 files changed, 47 insertions(+), 34 deletions(-) diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index 00fb54e3fe..d58a726029 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -142,6 +142,10 @@ template void WrapV_IUU() { func(PARAM(0), PARAM(1), PARAM(2)); } +template void WrapV_IIU() { + func(PARAM(0), PARAM(1), PARAM(2)); +} + template void WrapV_IUUUU() { func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); } diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index aadfb241c4..8f160946eb 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -327,14 +327,14 @@ const HLEFunction ThreadManForUser[] = {0xCD203292,&WrapU_V, "sceKernelCancelEventFlag"}, {0xA66B0120,&WrapU_IU, "sceKernelReferEventFlagStatus"}, - {0x8FFDF9A2,&WrapI_IIU, "sceKernelCancelSema"}, + {0x8FFDF9A2,&WrapV_IIU, "sceKernelCancelSema"}, {0xD6DA4BA1,sceKernelCreateSema, "sceKernelCreateSema"}, - {0x28b6489c,&WrapI_I, "sceKernelDeleteSema"}, + {0x28b6489c,&WrapV_I, "sceKernelDeleteSema"}, {0x58b1f937,&WrapI_II, "sceKernelPollSema"}, {0xBC6FEBC5,&WrapI_IU, "sceKernelReferSemaStatus"}, - {0x3F53E640,&WrapI_II, "sceKernelSignalSema"}, - {0x4E3A1105,&WrapI_IIU, "sceKernelWaitSema"}, - {0x6d212bac,&WrapI_IIU, "sceKernelWaitSemaCB"}, + {0x3F53E640,&WrapV_II, "sceKernelSignalSema"}, + {0x4E3A1105,&WrapV_IIU, "sceKernelWaitSema"}, + {0x6d212bac,&WrapV_IIU, "sceKernelWaitSemaCB"}, {0x60107536,0,"sceKernelDeleteLwMutex"}, {0x19CFF145,0,"sceKernelCreateLwMutex"}, diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 2b22f48c77..600c6e59ab 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -77,7 +77,9 @@ bool __KernelClearSemaThreads(Semaphore *s, int reason) return wokeThreads; } -int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) +// int sceKernelCancelSema(SceUID id, int newCount, int *numWaitThreads); +// void because it changes threads. +void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) { DEBUG_LOG(HLE,"sceKernelCancelSema(%i)", id); @@ -97,16 +99,17 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) s->ns.currentCount = newCount; s->ns.numWaitThreads = 0; + // We need to set the return value BEFORE rescheduling threads. + RETURN(0); + // TODO: Should this reschedule? if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_CANCEL)) __KernelReSchedule("semaphore cancelled"); - - return 0; } else { ERROR_LOG(HLE, "sceKernelCancelSema : Trying to cancel invalid semaphore %i", id); - return error; + RETURN(error); } } @@ -132,7 +135,8 @@ void sceKernelCreateSema() } //int sceKernelDeleteSema(SceUID semaid); -int sceKernelDeleteSema(SceUID id) +// void because it changes threads. +void sceKernelDeleteSema(SceUID id) { DEBUG_LOG(HLE,"sceKernelDeleteSema(%i)", id); @@ -140,18 +144,18 @@ int sceKernelDeleteSema(SceUID id) Semaphore *s = kernelObjects.Get(id, error); if (s) { - // TODO: Should this reschedule? - // threads/semaphore doesn't get final threads if not, but gets wrong result if so. - // Probably it should and there's a bug with the registers? if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE)) + { + RETURN(kernelObjects.Destroy(id)); __KernelReSchedule("semaphore deleted"); - - return kernelObjects.Destroy(id); + } + else + RETURN(kernelObjects.Destroy(id)); } else { ERROR_LOG(HLE, "sceKernelDeleteSema : Trying to delete invalid semaphore %i", id); - return error; + RETURN(error); } } @@ -174,7 +178,8 @@ int sceKernelReferSemaStatus(SceUID id, u32 infoPtr) } //int sceKernelSignalSema(SceUID semaid, int signal); -int sceKernelSignalSema(SceUID id, int signal) +// void because it changes threads. +void sceKernelSignalSema(SceUID id, int signal) { //TODO: check that this thing really works :) u32 error; @@ -188,7 +193,10 @@ int sceKernelSignalSema(SceUID id, int signal) else s->ns.currentCount += signal; DEBUG_LOG(HLE,"sceKernelSignalSema(%i, %i) (old: %i, new: %i)", id, signal, oldval, s->ns.currentCount); - + + // We need to set the return value BEFORE processing other threads. + RETURN(0); + bool wokeThreads = false; retry: //TODO: check for threads to wake up - wake them @@ -212,27 +220,28 @@ retry: break; } } - // RETURN(0); //pop the thread that were released from waiting // I don't think we should reschedule here //if (wokeThreads) // __KernelReSchedule("semaphore signalled"); - return 0; } else { ERROR_LOG(HLE, "sceKernelSignalSema : Trying to signal invalid semaphore %i", id); - return error; + RETURN(error;) } } -int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *badSemaMessage, bool processCallbacks) +void __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *badSemaMessage, bool processCallbacks) { u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { + // We need to set the return value BEFORE processing callbacks / etc. + RETURN(0); + if (s->ns.currentCount >= wantedCount) //TODO fix s->ns.currentCount -= wantedCount; else @@ -244,30 +253,30 @@ int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *bad if (processCallbacks) __KernelCheckCallbacks(); } - - return 0; } else { ERROR_LOG(HLE, badSemaMessage, id); - return error; + RETURN(error); } } //int sceKernelWaitSema(SceUID semaid, int signal, SceUInt *timeout); -int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) +// void because it changes threads. +void sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) { DEBUG_LOG(HLE,"sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr); - return __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSema: Trying to wait for invalid semaphore %i", false); + __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSema: Trying to wait for invalid semaphore %i", false); } //int sceKernelWaitSemaCB(SceUID semaid, int signal, SceUInt *timeout); -int sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr) +// void because it changes threads. +void sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr) { DEBUG_LOG(HLE,"sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr); - return __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSemaCB: Trying to wait for invalid semaphore %i", true); + __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSemaCB: Trying to wait for invalid semaphore %i", true); } // Should be same as WaitSema but without the wait, instead returning SCE_KERNEL_ERROR_SEMA_ZERO diff --git a/Core/HLE/sceKernelSemaphore.h b/Core/HLE/sceKernelSemaphore.h index 1a92cc40ba..185976f788 100644 --- a/Core/HLE/sceKernelSemaphore.h +++ b/Core/HLE/sceKernelSemaphore.h @@ -17,11 +17,11 @@ #pragma once -int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr); +void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr); void sceKernelCreateSema(); -int sceKernelDeleteSema(SceUID id); +void sceKernelDeleteSema(SceUID id); int sceKernelPollSema(SceUID id, int wantedCount); int sceKernelReferSemaStatus(SceUID id, u32 infoPtr); -int sceKernelSignalSema(SceUID id, int signal); -int sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr); -int sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr); +void sceKernelSignalSema(SceUID id, int signal); +void sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr); +void sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr); From d1fd16ecba73189c243491dbd4262d396284ba21 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 12 Nov 2012 08:16:16 -0800 Subject: [PATCH 10/13] sceKernelStartThread(): skip argPtr for 0 args. This makes threads/semaphores pass, so adding to passing list. Depends on an update to pspautotests. --- Core/HLE/sceKernelThread.cpp | 2 +- pspautotests | 2 +- test.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 8b2e6c3c6f..6784bab6ce 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -859,7 +859,7 @@ u32 sceKernelStartThread() startThread->nt.status = THREADSTATUS_READY; u32 sp = startThread->context.r[MIPS_REG_SP]; - if (argBlockPtr) + if (argBlockPtr && argSize > 0) { startThread->context.r[MIPS_REG_A0] = argSize; startThread->context.r[MIPS_REG_A1] = sp; diff --git a/pspautotests b/pspautotests index 3024341543..e6dfb3f2c2 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 3024341543e8f6a338d793bbc8701ea55e2d5c99 +Subproject commit e6dfb3f2c2ad71475aaad2d7c6807e91b64e5ab1 diff --git a/test.py b/test.py index bf70d1a52c..c6bde8cac7 100644 --- a/test.py +++ b/test.py @@ -31,6 +31,7 @@ tests_good = [ "string/string", "gpu/callbacks/ge_callbacks", "threads/mbx/mbx", + "threads/semaphores/semaphores", "power/power", "rtc/rtc", "umd/callbacks/umd", @@ -55,7 +56,6 @@ tests_good = [ "threads/msgpipe/msgpipe", "threads/mutex/mutex", "threads/scheduling/scheduling", - "threads/semaphores/semaphores", "threads/threads/threads", "threads/vpl/vpl", "threads/vtimers/vtimers", From 43b90527d4568ca8cc4e31099109be01363b86e1 Mon Sep 17 00:00:00 2001 From: "kev :)" Date: Mon, 12 Nov 2012 17:18:20 +0000 Subject: [PATCH 11/13] Default to english Default to english. Needs to be menu/config driven really... --- Core/HLE/sceImpose.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Core/HLE/sceImpose.cpp b/Core/HLE/sceImpose.cpp index 4562c39535..d37ac1f171 100644 --- a/Core/HLE/sceImpose.cpp +++ b/Core/HLE/sceImpose.cpp @@ -19,9 +19,24 @@ #include "FunctionWrappers.h" #include "../MIPS/MIPS.h" -static u32 iLanguage = 0; + +const int PSP_LANGUAGE_JAPANESE = 0; +const int PSP_LANGUAGE_ENGLISH = 1; +const int PSP_LANGUAGE_FRENCH = 2; +const int PSP_LANGUAGE_SPANISH = 3; +const int PSP_LANGUAGE_GERMAN = 4; +const int PSP_LANGUAGE_ITALIAN = 5; +const int PSP_LANGUAGE_DUTCH = 6; +const int PSP_LANGUAGE_PORTUGUESE = 7; +const int PSP_LANGUAGE_RUSSIAN = 8; +const int PSP_LANGUAGE_KOREAN = 9; +const int PSP_LANGUAGE_TRADITIONAL_CHINESE = 10; +const int PSP_LANGUAGE_SIMPLIFIED_CHINESE = 11; + +static u32 iLanguage = PSP_LANGUAGE_ENGLISH; static u32 iButtonValue = 0; + u32 sceImposeGetBatteryIconStatus(u32 chargingPtr, u32 iconStatusPtr) { DEBUG_LOG(HLE,"%i=sceImposeGetBatteryIconStatus(%08x, %08x)", chargingPtr, iconStatusPtr); @@ -40,10 +55,6 @@ u32 sceImposeSetLanguageMode(u32 languageVal, u32 buttonVal) return 0; } - - - - u32 sceImposeGetLanguageMode(u32 languagePtr, u32 btnPtr) { DEBUG_LOG(HLE,"%i=sceImposeGetLanguageMode(%08x, %08x)", languagePtr, btnPtr); From 2210b19244f8ae2823d4d3e6380af81688f720b3 Mon Sep 17 00:00:00 2001 From: "Diogo Franco (Kovensky)" Date: Mon, 12 Nov 2012 15:38:21 +0000 Subject: [PATCH 12/13] Xinput input support Picks the first Xinput device available, waits 100 frames between retries when no devices are available. Controls are hardcoded so every x360 controller button corresponds to the PSP button in the same physical position. Input from right stick and from analog triggers is ignored. The Xinput code though is overriden by SampleControls' hardcoded keyboard input. XinputDevice was tested to work with samples/controller/basic when SampleControls is disabled. --- Windows/InputDevice.h | 10 +++ Windows/PPSSPP.vcxproj | 5 +- Windows/PPSSPP.vcxproj.filters | 12 ++++ Windows/WindowsHost.cpp | 1 + Windows/WindowsHost.h | 2 + Windows/XinputDevice.cpp | 109 +++++++++++++++++++++++++++++++++ Windows/XinputDevice.h | 17 +++++ 7 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 Windows/InputDevice.h create mode 100644 Windows/XinputDevice.cpp create mode 100644 Windows/XinputDevice.h diff --git a/Windows/InputDevice.h b/Windows/InputDevice.h new file mode 100644 index 0000000000..8598f4d7ef --- /dev/null +++ b/Windows/InputDevice.h @@ -0,0 +1,10 @@ +#include "../Common/CommonTypes.h" +#include "../Core/HLE/sceCtrl.h" + +#pragma once +class InputDevice +{ +public: + virtual int UpdateState() = 0; +}; + diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 4a9074e9de..fc3ec58516 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -141,7 +141,7 @@ MultiThreadedDebugDLL - Winmm.lib;Ws2_32.lib;opengl32.lib;glu32.lib;comctl32.lib;dsound.lib;%(AdditionalDependencies) + Winmm.lib;Ws2_32.lib;opengl32.lib;glu32.lib;comctl32.lib;dsound.lib;xinput.lib;%(AdditionalDependencies) true $(OutDir)$(ProjectName).pdb Windows @@ -390,6 +390,7 @@ Create Create + @@ -403,6 +404,7 @@ + @@ -417,6 +419,7 @@ + diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index b7769f3b28..e4b591299f 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -23,6 +23,9 @@ {d53d0871-8572-4393-822e-d14db0a88dab} + + {a1963305-bf88-43ef-8ba2-bb3933584b38} + @@ -92,6 +95,9 @@ Android + + Windows\Input + @@ -161,6 +167,12 @@ Android + + Windows\Input + + + Windows\Input + diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 580b1e12ec..fdbfc2bad1 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -85,6 +85,7 @@ void WindowsHost::SetDebugMode(bool mode) void WindowsHost::BeginFrame() { + xinput.UpdateState(); GL_BeginFrame(); } void WindowsHost::EndFrame() diff --git a/Windows/WindowsHost.h b/Windows/WindowsHost.h index 3e7728d552..636211df49 100644 --- a/Windows/WindowsHost.h +++ b/Windows/WindowsHost.h @@ -1,4 +1,5 @@ #include "../Core/Host.h" +#include "XinputDevice.h" class WindowsHost : public Host { @@ -30,4 +31,5 @@ public: private: HWND displayWindow; + XinputDevice xinput; }; \ No newline at end of file diff --git a/Windows/XinputDevice.cpp b/Windows/XinputDevice.cpp new file mode 100644 index 0000000000..d6130a594e --- /dev/null +++ b/Windows/XinputDevice.cpp @@ -0,0 +1,109 @@ +#include "stdafx.h" +#include "XinputDevice.h" +#include +#include + +XinputDevice::XinputDevice() { + ZeroMemory( &this->prevState, sizeof(this->prevState) ); + this->check_delay = 0; + this->gamepad_idx = -1; +} + +struct Stick { + float x; + float y; +}; +static Stick NormalizedDeadzoneFilter(XINPUT_STATE &state); + +int XinputDevice::UpdateState() { + if (this->check_delay-- > 0) return -1; + XINPUT_STATE state; + ZeroMemory( &state, sizeof(XINPUT_STATE) ); + + DWORD dwResult; + if (this->gamepad_idx >= 0) + dwResult = XInputGetState( this->gamepad_idx, &state ); + else { + // use the first gamepad that responds + for (int i = 0; i < XUSER_MAX_COUNT; i++) { + dwResult = XInputGetState( i, &state ); + if (dwResult == ERROR_SUCCESS) { + this->gamepad_idx = i; + break; + } + } + } + + if ( dwResult == ERROR_SUCCESS ) { + this->ApplyDiff(state); + Stick left = NormalizedDeadzoneFilter(state); + __CtrlSetAnalog(left.x, left.y); + this->prevState = state; + this->check_delay = 0; + } else { + // wait check_delay frames before polling the controller again + this->gamepad_idx = -1; + this->check_delay = 100; + } + return 0; +} + +// We only filter the left stick since PSP has no analog triggers or right stick +static Stick NormalizedDeadzoneFilter(XINPUT_STATE &state) { + static const short DEADZONE = XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; + Stick left; + left.x = state.Gamepad.sThumbLX; + left.y = state.Gamepad.sThumbLY; + + float magnitude = sqrt(left.x*left.x + left.y*left.y); + + Stick norm; + norm.x = left.x / magnitude; + norm.y = left.y / magnitude; + + if (magnitude > DEADZONE) { + if (magnitude > 32767) magnitude = 32767; + // normalize the magnitude + magnitude -= DEADZONE; + magnitude /= (32767 - DEADZONE); + + // normalize the axis + left.x = norm.x * magnitude; + left.y = norm.y * magnitude; + } else + left.x = left.y = 0; + + return left; +} + +static const unsigned short xinput_ctrl_map[] = { + XINPUT_GAMEPAD_DPAD_UP, CTRL_UP, + XINPUT_GAMEPAD_DPAD_DOWN, CTRL_DOWN, + XINPUT_GAMEPAD_DPAD_LEFT, CTRL_LEFT, + XINPUT_GAMEPAD_DPAD_RIGHT, CTRL_RIGHT, + XINPUT_GAMEPAD_START, CTRL_START, + XINPUT_GAMEPAD_BACK, CTRL_SELECT, + XINPUT_GAMEPAD_LEFT_SHOULDER, CTRL_LTRIGGER, + XINPUT_GAMEPAD_RIGHT_SHOULDER, CTRL_RTRIGGER, + XINPUT_GAMEPAD_A, CTRL_CROSS, + XINPUT_GAMEPAD_B, CTRL_CIRCLE, + XINPUT_GAMEPAD_X, CTRL_SQUARE, + XINPUT_GAMEPAD_Y, CTRL_TRIANGLE, +}; +static inline u32 CtrlForXinput(int xinput) { + for (int i = 0; i < sizeof(xinput_ctrl_map)/sizeof(xinput_ctrl_map[0]); i += 2) + if (xinput_ctrl_map[i] == xinput) return (u32) xinput_ctrl_map[i+1]; + return 0; +} + +void XinputDevice::ApplyDiff(XINPUT_STATE &state) { + unsigned short pressed = state.Gamepad.wButtons & ~this->prevState.Gamepad.wButtons; + unsigned short released = ~state.Gamepad.wButtons & this->prevState.Gamepad.wButtons; + + for (int i = 1; i < USHRT_MAX; i <<= 1) { + if (pressed & i) + __CtrlButtonDown(CtrlForXinput(i)); + if (released & i) + __CtrlButtonUp(CtrlForXinput(i)); + } +} \ No newline at end of file diff --git a/Windows/XinputDevice.h b/Windows/XinputDevice.h new file mode 100644 index 0000000000..71a31becfe --- /dev/null +++ b/Windows/XinputDevice.h @@ -0,0 +1,17 @@ +#pragma once +#include "InputDevice.h" +#include "Xinput.h" + +class XinputDevice : + public InputDevice +{ +public: + XinputDevice(); + virtual int UpdateState(); +private: + void ApplyDiff(XINPUT_STATE &state); + int gamepad_idx; + int check_delay; + XINPUT_STATE prevState; +}; + From 7e7e9a0452e8674f2cf39af5efbf7b09d9726df8 Mon Sep 17 00:00:00 2001 From: "Diogo Franco (Kovensky)" Date: Mon, 12 Nov 2012 17:32:35 +0000 Subject: [PATCH 13/13] Add a class for keyboard input Removes the windows-specific hack from sceCtrl to read keyboard input and instead add a hack to PPSSPPWindows. The input mapping is still hardcoded and is the same as it was in sceCtrl. Add an std::list to WindowsHost that, curretly, contains a hardcoded list of preferred `InputDevice`s. Devices are tried in-order until one of them reports success. Xinput is preferred over Keyboard. Keyboard always returns success. Pointers are stored in the std::list for polymorphism. Change XinputDevice to report failure as soon as a device can't be queried, instead of only a frame later. --- Core/HLE/sceCtrl.cpp | 42 ------------------------------- Windows/InputDevice.cpp | 13 ++++++++++ Windows/InputDevice.h | 3 +++ Windows/KeyboardDevice.cpp | 46 ++++++++++++++++++++++++++++++++++ Windows/KeyboardDevice.h | 7 ++++++ Windows/PPSSPP.vcxproj | 3 +++ Windows/PPSSPP.vcxproj.filters | 9 +++++++ Windows/WindowsHost.cpp | 4 ++- Windows/WindowsHost.h | 7 ++++-- Windows/XinputDevice.cpp | 3 ++- 10 files changed, 91 insertions(+), 46 deletions(-) create mode 100644 Windows/InputDevice.cpp create mode 100644 Windows/KeyboardDevice.cpp create mode 100644 Windows/KeyboardDevice.h diff --git a/Core/HLE/sceCtrl.cpp b/Core/HLE/sceCtrl.cpp index 83ba95ff71..04b3107b70 100644 --- a/Core/HLE/sceCtrl.cpp +++ b/Core/HLE/sceCtrl.cpp @@ -66,48 +66,6 @@ void SampleControls() { _ctrl_data &data = ctrl; data.frame=1;//frame; frame++; -#ifdef _WIN32 - // TODO: Move this outta here! - data.buttons = 0; - int analogX = 128; - int analogY = 128; - if (GetAsyncKeyState(VK_SPACE)) - data.buttons|=CTRL_START; - if (GetAsyncKeyState('V')) - data.buttons|=CTRL_SELECT; - if (GetAsyncKeyState('A')) - data.buttons|=CTRL_SQUARE; - if (GetAsyncKeyState('S')) - data.buttons|=CTRL_TRIANGLE; - if (GetAsyncKeyState('X')) - data.buttons|=CTRL_CIRCLE; - if (GetAsyncKeyState('Z')) - data.buttons|=CTRL_CROSS; - if (GetAsyncKeyState('Q')) - data.buttons|=CTRL_LTRIGGER; - if (GetAsyncKeyState('W')) - data.buttons|=CTRL_RTRIGGER; - if (GetAsyncKeyState(VK_UP)) { - data.buttons|=CTRL_UP; - analogY -= 100; - } - if (GetAsyncKeyState(VK_DOWN)) { - data.buttons|=CTRL_DOWN; - analogY += 100; - } - if (GetAsyncKeyState(VK_LEFT)) { - data.buttons|=CTRL_LEFT; - analogX -= 100; - } - if (GetAsyncKeyState(VK_RIGHT)) - { - data.buttons|=CTRL_RIGHT; - analogX += 100; - } - - data.analog[0] = analogX; - data.analog[1] = analogY; -#endif } diff --git a/Windows/InputDevice.cpp b/Windows/InputDevice.cpp new file mode 100644 index 0000000000..ad882a2c73 --- /dev/null +++ b/Windows/InputDevice.cpp @@ -0,0 +1,13 @@ +#include "InputDevice.h" +#include "XinputDevice.h" +#include "KeyboardDevice.h" +#include +#include + +#define PUSH_BACK(Cls) do { list.push_back(std::shared_ptr(new Cls())); } while (0) +std::list> getInputDevices() { + std::list> list; + PUSH_BACK(XinputDevice); + PUSH_BACK(KeyboardDevice); + return list; +} diff --git a/Windows/InputDevice.h b/Windows/InputDevice.h index 8598f4d7ef..8c50214dfc 100644 --- a/Windows/InputDevice.h +++ b/Windows/InputDevice.h @@ -8,3 +8,6 @@ public: virtual int UpdateState() = 0; }; +#include +#include +std::list> getInputDevices(); diff --git a/Windows/KeyboardDevice.cpp b/Windows/KeyboardDevice.cpp new file mode 100644 index 0000000000..c69f97b90c --- /dev/null +++ b/Windows/KeyboardDevice.cpp @@ -0,0 +1,46 @@ +#include "KeyboardDevice.h" +#include "../Common/CommonTypes.h" +#include "../Core/HLE/sceCtrl.h" +#include "WinUser.h" + +static const unsigned short key_ctrl_map[] = { + VK_SPACE, CTRL_START, + 'V', CTRL_SELECT, + 'A', CTRL_SQUARE, + 'S', CTRL_TRIANGLE, + 'X', CTRL_CIRCLE, + 'Z', CTRL_CROSS, + 'Q', CTRL_LTRIGGER, + 'W', CTRL_RTRIGGER, + VK_UP, CTRL_UP, + VK_DOWN, CTRL_DOWN, + VK_LEFT, CTRL_LEFT, + VK_RIGHT, CTRL_RIGHT, +}; +int KeyboardDevice::UpdateState() { + float analogX = 0; + float analogY = 0; + for (int i = 0; i < sizeof(key_ctrl_map)/sizeof(key_ctrl_map[0]); i += 2) { + if (!GetAsyncKeyState(key_ctrl_map[i])) + __CtrlButtonUp(key_ctrl_map[i+1]); + else { + __CtrlButtonDown(key_ctrl_map[i+1]); + switch (key_ctrl_map[i]) { + case VK_UP: + analogY -= .8f; + break; + case VK_DOWN: + analogY += .8f; + break; + case VK_LEFT: + analogX -= .8f; + break; + case VK_RIGHT: + analogX += .8f; + break; + } + } + } + __CtrlSetAnalog(analogX, analogY); + return 0; +} \ No newline at end of file diff --git a/Windows/KeyboardDevice.h b/Windows/KeyboardDevice.h new file mode 100644 index 0000000000..79d238348c --- /dev/null +++ b/Windows/KeyboardDevice.h @@ -0,0 +1,7 @@ +#pragma once +#include "InputDevice.h" + +class KeyboardDevice : public InputDevice { +public: + virtual int UpdateState(); +}; diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index fc3ec58516..ea240ed01b 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -364,6 +364,8 @@ + + $(IntDir)%(Filename)2.obj @@ -405,6 +407,7 @@ + diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index e4b591299f..7df8759760 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -98,6 +98,12 @@ Windows\Input + + Windows\Input + + + Windows\Input + @@ -173,6 +179,9 @@ Windows\Input + + Windows\Input + diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index fdbfc2bad1..1ae42e6b08 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -85,7 +85,9 @@ void WindowsHost::SetDebugMode(bool mode) void WindowsHost::BeginFrame() { - xinput.UpdateState(); + for (auto iter = this->input.begin(); iter != this->input.end(); iter++) + if ((*iter)->UpdateState() == 0) + break; // *iter is std::shared_ptr, **iter is InputDevice GL_BeginFrame(); } void WindowsHost::EndFrame() diff --git a/Windows/WindowsHost.h b/Windows/WindowsHost.h index 636211df49..adbb24a876 100644 --- a/Windows/WindowsHost.h +++ b/Windows/WindowsHost.h @@ -1,5 +1,7 @@ #include "../Core/Host.h" -#include "XinputDevice.h" +#include "InputDevice.h" +#include +#include class WindowsHost : public Host { @@ -7,6 +9,7 @@ public: WindowsHost(HWND _displayWindow) { displayWindow = _displayWindow; + input = getInputDevices(); } void UpdateMemView(); void UpdateDisassembly(); @@ -31,5 +34,5 @@ public: private: HWND displayWindow; - XinputDevice xinput; + std::list> input; }; \ No newline at end of file diff --git a/Windows/XinputDevice.cpp b/Windows/XinputDevice.cpp index d6130a594e..3c1ac1041f 100644 --- a/Windows/XinputDevice.cpp +++ b/Windows/XinputDevice.cpp @@ -40,12 +40,13 @@ int XinputDevice::UpdateState() { __CtrlSetAnalog(left.x, left.y); this->prevState = state; this->check_delay = 0; + return 0; } else { // wait check_delay frames before polling the controller again this->gamepad_idx = -1; this->check_delay = 100; + return -1; } - return 0; } // We only filter the left stick since PSP has no analog triggers or right stick