mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 08:22:32 +00:00
Merge branch 'ajm' into test
This commit is contained in:
commit
8d6afc98a8
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -95,3 +95,6 @@
|
|||||||
path = externals/pugixml
|
path = externals/pugixml
|
||||||
url = https://github.com/zeux/pugixml.git
|
url = https://github.com/zeux/pugixml.git
|
||||||
shallow = true
|
shallow = true
|
||||||
|
[submodule "externals/LibAtrac9"]
|
||||||
|
path = externals/LibAtrac9
|
||||||
|
url = https://github.com/Vita3K/LibAtrac9
|
@ -177,6 +177,10 @@ set(AUDIO_LIB src/core/libraries/audio/audioin.cpp
|
|||||||
src/core/libraries/audio/audioout.h
|
src/core/libraries/audio/audioout.h
|
||||||
src/core/libraries/ajm/ajm.cpp
|
src/core/libraries/ajm/ajm.cpp
|
||||||
src/core/libraries/ajm/ajm.h
|
src/core/libraries/ajm/ajm.h
|
||||||
|
src/core/libraries/ajm/ajm_mp3.cpp
|
||||||
|
src/core/libraries/ajm/ajm_mp3.h
|
||||||
|
src/core/libraries/ajm/ajm_at9.cpp
|
||||||
|
src/core/libraries/ajm/ajm_at9.h
|
||||||
src/core/libraries/ngs2/ngs2.cpp
|
src/core/libraries/ngs2/ngs2.cpp
|
||||||
src/core/libraries/ngs2/ngs2.h
|
src/core/libraries/ngs2/ngs2.h
|
||||||
)
|
)
|
||||||
@ -742,7 +746,7 @@ endif()
|
|||||||
|
|
||||||
create_target_directory_groups(shadps4)
|
create_target_directory_groups(shadps4)
|
||||||
|
|
||||||
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn)
|
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui LibAtrac9 gcn)
|
||||||
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml)
|
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml)
|
||||||
|
|
||||||
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
|
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
|
||||||
|
9
externals/CMakeLists.txt
vendored
9
externals/CMakeLists.txt
vendored
@ -47,6 +47,15 @@ if (NOT TARGET FFmpeg::ffmpeg)
|
|||||||
add_library(FFmpeg::ffmpeg ALIAS ffmpeg)
|
add_library(FFmpeg::ffmpeg ALIAS ffmpeg)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# LibAtrac9
|
||||||
|
|
||||||
|
file(GLOB LIBATRAC9_SOURCES
|
||||||
|
LibAtrac9/C/src/*.c
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(LibAtrac9 STATIC ${LIBATRAC9_SOURCES})
|
||||||
|
target_include_directories(LibAtrac9 PUBLIC LibAtrac9/C/src)
|
||||||
|
|
||||||
# Zlib-Ng
|
# Zlib-Ng
|
||||||
if (NOT TARGET zlib-ng::zlib)
|
if (NOT TARGET zlib-ng::zlib)
|
||||||
set(ZLIB_ENABLE_TESTS OFF)
|
set(ZLIB_ENABLE_TESTS OFF)
|
||||||
|
1
externals/LibAtrac9
vendored
Submodule
1
externals/LibAtrac9
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 82767fe38823c32536726ea798f392b0b49e66b9
|
18
src/.vscode/c_cpp_properties.json
vendored
Normal file
18
src/.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "linux-gcc-x64",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**"
|
||||||
|
],
|
||||||
|
"compilerPath": "/usr/bin/gcc",
|
||||||
|
"cStandard": "${default}",
|
||||||
|
"cppStandard": "${default}",
|
||||||
|
"intelliSenseMode": "linux-gcc-x64",
|
||||||
|
"compilerArgs": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
24
src/.vscode/launch.json
vendored
Normal file
24
src/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "C/C++ Runner: Debug Session",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"args": [],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"externalConsole": false,
|
||||||
|
"cwd": "/home/turtle/Desktop/shadPS4/src",
|
||||||
|
"program": "/home/turtle/Desktop/shadPS4/src/build/Debug/outDebug",
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerPath": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
59
src/.vscode/settings.json
vendored
Normal file
59
src/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"C_Cpp_Runner.cCompilerPath": "gcc",
|
||||||
|
"C_Cpp_Runner.cppCompilerPath": "g++",
|
||||||
|
"C_Cpp_Runner.debuggerPath": "gdb",
|
||||||
|
"C_Cpp_Runner.cStandard": "",
|
||||||
|
"C_Cpp_Runner.cppStandard": "",
|
||||||
|
"C_Cpp_Runner.msvcBatchPath": "",
|
||||||
|
"C_Cpp_Runner.useMsvc": false,
|
||||||
|
"C_Cpp_Runner.warnings": [
|
||||||
|
"-Wall",
|
||||||
|
"-Wextra",
|
||||||
|
"-Wpedantic",
|
||||||
|
"-Wshadow",
|
||||||
|
"-Wformat=2",
|
||||||
|
"-Wcast-align",
|
||||||
|
"-Wconversion",
|
||||||
|
"-Wsign-conversion",
|
||||||
|
"-Wnull-dereference"
|
||||||
|
],
|
||||||
|
"C_Cpp_Runner.msvcWarnings": [
|
||||||
|
"/W4",
|
||||||
|
"/permissive-",
|
||||||
|
"/w14242",
|
||||||
|
"/w14287",
|
||||||
|
"/w14296",
|
||||||
|
"/w14311",
|
||||||
|
"/w14826",
|
||||||
|
"/w44062",
|
||||||
|
"/w44242",
|
||||||
|
"/w14905",
|
||||||
|
"/w14906",
|
||||||
|
"/w14263",
|
||||||
|
"/w44265",
|
||||||
|
"/w14928"
|
||||||
|
],
|
||||||
|
"C_Cpp_Runner.enableWarnings": true,
|
||||||
|
"C_Cpp_Runner.warningsAsError": false,
|
||||||
|
"C_Cpp_Runner.compilerArgs": [],
|
||||||
|
"C_Cpp_Runner.linkerArgs": [],
|
||||||
|
"C_Cpp_Runner.includePaths": [],
|
||||||
|
"C_Cpp_Runner.includeSearch": [
|
||||||
|
"*",
|
||||||
|
"**/*"
|
||||||
|
],
|
||||||
|
"C_Cpp_Runner.excludeSearch": [
|
||||||
|
"**/build",
|
||||||
|
"**/build/**",
|
||||||
|
"**/.*",
|
||||||
|
"**/.*/**",
|
||||||
|
"**/.vscode",
|
||||||
|
"**/.vscode/**"
|
||||||
|
],
|
||||||
|
"C_Cpp_Runner.useAddressSanitizer": false,
|
||||||
|
"C_Cpp_Runner.useUndefinedSanitizer": false,
|
||||||
|
"C_Cpp_Runner.useLeakSanitizer": false,
|
||||||
|
"C_Cpp_Runner.showCompilationTime": false,
|
||||||
|
"C_Cpp_Runner.useLinkTimeOptimization": false,
|
||||||
|
"C_Cpp_Runner.msvcSecureNoWarnings": false
|
||||||
|
}
|
@ -1,15 +1,59 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
#pragma clang optimize off
|
||||||
|
#include <numeric>
|
||||||
|
#include <magic_enum.hpp>
|
||||||
|
|
||||||
#include "ajm.h"
|
#include "ajm_at9.h"
|
||||||
#include "ajm_error.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/debug.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/libraries/ajm/ajm.h"
|
||||||
|
#include "core/libraries/ajm/ajm_error.h"
|
||||||
|
#include "core/libraries/ajm/ajm_instance.h"
|
||||||
|
#include "core/libraries/ajm/ajm_mp3.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <error_codes.h>
|
||||||
|
#include <libatrac9.h>
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
#include <libswresample/swresample.h>
|
||||||
|
#include <structures.h>
|
||||||
|
}
|
||||||
|
|
||||||
namespace Libraries::Ajm {
|
namespace Libraries::Ajm {
|
||||||
|
|
||||||
|
static constexpr u32 AJM_INSTANCE_STATISTICS = 0x80000;
|
||||||
|
|
||||||
|
static constexpr u32 MaxInstances = 0x2fff;
|
||||||
|
|
||||||
|
struct AjmDevice {
|
||||||
|
u32 max_prio;
|
||||||
|
u32 min_prio;
|
||||||
|
u32 curr_cursor{};
|
||||||
|
u32 release_cursor{MaxInstances - 1};
|
||||||
|
std::array<bool, NumAjmCodecs> is_registered{};
|
||||||
|
std::array<u32, MaxInstances> free_instances{};
|
||||||
|
std::array<std::unique_ptr<AjmAt9Decoder>, MaxInstances> instances;
|
||||||
|
|
||||||
|
bool IsRegistered(AjmCodecType type) const {
|
||||||
|
return is_registered[static_cast<u32>(type)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Register(AjmCodecType type) {
|
||||||
|
is_registered[static_cast<u32>(type)] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AjmDevice() {
|
||||||
|
std::iota(free_instances.begin(), free_instances.end(), 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::unique_ptr<AjmDevice> dev{};
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmBatchCancel() {
|
int PS4_SYSV_ABI sceAjmBatchCancel() {
|
||||||
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
@ -20,28 +64,314 @@ int PS4_SYSV_ABI sceAjmBatchErrorDump() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmBatchJobControlBufferRa() {
|
void* PS4_SYSV_ABI sceAjmBatchJobControlBufferRa(AjmSingleJob* batch_pos, u32 instance,
|
||||||
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
AjmFlags flags, u8* in_buffer, u32 in_size,
|
||||||
return ORBIS_OK;
|
u8* out_buffer, u32 out_size,
|
||||||
|
const void* ret_addr) {
|
||||||
|
LOG_INFO(Lib_Ajm,
|
||||||
|
"called instance = {:#x}, flags = {:#x}, cmd = {}, in_size = {:#x}, out_size = {:#x}, "
|
||||||
|
"ret_addr = {}",
|
||||||
|
instance, flags.raw, magic_enum::enum_name(AjmJobControlFlags(flags.command)), in_size,
|
||||||
|
out_size, fmt::ptr(ret_addr));
|
||||||
|
|
||||||
|
const u64 mask = instance == AJM_INSTANCE_STATISTICS ? 0xc0018007ULL : 0x60000000e7ffULL;
|
||||||
|
flags.raw &= mask;
|
||||||
|
|
||||||
|
const bool is_debug = ret_addr != nullptr;
|
||||||
|
batch_pos->opcode.instance = instance;
|
||||||
|
batch_pos->opcode.codec_flags = flags.codec;
|
||||||
|
batch_pos->opcode.command_flags = flags.command;
|
||||||
|
batch_pos->opcode.sideband_flags = AjmJobSidebandFlags(flags.sideband);
|
||||||
|
batch_pos->opcode.is_debug = is_debug;
|
||||||
|
batch_pos->opcode.is_statistic = instance == AJM_INSTANCE_STATISTICS;
|
||||||
|
batch_pos->opcode.is_control = true;
|
||||||
|
|
||||||
|
if (instance == AJM_INSTANCE_STATISTICS) {
|
||||||
|
BREAKPOINT();
|
||||||
|
}
|
||||||
|
|
||||||
|
AjmInOutJob* job = nullptr;
|
||||||
|
if (ret_addr == nullptr) {
|
||||||
|
batch_pos->job_size = sizeof(AjmInOutJob);
|
||||||
|
job = &batch_pos->job;
|
||||||
|
} else {
|
||||||
|
batch_pos->job_size = sizeof(AjmInOutJob) + 16;
|
||||||
|
batch_pos->ret.unk1 = batch_pos->ret.unk1 & 0xfffffff0 | 6;
|
||||||
|
batch_pos->ret.unk2 = 0;
|
||||||
|
batch_pos->ret.ret_addr = ret_addr;
|
||||||
|
job = &batch_pos->ret.job;
|
||||||
|
}
|
||||||
|
|
||||||
|
job->input.props &= 0xffffffe0;
|
||||||
|
job->input.props |= 2;
|
||||||
|
job->input.buf_size = in_size;
|
||||||
|
job->input.buffer = in_buffer;
|
||||||
|
job->unk1 = (job->unk1 & 0xfc000030) + ((flags.raw >> 0x1a) & 0x180000) + 3;
|
||||||
|
job->flags = u32(flags.raw);
|
||||||
|
job->output.props &= 0xffffffe0;
|
||||||
|
job->output.props |= 0x12;
|
||||||
|
job->output.buf_size = out_size;
|
||||||
|
job->output.buffer = out_buffer;
|
||||||
|
return ++job;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmBatchJobInlineBuffer() {
|
void* PS4_SYSV_ABI sceAjmBatchJobInlineBuffer(AjmSingleJob* batch_pos, const void* in_buffer,
|
||||||
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
size_t in_size, const void** batch_address) {
|
||||||
return ORBIS_OK;
|
// TODO
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmBatchJobRunBufferRa() {
|
auto ParseWavHeader = [](void* buf, WavHeader* header) {
|
||||||
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
if (!buf) {
|
||||||
return ORBIS_OK;
|
// buf is passed as nullptr in some cases (i.e. GetCodecInfo)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::memcpy(header, buf, sizeof(WavHeader));
|
||||||
|
|
||||||
|
std::string riff(header->RIFF, 4);
|
||||||
|
std::string wave(header->WAVE, 4);
|
||||||
|
std::string fmt(header->fmt, 4);
|
||||||
|
std::string dataID(header->Subchunk2ID, 4);
|
||||||
|
|
||||||
|
if (std::memcmp(header->RIFF, "RIFF", 4) != 0 || std::memcmp(header->WAVE, "WAVE", 4) != 0 ||
|
||||||
|
std::memcmp(header->fmt, "fmt ", 4) != 0 ||
|
||||||
|
std::memcmp(header->Subchunk2ID, "data", 4) != 0) {
|
||||||
|
LOG_ERROR(Lib_Ajm, "Invalid WAV file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(Lib_Ajm, "RIFF header: {}", riff);
|
||||||
|
LOG_INFO(Lib_Ajm, "WAVE header: {}", wave);
|
||||||
|
LOG_INFO(Lib_Ajm, "FMT: {}", fmt);
|
||||||
|
LOG_INFO(Lib_Ajm, "Data size: {}", header->ChunkSize);
|
||||||
|
LOG_INFO(Lib_Ajm, "Sampling Rate: {}", header->SamplesPerSec);
|
||||||
|
LOG_INFO(Lib_Ajm, "Number of bits used: {}", header->bitsPerSample);
|
||||||
|
LOG_INFO(Lib_Ajm, "Number of channels: {}", header->NumOfChan);
|
||||||
|
LOG_INFO(Lib_Ajm, "Number of bytes per second: {}", header->bytesPerSec);
|
||||||
|
LOG_INFO(Lib_Ajm, "Data length: {}", header->Subchunk2Size);
|
||||||
|
LOG_INFO(Lib_Ajm, "Audio Format: {}", header->AudioFormat);
|
||||||
|
LOG_INFO(Lib_Ajm, "Block align: {}", header->blockAlign);
|
||||||
|
LOG_INFO(Lib_Ajm, "Data string: {}", dataID);
|
||||||
|
};
|
||||||
|
|
||||||
|
void* PS4_SYSV_ABI sceAjmBatchJobRunBufferRa(AjmSingleJob* batch_pos, u32 instance, AjmFlags flags,
|
||||||
|
void* in_buffer, u32 in_size, u8* out_buffer,
|
||||||
|
const u32 out_size, u8* sideband_output,
|
||||||
|
const u32 sideband_output_size, const void* ret_addr) {
|
||||||
|
WavHeader header{};
|
||||||
|
ParseWavHeader(in_buffer, &header);
|
||||||
|
LOG_INFO(Lib_Ajm,
|
||||||
|
"called instance = {:#x}, flags = {:#x}, cmd = {}, in_size = {:#x}, out_size = {:#x}, "
|
||||||
|
"ret_addr = {}",
|
||||||
|
instance, flags.raw, magic_enum::enum_name(AjmJobRunFlags(flags.command)), in_size,
|
||||||
|
out_size, fmt::ptr(ret_addr));
|
||||||
|
|
||||||
|
const u64 mask = 0xE00000001FFFLL;
|
||||||
|
flags.raw &= mask;
|
||||||
|
|
||||||
|
const bool is_debug = ret_addr != nullptr;
|
||||||
|
batch_pos->opcode.instance = instance;
|
||||||
|
batch_pos->opcode.codec_flags = flags.codec;
|
||||||
|
batch_pos->opcode.command_flags = flags.command;
|
||||||
|
batch_pos->opcode.sideband_flags = AjmJobSidebandFlags(flags.sideband);
|
||||||
|
batch_pos->opcode.is_debug = is_debug;
|
||||||
|
batch_pos->opcode.is_statistic = false;
|
||||||
|
batch_pos->opcode.is_control = false;
|
||||||
|
|
||||||
|
AjmInOutJob* job = nullptr;
|
||||||
|
if (ret_addr == nullptr) {
|
||||||
|
batch_pos->job_size = sizeof(AjmInOutJob) + 16;
|
||||||
|
job = &batch_pos->job;
|
||||||
|
} else {
|
||||||
|
batch_pos->job_size = sizeof(AjmInOutJob) + 32;
|
||||||
|
batch_pos->ret.unk1 = batch_pos->ret.unk1 & 0xfffffff0 | 6;
|
||||||
|
job = &batch_pos->ret.job;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: add some missing stuff
|
||||||
|
job->input.buf_size = in_size;
|
||||||
|
job->input.buffer = static_cast<u8*>(in_buffer);
|
||||||
|
job->flags = u32(flags.raw);
|
||||||
|
job->unk1 = (job->unk1 & 0xfc000030) + (flags.raw >> 0x1a) + 4;
|
||||||
|
job->output.buf_size = out_size;
|
||||||
|
job->output.buffer = out_buffer;
|
||||||
|
job->output.props &= 0xffffffe0;
|
||||||
|
job->output.props |= 0x12;
|
||||||
|
*reinterpret_cast<u8**>(reinterpret_cast<u8*>(job) + 32) = sideband_output;
|
||||||
|
return job;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmBatchJobRunSplitBufferRa() {
|
void* PS4_SYSV_ABI sceAjmBatchJobRunSplitBufferRa(AjmMultiJob* batch_pos, u32 instance,
|
||||||
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
AjmFlags flags, const AjmBuffer* in_buffers,
|
||||||
return ORBIS_OK;
|
u64 num_in_buffers, const AjmBuffer* out_buffers,
|
||||||
|
u64 num_out_buffers, void* sideband_output,
|
||||||
|
u64 sideband_output_size, const void* ret_addr) {
|
||||||
|
LOG_DEBUG(Lib_Ajm,
|
||||||
|
"called instance = {}, flags = {:#x}, cmd = {}, sideband_cmd = {} num_input_buffers "
|
||||||
|
"= {}, num_output_buffers = {}, "
|
||||||
|
"ret_addr = {}",
|
||||||
|
instance, flags.raw, magic_enum::enum_name(AjmJobRunFlags(flags.command)),
|
||||||
|
magic_enum::enum_name(AjmJobSidebandFlags(flags.sideband)), num_in_buffers,
|
||||||
|
num_out_buffers, fmt::ptr(ret_addr));
|
||||||
|
const u32 job_size = (num_in_buffers * 2 + 1 + num_out_buffers * 2) * 8;
|
||||||
|
const bool is_debug = ret_addr != nullptr;
|
||||||
|
batch_pos->opcode.instance = instance;
|
||||||
|
batch_pos->opcode.codec_flags = flags.codec;
|
||||||
|
batch_pos->opcode.command_flags = flags.command;
|
||||||
|
batch_pos->opcode.sideband_flags = AjmJobSidebandFlags(flags.sideband);
|
||||||
|
batch_pos->opcode.is_debug = is_debug;
|
||||||
|
batch_pos->opcode.is_statistic = false;
|
||||||
|
batch_pos->opcode.is_control = false;
|
||||||
|
|
||||||
|
u32* job = nullptr;
|
||||||
|
if (!is_debug) {
|
||||||
|
batch_pos->job_size = job_size + 16;
|
||||||
|
job = batch_pos->job;
|
||||||
|
} else {
|
||||||
|
batch_pos->job_size = job_size + 32;
|
||||||
|
batch_pos->ret.unk1 &= 0xfffffff0;
|
||||||
|
batch_pos->ret.unk1 |= 6;
|
||||||
|
batch_pos->ret.unk2 = 0;
|
||||||
|
batch_pos->ret.ret_addr = ret_addr;
|
||||||
|
job = batch_pos->ret.job;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s32 i = 0; i < num_in_buffers; i++) {
|
||||||
|
AjmJobBuffer* in_buf = reinterpret_cast<AjmJobBuffer*>(job);
|
||||||
|
in_buf->props &= 0xffffffe0;
|
||||||
|
in_buf->props |= 1;
|
||||||
|
in_buf->buf_size = in_buffers[i].size;
|
||||||
|
in_buf->buffer = in_buffers[i].addr;
|
||||||
|
job += 4;
|
||||||
|
}
|
||||||
|
job[1] = u32(flags.raw & 0xe00000001fffULL);
|
||||||
|
job[0] &= 0xfc000030;
|
||||||
|
job[0] = s32((flags.raw & 0xe00000001fffULL) >> 0x1a) + 4;
|
||||||
|
job += 2;
|
||||||
|
|
||||||
|
for (s32 i = 0; i < num_out_buffers; i++) {
|
||||||
|
AjmJobBuffer* out_buf = reinterpret_cast<AjmJobBuffer*>(job);
|
||||||
|
out_buf->props &= 0xffffffe0;
|
||||||
|
out_buf->props |= 0x11;
|
||||||
|
out_buf->buf_size = out_buffers[i].size;
|
||||||
|
out_buf->buffer = out_buffers[i].addr;
|
||||||
|
job += 4;
|
||||||
|
}
|
||||||
|
job[0] = job[0] & 0xffffffe0 | 0x12; // output.props
|
||||||
|
job[1] = sideband_output_size; // output.buf_size
|
||||||
|
memcpy(&job[2], &sideband_output, sizeof(void*)); // output.buffer
|
||||||
|
return job + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmBatchStartBuffer() {
|
int PS4_SYSV_ABI sceAjmBatchStartBuffer(u32 context, const u8* batch, u32 batch_size,
|
||||||
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
const int priority, AjmBatchError* batch_error,
|
||||||
|
u32* out_batch_id) {
|
||||||
|
LOG_DEBUG(Lib_Ajm, "called context = {}, batch_size = {:#x}, priority = {}", context,
|
||||||
|
batch_size, priority);
|
||||||
|
|
||||||
|
if ((batch_size & 7) != 0) {
|
||||||
|
return ORBIS_AJM_ERROR_MALFORMED_BATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr u32 MaxBatches = 1000;
|
||||||
|
|
||||||
|
struct BatchInfo {
|
||||||
|
u16 instance;
|
||||||
|
u16 offset_in_qwords;
|
||||||
|
};
|
||||||
|
std::array<BatchInfo, MaxBatches> batches{};
|
||||||
|
u32 num_batches = 0;
|
||||||
|
|
||||||
|
const u8* batch_ptr = batch;
|
||||||
|
const u8* batch_end = batch + batch_size;
|
||||||
|
while (batch_ptr < batch_end) {
|
||||||
|
if (num_batches >= MaxBatches) {
|
||||||
|
LOG_ERROR(Lib_Ajm, "Too many batches in job!");
|
||||||
|
return ORBIS_AJM_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
AjmJobHeader header;
|
||||||
|
std::memcpy(&header, batch_ptr, sizeof(u64));
|
||||||
|
|
||||||
|
const auto& opcode = header.opcode;
|
||||||
|
const u32 instance = opcode.instance;
|
||||||
|
const u8* job_ptr = batch_ptr + sizeof(AjmJobHeader) + opcode.is_debug * 16;
|
||||||
|
|
||||||
|
if (opcode.is_control) {
|
||||||
|
// ASSERT_MSG(!opcode.is_statistic, "Statistic instance is not handled");
|
||||||
|
const auto command = AjmJobControlFlags(opcode.command_flags);
|
||||||
|
switch (command) {
|
||||||
|
case AjmJobControlFlags::Reset: {
|
||||||
|
LOG_INFO(Lib_Ajm, "Resetting instance {}", opcode.instance);
|
||||||
|
dev->instances[opcode.instance]->Reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (AjmJobControlFlags::Initialize | AjmJobControlFlags::Reset):
|
||||||
|
LOG_INFO(Lib_Ajm, "Initializing instance {}", opcode.instance);
|
||||||
|
break;
|
||||||
|
case AjmJobControlFlags::Resample:
|
||||||
|
LOG_INFO(Lib_Ajm, "Set resample params of instance {}", opcode.instance);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write sideband structures.
|
||||||
|
const AjmJobBuffer* out_buffer = reinterpret_cast<const AjmJobBuffer*>(job_ptr + 24);
|
||||||
|
auto* result = reinterpret_cast<AjmSidebandResult*>(out_buffer->buffer);
|
||||||
|
result->result = 0;
|
||||||
|
result->internal_result = 0;
|
||||||
|
} else {
|
||||||
|
const auto command = AjmJobRunFlags(opcode.command_flags);
|
||||||
|
const auto sideband = AjmJobSidebandFlags(opcode.sideband_flags);
|
||||||
|
const AjmJobBuffer* in_buffer = reinterpret_cast<const AjmJobBuffer*>(job_ptr);
|
||||||
|
const AjmJobBuffer* out_buffer = reinterpret_cast<const AjmJobBuffer*>(job_ptr + 24);
|
||||||
|
job_ptr += 24;
|
||||||
|
|
||||||
|
LOG_INFO(Lib_Ajm, "Decode job cmd = {}, sideband = {}, in_addr = {}, in_size = {}",
|
||||||
|
magic_enum::enum_name(command), magic_enum::enum_name(sideband),
|
||||||
|
fmt::ptr(in_buffer->buffer), in_buffer->buf_size);
|
||||||
|
|
||||||
|
// Decode as much of the input bitstream as possible.
|
||||||
|
AjmAt9Decoder* decoder_instance = dev->instances[opcode.instance].get();
|
||||||
|
const auto [in_remain, out_remain, num_frames] = decoder_instance->Decode(
|
||||||
|
in_buffer->buffer, in_buffer->buf_size, out_buffer->buffer, out_buffer->buf_size);
|
||||||
|
|
||||||
|
// Write sideband structures.
|
||||||
|
auto* sideband_ptr = *reinterpret_cast<u8* const*>(job_ptr + 8);
|
||||||
|
auto* result = reinterpret_cast<AjmSidebandResult*>(sideband_ptr);
|
||||||
|
result->result = 0;
|
||||||
|
result->internal_result = 0;
|
||||||
|
sideband_ptr += sizeof(AjmSidebandResult);
|
||||||
|
|
||||||
|
// Check sideband flags
|
||||||
|
if (True(sideband & AjmJobSidebandFlags::Stream)) {
|
||||||
|
auto* stream = reinterpret_cast<AjmSidebandStream*>(sideband_ptr);
|
||||||
|
stream->input_consumed = in_buffer->buf_size - in_remain;
|
||||||
|
stream->output_written = out_buffer->buf_size - out_remain;
|
||||||
|
stream->total_decoded_samples = decoder_instance->decoded_samples;
|
||||||
|
sideband_ptr += sizeof(AjmSidebandStream);
|
||||||
|
}
|
||||||
|
if (True(command & AjmJobRunFlags::MultipleFrames)) {
|
||||||
|
auto* mframe = reinterpret_cast<AjmSidebandMFrame*>(sideband_ptr);
|
||||||
|
mframe->num_frames = num_frames;
|
||||||
|
sideband_ptr += sizeof(AjmSidebandMFrame);
|
||||||
|
}
|
||||||
|
if (True(command & AjmJobRunFlags::GetCodecInfo)) {
|
||||||
|
LOG_TRACE(Lib_Ajm, "GetCodecInfo called, supplying dummy info for now");
|
||||||
|
auto* codec_info = reinterpret_cast<SceAjmSidebandDecAt9CodecInfo*>(sideband_ptr);
|
||||||
|
codec_info->uiFrameSamples = 0;
|
||||||
|
codec_info->uiFramesInSuperFrame = 0;
|
||||||
|
codec_info->uiNextFrameSize = 0;
|
||||||
|
codec_info->uiSuperFrameSize = 0;
|
||||||
|
sideband_ptr += sizeof(SceAjmSidebandDecAt9CodecInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
batch_ptr += sizeof(AjmJobHeader) + header.job_size;
|
||||||
|
}
|
||||||
|
static int batch_id = 0;
|
||||||
|
*out_batch_id = ++batch_id;
|
||||||
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,9 +385,16 @@ int PS4_SYSV_ABI sceAjmDecAt9ParseConfigData() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmDecMp3ParseFrame() {
|
int PS4_SYSV_ABI sceAjmDecMp3ParseFrame(const u8* buf, u32 stream_size, int parse_ofl,
|
||||||
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
AjmDecMp3ParseFrame* frame) {
|
||||||
return ORBIS_OK;
|
LOG_INFO(Lib_Ajm, "called parse_ofl = {}", parse_ofl);
|
||||||
|
if (buf == nullptr || stream_size < 4 || frame == nullptr) {
|
||||||
|
return ORBIS_AJM_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
if ((buf[0] & SYNCWORDH) != SYNCWORDH || (buf[1] & SYNCWORDL) != SYNCWORDL) {
|
||||||
|
return ORBIS_AJM_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
return AjmMp3Decoder::ParseMp3Header(buf, stream_size, parse_ofl, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmFinalize() {
|
int PS4_SYSV_ABI sceAjmFinalize() {
|
||||||
@ -65,8 +402,13 @@ int PS4_SYSV_ABI sceAjmFinalize() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmInitialize() {
|
int PS4_SYSV_ABI sceAjmInitialize(s64 reserved, u32* out_context) {
|
||||||
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
LOG_INFO(Lib_Ajm, "called reserved = {}", reserved);
|
||||||
|
if (out_context == nullptr || reserved != 0) {
|
||||||
|
return ORBIS_AJM_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
*out_context = 1;
|
||||||
|
dev = std::make_unique<AjmDevice>();
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,13 +417,55 @@ int PS4_SYSV_ABI sceAjmInstanceCodecType() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmInstanceCreate() {
|
int PS4_SYSV_ABI sceAjmInstanceCreate(u32 context, AjmCodecType codec_type, AjmInstanceFlags flags,
|
||||||
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
u32* out_instance) {
|
||||||
|
if (codec_type >= AjmCodecType::Max) {
|
||||||
|
return ORBIS_AJM_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
if (flags.version == 0) {
|
||||||
|
return ORBIS_AJM_ERROR_WRONG_REVISION_FLAG;
|
||||||
|
}
|
||||||
|
if (!dev->IsRegistered(codec_type)) {
|
||||||
|
return ORBIS_AJM_ERROR_CODEC_NOT_REGISTERED;
|
||||||
|
}
|
||||||
|
if (dev->curr_cursor == dev->release_cursor) {
|
||||||
|
return ORBIS_AJM_ERROR_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
const u32 index = dev->free_instances[dev->curr_cursor++];
|
||||||
|
dev->curr_cursor %= MaxInstances;
|
||||||
|
std::unique_ptr<AjmAt9Decoder> instance;
|
||||||
|
switch (codec_type) {
|
||||||
|
case AjmCodecType::Mp3Dec:
|
||||||
|
instance = std::make_unique<AjmAt9Decoder>();
|
||||||
|
break;
|
||||||
|
case AjmCodecType::At9Dec:
|
||||||
|
instance = std::make_unique<AjmAt9Decoder>();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
instance->index = index;
|
||||||
|
instance->codec_type = codec_type;
|
||||||
|
instance->num_channels = flags.channels;
|
||||||
|
dev->instances[index] = std::move(instance);
|
||||||
|
*out_instance = index;
|
||||||
|
LOG_INFO(Lib_Ajm, "called codec_type = {}, flags = {:#x}, instance = {}",
|
||||||
|
magic_enum::enum_name(codec_type), flags.raw, index);
|
||||||
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmInstanceDestroy() {
|
int PS4_SYSV_ABI sceAjmInstanceDestroy(u32 context, u32 instance) {
|
||||||
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
LOG_INFO(Lib_Ajm, "called context = {}, instance = {}", context, instance);
|
||||||
|
if ((instance & 0x3fff) > MaxInstances) {
|
||||||
|
return ORBIS_AJM_ERROR_INVALID_INSTANCE;
|
||||||
|
}
|
||||||
|
const u32 next_slot = (dev->release_cursor + 1) % MaxInstances;
|
||||||
|
if (next_slot != dev->curr_cursor) {
|
||||||
|
dev->free_instances[dev->release_cursor] = instance;
|
||||||
|
dev->release_cursor = next_slot;
|
||||||
|
}
|
||||||
|
dev->instances[instance].reset();
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,8 +489,16 @@ int PS4_SYSV_ABI sceAjmMemoryUnregister() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmModuleRegister() {
|
int PS4_SYSV_ABI sceAjmModuleRegister(u32 context, AjmCodecType codec_type, s64 reserved) {
|
||||||
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
|
LOG_INFO(Lib_Ajm, "called context = {}, codec_type = {}, reserved = {}", context,
|
||||||
|
u32(codec_type), reserved);
|
||||||
|
if (codec_type >= AjmCodecType::Max || reserved != 0) {
|
||||||
|
return ORBIS_AJM_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
if (dev->IsRegistered(codec_type)) {
|
||||||
|
return ORBIS_AJM_ERROR_CODEC_ALREADY_REGISTERED;
|
||||||
|
}
|
||||||
|
dev->Register(codec_type);
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/enum.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
@ -11,26 +12,170 @@ class SymbolsResolver;
|
|||||||
|
|
||||||
namespace Libraries::Ajm {
|
namespace Libraries::Ajm {
|
||||||
|
|
||||||
|
struct AjmBatchInfo {
|
||||||
|
void* pBuffer;
|
||||||
|
u64 offset;
|
||||||
|
u64 size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmBatchError {
|
||||||
|
int error_code;
|
||||||
|
const void* job_addr;
|
||||||
|
u32 cmd_offset;
|
||||||
|
const void* job_ra;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmBuffer {
|
||||||
|
u8* addr;
|
||||||
|
u64 size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmJobBuffer {
|
||||||
|
u32 props;
|
||||||
|
u32 buf_size;
|
||||||
|
u8* buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmInOutJob {
|
||||||
|
AjmJobBuffer input;
|
||||||
|
u32 unk1;
|
||||||
|
u32 flags;
|
||||||
|
AjmJobBuffer output;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class AjmJobControlFlags : u32 {
|
||||||
|
Reset = 1 << 2,
|
||||||
|
Initialize = 1 << 3,
|
||||||
|
Resample = 1 << 4,
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_FLAG_OPERATORS(AjmJobControlFlags)
|
||||||
|
|
||||||
|
enum class AjmJobRunFlags : u32 {
|
||||||
|
GetCodecInfo = 1 << 0,
|
||||||
|
MultipleFrames = 1 << 1,
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_FLAG_OPERATORS(AjmJobRunFlags)
|
||||||
|
|
||||||
|
enum class AjmJobSidebandFlags : u32 {
|
||||||
|
GaplessDecode = 1 << 0,
|
||||||
|
GetInfo = 1 << 1,
|
||||||
|
Stream = 1 << 2,
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_FLAG_OPERATORS(AjmJobSidebandFlags)
|
||||||
|
|
||||||
|
struct AjmHLEOpcode {
|
||||||
|
u32 instance : 14;
|
||||||
|
u32 codec_flags : 8;
|
||||||
|
u32 command_flags : 4;
|
||||||
|
AjmJobSidebandFlags sideband_flags : 3;
|
||||||
|
u32 is_statistic : 1;
|
||||||
|
u32 is_debug : 1;
|
||||||
|
u32 is_control : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmJobHeader {
|
||||||
|
AjmHLEOpcode opcode;
|
||||||
|
u32 job_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmSingleJob {
|
||||||
|
AjmHLEOpcode opcode;
|
||||||
|
u32 job_size;
|
||||||
|
union {
|
||||||
|
AjmInOutJob job;
|
||||||
|
struct {
|
||||||
|
u32 unk1;
|
||||||
|
u32 unk2;
|
||||||
|
const void* ret_addr;
|
||||||
|
AjmInOutJob job;
|
||||||
|
} ret;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(AjmSingleJob) == 0x40);
|
||||||
|
|
||||||
|
struct AjmMultiJob {
|
||||||
|
AjmHLEOpcode opcode;
|
||||||
|
u32 job_size;
|
||||||
|
union {
|
||||||
|
u32 job[];
|
||||||
|
struct {
|
||||||
|
u32 unk1;
|
||||||
|
u32 unk2;
|
||||||
|
const void* ret_addr;
|
||||||
|
u32 job[];
|
||||||
|
} ret;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
union AjmFlags {
|
||||||
|
u64 raw;
|
||||||
|
struct {
|
||||||
|
u64 version : 3;
|
||||||
|
u64 codec : 8;
|
||||||
|
u64 command : 4;
|
||||||
|
u64 reserved : 30;
|
||||||
|
u64 sideband : 3;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
union AjmInstanceFlags {
|
||||||
|
u64 raw;
|
||||||
|
struct {
|
||||||
|
u64 version : 3;
|
||||||
|
u64 channels : 4;
|
||||||
|
u64 format : 3;
|
||||||
|
u64 pad : 22;
|
||||||
|
u64 codec : 28;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceAjmSidebandDecAt9CodecInfo {
|
||||||
|
u32 uiSuperFrameSize;
|
||||||
|
u32 uiFramesInSuperFrame;
|
||||||
|
u32 uiNextFrameSize;
|
||||||
|
u32 uiFrameSamples;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmDecMp3ParseFrame;
|
||||||
|
enum class AjmCodecType : u32;
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceAjmBatchCancel();
|
int PS4_SYSV_ABI sceAjmBatchCancel();
|
||||||
int PS4_SYSV_ABI sceAjmBatchErrorDump();
|
int PS4_SYSV_ABI sceAjmBatchErrorDump();
|
||||||
int PS4_SYSV_ABI sceAjmBatchJobControlBufferRa();
|
void* PS4_SYSV_ABI sceAjmBatchJobControlBufferRa(AjmSingleJob* batch_pos, u32 instance,
|
||||||
int PS4_SYSV_ABI sceAjmBatchJobInlineBuffer();
|
AjmFlags flags, u8* in_buffer, u32 in_size,
|
||||||
int PS4_SYSV_ABI sceAjmBatchJobRunBufferRa();
|
u8* out_buffer, u32 out_size,
|
||||||
int PS4_SYSV_ABI sceAjmBatchJobRunSplitBufferRa();
|
const void* ret_addr);
|
||||||
int PS4_SYSV_ABI sceAjmBatchStartBuffer();
|
void* PS4_SYSV_ABI sceAjmBatchJobInlineBuffer(AjmSingleJob* batch_pos, const void* in_buffer,
|
||||||
|
size_t in_size, const void** batch_address);
|
||||||
|
void* PS4_SYSV_ABI sceAjmBatchJobRunBufferRa(AjmSingleJob* batch_pos, u32 instance, AjmFlags flags,
|
||||||
|
void * in_buffer, u32 in_size, u8* out_buffer,
|
||||||
|
const u32 out_size, u8* sideband_output,
|
||||||
|
const u32 sideband_output_size, const void* ret_addr);
|
||||||
|
void* PS4_SYSV_ABI sceAjmBatchJobRunSplitBufferRa(AjmMultiJob* batch_pos, u32 instance,
|
||||||
|
AjmFlags flags, const AjmBuffer* input_buffers,
|
||||||
|
u64 num_input_buffers,
|
||||||
|
const AjmBuffer* output_buffers,
|
||||||
|
u64 num_output_buffers, void* sideband_output,
|
||||||
|
u64 sideband_output_size, const void* ret_addr);
|
||||||
|
int PS4_SYSV_ABI sceAjmBatchStartBuffer(u32 context, const u8* batch, u32 batch_size,
|
||||||
|
const int priority, AjmBatchError* patch_error,
|
||||||
|
u32* out_batch_id);
|
||||||
int PS4_SYSV_ABI sceAjmBatchWait();
|
int PS4_SYSV_ABI sceAjmBatchWait();
|
||||||
int PS4_SYSV_ABI sceAjmDecAt9ParseConfigData();
|
int PS4_SYSV_ABI sceAjmDecAt9ParseConfigData();
|
||||||
int PS4_SYSV_ABI sceAjmDecMp3ParseFrame();
|
int PS4_SYSV_ABI sceAjmDecMp3ParseFrame(const u8* stream, u32 stream_size, int parse_ofl,
|
||||||
|
AjmDecMp3ParseFrame* frame);
|
||||||
int PS4_SYSV_ABI sceAjmFinalize();
|
int PS4_SYSV_ABI sceAjmFinalize();
|
||||||
int PS4_SYSV_ABI sceAjmInitialize();
|
int PS4_SYSV_ABI sceAjmInitialize(s64 reserved, u32* out_context);
|
||||||
int PS4_SYSV_ABI sceAjmInstanceCodecType();
|
int PS4_SYSV_ABI sceAjmInstanceCodecType();
|
||||||
int PS4_SYSV_ABI sceAjmInstanceCreate();
|
int PS4_SYSV_ABI sceAjmInstanceCreate(u32 context, AjmCodecType codec_type, AjmInstanceFlags flags,
|
||||||
int PS4_SYSV_ABI sceAjmInstanceDestroy();
|
u32* instance);
|
||||||
|
int PS4_SYSV_ABI sceAjmInstanceDestroy(u32 context, u32 instance);
|
||||||
int PS4_SYSV_ABI sceAjmInstanceExtend();
|
int PS4_SYSV_ABI sceAjmInstanceExtend();
|
||||||
int PS4_SYSV_ABI sceAjmInstanceSwitch();
|
int PS4_SYSV_ABI sceAjmInstanceSwitch();
|
||||||
int PS4_SYSV_ABI sceAjmMemoryRegister();
|
int PS4_SYSV_ABI sceAjmMemoryRegister();
|
||||||
int PS4_SYSV_ABI sceAjmMemoryUnregister();
|
int PS4_SYSV_ABI sceAjmMemoryUnregister();
|
||||||
int PS4_SYSV_ABI sceAjmModuleRegister();
|
int PS4_SYSV_ABI sceAjmModuleRegister(u32 context, AjmCodecType codec_type, s64 reserved);
|
||||||
int PS4_SYSV_ABI sceAjmModuleUnregister();
|
int PS4_SYSV_ABI sceAjmModuleUnregister();
|
||||||
int PS4_SYSV_ABI sceAjmStrError();
|
int PS4_SYSV_ABI sceAjmStrError();
|
||||||
|
|
||||||
|
58
src/core/libraries/ajm/ajm_at9.cpp
Normal file
58
src/core/libraries/ajm/ajm_at9.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "core/libraries/ajm/ajm_at9.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libatrac9.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Libraries::Ajm {
|
||||||
|
|
||||||
|
AjmAt9Decoder::AjmAt9Decoder() {
|
||||||
|
handle = Atrac9GetHandle();
|
||||||
|
ASSERT_MSG(handle, "Atrac9GetHandle failed");
|
||||||
|
AjmAt9Decoder::Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
AjmAt9Decoder::~AjmAt9Decoder() {}
|
||||||
|
|
||||||
|
void AjmAt9Decoder::Reset() {
|
||||||
|
decoded_samples = 0;
|
||||||
|
static int filename = 0;
|
||||||
|
file.close();
|
||||||
|
file.open(fmt::format("inst{}_{}.raw", index, ++filename), std::ios::out | std::ios::binary);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<u32, u32, u32> AjmAt9Decoder::Decode(const u8* in_buf, u32 in_size, u8* out_buf,
|
||||||
|
u32 out_size) {
|
||||||
|
auto ParseWavHeader = [](const uint8_t* buf, WavHeader* header) {
|
||||||
|
std::memcpy(header, buf, sizeof(WavHeader));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (in_size <= 0 || out_size <= 0) {
|
||||||
|
return std::tuple(in_size, out_size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
WavHeader header{};
|
||||||
|
ParseWavHeader(in_buf - 0x64, &header);
|
||||||
|
|
||||||
|
if (!decoder_initialized) {
|
||||||
|
Atrac9InitDecoder(handle, header.configData);
|
||||||
|
decoder_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: do something with decoded data :p
|
||||||
|
|
||||||
|
int bytes_used;
|
||||||
|
Atrac9Decode(handle, in_buf, nullptr, &bytes_used);
|
||||||
|
|
||||||
|
Atrac9CodecInfo codec_info;
|
||||||
|
Atrac9GetCodecInfo(handle, &codec_info);
|
||||||
|
|
||||||
|
return std::tuple(in_size, out_size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Libraries::Ajm
|
65
src/core/libraries/ajm/ajm_at9.h
Normal file
65
src/core/libraries/ajm/ajm_at9.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <guiddef.h>
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "core/libraries/ajm/ajm_instance.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <structures.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Libraries::Ajm {
|
||||||
|
|
||||||
|
constexpr unsigned int SCE_AT9_CONFIG_DATA_SIZE = 4;
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct WavHeader {
|
||||||
|
/* RIFF Chunk Descriptor */
|
||||||
|
char RIFF[4]; // RIFF Header Magic header
|
||||||
|
uint32_t ChunkSize; // RIFF Chunk Size
|
||||||
|
char WAVE[4]; // WAVE Header
|
||||||
|
/* "fmt" sub-chunk */
|
||||||
|
char fmt[4]; // FMT header
|
||||||
|
uint32_t Subchunk1Size; // Size of the fmt chunk
|
||||||
|
uint16_t AudioFormat; // Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law,
|
||||||
|
// 259=ADPCM
|
||||||
|
uint16_t NumOfChan; // Number of channels 1=Mono 2=Sterio
|
||||||
|
uint32_t SamplesPerSec; // Sampling Frequency in Hz
|
||||||
|
uint32_t bytesPerSec; // bytes per second
|
||||||
|
uint16_t blockAlign; // 2=16-bit mono, 4=16-bit stereo
|
||||||
|
uint16_t bitsPerSample; // Number of bits per sample
|
||||||
|
u16 cbSize; // Extension size
|
||||||
|
u16 samplesPerBlock;
|
||||||
|
u32 channelMask;
|
||||||
|
GUID subFormat;
|
||||||
|
u32 versionInfo;
|
||||||
|
u8 configData[SCE_AT9_CONFIG_DATA_SIZE]; // the juicy part
|
||||||
|
u32 reserved;
|
||||||
|
/* "fact" sub-chunk */
|
||||||
|
char Subchunk2ID[4]; // "fact" string
|
||||||
|
uint32_t Subchunk2Size; // Sampled data length
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
static_assert(sizeof(WavHeader) == 80);
|
||||||
|
|
||||||
|
struct AjmAt9Decoder final : AjmInstance {
|
||||||
|
void* handle;
|
||||||
|
bool decoder_initialized = false;
|
||||||
|
std::fstream file;
|
||||||
|
int length;
|
||||||
|
|
||||||
|
explicit AjmAt9Decoder();
|
||||||
|
~AjmAt9Decoder() override;
|
||||||
|
|
||||||
|
void Reset() override;
|
||||||
|
|
||||||
|
std::tuple<u32, u32, u32> Decode(const u8* in_buf, u32 in_size, u8* out_buf,
|
||||||
|
u32 out_size) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::Ajm
|
71
src/core/libraries/ajm/ajm_instance.h
Normal file
71
src/core/libraries/ajm/ajm_instance.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
struct AVCodec;
|
||||||
|
struct AVCodecContext;
|
||||||
|
struct AVCodecParserContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Libraries::Ajm {
|
||||||
|
|
||||||
|
enum class AjmCodecType : u32 {
|
||||||
|
Mp3Dec = 0,
|
||||||
|
At9Dec = 1,
|
||||||
|
M4aacDec = 2,
|
||||||
|
Max = 23,
|
||||||
|
};
|
||||||
|
static constexpr u32 NumAjmCodecs = u32(AjmCodecType::Max);
|
||||||
|
|
||||||
|
enum class AjmFormatEncoding : u32 {
|
||||||
|
S16 = 0,
|
||||||
|
S32 = 1,
|
||||||
|
Float = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmSidebandResult {
|
||||||
|
s32 result;
|
||||||
|
s32 internal_result;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmSidebandMFrame {
|
||||||
|
u32 num_frames;
|
||||||
|
u32 reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmSidebandStream {
|
||||||
|
s32 input_consumed;
|
||||||
|
s32 output_written;
|
||||||
|
u64 total_decoded_samples;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmSidebandFormat {
|
||||||
|
u32 num_channels;
|
||||||
|
u32 channel_mask;
|
||||||
|
u32 sampl_freq;
|
||||||
|
AjmFormatEncoding sample_encoding;
|
||||||
|
u32 bitrate;
|
||||||
|
u32 reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmInstance {
|
||||||
|
AjmCodecType codec_type;
|
||||||
|
u32 decoded_samples{};
|
||||||
|
AjmFormatEncoding fmt{};
|
||||||
|
u32 num_channels{};
|
||||||
|
u32 index{};
|
||||||
|
|
||||||
|
explicit AjmInstance() = default;
|
||||||
|
virtual ~AjmInstance() = default;
|
||||||
|
|
||||||
|
virtual void Reset() = 0;
|
||||||
|
|
||||||
|
virtual std::tuple<u32, u32, u32> Decode(const u8* in_buf, u32 in_size,
|
||||||
|
u8* out_buf, u32 out_size) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::Ajm
|
149
src/core/libraries/ajm/ajm_mp3.cpp
Normal file
149
src/core/libraries/ajm/ajm_mp3.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma clang optimize off
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "core/libraries/ajm/ajm_mp3.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
#include <libswresample/swresample.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Libraries::Ajm {
|
||||||
|
|
||||||
|
// Following tables have been reversed from AJM library
|
||||||
|
static constexpr std::array<std::array<s32, 3>, 3> SamplerateTable = {{
|
||||||
|
{0x5622, 0x5DC0, 0x3E80}, {0xAC44, 0xBB80, 0x7D00}, {0x2B11, 0x2EE0, 0x1F40},
|
||||||
|
}};
|
||||||
|
|
||||||
|
static constexpr std::array<std::array<s32, 15>, 2> BitrateTable = {{
|
||||||
|
{0, 0x20, 0x28, 0x30, 0x38, 0x40, 0x50, 0x60, 0x70, 0x80, 0xA0, 0xC0, 0xE0, 0x100, 0x140},
|
||||||
|
{0, 0x8, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0},
|
||||||
|
}};
|
||||||
|
|
||||||
|
static constexpr std::array<s32, 2> UnkTable = {0x48, 0x90};
|
||||||
|
|
||||||
|
SwrContext* swr_context{};
|
||||||
|
|
||||||
|
AVFrame* ConvertAudioFrame(AVFrame* frame) {
|
||||||
|
auto pcm16_frame = av_frame_clone(frame);
|
||||||
|
pcm16_frame->format = AV_SAMPLE_FMT_S16;
|
||||||
|
|
||||||
|
if (swr_context) {
|
||||||
|
swr_free(&swr_context);
|
||||||
|
swr_context = nullptr;
|
||||||
|
}
|
||||||
|
AVChannelLayout in_ch_layout = frame->ch_layout;
|
||||||
|
AVChannelLayout out_ch_layout = pcm16_frame->ch_layout;
|
||||||
|
swr_alloc_set_opts2(&swr_context, &out_ch_layout, AV_SAMPLE_FMT_S16, frame->sample_rate,
|
||||||
|
&in_ch_layout, AVSampleFormat(frame->format), frame->sample_rate, 0,
|
||||||
|
nullptr);
|
||||||
|
swr_init(swr_context);
|
||||||
|
const auto res = swr_convert_frame(swr_context, pcm16_frame, frame);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_ERROR(Lib_AvPlayer, "Could not convert to S16: {}", av_err2str(res));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
av_frame_free(&frame);
|
||||||
|
return pcm16_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
AjmMp3Decoder::AjmMp3Decoder() {
|
||||||
|
codec = avcodec_find_decoder(AV_CODEC_ID_MP3);
|
||||||
|
ASSERT_MSG(codec, "MP3 codec not found");
|
||||||
|
parser = av_parser_init(codec->id);
|
||||||
|
ASSERT_MSG(parser, "Parser not found");
|
||||||
|
AjmMp3Decoder::Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
AjmMp3Decoder::~AjmMp3Decoder() {
|
||||||
|
avcodec_free_context(&c);
|
||||||
|
av_free(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AjmMp3Decoder::Reset() {
|
||||||
|
if (c) {
|
||||||
|
avcodec_free_context(&c);
|
||||||
|
av_free(c);
|
||||||
|
}
|
||||||
|
c = avcodec_alloc_context3(codec);
|
||||||
|
ASSERT_MSG(c, "Could not allocate audio codec context");
|
||||||
|
int ret = avcodec_open2(c, codec, nullptr);
|
||||||
|
ASSERT_MSG(ret >= 0, "Could not open codec");
|
||||||
|
decoded_samples = 0;
|
||||||
|
static int filename = 0;
|
||||||
|
file.close();
|
||||||
|
file.open(fmt::format("inst{}_{}.raw", index, ++filename), std::ios::out | std::ios::binary);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<u32, u32, u32> AjmMp3Decoder::Decode(const u8* buf, u32 in_size,
|
||||||
|
u8* out_buf, u32 out_size) {
|
||||||
|
u32 num_frames = 0;
|
||||||
|
AVPacket* pkt = av_packet_alloc();
|
||||||
|
while (in_size > 0 && out_size > 0) {
|
||||||
|
int ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,
|
||||||
|
buf, in_size,
|
||||||
|
AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
|
||||||
|
ASSERT_MSG(ret >= 0, "Error while parsing {}", ret);
|
||||||
|
buf += ret;
|
||||||
|
in_size -= ret;
|
||||||
|
|
||||||
|
if (pkt->size) {
|
||||||
|
// Send the packet with the compressed data to the decoder
|
||||||
|
pkt->pts = parser->pts;
|
||||||
|
pkt->dts = parser->dts;
|
||||||
|
pkt->flags = (parser->key_frame == 1) ? AV_PKT_FLAG_KEY : 0;
|
||||||
|
ret = avcodec_send_packet(c, pkt);
|
||||||
|
ASSERT_MSG(ret >= 0, "Error submitting the packet to the decoder {}", ret);
|
||||||
|
|
||||||
|
// Read all the output frames (in general there may be any number of them
|
||||||
|
while (ret >= 0) {
|
||||||
|
AVFrame* frame = av_frame_alloc();
|
||||||
|
ret = avcodec_receive_frame(c, frame);
|
||||||
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||||
|
break;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
UNREACHABLE_MSG("Error during decoding");
|
||||||
|
}
|
||||||
|
if (frame->format != AV_SAMPLE_FMT_S16) {
|
||||||
|
frame = ConvertAudioFrame(frame);
|
||||||
|
}
|
||||||
|
const auto size = frame->ch_layout.nb_channels * frame->nb_samples * sizeof(u16);
|
||||||
|
std::memcpy(out_buf, frame->data[0], size);
|
||||||
|
file.write((const char*)frame->data[0], size);
|
||||||
|
out_buf += size;
|
||||||
|
out_size -= size;
|
||||||
|
decoded_samples += frame->nb_samples;
|
||||||
|
num_frames++;
|
||||||
|
av_frame_free(&frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
av_packet_free(&pkt);
|
||||||
|
return std::make_tuple(in_size, out_size, num_frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AjmMp3Decoder::ParseMp3Header(const u8* buf, u32 stream_size, int parse_ofl,
|
||||||
|
AjmDecMp3ParseFrame* frame) {
|
||||||
|
const u32 unk_idx = buf[1] >> 3 & 1;
|
||||||
|
const s32 version_idx = (buf[1] >> 3 & 3) ^ 2;
|
||||||
|
const s32 sr_idx = buf[2] >> 2 & 3;
|
||||||
|
const s32 br_idx = (buf[2] >> 4) & 0xf;
|
||||||
|
const s32 padding_bit = (buf[2] >> 1) & 0x1;
|
||||||
|
|
||||||
|
frame->sample_rate = SamplerateTable[version_idx][sr_idx];
|
||||||
|
frame->bitrate = BitrateTable[version_idx != 1][br_idx] * 1000;
|
||||||
|
frame->num_channels = (buf[3] < 0xc0) + 1;
|
||||||
|
frame->frame_size = (UnkTable[unk_idx] * frame->bitrate) / frame->sample_rate + padding_bit;
|
||||||
|
frame->samples_per_channel = UnkTable[unk_idx] * 8;
|
||||||
|
frame->encoder_delay = 0;
|
||||||
|
if (parse_ofl == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Libraries::Ajm
|
83
src/core/libraries/ajm/ajm_mp3.h
Normal file
83
src/core/libraries/ajm/ajm_mp3.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "core/libraries/ajm/ajm_instance.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
struct AVCodec;
|
||||||
|
struct AVCodecContext;
|
||||||
|
struct AVCodecParserContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Libraries::Ajm {
|
||||||
|
|
||||||
|
enum class AjmDecMp3OflType : u32 {
|
||||||
|
None = 0,
|
||||||
|
Lame = 1,
|
||||||
|
Vbri = 2,
|
||||||
|
Fgh = 3,
|
||||||
|
VbriAndFgh = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
// 11-bit syncword if MPEG 2.5 extensions are enabled
|
||||||
|
static constexpr u8 SYNCWORDH = 0xff;
|
||||||
|
static constexpr u8 SYNCWORDL = 0xe0;
|
||||||
|
|
||||||
|
struct AjmDecMp3ParseFrame {
|
||||||
|
u64 frame_size;
|
||||||
|
u32 num_channels;
|
||||||
|
u32 samples_per_channel;
|
||||||
|
u32 bitrate;
|
||||||
|
u32 sample_rate;
|
||||||
|
u32 encoder_delay;
|
||||||
|
u32 num_frames;
|
||||||
|
u32 total_samples;
|
||||||
|
AjmDecMp3OflType ofl_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ChannelMode : u8 {
|
||||||
|
Stereo = 0,
|
||||||
|
JointStero = 1,
|
||||||
|
Dual = 2,
|
||||||
|
Mono = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmSidebandDecMp3CodecInfo {
|
||||||
|
u32 header;
|
||||||
|
bool has_crc;
|
||||||
|
ChannelMode channel_mode;
|
||||||
|
u8 mode_extension;
|
||||||
|
u8 copyright;
|
||||||
|
u8 original;
|
||||||
|
u8 emphasis;
|
||||||
|
u16 reserved[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmDecMp3GetCodecInfoResult {
|
||||||
|
AjmSidebandResult result;
|
||||||
|
AjmSidebandDecMp3CodecInfo codec_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AjmMp3Decoder : public AjmInstance {
|
||||||
|
const AVCodec* codec = nullptr;
|
||||||
|
AVCodecContext* c = nullptr;
|
||||||
|
AVCodecParserContext* parser = nullptr;
|
||||||
|
std::ofstream file;
|
||||||
|
|
||||||
|
explicit AjmMp3Decoder();
|
||||||
|
~AjmMp3Decoder() override;
|
||||||
|
|
||||||
|
void Reset() override;
|
||||||
|
|
||||||
|
std::tuple<u32, u32, u32> Decode(const u8* in_buf, u32 in_size,
|
||||||
|
u8* out_buf, u32 out_size) override;
|
||||||
|
|
||||||
|
static int ParseMp3Header(const u8* buf, u32 stream_size, int parse_ofl,
|
||||||
|
AjmDecMp3ParseFrame* frame);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Libraries::Ajm
|
@ -309,7 +309,7 @@ void RegisterlibSceAvPlayer(Core::Loader::SymbolsResolver* sym) {
|
|||||||
LIB_FUNCTION("XC9wM+xULz8", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerJumpToTime);
|
LIB_FUNCTION("XC9wM+xULz8", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerJumpToTime);
|
||||||
LIB_FUNCTION("9y5v+fGN4Wk", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPause);
|
LIB_FUNCTION("9y5v+fGN4Wk", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPause);
|
||||||
LIB_FUNCTION("HD1YKVU26-M", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPostInit);
|
LIB_FUNCTION("HD1YKVU26-M", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPostInit);
|
||||||
LIB_FUNCTION("agig-iDRrTE", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPrintf);
|
//LIB_FUNCTION("agig-iDRrTE", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerPrintf);
|
||||||
LIB_FUNCTION("w5moABNwnRY", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerResume);
|
LIB_FUNCTION("w5moABNwnRY", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0, sceAvPlayerResume);
|
||||||
LIB_FUNCTION("k-q+xOxdc3E", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0,
|
LIB_FUNCTION("k-q+xOxdc3E", "libSceAvPlayer", 1, "libSceAvPlayer", 1, 0,
|
||||||
sceAvPlayerSetAvSyncMode);
|
sceAvPlayerSetAvSyncMode);
|
||||||
|
@ -1107,7 +1107,7 @@ int PS4_SYSV_ABI sceGnmInsertSetColorMarker() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmInsertSetMarker() {
|
int PS4_SYSV_ABI sceGnmInsertSetMarker(u32 *param_1,int param_2,char *param_3) {
|
||||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ s32 PS4_SYSV_ABI sceGnmInsertPopMarker(u32* cmdbuf, u32 size);
|
|||||||
int PS4_SYSV_ABI sceGnmInsertPushColorMarker();
|
int PS4_SYSV_ABI sceGnmInsertPushColorMarker();
|
||||||
s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker);
|
s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker);
|
||||||
int PS4_SYSV_ABI sceGnmInsertSetColorMarker();
|
int PS4_SYSV_ABI sceGnmInsertSetColorMarker();
|
||||||
int PS4_SYSV_ABI sceGnmInsertSetMarker();
|
int PS4_SYSV_ABI sceGnmInsertSetMarker(u32 *param_1,int param_2,char *param_3);
|
||||||
int PS4_SYSV_ABI sceGnmInsertThreadTraceMarker();
|
int PS4_SYSV_ABI sceGnmInsertThreadTraceMarker();
|
||||||
s32 PS4_SYSV_ABI sceGnmInsertWaitFlipDone(u32* cmdbuf, u32 size, s32 vo_handle, u32 buf_idx);
|
s32 PS4_SYSV_ABI sceGnmInsertWaitFlipDone(u32* cmdbuf, u32 size, s32 vo_handle, u32 buf_idx);
|
||||||
int PS4_SYSV_ABI sceGnmIsCoredumpValid();
|
int PS4_SYSV_ABI sceGnmIsCoredumpValid();
|
||||||
|
@ -502,6 +502,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
|
|||||||
sceLibcHeapGetTraceInfo);
|
sceLibcHeapGetTraceInfo);
|
||||||
LIB_FUNCTION("FxVZqBAA7ks", "libkernel", 1, "libkernel", 1, 1, ps4__write);
|
LIB_FUNCTION("FxVZqBAA7ks", "libkernel", 1, "libkernel", 1, 1, ps4__write);
|
||||||
LIB_FUNCTION("6XG4B33N09g", "libScePosix", 1, "libkernel", 1, 1, sched_yield);
|
LIB_FUNCTION("6XG4B33N09g", "libScePosix", 1, "libkernel", 1, 1, sched_yield);
|
||||||
|
LIB_FUNCTION("6XG4B33N09g", "libkernel", 1, "libkernel", 1, 1, sched_yield);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Libraries::Kernel
|
} // namespace Libraries::Kernel
|
||||||
|
@ -1042,7 +1042,7 @@ int PS4_SYSV_ABI scePthreadCreate(ScePthread* thread, const ScePthreadAttr* attr
|
|||||||
pthread_attr_setstacksize(&(*attr)->pth_attr, 2_MB);
|
pthread_attr_setstacksize(&(*attr)->pth_attr, 2_MB);
|
||||||
result = pthread_create(&(*thread)->pth, &(*attr)->pth_attr, run_thread, *thread);
|
result = pthread_create(&(*thread)->pth, &(*attr)->pth_attr, run_thread, *thread);
|
||||||
|
|
||||||
LOG_INFO(Kernel_Pthread, "thread create name = {}", (*thread)->name);
|
//LOG_INFO(Kernel_Pthread, "thread create name = {}", (*thread)->name);
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -1070,7 +1070,16 @@ ScePthread PThreadPool::Create(const char* name) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
auto* ret = new PthreadInternal{};
|
auto* ret = new PthreadInternal{};
|
||||||
|
#else
|
||||||
|
// TODO: Linux specific hack
|
||||||
|
static u8* hint_address = reinterpret_cast<u8*>(0x7FFFFC000ULL);
|
||||||
|
auto* ret = reinterpret_cast<PthreadInternal*>(
|
||||||
|
mmap(hint_address, sizeof(PthreadInternal), PROT_READ | PROT_WRITE,
|
||||||
|
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0));
|
||||||
|
hint_address += Common::AlignUp(sizeof(PthreadInternal), 4_KB);
|
||||||
|
#endif
|
||||||
ret->is_free = false;
|
ret->is_free = false;
|
||||||
ret->is_detached = false;
|
ret->is_detached = false;
|
||||||
ret->is_almost_done = false;
|
ret->is_almost_done = false;
|
||||||
|
@ -25,12 +25,13 @@ template <StringLiteral name, class R, class... Args, PS4_SYSV_ABI R (*f)(Args..
|
|||||||
struct wrapper_impl<name, PS4_SYSV_ABI R (*)(Args...), f> {
|
struct wrapper_impl<name, PS4_SYSV_ABI R (*)(Args...), f> {
|
||||||
static R PS4_SYSV_ABI wrap(Args... args) {
|
static R PS4_SYSV_ABI wrap(Args... args) {
|
||||||
if (std::string_view(name.value) != "scePthreadEqual" &&
|
if (std::string_view(name.value) != "scePthreadEqual" &&
|
||||||
std::string_view(name.value) != "sceUserServiceGetEvent") {
|
std::string_view(name.value) != "sceUserServiceGetEvent" &&
|
||||||
// LOG_WARNING(Core_Linker, "Function {} called", name.value);
|
!std::string_view(name.value).contains("scePthreadMutex")) {
|
||||||
|
//LOG_WARNING(Core_Linker, "Function {} called", name.value);
|
||||||
}
|
}
|
||||||
if constexpr (std::is_same_v<R, s32> || std::is_same_v<R, u32>) {
|
if constexpr (std::is_same_v<R, s32> || std::is_same_v<R, u32>) {
|
||||||
const u32 ret = f(args...);
|
const u32 ret = f(args...);
|
||||||
if (ret != 0 && std::string_view(name.value) != "scePthreadEqual") {
|
if (ret != 0 && std::string_view(name.value) != "scePthreadEqual" && !std::string_view(name.value).contains("Cond")) {
|
||||||
LOG_WARNING(Core_Linker, "Function {} returned {:#x}", name.value, ret);
|
LOG_WARNING(Core_Linker, "Function {} returned {:#x}", name.value, ret);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -43,7 +44,7 @@ struct wrapper_impl<name, PS4_SYSV_ABI R (*)(Args...), f> {
|
|||||||
template <StringLiteral name, class F, F f>
|
template <StringLiteral name, class F, F f>
|
||||||
constexpr auto wrapper = wrapper_impl<name, F, f>::wrap;
|
constexpr auto wrapper = wrapper_impl<name, F, f>::wrap;
|
||||||
|
|
||||||
// #define W(foo) wrapper<#foo, decltype(&foo), foo>
|
//#define W(foo) wrapper<#foo, decltype(&foo), foo>
|
||||||
#define W(foo) foo
|
#define W(foo) foo
|
||||||
|
|
||||||
#define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
|
#define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \
|
||||||
|
@ -296,7 +296,6 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Needs lock here as can be concurrently read by `sceVideoOutGetVblankStatus`
|
// Needs lock here as can be concurrently read by `sceVideoOutGetVblankStatus`
|
||||||
std::unique_lock lock{main_port.vo_mutex};
|
|
||||||
vblank_status.count++;
|
vblank_status.count++;
|
||||||
vblank_status.processTime = Libraries::Kernel::sceKernelGetProcessTime();
|
vblank_status.processTime = Libraries::Kernel::sceKernelGetProcessTime();
|
||||||
vblank_status.tsc = Libraries::Kernel::sceKernelReadTsc();
|
vblank_status.tsc = Libraries::Kernel::sceKernelReadTsc();
|
||||||
|
@ -205,11 +205,13 @@ void CFG::LinkBlocks() {
|
|||||||
end_inst.opcode == Opcode::S_ANDN2_B64 || end_inst.IsCmpx()) {
|
end_inst.opcode == Opcode::S_ANDN2_B64 || end_inst.IsCmpx()) {
|
||||||
// Blocks are stored ordered by address in the set
|
// Blocks are stored ordered by address in the set
|
||||||
auto next_it = std::next(it);
|
auto next_it = std::next(it);
|
||||||
|
ASSERT(next_it != blocks.end());
|
||||||
auto* target_block = &(*next_it);
|
auto* target_block = &(*next_it);
|
||||||
++target_block->num_predecessors;
|
++target_block->num_predecessors;
|
||||||
block.branch_true = target_block;
|
block.branch_true = target_block;
|
||||||
|
|
||||||
auto merge_it = std::next(next_it);
|
auto merge_it = std::next(next_it);
|
||||||
|
ASSERT(merge_it != blocks.end());
|
||||||
auto* merge_block = &(*merge_it);
|
auto* merge_block = &(*merge_it);
|
||||||
++merge_block->num_predecessors;
|
++merge_block->num_predecessors;
|
||||||
block.branch_false = merge_block;
|
block.branch_false = merge_block;
|
||||||
|
@ -300,7 +300,6 @@ void Translator::EmitVectorAlu(const GcnInst& inst) {
|
|||||||
return V_CMP_U32(ConditionOp::GE, false, true, inst);
|
return V_CMP_U32(ConditionOp::GE, false, true, inst);
|
||||||
case Opcode::V_CMPX_TRU_U32:
|
case Opcode::V_CMPX_TRU_U32:
|
||||||
return V_CMP_U32(ConditionOp::TRU, false, true, inst);
|
return V_CMP_U32(ConditionOp::TRU, false, true, inst);
|
||||||
|
|
||||||
// V_CMP_{OP8}_U64
|
// V_CMP_{OP8}_U64
|
||||||
case Opcode::V_CMP_NE_U64:
|
case Opcode::V_CMP_NE_U64:
|
||||||
return V_CMP_NE_U64(inst);
|
return V_CMP_NE_U64(inst);
|
||||||
|
@ -8,7 +8,6 @@ namespace Shader::Gcn {
|
|||||||
void Translator::EmitVectorMemory(const GcnInst& inst) {
|
void Translator::EmitVectorMemory(const GcnInst& inst) {
|
||||||
switch (inst.opcode) {
|
switch (inst.opcode) {
|
||||||
// MUBUF / MTBUF
|
// MUBUF / MTBUF
|
||||||
|
|
||||||
// Buffer load operations
|
// Buffer load operations
|
||||||
case Opcode::TBUFFER_LOAD_FORMAT_X:
|
case Opcode::TBUFFER_LOAD_FORMAT_X:
|
||||||
return BUFFER_LOAD(1, true, inst);
|
return BUFFER_LOAD(1, true, inst);
|
||||||
|
@ -46,6 +46,14 @@ Liverpool::~Liverpool() {
|
|||||||
void Liverpool::Process(std::stop_token stoken) {
|
void Liverpool::Process(std::stop_token stoken) {
|
||||||
Common::SetCurrentThreadName("shadPS4:GPU_CommandProcessor");
|
Common::SetCurrentThreadName("shadPS4:GPU_CommandProcessor");
|
||||||
|
|
||||||
|
for (int i = 0; i < NumTotalQueues; i++) {
|
||||||
|
GpuQueue& queue = mapped_queues[i];
|
||||||
|
std::scoped_lock<std::mutex> lk(queue.m_access);
|
||||||
|
|
||||||
|
queue.ccb_buffer.reserve(1024 * 1024);
|
||||||
|
queue.dcb_buffer.reserve(1024 * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
while (!stoken.stop_requested()) {
|
while (!stoken.stop_requested()) {
|
||||||
{
|
{
|
||||||
std::unique_lock lk{submit_mutex};
|
std::unique_lock lk{submit_mutex};
|
||||||
@ -97,8 +105,8 @@ void Liverpool::Process(std::stop_token stoken) {
|
|||||||
std::scoped_lock lock{queue.m_access};
|
std::scoped_lock lock{queue.m_access};
|
||||||
queue.submits.pop();
|
queue.submits.pop();
|
||||||
|
|
||||||
--num_submits;
|
|
||||||
std::scoped_lock lock2{submit_mutex};
|
std::scoped_lock lock2{submit_mutex};
|
||||||
|
--num_submits;
|
||||||
submit_cv.notify_all();
|
submit_cv.notify_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -462,6 +470,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||||||
mapped_queues[GfxQueueId].indirect_args_addr = set_base->Address<u64>();
|
mapped_queues[GfxQueueId].indirect_args_addr = set_base->Address<u64>();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case PM4ItOpcode::SetPredication:
|
||||||
case PM4ItOpcode::EventWrite: {
|
case PM4ItOpcode::EventWrite: {
|
||||||
// const auto* event = reinterpret_cast<const PM4CmdEventWrite*>(header);
|
// const auto* event = reinterpret_cast<const PM4CmdEventWrite*>(header);
|
||||||
break;
|
break;
|
||||||
@ -603,6 +612,9 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb, int vqid) {
|
|||||||
(count - 1) * sizeof(u32));
|
(count - 1) * sizeof(u32));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case PM4ItOpcode::DmaData: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
case PM4ItOpcode::DispatchDirect: {
|
case PM4ItOpcode::DispatchDirect: {
|
||||||
const auto* dispatch_direct = reinterpret_cast<const PM4CmdDispatchDirect*>(header);
|
const auto* dispatch_direct = reinterpret_cast<const PM4CmdDispatchDirect*>(header);
|
||||||
regs.cs_program.dim_x = dispatch_direct->dim_x;
|
regs.cs_program.dim_x = dispatch_direct->dim_x;
|
||||||
|
@ -621,6 +621,9 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr,
|
|||||||
const u32 num_layers = image.info.resources.layers;
|
const u32 num_layers = image.info.resources.layers;
|
||||||
const u32 max_offset = offset + size;
|
const u32 max_offset = offset + size;
|
||||||
for (u32 m = 0; m < image.info.resources.levels; m++) {
|
for (u32 m = 0; m < image.info.resources.levels; m++) {
|
||||||
|
if (offset >= buffer.SizeBytes()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
const u32 width = std::max(image.info.size.width >> m, 1u);
|
const u32 width = std::max(image.info.size.width >> m, 1u);
|
||||||
const u32 height = std::max(image.info.size.height >> m, 1u);
|
const u32 height = std::max(image.info.size.height >> m, 1u);
|
||||||
const u32 depth =
|
const u32 depth =
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include "core/signals.h"
|
#include "core/signals.h"
|
||||||
#include "video_core/page_manager.h"
|
#include "video_core/page_manager.h"
|
||||||
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
||||||
|
#define ENABLE_USERFAULTFD 1
|
||||||
#ifndef _WIN64
|
#ifndef _WIN64
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#ifdef ENABLE_USERFAULTFD
|
#ifdef ENABLE_USERFAULTFD
|
||||||
|
@ -212,6 +212,8 @@ vk::SamplerAddressMode ClampMode(AmdGpu::ClampMode mode) {
|
|||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case AmdGpu::ClampMode::ClampBorder:
|
case AmdGpu::ClampMode::ClampBorder:
|
||||||
return vk::SamplerAddressMode::eClampToBorder;
|
return vk::SamplerAddressMode::eClampToBorder;
|
||||||
|
case AmdGpu::ClampMode::ClampHalfBorder:
|
||||||
|
return vk::SamplerAddressMode::eClampToBorder;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -176,8 +176,8 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
|
|||||||
const auto vsharp = desc.GetSharp(*info);
|
const auto vsharp = desc.GetSharp(*info);
|
||||||
vk::BufferView& buffer_view = buffer_views.emplace_back(null_buffer_view);
|
vk::BufferView& buffer_view = buffer_views.emplace_back(null_buffer_view);
|
||||||
const u32 size = vsharp.GetSize();
|
const u32 size = vsharp.GetSize();
|
||||||
if (vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid && size != 0) {
|
const VAddr address = vsharp.base_address;
|
||||||
const VAddr address = vsharp.base_address;
|
if (vsharp.GetDataFmt() != AmdGpu::DataFormat::FormatInvalid && address != 0 && size != 0) {
|
||||||
if (desc.is_written) {
|
if (desc.is_written) {
|
||||||
if (texture_cache.TouchMeta(address, true)) {
|
if (texture_cache.TouchMeta(address, true)) {
|
||||||
LOG_TRACE(Render_Vulkan, "Metadata update skipped");
|
LOG_TRACE(Render_Vulkan, "Metadata update skipped");
|
||||||
@ -192,8 +192,8 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache,
|
|||||||
const auto [vk_buffer, offset] =
|
const auto [vk_buffer, offset] =
|
||||||
buffer_cache.ObtainBuffer(address, size, desc.is_written, true);
|
buffer_cache.ObtainBuffer(address, size, desc.is_written, true);
|
||||||
const u32 fmt_stride = AmdGpu::NumBits(vsharp.GetDataFmt()) >> 3;
|
const u32 fmt_stride = AmdGpu::NumBits(vsharp.GetDataFmt()) >> 3;
|
||||||
ASSERT_MSG(fmt_stride == vsharp.GetStride(),
|
//ASSERT_MSG(fmt_stride == vsharp.GetStride(),
|
||||||
"Texel buffer stride must match format stride");
|
// "Texel buffer stride must match format stride");
|
||||||
const u32 offset_aligned = Common::AlignDown(offset, alignment);
|
const u32 offset_aligned = Common::AlignDown(offset, alignment);
|
||||||
const u32 adjust = offset - offset_aligned;
|
const u32 adjust = offset - offset_aligned;
|
||||||
ASSERT(adjust % fmt_stride == 0);
|
ASSERT(adjust % fmt_stride == 0);
|
||||||
|
@ -383,6 +383,8 @@ bool Instance::CreateDevice() {
|
|||||||
.workgroupMemoryExplicitLayout16BitAccess = true,
|
.workgroupMemoryExplicitLayout16BitAccess = true,
|
||||||
},
|
},
|
||||||
vk::PhysicalDeviceRobustness2FeaturesEXT{
|
vk::PhysicalDeviceRobustness2FeaturesEXT{
|
||||||
|
.robustBufferAccess2 = true,
|
||||||
|
.robustImageAccess2 = true,
|
||||||
.nullDescriptor = true,
|
.nullDescriptor = true,
|
||||||
},
|
},
|
||||||
vk::PhysicalDeviceSynchronization2Features{
|
vk::PhysicalDeviceSynchronization2Features{
|
||||||
|
@ -138,6 +138,9 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
|
|||||||
image{instance->GetDevice(), instance->GetAllocator()}, cpu_addr{info.guest_address},
|
image{instance->GetDevice(), instance->GetAllocator()}, cpu_addr{info.guest_address},
|
||||||
cpu_addr_end{cpu_addr + info.guest_size_bytes} {
|
cpu_addr_end{cpu_addr + info.guest_size_bytes} {
|
||||||
mip_hashes.resize(info.resources.levels);
|
mip_hashes.resize(info.resources.levels);
|
||||||
|
if (info.size.height == 1620) {
|
||||||
|
printf("bad\n");
|
||||||
|
}
|
||||||
ASSERT(info.pixel_format != vk::Format::eUndefined);
|
ASSERT(info.pixel_format != vk::Format::eUndefined);
|
||||||
// Here we force `eExtendedUsage` as don't know all image usage cases beforehand. In normal case
|
// Here we force `eExtendedUsage` as don't know all image usage cases beforehand. In normal case
|
||||||
// the texture cache should re-create the resource with the usage requested
|
// the texture cache should re-create the resource with the usage requested
|
||||||
|
@ -183,10 +183,12 @@ vk::Format DemoteImageFormatForDetiling(vk::Format format) {
|
|||||||
case vk::Format::eB8G8R8A8Unorm:
|
case vk::Format::eB8G8R8A8Unorm:
|
||||||
case vk::Format::eR8G8B8A8Unorm:
|
case vk::Format::eR8G8B8A8Unorm:
|
||||||
case vk::Format::eR8G8B8A8Uint:
|
case vk::Format::eR8G8B8A8Uint:
|
||||||
|
case vk::Format::eR8G8B8A8Snorm:
|
||||||
case vk::Format::eR32Sfloat:
|
case vk::Format::eR32Sfloat:
|
||||||
case vk::Format::eR32Uint:
|
case vk::Format::eR32Uint:
|
||||||
case vk::Format::eR16G16Sfloat:
|
case vk::Format::eR16G16Sfloat:
|
||||||
case vk::Format::eR16G16Unorm:
|
case vk::Format::eR16G16Unorm:
|
||||||
|
case vk::Format::eR16G16Snorm:
|
||||||
case vk::Format::eB10G11R11UfloatPack32:
|
case vk::Format::eB10G11R11UfloatPack32:
|
||||||
return vk::Format::eR32Uint;
|
return vk::Format::eR32Uint;
|
||||||
case vk::Format::eBc1RgbaSrgbBlock:
|
case vk::Format::eBc1RgbaSrgbBlock:
|
||||||
|
Loading…
Reference in New Issue
Block a user