feat(log): log system detalization
This commit is contained in:
parent
13b30f93a9
commit
81d7adea95
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue