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

@@ -72,20 +72,22 @@ constexpr T round_up(T value, V multiple, bool force_non_zero = true) {
return (value + multiple - 1) / multiple * multiple;
}
// Using the same conventions as in shading languages, returning 0 for NaN.
// std::max is `a < b ? b : a`, thus in case of NaN, the first argument is
// always returned. Also -0 is not < +0, so +0 is also chosen for it.
// For NaN, returns min_value (or, if it's NaN too, max_value).
// If either of the boundaries is zero, and if the value is at that boundary or
// 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>
constexpr T saturate_unsigned(T value) {
return std::min(static_cast<T>(1.0f), std::max(static_cast<T>(0.0f), value));
T clamp_float(T value, T min_value, T max_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
// should be converted to 0, not to -1), but this expectation is not needed most
// of time, and cannot be met for free (unlike for 0...1 clamping).
// Using the same conventions as in shading languages, returning 0 for NaN.
// 0 is always returned as positive.
template <typename T>
constexpr T saturate_signed(T value) {
return std::min(static_cast<T>(1.0f), std::max(static_cast<T>(-1.0f), value));
T saturate(T 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
@@ -365,12 +367,6 @@ inline uint64_t rotate_right(uint64_t v, uint8_t sh) {
}
#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
// Utilities for SSE values.
template <int N>

View File

@@ -16,12 +16,37 @@
#include <functional>
#include <string>
#include <string_view>
#include <type_traits>
#include "xenia/base/byte_order.h"
namespace xe {
namespace memory {
// For variable declarations (not return values or `this` pointer).
// Not propagated.
#define XE_RESTRICT_VAR __restrict
// Aliasing-safe bit reinterpretation.
// For more complex cases such as non-trivially-copyable types, write copying
// code respecting the requirements for them externally instead of using these
// functions.
template <typename Dst, typename Src>
void Reinterpret(Dst& XE_RESTRICT_VAR dst, const Src& XE_RESTRICT_VAR src) {
static_assert(sizeof(Dst) == sizeof(Src));
static_assert(std::is_trivially_copyable_v<Dst>);
static_assert(std::is_trivially_copyable_v<Src>);
std::memcpy(&dst, &src, sizeof(Dst));
}
template <typename Dst, typename Src>
Dst Reinterpret(const Src& XE_RESTRICT_VAR src) {
Dst dst;
Reinterpret(dst, src);
return dst;
}
#if XE_PLATFORM_ANDROID
void AndroidInitialize();
void AndroidShutdown();

View File

@@ -107,10 +107,11 @@ TEST_CASE("WinSystemClock <-> XSystemClock", "[clock_cast]") {
auto error2 = xsys.time_since_epoch() - wxsys.time_since_epoch();
auto error3 = wsys - wxsys;
REQUIRE(error1 < 10ms);
REQUIRE(error1 > -10ms);
REQUIRE(error2 < 10ms);
REQUIRE(error2 > -10ms);
// In AppVeyor, the difference often can be as large as roughly 16ms.
REQUIRE(error1 < 20ms);
REQUIRE(error1 > -20ms);
REQUIRE(error2 < 20ms);
REQUIRE(error2 > -20ms);
REQUIRE(error3 < duration);
REQUIRE(error3 > -duration);
}