agc: initialize interpolant mapping registers
This commit is contained in:
parent
1546e93d67
commit
ebd47081ca
|
|
@ -71,19 +71,6 @@ constexpr uint32_t NormalizeRegisterOffset(uint32_t raw_offset) {
|
|||
return raw_offset & ~RegisterSelectorMask;
|
||||
}
|
||||
|
||||
// Indirect Cx descriptors retain their selector. Selector 1 offsets 0..31 address the
|
||||
// SPI_PS_INPUT_CNTL register bank; ordinary context-register offsets remain unchanged.
|
||||
constexpr uint32_t DecodeIndirectCxRegisterOffset(uint32_t raw_offset) {
|
||||
const auto offset = NormalizeRegisterOffset(raw_offset);
|
||||
return (raw_offset & RegisterSelectorMask) == Pm4::CX_PS_SHADER_USAGE_BASE && offset < 32u
|
||||
? Pm4::SPI_PS_INPUT_CNTL_0 + offset
|
||||
: offset;
|
||||
}
|
||||
|
||||
static_assert(DecodeIndirectCxRegisterOffset(Pm4::CX_PS_SHADER_USAGE_BASE + 2u) ==
|
||||
Pm4::SPI_PS_INPUT_CNTL_0 + 2u);
|
||||
static_assert(DecodeIndirectCxRegisterOffset(Pm4::DB_Z_INFO) == Pm4::DB_Z_INFO);
|
||||
|
||||
bool ReleaseMemGcrNeedsBarrier(uint32_t eop_event_type, uint32_t gcr_cntl) {
|
||||
return eop_event_type != 0x28u ||
|
||||
(gcr_cntl & (GcrGl2MetadataInvalidate | GcrGl0VectorInvalidate | GcrGl1Invalidate |
|
||||
|
|
@ -2370,10 +2357,10 @@ KYTY_CP_OP_PARSER(CpOpIndirectCxRegs) {
|
|||
EXIT("indirect CX registers have null address, num_regs = %" PRIu32 "\n", indirect_num_dw);
|
||||
}
|
||||
for (uint32_t i = 0; i < indirect_num_dw; i++, indirect_buffer += 2) {
|
||||
// Keep the encoded offset for packet control values, and use the decoded offset only
|
||||
// for register dispatch.
|
||||
// Keep the encoded offset for packet control values, and use the normalized offset
|
||||
// only for register dispatch.
|
||||
auto raw_cmd_offset = indirect_buffer[0];
|
||||
auto cmd_offset = DecodeIndirectCxRegisterOffset(raw_cmd_offset);
|
||||
auto cmd_offset = NormalizeRegisterOffset(raw_cmd_offset);
|
||||
auto value = indirect_buffer[1];
|
||||
|
||||
if (HwCtxTrySetFakeRegister(cmd_offset, value)) {
|
||||
|
|
|
|||
|
|
@ -387,9 +387,6 @@ constexpr uint32_t SPI_SHADER_POS_FORMAT = 0x1C3;
|
|||
constexpr uint32_t SPI_SHADER_Z_FORMAT = 0x1C4;
|
||||
constexpr uint32_t SPI_SHADER_COL_FORMAT = 0x1C5;
|
||||
|
||||
// Indirect Cx descriptor selector for the 32-entry PS input-control register bank.
|
||||
constexpr uint32_t CX_PS_SHADER_USAGE_BASE = 0x10000000u;
|
||||
|
||||
constexpr uint32_t CB_BLEND0_CONTROL = 0x1E0;
|
||||
constexpr uint32_t CB_BLEND0_CONTROL_COLOR_SRCBLEND_SHIFT = 0;
|
||||
constexpr uint32_t CB_BLEND0_CONTROL_COLOR_SRCBLEND_MASK = 0x1F;
|
||||
|
|
|
|||
|
|
@ -1353,9 +1353,7 @@ static const ShaderSemantic* find_interpolant_output_semantic(const Shader* gs,
|
|||
}
|
||||
|
||||
static void set_interpolant_register(ShaderRegister* regs, uint32_t index, uint32_t value) {
|
||||
// Interpolant mappings contain encoded Cx descriptors. Indirect PM4 ingestion resolves
|
||||
// this selector and slot to the physical SPI_PS_INPUT_CNTL register.
|
||||
regs[index].offset = Pm4::CX_PS_SHADER_USAGE_BASE + index;
|
||||
regs[index].offset = Pm4::SPI_PS_INPUT_CNTL_0 + index;
|
||||
regs[index].value = value;
|
||||
}
|
||||
|
||||
|
|
@ -1407,6 +1405,96 @@ int KYTY_SYSV_ABI AgcCreateInterpolantMapping(ShaderRegister* regs, const Shader
|
|||
return OK;
|
||||
}
|
||||
|
||||
static uint32_t apply_interpolant_two_bit_field(uint32_t value, uint32_t field,
|
||||
uint32_t shift) {
|
||||
const auto mask = 0x3u << shift;
|
||||
return (value & ~mask) | ((field & 0x3u) << shift);
|
||||
}
|
||||
|
||||
static uint32_t apply_interpolant_final_mask(uint32_t flags, uint32_t source,
|
||||
uint32_t mask) {
|
||||
flags = (flags & 0xffffffe0u) | ((mask >> 8u) & 0x1fu);
|
||||
flags = (flags & 0xfffffbffu) |
|
||||
((source & 0x400000u) != 0 ? 0x400u : ((source >> 14u) & 0x400u));
|
||||
return flags;
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI AgcCreateInterpolantMapping2(ShaderRegister* regs, const Shader* gs,
|
||||
const Shader* ps) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t regs = 0x%016" PRIx64 "\n"
|
||||
"\t gs = 0x%016" PRIx64 "\n"
|
||||
"\t ps = 0x%016" PRIx64 "\n",
|
||||
reinterpret_cast<uint64_t>(regs), reinterpret_cast<uint64_t>(gs),
|
||||
reinterpret_cast<uint64_t>(ps));
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(regs == nullptr);
|
||||
EXIT_NOT_IMPLEMENTED(ps != nullptr && ps->num_input_semantics != 0 &&
|
||||
ps->input_semantics == nullptr);
|
||||
|
||||
if (ps == nullptr || ps->num_input_semantics == 0) {
|
||||
set_identity_interpolant_registers(regs, 0);
|
||||
return OK;
|
||||
}
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(gs == nullptr);
|
||||
EXIT_NOT_IMPLEMENTED(gs->num_output_semantics != 0 && gs->output_semantics == nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < ps->num_input_semantics; i++) {
|
||||
const auto source = shader_semantic_word(ps->input_semantics[i]);
|
||||
auto mask_index = static_cast<uint32_t>(gs->num_output_semantics);
|
||||
|
||||
for (uint32_t j = 0; j < gs->num_output_semantics; j++) {
|
||||
if (gs->output_semantics[j].semantic == static_cast<uint8_t>(source)) {
|
||||
mask_index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const bool has_mask = mask_index < gs->num_output_semantics;
|
||||
const auto mask = has_mask ? shader_semantic_word(gs->output_semantics[mask_index]) : 0u;
|
||||
const auto mode = (source >> 20u) & 0x3u;
|
||||
auto flags = 0u;
|
||||
|
||||
if (mode == 0) {
|
||||
flags = (((source >> 24u) & 0x1u) | (has_mask ? 0u : 1u)) << 5u;
|
||||
flags = apply_interpolant_two_bit_field(flags, source >> 28u, 8u);
|
||||
} else {
|
||||
flags = ((source << 4u) & 0x03000000u) + 0x80000u;
|
||||
|
||||
if (mode == 2) {
|
||||
flags &= 0xffefffdfu;
|
||||
flags |= has_mask ? ((~(mask & source) >> 16u) & 0x20u) : 0x20u;
|
||||
flags = apply_interpolant_two_bit_field(flags, source >> 30u, 8u);
|
||||
flags = apply_interpolant_two_bit_field(flags, source >> 30u, 21u);
|
||||
} else {
|
||||
if (has_mask) {
|
||||
const auto masked = mask & source;
|
||||
flags = (flags & 0xffffffdfu) | ((masked >> 15u) & 0x20u);
|
||||
flags ^= 0x20u;
|
||||
flags = (flags & 0xffefffffu) | ((~masked >> 1u) & 0x100000u);
|
||||
flags = apply_interpolant_two_bit_field(flags, source >> 28u, 8u);
|
||||
} else {
|
||||
flags |= 0x100020u;
|
||||
flags = apply_interpolant_two_bit_field(flags, source >> 28u, 8u);
|
||||
}
|
||||
flags = apply_interpolant_two_bit_field(flags, source >> 30u, 21u);
|
||||
}
|
||||
}
|
||||
|
||||
flags = has_mask ? apply_interpolant_final_mask(flags, source, mask)
|
||||
: (flags & 0xfffffbe0u);
|
||||
set_interpolant_register(regs, i, flags);
|
||||
}
|
||||
|
||||
if (ps->num_input_semantics < 32u) {
|
||||
set_identity_interpolant_registers(regs, ps->num_input_semantics);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI AgcGetDataPacketPayloadAddress(uint32_t** addr, uint32_t* cmd, int type) {
|
||||
PRINT_NAME();
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ int KYTY_SYSV_ABI AgcGetGsOversubscription(ShaderRegister* regs, const Shader* g
|
|||
float factor);
|
||||
int KYTY_SYSV_ABI AgcCreateInterpolantMapping(ShaderRegister* regs, const Shader* gs,
|
||||
const Shader* ps);
|
||||
int KYTY_SYSV_ABI AgcCreateInterpolantMapping2(ShaderRegister* regs, const Shader* gs,
|
||||
const Shader* ps);
|
||||
int KYTY_SYSV_ABI AgcGetDataPacketPayloadAddress(uint32_t** addr, uint32_t* cmd, int type);
|
||||
int KYTY_SYSV_ABI AgcGetDataPacketPayloadRange(MemoryRange* range, uint32_t* cmd, int type);
|
||||
int KYTY_SYSV_ABI AgcWriteDataPatchSetAddressOrOffset(uint32_t* cmd, uint64_t address_or_offset);
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
#include "libs/libs.h"
|
||||
#include "loader/symbolDatabase.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace Libs {
|
||||
|
||||
namespace LibGen5 {
|
||||
|
|
@ -13,143 +11,6 @@ LIB_VERSION("Graphics5", 1, "Graphics5", 1, 1);
|
|||
|
||||
namespace Gen5 = Graphics::Gen5;
|
||||
|
||||
template <class T>
|
||||
static T ReadUnaligned(const uint8_t* ptr, uint32_t offset) {
|
||||
T ret {};
|
||||
std::memcpy(&ret, ptr + offset, sizeof(T));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t BitExtract(uint32_t value, uint32_t start, uint32_t len) {
|
||||
return (value >> start) & ((1u << len) - 1u);
|
||||
}
|
||||
|
||||
static void Graphics5UnknownDbWriteDefault(uint64_t* out, uint32_t first) {
|
||||
constexpr uint64_t default_entry = 0x10000000ull;
|
||||
|
||||
for (uint32_t i = first; i < 32u; i++) {
|
||||
const auto low = static_cast<uint32_t>(default_entry) + i;
|
||||
const auto high = static_cast<uint32_t>(default_entry >> 37u) * 32u + i;
|
||||
out[i] = (static_cast<uint64_t>(high) << 32u) | low;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t Graphics5UnknownDbApplyTwoBitField(uint32_t value, uint32_t field, uint32_t shift) {
|
||||
const auto mask = 0x3u << shift;
|
||||
|
||||
switch (field & 0x3u) {
|
||||
case 0: return value & ~mask;
|
||||
case 1: return (value & ~mask) | (0x1u << shift);
|
||||
case 2: return (value & ~mask) | (0x2u << shift);
|
||||
default: return value | mask;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t Graphics5UnknownDbApplyFinalMask(uint32_t flags, uint32_t src,
|
||||
uint32_t mask_value) {
|
||||
flags &= 0xffffffe0u;
|
||||
flags |= BitExtract(mask_value, 8u, 5u);
|
||||
flags &= 0xfffffbffu;
|
||||
flags |= ((src & 0x400000u) != 0 ? 0x400u : ((src >> 14u) & 0x400u));
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI AgcUnknownDbOlWdppb4o(uint64_t arg0, uint64_t arg1, uint64_t arg2,
|
||||
uint64_t arg3, uint64_t arg4, uint64_t arg5) {
|
||||
PRINT_NAME();
|
||||
|
||||
(void)arg3;
|
||||
(void)arg4;
|
||||
(void)arg5;
|
||||
|
||||
auto* out = reinterpret_cast<uint64_t*>(arg0);
|
||||
|
||||
if (arg2 == 0) {
|
||||
Graphics5UnknownDbWriteDefault(out, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto* desc = reinterpret_cast<const uint8_t*>(arg1);
|
||||
const auto* src = reinterpret_cast<const uint8_t*>(arg2);
|
||||
|
||||
const auto count = ReadUnaligned<uint32_t>(src, 0x50u);
|
||||
|
||||
if (count == 0) {
|
||||
Graphics5UnknownDbWriteDefault(out, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto mask_count = ReadUnaligned<uint16_t>(desc, 0x56u);
|
||||
const auto* masks = reinterpret_cast<const uint32_t*>(ReadUnaligned<uint64_t>(desc, 0x38u));
|
||||
const auto* src_entries =
|
||||
reinterpret_cast<const uint32_t*>(ReadUnaligned<uint64_t>(src, 0x30u));
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
auto src_value = src_entries[i];
|
||||
auto mask_index = static_cast<uint32_t>(mask_count);
|
||||
|
||||
for (uint32_t j = 0; j < mask_count; j++) {
|
||||
if ((static_cast<uint8_t>(masks[j]) ^ static_cast<uint8_t>(src_value)) == 0) {
|
||||
mask_index = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const bool has_mask = (mask_index < mask_count);
|
||||
const auto mode = (src_value >> 20u) & 0x3u;
|
||||
auto flags = 0u;
|
||||
|
||||
if (mode == 0) {
|
||||
flags = (((src_value >> 24u) & 0x1u) | (has_mask ? 0u : 1u)) << 5u;
|
||||
flags = Graphics5UnknownDbApplyTwoBitField(flags, (src_value >> 28u) & 0x3u, 8u);
|
||||
} else {
|
||||
const auto shifted_mode = (src_value << 4u) & 0x03000000u;
|
||||
flags = shifted_mode + 0x80000u;
|
||||
|
||||
if (mode == 2) {
|
||||
flags &= 0xffefffdfu;
|
||||
if (has_mask) {
|
||||
flags |= ((~(masks[mask_index] & src_value) >> 16u) & 0x20u);
|
||||
} else {
|
||||
flags |= 0x20u;
|
||||
}
|
||||
flags = Graphics5UnknownDbApplyTwoBitField(flags, (src_value >> 30u) & 0x3u, 8u);
|
||||
flags = Graphics5UnknownDbApplyTwoBitField(flags, (src_value >> 30u) & 0x3u, 21u);
|
||||
} else {
|
||||
if (has_mask) {
|
||||
const auto masked = masks[mask_index] & src_value;
|
||||
flags &= 0xffffffdfu;
|
||||
flags |= (masked >> 15u) & 0x20u;
|
||||
flags ^= 0x20u;
|
||||
flags &= 0xffefffffu;
|
||||
flags |= ((~masked >> 1u) & 0x100000u);
|
||||
flags =
|
||||
Graphics5UnknownDbApplyTwoBitField(flags, (src_value >> 30u) & 0x3u, 8u);
|
||||
} else {
|
||||
flags |= 0x100020u;
|
||||
flags =
|
||||
Graphics5UnknownDbApplyTwoBitField(flags, (src_value >> 28u) & 0x3u, 8u);
|
||||
}
|
||||
flags = Graphics5UnknownDbApplyTwoBitField(flags, (src_value >> 30u) & 0x3u, 21u);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_mask) {
|
||||
flags = Graphics5UnknownDbApplyFinalMask(flags, src_value, masks[mask_index]);
|
||||
} else {
|
||||
flags &= 0xfffffbe0u;
|
||||
}
|
||||
|
||||
out[i] = (static_cast<uint64_t>(flags) << 32u) | (0x10000000u + i);
|
||||
}
|
||||
|
||||
if (count < 32u) {
|
||||
Graphics5UnknownDbWriteDefault(out, count);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIB_DEFINE(InitAgcDriver_1) {
|
||||
PRINT_NAME_ENABLE(true);
|
||||
|
||||
|
|
@ -182,7 +43,7 @@ LIB_DEFINE(InitAgcDriver_1) {
|
|||
LIB_FUNC("qj7QZpgr9Uw", Gen5::AgcDcbContextStateOp);
|
||||
LIB_FUNC("H6vHS5cidSA", Gen5::AgcDcbContextStateOpGetSize);
|
||||
LIB_FUNC("BfBDZGbti7A", Gen5::AgcGetIsTrinityMode);
|
||||
LIB_FUNC("dbOlWdppb4o", LibGen5::AgcUnknownDbOlWdppb4o);
|
||||
LIB_FUNC("dbOlWdppb4o", Gen5::AgcCreateInterpolantMapping2);
|
||||
|
||||
LIB_FUNC("F0ZXt5q0ZTA", Gen5::AgcDriverGetDefaultOwner);
|
||||
LIB_FUNC("F0Y42t-3e18", Gen5::AgcDriverInitResourceRegistration);
|
||||
|
|
|
|||
|
|
@ -5504,12 +5504,22 @@ void TestGraphicsCreateInterpolantMapping() {
|
|||
Check(Gen5::AgcCreateInterpolantMapping(regs, nullptr, nullptr) == 0,
|
||||
"null pixel shader interpolant mapping failed");
|
||||
for (uint32_t i = 0; i < 32u; i++) {
|
||||
Check(regs[i].offset == Pm4::CX_PS_SHADER_USAGE_BASE + i,
|
||||
Check(regs[i].offset == Pm4::SPI_PS_INPUT_CNTL_0 + i,
|
||||
"identity interpolant register offset was unexpected");
|
||||
Check(regs[i].value == i,
|
||||
"identity interpolant register value was unexpected");
|
||||
}
|
||||
|
||||
ShaderRegister native_regs[32] = {};
|
||||
Check(Gen5::AgcCreateInterpolantMapping2(native_regs, nullptr, nullptr) == 0,
|
||||
"native interpolant mapping identity path failed");
|
||||
for (uint32_t i = 0; i < 32u; i++) {
|
||||
Check(native_regs[i].offset == Pm4::SPI_PS_INPUT_CNTL_0 + i,
|
||||
"native interpolant register offset was unexpected");
|
||||
Check(native_regs[i].value == i,
|
||||
"native interpolant register value was unexpected");
|
||||
}
|
||||
|
||||
ShaderSemantic gs_semantics[3] = {};
|
||||
gs_semantics[0].semantic = 7;
|
||||
gs_semantics[0].hardware_mapping = 5;
|
||||
|
|
@ -5523,7 +5533,7 @@ void TestGraphicsCreateInterpolantMapping() {
|
|||
gs.output_semantics = gs_semantics;
|
||||
gs.num_output_semantics = static_cast<uint16_t>(std::size(gs_semantics));
|
||||
|
||||
ShaderSemantic ps_semantics[4] = {};
|
||||
ShaderSemantic ps_semantics[6] = {};
|
||||
ps_semantics[0].semantic = 7;
|
||||
ps_semantics[1].semantic = 8;
|
||||
ps_semantics[1].default_value = 2;
|
||||
|
|
@ -5535,6 +5545,13 @@ void TestGraphicsCreateInterpolantMapping() {
|
|||
ps_semantics[3].is_f16 = 1;
|
||||
ps_semantics[3].default_value = 3;
|
||||
ps_semantics[3].default_value_hi = 2;
|
||||
ps_semantics[4].semantic = 10;
|
||||
ps_semantics[4].is_f16 = 2;
|
||||
ps_semantics[4].default_value_hi = 3;
|
||||
ps_semantics[5].semantic = 11;
|
||||
ps_semantics[5].is_f16 = 1;
|
||||
ps_semantics[5].default_value = 2;
|
||||
ps_semantics[5].default_value_hi = 1;
|
||||
|
||||
Shader ps{};
|
||||
ps.input_semantics = ps_semantics;
|
||||
|
|
@ -5550,9 +5567,25 @@ void TestGraphicsCreateInterpolantMapping() {
|
|||
"flat/custom interpolant mapping bits were unexpected");
|
||||
Check(regs[3].value == 0x01580304u,
|
||||
"f16 interpolant mapping bits were unexpected");
|
||||
Check(regs[4].offset == Pm4::CX_PS_SHADER_USAGE_BASE + 4u &&
|
||||
regs[4].value == 4u,
|
||||
Check(regs[6].offset == Pm4::SPI_PS_INPUT_CNTL_0 + 6u &&
|
||||
regs[6].value == 6u,
|
||||
"interpolant identity tail was not filled");
|
||||
|
||||
Check(Gen5::AgcCreateInterpolantMapping2(native_regs, &gs, &ps) == 0,
|
||||
"native shader interpolant mapping failed");
|
||||
Check(native_regs[0].value == 0x00000005u &&
|
||||
native_regs[1].value == 0x00000220u &&
|
||||
native_regs[2].value == 0x0000052cu &&
|
||||
native_regs[3].value == 0x01580304u,
|
||||
"native shader interpolant values were unexpected");
|
||||
Check(native_regs[4].offset == Pm4::SPI_PS_INPUT_CNTL_0 + 4u &&
|
||||
native_regs[4].value == 0x02680324u &&
|
||||
native_regs[5].offset == Pm4::SPI_PS_INPUT_CNTL_0 + 5u &&
|
||||
native_regs[5].value == 0x01380220u,
|
||||
"native mode-specific interpolant values were unexpected");
|
||||
Check(native_regs[6].offset == Pm4::SPI_PS_INPUT_CNTL_0 + 6u &&
|
||||
native_regs[6].value == 6u,
|
||||
"native interpolant identity tail was not filled");
|
||||
}
|
||||
|
||||
void TestNewShaderRecompilerNativeWideScalarMemoryIr() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue