acc_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. // Copyright 2016 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package vector
  5. import (
  6. "bytes"
  7. "fmt"
  8. "math/rand"
  9. "testing"
  10. )
  11. // TestDivideByFFFF tests that dividing by 0xffff is equivalent to multiplying
  12. // and then shifting by magic constants. The Go compiler itself issues this
  13. // multiply-and-shift for a division by the constant value 0xffff. This trick
  14. // is used in the asm code as the GOARCH=amd64 SIMD instructions have parallel
  15. // multiply but not parallel divide.
  16. //
  17. // There's undoubtedly a justification somewhere in Hacker's Delight chapter 10
  18. // "Integer Division by Constants", but I don't have a more specific link.
  19. //
  20. // http://www.hackersdelight.org/divcMore.pdf and
  21. // http://www.hackersdelight.org/magic.htm
  22. func TestDivideByFFFF(t *testing.T) {
  23. const mul, shift = 0x80008001, 47
  24. rng := rand.New(rand.NewSource(1))
  25. for i := 0; i < 20000; i++ {
  26. u := rng.Uint32()
  27. got := uint32((uint64(u) * mul) >> shift)
  28. want := u / 0xffff
  29. if got != want {
  30. t.Fatalf("i=%d, u=%#08x: got %#08x, want %#08x", i, u, got, want)
  31. }
  32. }
  33. }
  34. // TestXxxSIMDUnaligned tests that unaligned SIMD loads/stores don't crash.
  35. func TestFixedAccumulateSIMDUnaligned(t *testing.T) {
  36. if !haveFixedAccumulateSIMD {
  37. t.Skip("No SIMD implemention")
  38. }
  39. dst := make([]uint8, 64)
  40. src := make([]uint32, 64)
  41. for d := 0; d < 16; d++ {
  42. for s := 0; s < 16; s++ {
  43. fixedAccumulateOpSrcSIMD(dst[d:d+32], src[s:s+32])
  44. }
  45. }
  46. }
  47. func TestFloatingAccumulateSIMDUnaligned(t *testing.T) {
  48. if !haveFloatingAccumulateSIMD {
  49. t.Skip("No SIMD implemention")
  50. }
  51. dst := make([]uint8, 64)
  52. src := make([]float32, 64)
  53. for d := 0; d < 16; d++ {
  54. for s := 0; s < 16; s++ {
  55. floatingAccumulateOpSrcSIMD(dst[d:d+32], src[s:s+32])
  56. }
  57. }
  58. }
  59. // TestXxxSIMDShortDst tests that the SIMD implementations don't write past the
  60. // end of the dst buffer.
  61. func TestFixedAccumulateSIMDShortDst(t *testing.T) {
  62. if !haveFixedAccumulateSIMD {
  63. t.Skip("No SIMD implemention")
  64. }
  65. const oneQuarter = uint32(int2ϕ(fxOne*fxOne)) / 4
  66. src := []uint32{oneQuarter, oneQuarter, oneQuarter, oneQuarter}
  67. for i := 0; i < 4; i++ {
  68. dst := make([]uint8, 4)
  69. fixedAccumulateOpSrcSIMD(dst[:i], src[:i])
  70. for j := range dst {
  71. if j < i {
  72. if got := dst[j]; got == 0 {
  73. t.Errorf("i=%d, j=%d: got %#02x, want non-zero", i, j, got)
  74. }
  75. } else {
  76. if got := dst[j]; got != 0 {
  77. t.Errorf("i=%d, j=%d: got %#02x, want zero", i, j, got)
  78. }
  79. }
  80. }
  81. }
  82. }
  83. func TestFloatingAccumulateSIMDShortDst(t *testing.T) {
  84. if !haveFloatingAccumulateSIMD {
  85. t.Skip("No SIMD implemention")
  86. }
  87. const oneQuarter = 0.25
  88. src := []float32{oneQuarter, oneQuarter, oneQuarter, oneQuarter}
  89. for i := 0; i < 4; i++ {
  90. dst := make([]uint8, 4)
  91. floatingAccumulateOpSrcSIMD(dst[:i], src[:i])
  92. for j := range dst {
  93. if j < i {
  94. if got := dst[j]; got == 0 {
  95. t.Errorf("i=%d, j=%d: got %#02x, want non-zero", i, j, got)
  96. }
  97. } else {
  98. if got := dst[j]; got != 0 {
  99. t.Errorf("i=%d, j=%d: got %#02x, want zero", i, j, got)
  100. }
  101. }
  102. }
  103. }
  104. }
  105. func TestFixedAccumulateOpOverShort(t *testing.T) { testAcc(t, fxInShort, fxMaskShort, "over") }
  106. func TestFixedAccumulateOpSrcShort(t *testing.T) { testAcc(t, fxInShort, fxMaskShort, "src") }
  107. func TestFixedAccumulateMaskShort(t *testing.T) { testAcc(t, fxInShort, fxMaskShort, "mask") }
  108. func TestFloatingAccumulateOpOverShort(t *testing.T) { testAcc(t, flInShort, flMaskShort, "over") }
  109. func TestFloatingAccumulateOpSrcShort(t *testing.T) { testAcc(t, flInShort, flMaskShort, "src") }
  110. func TestFloatingAccumulateMaskShort(t *testing.T) { testAcc(t, flInShort, flMaskShort, "mask") }
  111. func TestFixedAccumulateOpOver16(t *testing.T) { testAcc(t, fxIn16, fxMask16, "over") }
  112. func TestFixedAccumulateOpSrc16(t *testing.T) { testAcc(t, fxIn16, fxMask16, "src") }
  113. func TestFixedAccumulateMask16(t *testing.T) { testAcc(t, fxIn16, fxMask16, "mask") }
  114. func TestFloatingAccumulateOpOver16(t *testing.T) { testAcc(t, flIn16, flMask16, "over") }
  115. func TestFloatingAccumulateOpSrc16(t *testing.T) { testAcc(t, flIn16, flMask16, "src") }
  116. func TestFloatingAccumulateMask16(t *testing.T) { testAcc(t, flIn16, flMask16, "mask") }
  117. func testAcc(t *testing.T, in interface{}, mask []uint32, op string) {
  118. for _, simd := range []bool{false, true} {
  119. maxN := 0
  120. switch in := in.(type) {
  121. case []uint32:
  122. if simd && !haveFixedAccumulateSIMD {
  123. continue
  124. }
  125. maxN = len(in)
  126. case []float32:
  127. if simd && !haveFloatingAccumulateSIMD {
  128. continue
  129. }
  130. maxN = len(in)
  131. }
  132. for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
  133. 33, 55, 79, 96, 120, 165, 256, maxN} {
  134. if n > maxN {
  135. continue
  136. }
  137. var (
  138. got8, want8 []uint8
  139. got32, want32 []uint32
  140. )
  141. switch op {
  142. case "over":
  143. const background = 0x40
  144. got8 = make([]uint8, n)
  145. for i := range got8 {
  146. got8[i] = background
  147. }
  148. want8 = make([]uint8, n)
  149. for i := range want8 {
  150. dstA := uint32(background * 0x101)
  151. maskA := mask[i]
  152. outA := dstA*(0xffff-maskA)/0xffff + maskA
  153. want8[i] = uint8(outA >> 8)
  154. }
  155. case "src":
  156. got8 = make([]uint8, n)
  157. want8 = make([]uint8, n)
  158. for i := range want8 {
  159. want8[i] = uint8(mask[i] >> 8)
  160. }
  161. case "mask":
  162. got32 = make([]uint32, n)
  163. want32 = mask[:n]
  164. }
  165. switch in := in.(type) {
  166. case []uint32:
  167. switch op {
  168. case "over":
  169. if simd {
  170. fixedAccumulateOpOverSIMD(got8, in[:n])
  171. } else {
  172. fixedAccumulateOpOver(got8, in[:n])
  173. }
  174. case "src":
  175. if simd {
  176. fixedAccumulateOpSrcSIMD(got8, in[:n])
  177. } else {
  178. fixedAccumulateOpSrc(got8, in[:n])
  179. }
  180. case "mask":
  181. copy(got32, in[:n])
  182. if simd {
  183. fixedAccumulateMaskSIMD(got32)
  184. } else {
  185. fixedAccumulateMask(got32)
  186. }
  187. }
  188. case []float32:
  189. switch op {
  190. case "over":
  191. if simd {
  192. floatingAccumulateOpOverSIMD(got8, in[:n])
  193. } else {
  194. floatingAccumulateOpOver(got8, in[:n])
  195. }
  196. case "src":
  197. if simd {
  198. floatingAccumulateOpSrcSIMD(got8, in[:n])
  199. } else {
  200. floatingAccumulateOpSrc(got8, in[:n])
  201. }
  202. case "mask":
  203. if simd {
  204. floatingAccumulateMaskSIMD(got32, in[:n])
  205. } else {
  206. floatingAccumulateMask(got32, in[:n])
  207. }
  208. }
  209. }
  210. if op != "mask" {
  211. if !bytes.Equal(got8, want8) {
  212. t.Errorf("simd=%t, n=%d:\ngot: % x\nwant: % x", simd, n, got8, want8)
  213. }
  214. } else {
  215. if !uint32sEqual(got32, want32) {
  216. t.Errorf("simd=%t, n=%d:\ngot: % x\nwant: % x", simd, n, got32, want32)
  217. }
  218. }
  219. }
  220. }
  221. }
  222. func uint32sEqual(xs, ys []uint32) bool {
  223. if len(xs) != len(ys) {
  224. return false
  225. }
  226. for i := range xs {
  227. if xs[i] != ys[i] {
  228. return false
  229. }
  230. }
  231. return true
  232. }
  233. func float32sEqual(xs, ys []float32) bool {
  234. if len(xs) != len(ys) {
  235. return false
  236. }
  237. for i := range xs {
  238. if xs[i] != ys[i] {
  239. return false
  240. }
  241. }
  242. return true
  243. }
  244. func BenchmarkFixedAccumulateOpOver16(b *testing.B) { benchAcc(b, fxIn16, "over", false) }
  245. func BenchmarkFixedAccumulateOpOverSIMD16(b *testing.B) { benchAcc(b, fxIn16, "over", true) }
  246. func BenchmarkFixedAccumulateOpSrc16(b *testing.B) { benchAcc(b, fxIn16, "src", false) }
  247. func BenchmarkFixedAccumulateOpSrcSIMD16(b *testing.B) { benchAcc(b, fxIn16, "src", true) }
  248. func BenchmarkFixedAccumulateMask16(b *testing.B) { benchAcc(b, fxIn16, "mask", false) }
  249. func BenchmarkFixedAccumulateMaskSIMD16(b *testing.B) { benchAcc(b, fxIn16, "mask", true) }
  250. func BenchmarkFloatingAccumulateOpOver16(b *testing.B) { benchAcc(b, flIn16, "over", false) }
  251. func BenchmarkFloatingAccumulateOpOverSIMD16(b *testing.B) { benchAcc(b, flIn16, "over", true) }
  252. func BenchmarkFloatingAccumulateOpSrc16(b *testing.B) { benchAcc(b, flIn16, "src", false) }
  253. func BenchmarkFloatingAccumulateOpSrcSIMD16(b *testing.B) { benchAcc(b, flIn16, "src", true) }
  254. func BenchmarkFloatingAccumulateMask16(b *testing.B) { benchAcc(b, flIn16, "mask", false) }
  255. func BenchmarkFloatingAccumulateMaskSIMD16(b *testing.B) { benchAcc(b, flIn16, "mask", true) }
  256. func BenchmarkFixedAccumulateOpOver64(b *testing.B) { benchAcc(b, fxIn64, "over", false) }
  257. func BenchmarkFixedAccumulateOpOverSIMD64(b *testing.B) { benchAcc(b, fxIn64, "over", true) }
  258. func BenchmarkFixedAccumulateOpSrc64(b *testing.B) { benchAcc(b, fxIn64, "src", false) }
  259. func BenchmarkFixedAccumulateOpSrcSIMD64(b *testing.B) { benchAcc(b, fxIn64, "src", true) }
  260. func BenchmarkFixedAccumulateMask64(b *testing.B) { benchAcc(b, fxIn64, "mask", false) }
  261. func BenchmarkFixedAccumulateMaskSIMD64(b *testing.B) { benchAcc(b, fxIn64, "mask", true) }
  262. func BenchmarkFloatingAccumulateOpOver64(b *testing.B) { benchAcc(b, flIn64, "over", false) }
  263. func BenchmarkFloatingAccumulateOpOverSIMD64(b *testing.B) { benchAcc(b, flIn64, "over", true) }
  264. func BenchmarkFloatingAccumulateOpSrc64(b *testing.B) { benchAcc(b, flIn64, "src", false) }
  265. func BenchmarkFloatingAccumulateOpSrcSIMD64(b *testing.B) { benchAcc(b, flIn64, "src", true) }
  266. func BenchmarkFloatingAccumulateMask64(b *testing.B) { benchAcc(b, flIn64, "mask", false) }
  267. func BenchmarkFloatingAccumulateMaskSIMD64(b *testing.B) { benchAcc(b, flIn64, "mask", true) }
  268. func benchAcc(b *testing.B, in interface{}, op string, simd bool) {
  269. var f func()
  270. switch in := in.(type) {
  271. case []uint32:
  272. if simd && !haveFixedAccumulateSIMD {
  273. b.Skip("No SIMD implemention")
  274. }
  275. switch op {
  276. case "over":
  277. dst := make([]uint8, len(in))
  278. if simd {
  279. f = func() { fixedAccumulateOpOverSIMD(dst, in) }
  280. } else {
  281. f = func() { fixedAccumulateOpOver(dst, in) }
  282. }
  283. case "src":
  284. dst := make([]uint8, len(in))
  285. if simd {
  286. f = func() { fixedAccumulateOpSrcSIMD(dst, in) }
  287. } else {
  288. f = func() { fixedAccumulateOpSrc(dst, in) }
  289. }
  290. case "mask":
  291. buf := make([]uint32, len(in))
  292. copy(buf, in)
  293. if simd {
  294. f = func() { fixedAccumulateMaskSIMD(buf) }
  295. } else {
  296. f = func() { fixedAccumulateMask(buf) }
  297. }
  298. }
  299. case []float32:
  300. if simd && !haveFloatingAccumulateSIMD {
  301. b.Skip("No SIMD implemention")
  302. }
  303. switch op {
  304. case "over":
  305. dst := make([]uint8, len(in))
  306. if simd {
  307. f = func() { floatingAccumulateOpOverSIMD(dst, in) }
  308. } else {
  309. f = func() { floatingAccumulateOpOver(dst, in) }
  310. }
  311. case "src":
  312. dst := make([]uint8, len(in))
  313. if simd {
  314. f = func() { floatingAccumulateOpSrcSIMD(dst, in) }
  315. } else {
  316. f = func() { floatingAccumulateOpSrc(dst, in) }
  317. }
  318. case "mask":
  319. dst := make([]uint32, len(in))
  320. if simd {
  321. f = func() { floatingAccumulateMaskSIMD(dst, in) }
  322. } else {
  323. f = func() { floatingAccumulateMask(dst, in) }
  324. }
  325. }
  326. }
  327. b.ResetTimer()
  328. for i := 0; i < b.N; i++ {
  329. f()
  330. }
  331. }
  332. // itou exists because "uint32(int2ϕ(-1))" doesn't compile: constant -1
  333. // overflows uint32.
  334. func itou(i int2ϕ) uint32 {
  335. return uint32(i)
  336. }
  337. var fxInShort = []uint32{
  338. itou(+0x08000), // +0.125, // Running sum: +0.125
  339. itou(-0x20000), // -0.500, // Running sum: -0.375
  340. itou(+0x10000), // +0.250, // Running sum: -0.125
  341. itou(+0x18000), // +0.375, // Running sum: +0.250
  342. itou(+0x08000), // +0.125, // Running sum: +0.375
  343. itou(+0x00000), // +0.000, // Running sum: +0.375
  344. itou(-0x40000), // -1.000, // Running sum: -0.625
  345. itou(-0x20000), // -0.500, // Running sum: -1.125
  346. itou(+0x10000), // +0.250, // Running sum: -0.875
  347. itou(+0x38000), // +0.875, // Running sum: +0.000
  348. itou(+0x10000), // +0.250, // Running sum: +0.250
  349. itou(+0x30000), // +0.750, // Running sum: +1.000
  350. }
  351. var flInShort = []float32{
  352. +0.125, // Running sum: +0.125
  353. -0.500, // Running sum: -0.375
  354. +0.250, // Running sum: -0.125
  355. +0.375, // Running sum: +0.250
  356. +0.125, // Running sum: +0.375
  357. +0.000, // Running sum: +0.375
  358. -1.000, // Running sum: -0.625
  359. -0.500, // Running sum: -1.125
  360. +0.250, // Running sum: -0.875
  361. +0.875, // Running sum: +0.000
  362. +0.250, // Running sum: +0.250
  363. +0.750, // Running sum: +1.000
  364. }
  365. // It's OK for fxMaskShort and flMaskShort to have slightly different values.
  366. // Both the fixed and floating point implementations already have (different)
  367. // rounding errors in the xxxLineTo methods before we get to accumulation. It's
  368. // OK for 50% coverage (in ideal math) to be approximated by either 0x7fff or
  369. // 0x8000. Both slices do contain checks that 0% and 100% map to 0x0000 and
  370. // 0xffff, as does checkCornersCenter in vector_test.go.
  371. //
  372. // It is important, though, for the SIMD and non-SIMD fixed point
  373. // implementations to give the exact same output, and likewise for the floating
  374. // point implementations.
  375. var fxMaskShort = []uint32{
  376. 0x2000,
  377. 0x6000,
  378. 0x2000,
  379. 0x4000,
  380. 0x6000,
  381. 0x6000,
  382. 0xa000,
  383. 0xffff,
  384. 0xe000,
  385. 0x0000,
  386. 0x4000,
  387. 0xffff,
  388. }
  389. var flMaskShort = []uint32{
  390. 0x1fff,
  391. 0x5fff,
  392. 0x1fff,
  393. 0x3fff,
  394. 0x5fff,
  395. 0x5fff,
  396. 0x9fff,
  397. 0xffff,
  398. 0xdfff,
  399. 0x0000,
  400. 0x3fff,
  401. 0xffff,
  402. }
  403. func TestMakeFxInXxx(t *testing.T) {
  404. dump := func(us []uint32) string {
  405. var b bytes.Buffer
  406. for i, u := range us {
  407. if i%8 == 0 {
  408. b.WriteByte('\n')
  409. }
  410. fmt.Fprintf(&b, "%#08x, ", u)
  411. }
  412. return b.String()
  413. }
  414. if !uint32sEqual(fxIn16, hardCodedFxIn16) {
  415. t.Errorf("height 16: got:%v\nwant:%v", dump(fxIn16), dump(hardCodedFxIn16))
  416. }
  417. }
  418. func TestMakeFlInXxx(t *testing.T) {
  419. dump := func(fs []float32) string {
  420. var b bytes.Buffer
  421. for i, f := range fs {
  422. if i%8 == 0 {
  423. b.WriteByte('\n')
  424. }
  425. fmt.Fprintf(&b, "%v, ", f)
  426. }
  427. return b.String()
  428. }
  429. if !float32sEqual(flIn16, hardCodedFlIn16) {
  430. t.Errorf("height 16: got:%v\nwant:%v", dump(flIn16), dump(hardCodedFlIn16))
  431. }
  432. }
  433. func makeInXxx(height int, useFloatingPointMath bool) *Rasterizer {
  434. width, data := scaledBenchmarkGlyphData(height)
  435. z := NewRasterizer(width, height)
  436. z.setUseFloatingPointMath(useFloatingPointMath)
  437. for _, d := range data {
  438. switch d.n {
  439. case 0:
  440. z.MoveTo(d.px, d.py)
  441. case 1:
  442. z.LineTo(d.px, d.py)
  443. case 2:
  444. z.QuadTo(d.px, d.py, d.qx, d.qy)
  445. }
  446. }
  447. return z
  448. }
  449. func makeFxInXxx(height int) []uint32 {
  450. z := makeInXxx(height, false)
  451. return z.bufU32
  452. }
  453. func makeFlInXxx(height int) []float32 {
  454. z := makeInXxx(height, true)
  455. return z.bufF32
  456. }
  457. // fxInXxx and flInXxx are the z.bufU32 and z.bufF32 inputs to the accumulate
  458. // functions when rasterizing benchmarkGlyphData at a height of Xxx pixels.
  459. //
  460. // fxMaskXxx and flMaskXxx are the corresponding golden outputs of those
  461. // accumulateMask functions.
  462. //
  463. // The hardCodedEtc versions are a sanity check for unexpected changes in the
  464. // rasterization implementations up to but not including accumulation.
  465. var (
  466. fxIn16 = makeFxInXxx(16)
  467. fxIn64 = makeFxInXxx(64)
  468. flIn16 = makeFlInXxx(16)
  469. flIn64 = makeFlInXxx(64)
  470. )
  471. var hardCodedFxIn16 = []uint32{
  472. 0x00000000, 0x00000000, 0xffffe91d, 0xfffe7c4a, 0xfffeaa9f, 0xffff4e33, 0xffffc1c5, 0x00007782,
  473. 0x00009619, 0x0001a857, 0x000129e9, 0x00000028, 0x00000000, 0x00000000, 0xffff6e70, 0xfffd3199,
  474. 0xffff5ff8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00014b29,
  475. 0x0002acf3, 0x000007e2, 0xffffca5a, 0xfffcab73, 0xffff8a34, 0x00001b55, 0x0001b334, 0x0001449e,
  476. 0x0000434d, 0xffff62ec, 0xfffe1443, 0xffff325d, 0x00000000, 0x0002234a, 0x0001dcb6, 0xfffe2948,
  477. 0xfffdd6b8, 0x00000000, 0x00028cc0, 0x00017340, 0x00000000, 0x00000000, 0x00000000, 0xffffd2d6,
  478. 0xfffcadd0, 0xffff7f5c, 0x00007400, 0x00038c00, 0xfffe9260, 0xffff2da0, 0x0000023a, 0x0002259b,
  479. 0x0000182a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xfffdc600, 0xfffe3a00, 0x00000059,
  480. 0x0003a44d, 0x00005b59, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
  481. 0x00000000, 0x00000000, 0xfffe33f3, 0xfffdcc0d, 0x00000000, 0x00033c02, 0x0000c3fe, 0x00000000,
  482. 0x00000000, 0xffffa13d, 0xfffeeec8, 0xffff8c02, 0xffff8c48, 0xffffc7b5, 0x00000000, 0xffff5b68,
  483. 0xffff3498, 0x00000000, 0x00033c00, 0x0000c400, 0xffff9bc4, 0xfffdf4a3, 0xfffe8df3, 0xffffe1a8,
  484. 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00033c00,
  485. 0x000092c7, 0xfffcf373, 0xffff3dc7, 0x00000fcc, 0x00011ae7, 0x000130c3, 0x0000680d, 0x00004a59,
  486. 0x00000a20, 0xfffe9dc4, 0xfffe4a3c, 0x00000000, 0x00033c00, 0xfffe87ef, 0xfffe3c11, 0x0000105e,
  487. 0x0002b9c4, 0x000135dc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xfffe3600, 0xfffdca00,
  488. 0x00000000, 0x00033c00, 0xfffd9000, 0xffff3400, 0x0000e400, 0x00031c00, 0x00000000, 0x00000000,
  489. 0x00000000, 0x00000000, 0x00000000, 0xfffe3600, 0xfffdca00, 0x00000000, 0x00033c00, 0xfffcf9a5,
  490. 0xffffca5b, 0x000120e6, 0x0002df1a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
  491. 0xfffdb195, 0xfffe4e6b, 0x00000000, 0x00033c00, 0xfffd9e00, 0xffff2600, 0x00002f0e, 0x00033ea3,
  492. 0x0000924d, 0x00000000, 0x00000000, 0x00000000, 0xfffe83b3, 0xfffd881d, 0xfffff431, 0x00000000,
  493. 0x00031f60, 0xffff297a, 0xfffdb726, 0x00000000, 0x000053a7, 0x0001b506, 0x0000a24b, 0xffffa32d,
  494. 0xfffead9b, 0xffff0479, 0xffffffc9, 0x00000000, 0x00000000, 0x0002d800, 0x0001249d, 0xfffd67bb,
  495. 0xfffe9baa, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000ac03, 0x0001448b,
  496. 0xfffe0f70, 0x00000000, 0x000229ea, 0x0001d616, 0xffffff8c, 0xfffebf76, 0xfffe54d9, 0xffff5d9e,
  497. 0xffffd3eb, 0x0000c65e, 0x0000fc15, 0x0001d491, 0xffffb566, 0xfffd9433, 0x00000000, 0x0000e4ec,
  498. }
  499. var hardCodedFlIn16 = []float32{
  500. 0, 0, -0.022306755, -0.3782405, -0.33334962, -0.1741521, -0.0607556, 0.11660573,
  501. 0.14664596, 0.41462868, 0.2907673, 0.0001568835, 0, 0, -0.14239307, -0.7012868,
  502. -0.15632017, 0, 0, 0, 0, 0, 0, 0.3230303,
  503. 0.6690931, 0.007876594, -0.05189419, -0.832786, -0.11531975, 0.026225802, 0.42518616, 0.3154636,
  504. 0.06598757, -0.15304244, -0.47969276, -0.20012794, 0, 0.5327272, 0.46727282, -0.45950258,
  505. -0.5404974, 0, 0.63484025, 0.36515975, 0, 0, 0, -0.04351709,
  506. -0.8293345, -0.12714837, 0.11087036, 0.88912964, -0.35792422, -0.2053554, 0.0022513224, 0.5374398,
  507. 0.023588525, 0, 0, 0, 0, -0.55346966, -0.44653034, 0.0002531938,
  508. 0.9088273, 0.090919495, 0, 0, 0, 0, 0, 0,
  509. 0, 0, -0.44745448, -0.5525455, 0, 0.80748945, 0.19251058, 0,
  510. 0, -0.092476256, -0.2661464, -0.11322958, -0.11298219, -0.055094406, 0, -0.16045958,
  511. -0.1996116, 0, 0.80748653, 0.19251347, -0.09804727, -0.51129663, -0.3610403, -0.029615778,
  512. 0, 0, 0, 0, 0, 0, 0, 0.80748653,
  513. 0.14411622, -0.76251525, -0.1890875, 0.01527351, 0.27528667, 0.29730347, 0.101477206, 0.07259522,
  514. 0.009900213, -0.34395567, -0.42788061, 0, 0.80748653, -0.3648737, -0.44261283, 0.015778137,
  515. 0.6826565, 0.30156538, 0, 0, 0, 0, -0.44563293, -0.55436707,
  516. 0, 0.80748653, -0.60703933, -0.20044717, 0.22371745, 0.77628255, 0, 0,
  517. 0, 0, 0, -0.44563293, -0.55436707, 0, 0.80748653, -0.7550391,
  518. -0.05244744, 0.2797074, 0.72029257, 0, 0, 0, 0, 0,
  519. -0.57440215, -0.42559785, 0, 0.80748653, -0.59273535, -0.21475118, 0.04544862, 0.81148535,
  520. 0.14306602, 0, 0, 0, -0.369642, -0.61841226, -0.011945802, 0,
  521. 0.7791623, -0.20691396, -0.57224834, 0, 0.08218567, 0.42637306, 0.1586175, -0.089709565,
  522. -0.32935485, -0.24788953, -0.00022224105, 0, 0, 0.7085409, 0.28821066, -0.64765793,
  523. -0.34909368, 0, 0, 0, 0, 0, 0.16679136, 0.31914657,
  524. -0.48593786, 0, 0.537915, 0.462085, -0.00041967133, -0.3120329, -0.41914812, -0.15886839,
  525. -0.042683028, 0.19370951, 0.24624406, 0.45803425, -0.07049577, -0.6091341, 0, 0.22253075,
  526. }
  527. var fxMask16 = []uint32{
  528. 0x0000, 0x0000, 0x05b8, 0x66a6, 0xbbfe, 0xe871, 0xf800, 0xda20, 0xb499, 0x4a84, 0x0009, 0x0000, 0x0000,
  529. 0x0000, 0x2463, 0xd7fd, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xad35, 0x01f8, 0x0000,
  530. 0x0d69, 0xe28c, 0xffff, 0xf92a, 0x8c5d, 0x3b36, 0x2a62, 0x51a7, 0xcc97, 0xffff, 0xffff, 0x772d, 0x0000,
  531. 0x75ad, 0xffff, 0xffff, 0x5ccf, 0x0000, 0x0000, 0x0000, 0x0000, 0x0b4a, 0xdfd6, 0xffff, 0xe2ff, 0x0000,
  532. 0x5b67, 0x8fff, 0x8f70, 0x060a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8e7f, 0xffff, 0xffe9, 0x16d6,
  533. 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7303, 0xffff, 0xffff, 0x30ff,
  534. 0x0000, 0x0000, 0x0000, 0x17b0, 0x5bfe, 0x78fe, 0x95ec, 0xa3fe, 0xa3fe, 0xcd24, 0xfffe, 0xfffe, 0x30fe,
  535. 0x0001, 0x190d, 0x9be5, 0xf868, 0xfffe, 0xfffe, 0xfffe, 0xfffe, 0xfffe, 0xfffe, 0xfffe, 0xfffe, 0x30fe,
  536. 0x0c4c, 0xcf6f, 0xfffe, 0xfc0b, 0xb551, 0x6920, 0x4f1d, 0x3c87, 0x39ff, 0x928e, 0xffff, 0xffff, 0x30ff,
  537. 0x8f03, 0xffff, 0xfbe7, 0x4d76, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x727f, 0xffff, 0xffff, 0x30ff,
  538. 0xccff, 0xffff, 0xc6ff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x727f, 0xffff, 0xffff, 0x30ff,
  539. 0xf296, 0xffff, 0xb7c6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x939a, 0xffff, 0xffff, 0x30ff,
  540. 0xc97f, 0xffff, 0xf43c, 0x2493, 0x0000, 0x0000, 0x0000, 0x0000, 0x5f13, 0xfd0c, 0xffff, 0xffff, 0x3827,
  541. 0x6dc9, 0xffff, 0xffff, 0xeb16, 0x7dd4, 0x5541, 0x6c76, 0xc10f, 0xfff1, 0xffff, 0xffff, 0xffff, 0x49ff,
  542. 0x00d8, 0xa6e9, 0xfffe, 0xfffe, 0xfffe, 0xfffe, 0xfffe, 0xfffe, 0xd4fe, 0x83db, 0xffff, 0xffff, 0x7584,
  543. 0x0000, 0x001c, 0x503e, 0xbb08, 0xe3a1, 0xeea6, 0xbd0e, 0x7e09, 0x08e5, 0x1b8b, 0xb67f, 0xb67f, 0x7d44,
  544. }
  545. var flMask16 = []uint32{
  546. 0x0000, 0x0000, 0x05b5, 0x668a, 0xbbe0, 0xe875, 0xf803, 0xda29, 0xb49f, 0x4a7a, 0x000a, 0x0000, 0x0000,
  547. 0x0000, 0x2473, 0xd7fb, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xad4d, 0x0204, 0x0000,
  548. 0x0d48, 0xe27a, 0xffff, 0xf949, 0x8c70, 0x3bae, 0x2ac9, 0x51f7, 0xccc4, 0xffff, 0xffff, 0x779f, 0x0000,
  549. 0x75a1, 0xffff, 0xffff, 0x5d7b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0b23, 0xdf73, 0xffff, 0xe39d, 0x0000,
  550. 0x5ba0, 0x9033, 0x8f9f, 0x0609, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8db0, 0xffff, 0xffef, 0x1746,
  551. 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x728c, 0xffff, 0xffff, 0x3148,
  552. 0x0000, 0x0000, 0x0000, 0x17ac, 0x5bce, 0x78cb, 0x95b7, 0xa3d2, 0xa3d2, 0xcce6, 0xffff, 0xffff, 0x3148,
  553. 0x0000, 0x1919, 0x9bfd, 0xf86b, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x3148,
  554. 0x0c63, 0xcf97, 0xffff, 0xfc17, 0xb59d, 0x6981, 0x4f87, 0x3cf1, 0x3a68, 0x9276, 0xffff, 0xffff, 0x3148,
  555. 0x8eb0, 0xffff, 0xfbf5, 0x4d33, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7214, 0xffff, 0xffff, 0x3148,
  556. 0xccaf, 0xffff, 0xc6ba, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7214, 0xffff, 0xffff, 0x3148,
  557. 0xf292, 0xffff, 0xb865, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x930c, 0xffff, 0xffff, 0x3148,
  558. 0xc906, 0xffff, 0xf45d, 0x249f, 0x0000, 0x0000, 0x0000, 0x0000, 0x5ea0, 0xfcf1, 0xffff, 0xffff, 0x3888,
  559. 0x6d81, 0xffff, 0xffff, 0xeaf5, 0x7dcf, 0x5533, 0x6c2b, 0xc07b, 0xfff1, 0xffff, 0xffff, 0xffff, 0x4a9d,
  560. 0x00d4, 0xa6a1, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xd54d, 0x8399, 0xffff, 0xffff, 0x764b,
  561. 0x0000, 0x001b, 0x4ffc, 0xbb4a, 0xe3f5, 0xeee3, 0xbd4c, 0x7e42, 0x0900, 0x1b0c, 0xb6fc, 0xb6fc, 0x7e04,
  562. }
  563. // TestFixedFloatingCloseness compares the closeness of the fixed point and
  564. // floating point rasterizer.
  565. func TestFixedFloatingCloseness(t *testing.T) {
  566. if len(fxMask16) != len(flMask16) {
  567. t.Fatalf("len(fxMask16) != len(flMask16)")
  568. }
  569. total := uint32(0)
  570. for i := range fxMask16 {
  571. a := fxMask16[i]
  572. b := flMask16[i]
  573. if a > b {
  574. total += a - b
  575. } else {
  576. total += b - a
  577. }
  578. }
  579. n := len(fxMask16)
  580. // This log message is useful when changing the fixed point rasterizer
  581. // implementation, such as by changing ϕ. Assuming that the floating point
  582. // rasterizer is accurate, the average difference is a measure of how
  583. // inaccurate the (faster) fixed point rasterizer is.
  584. //
  585. // Smaller is better.
  586. percent := float64(total*100) / float64(n*65535)
  587. t.Logf("Comparing closeness of the fixed point and floating point rasterizer.\n"+
  588. "Specifically, the elements of fxMask16 and flMask16.\n"+
  589. "Total diff = %d, n = %d, avg = %.5f out of 65535, or %.5f%%.\n",
  590. total, n, float64(total)/float64(n), percent)
  591. const thresholdPercent = 1.0
  592. if percent > thresholdPercent {
  593. t.Errorf("average difference: got %.5f%%, want <= %.5f%%", percent, thresholdPercent)
  594. }
  595. }