mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 06:40:17 +00:00
Pica: Rewrite Fix12P4 and move to pica_types.h
This commit is contained in:
parent
2d848836c1
commit
5d7dbf5807
@ -5,12 +5,154 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Pica {
|
||||
|
||||
/**
|
||||
* Class for storing and operating on Fixed point types using:
|
||||
*
|
||||
* - 12 integer bits
|
||||
* - 4 fraction bits
|
||||
* - Negative values in two's complement
|
||||
*
|
||||
* @todo Verify on HW where and how this is used.
|
||||
* @todo Create a template for more fixed point types and use this elsewhere too.
|
||||
*/
|
||||
class Fix12P4 final {
|
||||
public:
|
||||
constexpr Fix12P4() = default;
|
||||
constexpr Fix12P4(const Fix12P4&) = default;
|
||||
constexpr Fix12P4(Fix12P4&&) = default;
|
||||
constexpr explicit Fix12P4(int16_t raw) noexcept : value(raw) {}
|
||||
|
||||
Fix12P4& operator=(const Fix12P4&) = default;
|
||||
Fix12P4& operator=(Fix12P4&&) = default;
|
||||
|
||||
static constexpr Fix12P4 FromInt(int16_t int_val, uint16_t frac_val = 0) noexcept {
|
||||
return Fix12P4{static_cast<int16_t>(((int_val * 16) & IntMask()) | (frac_val & FracMask()))};
|
||||
}
|
||||
|
||||
static Fix12P4 FromFloat(float float_val) noexcept {
|
||||
return Fix12P4{static_cast<int16_t>(::round(float_val * 16.0f))};
|
||||
}
|
||||
|
||||
static constexpr Fix12P4 Zero() noexcept {
|
||||
return Fix12P4{static_cast<int16_t>(0)};
|
||||
}
|
||||
|
||||
static constexpr int16_t FracMask() noexcept {
|
||||
return static_cast<int16_t>(0xF);
|
||||
}
|
||||
|
||||
static constexpr int16_t IntMask() noexcept {
|
||||
return static_cast<int16_t>(~0xF);
|
||||
}
|
||||
|
||||
constexpr int16_t Int() const noexcept {
|
||||
return static_cast<int16_t>((value & IntMask()) / 16);
|
||||
}
|
||||
|
||||
constexpr uint16_t Frac() const noexcept {
|
||||
return static_cast<uint16_t>(value & FracMask());
|
||||
}
|
||||
|
||||
constexpr Fix12P4 Ceil() const noexcept {
|
||||
return Fix12P4{static_cast<int16_t>(value + FracMask())}.Floor();
|
||||
}
|
||||
|
||||
constexpr Fix12P4 Floor() const noexcept {
|
||||
return Fix12P4{static_cast<int16_t>(value & IntMask())};
|
||||
}
|
||||
|
||||
constexpr explicit operator int16_t() const noexcept {
|
||||
return value;
|
||||
}
|
||||
|
||||
constexpr Fix12P4 operator+() const noexcept {
|
||||
return Fix12P4{static_cast<int16_t>(+value)};
|
||||
}
|
||||
|
||||
constexpr Fix12P4 operator-() const noexcept {
|
||||
return Fix12P4{static_cast<int16_t>(-value)};
|
||||
}
|
||||
|
||||
constexpr Fix12P4 operator+(const Fix12P4& other) const noexcept {
|
||||
return Fix12P4{static_cast<int16_t>(value + other.value)};
|
||||
}
|
||||
|
||||
constexpr Fix12P4 operator-(const Fix12P4& other) const noexcept {
|
||||
return Fix12P4{static_cast<int16_t>(value - other.value)};
|
||||
}
|
||||
|
||||
constexpr Fix12P4 operator*(const Fix12P4& other) const noexcept {
|
||||
return Fix12P4{Multiply(value, other.value)};
|
||||
}
|
||||
|
||||
constexpr Fix12P4 operator/(const Fix12P4& other) const noexcept {
|
||||
return Fix12P4{Divide(value, other.value)};
|
||||
}
|
||||
|
||||
Fix12P4& operator+=(const Fix12P4& other) noexcept {
|
||||
value += other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Fix12P4& operator-=(const Fix12P4& other) noexcept {
|
||||
value -= other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Fix12P4& operator*=(const Fix12P4& other) noexcept {
|
||||
value = Multiply(value, other.value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Fix12P4& operator/=(const Fix12P4& other) noexcept {
|
||||
value = Divide(value, other.value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend constexpr bool operator<(const Fix12P4& left, const Fix12P4& right) noexcept {
|
||||
return left.value < right.value;
|
||||
}
|
||||
|
||||
friend constexpr bool operator>(const Fix12P4& left, const Fix12P4& right) noexcept {
|
||||
return operator<(right, left);
|
||||
}
|
||||
|
||||
friend constexpr bool operator>=(const Fix12P4& left, const Fix12P4& right) noexcept {
|
||||
return !operator<(left, right);
|
||||
}
|
||||
|
||||
friend constexpr bool operator<=(const Fix12P4& left, const Fix12P4& right) noexcept {
|
||||
return !operator<(right, left);
|
||||
}
|
||||
|
||||
friend constexpr bool operator==(const Fix12P4& left, const Fix12P4& right) noexcept {
|
||||
return left.value == right.value;
|
||||
}
|
||||
|
||||
friend constexpr bool operator!=(const Fix12P4& left, const Fix12P4& right) noexcept {
|
||||
return !operator==(left, right);
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr int16_t Multiply(int16_t left, int16_t right) noexcept {
|
||||
return static_cast<int16_t>((left * right) / 16);
|
||||
}
|
||||
|
||||
static constexpr int16_t Divide(int16_t left, int16_t right) noexcept {
|
||||
return static_cast<int16_t>((left * 16) / right);
|
||||
}
|
||||
|
||||
int16_t value = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Template class for converting arbitrary Pica float types to IEEE 754 32-bit single-precision
|
||||
* floating point.
|
||||
|
@ -257,73 +257,6 @@ static u8 PerformStencilAction(Regs::StencilAction action, u8 old_stencil, u8 re
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values
|
||||
struct Fix12P4 {
|
||||
Fix12P4() {}
|
||||
|
||||
static Fix12P4 FromRaw(s16 val) {
|
||||
Fix12P4 res;
|
||||
res.val = val;
|
||||
return res;
|
||||
}
|
||||
|
||||
static Fix12P4 FromInt(s16 intVal, u16 fracVal = 0) {
|
||||
return FromRaw(static_cast<s16>(((intVal * 16) & IntMask()) | (fracVal & FracMask())));
|
||||
}
|
||||
|
||||
static Fix12P4 FromFloat(float fltVal) {
|
||||
return FromRaw(static_cast<s16>(round(fltVal * 16.0f)));
|
||||
}
|
||||
|
||||
static Fix12P4 Zero() {
|
||||
return FromRaw(0);
|
||||
}
|
||||
|
||||
static u16 FracMask() { return 0xF; }
|
||||
static u16 IntMask() { return (u16)~0xF; }
|
||||
|
||||
s16 Int() const {
|
||||
return static_cast<s16>((val & IntMask()) / 16);
|
||||
}
|
||||
|
||||
u16 Frac() const {
|
||||
return static_cast<u16>(val & FracMask());
|
||||
}
|
||||
|
||||
Fix12P4 Ceil() const {
|
||||
return FromRaw(static_cast<s16>(val + FracMask())).Floor();
|
||||
}
|
||||
|
||||
Fix12P4 Floor() const {
|
||||
return FromRaw(static_cast<s16>(val & IntMask()));
|
||||
}
|
||||
|
||||
operator s16() const {
|
||||
return val;
|
||||
}
|
||||
|
||||
bool operator < (const Fix12P4& oth) const {
|
||||
return (s16)*this < (s16)oth;
|
||||
}
|
||||
|
||||
Fix12P4 operator + (const Fix12P4& oth) const {
|
||||
return FromRaw(val + oth.val);
|
||||
}
|
||||
|
||||
Fix12P4 operator / (const Fix12P4& oth) const {
|
||||
return FromRaw(static_cast<s16>((int)val * 16 / (int)oth.val));
|
||||
}
|
||||
|
||||
Fix12P4& operator += (const Fix12P4& oth) {
|
||||
val += oth.val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
s16 val;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate signed area of the triangle spanned by the three argument vertices.
|
||||
* The sign denotes an orientation.
|
||||
@ -333,8 +266,12 @@ private:
|
||||
static int SignedArea (const Math::Vec2<Fix12P4>& vtx1,
|
||||
const Math::Vec2<Fix12P4>& vtx2,
|
||||
const Math::Vec2<Fix12P4>& vtx3) {
|
||||
const auto vec1 = Math::MakeVec(vtx2 - vtx1, 0);
|
||||
const auto vec2 = Math::MakeVec(vtx3 - vtx1, 0);
|
||||
const auto vec1 = Math::MakeVec<int>(static_cast<s16>(vtx2.x) - static_cast<s16>(vtx1.x),
|
||||
static_cast<s16>(vtx2.y) - static_cast<s16>(vtx1.y),
|
||||
0);
|
||||
const auto vec2 = Math::MakeVec<int>(static_cast<s16>(vtx3.x) - static_cast<s16>(vtx1.x),
|
||||
static_cast<s16>(vtx3.y) - static_cast<s16>(vtx1.y),
|
||||
0);
|
||||
// TODO: There is a very small chance this will overflow for sizeof(int) == 4
|
||||
return Math::Cross(vec1, vec2).z;
|
||||
};
|
||||
@ -355,6 +292,9 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
|
||||
const auto& output_merger = regs.output_merger;
|
||||
MICROPROFILE_SCOPE(GPU_Rasterization);
|
||||
|
||||
// NOTE: Assuming that rasterizer coordinates are signed 12.4 fixed-point values.
|
||||
// This type is what PSP uses, we haven't tested what the 3DS uses.
|
||||
|
||||
// vertex positions in rasterizer coordinates
|
||||
static auto FloatToFix = [](float24 flt) {
|
||||
// TODO: Rounding in Fix12P4::FromFloat is necessary to prevent garbage pixels at
|
||||
@ -420,7 +360,11 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
|
||||
} else {
|
||||
// check if vertex is on our left => right side
|
||||
// TODO: Not sure how likely this is to overflow
|
||||
return (int)vtx.x < (int)line1.x + ((int)line2.x - (int)line1.x) * ((int)vtx.y - (int)line1.y) / ((int)line2.y - (int)line1.y);
|
||||
int line_dx = static_cast<s16>(line2.x) - static_cast<s16>(line1.x);
|
||||
int line_dy = static_cast<s16>(line2.y) - static_cast<s16>(line1.y);
|
||||
int line_vtx_dx = static_cast<s16>(vtx.x) - static_cast<s16>(line1.x);
|
||||
int line_vtx_dy = static_cast<s16>(vtx.y) - static_cast<s16>(line1.y);
|
||||
return line_vtx_dx < line_vtx_dy * line_dx / line_dy;
|
||||
}
|
||||
};
|
||||
int bias0 = IsRightSideOrFlatBottomEdge(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) ? -1 : 0;
|
||||
|
Loading…
Reference in New Issue
Block a user