feat(log): log system detalization

This commit is contained in:
boykopovar 2026-09-08 12:10:49 +03:00
parent 13b30f93a9
commit 81d7adea95
9 changed files with 282 additions and 207 deletions

View File

@ -7,6 +7,7 @@ Implementations of system prx libraries suitable for dynamic linking: [core/libs
Execution reaches `_start`, stack unwinding and exception handling tables are built. All unimplemented functions throw std::runtime_error. `what()` is printed to stderr and the process terminates.
Shader initialization via `sceAgcCreate*` passes.
Now: `sceVideoOutOpen not implemented`.
## Disclaimer

View File

@ -1,6 +1,7 @@
add_library(libSceAgc SHARED EXCLUDE_FROM_ALL
${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Shader/Export.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Shader/ShaderUtils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Acb/Export.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Cb/Export.cpp
${CMAKE_CURRENT_SOURCE_DIR}/DcbDraw/Export.cpp

View File

@ -1,228 +1,64 @@
#include <cstdint>
#include <cstddef>
#include <cstdio>
#include <stdexcept>
#include <prx/libc/include/General.hpp>
#include "SceShaders.hpp"
#include "prx/libc/include/General.hpp"
#include "ShaderUtils.hpp"
#include "ShaderConstants.hpp"
namespace {
using namespace ShaderRegs;
template <typename T>
static void _resolveRelativePtr(T*& field) {
if (field == nullptr) {
return;
}
field = reinterpret_cast<T*>(
reinterpret_cast<std::uintptr_t>(field) + reinterpret_cast<std::uintptr_t>(&field)
);
}
static bool _getProgramAddressRegisterOffset(std::uint8_t type, std::uint32_t& loOffset) {
switch (static_cast<ShaderBinaryType>(type)) {
case ShaderBinaryType::Cs: loOffset = COMPUTE_PGM_LO; return true;
case ShaderBinaryType::Ps: loOffset = SPI_SHADER_PGM_LO_PS; return true;
case ShaderBinaryType::Gs: loOffset = SPI_SHADER_PGM_LO_ES; return true;
case ShaderBinaryType::Hs: loOffset = SPI_SHADER_PGM_LO_LS; return true;
case ShaderBinaryType::GsBack: loOffset = SPI_SHADER_PGM_LO_GS; return true;
case ShaderBinaryType::HsBack: loOffset = SPI_SHADER_PGM_LO_HS; return true;
default: return false;
}
}
static int _patchProgramAddressRegister(ShaderRegister* regs, std::uint32_t numRegs, std::uint8_t type, std::uint64_t base) {
std::uint32_t loOffset = 0;
if (!_getProgramAddressRegisterOffset(type, loOffset)) {
return 0;
}
if (regs == nullptr || numRegs == 0) {
throw std::runtime_error("sceAgcCreateShader: sh_registers missing for shader type requiring program address patch");
}
for (std::uint32_t i = 0; i < numRegs; ++i) {
if (regs[i].offset != loOffset) {
continue;
}
const std::uint32_t hiIndex = i + 1u;
if (hiIndex >= numRegs || regs[hiIndex].offset != loOffset + 1u) {
throw std::runtime_error("sceAgcCreateShader: shader program address hi register missing");
}
const std::uint64_t shaderOffset =
(static_cast<std::uint64_t>(regs[i].value) << 8u) |
((static_cast<std::uint64_t>(regs[hiIndex].value) & 0xFFu) << 40u);
const std::uint64_t addr = base + shaderOffset;
regs[i].value = static_cast<std::uint32_t>((addr >> 8u) & 0xFFFFFFFFu);
regs[hiIndex].value &= 0xFFFFFF00u;
regs[hiIndex].value |= static_cast<std::uint32_t>((addr >> 40u) & 0xFFu);
return 0;
}
throw std::runtime_error("sceAgcCreateShader: shader program address lo register not found");
}
static std::uint32_t _graphicsPrimTypeToGsOut(std::uint32_t primType) {
switch (static_cast<PrimitiveType>(primType)) {
case PrimitiveType::PointList:
return static_cast<std::uint32_t>(GsOutputPrimitiveType::Points);
case PrimitiveType::LineList:
case PrimitiveType::LineStrip:
case PrimitiveType::LineListAdjacency:
case PrimitiveType::LineStripAdjacency:
case PrimitiveType::LineLoop:
return static_cast<std::uint32_t>(GsOutputPrimitiveType::Lines);
case PrimitiveType::RectList:
return static_cast<std::uint32_t>(GsOutputPrimitiveType::Rectangle2D);
case PrimitiveType::RectListLegacy:
return static_cast<std::uint32_t>(GsOutputPrimitiveType::RectList);
default:
return static_cast<std::uint32_t>(GsOutputPrimitiveType::Triangles);
}
}
static std::uint32_t _shaderSemanticWord(const ShaderSemantic& s) {
return ((s.semantic & 0xFFu) << 0u)
| ((s.hardware_mapping & 0xFFu) << 8u)
| ((s.size_in_elements & 0xFu) << 16u)
| ((s.is_f16 & 0x3u) << 20u)
| ((s.is_flat_shaded & 0x1u) << 22u)
| ((s.is_linear & 0x1u) << 23u)
| ((s.is_custom & 0x1u) << 24u)
| ((s.static_vb_index & 0x1u) << 25u)
| ((s.static_attribute & 0x1u) << 26u)
| ((s.reserved & 0x1u) << 27u)
| ((s.default_value & 0x3u) << 28u)
| ((s.default_value_hi & 0x3u) << 30u);
}
static std::uint32_t _applyInterpolantDefaultValue(std::uint32_t value, std::uint32_t psWord) {
value &= ~0x00000300u;
value |= ((psWord >> 28u) & 0x3u) << 8u;
return value;
}
static std::uint32_t _applyInterpolantDefaultValueHi(std::uint32_t value, std::uint32_t psWord) {
value &= ~0x00600000u;
value |= ((psWord >> 30u) & 0x3u) << 21u;
return value;
}
static std::uint32_t _createInterpolantF16Value(std::uint32_t psWord, const ShaderSemantic* gsSemantic) {
std::uint32_t value = (psWord << 4u) & 0x03000000u;
if (gsSemantic == nullptr) {
value |= 0x00180020u;
} else {
const std::uint32_t commonWord = psWord & _shaderSemanticWord(*gsSemantic);
value &= 0xFFF7FFDFu;
value |= (commonWord >> 15u) & 0x20u;
value ^= 0x00080020u;
value &= ~0x00100000u;
value |= (~commonWord >> 1u) & 0x00100000u;
}
return _applyInterpolantDefaultValueHi(value, psWord);
}
static std::uint32_t _createInterpolantNonF16Value(std::uint32_t psWord, const ShaderSemantic* gsSemantic) {
std::uint32_t value = 0;
if ((psWord & 0x01000000u) != 0 || gsSemantic == nullptr) {
value |= 0x20u;
}
return value;
}
static std::uint32_t _createInterpolantMappingValue(std::uint32_t value, std::uint32_t psWord, std::uint32_t gsWord) {
const std::uint32_t flatShade =
((psWord & 0x00400000u) != 0 || (psWord & 0x01000000u) != 0) ? 0x00000400u : 0u;
value &= ~0x0000001Fu;
value |= (gsWord >> 8u) & 0x1Fu;
value &= ~0x00000400u;
value |= flatShade;
return _applyInterpolantDefaultValue(value, psWord);
}
static std::uint32_t _createInterpolantDefaultValue(std::uint32_t value, std::uint32_t psWord) {
value &= ~0x0000001Fu;
value &= ~0x00000400u;
return _applyInterpolantDefaultValue(value, psWord);
}
static const ShaderSemantic* _findOutputSemantic(const Shader* gs, std::uint32_t semantic) {
if (gs == nullptr || gs->output_semantics == nullptr) {
return nullptr;
}
for (std::uint16_t i = 0; i < gs->num_output_semantics; ++i) {
if (gs->output_semantics[i].semantic == semantic) {
return &gs->output_semantics[i];
}
}
return nullptr;
}
static void _setInterpolantRegister(ShaderRegister* regs, std::uint32_t index, std::uint32_t value) {
regs[index].offset = SPI_PS_INPUT_CNTL_0 + index;
regs[index].value = value;
}
static void _fillIdentityInterpolants(ShaderRegister* regs, std::uint32_t firstIndex) {
for (std::uint32_t i = firstIndex; i < 32u; ++i) {
_setInterpolantRegister(regs, i, i);
}
}
}
extern "C" {
int sceAgcCreateShader(Shader** dst, void* header, const volatile void* code) {
constexpr auto fn = __func__;
if (dst == nullptr) {
throw std::runtime_error("sceAgcCreateShader: dst is null");
throw std::runtime_error(std::string(fn) + ": dst is null");
}
if (header == nullptr) {
throw std::runtime_error("sceAgcCreateShader: header is null");
throw std::runtime_error(std::string(fn) + ": header is null");
}
if (code == nullptr) {
throw std::runtime_error("sceAgcCreateShader: code is null");
throw std::runtime_error(std::string(fn) + ": code is null");
}
auto* h = static_cast<Shader*>(header);
_resolveRelativePtr(h->cx_registers);
_resolveRelativePtr(h->sh_registers);
_resolveRelativePtr(h->user_data);
_resolveRelativePtr(h->specials);
_resolveRelativePtr(h->input_semantics);
_resolveRelativePtr(h->output_semantics);
ResolveRelativePtr(h->cx_registers);
ResolveRelativePtr(h->sh_registers);
ResolveRelativePtr(h->user_data);
ResolveRelativePtr(h->specials);
ResolveRelativePtr(h->input_semantics);
ResolveRelativePtr(h->output_semantics);
if (h->user_data != nullptr) {
_resolveRelativePtr(h->user_data->direct_resource_offset);
_resolveRelativePtr(h->user_data->sharp_resource_offset[0]);
_resolveRelativePtr(h->user_data->sharp_resource_offset[1]);
_resolveRelativePtr(h->user_data->sharp_resource_offset[2]);
_resolveRelativePtr(h->user_data->sharp_resource_offset[3]);
ResolveRelativePtr(h->user_data->direct_resource_offset);
ResolveRelativePtr(h->user_data->sharp_resource_offset[0]);
ResolveRelativePtr(h->user_data->sharp_resource_offset[1]);
ResolveRelativePtr(h->user_data->sharp_resource_offset[2]);
ResolveRelativePtr(h->user_data->sharp_resource_offset[3]);
}
h->code = code;
if (h->file_header != ShaderRegs::SHADER_FILE_HEADER_MAGIC) {
throw std::runtime_error("sceAgcCreateShader: invalid file_header magic");
throw std::runtime_error(std::string(fn) + ": invalid file_header magic");
}
if (h->version != ShaderRegs::SHADER_VERSION) {
throw std::runtime_error("sceAgcCreateShader: unsupported shader version");
throw std::runtime_error(std::string(fn) + ": unsupported shader version");
}
const auto base = reinterpret_cast<std::uint64_t>(code);
if ((base & ShaderRegs::SHADER_BASE_ALIGN_MASK) != 0) {
throw std::runtime_error("sceAgcCreateShader: code address violates alignment mask");
throw std::runtime_error(std::string(fn) + ": code address violates alignment mask");
}
int result = _patchProgramAddressRegister(h->sh_registers, h->num_sh_registers, h->type, base);
int result = PatchProgramAddressRegister(h->sh_registers, h->num_sh_registers, h->type, base);
if (result != 0) {
return result;
}
*dst = h;
APS5_LOG_OUT("OK type=%u sh_regs=%u shader_size=%u", h->type, h->num_sh_registers, h->shader_size);
return 0;
}
@ -231,7 +67,7 @@ int sceAgcCreatePrimState(ShaderRegister* cx_regs, ShaderRegister* uc_regs, cons
return 0;
}
if (gs == nullptr) {
throw std::runtime_error("sceAgcCreatePrimState: gs is null");
throw std::runtime_error(std::string(__func__) + ": gs is null");
}
if (cx_regs != nullptr) {
@ -240,7 +76,7 @@ int sceAgcCreatePrimState(ShaderRegister* cx_regs, ShaderRegister* uc_regs, cons
cx_regs[1] = gs->specials->vgt_gs_out_prim_type;
} else {
cx_regs[1].offset = ShaderRegs::VGT_GS_OUT_PRIM_TYPE;
cx_regs[1].value = _graphicsPrimTypeToGsOut(prim_type);
cx_regs[1].value = GraphicsPrimTypeToGsOut(prim_type);
}
if (hs != nullptr) {
@ -262,13 +98,14 @@ int sceAgcCreatePrimState(ShaderRegister* cx_regs, ShaderRegister* uc_regs, cons
}
}
APS5_LOG_OUT("OK prim_type=%u", prim_type);
return 0;
}
int sceAgcUpdatePrimState(ShaderRegister* cx_regs, ShaderRegister* uc_regs, std::uint32_t prim_type) {
if (cx_regs != nullptr && (cx_regs[0].value & (ShaderRegs::VGT_SHADER_STAGES_GS_BIT | ShaderRegs::VGT_SHADER_STAGES_NGG_BIT)) == 0) {
cx_regs[1].value &= ~0x7u;
cx_regs[1].value |= _graphicsPrimTypeToGsOut(prim_type);
cx_regs[1].value |= GraphicsPrimTypeToGsOut(prim_type);
}
if (uc_regs != nullptr) {
@ -276,49 +113,53 @@ int sceAgcUpdatePrimState(ShaderRegister* cx_regs, ShaderRegister* uc_regs, std:
uc_regs[2].value |= prim_type;
}
APS5_LOG_OUT("OK prim_type=%u", prim_type);
return 0;
}
int sceAgcCreateInterpolantMapping(ShaderRegister* regs, const Shader* gs, const Shader* ps) {
constexpr auto fn = __func__;
if (regs == nullptr) {
throw std::runtime_error("sceAgcCreateInterpolantMapping: regs is null");
throw std::runtime_error(std::string(fn) + ": regs is null");
}
if (ps == nullptr || ps->num_input_semantics == 0) {
_fillIdentityInterpolants(regs, 0);
FillIdentityInterpolants(regs, 0);
APS5_LOG_CHARS_OUT("OK identity ps_inputs=0");
return 0;
}
if (ps->num_input_semantics != 0 && ps->input_semantics == nullptr) {
throw std::runtime_error("sceAgcCreateInterpolantMapping: ps->input_semantics is null but num_input_semantics != 0");
throw std::runtime_error(std::string(fn) + ": ps->input_semantics is null but num_input_semantics != 0");
}
if (gs == nullptr) {
throw std::runtime_error("sceAgcCreateInterpolantMapping: gs is null");
throw std::runtime_error(std::string(fn) + ": gs is null");
}
if (gs->num_output_semantics != 0 && gs->output_semantics == nullptr) {
throw std::runtime_error("sceAgcCreateInterpolantMapping: gs->output_semantics is null but num_output_semantics != 0");
throw std::runtime_error(std::string(fn) + ": gs->output_semantics is null but num_output_semantics != 0");
}
for (std::uint32_t i = 0; i < ps->num_input_semantics; ++i) {
const ShaderSemantic& psSemantic = ps->input_semantics[i];
const ShaderSemantic* gsSemantic = _findOutputSemantic(gs, psSemantic.semantic);
const std::uint32_t psWord = _shaderSemanticWord(psSemantic);
const ShaderSemantic* gsSemantic = FindOutputSemantic(gs, psSemantic.semantic);
const std::uint32_t psWord = ShaderSemanticWord(psSemantic);
std::uint32_t value = ((psWord & 0x00300000u) != 0)
? _createInterpolantF16Value(psWord, gsSemantic)
: _createInterpolantNonF16Value(psWord, gsSemantic);
? CreateInterpolantF16Value(psWord, gsSemantic)
: CreateInterpolantNonF16Value(psWord, gsSemantic);
value = (gsSemantic == nullptr)
? _createInterpolantDefaultValue(value, psWord)
: _createInterpolantMappingValue(value, psWord, _shaderSemanticWord(*gsSemantic));
? CreateInterpolantDefaultValue(value, psWord)
: CreateInterpolantMappingValue(value, psWord, ShaderSemanticWord(*gsSemantic));
_setInterpolantRegister(regs, i, value);
SetInterpolantRegister(regs, i, value);
}
_fillIdentityInterpolants(regs, ps->num_input_semantics);
FillIdentityInterpolants(regs, ps->num_input_semantics);
APS5_LOG_OUT("OK ps_inputs=%u gs_outputs=%u", ps->num_input_semantics, gs->num_output_semantics);
return 0;
}
} // extern "C"
}

View File

@ -0,0 +1,152 @@
#include <stdexcept>
#include "ShaderUtils.hpp"
using namespace ShaderRegs;
bool GetProgramAddressRegisterOffset(std::uint8_t type, std::uint32_t& loOffset) {
switch (static_cast<ShaderBinaryType>(type)) {
case ShaderBinaryType::Cs: loOffset = COMPUTE_PGM_LO; return true;
case ShaderBinaryType::Ps: loOffset = SPI_SHADER_PGM_LO_PS; return true;
case ShaderBinaryType::Gs: loOffset = SPI_SHADER_PGM_LO_ES; return true;
case ShaderBinaryType::Hs: loOffset = SPI_SHADER_PGM_LO_LS; return true;
case ShaderBinaryType::GsBack: loOffset = SPI_SHADER_PGM_LO_GS; return true;
case ShaderBinaryType::HsBack: loOffset = SPI_SHADER_PGM_LO_HS; return true;
default: return false;
}
}
int PatchProgramAddressRegister(ShaderRegister* regs, std::uint32_t numRegs, std::uint8_t type, std::uint64_t base) {
std::uint32_t loOffset = 0;
if (!GetProgramAddressRegisterOffset(type, loOffset)) {
return 0;
}
if (regs == nullptr || numRegs == 0) {
throw std::runtime_error("sceAgcCreateShader: sh_registers missing for shader type requiring program address patch");
}
for (std::uint32_t i = 0; i < numRegs; ++i) {
if (regs[i].offset != loOffset) {
continue;
}
const std::uint32_t hiIndex = i + 1u;
if (hiIndex >= numRegs || regs[hiIndex].offset != loOffset + 1u) {
throw std::runtime_error("sceAgcCreateShader: shader program address hi register missing");
}
const std::uint64_t shaderOffset =
(static_cast<std::uint64_t>(regs[i].value) << 8u) |
((static_cast<std::uint64_t>(regs[hiIndex].value) & 0xFFu) << 40u);
const std::uint64_t addr = base + shaderOffset;
regs[i].value = static_cast<std::uint32_t>((addr >> 8u) & 0xFFFFFFFFu);
regs[hiIndex].value &= 0xFFFFFF00u;
regs[hiIndex].value |= static_cast<std::uint32_t>((addr >> 40u) & 0xFFu);
return 0;
}
throw std::runtime_error("sceAgcCreateShader: shader program address lo register not found");
}
std::uint32_t GraphicsPrimTypeToGsOut(std::uint32_t primType) {
switch (static_cast<PrimitiveType>(primType)) {
case PrimitiveType::PointList:
return static_cast<std::uint32_t>(GsOutputPrimitiveType::Points);
case PrimitiveType::LineList:
case PrimitiveType::LineStrip:
case PrimitiveType::LineListAdjacency:
case PrimitiveType::LineStripAdjacency:
case PrimitiveType::LineLoop:
return static_cast<std::uint32_t>(GsOutputPrimitiveType::Lines);
case PrimitiveType::RectList:
return static_cast<std::uint32_t>(GsOutputPrimitiveType::Rectangle2D);
case PrimitiveType::RectListLegacy:
return static_cast<std::uint32_t>(GsOutputPrimitiveType::RectList);
default:
return static_cast<std::uint32_t>(GsOutputPrimitiveType::Triangles);
}
}
std::uint32_t ShaderSemanticWord(const ShaderSemantic& s) {
return ((s.semantic & 0xFFu) << 0u)
| ((s.hardware_mapping & 0xFFu) << 8u)
| ((s.size_in_elements & 0xFu) << 16u)
| ((s.is_f16 & 0x3u) << 20u)
| ((s.is_flat_shaded & 0x1u) << 22u)
| ((s.is_linear & 0x1u) << 23u)
| ((s.is_custom & 0x1u) << 24u)
| ((s.static_vb_index & 0x1u) << 25u)
| ((s.static_attribute & 0x1u) << 26u)
| ((s.reserved & 0x1u) << 27u)
| ((s.default_value & 0x3u) << 28u)
| ((s.default_value_hi & 0x3u) << 30u);
}
std::uint32_t ApplyInterpolantDefaultValue(std::uint32_t value, std::uint32_t psWord) {
value &= ~0x00000300u;
value |= ((psWord >> 28u) & 0x3u) << 8u;
return value;
}
std::uint32_t ApplyInterpolantDefaultValueHi(std::uint32_t value, std::uint32_t psWord) {
value &= ~0x00600000u;
value |= ((psWord >> 30u) & 0x3u) << 21u;
return value;
}
std::uint32_t CreateInterpolantF16Value(std::uint32_t psWord, const ShaderSemantic* gsSemantic) {
std::uint32_t value = (psWord << 4u) & 0x03000000u;
if (gsSemantic == nullptr) {
value |= 0x00180020u;
} else {
const std::uint32_t commonWord = psWord & ShaderSemanticWord(*gsSemantic);
value &= 0xFFF7FFDFu;
value |= (commonWord >> 15u) & 0x20u;
value ^= 0x00080020u;
value &= ~0x00100000u;
value |= (~commonWord >> 1u) & 0x00100000u;
}
return ApplyInterpolantDefaultValueHi(value, psWord);
}
std::uint32_t CreateInterpolantNonF16Value(std::uint32_t psWord, const ShaderSemantic* gsSemantic) {
std::uint32_t value = 0;
if ((psWord & 0x01000000u) != 0 || gsSemantic == nullptr) {
value |= 0x20u;
}
return value;
}
std::uint32_t CreateInterpolantMappingValue(std::uint32_t value, std::uint32_t psWord, std::uint32_t gsWord) {
const std::uint32_t flatShade =
((psWord & 0x00400000u) != 0 || (psWord & 0x01000000u) != 0) ? 0x00000400u : 0u;
value &= ~0x0000001Fu;
value |= (gsWord >> 8u) & 0x1Fu;
value &= ~0x00000400u;
value |= flatShade;
return ApplyInterpolantDefaultValue(value, psWord);
}
std::uint32_t CreateInterpolantDefaultValue(std::uint32_t value, std::uint32_t psWord) {
value &= ~0x0000001Fu;
value &= ~0x00000400u;
return ApplyInterpolantDefaultValue(value, psWord);
}
const ShaderSemantic* FindOutputSemantic(const Shader* gs, std::uint32_t semantic) {
if (gs == nullptr || gs->output_semantics == nullptr) {
return nullptr;
}
for (std::uint16_t i = 0; i < gs->num_output_semantics; ++i) {
if (gs->output_semantics[i].semantic == semantic) {
return &gs->output_semantics[i];
}
}
return nullptr;
}
void SetInterpolantRegister(ShaderRegister* regs, std::uint32_t index, std::uint32_t value) {
regs[index].offset = SPI_PS_INPUT_CNTL_0 + index;
regs[index].value = value;
}
void FillIdentityInterpolants(ShaderRegister* regs, std::uint32_t firstIndex) {
for (std::uint32_t i = firstIndex; i < 32u; ++i) {
SetInterpolantRegister(regs, i, i);
}
}

View File

@ -0,0 +1,32 @@
#ifndef CORE_LIBS_LIBSCEAGC_SHADER_UTILS_HPP
#define CORE_LIBS_LIBSCEAGC_SHADER_UTILS_HPP
#include <cstdint>
#include "SceShaders.hpp"
#include "ShaderConstants.hpp"
template <typename T>
void ResolveRelativePtr(T*& field) {
if (field == nullptr) {
return;
}
field = reinterpret_cast<T*>(
reinterpret_cast<std::uintptr_t>(field) + reinterpret_cast<std::uintptr_t>(&field)
);
}
bool GetProgramAddressRegisterOffset(std::uint8_t type, std::uint32_t& loOffset);
int PatchProgramAddressRegister(ShaderRegister* regs, std::uint32_t numRegs, std::uint8_t type, std::uint64_t base);
std::uint32_t GraphicsPrimTypeToGsOut(std::uint32_t primType);
std::uint32_t ShaderSemanticWord(const ShaderSemantic& s);
std::uint32_t ApplyInterpolantDefaultValue(std::uint32_t value, std::uint32_t psWord);
std::uint32_t ApplyInterpolantDefaultValueHi(std::uint32_t value, std::uint32_t psWord);
std::uint32_t CreateInterpolantF16Value(std::uint32_t psWord, const ShaderSemantic* gsSemantic);
std::uint32_t CreateInterpolantNonF16Value(std::uint32_t psWord, const ShaderSemantic* gsSemantic);
std::uint32_t CreateInterpolantMappingValue(std::uint32_t value, std::uint32_t psWord, std::uint32_t gsWord);
std::uint32_t CreateInterpolantDefaultValue(std::uint32_t value, std::uint32_t psWord);
const ShaderSemantic* FindOutputSemantic(const Shader* gs, std::uint32_t semantic);
void SetInterpolantRegister(ShaderRegister* regs, std::uint32_t index, std::uint32_t value);
void FillIdentityInterpolants(ShaderRegister* regs, std::uint32_t firstIndex);
#endif

View File

@ -23,20 +23,24 @@ extern "C" {
void init_env_nid_postfix(const InitEnvParams* params) {
(void)params;
NotImplemented_nid_no_patch(__func__);
}
void catchReturnFromMain_nid_postfix(int status) {
(void)status;
NotImplemented_nid_no_patch(__func__);
}
int cxa_atexit_nid_postfix(void (*func)(void*), void* arg, void* d) {
(void)func;
(void)arg;
(void)d;
NotImplemented_nid_no_patch(__func__);
return 0;
}
void cxa_finalize_nid_postfix(void* d) {
NotImplemented_nid_no_patch(__func__);
(void)d;
}
@ -44,17 +48,20 @@ extern "C" {
(void)flag;
(void)func;
(void)arg;
NotImplemented_nid_no_patch(__func__);
return 0;
}
void LibcHeapGetTraceInfo_nid_postfix(LibcHeapInfo* info) {
(void)info;
NotImplemented_nid_no_patch(__func__);
}
int LibcInternalExtCxaThreadAtexit_nid_postfix(void (*destructor)(void*), void* object, void* module_id) {
(void)destructor;
(void)object;
(void)module_id;
NotImplemented_nid_no_patch(__func__);
return 0;
}
@ -64,6 +71,7 @@ extern "C" {
) {
(void)msp; (void)ptr; (void)error;
(void)arg3; (void)arg4; (void)arg5;
NotImplemented_nid_no_patch(__func__);
return 0;
}

View File

@ -1,6 +1,46 @@
#ifndef CORE_LIBS_PRX_LIBC_INCLUDE_GENERAL_HPP
#define CORE_LIBS_PRX_LIBC_INCLUDE_GENERAL_HPP
#include <cstring>
extern "C" void NotImplemented_nid_no_patch(const char* funcName);
inline const char* TrimNidPostfix(const char* func) {
return func;
const char* pos = std::strstr(func, "_nid_postfix");
if (pos != nullptr) {
static thread_local char buf[256];
const std::size_t len = static_cast<std::size_t>(pos - func);
std::memcpy(buf, func, len);
buf[len] = '\0';
return buf;
}
return func;
}
constexpr const char* BaseName(const char* path) {
const char* last = path;
const char* prev = nullptr;
for (const char* p = path; *p; ++p)
if (*p == '/' || *p == '\\') {
prev = last;
last = p + 1;
}
return (prev && *prev) ? prev : last;
}
#define _APS5_FILE_ BaseName(__FILE__)
#define _APS5_LOG_IMPL(stream, fmt, ...) \
(std::fprintf(stream, "[%s:%d %s] " fmt "\n", _APS5_FILE_, __LINE__, TrimNidPostfix(__func__), __VA_ARGS__), \
std::fflush(stream))
#define _APS5_LOG_IMPL_NF(stream, fmt) \
(std::fprintf(stream, "[%s:%d %s] " fmt "\n", _APS5_FILE_, __LINE__, TrimNidPostfix(__func__)), \
std::fflush(stream))
#define APS5_LOG_OUT(fmt, ...) _APS5_LOG_IMPL(stdout, fmt, __VA_ARGS__)
#define APS5_LOG_ERR(fmt, ...) _APS5_LOG_IMPL(stderr, fmt, __VA_ARGS__)
#define APS5_LOG_CHARS_OUT(fmt) _APS5_LOG_IMPL_NF(stdout, fmt)
#define APS5_LOG_CHARS_ERR(fmt) _APS5_LOG_IMPL_NF(stderr, fmt)
#endif

View File

@ -23,7 +23,7 @@ FileStream* fopen_nid_postfix(const char* filename, const char* mode) {
auto stream = std::make_unique<FileStream>(handle.get(), true);
handle.release();
std::fprintf(stderr, "fopen success: \"%s\"\n", filename);
APS5_LOG_OUT("success: \"%s\"", filename);
return stream.release();
}

View File

@ -8,7 +8,7 @@
extern "C" {
void* memset_nid_postfix(void* s, int c, size_t n) {
fprintf(stderr, "memset_nid_postfix: s=%p c=%d n=%zu\n", s, c, n);
APS5_LOG_OUT("s=%p c=%d n=%zu", s, c, n);
return std::memset(s, c, n);
}