github.com/gop9/olt@v0.0.0-20200202132135-d956aad50b08/framework/drawfillover_test.go (about) 1 package framework 2 3 import ( 4 "image" 5 "testing" 6 ) 7 8 func drawFillOver_Normal(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) { 9 const m = 1<<16 - 1 10 // The 0x101 is here for the same reason as in drawRGBA. 11 a := (m - sa) * 0x101 12 i0 := dst.PixOffset(r.Min.X, r.Min.Y) 13 i1 := i0 + r.Dx()*4 14 for y := r.Min.Y; y != r.Max.Y; y++ { 15 for i := i0; i < i1; i += 4 { 16 dr := &dst.Pix[i+0] 17 dg := &dst.Pix[i+1] 18 db := &dst.Pix[i+2] 19 da := &dst.Pix[i+3] 20 21 *dr = uint8((uint32(*dr)*a/m + sr) >> 8) 22 *dg = uint8((uint32(*dg)*a/m + sg) >> 8) 23 *db = uint8((uint32(*db)*a/m + sb) >> 8) 24 *da = uint8((uint32(*da)*a/m + sa) >> 8) 25 } 26 i0 += dst.Stride 27 i1 += dst.Stride 28 } 29 } 30 31 func drawFillOver_NoPtr(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) { 32 const m = 1<<16 - 1 33 // The 0x101 is here for the same reason as in drawRGBA. 34 a := (m - sa) * 0x101 35 i0 := dst.PixOffset(r.Min.X, r.Min.Y) 36 i1 := i0 + r.Dx()*4 37 for y := r.Min.Y; y != r.Max.Y; y++ { 38 for i := i0; i < i1; i += 4 { 39 dst.Pix[i+0] = uint8((uint32(dst.Pix[i+0])*a/m + sr) >> 8) 40 dst.Pix[i+1] = uint8((uint32(dst.Pix[i+1])*a/m + sg) >> 8) 41 dst.Pix[i+2] = uint8((uint32(dst.Pix[i+2])*a/m + sb) >> 8) 42 dst.Pix[i+3] = uint8((uint32(dst.Pix[i+3])*a/m + sa) >> 8) 43 } 44 i0 += dst.Stride 45 i1 += dst.Stride 46 } 47 } 48 49 func drawFillOver_SIMD(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) { 50 const m = 1<<16 - 1 51 a := (m - sa) * 0x101 52 adivm := a / m 53 i0 := dst.PixOffset(r.Min.X, r.Min.Y) 54 i1 := i0 + r.Dx()*4 55 drawFillOver_SIMD_internal(&dst.Pix[0], i0, i1, dst.Stride, r.Max.Y-r.Min.Y, adivm, sr, sg, sb, sa) 56 } 57 58 func clearImg(b *image.RGBA) { 59 for i := 0; i < len(b.Pix); i += 4 { 60 b.Pix[i+0] = 50 61 b.Pix[i+1] = 50 62 b.Pix[i+2] = 50 63 b.Pix[i+3] = 255 64 } 65 } 66 67 func checkUniform(t *testing.T, b *image.RGBA, tgtr, tgtg, tgtb, tgta uint8) { 68 ok := true 69 for i := 0; i < len(b.Pix); i += 4 { 70 if b.Pix[i+0] != tgtr { 71 ok = false 72 t.Errorf("mismatch at pixel %d (red) %d %d\n", i/4, b.Pix[i+0], tgtr) 73 } 74 if b.Pix[i+1] != tgtg { 75 ok = false 76 t.Errorf("mismatch at pixel %d (green) %d %d\n", i/4, b.Pix[i+1], tgtg) 77 } 78 if b.Pix[i+2] != tgtb { 79 ok = false 80 t.Errorf("mismatch at pixel %d (blue) %d %d\n", i/4, b.Pix[i+2], tgtb) 81 } 82 if b.Pix[i+3] != tgta { 83 ok = false 84 t.Errorf("mismatch at pixel %d (alpha) %d %d\n", i/4, b.Pix[i+3], tgta) 85 } 86 if !ok { 87 t.Fatal("previous errors") 88 } 89 } 90 outr, outg, outb, outa := b.Pix[0], b.Pix[1], b.Pix[2], b.Pix[3] 91 t.Logf("color %d %d %d %d\n", outr, outg, outb, outa) 92 } 93 94 type fillOverFunc func(b *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) 95 96 func testFillOver(t *testing.T, b *image.RGBA, fo fillOverFunc) { 97 clearImg(b) 98 fo(b, b.Bounds(), 12850, 14906, 15677, 57825) 99 checkUniform(t, b, 56, 64, 67, 255) 100 } 101 102 func TestDrawFillOver(t *testing.T) { 103 b := image.NewRGBA(image.Rect(0, 0, 2550, 1400)) 104 testFillOver(t, b, drawFillOver_Normal) 105 testFillOver(t, b, drawFillOver_NoPtr) 106 testFillOver(t, b, drawFillOver_SIMD) 107 } 108 109 func benchFillOver(bnc *testing.B, fo fillOverFunc) { 110 bnc.StopTimer() 111 b := image.NewRGBA(image.Rect(0, 0, 2550, 1400)) 112 113 for n := 0; n < bnc.N; n++ { 114 clearImg(b) 115 bnc.StartTimer() 116 fo(b, b.Bounds(), 12850, 14906, 15677, 57825) 117 bnc.StopTimer() 118 } 119 120 } 121 122 // go test -bench=DrawFillOver -run=NONE -v 123 124 func BenchmarkDrawFillOverNormal(bnc *testing.B) { // 18734046 ns/op 125 benchFillOver(bnc, drawFillOver_Normal) 126 } 127 128 func BenchmarkDrawFillOverNoPtr(bnc *testing.B) { // 19357654 ns/op 129 benchFillOver(bnc, drawFillOver_NoPtr) 130 } 131 132 func BenchmarkDrawFillOverSIMD(bnc *testing.B) { // 4644812 ns/op 133 benchFillOver(bnc, drawFillOver_SIMD) 134 }