blob: bddfd7e508934c888f20d1baa7ff2212acb4104a [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Herb Derbyc3cc5fa2017-03-07 11:11:47 -05007#include "SkArenaAlloc.h"
caryclark@google.comcffbcc32013-06-04 17:59:42 +00008#include "SkFloatBits.h"
caryclark27c8eb82015-07-06 11:38:33 -07009#include "SkOpCoincidence.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +000010#include "SkPathOpsTypes.h"
11
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000012static bool arguments_denormalized(float a, float b, int epsilon) {
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +000013 float denormalizedCheck = FLT_EPSILON * epsilon / 2;
14 return fabsf(a) <= denormalizedCheck && fabsf(b) <= denormalizedCheck;
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000015}
16
caryclark@google.com07393ca2013-04-08 11:47:37 +000017// from http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
caryclark@google.comcffbcc32013-06-04 17:59:42 +000018// FIXME: move to SkFloatBits.h
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +000019static bool equal_ulps(float a, float b, int epsilon, int depsilon) {
caryclarkb6693002015-12-16 12:28:35 -080020 if (arguments_denormalized(a, b, depsilon)) {
21 return true;
22 }
23 int aBits = SkFloatAs2sCompliment(a);
24 int bBits = SkFloatAs2sCompliment(b);
25 // Find the difference in ULPs.
26 return aBits < bBits + epsilon && bBits < aBits + epsilon;
27}
28
caryclark55888e42016-07-18 10:01:36 -070029static bool equal_ulps_no_normal_check(float a, float b, int epsilon, int depsilon) {
30 int aBits = SkFloatAs2sCompliment(a);
31 int bBits = SkFloatAs2sCompliment(b);
32 // Find the difference in ULPs.
33 return aBits < bBits + epsilon && bBits < aBits + epsilon;
34}
35
caryclarkb6693002015-12-16 12:28:35 -080036static bool equal_ulps_pin(float a, float b, int epsilon, int depsilon) {
caryclark@google.com570863f2013-09-16 15:55:01 +000037 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
38 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +000039 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +000040 if (arguments_denormalized(a, b, depsilon)) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000041 return true;
42 }
43 int aBits = SkFloatAs2sCompliment(a);
44 int bBits = SkFloatAs2sCompliment(b);
45 // Find the difference in ULPs.
46 return aBits < bBits + epsilon && bBits < aBits + epsilon;
47}
48
49static bool d_equal_ulps(float a, float b, int epsilon) {
caryclark@google.com570863f2013-09-16 15:55:01 +000050 int aBits = SkFloatAs2sCompliment(a);
51 int bBits = SkFloatAs2sCompliment(b);
caryclark@google.com07393ca2013-04-08 11:47:37 +000052 // Find the difference in ULPs.
caryclark@google.com570863f2013-09-16 15:55:01 +000053 return aBits < bBits + epsilon && bBits < aBits + epsilon;
54}
55
56static bool not_equal_ulps(float a, float b, int epsilon) {
caryclarkb6693002015-12-16 12:28:35 -080057 if (arguments_denormalized(a, b, epsilon)) {
58 return false;
59 }
60 int aBits = SkFloatAs2sCompliment(a);
61 int bBits = SkFloatAs2sCompliment(b);
62 // Find the difference in ULPs.
63 return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
64}
65
66static bool not_equal_ulps_pin(float a, float b, int epsilon) {
caryclark@google.com570863f2013-09-16 15:55:01 +000067 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
68 return false;
69 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000070 if (arguments_denormalized(a, b, epsilon)) {
71 return false;
72 }
73 int aBits = SkFloatAs2sCompliment(a);
74 int bBits = SkFloatAs2sCompliment(b);
75 // Find the difference in ULPs.
76 return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
77}
78
79static bool d_not_equal_ulps(float a, float b, int epsilon) {
caryclark@google.com570863f2013-09-16 15:55:01 +000080 int aBits = SkFloatAs2sCompliment(a);
81 int bBits = SkFloatAs2sCompliment(b);
82 // Find the difference in ULPs.
83 return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
caryclark@google.com07e97fc2013-07-08 17:17:02 +000084}
85
caryclark@google.com4fdbb222013-07-23 15:27:41 +000086static bool less_ulps(float a, float b, int epsilon) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000087 if (arguments_denormalized(a, b, epsilon)) {
88 return a <= b - FLT_EPSILON * epsilon;
89 }
caryclark@google.com570863f2013-09-16 15:55:01 +000090 int aBits = SkFloatAs2sCompliment(a);
91 int bBits = SkFloatAs2sCompliment(b);
caryclark@google.comfa2aeee2013-07-15 13:29:13 +000092 // Find the difference in ULPs.
caryclark@google.com570863f2013-09-16 15:55:01 +000093 return aBits <= bBits - epsilon;
94}
95
96static bool less_or_equal_ulps(float a, float b, int epsilon) {
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000097 if (arguments_denormalized(a, b, epsilon)) {
98 return a < b + FLT_EPSILON * epsilon;
99 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000100 int aBits = SkFloatAs2sCompliment(a);
101 int bBits = SkFloatAs2sCompliment(b);
102 // Find the difference in ULPs.
103 return aBits < bBits + epsilon;
104}
105
106// equality using the same error term as between
107bool AlmostBequalUlps(float a, float b) {
108 const int UlpsEpsilon = 2;
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000109 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
110}
111
112bool AlmostPequalUlps(float a, float b) {
113 const int UlpsEpsilon = 8;
114 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000115}
116
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000117bool AlmostDequalUlps(float a, float b) {
118 const int UlpsEpsilon = 16;
119 return d_equal_ulps(a, b, UlpsEpsilon);
120}
121
commit-bot@chromium.org2db7fe72014-05-07 15:31:40 +0000122bool AlmostDequalUlps(double a, double b) {
caryclarkb6693002015-12-16 12:28:35 -0800123 return AlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
commit-bot@chromium.org2db7fe72014-05-07 15:31:40 +0000124}
125
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000126bool AlmostEqualUlps(float a, float b) {
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000127 const int UlpsEpsilon = 16;
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000128 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000129}
130
caryclark55888e42016-07-18 10:01:36 -0700131bool AlmostEqualUlpsNoNormalCheck(float a, float b) {
132 const int UlpsEpsilon = 16;
133 return equal_ulps_no_normal_check(a, b, UlpsEpsilon, UlpsEpsilon);
134}
135
caryclarkb6693002015-12-16 12:28:35 -0800136bool AlmostEqualUlps_Pin(float a, float b) {
137 const int UlpsEpsilon = 16;
138 return equal_ulps_pin(a, b, UlpsEpsilon, UlpsEpsilon);
139}
140
caryclark@google.com570863f2013-09-16 15:55:01 +0000141bool NotAlmostEqualUlps(float a, float b) {
142 const int UlpsEpsilon = 16;
143 return not_equal_ulps(a, b, UlpsEpsilon);
144}
145
caryclarkb6693002015-12-16 12:28:35 -0800146bool NotAlmostEqualUlps_Pin(float a, float b) {
147 const int UlpsEpsilon = 16;
148 return not_equal_ulps_pin(a, b, UlpsEpsilon);
149}
150
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000151bool NotAlmostDequalUlps(float a, float b) {
152 const int UlpsEpsilon = 16;
153 return d_not_equal_ulps(a, b, UlpsEpsilon);
154}
155
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000156bool RoughlyEqualUlps(float a, float b) {
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000157 const int UlpsEpsilon = 256;
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000158 const int DUlpsEpsilon = 1024;
159 return equal_ulps(a, b, UlpsEpsilon, DUlpsEpsilon);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000160}
161
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000162bool AlmostBetweenUlps(float a, float b, float c) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000163 const int UlpsEpsilon = 2;
164 return a <= c ? less_or_equal_ulps(a, b, UlpsEpsilon) && less_or_equal_ulps(b, c, UlpsEpsilon)
165 : less_or_equal_ulps(b, a, UlpsEpsilon) && less_or_equal_ulps(c, b, UlpsEpsilon);
166}
167
168bool AlmostLessUlps(float a, float b) {
169 const int UlpsEpsilon = 16;
170 return less_ulps(a, b, UlpsEpsilon);
171}
172
173bool AlmostLessOrEqualUlps(float a, float b) {
174 const int UlpsEpsilon = 16;
175 return less_or_equal_ulps(a, b, UlpsEpsilon);
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000176}
177
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000178int UlpsDistance(float a, float b) {
179 SkFloatIntUnion floatIntA, floatIntB;
180 floatIntA.fFloat = a;
181 floatIntB.fFloat = b;
182 // Different signs means they do not match.
183 if ((floatIntA.fSignBitInt < 0) != (floatIntB.fSignBitInt < 0)) {
184 // Check for equality to make sure +0 == -0
185 return a == b ? 0 : SK_MaxS32;
186 }
187 // Find the difference in ULPs.
bungeman60e0fee2015-08-26 05:15:46 -0700188 return SkTAbs(floatIntA.fSignBitInt - floatIntB.fSignBitInt);
caryclark@google.com4fdbb222013-07-23 15:27:41 +0000189}
190
caryclark@google.com07393ca2013-04-08 11:47:37 +0000191// cube root approximation using bit hack for 64-bit float
192// adapted from Kahan's cbrt
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000193static double cbrt_5d(double d) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000194 const unsigned int B1 = 715094163;
195 double t = 0.0;
196 unsigned int* pt = (unsigned int*) &t;
197 unsigned int* px = (unsigned int*) &d;
198 pt[1] = px[1] / 3 + B1;
199 return t;
200}
201
202// iterative cube root approximation using Halley's method (double)
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000203static double cbrta_halleyd(const double a, const double R) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000204 const double a3 = a * a * a;
205 const double b = a * (a3 + R + R) / (a3 + a3 + R);
206 return b;
207}
208
209// cube root approximation using 3 iterations of Halley's method (double)
210static double halley_cbrt3d(double d) {
211 double a = cbrt_5d(d);
212 a = cbrta_halleyd(a, d);
213 a = cbrta_halleyd(a, d);
214 return cbrta_halleyd(a, d);
215}
216
217double SkDCubeRoot(double x) {
218 if (approximately_zero_cubed(x)) {
219 return 0;
220 }
221 double result = halley_cbrt3d(fabs(x));
222 if (x < 0) {
223 result = -result;
224 }
225 return result;
226}
caryclark27c8eb82015-07-06 11:38:33 -0700227
caryclark55888e42016-07-18 10:01:36 -0700228SkOpGlobalState::SkOpGlobalState(SkOpContourHead* head,
Herb Derbyc3cc5fa2017-03-07 11:11:47 -0500229 SkArenaAlloc* allocator
caryclarkdae6b972016-06-08 04:28:19 -0700230 SkDEBUGPARAMS(bool debugSkipAssert)
caryclarkd4349722015-07-23 12:40:22 -0700231 SkDEBUGPARAMS(const char* testName))
caryclark55888e42016-07-18 10:01:36 -0700232 : fAllocator(allocator)
233 , fCoincidence(nullptr)
caryclark27c8eb82015-07-06 11:38:33 -0700234 , fContourHead(head)
235 , fNested(0)
236 , fWindingFailed(false)
Cary Clarkab87d7a2016-10-04 10:01:04 -0400237 , fPhase(SkOpPhase::kIntersecting)
caryclarkd4349722015-07-23 12:40:22 -0700238 SkDEBUGPARAMS(fDebugTestName(testName))
caryclark27c8eb82015-07-06 11:38:33 -0700239 SkDEBUGPARAMS(fAngleID(0))
caryclark26ad22a2015-10-16 09:03:38 -0700240 SkDEBUGPARAMS(fCoinID(0))
caryclark27c8eb82015-07-06 11:38:33 -0700241 SkDEBUGPARAMS(fContourID(0))
242 SkDEBUGPARAMS(fPtTID(0))
243 SkDEBUGPARAMS(fSegmentID(0))
Cary Clarkab87d7a2016-10-04 10:01:04 -0400244 SkDEBUGPARAMS(fSpanID(0))
245 SkDEBUGPARAMS(fDebugSkipAssert(debugSkipAssert)) {
caryclark26ad22a2015-10-16 09:03:38 -0700246#if DEBUG_T_SECT_LOOP_COUNT
247 debugResetLoopCounts();
248#endif
Cary Clarkab87d7a2016-10-04 10:01:04 -0400249#if DEBUG_COIN
250 fPreviousFuncName = nullptr;
251#endif
caryclark27c8eb82015-07-06 11:38:33 -0700252}