Merge branch 'master' of https://github.com/xenia-project/xenia into canary_experimental

This commit is contained in:
Gliniak
2024-05-31 22:43:59 +02:00
38 changed files with 3073 additions and 1908 deletions

View File

@@ -21,10 +21,7 @@ void ShaderInterpreter::Execute() {
state_.Reset();
const uint32_t* bool_constants =
&register_file_[XE_GPU_REG_SHADER_CONSTANT_BOOL_000_031].u32;
const xenos::LoopConstant* loop_constants =
reinterpret_cast<const xenos::LoopConstant*>(
&register_file_[XE_GPU_REG_SHADER_CONSTANT_LOOP_00].u32);
&register_file_[XE_GPU_REG_SHADER_CONSTANT_BOOL_000_031];
bool exec_ended = false;
uint32_t cf_index_next = 1;
@@ -133,8 +130,8 @@ void ShaderInterpreter::Execute() {
cf_index_next = cf_loop_start.address();
continue;
}
xenos::LoopConstant loop_constant =
loop_constants[cf_loop_start.loop_id()];
auto loop_constant = register_file_.Get<xenos::LoopConstant>(
XE_GPU_REG_SHADER_CONSTANT_LOOP_00 + cf_loop_start.loop_id());
state_.loop_constants[state_.loop_stack_depth] = loop_constant;
uint32_t& loop_iterator_ref =
state_.loop_iterators[state_.loop_stack_depth];
@@ -163,8 +160,11 @@ void ShaderInterpreter::Execute() {
&cf_instr);
xenos::LoopConstant loop_constant =
state_.loop_constants[state_.loop_stack_depth - 1];
assert_true(loop_constant.value ==
loop_constants[cf_loop_end.loop_id()].value);
assert_zero(
std::memcmp(&loop_constant,
&register_file_[XE_GPU_REG_SHADER_CONSTANT_LOOP_00 +
cf_loop_end.loop_id()],
sizeof(loop_constant)));
uint32_t loop_iterator =
++state_.loop_iterators[state_.loop_stack_depth - 1];
if (loop_iterator < loop_constant.count &&
@@ -250,28 +250,31 @@ void ShaderInterpreter::Execute() {
}
}
const float* ShaderInterpreter::GetFloatConstant(
const std::array<float, 4> ShaderInterpreter::GetFloatConstant(
uint32_t address, bool is_relative, bool relative_address_is_a0) const {
static const float zero[4] = {};
int32_t index = int32_t(address);
if (is_relative) {
index += relative_address_is_a0 ? state_.address_register
: state_.GetLoopAddress();
}
if (index < 0) {
return zero;
return std::array<float, 4>();
}
auto base_and_size_minus_1 = register_file_.Get<reg::SQ_VS_CONST>(
shader_type_ == xenos::ShaderType::kVertex ? XE_GPU_REG_SQ_VS_CONST
: XE_GPU_REG_SQ_PS_CONST);
if (uint32_t(index) > base_and_size_minus_1.size) {
return zero;
return std::array<float, 4>();
}
index += base_and_size_minus_1.base;
if (index >= 512) {
return zero;
return std::array<float, 4>();
}
return &register_file_[XE_GPU_REG_SHADER_CONSTANT_000_X + 4 * index].f32;
std::array<float, 4> value;
std::memcpy(value.data(),
&register_file_[XE_GPU_REG_SHADER_CONSTANT_000_X + 4 * index],
sizeof(float) * 4);
return value;
}
void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
@@ -290,6 +293,7 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
const float* vector_src_ptr;
uint32_t vector_src_register = instr.src_reg(1 + i);
bool vector_src_absolute = false;
std::array<float, 4> vector_src_float_constant;
if (instr.src_is_temp(1 + i)) {
vector_src_ptr = GetTempRegister(
ucode::AluInstruction::src_temp_reg(vector_src_register),
@@ -297,9 +301,10 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
vector_src_absolute = ucode::AluInstruction::is_src_temp_value_absolute(
vector_src_register);
} else {
vector_src_ptr = GetFloatConstant(
vector_src_float_constant = GetFloatConstant(
vector_src_register, instr.src_const_is_addressed(1 + i),
instr.is_const_address_register_relative());
vector_src_ptr = vector_src_float_constant.data();
}
uint32_t vector_src_absolute_mask =
~(uint32_t(vector_src_absolute) << 31);
@@ -334,16 +339,18 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
} break;
case ucode::AluVectorOpcode::kMax: {
for (uint32_t i = 0; i < 4; ++i) {
vector_result[i] = vector_operands[0][i] >= vector_operands[1][i]
? vector_operands[0][i]
: vector_operands[1][i];
vector_result[i] =
std::isgreaterequal(vector_operands[0][i], vector_operands[1][i])
? vector_operands[0][i]
: vector_operands[1][i];
}
} break;
case ucode::AluVectorOpcode::kMin: {
for (uint32_t i = 0; i < 4; ++i) {
vector_result[i] = vector_operands[0][i] < vector_operands[1][i]
? vector_operands[0][i]
: vector_operands[1][i];
vector_result[i] =
std::isless(vector_operands[0][i], vector_operands[1][i])
? vector_operands[0][i]
: vector_operands[1][i];
}
} break;
case ucode::AluVectorOpcode::kSeq: {
@@ -354,14 +361,14 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
} break;
case ucode::AluVectorOpcode::kSgt: {
for (uint32_t i = 0; i < 4; ++i) {
vector_result[i] =
float(vector_operands[0][i] > vector_operands[1][i]);
vector_result[i] = float(
std::isgreater(vector_operands[0][i], vector_operands[1][i]));
}
} break;
case ucode::AluVectorOpcode::kSge: {
for (uint32_t i = 0; i < 4; ++i) {
vector_result[i] =
float(vector_operands[0][i] >= vector_operands[1][i]);
vector_result[i] = float(std::isgreaterequal(vector_operands[0][i],
vector_operands[1][i]));
}
} break;
case ucode::AluVectorOpcode::kSne: {
@@ -407,14 +414,14 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
} break;
case ucode::AluVectorOpcode::kCndGe: {
for (uint32_t i = 0; i < 4; ++i) {
vector_result[i] = vector_operands[0][i] >= 0.0f
vector_result[i] = std::isgreaterequal(vector_operands[0][i], 0.0f)
? vector_operands[1][i]
: vector_operands[2][i];
}
} break;
case ucode::AluVectorOpcode::kCndGt: {
for (uint32_t i = 0; i < 4; ++i) {
vector_result[i] = vector_operands[0][i] > 0.0f
vector_result[i] = std::isgreater(vector_operands[0][i], 0.0f)
? vector_operands[1][i]
: vector_operands[2][i];
}
@@ -466,32 +473,38 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
float x_abs = std::abs(x), y_abs = std::abs(y), z_abs = std::abs(z);
// Result is T coordinate, S coordinate, 2 * major axis, face ID.
if (z_abs >= x_abs && z_abs >= y_abs) {
bool z_negative = std::isless(z, 0.0f);
vector_result[0] = -y;
vector_result[1] = z < 0.0f ? -x : x;
vector_result[1] = z_negative ? -x : x;
vector_result[2] = z;
vector_result[3] = z < 0.0f ? 5.0f : 4.0f;
vector_result[3] = z_negative ? 5.0f : 4.0f;
} else if (y_abs >= x_abs) {
vector_result[0] = y < 0.0f ? -z : z;
bool y_negative = std::isless(y, 0.0f);
vector_result[0] = y_negative ? -z : z;
vector_result[1] = x;
vector_result[2] = y;
vector_result[3] = y < 0.0f ? 3.0f : 2.0f;
vector_result[3] = y_negative ? 3.0f : 2.0f;
} else {
bool x_negative = std::isless(x, 0.0f);
vector_result[0] = -y;
vector_result[1] = x < 0.0f ? z : -z;
vector_result[1] = x_negative ? z : -z;
vector_result[2] = x;
vector_result[3] = x < 0.0f ? 1.0f : 0.0f;
vector_result[3] = x_negative ? 1.0f : 0.0f;
}
vector_result[2] *= 2.0f;
} break;
case ucode::AluVectorOpcode::kMax4: {
if (vector_operands[0][0] >= vector_operands[0][1] &&
vector_operands[0][0] >= vector_operands[0][2] &&
vector_operands[0][0] >= vector_operands[0][3]) {
if (std::isgreaterequal(vector_operands[0][0], vector_operands[0][1]) &&
std::isgreaterequal(vector_operands[0][0], vector_operands[0][2]) &&
std::isgreaterequal(vector_operands[0][0], vector_operands[0][3])) {
vector_result[0] = vector_operands[0][0];
} else if (vector_operands[0][1] >= vector_operands[0][2] &&
vector_operands[0][1] >= vector_operands[0][3]) {
} else if (std::isgreaterequal(vector_operands[0][1],
vector_operands[0][2]) &&
std::isgreaterequal(vector_operands[0][1],
vector_operands[0][3])) {
vector_result[0] = vector_operands[0][1];
} else if (vector_operands[0][2] >= vector_operands[0][3]) {
} else if (std::isgreaterequal(vector_operands[0][2],
vector_operands[0][3])) {
vector_result[0] = vector_operands[0][2];
} else {
vector_result[0] = vector_operands[0][3];
@@ -517,21 +530,21 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
replicate_vector_result_x = true;
} break;
case ucode::AluVectorOpcode::kSetpGtPush: {
state_.predicate =
vector_operands[0][3] == 0.0f && vector_operands[1][3] > 0.0f;
vector_result[0] =
(vector_operands[0][0] == 0.0f && vector_operands[1][0] > 0.0f)
? 0.0f
: vector_operands[0][0] + 1.0f;
state_.predicate = vector_operands[0][3] == 0.0f &&
std::isgreater(vector_operands[1][3], 0.0f);
vector_result[0] = (vector_operands[0][0] == 0.0f &&
std::isgreater(vector_operands[1][0], 0.0f))
? 0.0f
: vector_operands[0][0] + 1.0f;
replicate_vector_result_x = true;
} break;
case ucode::AluVectorOpcode::kSetpGePush: {
state_.predicate =
vector_operands[0][3] == 0.0f && vector_operands[1][3] >= 0.0f;
vector_result[0] =
(vector_operands[0][0] == 0.0f && vector_operands[1][0] >= 0.0f)
? 0.0f
: vector_operands[0][0] + 1.0f;
state_.predicate = vector_operands[0][3] == 0.0f &&
std::isgreaterequal(vector_operands[1][3], 0.0f);
vector_result[0] = (vector_operands[0][0] == 0.0f &&
std::isgreaterequal(vector_operands[1][0], 0.0f))
? 0.0f
: vector_operands[0][0] + 1.0f;
replicate_vector_result_x = true;
} break;
// Not implementing pixel kill currently, the interpreter is currently
@@ -545,19 +558,19 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
replicate_vector_result_x = true;
} break;
case ucode::AluVectorOpcode::kKillGt: {
vector_result[0] =
float(vector_operands[0][0] > vector_operands[1][0] ||
vector_operands[0][1] > vector_operands[1][1] ||
vector_operands[0][2] > vector_operands[1][2] ||
vector_operands[0][3] > vector_operands[1][3]);
vector_result[0] = float(
std::isgreater(vector_operands[0][0], vector_operands[1][0]) ||
std::isgreater(vector_operands[0][1], vector_operands[1][1]) ||
std::isgreater(vector_operands[0][2], vector_operands[1][2]) ||
std::isgreater(vector_operands[0][3], vector_operands[1][3]));
replicate_vector_result_x = true;
} break;
case ucode::AluVectorOpcode::kKillGe: {
vector_result[0] =
float(vector_operands[0][0] >= vector_operands[1][0] ||
vector_operands[0][1] >= vector_operands[1][1] ||
vector_operands[0][2] >= vector_operands[1][2] ||
vector_operands[0][3] >= vector_operands[1][3]);
vector_result[0] = float(
std::isgreaterequal(vector_operands[0][0], vector_operands[1][0]) ||
std::isgreaterequal(vector_operands[0][1], vector_operands[1][1]) ||
std::isgreaterequal(vector_operands[0][2], vector_operands[1][2]) ||
std::isgreaterequal(vector_operands[0][3], vector_operands[1][3]));
replicate_vector_result_x = true;
} break;
case ucode::AluVectorOpcode::kKillNe: {
@@ -578,14 +591,13 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
vector_result[3] = vector_operands[1][3];
} break;
case ucode::AluVectorOpcode::kMaxA: {
// std::max is `a < b ? b : a`, thus in case of NaN, the first argument
// (-256.0f) is always the result.
state_.address_register = int32_t(std::floor(
std::min(255.0f, std::max(-256.0f, vector_operands[0][3])) + 0.5f));
xe::clamp_float(vector_operands[0][3], -256.0f, 255.0f) + 0.5f));
for (uint32_t i = 0; i < 4; ++i) {
vector_result[i] = vector_operands[0][i] >= vector_operands[1][i]
? vector_operands[0][i]
: vector_operands[1][i];
vector_result[i] =
std::isgreaterequal(vector_operands[0][i], vector_operands[1][i])
? vector_operands[0][i]
: vector_operands[1][i];
}
} break;
default: {
@@ -611,6 +623,7 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
// r#/c#.w or r#/c#.wx.
const float* scalar_src_ptr;
uint32_t scalar_src_register = instr.src_reg(3);
std::array<float, 4> scalar_src_float_constant;
if (instr.src_is_temp(3)) {
scalar_src_ptr = GetTempRegister(
ucode::AluInstruction::src_temp_reg(scalar_src_register),
@@ -618,9 +631,10 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
scalar_src_absolute = ucode::AluInstruction::is_src_temp_value_absolute(
scalar_src_register);
} else {
scalar_src_ptr = GetFloatConstant(
scalar_src_float_constant = GetFloatConstant(
scalar_src_register, instr.src_const_is_addressed(3),
instr.is_const_address_register_relative());
scalar_src_ptr = scalar_src_float_constant.data();
}
uint32_t scalar_src_swizzle = instr.src_swizzle(3);
scalar_operand_component_count =
@@ -688,7 +702,8 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
case ucode::AluScalarOpcode::kMulsPrev2: {
if (state_.previous_scalar == -FLT_MAX ||
!std::isfinite(state_.previous_scalar) ||
!std::isfinite(scalar_operands[1]) || scalar_operands[1] <= 0.0f) {
!std::isfinite(scalar_operands[1]) ||
std::islessequal(scalar_operands[1], 0.0f)) {
state_.previous_scalar = -FLT_MAX;
} else {
// Direct3D 9 behavior (0 or denormal * anything = +0).
@@ -699,23 +714,26 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
}
} break;
case ucode::AluScalarOpcode::kMaxs: {
state_.previous_scalar = scalar_operands[0] >= scalar_operands[1]
? scalar_operands[0]
: scalar_operands[1];
state_.previous_scalar =
std::isgreaterequal(scalar_operands[0], scalar_operands[1])
? scalar_operands[0]
: scalar_operands[1];
} break;
case ucode::AluScalarOpcode::kMins: {
state_.previous_scalar = scalar_operands[0] >= scalar_operands[1]
? scalar_operands[0]
: scalar_operands[1];
state_.previous_scalar =
std::isless(scalar_operands[0], scalar_operands[1])
? scalar_operands[0]
: scalar_operands[1];
} break;
case ucode::AluScalarOpcode::kSeqs: {
state_.previous_scalar = float(scalar_operands[0] == 0.0f);
} break;
case ucode::AluScalarOpcode::kSgts: {
state_.previous_scalar = float(scalar_operands[0] > 0.0f);
state_.previous_scalar = float(std::isgreater(scalar_operands[0], 0.0f));
} break;
case ucode::AluScalarOpcode::kSges: {
state_.previous_scalar = float(scalar_operands[0] >= 0.0f);
state_.previous_scalar =
float(std::isgreaterequal(scalar_operands[0], 0.0f));
} break;
case ucode::AluScalarOpcode::kSnes: {
state_.previous_scalar = float(scalar_operands[0] != 0.0f);
@@ -781,22 +799,20 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
state_.previous_scalar = 1.0f / std::sqrt(scalar_operands[0]);
} break;
case ucode::AluScalarOpcode::kMaxAs: {
// std::max is `a < b ? b : a`, thus in case of NaN, the first argument
// (-256.0f) is always the result.
state_.address_register = int32_t(std::floor(
std::min(255.0f, std::max(-256.0f, scalar_operands[0])) + 0.5f));
state_.previous_scalar = scalar_operands[0] >= scalar_operands[1]
? scalar_operands[0]
: scalar_operands[1];
xe::clamp_float(scalar_operands[0], -256.0f, 255.0f) + 0.5f));
state_.previous_scalar =
std::isgreaterequal(scalar_operands[0], scalar_operands[1])
? scalar_operands[0]
: scalar_operands[1];
} break;
case ucode::AluScalarOpcode::kMaxAsf: {
// std::max is `a < b ? b : a`, thus in case of NaN, the first argument
// (-256.0f) is always the result.
state_.address_register = int32_t(
std::floor(std::min(255.0f, std::max(-256.0f, scalar_operands[0]))));
state_.previous_scalar = scalar_operands[0] >= scalar_operands[1]
? scalar_operands[0]
: scalar_operands[1];
std::floor(xe::clamp_float(scalar_operands[0], -256.0f, 255.0f)));
state_.previous_scalar =
std::isgreaterequal(scalar_operands[0], scalar_operands[1])
? scalar_operands[0]
: scalar_operands[1];
} break;
case ucode::AluScalarOpcode::kSubs:
case ucode::AluScalarOpcode::kSubsc0:
@@ -815,11 +831,11 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
state_.previous_scalar = float(!state_.predicate);
} break;
case ucode::AluScalarOpcode::kSetpGt: {
state_.predicate = scalar_operands[0] > 0.0f;
state_.predicate = std::isgreater(scalar_operands[0], 0.0f);
state_.previous_scalar = float(!state_.predicate);
} break;
case ucode::AluScalarOpcode::kSetpGe: {
state_.predicate = scalar_operands[0] >= 0.0f;
state_.predicate = std::isgreaterequal(scalar_operands[0], 0.0f);
state_.previous_scalar = float(!state_.predicate);
} break;
case ucode::AluScalarOpcode::kSetpInv: {
@@ -831,7 +847,7 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
} break;
case ucode::AluScalarOpcode::kSetpPop: {
float new_counter = scalar_operands[0] - 1.0f;
state_.predicate = new_counter <= 0.0f;
state_.predicate = std::islessequal(new_counter, 0.0f);
state_.previous_scalar = state_.predicate ? 0.0f : new_counter;
} break;
case ucode::AluScalarOpcode::kSetpClr: {
@@ -848,10 +864,11 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
state_.previous_scalar = float(scalar_operands[0] == 0.0f);
} break;
case ucode::AluScalarOpcode::kKillsGt: {
state_.previous_scalar = float(scalar_operands[0] > 0.0f);
state_.previous_scalar = float(std::isgreater(scalar_operands[0], 0.0f));
} break;
case ucode::AluScalarOpcode::kKillsGe: {
state_.previous_scalar = float(scalar_operands[0] >= 0.0f);
state_.previous_scalar =
float(std::isgreaterequal(scalar_operands[0], 0.0f));
} break;
case ucode::AluScalarOpcode::kKillsNe: {
state_.previous_scalar = float(scalar_operands[0] != 0.0f);
@@ -877,11 +894,11 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
if (instr.vector_clamp()) {
for (uint32_t i = 0; i < 4; ++i) {
vector_result[i] = xe::saturate_unsigned(vector_result[i]);
vector_result[i] = xe::saturate(vector_result[i]);
}
}
float scalar_result = instr.scalar_clamp()
? xe::saturate_unsigned(state_.previous_scalar)
? xe::saturate(state_.previous_scalar)
: state_.previous_scalar;
uint32_t scalar_result_write_mask = instr.GetScalarOpResultWriteMask();
@@ -977,10 +994,8 @@ void ShaderInterpreter::ExecuteVertexFetchInstruction(
state_.vfetch_full_last = instr;
}
xenos::xe_gpu_vertex_fetch_t fetch_constant =
*reinterpret_cast<const xenos::xe_gpu_vertex_fetch_t*>(
&register_file_[XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 +
state_.vfetch_full_last.fetch_constant_index()]);
xenos::xe_gpu_vertex_fetch_t fetch_constant = register_file_.GetVertexFetch(
state_.vfetch_full_last.fetch_constant_index());
if (!instr.is_mini_fetch()) {
// Get the part of the address that depends on vfetch_full data.