Merge pull request #175 from shadps4-emu/missing_gnm_calls

Additional GnmDriver functions
This commit is contained in:
georgemoralis 2024-06-09 00:58:45 +03:00 committed by GitHub
commit ac192134e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 126 additions and 30 deletions

View File

@ -240,6 +240,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/rdtsc.cpp src/common/rdtsc.cpp
src/common/rdtsc.h src/common/rdtsc.h
src/common/singleton.h src/common/singleton.h
src/common/slot_vector.h
src/common/string_util.cpp src/common/string_util.cpp
src/common/string_util.h src/common/string_util.h
src/common/thread.cpp src/common/thread.cpp
@ -420,7 +421,6 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/texture_cache/image_view.h src/video_core/texture_cache/image_view.h
src/video_core/texture_cache/sampler.cpp src/video_core/texture_cache/sampler.cpp
src/video_core/texture_cache/sampler.h src/video_core/texture_cache/sampler.h
src/video_core/texture_cache/slot_vector.h
src/video_core/texture_cache/texture_cache.cpp src/video_core/texture_cache/texture_cache.cpp
src/video_core/texture_cache/texture_cache.h src/video_core/texture_cache/texture_cache.h
src/video_core/texture_cache/tile_manager.cpp src/video_core/texture_cache/tile_manager.cpp

View File

@ -113,8 +113,10 @@ struct AddressSpace::Impl {
return ptr; return ptr;
} }
void* MapPrivate(VAddr virtual_addr, size_t size, u64 alignment, ULONG prot) { void* MapPrivate(VAddr virtual_addr, size_t size, u64 alignment, ULONG prot,
bool no_commit = false) {
// Map a private allocation // Map a private allocation
PVOID addr = reinterpret_cast<PVOID>(virtual_addr);
MEM_ADDRESS_REQUIREMENTS req{}; MEM_ADDRESS_REQUIREMENTS req{};
MEM_EXTENDED_PARAMETER param{}; MEM_EXTENDED_PARAMETER param{};
// req.LowestStartingAddress = // req.LowestStartingAddress =
@ -124,9 +126,27 @@ struct AddressSpace::Impl {
req.Alignment = alignment < 64_KB ? 0 : alignment; req.Alignment = alignment < 64_KB ? 0 : alignment;
param.Type = MemExtendedParameterAddressRequirements; param.Type = MemExtendedParameterAddressRequirements;
param.Pointer = &req; param.Pointer = &req;
ULONG alloc_type = MEM_COMMIT | MEM_RESERVE | (alignment > 2_MB ? MEM_LARGE_PAGES : 0); ULONG alloc_type = MEM_RESERVE | (alignment > 2_MB ? MEM_LARGE_PAGES : 0);
void* const ptr = VirtualAlloc2(process, nullptr, size, alloc_type, prot, &param, 1); if (!no_commit) {
alloc_type |= MEM_COMMIT;
}
// Check if the area has been reserved beforehand (typically for tesselation buffer)
// and in that case don't reserve it again as Windows complains.
if (virtual_addr) {
MEMORY_BASIC_INFORMATION info;
VirtualQuery(addr, &info, sizeof(info));
if (info.State == MEM_RESERVE) {
alloc_type &= ~MEM_RESERVE;
}
}
void* ptr{};
if (virtual_addr) {
ptr = VirtualAlloc2(process, addr, size, alloc_type, prot, NULL, 0);
ASSERT_MSG(ptr && VAddr(ptr) == virtual_addr, "{}", Common::GetLastErrorMsg());
} else {
ptr = VirtualAlloc2(process, nullptr, size, alloc_type, prot, &param, 1);
ASSERT_MSG(ptr, "{}", Common::GetLastErrorMsg()); ASSERT_MSG(ptr, "{}", Common::GetLastErrorMsg());
}
return ptr; return ptr;
} }
@ -224,7 +244,8 @@ struct AddressSpace::Impl {
return nullptr; return nullptr;
} }
void* MapPrivate(VAddr virtual_addr, size_t size, u64 alignment, PosixPageProtection prot) { void* MapPrivate(VAddr virtual_addr, size_t size, u64 alignment, PosixPageProtection prot,
bool no_commit = false) {
UNREACHABLE(); UNREACHABLE();
return nullptr; return nullptr;
} }
@ -271,4 +292,8 @@ void AddressSpace::Protect(VAddr virtual_addr, size_t size, MemoryPermission per
return impl->Protect(virtual_addr, size, true, true, true); return impl->Protect(virtual_addr, size, true, true, true);
} }
void* AddressSpace::Reserve(size_t size, u64 alignment) {
return impl->MapPrivate(0, size, alignment, PAGE_READWRITE, true);
}
} // namespace Core } // namespace Core

View File

@ -49,6 +49,8 @@ public:
void Protect(VAddr virtual_addr, size_t size, MemoryPermission perms); void Protect(VAddr virtual_addr, size_t size, MemoryPermission perms);
void* Reserve(size_t size, u64 alignment);
private: private:
struct Impl; struct Impl;
std::unique_ptr<Impl> impl; std::unique_ptr<Impl> impl;

View File

@ -246,6 +246,13 @@ constexpr int SCE_VIDEO_OUT_ERROR_SLOT_OCCUPIED = 0x80290010; // slot alr
constexpr int SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL = 0x80290012; // flip queue is full constexpr int SCE_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL = 0x80290012; // flip queue is full
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_OPTION = 0x8029001A; // Invalid buffer attribute option constexpr int SCE_VIDEO_OUT_ERROR_INVALID_OPTION = 0x8029001A; // Invalid buffer attribute option
// GnmDriver
constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_PIPE_ID = 0x80D17000;
constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_QUEUE_ID = 0x80D17001;
constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_RING_BASE_ADDR = 0x80D17003;
constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_RING_SIZE = 0x80D17002;
constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_READ_PTR_ADDR = 0x80D17004;
// Generic // Generic
constexpr int ORBIS_OK = 0x00000000; constexpr int ORBIS_OK = 0x00000000;
constexpr int ORBIS_FAIL = 0xFFFFFFFF; constexpr int ORBIS_FAIL = 0xFFFFFFFF;

View File

@ -5,10 +5,12 @@
#include "common/config.h" #include "common/config.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/path_util.h" #include "common/path_util.h"
#include "common/slot_vector.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/gnmdriver/gnmdriver.h" #include "core/libraries/gnmdriver/gnmdriver.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "core/libraries/videoout/video_out.h" #include "core/libraries/videoout/video_out.h"
#include "core/memory.h"
#include "core/platform.h" #include "core/platform.h"
#include "video_core/amdgpu/liverpool.h" #include "video_core/amdgpu/liverpool.h"
#include "video_core/amdgpu/pm4_cmds.h" #include "video_core/amdgpu/pm4_cmds.h"
@ -32,6 +34,17 @@ static constexpr bool g_fair_hw_init = false;
static u32 submission_lock{}; static u32 submission_lock{};
static u64 frames_submitted{}; // frame counter static u64 frames_submitted{}; // frame counter
struct AscQueueInfo {
VAddr map_addr;
u32* read_addr;
u32 ring_size_dw;
};
static VideoCore::SlotVector<AscQueueInfo> asc_queues{};
static constexpr u32 TessellationFactorRingSize = 128_KB;
static constexpr u32 TessellationFactorRingAlignment = 64_KB; // toolkit is using this alignment
VAddr tessellation_factors_ring_addr{0};
static void DumpCommandList(std::span<const u32> cmd_list, const std::string& postfix) { static void DumpCommandList(std::span<const u32> cmd_list, const std::string& postfix) {
using namespace Common::FS; using namespace Common::FS;
const auto dump_dir = GetUserPath(PathType::PM4Dir); const auto dump_dir = GetUserPath(PathType::PM4Dir);
@ -367,9 +380,18 @@ int PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState175() { u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState175(u32* cmdbuf, u32 size) {
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); LOG_TRACE(Lib_GnmDriver, "called");
return ORBIS_OK;
if (size > 0xff) {
if constexpr (g_fair_hw_init) {
ASSERT_MSG(0, "Not implemented");
} else {
cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, 0xff);
}
return 0x100; // it is a size, not a retcode
}
return 0;
} }
u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState200(u32* cmdbuf, u32 size) { u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState200(u32* cmdbuf, u32 size) {
@ -379,7 +401,7 @@ u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState200(u32* cmdbuf, u32 size) {
if constexpr (g_fair_hw_init) { if constexpr (g_fair_hw_init) {
ASSERT_MSG(0, "Not implemented"); ASSERT_MSG(0, "Not implemented");
} else { } else {
cmdbuf = cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, 0xff); cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, 0xff);
} }
return 0x100; // it is a size, not a retcode return 0x100; // it is a size, not a retcode
} }
@ -393,7 +415,7 @@ u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState350(u32* cmdbuf, u32 size) {
if constexpr (g_fair_hw_init) { if constexpr (g_fair_hw_init) {
ASSERT_MSG(0, "Not implemented"); ASSERT_MSG(0, "Not implemented");
} else { } else {
cmdbuf = cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, 0xff); cmdbuf = WriteHeader<PM4ItOpcode::Nop>(cmdbuf, 0xff);
} }
return 0x100; // it is a size, not a retcode return 0x100; // it is a size, not a retcode
} }
@ -599,9 +621,15 @@ int PS4_SYSV_ABI sceGnmGetShaderStatus() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceGnmGetTheTessellationFactorRingBufferBaseAddress() { VAddr PS4_SYSV_ABI sceGnmGetTheTessellationFactorRingBufferBaseAddress() {
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); LOG_TRACE(Lib_GnmDriver, "called");
return ORBIS_OK; // Actual virtual buffer address is hardcoded in the driver to 0xff00'000
if (tessellation_factors_ring_addr == 0) {
auto* memory = Core::Memory::Instance();
tessellation_factors_ring_addr =
memory->Reserve(TessellationFactorRingSize, TessellationFactorRingAlignment);
}
return tessellation_factors_ring_addr;
} }
int PS4_SYSV_ABI sceGnmGpuPaDebugEnter() { int PS4_SYSV_ABI sceGnmGpuPaDebugEnter() {
@ -718,14 +746,44 @@ int PS4_SYSV_ABI sceGnmLogicalTcaUnitToPhysical() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceGnmMapComputeQueue() { int PS4_SYSV_ABI sceGnmMapComputeQueue(u32 pipe_id, u32 queue_id, VAddr ring_base_addr,
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); u32 ring_size_dw, u32* read_ptr_addr) {
return ORBIS_OK; LOG_TRACE(Lib_GnmDriver, "called");
if (pipe_id >= Liverpool::NumComputePipes) {
return ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_PIPE_ID;
}
if (queue_id >= Liverpool::NumQueuesPerPipe) {
return ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_QUEUE_ID;
}
if (VAddr(ring_base_addr) % 256 != 0) { // alignment check
return ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_RING_BASE_ADDR;
}
if (!std::has_single_bit(ring_size_dw)) {
return ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_RING_SIZE;
}
if (VAddr(read_ptr_addr) % 4 != 0) { // alignment check
return ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_READ_PTR_ADDR;
}
auto vqid = asc_queues.insert(VAddr(ring_base_addr), read_ptr_addr, ring_size_dw);
LOG_INFO(Lib_GnmDriver, "ASC pipe {} queue {} mapped to vqueue {}", pipe_id, queue_id,
vqid.index);
return vqid.index;
} }
int PS4_SYSV_ABI sceGnmMapComputeQueueWithPriority() { int PS4_SYSV_ABI sceGnmMapComputeQueueWithPriority(u32 pipe_id, u32 queue_id, VAddr ring_base_addr,
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); u32 ring_size_dw, u32* read_ptr_addr,
return ORBIS_OK; u32 pipePriority) {
LOG_TRACE(Lib_GnmDriver, "called");
(void)pipePriority;
return sceGnmMapComputeQueue(pipe_id, queue_id, ring_base_addr, ring_size_dw, read_ptr_addr);
} }
int PS4_SYSV_ABI sceGnmPaDisableFlipCallbacks() { int PS4_SYSV_ABI sceGnmPaDisableFlipCallbacks() {

View File

@ -54,7 +54,7 @@ int PS4_SYSV_ABI sceGnmDrawIndirect();
int PS4_SYSV_ABI sceGnmDrawIndirectCountMulti(); int PS4_SYSV_ABI sceGnmDrawIndirectCountMulti();
int PS4_SYSV_ABI sceGnmDrawIndirectMulti(); int PS4_SYSV_ABI sceGnmDrawIndirectMulti();
int PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState(); int PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState();
int PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState175(); u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState175(u32* cmdbuf, u32 size);
u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState200(u32* cmdbuf, u32 size); u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState200(u32* cmdbuf, u32 size);
u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState350(u32* cmdbuf, u32 size); u32 PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState350(u32* cmdbuf, u32 size);
int PS4_SYSV_ABI sceGnmDrawInitToDefaultContextState(); int PS4_SYSV_ABI sceGnmDrawInitToDefaultContextState();
@ -97,7 +97,7 @@ int PS4_SYSV_ABI sceGnmGetResourceType();
int PS4_SYSV_ABI sceGnmGetResourceUserData(); int PS4_SYSV_ABI sceGnmGetResourceUserData();
int PS4_SYSV_ABI sceGnmGetShaderProgramBaseAddress(); int PS4_SYSV_ABI sceGnmGetShaderProgramBaseAddress();
int PS4_SYSV_ABI sceGnmGetShaderStatus(); int PS4_SYSV_ABI sceGnmGetShaderStatus();
int PS4_SYSV_ABI sceGnmGetTheTessellationFactorRingBufferBaseAddress(); VAddr PS4_SYSV_ABI sceGnmGetTheTessellationFactorRingBufferBaseAddress();
int PS4_SYSV_ABI sceGnmGpuPaDebugEnter(); int PS4_SYSV_ABI sceGnmGpuPaDebugEnter();
int PS4_SYSV_ABI sceGnmGpuPaDebugLeave(); int PS4_SYSV_ABI sceGnmGpuPaDebugLeave();
int PS4_SYSV_ABI sceGnmInsertDingDongMarker(); int PS4_SYSV_ABI sceGnmInsertDingDongMarker();
@ -113,8 +113,11 @@ int PS4_SYSV_ABI sceGnmIsUserPaEnabled();
int PS4_SYSV_ABI sceGnmLogicalCuIndexToPhysicalCuIndex(); int PS4_SYSV_ABI sceGnmLogicalCuIndexToPhysicalCuIndex();
int PS4_SYSV_ABI sceGnmLogicalCuMaskToPhysicalCuMask(); int PS4_SYSV_ABI sceGnmLogicalCuMaskToPhysicalCuMask();
int PS4_SYSV_ABI sceGnmLogicalTcaUnitToPhysical(); int PS4_SYSV_ABI sceGnmLogicalTcaUnitToPhysical();
int PS4_SYSV_ABI sceGnmMapComputeQueue(); int PS4_SYSV_ABI sceGnmMapComputeQueue(u32 pipe_id, u32 queue_id, VAddr ring_base_addr,
int PS4_SYSV_ABI sceGnmMapComputeQueueWithPriority(); u32 ring_size_dw, u32* read_ptr_addr);
int PS4_SYSV_ABI sceGnmMapComputeQueueWithPriority(u32 pipe_id, u32 queue_id, VAddr ring_base_addr,
u32 ring_size_dw, u32* read_ptr_addr,
u32 pipePriority);
int PS4_SYSV_ABI sceGnmPaDisableFlipCallbacks(); int PS4_SYSV_ABI sceGnmPaDisableFlipCallbacks();
int PS4_SYSV_ABI sceGnmPaEnableFlipCallbacks(); int PS4_SYSV_ABI sceGnmPaEnableFlipCallbacks();
int PS4_SYSV_ABI sceGnmPaHeartbeat(); int PS4_SYSV_ABI sceGnmPaHeartbeat();

View File

@ -92,10 +92,7 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M
it++; it++;
} }
ASSERT(it != vma_map.end()); ASSERT(it != vma_map.end());
if (alignment > 0) { mapped_addr = alignment > 0 ? Common::AlignUp(it->second.base, alignment) : it->second.base;
ASSERT_MSG(it->second.base % alignment == 0, "Free region base is not aligned");
}
mapped_addr = it->second.base;
} }
// Perform the mapping. // Perform the mapping.

View File

@ -115,6 +115,10 @@ public:
int DirectMemoryQuery(PAddr addr, bool find_next, Libraries::Kernel::OrbisQueryInfo* out_info); int DirectMemoryQuery(PAddr addr, bool find_next, Libraries::Kernel::OrbisQueryInfo* out_info);
VAddr Reserve(size_t size, u64 alignment) {
return reinterpret_cast<VAddr>(impl.Reserve(size, alignment));
}
std::pair<vk::Buffer, size_t> GetVulkanBuffer(VAddr addr); std::pair<vk::Buffer, size_t> GetVulkanBuffer(VAddr addr);
private: private:

View File

@ -7,12 +7,12 @@
#include <boost/icl/interval_map.hpp> #include <boost/icl/interval_map.hpp>
#include <tsl/robin_map.h> #include <tsl/robin_map.h>
#include "common/slot_vector.h"
#include "video_core/amdgpu/resource.h" #include "video_core/amdgpu/resource.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/texture_cache/image.h" #include "video_core/texture_cache/image.h"
#include "video_core/texture_cache/image_view.h" #include "video_core/texture_cache/image_view.h"
#include "video_core/texture_cache/sampler.h" #include "video_core/texture_cache/sampler.h"
#include "video_core/texture_cache/slot_vector.h"
#include "video_core/texture_cache/tile_manager.h" #include "video_core/texture_cache/tile_manager.h"
namespace Core::Libraries::VideoOut { namespace Core::Libraries::VideoOut {

View File

@ -3,8 +3,8 @@
#pragma once #pragma once
#include "common/slot_vector.h"
#include "common/types.h" #include "common/types.h"
#include "video_core/texture_cache/slot_vector.h"
namespace VideoCore { namespace VideoCore {