1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-05 01:24:14 +01:00
dxvk/src/util/util_vector.h
Alpyne 5d29140f74 [util] replaceNaN: Use unaligned SIMD _mm_loadu_ps
There is no good reason to expect games will have aligned the data they're passing in.
2023-06-19 21:13:37 +01:00

169 lines
4.0 KiB
C++

#pragma once
#include <iostream>
#include "util_bit.h"
#include "util_math.h"
namespace dxvk {
template <typename T>
struct Vector4Base {
Vector4Base()
: x{ }, y{ }, z{ }, w{ } { }
Vector4Base(T splat)
: x(splat), y(splat), z(splat), w(splat) { }
Vector4Base(T x, T y, T z, T w)
: x(x), y(y), z(z), w(w) { }
Vector4Base(const T xyzw[4])
: x(xyzw[0]), y(xyzw[1]), z(xyzw[2]), w(xyzw[3]) { }
Vector4Base(const Vector4Base<T>& other) = default;
Vector4Base& operator=(const Vector4Base<T>& other) = default;
inline T& operator[](size_t index) { return data[index]; }
inline const T& operator[](size_t index) const { return data[index]; }
bool operator==(const Vector4Base<T>& other) const {
for (uint32_t i = 0; i < 4; i++) {
if (data[i] != other.data[i])
return false;
}
return true;
}
bool operator!=(const Vector4Base<T>& other) const {
return !operator==(other);
}
Vector4Base operator-() const { return {-x, -y, -z, -w}; }
Vector4Base operator+(const Vector4Base<T>& other) const {
return {x + other.x, y + other.y, z + other.z, w + other.w};
}
Vector4Base operator-(const Vector4Base<T>& other) const {
return {x - other.x, y - other.y, z - other.z, w - other.w};
}
Vector4Base operator*(T scalar) const {
return {scalar * x, scalar * y, scalar * z, scalar * w};
}
Vector4Base operator*(const Vector4Base<T>& other) const {
Vector4Base result;
for (uint32_t i = 0; i < 4; i++)
result[i] = data[i] * other.data[i];
return result;
}
Vector4Base operator/(const Vector4Base<T>& other) const {
Vector4Base result;
for (uint32_t i = 0; i < 4; i++)
result[i] = data[i] / other.data[i];
return result;
}
Vector4Base operator/(T scalar) const {
return {x / scalar, y / scalar, z / scalar, w / scalar};
}
Vector4Base& operator+=(const Vector4Base<T>& other) {
x += other.x;
y += other.y;
z += other.z;
w += other.w;
return *this;
}
Vector4Base& operator-=(const Vector4Base<T>& other) {
x -= other.x;
y -= other.y;
z -= other.z;
w -= other.w;
return *this;
}
Vector4Base& operator*=(T scalar) {
x *= scalar;
y *= scalar;
z *= scalar;
w *= scalar;
return *this;
}
Vector4Base& operator/=(T scalar) {
x /= scalar;
y /= scalar;
z /= scalar;
w /= scalar;
return *this;
}
union {
T data[4];
struct {
T x, y, z, w;
};
struct {
T r, g, b, a;
};
};
};
template <typename T>
inline Vector4Base<T> operator*(T scalar, const Vector4Base<T>& vector) {
return vector * scalar;
}
template <typename T>
float dot(const Vector4Base<T>& a, const Vector4Base<T>& b) {
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}
template <typename T>
T lengthSqr(const Vector4Base<T>& a) { return dot(a, a); }
template <typename T>
float length(const Vector4Base<T>& a) { return std::sqrt(float(lengthSqr(a))); }
template <typename T>
Vector4Base<T> normalize(const Vector4Base<T>& a) { return a * T(1.0f / length(a)); }
template <typename T>
std::ostream& operator<<(std::ostream& os, const Vector4Base<T>& v) {
return os << "Vector4(" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << ")";
}
using Vector4 = Vector4Base<float>;
using Vector4i = Vector4Base<int>;
static_assert(sizeof(Vector4) == sizeof(float) * 4);
static_assert(sizeof(Vector4i) == sizeof(int) * 4);
inline Vector4 replaceNaN(Vector4 a) {
#ifdef DXVK_ARCH_X86
Vector4 result;
__m128 value = _mm_loadu_ps(a.data);
__m128 mask = _mm_cmpeq_ps(value, value);
value = _mm_and_ps(value, mask);
_mm_store_ps(result.data, value);
return result;
#else
for (int i = 0; i < 4; i++)
a[i] = std::isnan(a[i]) ? 0.0f : a[i];
return a;
#endif
}
}