mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-02 12:56:05 +00:00
The legacy call takes no version and answered with the version 0 table. On a console it returns the running system software's table: 128 keyed entries over 79 context blocks on 10.x and 137 over 84 on 12.02 and 13.x, as ps5-vulkan measured and relies on. Version 0 holds 150 entries and its MRT0 block starts at 0x318 followed by 0x319, so PPSA99011 refused it even with the types fixed. Return the version 13 table, which is the 137-entry one.
111 lines
5.7 KiB
C++
111 lines
5.7 KiB
C++
#include "SceShaders.hpp"
|
|
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include "prx/libSceAgc/Shader/include/ShaderConstants.hpp"
|
|
#include <array>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
#include <span>
|
|
extern "C" int APS5_VABI sceAgcLinkShaders(ShaderRegister*, ShaderRegister*, const void*, const Shader*, const Shader*, std::uint32_t);
|
|
extern "C" void* APS5_VABI sceAgcGetRegisterDefaults();
|
|
extern "C" void* APS5_VABI sceAgcGetRegisterDefaults2(std::uint32_t);
|
|
static void Require(bool value) { if (!value) std::abort(); }
|
|
static unsigned preparations = 0;
|
|
static unsigned mappings = 0;
|
|
static unsigned links = 0;
|
|
static const Shader* mappedPixel = nullptr;
|
|
|
|
extern "C" void AgcDriverResolveGraphicsStagesAbi_nid_postfix(std::span<const Shader* const> stages, std::span<const ShaderRegister> context, std::span<const ShaderRegister> primitive) {
|
|
Require(!stages.empty() && stages[0] != nullptr && primitive.size() == 3u);
|
|
Require((stages.size() == 1u && context.size() == 2u) ||
|
|
(stages.size() == 2u && stages[1] == mappedPixel && context.size() == 34u));
|
|
++preparations;
|
|
}
|
|
|
|
extern "C" void AgcDriverResolveShaderAbi_nid_postfix(const Shader* shader, std::span<const ShaderRegister> context, std::span<const ShaderRegister> primitive) {
|
|
Require(shader != nullptr && context.size() == 32u && primitive.empty());
|
|
mappedPixel = shader;
|
|
++mappings;
|
|
}
|
|
|
|
extern "C" void AgcDriverResolveGraphicsAbi_nid_postfix(const Shader* vertex, const Shader* pixel, std::uint32_t primitiveType) {
|
|
Require(vertex != nullptr && (pixel == nullptr || pixel == mappedPixel) && (primitiveType == 0u || primitiveType == 2u || primitiveType == 4u));
|
|
++links;
|
|
}
|
|
int main() {
|
|
using namespace ShaderRegs;
|
|
auto* defaults = static_cast<unsigned char*>(sceAgcGetRegisterDefaults());
|
|
Require(defaults && defaults == sceAgcGetRegisterDefaults());
|
|
Require(defaults == sceAgcGetRegisterDefaults2(13));
|
|
// These are the byte offsets used by native callers, independent of the
|
|
// private C++ structure used to construct the defaults object.
|
|
ShaderRegister** contextBlocks = nullptr;
|
|
std::uint32_t contextCount = 0;
|
|
std::memcpy(&contextBlocks, defaults, sizeof(contextBlocks));
|
|
std::memcpy(&contextCount, defaults + 0x20, sizeof(contextCount));
|
|
Require(contextBlocks && contextBlocks[0] && contextCount == 488);
|
|
bool hasRenderTarget = false;
|
|
bool hasRasterizer = false;
|
|
for (std::uint32_t i = 0; i < contextCount; ++i) {
|
|
hasRenderTarget |= contextBlocks[0][i].offset == 0x318;
|
|
hasRasterizer |= contextBlocks[0][i].offset == 0x205;
|
|
}
|
|
Require(hasRenderTarget && hasRasterizer);
|
|
ShaderSpecialRegs special{};
|
|
special.vgt_shader_stages_en = {VGT_SHADER_STAGES_EN, 0x2000u};
|
|
special.vgt_gs_out_prim_type = {VGT_GS_OUT_PRIM_TYPE, 0};
|
|
special.ge_cntl = {GE_CNTL, 0x123};
|
|
special.ge_user_vgpr_en = {GE_USER_VGPR_EN, 7};
|
|
Shader vertex{};
|
|
vertex.type = static_cast<std::uint8_t>(ShaderBinaryType::Gs);
|
|
vertex.specials = &special;
|
|
Shader pixel{};
|
|
pixel.type = static_cast<std::uint8_t>(ShaderBinaryType::Ps);
|
|
std::array<ShaderRegister, 35> context{};
|
|
std::array<ShaderRegister, 4> primitive{};
|
|
context.back() = {0xdeadbeef, 0xcafebabe};
|
|
primitive.back() = context.back();
|
|
Require(sceAgcLinkShaders(context.data(), primitive.data(), nullptr, &vertex, &pixel, 4) == 0);
|
|
Require(context[0].offset == VGT_SHADER_STAGES_EN && context[0].value == 0x2000u);
|
|
Require(context[1].offset == VGT_GS_OUT_PRIM_TYPE && context[1].value == 2);
|
|
for (unsigned i = 0; i < 32; ++i)
|
|
Require(context[i + 2].offset == SPI_PS_INPUT_CNTL_0 + i && context[i + 2].value == i);
|
|
Require(primitive[0].offset == GE_CNTL && primitive[0].value == 0x123);
|
|
Require(primitive[1].offset == GE_USER_VGPR_EN && primitive[1].value == 7);
|
|
Require(primitive[2].offset == VGT_PRIMITIVE_TYPE && primitive[2].value == 4);
|
|
Require(context.back().value == 0xcafebabe && primitive.back().value == 0xcafebabe);
|
|
const auto savedContext = context;
|
|
const auto savedPrimitive = primitive;
|
|
pixel.num_input_semantics = 33;
|
|
Require(sceAgcLinkShaders(context.data(), primitive.data(), nullptr, &vertex, &pixel, 4) == GRAPHICS5_ERROR_INVALID_SHADER_PROGRAM);
|
|
Require(std::memcmp(context.data(), savedContext.data(), sizeof(context)) == 0);
|
|
Require(std::memcmp(primitive.data(), savedPrimitive.data(), sizeof(primitive)) == 0);
|
|
pixel.num_input_semantics = 0;
|
|
special.ge_cntl.offset = 0;
|
|
bool rejected = false;
|
|
try { sceAgcLinkShaders(context.data(), primitive.data(), nullptr, &vertex, &pixel, 4); }
|
|
catch (const std::runtime_error&) { rejected = true; }
|
|
Require(rejected);
|
|
Require(std::memcmp(context.data(), savedContext.data(), sizeof(context)) == 0);
|
|
special.ge_cntl.offset = GE_CNTL;
|
|
Require(sceAgcLinkShaders(context.data(), primitive.data(), nullptr, &vertex, nullptr, 2) == 0);
|
|
Require(context[1].value == 1 && primitive[2].value == 2);
|
|
ShaderSemantic output{};
|
|
output.semantic = 9;
|
|
output.hardware_mapping = 5;
|
|
vertex.output_semantics = &output;
|
|
vertex.num_output_semantics = 1;
|
|
ShaderSemantic input{};
|
|
input.semantic = 9;
|
|
input.is_flat_shaded = 1;
|
|
pixel.input_semantics = &input;
|
|
pixel.num_input_semantics = 1;
|
|
Require(sceAgcLinkShaders(context.data(), primitive.data(), nullptr, &vertex, &pixel, 4) == 0);
|
|
Require(context[2].offset == SPI_PS_INPUT_CNTL_0 && context[2].value == (5 | 0x400));
|
|
input.semantic = 10;
|
|
input.default_value = 2;
|
|
Require(sceAgcLinkShaders(context.data(), primitive.data(), nullptr, &vertex, &pixel, 4) == 0);
|
|
Require(context[2].value == 0x220);
|
|
Require(preparations == 7u && mappings == 3u && links == 7u);
|
|
}
|