shadPS4/src/core/libraries/ngs2/ngs2_impl.cpp
TheTurtle c4506da0ae
kernel: Rewrite pthread emulation (#1440)
* libkernel: Cleanup some function places

* kernel: Refactor thread functions

* kernel: It builds

* kernel: Fix a bunch of bugs, kernel thread heap

* kernel: File cleanup pt1

* File cleanup pt2

* File cleanup pt3

* File cleanup pt4

* kernel: Add missing funcs

* kernel: Add basic exceptions for linux

* gnmdriver: Add workload functions

* kernel: Fix new pthreads code on macOS. (#1441)

* kernel: Downgrade edeadlk to log

* gnmdriver: Add sceGnmSubmitCommandBuffersForWorkload

* exception: Add context register population for macOS. (#1444)

* kernel: Pthread rewrite touchups for Windows

* kernel: Multiplatform thread implementation

* mutex: Remove spamming log

* pthread_spec: Make assert into a log

* pthread_spec: Zero initialize array

* Attempt to fix non-Windows builds

* hotfix: change incorrect NID for scePthreadAttrSetaffinity

* scePthreadAttrSetaffinity implementation

* Attempt to fix Linux

* windows: Address a bunch of address space problems

* address_space: Fix unmap of region surrounded by placeholders

* libs: Reduce logging

* pthread: Implement condvar with waitable atomics and sleepqueue

* sleepq: Separate and make faster

* time: Remove delay execution

* Causes high cpu usage in Tohou Luna Nights

* kernel: Cleanup files again

* pthread: Add missing include

* semaphore: Use binary_semaphore instead of condvar

* Seems more reliable

* libraries/sysmodule: log module on `sceSysmoduleIsLoaded`

* libraries/kernel: implement `scePthreadSetPrio`

---------

Co-authored-by: squidbus <175574877+squidbus@users.noreply.github.com>
Co-authored-by: Daniel R. <47796739+polybiusproxy@users.noreply.github.com>
2024-11-21 22:59:38 +02:00

165 lines
5.0 KiB
C++

// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/kernel.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {
s32 Ngs2::ReportInvalid(Ngs2Handle* handle, u32 handle_type) const {
uintptr_t hAddress = reinterpret_cast<uintptr_t>(handle);
switch (handle_type) {
case 1:
LOG_ERROR(Lib_Ngs2, "Invalid system handle {}", hAddress);
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
case 2:
LOG_ERROR(Lib_Ngs2, "Invalid rack handle {}", hAddress);
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
case 4:
LOG_ERROR(Lib_Ngs2, "Invalid voice handle {}", hAddress);
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
case 8:
LOG_ERROR(Lib_Ngs2, "Invalid report handle {}", hAddress);
return ORBIS_NGS2_ERROR_INVALID_REPORT_HANDLE;
default:
LOG_ERROR(Lib_Ngs2, "Invalid handle {}", hAddress);
return ORBIS_NGS2_ERROR_INVALID_HANDLE;
}
}
s32 Ngs2::HandleSetup(Ngs2Handle* handle, void* data, std::atomic<u32>* atomic, u32 type,
u32 flags) {
handle->dataPointer = data;
handle->atomicPtr = atomic;
handle->handleType = type;
handle->flags_unk = flags;
return ORBIS_OK;
}
s32 Ngs2::HandleCleanup(Ngs2Handle* handle, u32 hType, void* dataOut) {
if (handle && handle->selfPointer == handle) {
std::atomic<u32>* tmp_atomic = handle->atomicPtr;
if (tmp_atomic && handle->handleType == hType) {
while (tmp_atomic->load() != 0) {
u32 expected = 1;
if (tmp_atomic->compare_exchange_strong(expected, 0)) {
if (dataOut) {
dataOut = handle->dataPointer;
}
// sceNgs2MemoryClear(handle, 32);
return ORBIS_OK;
}
tmp_atomic = handle->atomicPtr;
}
}
}
return this->ReportInvalid(handle, hType);
}
s32 Ngs2::HandleEnter(Ngs2Handle* handle, u32 hType, Ngs2Handle* handleOut) {
if (!handle) {
return this->ReportInvalid(handle, 0);
}
if (handle->selfPointer != handle || !handle->atomicPtr || !handle->dataPointer ||
(~hType & handle->handleType)) {
return this->ReportInvalid(handle, handle->handleType);
}
std::atomic<u32>* atomic = handle->atomicPtr;
while (true) {
u32 i = atomic->load();
if (i == 0) {
return this->ReportInvalid(handle, handle->handleType);
}
if (atomic->compare_exchange_strong(i, i + 1)) {
break;
}
}
if (handleOut) {
handleOut = handle;
}
return ORBIS_OK;
}
s32 Ngs2::HandleLeave(Ngs2Handle* handle) {
std::atomic<u32>* tmp_atomic;
u32 i;
do {
tmp_atomic = handle->atomicPtr;
i = tmp_atomic->load();
} while (!tmp_atomic->compare_exchange_strong(i, i - 1));
return ORBIS_OK;
}
s32 Ngs2::StackBufferOpen(StackBuffer* buf, void* base_addr, size_t size, void** stackTop,
bool verify) {
buf->top = stackTop;
buf->base = base_addr;
buf->curr = base_addr;
buf->usedSize = 0;
buf->totalSize = size;
buf->alignment = 8;
buf->isVerifyEnabled = verify;
if (stackTop) {
*stackTop = nullptr;
}
return ORBIS_OK;
}
s32 Ngs2::StackBufferClose(StackBuffer* buf, size_t* usedSize) {
if (usedSize) {
*usedSize = buf->usedSize + buf->alignment;
}
return ORBIS_OK;
}
s32 Ngs2::SystemSetupCore(StackBuffer* buf, SystemOptions* options, Ngs2Handle** sysOut) {
u32 maxGrainSamples = 512;
u32 numGrainSamples = 256;
u32 sampleRate = 48000;
if (options) {
maxGrainSamples = options->maxGrainSamples;
numGrainSamples = options->numGrainSamples;
sampleRate = options->sampleRate;
}
// Validate maxGrainSamples
if (maxGrainSamples < 64 || maxGrainSamples > 1024 || (maxGrainSamples & 0x3F) != 0) {
LOG_ERROR(Lib_Ngs2, "Invalid system option (maxGrainSamples={},x64)", maxGrainSamples);
return ORBIS_NGS2_ERROR_INVALID_MAX_GRAIN_SAMPLES;
}
// Validate numGrainSamples
if (numGrainSamples < 64 || numGrainSamples > 1024 || (numGrainSamples & 0x3F) != 0) {
LOG_ERROR(Lib_Ngs2, "Invalid system option (numGrainSamples={},x64)", numGrainSamples);
return ORBIS_NGS2_ERROR_INVALID_NUM_GRAIN_SAMPLES;
}
// Validate sampleRate
if (sampleRate != 11025 && sampleRate != 12000 && sampleRate != 22050 && sampleRate != 24000 &&
sampleRate != 44100 && sampleRate != 48000 && sampleRate != 88200 && sampleRate != 96000) {
LOG_ERROR(Lib_Ngs2, "Invalid system option(sampleRate={}:44.1/48kHz series)", sampleRate);
return ORBIS_NGS2_ERROR_INVALID_SAMPLE_RATE;
}
int result = ORBIS_OK;
// TODO
return result; // Success
}
} // namespace Libraries::Ngs2