This commit is contained in:
Martin Baliet 2024-04-17 21:39:03 +02:00
parent fbf46eb9aa
commit 935df442ad
17 changed files with 573 additions and 275 deletions

View File

@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.24)
include(ExternalProject)
set(PSOFF_LIB_VERSION v.0.0)
set(PSOFF_RENDER_VERSION v.0.5-nightly_17.04.24)
set(ProjectName psOff_${CMAKE_BUILD_TYPE})
project(${ProjectName} VERSION 0.0.1)
@ -66,6 +67,19 @@ ExternalProject_Add(third_party
URL https://github.com/SysRay/psOff_thirdParty/releases/download/${PSOFF_LIB_VERSION}/psOff-3rd.zip
)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
ExternalProject_Add(renderer
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
PREFIX ${CMAKE_BINARY_DIR}/renderer
BUILD_IN_SOURCE 1
URL https://github.com/SysRay/psOff_Renderer/releases/download/${PSOFF_RENDER_VERSION}/psOff-renderer.zip
)
install(FILES ${CMAKE_BINARY_DIR}/renderer/src/renderer/emulator.exe DESTINATION ${CMAKE_INSTALL_PREFIX})
endif()
set(TEST_BENCH OFF CACHE BOOL "Enable testing")
if(TEST_BENCH)

View File

@ -39,6 +39,8 @@ target_link_libraries(core PRIVATE
OptickCore
psOff_utility
config_emu.lib
onecore.lib
VulkanMemoryAllocator
${Vulkan_LIBRARIES}
)

View File

@ -1,5 +1,10 @@
add_library(dmem OBJECT
dmem.cpp
directmem.cpp
)
add_dependencies(dmem third_party psOff_utility)
target_include_directories(dmem PRIVATE
${Vulkan_INCLUDE_DIRS}
)

419
core/dmem/directmem.cpp Normal file
View File

@ -0,0 +1,419 @@
#define __APICALL_EXTERN
#include "dmem.h"
#undef __APICALL_EXTERN
#include "core/imports/exports/procParam.h"
#include "core/imports/imports_runtime.h"
#include "core/kernel/filesystem.h"
#include "core/videoout/videoout.h"
#include "logging.h"
#include "modules/libkernel/codes.h"
#include "modules/libkernel/dmem.h"
#include "utility/utility.h"
#include <boost/thread.hpp>
#include <map>
#include <vk_mem_alloc.h>
#include <vulkan/vk_enum_string_helper.h>
#include <windows.h>
#undef min
LOG_DEFINE_MODULE(DirectMemory);
namespace {
constexpr uint64_t DIRECTMEM_START = 0x100000000u;
enum class MemoryState {
Free,
Reserved,
Commited,
};
struct MemoryMapping {
uint64_t addr = 0;
uint64_t heapAddr = 0; // addr for MemoryInfo
uint64_t size = 0;
uint64_t alignment = 0;
VmaVirtualAllocation vmaAlloc;
};
struct MemoryInfo {
uint64_t addr = 0;
void* allocAddr = nullptr;
uint64_t size = 0;
uint64_t alignment = 0;
int memoryType = 0;
int prot = 0;
VmaVirtualAllocation vmaAlloc;
VmaVirtualBlock vmaBlock = nullptr;
MemoryState state = MemoryState::Free;
};
bool checkIsGPU(int protection) {
return (protection & 0xf0) > 0;
}
DWORD convProtection(int prot) {
switch (prot & 0xf) {
case 0: return PAGE_NOACCESS;
case 1: return PAGE_READONLY;
case 2:
case 3: return PAGE_READWRITE;
case 4: return PAGE_EXECUTE;
case 5: return PAGE_EXECUTE_READ;
case 6:
case 7: return PAGE_EXECUTE_READWRITE;
}
if (checkIsGPU(prot)) {
return PAGE_READWRITE; // special case: cpu read/writes gpumemory on host memory
}
return PAGE_NOACCESS;
}
} // namespace
class DirectMemory: public IDirectMemory {
boost::mutex m_mutexInt;
std::map<uint64_t, MemoryInfo> m_objects;
std::map<uint64_t, MemoryMapping> m_mappings;
uint64_t m_allocSize = 0;
uint64_t m_usedSize = 0;
uint64_t m_sdkVersion = 0;
VmaVirtualBlock m_virtualDeviceMemory;
uint64_t getSDKVersion() {
if (m_sdkVersion == 0) {
auto* procParam = (ProcParam*)accessRuntimeExport()->mainModuleInfo().procParamAddr;
m_sdkVersion = procParam->header.sdkVersion;
}
return m_sdkVersion;
}
int retNoMem() {
if (m_sdkVersion < 0x3500000) return getErr(ErrCode::_EINVAL);
return getErr(ErrCode::_ENOMEM);
}
MemoryInfo* getMemoryInfo(uint64_t len, uint64_t alignment, int prot, VmaVirtualAllocation& outAlloc, uint64_t& outAddr);
public:
DirectMemory() {
LOG_USE_MODULE(DirectMemory);
VmaVirtualBlockCreateInfo blockCreateInfo = {
.size = SCE_KERNEL_MAIN_DMEM_SIZE,
};
if (auto result = vmaCreateVirtualBlock(&blockCreateInfo, &m_virtualDeviceMemory); result != VK_SUCCESS) {
LOG_CRIT(L"vmaCreateVirtualBlock err:%S", string_VkResult(result));
}
}
virtual ~DirectMemory() { deinit(); }
// ### Interface
int alloc(size_t len, size_t alignment, int memoryType, uint64_t* outAddr) final;
int free(off_t start, size_t len) final;
int map(uint64_t vaddr, off_t directMemoryOffset, size_t len, int prot, int flags, size_t alignment, uint64_t* outAddr) final;
int unmap(uint64_t vaddr, uint64_t size) final;
virtual int reserve(uint64_t start, size_t len, size_t alignment, int flags, uint64_t* outAddr) final;
uint64_t size() const final;
int getAvailableSize(uint32_t start, uint32_t end, size_t alignment, uint32_t* startOut, size_t* sizeOut) final;
void deinit() final;
};
IDirectMemory& accessDirectMemory() {
static DirectMemory obj;
return obj;
}
MemoryInfo* DirectMemory::getMemoryInfo(uint64_t len, uint64_t alignment, int prot, VmaVirtualAllocation& outAlloc, uint64_t& outAddr) {
if (m_objects.empty()) return nullptr;
VmaVirtualAllocationCreateInfo allocCreateInfo = {
.size = len,
.alignment = alignment,
};
for (auto& item: m_objects) {
if (item.second.state == MemoryState::Reserved) continue;
if (item.second.state == MemoryState::Commited && prot != item.second.prot) continue;
if (auto result = vmaVirtualAllocate(item.second.vmaBlock, &allocCreateInfo, &outAlloc, &outAddr); result == VK_SUCCESS) {
return &item.second;
}
}
return nullptr;
}
int DirectMemory::alloc(size_t len, size_t alignment, int memoryType, uint64_t* outAddr) {
LOG_USE_MODULE(DirectMemory);
if ((alignment > 0 && !util::isPowerOfTwo(alignment)) || (len % SCE_KERNEL_PAGE_SIZE != 0) || (alignment % SCE_KERNEL_PAGE_SIZE != 0))
return getErr(ErrCode::_EINVAL);
boost::unique_lock lock(m_mutexInt);
VmaVirtualAllocationCreateInfo allocCreateInfo = {
.size = len,
.alignment = alignment,
};
// Get block from device memory
VmaVirtualAllocation alloc;
if (auto result = vmaVirtualAllocate(m_virtualDeviceMemory, &allocCreateInfo, &alloc, outAddr); result != VK_SUCCESS) {
LOG_ERR(L"Alloc Error| len:0x%08llx alignment:0x%08llx memorytype:%d err:%d", len, alignment, memoryType, GetLastError());
return getErr(ErrCode::_ENOMEM);
}
// - check devicememory
*outAddr += DIRECTMEM_START; // For debugging info
// Device has space -> Create allocation
VmaVirtualBlockCreateInfo blockCreateInfo = {
.size = len,
};
VmaVirtualBlock block;
if (auto result = vmaCreateVirtualBlock(&blockCreateInfo, &block); result != VK_SUCCESS) {
LOG_ERR(L"Alloc Error| len:0x%08llx alignment:0x%08llx memorytype:%d err:%d", len, alignment, memoryType, GetLastError());
return getErr(ErrCode::_ENOMEM);
}
// -
m_allocSize += len;
m_objects.emplace(std::make_pair(
*outAddr, MemoryInfo {.addr = *outAddr, .size = len, .alignment = alignment, .memoryType = memoryType, .vmaAlloc = alloc, .vmaBlock = block}));
LOG_DEBUG(L"-> Allocated: len:0x%08llx alignment:0x%08llx memorytype:%d -> 0x%08llx", len, alignment, memoryType, *outAddr);
return Ok;
}
int DirectMemory::free(off_t start, size_t len) {
LOG_USE_MODULE(DirectMemory);
boost::unique_lock lock(m_mutexInt);
uint64_t addr = DIRECTMEM_START + start;
m_allocSize -= len;
// Find the object
if (m_objects.empty()) return Ok;
auto itHeap = m_objects.lower_bound(addr);
if (itHeap == m_objects.end() || (itHeap != m_objects.begin() && itHeap->first != addr)) --itHeap; // Get the correct item
if (!(itHeap->first <= addr && (itHeap->first + itHeap->second.size >= addr))) return Ok; // Can't be found
//-
LOG_DEBUG(L"free| addr:0x%08llx len:0x%08llx heap -> addr:0x%08llx len:0x%08llx", addr, len, itHeap->first, itHeap->second.size);
// special: Check reserve if full reservation or commits
if (itHeap->second.state == MemoryState::Reserved) {
// todo
VirtualFree((void*)itHeap->second.addr, itHeap->second.size, 0);
return Ok;
}
if (itHeap->first != addr || itHeap->second.size != len) {
LOG_ERR(L"free Error| start:0x%08llx len:0x%08llx != start:0x%08llx len:0x%08llx", addr, len, itHeap->first, itHeap->second.size);
}
if (checkIsGPU(itHeap->second.prot)) {
// todo
} else {
if (itHeap->second.allocAddr != 0) VirtualFree(itHeap->second.allocAddr, itHeap->second.size, 0);
}
{
std::list<uint64_t> dump;
for (auto& item: m_mappings) {
if (item.second.heapAddr == itHeap->first) {
m_usedSize -= item.second.size;
LOG_TRACE(L"Missing unmap for addr:0x%08llx len:0x%08llx, force unmap", item.second.addr, item.second.size);
vmaVirtualFree(itHeap->second.vmaBlock, item.second.vmaAlloc);
unregisterMapping(item.first);
dump.push_back(item.first);
}
for (auto item: dump) {
m_mappings.erase(item);
}
}
}
vmaDestroyVirtualBlock(itHeap->second.vmaBlock);
vmaVirtualFree(m_virtualDeviceMemory, itHeap->second.vmaAlloc);
m_objects.erase(itHeap);
return Ok;
}
int DirectMemory::map(uint64_t vaddr, off_t offset, size_t len, int prot, int flags, size_t alignment, uint64_t* outAddr) {
LOG_USE_MODULE(DirectMemory);
boost::unique_lock lock(m_mutexInt);
if (flags & (int)filesystem::SceMapMode::VOID_) {
LOG_CRIT(L"todo void map");
}
if (flags & (int)filesystem::SceMapMode::FIXED) {
LOG_CRIT(L"todo fixed map");
}
VmaVirtualAllocation alloc = nullptr;
// search for free space
uint64_t fakeAddrOffset = 0;
MemoryInfo* info = getMemoryInfo(len, alignment, prot, alloc, fakeAddrOffset);
if (info == nullptr) return retNoMem();
// -
// Check if Commit needed
if (info->state == MemoryState::Free) {
MEM_ADDRESS_REQUIREMENTS addressReqs = {0};
MEM_EXTENDED_PARAMETER extendedParams = {0};
addressReqs.Alignment = 0; // 64 KB alignment
addressReqs.LowestStartingAddress = (PVOID)DIRECTMEM_START;
addressReqs.HighestEndingAddress = (PVOID)0;
extendedParams.Type = MemExtendedParameterAddressRequirements;
extendedParams.Pointer = &addressReqs;
void* ptr = VirtualAlloc2(NULL, 0, info->size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, convProtection(prot), &extendedParams, 1);
if (ptr == 0) {
auto const err = GetLastError();
LOG_ERR(L"Commit Error| addr:0x%08llx len:0x%08llx err:%d", info->addr, info->size, GetLastError());
return getErr(ErrCode::_EINVAL);
}
info->allocAddr = ptr;
info->state = MemoryState::Commited;
LOG_DEBUG(L"Commit| addr:0x%08llx len:0x%08llx prot:%d ->", info->addr, info->size, prot, ptr);
}
// - commit
*outAddr = (uint64_t)info->allocAddr + fakeAddrOffset;
m_mappings.emplace(
std::make_pair(*outAddr, MemoryMapping {.addr = *outAddr, .heapAddr = info->addr, .size = len, .alignment = alignment, .vmaAlloc = alloc}));
registerMapping(*outAddr, MappingType::Direct);
m_usedSize += len;
LOG_DEBUG(L"-> Map: start:0x%08llx(0x%lx) len:0x%08llx alignment:0x%08llx prot:%d -> 0x%08llx", vaddr, offset, len, alignment, prot, *outAddr);
if (checkIsGPU(prot)) {
if (!accessVideoOut().notify_allocHeap(*outAddr, len, prot)) {
return getErr(ErrCode::_EINVAL);
}
}
return Ok;
}
int DirectMemory::reserve(uint64_t start, size_t len, size_t alignment, int flags, uint64_t* outAddr) {
LOG_USE_MODULE(DirectMemory);
boost::unique_lock lock(m_mutexInt);
MEM_ADDRESS_REQUIREMENTS addressReqs = {0};
MEM_EXTENDED_PARAMETER extendedParams = {0};
addressReqs.Alignment = alignment;
addressReqs.LowestStartingAddress = (PVOID)0x100000000;
addressReqs.HighestEndingAddress = (PVOID)0;
extendedParams.Type = MemExtendedParameterAddressRequirements;
extendedParams.Pointer = &addressReqs;
*outAddr = (uint64_t)VirtualAlloc2(NULL, 0, len, MEM_RESERVE | MEM_WRITE_WATCH, PAGE_NOACCESS, &extendedParams, 1);
if (*outAddr == 0) {
auto const err = GetLastError();
LOG_ERR(L"Reserve Error| addr:0x%08llx len:0x%08llx align:0x%08llx flags:0x%x err:%d", start, len, alignment, flags, GetLastError());
return getErr(ErrCode::_EINVAL);
}
LOG_DEBUG(L"-> Reserve: start:0x%08llx len:0x%08llx alignment:0x%08llx flags:0x%x -> 0x%08llx", start, len, alignment, flags, *outAddr);
m_objects.emplace(
std::make_pair(*outAddr, MemoryInfo {.addr = *outAddr, .size = len, .alignment = alignment, .memoryType = 0, .state = MemoryState::Reserved}));
return Ok;
}
int DirectMemory::unmap(uint64_t vaddr, uint64_t size) {
LOG_USE_MODULE(DirectMemory);
boost::unique_lock lock(m_mutexInt);
// Find the object
if (m_mappings.empty()) return Ok;
auto itItem = m_mappings.lower_bound(vaddr);
if (itItem == m_mappings.end() || (itItem != m_mappings.begin() && itItem->first != vaddr)) --itItem; // Get the correct item
if (!(itItem->first <= vaddr && (itItem->first + itItem->second.size >= vaddr))) {
LOG_ERR(L"Couldn't find mapping for 0x%08llx 0x%08llx", vaddr, size);
return -1;
}
//-
if (auto it = m_objects.find(itItem->second.heapAddr); it != m_objects.end()) {
vmaVirtualFree(it->second.vmaBlock, itItem->second.vmaAlloc);
} else {
LOG_ERR(L"Couldn't find Heap for 0x%08llx", itItem->second.heapAddr);
}
LOG_DEBUG(L"unmap| 0x%08llx 0x%08llx", vaddr, size);
m_usedSize -= itItem->second.size;
m_mappings.erase(itItem);
return Ok;
}
uint64_t DirectMemory::size() const {
return m_allocSize;
}
int DirectMemory::getAvailableSize(uint32_t start, uint32_t end, size_t alignment, uint32_t* startOut, size_t* sizeOut) {
LOG_USE_MODULE(DirectMemory);
LOG_ERR(L"availableSize: start:0x%08llx end:0x%08llx alignment:0x%08llx", start, end, alignment);
*startOut = m_usedSize;
*sizeOut = m_allocSize - m_usedSize;
return Ok;
}
void DirectMemory::deinit() {
for (auto& item: m_objects) {
if (checkIsGPU(item.second.prot)) {
// done by gpuMemoryManager
} else {
// memory::free(item.first);
}
}
m_objects.clear();
}

View File

@ -36,159 +36,6 @@ auto getData() {
}
} // namespace
// Allocates the sections (memory pool is done internally (in app))
class PhysicalMemory: public IPhysicalMemory {
std::mutex m_mutex_int;
std::unordered_map<uint64_t, MemoryInfo> m_objects;
public:
PhysicalMemory() = default;
virtual ~PhysicalMemory() { deinit(); }
uint64_t alloc(uint64_t vaddr, size_t len, int memoryTye) final;
bool reserve(uint64_t start, size_t len, size_t alignment, uint64_t* outAddr, int memoryType) final;
uintptr_t commit(uint64_t base, uint64_t offset, size_t len, size_t alignment, int prot) final;
bool Map(uint64_t vaddr, uint64_t physAddr, size_t len, int prot, bool allocFixed, size_t alignment, uint64_t* outAddr) final;
bool Release(uint64_t start, size_t len, uint64_t* vaddr, uint64_t* size) final;
bool Unmap(uint64_t vaddr, uint64_t size) final;
void deinit() final;
};
IPhysicalMemory& accessPysicalMemory() {
static PhysicalMemory inst;
return inst;
}
uint64_t PhysicalMemory::alloc(uint64_t vaddr, size_t len, int prot) {
LOG_USE_MODULE(MemoryManager);
m_allocSize += len;
LOG_DEBUG(L"Alloc: 0x%08llx len:0x%08llx prot:%d curSize=0x%08llx", vaddr, len, prot, m_allocSize);
return 0;
}
bool PhysicalMemory::reserve(uint64_t start, size_t len, size_t alignment, uint64_t* outAddr, int memoryType) {
LOG_USE_MODULE(MemoryManager);
auto const isGpu = memoryType == 3;
*outAddr = memory::reserve(start, len, alignment, isGpu);
{
std::unique_lock const lock(m_mutex_int);
m_availableSize -= len;
}
LOG_DEBUG(L"Reserve| start:0x%08llx size:%08llx alignment:%llu memType:%d -> @%08llx", start, len, alignment, memoryType, *outAddr);
return *outAddr != 0;
}
uintptr_t PhysicalMemory::commit(uint64_t base, uint64_t vaddr, size_t len, size_t alignment, int prot) {
LOG_USE_MODULE(MemoryManager);
uintptr_t addr = 0;
auto [protCPU, protGPU] = util::getMemoryProtection(prot);
if (protGPU != 0) {
addr = memory::allocGPUMemory(base, 0, len, alignment);
} else {
addr = memory::commit(base, 0, len, alignment, prot);
}
m_objects[addr] = MemoryInfo {.isGpu = protGPU != 0, .size = len};
if (protGPU != 0) {
if (!accessVideoOut().notify_allocHeap(addr, len, prot)) {
LOG_ERR(L"Commit| Couldn't allocHeap| base:0x%08llx offset:0x%08llx size:%08llx alignment:%llu prot:%d -> @%08llx", base, vaddr, len, alignment, prot,
addr);
return 0;
}
}
LOG_DEBUG(L"Commit| base:0x%08llx offset:0x%08llx size:%08llx alignment:%llu prot:%d -> @%08llx", base, vaddr, len, alignment, prot, addr);
return addr;
}
bool PhysicalMemory::Map(uint64_t vaddr, uint64_t physAddr, size_t len, int prot, bool allocFixed, size_t alignment, uint64_t* outAddr) {
LOG_USE_MODULE(MemoryManager);
bool mapped = false;
*outAddr = 0;
{
std::unique_lock const lock(m_mutex_int);
auto [protCPU, protGPU] = util::getMemoryProtection(prot);
if (allocFixed) {
if (memory::allocFixed(physAddr, len, prot)) {
*outAddr = physAddr;
}
} else {
*outAddr = memory::allocAligned(physAddr, len, prot, alignment);
}
m_objects[*outAddr] = MemoryInfo {.isGpu = protGPU != 0, .size = len};
if (protGPU != 0) {
if (!accessVideoOut().notify_allocHeap(*outAddr, len, prot)) {
LOG_ERR(L"Map| Couldn't allocHeap vaddr:0x%08llx physAddr:0x%08llx len:0x%08llx prot:0x%x -> out:0x%08llx", vaddr, physAddr, len, prot, *outAddr);
return false;
}
}
if (*outAddr == NULL) {
return false;
}
m_availableSize -= len;
}
LOG_INFO(L"Map| vaddr:0x%08llx physAddr:0x%08llx len:0x%08llx prot:0x%x -> out:0x%08llx", vaddr, physAddr, len, prot, *outAddr);
return true;
}
bool PhysicalMemory::Release(uint64_t start, size_t len, uint64_t* vaddr, uint64_t* size) {
LOG_USE_MODULE(MemoryManager);
LOG_ERR(L"todo %S", __FUNCTION__);
m_allocSize -= len;
return true;
}
bool PhysicalMemory::Unmap(uint64_t vaddr, uint64_t size) {
LOG_USE_MODULE(MemoryManager);
if (auto it = m_objects.find(vaddr); it != m_objects.end()) {
if (it->second.isGpu) {
// if(isGPU) accessGpuMemory().freeHeap(vaddr); // todo, notify free (should free host memory aswell)
memory::free(vaddr);
} else {
memory::free(vaddr);
}
} else {
LOG_ERR(L"Unmap not in map: vaddr:0x%08llx len:%lld", vaddr, size);
memory::free(vaddr);
}
{
std::unique_lock const lock(m_mutex_int);
m_availableSize += size;
}
LOG_INFO(L"Unmap: vaddr:0x%08llx len:%lld", vaddr, size);
return true;
}
void PhysicalMemory::deinit() {
for (auto& item: m_objects) {
if (item.second.isGpu) {
// done by gpuMemoryManager
} else {
memory::free(item.first);
}
}
m_objects.clear();
}
class FlexibleMemory: public IFlexibleMemory {
uint64_t m_totalAllocated = 0;
std::mutex m_mutex_int;

View File

@ -4,35 +4,30 @@
enum class GpuMemoryMode { NoAccess, Read, Write, ReadWrite };
enum class MappingType { None, File, Flexible, Fixed };
enum class MappingType { None, File, Flexible, Fixed, Direct };
class IPhysicalMemory {
CLASS_NO_COPY(IPhysicalMemory);
class IDirectMemory {
CLASS_NO_COPY(IDirectMemory);
CLASS_NO_MOVE(IDirectMemory);
protected:
IPhysicalMemory() = default;
uint64_t m_availableSize = 5000000000llu; // todo get from system memory
size_t m_allocSize = 0;
IDirectMemory() = default;
public:
virtual ~IPhysicalMemory() = default;
virtual ~IDirectMemory() = default;
void getAvailableSize(uint32_t start, uint32_t end, size_t alignment, uint32_t* startOut, size_t* sizeOut) {
*startOut = size() - m_availableSize;
*sizeOut = m_availableSize;
}
virtual int alloc(size_t len, size_t alignment, int memoryType, uint64_t* outAddr) = 0;
virtual int free(off_t start, size_t len) = 0;
virtual uint64_t alloc(uint64_t vaddr, size_t len, int memoryType) = 0;
virtual int map(uint64_t vaddr, off_t directMemoryOffset, size_t len, int prot, int flags, size_t alignment, uint64_t* outAddr) = 0;
virtual int unmap(uint64_t vaddr, uint64_t size) = 0;
virtual bool reserve(uint64_t start, size_t len, size_t alignment, uint64_t* outAddr, int memoryType) = 0;
virtual uintptr_t commit(uint64_t base, uint64_t offset, size_t len, size_t alignment, int prot) = 0;
virtual int reserve(uint64_t start, size_t len, size_t alignment, int flags, uint64_t* outAddr) = 0;
virtual bool Map(uint64_t vaddr, uint64_t physAddr, size_t len, int prot, bool allocFixed, size_t alignment, uint64_t* outAddr) = 0;
virtual bool Release(uint64_t start, size_t len, uint64_t* vaddr, uint64_t* size) = 0;
virtual bool Unmap(uint64_t vaddr, uint64_t size) = 0;
virtual void deinit() = 0;
virtual uint64_t size() const = 0;
virtual int getAvailableSize(uint32_t start, uint32_t end, size_t alignment, uint32_t* startOut, size_t* sizeOut) = 0;
uint64_t const size() const { return m_allocSize; } // use system ram
virtual void deinit() = 0;
};
class IFlexibleMemory {
@ -82,6 +77,7 @@ __APICALL void registerMapping(uint64_t vaddr, MappingType type);
*/
__APICALL MappingType unregisterMapping(uint64_t vaddr);
__APICALL IPhysicalMemory& accessPysicalMemory();
__APICALL IDirectMemory& accessDirectMemory();
__APICALL IFlexibleMemory& accessFlexibleMemory();
#undef __APICALL

View File

@ -157,6 +157,10 @@ int munmap(void* addr, size_t len) {
return UnmapViewOfFile(addr) != 0 ? Ok : -1;
} break;
case MappingType::Direct: {
return accessDirectMemory().unmap((uint64_t)addr, len);
} break;
case MappingType::Flexible: {
return accessFlexibleMemory().destroy((uint64_t)addr, len) != 0 ? Ok : -1;
} break;
@ -166,7 +170,7 @@ int munmap(void* addr, size_t len) {
} break;
case MappingType::None: {
LOG_ERR(L"munmap unkown 0x%08llx 0x%08llx", addr, len);
LOG_ERR(L"munmap unkown 0x%08llx 0x%08llx type:%d", addr, len, type);
} break;
}
return -1;

View File

@ -126,12 +126,17 @@ std::optional<ImageData> ImageHandler::getImage_blocking() {
VkResult result = VK_SUCCESS;
for (; numTries >= 0; --numTries) {
if (result = vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX, imageData.semImageReady, VK_NULL_HANDLE, &imageData.index); result != VK_SUCCESS) {
// toggle every 1ms
if (result = vkAcquireNextImageKHR(m_device, m_swapchain, (uint64_t)1e6, imageData.semImageReady, VK_NULL_HANDLE, &imageData.index);
result != VK_SUCCESS) {
if (result == VK_NOT_READY) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::microseconds(100));
} else if (result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_OUT_OF_DATE_KHR) {
recreate();
++numTries;
} else if (result == VK_TIMEOUT) {
if (m_stop) return {};
++numTries;
}
} else
break;

View File

@ -278,7 +278,10 @@ class VideoOut: public IVideoOut, private IEventsGraphics {
void getSafeAreaRatio(float* area) final {
auto ext = m_imageHandler.get()->getExtent();
if (area != nullptr) *area = ext.width / (float)ext.height;
if (area != nullptr) {
*area = 0.781298f; // todo check what's up here
//*area = (float)ext.height / (float)ext.width;
}
}
vulkan::DeviceInfo* getDeviceInfo() final { return &m_vulkanObj->deviceInfo; }
@ -489,8 +492,8 @@ int VideoOut::SDLInit(uint32_t flags) {
m_condSDL2.notify_one();
lock.lock();
m_condDone.wait(lock, [=] { return result; });
return result;
m_condDone.wait(lock, [=] { return result >= 0; });
return result == 0 ? Ok : -1;
}
void VideoOut::transferDisplay(ImageData const& imageData, vulkan::SwapchainData::DisplayBuffers& displayBufferMeta, VkSemaphore waitSema, size_t waitValue) {
@ -670,7 +673,7 @@ int VideoOut::registerBuffers(int handle, int startIndex, void* const* addresses
bufferSet.buffers[n].bufferAlign = displaySizeAlign;
LOG_INFO(L"+bufferset[%d] buffer:%d vaddr:0x%08llx-0x%08llx", setIndex, n, (uint64_t)addresses[n], (uint64_t)addresses[n] + displaySizeAlign);
auto [format, colorSpace] = vulkan::getDisplayFormat(m_vulkanObj);
auto [format, _] = vulkan::getDisplayFormat(m_vulkanObj);
if (!m_graphics->registerDisplayBuffer(bufferSet.buffers[n].bufferVaddr, VkExtent2D {.width = _att->width, .height = _att->height}, _att->pitchInPixel,
format))
return -1;

View File

@ -34,17 +34,21 @@ std::pair<VkFormat, VkColorSpaceKHR> getDisplayFormat(VulkanObj* obj) {
if (obj->surfaceCapabilities.formats.empty()) {
return {VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR};
}
VkFormat format = obj->surfaceCapabilities.formats[0].format;
VkColorSpaceKHR imageColorSpace = obj->surfaceCapabilities.formats[0].colorSpace;
if (obj->surfaceCapabilities.format_unorm_bgra32) {
format = VK_FORMAT_B8G8R8A8_UNORM;
imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
} else if (obj->surfaceCapabilities.format_srgb_bgra32) {
format = VK_FORMAT_B8G8R8A8_SRGB;
imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
bool found = false;
for (auto const& format: obj->surfaceCapabilities.formats) {
if (format.format == VK_FORMAT_R8G8B8A8_SRGB) {
found = true;
}
}
return {format, imageColorSpace};
if (!found) {
LOG_USE_MODULE(vulkanHelper);
for (auto const& format: obj->surfaceCapabilities.formats) {
LOG_ERR(L"format %S", string_VkFormat(format.format));
}
LOG_CRIT(L"VK_FORMAT_B8G8R8A8_SRGB not supported");
}
return {VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR};
}
void submitDisplayTransfer(SwapchainData::DisplayBuffers const* displayBuffer, ImageData const& imageData, QueueInfo const* queue, VkSemaphore waitSema,

View File

@ -14,7 +14,8 @@ constexpr uint8_t SCE_KERNEL_PROT_GPU_WRITE = 0x20;
constexpr uint8_t SCE_KERNEL_PROT_GPU_RW = 0x30;
constexpr uint8_t SCE_KERNEL_PROT_GPU_ALL = 0x30;
constexpr uint32_t SCE_KERNEL_PAGE_SIZE = 16384;
constexpr uint32_t SCE_KERNEL_PAGE_SIZE = 16384;
constexpr uint64_t SCE_KERNEL_MAIN_DMEM_SIZE = 0x180000000;
constexpr uint32_t SCE_KERNEL_AIO_SCHED_WINDOW_MAX = 128;
constexpr uint32_t SCE_KERNEL_AIO_DELAYED_COUNT_MAX = 128;

View File

@ -3,6 +3,7 @@
#include "assert.h"
#include "common.h"
#include "core/dmem/dmem.h"
#include "core/kernel/filesystem.h"
#include "core/memory/memory.h"
#include "core/videoout/videoout.h"
#include "logging.h"
@ -18,7 +19,7 @@ extern "C" {
EXPORT SYSV_ABI size_t sceKernelGetDirectMemorySize() {
LOG_USE_MODULE(dmem);
auto size = accessPysicalMemory().size();
auto size = accessDirectMemory().size();
LOG_DEBUG(L"%S size:0x%08llx", __FUNCTION__, size);
return size;
}
@ -56,56 +57,41 @@ EXPORT SYSV_ABI int32_t sceKernelGetPrtAperture(int index, void** addr, size_t*
return Ok;
}
EXPORT SYSV_ABI int32_t sceKernelAllocateDirectMemory(off_t searchStart, off_t searchEnd, size_t len, size_t alignment, int memoryType, off_t* physAddrOut) {
EXPORT SYSV_ABI int32_t sceKernelAllocateDirectMemory(uint64_t searchStart, uint64_t searchEnd, size_t len, size_t alignment, int memoryType,
uint64_t* physAddrOut) {
if (len == 0 || physAddrOut == nullptr) {
return getErr(ErrCode::_EINVAL);
}
accessPysicalMemory().alloc(0, len, memoryType);
*physAddrOut = 1; // done with map
return Ok;
return accessDirectMemory().alloc(len, alignment, memoryType, physAddrOut);
}
EXPORT SYSV_ABI int32_t sceKernelAllocateMainDirectMemory(size_t len, size_t alignment, int memoryType, off_t* physAddrOut) {
EXPORT SYSV_ABI int32_t sceKernelAllocateMainDirectMemory(size_t len, size_t alignment, int memoryType, uint64_t* physAddrOut) {
if (len == 0 || physAddrOut == nullptr) {
return getErr(ErrCode::_EINVAL);
}
*physAddrOut = 1; // done with map
return Ok;
return accessDirectMemory().alloc(len, alignment, memoryType, physAddrOut);
}
EXPORT SYSV_ABI int32_t sceKernelReleaseDirectMemory(off_t start, size_t len) {
uint64_t vaddr = 0;
uint64_t size = 0;
bool result = accessPysicalMemory().Release(start, len, &vaddr, &size);
return Ok;
return accessDirectMemory().free(start, len);
}
EXPORT SYSV_ABI int32_t sceKernelCheckedReleaseDirectMemory(off_t start, size_t len) {
uint64_t vaddr = 0;
uint64_t size = 0;
bool result = accessPysicalMemory().Release(start, len, &vaddr, &size);
return Ok;
return accessDirectMemory().free(start, len);
}
EXPORT SYSV_ABI int32_t sceKernelMapNamedDirectMemory(uint64_t* addr, size_t len, int prot, int flags, off_t directMemoryStart, size_t alignment,
const char* name) {
if (!accessPysicalMemory().Map(*addr, directMemoryStart, len, prot, flags == 0x10, alignment, addr)) {
return getErr(ErrCode::_EINVAL);
}
return Ok;
EXPORT SYSV_ABI int32_t sceKernelMapNamedDirectMemory(uint64_t* addr, size_t len, int prot, int flags, off_t offset, size_t alignment, const char* name) {
return accessDirectMemory().map(*addr, offset, len, prot, flags, alignment, addr);
}
EXPORT SYSV_ABI int32_t sceKernelMapDirectMemory(uint64_t* addr, size_t len, int prot, int flags, off_t directMemoryStart, size_t maxPageSize) {
return sceKernelMapNamedDirectMemory(addr, len, prot, flags, directMemoryStart, maxPageSize, nullptr);
EXPORT SYSV_ABI int32_t sceKernelMapDirectMemory(uint64_t* addr, size_t len, int prot, int flags, off_t offset, size_t maxPageSize) {
return sceKernelMapNamedDirectMemory(addr, len, prot, flags, offset, maxPageSize, nullptr);
}
EXPORT SYSV_ABI int32_t sceKernelMapDirectMemory2(uint64_t* addr, size_t len, int type, int prot, int flags, off_t directMemoryStart, size_t maxPageSize) {
return sceKernelMapNamedDirectMemory(addr, len, prot, flags, directMemoryStart, maxPageSize, nullptr);
EXPORT SYSV_ABI int32_t sceKernelMapDirectMemory2(uint64_t* addr, size_t len, int type, int prot, int flags, off_t offset, size_t maxPageSize) {
return sceKernelMapNamedDirectMemory(addr, len, prot, flags, offset, maxPageSize, nullptr);
}
EXPORT SYSV_ABI int32_t sceKernelGetDirectMemoryType(off_t start, int* memoryType, off_t* regionStartOut, off_t* regionEndOut) {
@ -114,30 +100,38 @@ EXPORT SYSV_ABI int32_t sceKernelGetDirectMemoryType(off_t start, int* memoryTyp
return Ok;
}
EXPORT SYSV_ABI int32_t sceKernelBatchMap(SceKernelBatchMapEntry* items, int size, int* count) {
struct BatchMapEntry {
uint64_t start;
uint32_t physAddr;
size_t length;
uint8_t prot;
uint8_t type;
short pad1;
int operation;
};
EXPORT SYSV_ABI int32_t sceKernelBatchMap2(SceKernelBatchMapEntry* entries, int numberOfEntries, int* numberOfEntriesOut, int flags) {
LOG_USE_MODULE(dmem);
for (*numberOfEntriesOut = 0; *numberOfEntriesOut < numberOfEntries; ++*numberOfEntriesOut) {
auto& batchEntry = (entries)[*numberOfEntriesOut];
for (*count = 0; *count < size; ++*count) {
auto& batchEntry = ((BatchMapEntry*)items)[*count];
uint64_t addr = accessPysicalMemory().commit(batchEntry.start, batchEntry.physAddr, batchEntry.length, 0, batchEntry.prot);
if (addr == 0) {
return getErr(ErrCode::_ENOMEM);
switch (batchEntry.operation) {
case SceKernelMapOp::MAP_DIRECT: {
auto res = accessDirectMemory().map(batchEntry.start, batchEntry.physAddr, batchEntry.length, batchEntry.prot, flags, 0, &batchEntry.start);
if (res != Ok) {
return res;
}
} break;
case SceKernelMapOp::UNMAP: {
LOG_ERR(L"todo %S op:%d", __FUNCTION__, batchEntry.operation);
} break;
case SceKernelMapOp::PROTECT: {
LOG_ERR(L"todo %S op:%d", __FUNCTION__, batchEntry.operation);
} break;
case SceKernelMapOp::MAP_FLEXIBLE: {
LOG_ERR(L"todo %S op:%d", __FUNCTION__, batchEntry.operation);
} break;
case SceKernelMapOp::TYPE_PROTECT: {
LOG_ERR(L"todo %S op:%d", __FUNCTION__, batchEntry.operation);
} break;
}
}
return Ok;
}
EXPORT SYSV_ABI int32_t sceKernelBatchMap2(SceKernelBatchMapEntry* entries, int numberOfEntries, int* numberOfEntriesOut, int flags) {
return sceKernelBatchMap(entries, numberOfEntries, numberOfEntriesOut);
EXPORT SYSV_ABI int32_t sceKernelBatchMap(SceKernelBatchMapEntry* items, int size, int* count) {
return sceKernelBatchMap2(items, size, count, (int)filesystem::SceMapMode::NO_OVERWRITE);
}
EXPORT SYSV_ABI int32_t sceKernelJitCreateSharedMemory(const char* name, size_t len, int maxProt, int* fdOut) {
@ -226,17 +220,11 @@ EXPORT SYSV_ABI int32_t sceKernelSetVirtualRangeName(void* start, size_t len, co
}
EXPORT SYSV_ABI int sceKernelReserveVirtualRange(uintptr_t* addr, size_t len, int flags, size_t alignment) {
auto const inAddr = *addr;
if (len == 0) {
if (addr == nullptr || len == 0) {
return getErr(ErrCode::_EINVAL);
}
if (!accessPysicalMemory().reserve(inAddr, len, alignment, addr, 1)) {
return getErr(ErrCode::_EAGAIN);
}
return Ok;
return accessDirectMemory().reserve(*addr, len, alignment, flags, addr);
}
struct QueryInfo {
@ -278,7 +266,7 @@ EXPORT SYSV_ABI int32_t sceKernelMtypeprotect(const void* addr, size_t size, int
}
EXPORT SYSV_ABI int32_t sceKernelAvailableDirectMemorySize(off_t start, off_t end, size_t alignment, uint32_t* startOut, size_t* sizeOut) {
accessPysicalMemory().getAvailableSize(start, end, alignment, startOut, sizeOut);
accessDirectMemory().getAvailableSize(start, end, alignment, startOut, sizeOut);
return Ok;
}
@ -318,7 +306,8 @@ EXPORT SYSV_ABI int32_t sceKernelMemoryPoolDecommit(void* addr, size_t len, int
EXPORT SYSV_ABI int32_t sceKernelMemoryPoolExpand(off_t searchStart, off_t searchEnd, size_t len, size_t alignment, off_t* physAddrOut) {
LOG_USE_MODULE(dmem);
LOG_ERR(L"todo %S| start:0x%08llx end:0x%08llx, len:0x%08llx align:0x%08llx", __FUNCTION__, searchStart, searchEnd, len, alignment);
*physAddrOut = memory::reserve(0, len, alignment, false);
LOG_DEBUG(L"PoolReserve| start:0x%08llx, len:0x%08llx align:0x%08llx-> out:0x%08llx", searchStart, len, alignment, *physAddrOut);
return Ok;
}

View File

@ -2,15 +2,22 @@
#include <modules_include/common.h>
enum class SceKernelMemoryType { WB_ONION = 0, WC_GARLIC = 3, WB_GARLIC, MEMORY_TYPE_END };
enum class SceKernelMapOp : int {
MAP_DIRECT,
UNMAP,
PROTECT,
MAP_FLEXIBLE,
TYPE_PROTECT,
};
struct SceKernelBatchMapEntry {
uint64_t start;
uint32_t physAddr;
size_t length;
uint8_t prot;
uint8_t type;
short pad1;
int operation;
uint64_t start;
uint32_t physAddr;
size_t length;
uint8_t prot;
uint8_t type;
short pad1;
SceKernelMapOp operation;
};
struct SceKernelVirtualQueryInfo {

View File

@ -19,3 +19,5 @@ include_directories(
)
add_subdirectory(core)
install(TARGETS semaphore_test RUNTIME DESTINATION .)

View File

@ -15,11 +15,3 @@ target_link_libraries(semaphore_test PRIVATE
libboost_thread
libboost_chrono
)
set_target_properties(semaphore_test
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/."
)

View File

@ -52,8 +52,11 @@ void setThreadName(std::string_view name, void* nativeHandle) {
}
int getPageSize(void) {
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwPageSize;
static int pageSize = [] {
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwPageSize;
}();
return pageSize;
}
} // namespace util

View File

@ -88,6 +88,11 @@ constexpr std::uint64_t alignDown(uint64_t value, uint64_t alignment) {
return value & ~(alignment - 1);
}
constexpr bool isPowerOfTwo(int n) {
if (n == 0) return false;
return (n & (n - 1)) == 0;
}
void setThreadName(std::string_view name);
void setThreadName(std::string_view name, void* nativeHandle);