使用新的iFloat替代原先的ifloat_t

This commit is contained in:
2025-06-28 18:32:37 +08:00
parent 4db0f654ed
commit 8388f448f3
9 changed files with 1089 additions and 142 deletions
+2 -1
View File
@@ -15,7 +15,7 @@ set(DV_CORE_MATH_INCLUDE_FILES
include/math/dvc_matrix3.h
include/math/dvc_matrix4.h
include/math/dvc_math_util.h
include/math/dvc_fixmath.h
include/math/dvc_fix_point.h
)
source_group("include/math" FILES ${DV_CORE_MATH_INCLUDE_FILES})
@@ -26,6 +26,7 @@ set(DV_CORE_MATH_SOURCE_FILES
source/math/dvc_matrix3.cpp
source/math/dvc_matrix4.cpp
source/math/dvc_math_util.cpp
source/math/dvc_fix_point.cpp
)
source_group("source/math" FILES ${DV_CORE_MATH_SOURCE_FILES})
+456
View File
@@ -0,0 +1,456 @@
#pragma once
#include "dvc_config.h"
DV_CORE_BEGIN_NAMESPACE
class ifloat32
{
public:
static constexpr int32_t kShift = 16;
static constexpr float32_t kFloatScale = static_cast<float32_t>(1<<kShift); //65536.0
static constexpr float32_t kFloatInvScale = 1.f / kFloatScale;
static constexpr int32_t kZero_s1516 = 0;
static constexpr int32_t kOne_s1516 = 1 << kShift;
static constexpr int32_t kTwo_s1516 = 2 << kShift;
static constexpr int32_t kThree_s1516 = 3 << kShift;
static constexpr int32_t kFour_s1516 = 4 << kShift;
static constexpr int32_t kHalf_s1516 = kOne_s1516 >> 1;
static constexpr int32_t kPI_s1516 = 0x3243f;//(int32_t)(M_PI * kFloatScale);
static constexpr int32_t kPi2_s1516 = 0x6487e;
static constexpr int32_t kPiHalf_s1516 = 0x1921f;
static constexpr int32_t kE_s1516 = 0x2b7e1;
static constexpr int32_t kNegOne_s1516 = -1 << kShift;
static constexpr int32_t kMax_s1516 = 0x7fffff80; //(int32_t)(nextafter(INT32_MAX/kFloatScale, 0.f)*kFloatScale);
static constexpr int32_t kMax_int32 = kMax_s1516 >> kShift;
static constexpr float32_t kMax_float = (float32_t)kMax_s1516 * kFloatInvScale;
static constexpr int32_t kMin_s1516 = 0x80000000; // (int32_t)(nextafter(-INT32_MAX / ifloat32::kFloatScale, -FLT_MAX) * ifloat32::kFloatScale)
static constexpr int32_t kMin_int32 = kMin_s1516 >> kShift;
static constexpr float32_t kMin_float = (float32_t)kMin_s1516 * kFloatInvScale;
public:
ifloat32() : s1516(0) {}
ifloat32(const ifloat32& other) : s1516(other.s1516) {}
//Converts a float to a fixed-point value.
ifloat32(float32_t f) {
s1516 = static_cast<int32_t>(f * kFloatScale);
}
//Converts a double to a fixed-point value.
ifloat32(float64_t f) {
s1516 = static_cast<int32_t>(f * kFloatScale);
}
//Converts an integer to a fixed-point value.
ifloat32(int32_t n) {
s1516 = static_cast<int32_t>(n << kShift);
}
public:
//Converts into a float.
float32_t to_float() const {
return static_cast<float32_t>(s1516 * kFloatInvScale);
}
//Converts a fixed-point value into an integer by rounding it down to nearest integer. example: 3.94 -> 3, -2.1 -> -3
int32_t to_int32() const {
return static_cast<int32_t>(s1516 >> kShift);
}
public:
inline ifloat32& operator = (const ifloat32& other) {
s1516 = other.s1516;
return *this;
}
inline bool operator == (const ifloat32& other) const {
return (s1516 == other.s1516);
}
inline bool operator != (const ifloat32& other) const {
return (s1516 != other.s1516);
}
inline bool operator < (const ifloat32& other) const {
return (s1516 < other.s1516);
}
inline bool operator > (const ifloat32& other) const {
return (s1516 > other.s1516);
}
public:
inline ifloat32& operator += (const ifloat32 other) {
s1516 += other.s1516;
return *this;
}
inline ifloat32& operator -= (const ifloat32 other) {
s1516 -= other.s1516;
return *this;
}
public:
//Adds the two FP numbers together.
inline friend ifloat32 operator + (const ifloat32& l, const ifloat32& r) {
int64_t t = static_cast<int64_t>(l.s1516) + static_cast<int64_t>(r.s1516);
ifloat32 ret;
ret.s1516 = static_cast<int32_t>(t);
return ret;
}
//Subtracts the two FP numbers from each other.
inline friend ifloat32 operator - (const ifloat32& l, const ifloat32& r) {
int64_t t = static_cast<int64_t>(l.s1516) - static_cast<int64_t>(r.s1516);
ifloat32 ret;
ret.s1516 = t;
return ret;
}
inline friend ifloat32 operator * (const ifloat32& a, const float32_t& b) {
int64_t t = static_cast<int64_t>(a.s1516) * static_cast<int64_t>(b * kFloatScale);
t = t >> kShift;
ifloat32 ret;
ret.s1516 = t;
return ret;
}
inline friend ifloat32 operator * (const ifloat32& a, const int32_t& b) {
ifloat32 ret;
ret.s1516 = a.s1516 * b;
return ret;
}
//Multiplies two FP values together.
inline friend ifloat32 operator * (const ifloat32& a, const ifloat32& b) {
int64_t t = static_cast<int64_t>(a.s1516) * static_cast<int64_t>(b.s1516);
t = t >> kShift;
ifloat32 ret;
ret.s1516 = static_cast<int32_t>(t);
return ret;
}
inline friend ifloat32 operator / (const ifloat32& a, const ifloat32& b) {
// pre-multiply by the base
int64_t t = static_cast<int64_t>(a.s1516) << kShift;
t /= b.s1516;
ifloat32 ret;
ret.s1516 = static_cast<int32_t>(t);
return ret;
}
public:
int32_t s1516;
};
class ifloat64
{
public:
static constexpr int32_t kShift = 32;
static constexpr float32_t kFloatScale = static_cast<float32_t>(INT64_C(1) << kShift); //4294967296.0
static constexpr float32_t kFloatInvScale = 1.0f / kFloatScale;
static constexpr int64_t kFractionMask = (INT64_C(1) << kShift) - 1; // Space before INT64_C(1) needed because of hacky C++ code generator
//static_cast<int64_t>(nextafter(INT64_MAX / iFloat64::kFloatScale, 0.0) * iFloat64::kFloatScale);
static constexpr int64_t kMax_s3132 = INT64_C(0x7ffffffffffffc00);
static constexpr int32_t kMax_int32 = static_cast<int32_t>(kMax_s3132 >> kShift);
static constexpr float32_t kMax_float = 2.14748352e+09f; //nextafter(static_cast<float32_t>(kS3132_Max * kFloatInvScale), 0.0f);
//(int32_t)(nextafter(-INT64_MAX / iFloat64::kFloatScale, -DBL_MAX) * iFloat64::kFloatScale);
static constexpr int64_t kMin_s3132 = INT64_C(0x8000000000000000);
static constexpr int32_t kMin_int32 = static_cast<int32_t>(kMin_s3132 >> kShift);
static constexpr float32_t kMin_float = static_cast<float64_t>(kMin_s3132 * kFloatInvScale);
// special value
static DV_CORE_API const ifloat64 kMax;
static DV_CORE_API const ifloat64 kMin;
static DV_CORE_API const ifloat64 kZero;
static DV_CORE_API const ifloat64 kOne;
static DV_CORE_API const ifloat64 kTwo;
static DV_CORE_API const ifloat64 kThree;
static DV_CORE_API const ifloat64 kFour;
static DV_CORE_API const ifloat64 kHalf;
static DV_CORE_API const ifloat64 kPi;
static DV_CORE_API const ifloat64 kPi2;
static DV_CORE_API const ifloat64 kPiHalf;
static DV_CORE_API const ifloat64 kE;
static DV_CORE_API const ifloat64 kNegOne;
public:
ifloat64() : s3132(0) {}
ifloat64(const ifloat64& other) : s3132(other.s3132) {}
//Converts a float to a fixed-point value.
ifloat64(float32_t f) {
s3132 = static_cast<int64_t>(std::round(f * kFloatScale));
}
//Converts a double to a fixed-point value.
ifloat64(float64_t f) {
s3132 = static_cast<int64_t>(std::round(f * kFloatScale));
}
//Converts an integer to a fixed-point value.
ifloat64(int32_t n) {
s3132 = static_cast<int64_t>(n) << kShift;
}
private:
ifloat64(int64_t _s3132) {
s3132 = _s3132;
}
public:
//Converts into a float.
float32_t to_float() const {
return static_cast<float32_t>(s3132 * kFloatInvScale);
}
//Converts a fixed-point value into an integer by rounding it down to nearest integer. example: 3.94 -> 3, -2.1 -> -3
int32_t to_int32() const {
return static_cast<int32_t>(s3132 >> kShift);
}
public:
inline const ifloat64& operator + () const {
return *this;
}
inline ifloat64 operator - () const {
return ifloat64(-s3132);
}
inline ifloat64& operator = (const ifloat64& other) {
s3132 = other.s3132;
return *this;
}
inline bool operator == (const ifloat64& other) const {
return (s3132 == other.s3132);
}
inline bool operator != (const ifloat64& other) const {
return (s3132 != other.s3132);
}
inline bool operator < (const ifloat64& other) const {
return (s3132 < other.s3132);
}
inline bool operator > (const ifloat64& other) const {
return (s3132 > other.s3132);
}
public:
inline ifloat64& operator += (const ifloat64 other) {
s3132 += other.s3132;
return *this;
}
inline ifloat64& operator -= (const ifloat64 other) {
s3132 -= other.s3132;
return *this;
}
public:
//Adds the two FP numbers together.
inline friend ifloat64 operator + (const ifloat64& a, const ifloat64& b) {
ifloat64 ret;
ret.s3132 = a.s3132 + b.s3132;
return ret;
}
//Subtracts the two FP numbers from each other.
inline friend ifloat64 operator - (const ifloat64& a, const ifloat64& b) {
ifloat64 ret;
ret.s3132 = a.s3132 - b.s3132;
return ret;
}
inline friend ifloat64 operator * (const ifloat64& a, const int32_t& b) {
ifloat64 ret;
ret.s3132 = a.s3132 * b;
return ret;
}
inline friend ifloat64 operator * (const ifloat64& a, const float32_t& b) {
ifloat64 ret;
ret.s3132 = _safeMulti(a.s3132, static_cast<int64_t>(b * kFloatScale));
return ret;
}
//Multiplies two FP values together.
inline friend ifloat64 operator * (const ifloat64& a, const ifloat64& b) {
ifloat64 ret;
ret.s3132 = _safeMulti(a.s3132, b.s3132);
return ret;
}
inline friend ifloat64 operator / (const ifloat64& a, const ifloat64& b) {
// From http://www.hackersdelight.org/hdcodetxt/divlu.c.txt
int64_t sign_dif = a.s3132 ^ b.s3132;
static const uint64_t B = INT64_C(0x100000000); // Number base (32 bits)
uint64_t abs_a = (uint64_t)((a.s3132 < 0) ? -a.s3132 : a.s3132);
uint64_t u1 = abs_a >> 32;
uint64_t u0 = abs_a << 32;
uint64_t v = (uint64_t)((b.s3132 < 0) ? -b.s3132 : b.s3132);
// Overflow?
if (u1 >= v)
{
//invalid number
ifloat64 ret;
ret.s3132 = 0x7fffffffffffffff;
return ret;
}
// Shift amount for norm
int32_t s = _nlz(v); // 0 <= s <= 63
v = v << s; // Normalize the divisor
uint64_t vn1 = v >> 32; // Break the divisor into two 32-bit digits
uint64_t vn0 = v & INT64_C(0xffffffff);
uint64_t un32 = (u1 << s) | (u0 >> (64 - s)) & (uint64_t)((int64_t)-s >> 63);
uint64_t un10 = u0 << s; // Shift dividend left
uint64_t un1 = un10 >> 32; // Break the right half of dividend into two digits
uint64_t un0 = un10 & INT64_C(0xffffffff);
// Compute the first quotient digit, q1
uint64_t q1 = un32 / vn1;
uint64_t rhat = un32 - q1 * vn1;
do
{
if ((q1 >= B) || ((q1 * vn0) > (B * rhat + un1)))
{
q1 = q1 - 1;
rhat = rhat + vn1;
}
else break;
} while (rhat < B);
uint64_t un21 = un32 * B + un1 - q1 * v; // Multiply and subtract
// Compute the second quotient digit, q0
uint64_t q0 = un21 / vn1;
rhat = un21 - q0 * vn1;
do
{
if ((q0 >= B) || ((q0 * vn0) > (B * rhat + un0)))
{
q0 = q0 - 1;
rhat = rhat + vn1;
}
else break;
} while (rhat < B);
// Calculate the remainder
// uint64_t r = (un21 * b + un0 - q0 * v) >> s;
// rem = (int64_t)r;
int64_t t = q1 * B + q0;
ifloat64 ret;
ret.s3132 = (sign_dif < 0) ? -(int64_t)t : (int64_t)t;
return ret;
}
public:
static int64_t _safeMulti(const int64_t a, const int64_t b) {
int64_t sign_diff = a ^ b;
uint64_t abs_a = a < 0 ? -a : a;
uint64_t abs_b = b < 0 ? -b : b;
uint64_t ai = abs_a >> kShift;
uint64_t af = (abs_a & kFractionMask);
uint64_t bi = abs_b >> kShift;
uint64_t bf = (abs_b & kFractionMask);
// (Ai+Af)*(Bi+Bf)=Af*Bf + Ai*(Bi+Bf) + Af*Bi
int64_t t = ((af * bf) >> kShift) + ai * abs_b + af * bi;
return (sign_diff < 0) ? -t : t;
}
static int32_t _nlz(uint64_t x)
{
int32_t n = 0;
if (x <= INT64_C(0x00000000FFFFFFFF)) { n = n + 32; x = x << 32; }
if (x <= INT64_C(0x0000FFFFFFFFFFFF)) { n = n + 16; x = x << 16; }
if (x <= INT64_C(0x00FFFFFFFFFFFFFF)) { n = n + 8; x = x << 8; }
if (x <= INT64_C(0x0FFFFFFFFFFFFFFF)) { n = n + 4; x = x << 4; }
if (x <= INT64_C(0x3FFFFFFFFFFFFFFF)) { n = n + 2; x = x << 2; }
if (x <= INT64_C(0x7FFFFFFFFFFFFFFF)) { n = n + 1; }
if (x == 0) return 64;
return n;
}
public:
int64_t s3132;
};
typedef ifloat32 iFloat32;
typedef ifloat64 iFloat64;
typedef ifloat64 iFloat;
struct iFloat2
{
iFloat x, y;
iFloat2() : x(0), y(0) {}
iFloat2(const iFloat2& other) : x(other.x), y(other.y) {}
iFloat2(float32_t _x, float32_t _y) : x(_x), y(_y) {}
};
struct iFloat3
{
iFloat x, y, z;
inline void add(const iFloat3& other) {
x += other.x;
y += other.y;
z += other.z;
}
inline void sub(const iFloat3& other) {
x -= other.x;
y -= other.y;
z -= other.z;
}
inline void mul(const iFloat& multiplier) {
x = x * multiplier;
y = y * multiplier;
z = z * multiplier;
}
inline iFloat operator [] (const size_t i) const {
return *(&x + i);
}
inline iFloat& operator [] (const size_t i) {
return *(&x + i);
}
iFloat3() : x(0), y(0), z(0) {}
iFloat3(const iFloat3& other) : x(other.x), y(other.y), z(other.z) {}
iFloat3(float32_t _x, float32_t _y, float32_t _z) : x(_x), y(_y), z(_z) {}
iFloat3(iFloat _x, iFloat _y, iFloat _z) : x(_x), y(_y), z(_z) {}
};
DV_CORE_END_NAMESPACE
-98
View File
@@ -1,98 +0,0 @@
#pragma once
#include "dvc_config.h"
DV_CORE_BEGIN_NAMESPACE
typedef int64_t ifloat_t;
//typedef int64_t ifloat2_t[2];
//typedef int64_t ifloat3_t[3];
#define IFLOAT_SHIFT (16)
#define IFLOAT_SCALE ((float64_t)(1<<IFLOAT_SHIFT))
//-------------------------------------------------------------------------------------
inline ifloat_t ifloat_init(float32_t a)
{
return (ifloat_t)((float64_t)a * IFLOAT_SCALE + 0.5);
}
//-------------------------------------------------------------------------------------
inline ifloat_t ifloat_init(int32_t a)
{
return (int64_t)(a)<< IFLOAT_SHIFT;
}
//-------------------------------------------------------------------------------------
inline float32_t ifloat_get_float(ifloat_t a)
{
return (float32_t)((float64_t)a/ IFLOAT_SCALE);
}
//-------------------------------------------------------------------------------------
inline ifloat_t ifloat_multiply(ifloat_t a, ifloat_t b)
{
return (ifloat_t)((a * b) >> IFLOAT_SHIFT);
}
//-------------------------------------------------------------------------------------
//inline void ifloat3_add(ifloat3_t& a, const ifloat3_t& b)
//{
// a[0] += b[0]; a[1] += b[1]; a[2] += b[2];
//}
//-------------------------------------------------------------------------------------
//inline void ifloat3_sub(ifloat3_t& a, const ifloat3_t& b)
//{
// a[0] -= b[0]; a[1] -= b[1]; a[2] -= b[2];
//}
//-------------------------------------------------------------------------------------
//inline void ifloat3_cpy(ifloat3_t& a, const ifloat3_t& b)
//{
// a[0] = b[0]; a[1] = b[1]; a[2] = b[2];
//}
//-------------------------------------------------------------------------------------
struct ifloat2_t
{
ifloat_t x, y;
ifloat2_t() : x(0ll), y(0ll) {}
ifloat2_t(const ifloat2_t& other) : x(other.x), y(other.y) {}
ifloat2_t(float32_t _x, float32_t _y) : x(ifloat_init(_x)), y(ifloat_init(_y)) {}
};
struct ifloat3_t
{
ifloat_t x, y, z;
inline void add(const ifloat3_t& other) {
x += other.x;
y += other.y;
z += other.z;
}
inline void sub(const ifloat3_t& other) {
x -= other.x;
y -= other.y;
z -= other.z;
}
inline ifloat_t operator [] (const size_t i) const {
return *(&x + i);
}
inline ifloat_t& operator [] (const size_t i) {
return *(&x + i);
}
ifloat3_t() : x(0ll), y(0ll), z(0ll) {}
ifloat3_t(const ifloat3_t& other) : x(other.x), y(other.y), z(other.z) {}
ifloat3_t(float32_t _x, float32_t _y, float32_t _z) : x(ifloat_init(_x)), y(ifloat_init(_y)), z(ifloat_init(_z)) {}
ifloat3_t(ifloat_t _x, ifloat_t _y, ifloat_t _z) : x(_x), y(_y), z(_z) {}
};
DV_CORE_END_NAMESPACE
+15 -1
View File
@@ -21,10 +21,24 @@ public:
public:
typedef std::function<void(const std::pair<int32_t, int32_t>& pos, const fVector3& percent)> DrawTriangleCallback;
struct DebugParam
{
bool debug;
const char* szOutputFileName;
int32_t x;
int32_t y;
FILE* fpOutput;
int32_t tile_id;
int32_t coarse_id;
int32_t fine_id;
int32_t edge_id;
};
//Larrabee algorithm
static void drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight,
const fVector2& v0, const fVector2& v1, const fVector2& v2,
DrawTriangleCallback callback, bool ccw=true);
DrawTriangleCallback callback, bool ccw=true, const DebugParam* debugParam=nullptr);
//Scaleline algorithm
static void drawTriangleScanline(int32_t canvasWidth, int32_t canvasHeight,
+20
View File
@@ -0,0 +1,20 @@
#include "math/dvc_fix_point.h"
DV_CORE_BEGIN_NAMESPACE
const ifloat64 ifloat64::kMax{ ifloat64::kMax_s3132 };
const ifloat64 ifloat64::kMin{ ifloat64::kMin_s3132 };
const ifloat64 ifloat64::kZero{ 0 };
const ifloat64 ifloat64::kOne{ INT64_C(1) << ifloat64::kShift };
const ifloat64 ifloat64::kTwo{ INT64_C(2) << kShift };
const ifloat64 ifloat64::kThree{ INT64_C(3) << ifloat64::kShift };
const ifloat64 ifloat64::kFour{ INT64_C(4) << ifloat64::kShift };
const ifloat64 ifloat64::kHalf{ INT64_C(1) << (ifloat64::kShift-1) };
const ifloat64 ifloat64::kPi{ INT64_C(0x3243f6a89) }; //static_cast<int64_t>(std::round(M_PI * kFloatScale));
const ifloat64 ifloat64::kPi2{ INT64_C(0x6487ed511) };
const ifloat64 ifloat64::kPiHalf{ INT64_C(0x1921fb544) };
const ifloat64 ifloat64::kE{ INT64_C(0x2b7e15163) };
const ifloat64 ifloat64::kNegOne{ INT64_C(-1) << kShift };
DV_CORE_END_NAMESPACE
@@ -1,5 +1,5 @@
#include "pipe/dvc_rasterizer.h"
#include "math/dvc_fixmath.h"
#include "math/dvc_fix_point.h"
#include "math/dvc_math_util.h"
/*
@@ -21,7 +21,8 @@ struct DrawTriangleParam
float32_t bbox_max_y;
bool tlBorder[3];
float32_t area;
ifloat3_t edgesDX, edgesDY;
iFloat3 edgesDX, edgesDY;
Rasterizer::DebugParam debugParam;
};
//-------------------------------------------------------------------------------------
@@ -29,10 +30,15 @@ enum { TILE_WIDTH_IN_PIXELS = 64, COARSE_BLOCK_WIDTH_IN_PIXELS = 16, FINE_BLOCK_
//-------------------------------------------------------------------------------------
void _drawTriangle_Fine(int32_t tile_id, int32_t coarse_id, int32_t fine_id,
const DrawTriangleParam& param, const ifloat3_t& edges0, uint32_t testEdgeMask,
const DrawTriangleParam& param, const iFloat3& edges0, uint32_t testEdgeMask,
Rasterizer::DrawTriangleCallback callback)
{
ifloat3_t pixelEdges(edges0);
iFloat3 kHalfDX = param.edgesDX; kHalfDX.mul(iFloat::kHalf);
iFloat3 kHalfDY = param.edgesDY; kHalfDY.mul(iFloat::kHalf);
iFloat3 pixelEdges(edges0);
pixelEdges.sub(kHalfDY);
pixelEdges.add(kHalfDX);
const fVector2 v0(param.verts[0]), v1(param.verts[1]), v2(param.verts[2]);
const bool edgeMask[3] = { (testEdgeMask & 1) != 0 , (testEdgeMask & 2) != 0 , (testEdgeMask & 4) != 0 };
@@ -45,10 +51,39 @@ void _drawTriangle_Fine(int32_t tile_id, int32_t coarse_id, int32_t fine_id,
for (int32_t y_index=0, y= fine_start_y; y_index < 4; y_index++, y++)
{
ifloat3_t edgesRow(pixelEdges);
iFloat3 edgesRow(pixelEdges);
for (int32_t x_index = 0, x=fine_start_x; x_index < 4; x_index++, x++)
{
if (param.debugParam.debug)
{
if (x == param.debugParam.x && y == param.debugParam.y)
{
iFloat3 LBEdges(edges0);
LBEdges.sub(kHalfDY);
LBEdges.add(kHalfDX);
fprintf(param.debugParam.fpOutput, "======= Fine =======\n");
fprintf(param.debugParam.fpOutput, "LeftBottom=[%d,%d](%f,%f)\n", fine_start_x, fine_start_y, fine_start_x+0.5f, fine_start_y+0.5f);
fprintf(param.debugParam.fpOutput, "Edge0=(%f,%f,%f)[%lld,%lld,%lld]\n",
edges0.x.to_float(), edges0.y.to_float(), edges0.z.to_float(),
edges0.x.s3132, edges0.y.s3132, edges0.z.s3132
);
fprintf(param.debugParam.fpOutput, "Edge0+0.5=(%f,%f,%f)[%lld,%lld,%lld]\n",
LBEdges.x.to_float(), LBEdges.y.to_float(), LBEdges.z.to_float(),
LBEdges.x.s3132, LBEdges.y.s3132, LBEdges.z.s3132
);
fprintf(param.debugParam.fpOutput, "======= Pixel =======\n");
fprintf(param.debugParam.fpOutput, "Position=[%d,%d](%f,%f)\n", x, y, x+0.5f, y+0.5f);
fprintf(param.debugParam.fpOutput, "IndexInFind=[%d,%d]\n", x_index, y_index);
fprintf(param.debugParam.fpOutput, "Edge=(%f,%f,%f)[%lld,%lld,%lld]\n",
edgesRow.x.to_float(), edgesRow.y.to_float(), edgesRow.z.to_float(),
edgesRow.x.s3132, edgesRow.y.s3132, edgesRow.z.s3132
);
}
}
bool rejected =
(edgeMask[0] && (edgesRow.x < 0 || (!param.tlBorder[0] && edgesRow.x == 0))) ||
(edgeMask[1] && (edgesRow.y < 0 || (!param.tlBorder[1] && edgesRow.y == 0))) ||
@@ -74,24 +109,24 @@ void _drawTriangle_Fine(int32_t tile_id, int32_t coarse_id, int32_t fine_id,
//-------------------------------------------------------------------------------------
void _drawTriangle_Coarse(int32_t tile_id, int32_t coarse_id,
DrawTriangleParam& param, const ifloat3_t& edges0, uint32_t testEdgeMask,
DrawTriangleParam& param, const iFloat3& edges0, uint32_t testEdgeMask,
Rasterizer::DrawTriangleCallback callback)
{
const ifloat3_t blockEdgesDX(
const iFloat3 blockEdgesDX(
param.edgesDX.x * FINE_BLOCK_WIDTH_IN_PIXELS,
param.edgesDX.y * FINE_BLOCK_WIDTH_IN_PIXELS,
param.edgesDX.z * FINE_BLOCK_WIDTH_IN_PIXELS
);
const ifloat3_t blockEdgesDY(
const iFloat3 blockEdgesDY(
param.edgesDY.x * FINE_BLOCK_WIDTH_IN_PIXELS,
param.edgesDY.y * FINE_BLOCK_WIDTH_IN_PIXELS,
param.edgesDY.z * FINE_BLOCK_WIDTH_IN_PIXELS
);
const bool edgeMask[3] = { (testEdgeMask & 1) != 0 , (testEdgeMask & 2) != 0 , (testEdgeMask & 4) != 0 };
ifloat3_t blockReject(edges0);
ifloat3_t blockAccept(edges0);
ifloat3_t blockEdges(edges0);
iFloat3 blockReject(edges0);
iFloat3 blockAccept(edges0);
iFloat3 blockEdges(edges0);
for (size_t v = 0; v < 3; v++)
{
@@ -117,8 +152,8 @@ void _drawTriangle_Coarse(int32_t tile_id, int32_t coarse_id,
if (block_start_y + (y_index + 1)*FINE_BLOCK_WIDTH_IN_PIXELS >= param.bbox_min_y)
{
ifloat3_t edgesRow(blockEdges);
ifloat3_t edgesRowReject, edgesRowAccept;
iFloat3 edgesRow(blockEdges);
iFloat3 edgesRowReject, edgesRowAccept;
for (size_t v = 0; v < 3; v++)
{
@@ -182,25 +217,25 @@ void _drawTriangle_Coarse(int32_t tile_id, int32_t coarse_id,
//-------------------------------------------------------------------------------------
void _drawTriangle_Title(int32_t tile_id,
DrawTriangleParam& param, const ifloat3_t& edges0, uint32_t testEdgeMask,
DrawTriangleParam& param, const iFloat3& edges0, uint32_t testEdgeMask,
Rasterizer::DrawTriangleCallback callback)
{
const ifloat3_t blockEdgesDX(
const iFloat3 blockEdgesDX(
param.edgesDX[0] * COARSE_BLOCK_WIDTH_IN_PIXELS,
param.edgesDX[1] * COARSE_BLOCK_WIDTH_IN_PIXELS,
param.edgesDX[2] * COARSE_BLOCK_WIDTH_IN_PIXELS
);
const ifloat3_t blockEdgesDY(
const iFloat3 blockEdgesDY(
param.edgesDY[0] * COARSE_BLOCK_WIDTH_IN_PIXELS,
param.edgesDY[1] * COARSE_BLOCK_WIDTH_IN_PIXELS,
param.edgesDY[2] * COARSE_BLOCK_WIDTH_IN_PIXELS
);
const bool edgeMask[3] = { (testEdgeMask & 1) != 0 , (testEdgeMask & 2) != 0 , (testEdgeMask & 4) != 0 };
ifloat3_t blockReject(edges0);
ifloat3_t blockAccept(edges0);
ifloat3_t blockEdges(edges0);
iFloat3 blockReject(edges0);
iFloat3 blockAccept(edges0);
iFloat3 blockEdges(edges0);
for (size_t v = 0; v < 3; v++)
{
@@ -226,8 +261,8 @@ void _drawTriangle_Title(int32_t tile_id,
if (block_start_y + (y_index + 1)*COARSE_BLOCK_WIDTH_IN_PIXELS >= param.bbox_min_y)
{
ifloat3_t edges(blockEdges);
ifloat3_t edgesRowReject, edgesRowAccept;
iFloat3 edges(blockEdges);
iFloat3 edgesRowReject, edgesRowAccept;
for (size_t v = 0; v < 3; v++)
{
@@ -298,7 +333,7 @@ void _drawTriangle_Title(int32_t tile_id,
//-------------------------------------------------------------------------------------
void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight,
const fVector2& v0, const fVector2& v1, const fVector2& v2,
DrawTriangleCallback callback, bool ccw)
DrawTriangleCallback callback, bool ccw, const DebugParam* debugParam)
{
assert(canvasWidth >= TILE_WIDTH_IN_PIXELS && canvasHeight >= TILE_WIDTH_IN_PIXELS);
assert(canvasWidth%TILE_WIDTH_IN_PIXELS == 0 && canvasHeight%TILE_WIDTH_IN_PIXELS == 0);
@@ -306,20 +341,23 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight,
DrawTriangleParam param;
param.widthInTiles = canvasWidth / TILE_WIDTH_IN_PIXELS;
//ccw
//Whether the three input vertices are in the agreed clockwise order or not,
// it indicates that the triangle is invisible
bool isCCW = (v1 - v0).crossProduct(v2 - v1)>0;
if (isCCW != ccw) return;
//By default, the order is counterclockwise. So if the input data is clockwise, a reversal is needed.
// Swap v1 and v2, and then reverse it back when the final callback is made
param.ccw = ccw;
param.verts[0] = v0;
param.verts[1] = ccw ? v1 : v2;
param.verts[2] = ccw ? v2 : v1;
param.area = (param.verts[1] - param.verts[0]).crossProduct(param.verts[2] - param.verts[1]);
ifloat2_t vertices[3];
iFloat2 vertices[3];
for (size_t i = 0; i < 3; i++)
{
vertices[i] = ifloat2_t(param.verts[i].x, param.verts[i].y);
vertices[i] = iFloat2(param.verts[i].x, param.verts[i].y);
}
//get window coordinates bounding box
@@ -329,8 +367,8 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight,
param.bbox_max_y = MathUtil::max3(v0.y, v1.y, v2.y);
//canvas size
ifloat_t iCanvasWidth = ifloat_init(canvasWidth);
ifloat_t iCanvasHeight = ifloat_init(canvasHeight);
iFloat iCanvasWidth(canvasWidth);
iFloat iCanvasHeight(canvasHeight);
// clip triangles that are fully outside the scissor rect (scissor rect = whole window)
if (param.bbox_max_x < 0 || param.bbox_max_y < 0 || param.bbox_min_x >= canvasWidth || param.bbox_min_y >= canvasHeight)
@@ -348,13 +386,13 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight,
int32_t last_tile_x = (int32_t)(param.bbox_max_x / TILE_WIDTH_IN_PIXELS);
int32_t last_tile_y = (int32_t)(param.bbox_max_y / TILE_WIDTH_IN_PIXELS);
// evaluate edge equation at the top left tile
ifloat_t firstTileX = first_tile_x * ifloat_init(TILE_WIDTH_IN_PIXELS);
ifloat_t firstTileY = first_tile_y * ifloat_init(TILE_WIDTH_IN_PIXELS);
//The first Title is the Title at the lower left corner within the bounding box range covered by the triangle
iFloat firstTileX = iFloat(first_tile_x * TILE_WIDTH_IN_PIXELS);
iFloat firstTileY = iFloat(first_tile_y * TILE_WIDTH_IN_PIXELS);
ifloat3_t edges0;
ifloat3_t tileEdgesDX, tileEdgesDY, edgesReject, edgesAccept;
const ifloat_t kZeroPointFive = ifloat_init(0.5f);
iFloat3 edgesLB; //The edge value at the lower left corner of the first title
iFloat3 tileEdgesDX, tileEdgesDY;
iFloat3 edgesReject, edgesAccept;
for (size_t v = 0; v < 3; v++)
{
@@ -366,8 +404,8 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight,
tileEdgesDY[v] = param.edgesDY[v] * TILE_WIDTH_IN_PIXELS;
//(V0,V1) X (V0, P) = (x1-x0)(py-y0)-(y1-y0)(px-x0)
edges0[v] = ifloat_multiply(param.edgesDX[v], (firstTileY + kZeroPointFive - vertices[v].y))
- ifloat_multiply(param.edgesDY[v], (firstTileX + kZeroPointFive - vertices[v].x));
edgesLB[v] = param.edgesDX[v] * (firstTileY - vertices[v].y)
- param.edgesDY[v] * (firstTileX - vertices[v].x);
// Top-left rule:
// shift top-left edges ever so slightly outward to make the top-left edges be
@@ -382,7 +420,7 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight,
param.tlBorder[v] = false;
}
edgesReject[v] = edgesAccept[v] = edges0[v];
edgesReject[v] = edgesAccept[v] = edgesLB[v];
if (tileEdgesDX[v] > 0) edgesReject[v] += tileEdgesDX[v];
else if (tileEdgesDX[v] < 0) edgesAccept[v] += tileEdgesDX[v];
@@ -391,18 +429,77 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight,
else if (tileEdgesDY[v] < 0) edgesReject[v] -= tileEdgesDY[v];
}
ifloat3_t rowEdges(edges0);
if (debugParam != nullptr)
{
param.debugParam.debug = debugParam->debug;
param.debugParam.szOutputFileName = debugParam->szOutputFileName;
param.debugParam.x = debugParam->x;
param.debugParam.y = debugParam->y;
if (param.debugParam.debug) {
param.debugParam.fpOutput = fopen(debugParam->szOutputFileName, "w");
fprintf(param.debugParam.fpOutput, "===== Triangle ====\n");
for (int32_t i = 0; i < 3; i++) {
fprintf(param.debugParam.fpOutput, "v%d=(%f,%f)[%lld,%lld]\n", i,
param.verts[i].x, param.verts[i].y, vertices[i].x.s3132, vertices[i].y.s3132);
}
fprintf(param.debugParam.fpOutput, "===== TitleRange ====\n");
fprintf(param.debugParam.fpOutput,
"tile_x={%d, %d}\ntile_y={%d, %d}\n",
first_tile_x, last_tile_x, first_tile_y, last_tile_y);
fprintf(param.debugParam.fpOutput,
"FirstTitle=(%f,%f)[%lld,%lld]\n", firstTileX.to_float(), firstTileY.to_float(),
firstTileX.s3132, firstTileY.s3132
);
fprintf(param.debugParam.fpOutput, "===== Edge ====\n");
for (int32_t i = 0; i < 3; i++) {
fprintf(param.debugParam.fpOutput, "DX%d=(%f)[%lld]\tDY%d=(%f)[%lld]\n",
i,
param.edgesDX[i].to_float(), param.edgesDX[i].s3132,
i,
param.edgesDY[i].to_float(), param.edgesDY[i].s3132);
}
fprintf(param.debugParam.fpOutput, "\n");
for (int32_t i = 0; i < 3; i++) {
fprintf(param.debugParam.fpOutput, "Edge%d=(%lld)*(y-%lld)-(%lld)*(x-%lld)\n\t=(%f)*(y-%f)-(%f)*(x-%f)\n", i,
param.edgesDX[i].s3132, vertices[i].y.s3132, param.edgesDY[i].s3132, vertices[i].x.s3132,
param.edgesDX[i].to_float(), vertices[i].y.to_float(), param.edgesDY[i].to_float(), vertices[i].x.to_float()
);
}
fprintf(param.debugParam.fpOutput, "EdgeLB=(%f,%f,%f)[%lld,%lld,%lld]\n",
edgesLB.x.to_float(), edgesLB.y.to_float(), edgesLB.z.to_float(),
edgesLB.x.s3132, edgesLB.y.s3132, edgesLB.z.s3132
);
for (int32_t i = 0; i < 3; i++)
{
fprintf(param.debugParam.fpOutput, "EdgeLB.%d=%lld*(%lld-%lld)-%lld*(%lld-%lld)\n", i,
param.edgesDX[i].s3132, firstTileY.s3132, vertices[i].y.s3132,
param.edgesDY[i].s3132, firstTileX.s3132, vertices[i].x.s3132
);
}
fprintf(param.debugParam.fpOutput, "TopLeft=%s,%s,%s\n",
param.tlBorder[0] ? "true" : "false", param.tlBorder[1] ? "true" : "false", param.tlBorder[2] ? "true" : "false"
);
}
}
iFloat3 rowEdges(edgesLB);
int32_t tile_row_start = first_tile_y * param.widthInTiles + first_tile_x;
for (int32_t tile_y = first_tile_y; tile_y <= last_tile_y; tile_y++)
{
ifloat3_t edges(rowEdges);
ifloat3_t tileEdgesReject(edgesReject);
ifloat3_t tileEdgesAccept(edgesAccept);
iFloat3 edges(rowEdges);
iFloat3 tileEdgesReject(edgesReject);
iFloat3 tileEdgesAccept(edgesAccept);
int32_t tile_i = tile_row_start;
for (int32_t tile_x = first_tile_x; tile_x <= last_tile_x; tile_x++)
{
//If the title is excluded by any edge,
// it indicates that the title is completely outside the triangle and does not require rendering
bool rejected =
((tileEdgesReject[0] < 0 || (!param.tlBorder[0] && tileEdgesReject[0] == 0))) ||
((tileEdgesReject[1] < 0 || (!param.tlBorder[1] && tileEdgesReject[1] == 0))) ||
@@ -416,7 +513,9 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight,
{
if (tileEdgesAccept[v] < 0 || (tileEdgesAccept[v] == 0 && !param.tlBorder[v]))
{
testEdgeMask += (1 << v);
//whether the accepting vertex of this title is on the "outside" of the three edges,
// that is, it may intersect or be completely outside
testEdgeMask += (1 << v);
}
}
@@ -436,6 +535,12 @@ void Rasterizer::drawTriangleLarrabee(int32_t canvasWidth, int32_t canvasHeight,
edgesAccept.add(tileEdgesDX);
tile_row_start += param.widthInTiles;
}
if (debugParam != nullptr && debugParam->debug)
{
fclose(param.debugParam.fpOutput);
param.debugParam.fpOutput = nullptr;
}
}
//-------------------------------------------------------------------------------------