[Base/GPU] Cleanup float comparisons and NaN and -0 in clamping
C++ relational operators are supposed to raise FE_INVALID if an argument is NaN, use std::isless/greater[equal] instead where they were easy to locate (though there are other places possibly, mostly min/max and clamp usage was checked). Also fixes a copy-paste error making the CPU shader interpreter execute MINs as MAXs instead.
This commit is contained in:
parent
f964290ea8
commit
a3304d252f
|
@ -921,7 +921,7 @@ void XmaContext::ConvertFrame(const uint8_t** samples, bool is_two_channel,
|
||||||
auto in = reinterpret_cast<const float*>(samples[j]);
|
auto in = reinterpret_cast<const float*>(samples[j]);
|
||||||
|
|
||||||
// Raw samples sometimes aren't within [-1, 1]
|
// Raw samples sometimes aren't within [-1, 1]
|
||||||
float scaled_sample = xe::saturate_signed(in[i]) * scale;
|
float scaled_sample = xe::clamp_float(in[i], -1.0f, 1.0f) * scale;
|
||||||
|
|
||||||
// Convert the sample and output it in big endian.
|
// Convert the sample and output it in big endian.
|
||||||
auto sample = static_cast<int16_t>(scaled_sample);
|
auto sample = static_cast<int16_t>(scaled_sample);
|
||||||
|
|
|
@ -60,20 +60,22 @@ constexpr T round_up(T value, V multiple, bool force_non_zero = true) {
|
||||||
return (value + multiple - 1) / multiple * multiple;
|
return (value + multiple - 1) / multiple * multiple;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using the same conventions as in shading languages, returning 0 for NaN.
|
// For NaN, returns min_value (or, if it's NaN too, max_value).
|
||||||
// std::max is `a < b ? b : a`, thus in case of NaN, the first argument is
|
// If either of the boundaries is zero, and if the value is at that boundary or
|
||||||
// always returned. Also -0 is not < +0, so +0 is also chosen for it.
|
// exceeds it, the result will have the sign of that boundary. If both
|
||||||
|
// boundaries are zero, which sign is selected among the argument signs is not
|
||||||
|
// explicitly defined.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr T saturate_unsigned(T value) {
|
T clamp_float(T value, T min_value, T max_value) {
|
||||||
return std::min(static_cast<T>(1.0f), std::max(static_cast<T>(0.0f), value));
|
float clamped_to_min = std::isgreater(value, min_value) ? value : min_value;
|
||||||
|
return std::isless(clamped_to_min, max_value) ? clamped_to_min : max_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This diverges from the GPU NaN rules for signed normalized formats (NaN
|
// Using the same conventions as in shading languages, returning 0 for NaN.
|
||||||
// should be converted to 0, not to -1), but this expectation is not needed most
|
// 0 is always returned as positive.
|
||||||
// of time, and cannot be met for free (unlike for 0...1 clamping).
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr T saturate_signed(T value) {
|
T saturate(T value) {
|
||||||
return std::min(static_cast<T>(1.0f), std::max(static_cast<T>(-1.0f), value));
|
return clamp_float(value, static_cast<T>(0.0f), static_cast<T>(1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the next power of two value that is greater than or equal to the given
|
// Gets the next power of two value that is greater than or equal to the given
|
||||||
|
@ -330,12 +332,6 @@ inline uint64_t rotate_left(uint64_t v, uint8_t sh) {
|
||||||
}
|
}
|
||||||
#endif // XE_PLATFORM_WIN32
|
#endif // XE_PLATFORM_WIN32
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T clamp(T value, T min_value, T max_value) {
|
|
||||||
const T t = value < min_value ? min_value : value;
|
|
||||||
return t > max_value ? max_value : t;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if XE_ARCH_AMD64
|
#if XE_ARCH_AMD64
|
||||||
// Utilities for SSE values.
|
// Utilities for SSE values.
|
||||||
template <int N>
|
template <int N>
|
||||||
|
|
|
@ -182,7 +182,7 @@ void DebugWindow::DrawFrame(ImGuiIO& io) {
|
||||||
ImVec2(kSplitterWidth, top_panes_height));
|
ImVec2(kSplitterWidth, top_panes_height));
|
||||||
if (ImGui::IsItemActive()) {
|
if (ImGui::IsItemActive()) {
|
||||||
function_pane_width += io.MouseDelta.x;
|
function_pane_width += io.MouseDelta.x;
|
||||||
function_pane_width = xe::clamp(function_pane_width, 30.0f, FLT_MAX);
|
function_pane_width = xe::clamp_float(function_pane_width, 30.0f, FLT_MAX);
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::BeginChild("##source_pane",
|
ImGui::BeginChild("##source_pane",
|
||||||
|
@ -194,7 +194,7 @@ void DebugWindow::DrawFrame(ImGuiIO& io) {
|
||||||
ImVec2(kSplitterWidth, top_panes_height));
|
ImVec2(kSplitterWidth, top_panes_height));
|
||||||
if (ImGui::IsItemActive()) {
|
if (ImGui::IsItemActive()) {
|
||||||
source_pane_width += io.MouseDelta.x;
|
source_pane_width += io.MouseDelta.x;
|
||||||
source_pane_width = xe::clamp(source_pane_width, 30.0f, FLT_MAX);
|
source_pane_width = xe::clamp_float(source_pane_width, 30.0f, FLT_MAX);
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::BeginChild("##registers_pane",
|
ImGui::BeginChild("##registers_pane",
|
||||||
|
@ -206,7 +206,8 @@ void DebugWindow::DrawFrame(ImGuiIO& io) {
|
||||||
ImVec2(kSplitterWidth, top_panes_height));
|
ImVec2(kSplitterWidth, top_panes_height));
|
||||||
if (ImGui::IsItemActive()) {
|
if (ImGui::IsItemActive()) {
|
||||||
registers_pane_width += io.MouseDelta.x;
|
registers_pane_width += io.MouseDelta.x;
|
||||||
registers_pane_width = xe::clamp(registers_pane_width, 30.0f, FLT_MAX);
|
registers_pane_width =
|
||||||
|
xe::clamp_float(registers_pane_width, 30.0f, FLT_MAX);
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::BeginChild("##right_pane", ImVec2(0, top_panes_height), true);
|
ImGui::BeginChild("##right_pane", ImVec2(0, top_panes_height), true);
|
||||||
|
@ -234,7 +235,7 @@ void DebugWindow::DrawFrame(ImGuiIO& io) {
|
||||||
ImGui::InvisibleButton("##hsplitter0", ImVec2(-1, kSplitterWidth));
|
ImGui::InvisibleButton("##hsplitter0", ImVec2(-1, kSplitterWidth));
|
||||||
if (ImGui::IsItemActive()) {
|
if (ImGui::IsItemActive()) {
|
||||||
bottom_panes_height -= io.MouseDelta.y;
|
bottom_panes_height -= io.MouseDelta.y;
|
||||||
bottom_panes_height = xe::clamp(bottom_panes_height, 30.0f, FLT_MAX);
|
bottom_panes_height = xe::clamp_float(bottom_panes_height, 30.0f, FLT_MAX);
|
||||||
}
|
}
|
||||||
ImGui::BeginChild("##log_pane", ImVec2(log_pane_width, bottom_panes_height),
|
ImGui::BeginChild("##log_pane", ImVec2(log_pane_width, bottom_panes_height),
|
||||||
true);
|
true);
|
||||||
|
@ -245,7 +246,8 @@ void DebugWindow::DrawFrame(ImGuiIO& io) {
|
||||||
ImVec2(kSplitterWidth, bottom_panes_height));
|
ImVec2(kSplitterWidth, bottom_panes_height));
|
||||||
if (ImGui::IsItemActive()) {
|
if (ImGui::IsItemActive()) {
|
||||||
breakpoints_pane_width -= io.MouseDelta.x;
|
breakpoints_pane_width -= io.MouseDelta.x;
|
||||||
breakpoints_pane_width = xe::clamp(breakpoints_pane_width, 30.0f, FLT_MAX);
|
breakpoints_pane_width =
|
||||||
|
xe::clamp_float(breakpoints_pane_width, 30.0f, FLT_MAX);
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::BeginChild("##breakpoints_pane", ImVec2(0, 0), true);
|
ImGui::BeginChild("##breakpoints_pane", ImVec2(0, 0), true);
|
||||||
|
|
|
@ -399,16 +399,11 @@ void GetHostViewportInfo(const RegisterFile& regs,
|
||||||
float offset_axis = offset_base_xy[i] + offset_add_xy[i];
|
float offset_axis = offset_base_xy[i] + offset_add_xy[i];
|
||||||
float scale_axis = scale_xy[i];
|
float scale_axis = scale_xy[i];
|
||||||
float scale_axis_abs = std::abs(scale_xy[i]);
|
float scale_axis_abs = std::abs(scale_xy[i]);
|
||||||
float axis_0 = offset_axis - scale_axis_abs;
|
|
||||||
float axis_1 = offset_axis + scale_axis_abs;
|
|
||||||
float axis_max_unscaled_float = float(xy_max_unscaled[i]);
|
float axis_max_unscaled_float = float(xy_max_unscaled[i]);
|
||||||
// max(0.0f, xy) drops NaN and < 0 - max picks the first argument in the
|
uint32_t axis_0_int = uint32_t(xe::clamp_float(
|
||||||
// !(a < b) case (always for NaN), min as float (axis_max_unscaled_float
|
offset_axis - scale_axis_abs, 0.0f, axis_max_unscaled_float));
|
||||||
// is well below 2^24) to safely drop very large values.
|
uint32_t axis_1_int = uint32_t(xe::clamp_float(
|
||||||
uint32_t axis_0_int =
|
offset_axis + scale_axis_abs, 0.0f, axis_max_unscaled_float));
|
||||||
uint32_t(std::min(axis_max_unscaled_float, std::max(0.0f, axis_0)));
|
|
||||||
uint32_t axis_1_int =
|
|
||||||
uint32_t(std::min(axis_max_unscaled_float, std::max(0.0f, axis_1)));
|
|
||||||
uint32_t axis_extent_int = axis_1_int - axis_0_int;
|
uint32_t axis_extent_int = axis_1_int - axis_0_int;
|
||||||
viewport_info_out.xy_offset[i] = axis_0_int * axis_resolution_scale;
|
viewport_info_out.xy_offset[i] = axis_0_int * axis_resolution_scale;
|
||||||
viewport_info_out.xy_extent[i] = axis_extent_int * axis_resolution_scale;
|
viewport_info_out.xy_extent[i] = axis_extent_int * axis_resolution_scale;
|
||||||
|
@ -511,8 +506,8 @@ void GetHostViewportInfo(const RegisterFile& regs,
|
||||||
// extension. But cases when this really matters are yet to be found -
|
// extension. But cases when this really matters are yet to be found -
|
||||||
// trying to fix this will result in more correct depth values, but
|
// trying to fix this will result in more correct depth values, but
|
||||||
// incorrect clipping.
|
// incorrect clipping.
|
||||||
z_min = xe::saturate_unsigned(host_clip_offset_z);
|
z_min = xe::saturate(host_clip_offset_z);
|
||||||
z_max = xe::saturate_unsigned(host_clip_offset_z + host_clip_scale_z);
|
z_max = xe::saturate(host_clip_offset_z + host_clip_scale_z);
|
||||||
// Direct3D 12 doesn't allow reverse depth range - on some drivers it
|
// Direct3D 12 doesn't allow reverse depth range - on some drivers it
|
||||||
// works, on some drivers it doesn't, actually, but it was never
|
// works, on some drivers it doesn't, actually, but it was never
|
||||||
// explicitly allowed by the specification.
|
// explicitly allowed by the specification.
|
||||||
|
@ -877,10 +872,10 @@ bool GetResolveInfo(const RegisterFile& regs, const Memory& memory,
|
||||||
GetScissor(regs, scissor, false);
|
GetScissor(regs, scissor, false);
|
||||||
int32_t scissor_right = int32_t(scissor.offset[0] + scissor.extent[0]);
|
int32_t scissor_right = int32_t(scissor.offset[0] + scissor.extent[0]);
|
||||||
int32_t scissor_bottom = int32_t(scissor.offset[1] + scissor.extent[1]);
|
int32_t scissor_bottom = int32_t(scissor.offset[1] + scissor.extent[1]);
|
||||||
x0 = xe::clamp(x0, int32_t(scissor.offset[0]), scissor_right);
|
x0 = std::clamp(x0, int32_t(scissor.offset[0]), scissor_right);
|
||||||
y0 = xe::clamp(y0, int32_t(scissor.offset[1]), scissor_bottom);
|
y0 = std::clamp(y0, int32_t(scissor.offset[1]), scissor_bottom);
|
||||||
x1 = xe::clamp(x1, int32_t(scissor.offset[0]), scissor_right);
|
x1 = std::clamp(x1, int32_t(scissor.offset[0]), scissor_right);
|
||||||
y1 = xe::clamp(y1, int32_t(scissor.offset[1]), scissor_bottom);
|
y1 = std::clamp(y1, int32_t(scissor.offset[1]), scissor_bottom);
|
||||||
|
|
||||||
assert_true(x0 <= x1 && y0 <= y1);
|
assert_true(x0 <= x1 && y0 <= y1);
|
||||||
|
|
||||||
|
|
|
@ -346,16 +346,18 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kMax: {
|
case ucode::AluVectorOpcode::kMax: {
|
||||||
for (uint32_t i = 0; i < 4; ++i) {
|
for (uint32_t i = 0; i < 4; ++i) {
|
||||||
vector_result[i] = vector_operands[0][i] >= vector_operands[1][i]
|
vector_result[i] =
|
||||||
? vector_operands[0][i]
|
std::isgreaterequal(vector_operands[0][i], vector_operands[1][i])
|
||||||
: vector_operands[1][i];
|
? vector_operands[0][i]
|
||||||
|
: vector_operands[1][i];
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kMin: {
|
case ucode::AluVectorOpcode::kMin: {
|
||||||
for (uint32_t i = 0; i < 4; ++i) {
|
for (uint32_t i = 0; i < 4; ++i) {
|
||||||
vector_result[i] = vector_operands[0][i] < vector_operands[1][i]
|
vector_result[i] =
|
||||||
? vector_operands[0][i]
|
std::isless(vector_operands[0][i], vector_operands[1][i])
|
||||||
: vector_operands[1][i];
|
? vector_operands[0][i]
|
||||||
|
: vector_operands[1][i];
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kSeq: {
|
case ucode::AluVectorOpcode::kSeq: {
|
||||||
|
@ -366,14 +368,14 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kSgt: {
|
case ucode::AluVectorOpcode::kSgt: {
|
||||||
for (uint32_t i = 0; i < 4; ++i) {
|
for (uint32_t i = 0; i < 4; ++i) {
|
||||||
vector_result[i] =
|
vector_result[i] = float(
|
||||||
float(vector_operands[0][i] > vector_operands[1][i]);
|
std::isgreater(vector_operands[0][i], vector_operands[1][i]));
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kSge: {
|
case ucode::AluVectorOpcode::kSge: {
|
||||||
for (uint32_t i = 0; i < 4; ++i) {
|
for (uint32_t i = 0; i < 4; ++i) {
|
||||||
vector_result[i] =
|
vector_result[i] = float(std::isgreaterequal(vector_operands[0][i],
|
||||||
float(vector_operands[0][i] >= vector_operands[1][i]);
|
vector_operands[1][i]));
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kSne: {
|
case ucode::AluVectorOpcode::kSne: {
|
||||||
|
@ -419,14 +421,14 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kCndGe: {
|
case ucode::AluVectorOpcode::kCndGe: {
|
||||||
for (uint32_t i = 0; i < 4; ++i) {
|
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[1][i]
|
||||||
: vector_operands[2][i];
|
: vector_operands[2][i];
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kCndGt: {
|
case ucode::AluVectorOpcode::kCndGt: {
|
||||||
for (uint32_t i = 0; i < 4; ++i) {
|
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[1][i]
|
||||||
: vector_operands[2][i];
|
: vector_operands[2][i];
|
||||||
}
|
}
|
||||||
|
@ -478,32 +480,38 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
float x_abs = std::abs(x), y_abs = std::abs(y), z_abs = std::abs(z);
|
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.
|
// Result is T coordinate, S coordinate, 2 * major axis, face ID.
|
||||||
if (z_abs >= x_abs && z_abs >= y_abs) {
|
if (z_abs >= x_abs && z_abs >= y_abs) {
|
||||||
|
bool z_negative = std::isless(z, 0.0f);
|
||||||
vector_result[0] = -y;
|
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[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) {
|
} 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[1] = x;
|
||||||
vector_result[2] = y;
|
vector_result[2] = y;
|
||||||
vector_result[3] = y < 0.0f ? 3.0f : 2.0f;
|
vector_result[3] = y_negative ? 3.0f : 2.0f;
|
||||||
} else {
|
} else {
|
||||||
|
bool x_negative = std::isless(x, 0.0f);
|
||||||
vector_result[0] = -y;
|
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[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;
|
vector_result[2] *= 2.0f;
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kMax4: {
|
case ucode::AluVectorOpcode::kMax4: {
|
||||||
if (vector_operands[0][0] >= vector_operands[0][1] &&
|
if (std::isgreaterequal(vector_operands[0][0], vector_operands[0][1]) &&
|
||||||
vector_operands[0][0] >= vector_operands[0][2] &&
|
std::isgreaterequal(vector_operands[0][0], vector_operands[0][2]) &&
|
||||||
vector_operands[0][0] >= vector_operands[0][3]) {
|
std::isgreaterequal(vector_operands[0][0], vector_operands[0][3])) {
|
||||||
vector_result[0] = vector_operands[0][0];
|
vector_result[0] = vector_operands[0][0];
|
||||||
} else if (vector_operands[0][1] >= vector_operands[0][2] &&
|
} else if (std::isgreaterequal(vector_operands[0][1],
|
||||||
vector_operands[0][1] >= vector_operands[0][3]) {
|
vector_operands[0][2]) &&
|
||||||
|
std::isgreaterequal(vector_operands[0][1],
|
||||||
|
vector_operands[0][3])) {
|
||||||
vector_result[0] = vector_operands[0][1];
|
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];
|
vector_result[0] = vector_operands[0][2];
|
||||||
} else {
|
} else {
|
||||||
vector_result[0] = vector_operands[0][3];
|
vector_result[0] = vector_operands[0][3];
|
||||||
|
@ -529,21 +537,21 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
replicate_vector_result_x = true;
|
replicate_vector_result_x = true;
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kSetpGtPush: {
|
case ucode::AluVectorOpcode::kSetpGtPush: {
|
||||||
state_.predicate =
|
state_.predicate = vector_operands[0][3] == 0.0f &&
|
||||||
vector_operands[0][3] == 0.0f && vector_operands[1][3] > 0.0f;
|
std::isgreater(vector_operands[1][3], 0.0f);
|
||||||
vector_result[0] =
|
vector_result[0] = (vector_operands[0][0] == 0.0f &&
|
||||||
(vector_operands[0][0] == 0.0f && vector_operands[1][0] > 0.0f)
|
std::isgreater(vector_operands[1][0], 0.0f))
|
||||||
? 0.0f
|
? 0.0f
|
||||||
: vector_operands[0][0] + 1.0f;
|
: vector_operands[0][0] + 1.0f;
|
||||||
replicate_vector_result_x = true;
|
replicate_vector_result_x = true;
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kSetpGePush: {
|
case ucode::AluVectorOpcode::kSetpGePush: {
|
||||||
state_.predicate =
|
state_.predicate = vector_operands[0][3] == 0.0f &&
|
||||||
vector_operands[0][3] == 0.0f && vector_operands[1][3] >= 0.0f;
|
std::isgreaterequal(vector_operands[1][3], 0.0f);
|
||||||
vector_result[0] =
|
vector_result[0] = (vector_operands[0][0] == 0.0f &&
|
||||||
(vector_operands[0][0] == 0.0f && vector_operands[1][0] >= 0.0f)
|
std::isgreaterequal(vector_operands[1][0], 0.0f))
|
||||||
? 0.0f
|
? 0.0f
|
||||||
: vector_operands[0][0] + 1.0f;
|
: vector_operands[0][0] + 1.0f;
|
||||||
replicate_vector_result_x = true;
|
replicate_vector_result_x = true;
|
||||||
} break;
|
} break;
|
||||||
// Not implementing pixel kill currently, the interpreter is currently
|
// Not implementing pixel kill currently, the interpreter is currently
|
||||||
|
@ -557,19 +565,19 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
replicate_vector_result_x = true;
|
replicate_vector_result_x = true;
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kKillGt: {
|
case ucode::AluVectorOpcode::kKillGt: {
|
||||||
vector_result[0] =
|
vector_result[0] = float(
|
||||||
float(vector_operands[0][0] > vector_operands[1][0] ||
|
std::isgreater(vector_operands[0][0], vector_operands[1][0]) ||
|
||||||
vector_operands[0][1] > vector_operands[1][1] ||
|
std::isgreater(vector_operands[0][1], vector_operands[1][1]) ||
|
||||||
vector_operands[0][2] > vector_operands[1][2] ||
|
std::isgreater(vector_operands[0][2], vector_operands[1][2]) ||
|
||||||
vector_operands[0][3] > vector_operands[1][3]);
|
std::isgreater(vector_operands[0][3], vector_operands[1][3]));
|
||||||
replicate_vector_result_x = true;
|
replicate_vector_result_x = true;
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kKillGe: {
|
case ucode::AluVectorOpcode::kKillGe: {
|
||||||
vector_result[0] =
|
vector_result[0] = float(
|
||||||
float(vector_operands[0][0] >= vector_operands[1][0] ||
|
std::isgreaterequal(vector_operands[0][0], vector_operands[1][0]) ||
|
||||||
vector_operands[0][1] >= vector_operands[1][1] ||
|
std::isgreaterequal(vector_operands[0][1], vector_operands[1][1]) ||
|
||||||
vector_operands[0][2] >= vector_operands[1][2] ||
|
std::isgreaterequal(vector_operands[0][2], vector_operands[1][2]) ||
|
||||||
vector_operands[0][3] >= vector_operands[1][3]);
|
std::isgreaterequal(vector_operands[0][3], vector_operands[1][3]));
|
||||||
replicate_vector_result_x = true;
|
replicate_vector_result_x = true;
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kKillNe: {
|
case ucode::AluVectorOpcode::kKillNe: {
|
||||||
|
@ -590,14 +598,13 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
vector_result[3] = vector_operands[1][3];
|
vector_result[3] = vector_operands[1][3];
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluVectorOpcode::kMaxA: {
|
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(
|
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) {
|
for (uint32_t i = 0; i < 4; ++i) {
|
||||||
vector_result[i] = vector_operands[0][i] >= vector_operands[1][i]
|
vector_result[i] =
|
||||||
? vector_operands[0][i]
|
std::isgreaterequal(vector_operands[0][i], vector_operands[1][i])
|
||||||
: vector_operands[1][i];
|
? vector_operands[0][i]
|
||||||
|
: vector_operands[1][i];
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
default: {
|
default: {
|
||||||
|
@ -702,7 +709,8 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
case ucode::AluScalarOpcode::kMulsPrev2: {
|
case ucode::AluScalarOpcode::kMulsPrev2: {
|
||||||
if (state_.previous_scalar == -FLT_MAX ||
|
if (state_.previous_scalar == -FLT_MAX ||
|
||||||
!std::isfinite(state_.previous_scalar) ||
|
!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;
|
state_.previous_scalar = -FLT_MAX;
|
||||||
} else {
|
} else {
|
||||||
// Direct3D 9 behavior (0 or denormal * anything = +0).
|
// Direct3D 9 behavior (0 or denormal * anything = +0).
|
||||||
|
@ -713,23 +721,26 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kMaxs: {
|
case ucode::AluScalarOpcode::kMaxs: {
|
||||||
state_.previous_scalar = scalar_operands[0] >= scalar_operands[1]
|
state_.previous_scalar =
|
||||||
? scalar_operands[0]
|
std::isgreaterequal(scalar_operands[0], scalar_operands[1])
|
||||||
: scalar_operands[1];
|
? scalar_operands[0]
|
||||||
|
: scalar_operands[1];
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kMins: {
|
case ucode::AluScalarOpcode::kMins: {
|
||||||
state_.previous_scalar = scalar_operands[0] >= scalar_operands[1]
|
state_.previous_scalar =
|
||||||
? scalar_operands[0]
|
std::isless(scalar_operands[0], scalar_operands[1])
|
||||||
: scalar_operands[1];
|
? scalar_operands[0]
|
||||||
|
: scalar_operands[1];
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kSeqs: {
|
case ucode::AluScalarOpcode::kSeqs: {
|
||||||
state_.previous_scalar = float(scalar_operands[0] == 0.0f);
|
state_.previous_scalar = float(scalar_operands[0] == 0.0f);
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kSgts: {
|
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;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kSges: {
|
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;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kSnes: {
|
case ucode::AluScalarOpcode::kSnes: {
|
||||||
state_.previous_scalar = float(scalar_operands[0] != 0.0f);
|
state_.previous_scalar = float(scalar_operands[0] != 0.0f);
|
||||||
|
@ -795,22 +806,20 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
state_.previous_scalar = 1.0f / std::sqrt(scalar_operands[0]);
|
state_.previous_scalar = 1.0f / std::sqrt(scalar_operands[0]);
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kMaxAs: {
|
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(
|
state_.address_register = int32_t(std::floor(
|
||||||
std::min(255.0f, std::max(-256.0f, scalar_operands[0])) + 0.5f));
|
xe::clamp_float(scalar_operands[0], -256.0f, 255.0f) + 0.5f));
|
||||||
state_.previous_scalar = scalar_operands[0] >= scalar_operands[1]
|
state_.previous_scalar =
|
||||||
? scalar_operands[0]
|
std::isgreaterequal(scalar_operands[0], scalar_operands[1])
|
||||||
: scalar_operands[1];
|
? scalar_operands[0]
|
||||||
|
: scalar_operands[1];
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kMaxAsf: {
|
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(
|
state_.address_register = int32_t(
|
||||||
std::floor(std::min(255.0f, std::max(-256.0f, scalar_operands[0]))));
|
std::floor(xe::clamp_float(scalar_operands[0], -256.0f, 255.0f)));
|
||||||
state_.previous_scalar = scalar_operands[0] >= scalar_operands[1]
|
state_.previous_scalar =
|
||||||
? scalar_operands[0]
|
std::isgreaterequal(scalar_operands[0], scalar_operands[1])
|
||||||
: scalar_operands[1];
|
? scalar_operands[0]
|
||||||
|
: scalar_operands[1];
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kSubs:
|
case ucode::AluScalarOpcode::kSubs:
|
||||||
case ucode::AluScalarOpcode::kSubsc0:
|
case ucode::AluScalarOpcode::kSubsc0:
|
||||||
|
@ -829,11 +838,11 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
state_.previous_scalar = float(!state_.predicate);
|
state_.previous_scalar = float(!state_.predicate);
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kSetpGt: {
|
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);
|
state_.previous_scalar = float(!state_.predicate);
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kSetpGe: {
|
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);
|
state_.previous_scalar = float(!state_.predicate);
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kSetpInv: {
|
case ucode::AluScalarOpcode::kSetpInv: {
|
||||||
|
@ -845,7 +854,7 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kSetpPop: {
|
case ucode::AluScalarOpcode::kSetpPop: {
|
||||||
float new_counter = scalar_operands[0] - 1.0f;
|
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;
|
state_.previous_scalar = state_.predicate ? 0.0f : new_counter;
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kSetpClr: {
|
case ucode::AluScalarOpcode::kSetpClr: {
|
||||||
|
@ -862,10 +871,11 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
state_.previous_scalar = float(scalar_operands[0] == 0.0f);
|
state_.previous_scalar = float(scalar_operands[0] == 0.0f);
|
||||||
} break;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kKillsGt: {
|
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;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kKillsGe: {
|
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;
|
} break;
|
||||||
case ucode::AluScalarOpcode::kKillsNe: {
|
case ucode::AluScalarOpcode::kKillsNe: {
|
||||||
state_.previous_scalar = float(scalar_operands[0] != 0.0f);
|
state_.previous_scalar = float(scalar_operands[0] != 0.0f);
|
||||||
|
@ -891,11 +901,11 @@ void ShaderInterpreter::ExecuteAluInstruction(ucode::AluInstruction instr) {
|
||||||
|
|
||||||
if (instr.vector_clamp()) {
|
if (instr.vector_clamp()) {
|
||||||
for (uint32_t i = 0; i < 4; ++i) {
|
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()
|
float scalar_result = instr.scalar_clamp()
|
||||||
? xe::saturate_unsigned(state_.previous_scalar)
|
? xe::saturate(state_.previous_scalar)
|
||||||
: state_.previous_scalar;
|
: state_.previous_scalar;
|
||||||
|
|
||||||
uint32_t scalar_result_write_mask = instr.GetScalarOpResultWriteMask();
|
uint32_t scalar_result_write_mask = instr.GetScalarOpResultWriteMask();
|
||||||
|
|
|
@ -1066,7 +1066,7 @@ void ProgressBar(float frac, float width, float height = 0,
|
||||||
if (height == 0) {
|
if (height == 0) {
|
||||||
height = ImGui::GetTextLineHeightWithSpacing();
|
height = ImGui::GetTextLineHeightWithSpacing();
|
||||||
}
|
}
|
||||||
frac = xe::saturate_unsigned(frac);
|
frac = xe::saturate(frac);
|
||||||
|
|
||||||
const auto fontAtlas = ImGui::GetIO().Fonts;
|
const auto fontAtlas = ImGui::GetIO().Fonts;
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace xenos {
|
||||||
float PWLGammaToLinear(float gamma) {
|
float PWLGammaToLinear(float gamma) {
|
||||||
// Not found in game executables, so just using the logic similar to that in
|
// Not found in game executables, so just using the logic similar to that in
|
||||||
// the Source Engine.
|
// the Source Engine.
|
||||||
gamma = xe::saturate_unsigned(gamma);
|
gamma = xe::saturate(gamma);
|
||||||
float scale, offset;
|
float scale, offset;
|
||||||
// While the compiled code for linear to gamma conversion uses `vcmpgtfp
|
// While the compiled code for linear to gamma conversion uses `vcmpgtfp
|
||||||
// constant, value` comparison (constant > value, or value < constant), it's
|
// constant, value` comparison (constant > value, or value < constant), it's
|
||||||
|
@ -68,7 +68,7 @@ float PWLGammaToLinear(float gamma) {
|
||||||
}
|
}
|
||||||
|
|
||||||
float LinearToPWLGamma(float linear) {
|
float LinearToPWLGamma(float linear) {
|
||||||
linear = xe::saturate_unsigned(linear);
|
linear = xe::saturate(linear);
|
||||||
float scale, offset;
|
float scale, offset;
|
||||||
// While the compiled code uses `vcmpgtfp constant, value` comparison
|
// While the compiled code uses `vcmpgtfp constant, value` comparison
|
||||||
// (constant > value, or value < constant), it's preferable to use `value >=
|
// (constant > value, or value < constant), it's preferable to use `value >=
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
|
#include "xenia/base/math.h"
|
||||||
#include "xenia/ui/graphics_util.h"
|
#include "xenia/ui/graphics_util.h"
|
||||||
#include "xenia/ui/presenter.h"
|
#include "xenia/ui/presenter.h"
|
||||||
|
|
||||||
|
@ -67,24 +68,19 @@ bool ImmediateDrawer::ScissorToRenderTarget(const ImmediateDraw& immediate_draw,
|
||||||
}
|
}
|
||||||
float render_target_width_float = float(render_target_width);
|
float render_target_width_float = float(render_target_width);
|
||||||
float render_target_height_float = float(render_target_height);
|
float render_target_height_float = float(render_target_height);
|
||||||
// Scale to render target coordinates, drop NaNs (by doing
|
// Scale to render target coordinates, drop NaNs, and clamp to the render
|
||||||
// std::max(0.0f, variable) in this argument order), and clamp to the render
|
|
||||||
// target size, below which the values are representable as 16p8 fixed-point.
|
// target size, below which the values are representable as 16p8 fixed-point.
|
||||||
float scale_x = render_target_width / coordinate_space_width();
|
float scale_x = render_target_width / coordinate_space_width();
|
||||||
float scale_y = render_target_height / coordinate_space_height();
|
float scale_y = render_target_height / coordinate_space_height();
|
||||||
float x0_float =
|
float x0_float = xe::clamp_float(immediate_draw.scissor_left * scale_x, 0.0f,
|
||||||
std::min(render_target_width_float,
|
render_target_width_float);
|
||||||
std::max(0.0f, immediate_draw.scissor_left * scale_x));
|
float y0_float = xe::clamp_float(immediate_draw.scissor_top * scale_y, 0.0f,
|
||||||
float y0_float =
|
render_target_height_float);
|
||||||
std::min(render_target_height_float,
|
|
||||||
std::max(0.0f, immediate_draw.scissor_top * scale_y));
|
|
||||||
// Also make sure the size is non-negative.
|
// Also make sure the size is non-negative.
|
||||||
float x1_float =
|
float x1_float = xe::clamp_float(immediate_draw.scissor_right * scale_x,
|
||||||
std::min(render_target_width_float,
|
x0_float, render_target_width_float);
|
||||||
std::max(x0_float, immediate_draw.scissor_right * scale_x));
|
float y1_float = xe::clamp_float(immediate_draw.scissor_bottom * scale_y,
|
||||||
float y1_float =
|
y0_float, render_target_height_float);
|
||||||
std::min(render_target_height_float,
|
|
||||||
std::max(y0_float, immediate_draw.scissor_bottom * scale_y));
|
|
||||||
// Top-left - include .5 (0.128 treated as 0 covered, 0.129 as 0 not covered).
|
// Top-left - include .5 (0.128 treated as 0 covered, 0.129 as 0 not covered).
|
||||||
int32_t x0 = (FloatToD3D11Fixed16p8(x0_float) + 127) >> 8;
|
int32_t x0 = (FloatToD3D11Fixed16p8(x0_float) + 127) >> 8;
|
||||||
int32_t y0 = (FloatToD3D11Fixed16p8(y0_float) + 127) >> 8;
|
int32_t y0 = (FloatToD3D11Fixed16p8(y0_float) + 127) >> 8;
|
||||||
|
|
|
@ -153,16 +153,16 @@ bool AndroidWindow::OnActivitySurfaceMotionEvent(jobject event) {
|
||||||
// with out-of-bounds coordinates), when moving the mouse outside the
|
// with out-of-bounds coordinates), when moving the mouse outside the
|
||||||
// View, or when starting moving the mouse when the pointer was previously
|
// View, or when starting moving the mouse when the pointer was previously
|
||||||
// outside the View in some cases.
|
// outside the View in some cases.
|
||||||
int32_t mouse_x = int32_t(
|
int32_t mouse_x =
|
||||||
std::min(float(GetActualPhysicalWidth()),
|
int32_t(xe::clamp_float(jni_env->CallFloatMethod(
|
||||||
std::max(0.0f, jni_env->CallFloatMethod(
|
event, jni_ids.motion_event_get_x, 0),
|
||||||
event, jni_ids.motion_event_get_x, 0))) +
|
0.0f, float(GetActualPhysicalWidth())) +
|
||||||
0.5f);
|
0.5f);
|
||||||
int32_t mouse_y = int32_t(
|
int32_t mouse_y =
|
||||||
std::min(float(GetActualPhysicalHeight()),
|
int32_t(xe::clamp_float(jni_env->CallFloatMethod(
|
||||||
std::max(0.0f, jni_env->CallFloatMethod(
|
event, jni_ids.motion_event_get_y, 0),
|
||||||
event, jni_ids.motion_event_get_y, 0))) +
|
0.0f, float(GetActualPhysicalHeight())) +
|
||||||
0.5f);
|
0.5f);
|
||||||
static const MouseEvent::Button kMouseEventButtons[] = {
|
static const MouseEvent::Button kMouseEventButtons[] = {
|
||||||
MouseEvent::Button::kLeft, MouseEvent::Button::kRight,
|
MouseEvent::Button::kLeft, MouseEvent::Button::kRight,
|
||||||
MouseEvent::Button::kMiddle, MouseEvent::Button::kX1,
|
MouseEvent::Button::kMiddle, MouseEvent::Button::kX1,
|
||||||
|
|
Loading…
Reference in New Issue