1 // Copyright 2011 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 5 package draw 6 7 import ( 8 "image" 9 "image/color" 10 "reflect" 11 "testing" 12 ) 13 14 const ( 15 dstw, dsth = 640, 480 16 srcw, srch = 400, 300 17 ) 18 19 var palette = color.Palette{ 20 color.Black, 21 color.White, 22 } 23 24 // bench benchmarks drawing src and mask images onto a dst image with the 25 // given op and the color models to create those images from. 26 // The created images' pixels are initialized to non-zero values. 27 func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) { 28 b.StopTimer() 29 30 var dst Image 31 switch dcm { 32 case color.RGBAModel: 33 dst1 := image.NewRGBA(image.Rect(0, 0, dstw, dsth)) 34 for y := 0; y < dsth; y++ { 35 for x := 0; x < dstw; x++ { 36 dst1.SetRGBA(x, y, color.RGBA{ 37 uint8(5 * x % 0x100), 38 uint8(7 * y % 0x100), 39 uint8((7*x + 5*y) % 0x100), 40 0xff, 41 }) 42 } 43 } 44 dst = dst1 45 case color.RGBA64Model: 46 dst1 := image.NewRGBA64(image.Rect(0, 0, dstw, dsth)) 47 for y := 0; y < dsth; y++ { 48 for x := 0; x < dstw; x++ { 49 dst1.SetRGBA64(x, y, color.RGBA64{ 50 uint16(53 * x % 0x10000), 51 uint16(59 * y % 0x10000), 52 uint16((59*x + 53*y) % 0x10000), 53 0xffff, 54 }) 55 } 56 } 57 dst = dst1 58 default: 59 // The == operator isn't defined on a color.Palette (a slice), so we 60 // use reflection. 61 if reflect.DeepEqual(dcm, palette) { 62 dst1 := image.NewPaletted(image.Rect(0, 0, dstw, dsth), palette) 63 for y := 0; y < dsth; y++ { 64 for x := 0; x < dstw; x++ { 65 dst1.SetColorIndex(x, y, uint8(x^y)&1) 66 } 67 } 68 dst = dst1 69 } else { 70 b.Fatal("unknown destination color model", dcm) 71 } 72 } 73 74 var src image.Image 75 switch scm { 76 case nil: 77 src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0xff}} 78 case color.CMYKModel: 79 src1 := image.NewCMYK(image.Rect(0, 0, srcw, srch)) 80 for y := 0; y < srch; y++ { 81 for x := 0; x < srcw; x++ { 82 src1.SetCMYK(x, y, color.CMYK{ 83 uint8(13 * x % 0x100), 84 uint8(11 * y % 0x100), 85 uint8((11*x + 13*y) % 0x100), 86 uint8((31*x + 37*y) % 0x100), 87 }) 88 } 89 } 90 src = src1 91 case color.GrayModel: 92 src1 := image.NewGray(image.Rect(0, 0, srcw, srch)) 93 for y := 0; y < srch; y++ { 94 for x := 0; x < srcw; x++ { 95 src1.SetGray(x, y, color.Gray{ 96 uint8((11*x + 13*y) % 0x100), 97 }) 98 } 99 } 100 src = src1 101 case color.RGBAModel: 102 src1 := image.NewRGBA(image.Rect(0, 0, srcw, srch)) 103 for y := 0; y < srch; y++ { 104 for x := 0; x < srcw; x++ { 105 src1.SetRGBA(x, y, color.RGBA{ 106 uint8(13 * x % 0x80), 107 uint8(11 * y % 0x80), 108 uint8((11*x + 13*y) % 0x80), 109 0x7f, 110 }) 111 } 112 } 113 src = src1 114 case color.RGBA64Model: 115 src1 := image.NewRGBA64(image.Rect(0, 0, srcw, srch)) 116 for y := 0; y < srch; y++ { 117 for x := 0; x < srcw; x++ { 118 src1.SetRGBA64(x, y, color.RGBA64{ 119 uint16(103 * x % 0x8000), 120 uint16(101 * y % 0x8000), 121 uint16((101*x + 103*y) % 0x8000), 122 0x7fff, 123 }) 124 } 125 } 126 src = src1 127 case color.NRGBAModel: 128 src1 := image.NewNRGBA(image.Rect(0, 0, srcw, srch)) 129 for y := 0; y < srch; y++ { 130 for x := 0; x < srcw; x++ { 131 src1.SetNRGBA(x, y, color.NRGBA{ 132 uint8(13 * x % 0x100), 133 uint8(11 * y % 0x100), 134 uint8((11*x + 13*y) % 0x100), 135 0x7f, 136 }) 137 } 138 } 139 src = src1 140 case color.YCbCrModel: 141 yy := make([]uint8, srcw*srch) 142 cb := make([]uint8, srcw*srch) 143 cr := make([]uint8, srcw*srch) 144 for i := range yy { 145 yy[i] = uint8(3 * i % 0x100) 146 cb[i] = uint8(5 * i % 0x100) 147 cr[i] = uint8(7 * i % 0x100) 148 } 149 src = &image.YCbCr{ 150 Y: yy, 151 Cb: cb, 152 Cr: cr, 153 YStride: srcw, 154 CStride: srcw, 155 SubsampleRatio: image.YCbCrSubsampleRatio444, 156 Rect: image.Rect(0, 0, srcw, srch), 157 } 158 default: 159 b.Fatal("unknown source color model", scm) 160 } 161 162 var mask image.Image 163 switch mcm { 164 case nil: 165 // No-op. 166 case color.AlphaModel: 167 mask1 := image.NewAlpha(image.Rect(0, 0, srcw, srch)) 168 for y := 0; y < srch; y++ { 169 for x := 0; x < srcw; x++ { 170 a := uint8((23*x + 29*y) % 0x100) 171 // Glyph masks are typically mostly zero, 172 // so we only set a quarter of mask1's pixels. 173 if a >= 0xc0 { 174 mask1.SetAlpha(x, y, color.Alpha{a}) 175 } 176 } 177 } 178 mask = mask1 179 default: 180 b.Fatal("unknown mask color model", mcm) 181 } 182 183 b.StartTimer() 184 for i := 0; i < b.N; i++ { 185 // Scatter the destination rectangle to draw into. 186 x := 3 * i % (dstw - srcw) 187 y := 7 * i % (dsth - srch) 188 189 DrawMask(dst, dst.Bounds().Add(image.Pt(x, y)), src, image.ZP, mask, image.ZP, op) 190 } 191 } 192 193 // The BenchmarkFoo functions exercise a drawFoo fast-path function in draw.go. 194 195 func BenchmarkFillOver(b *testing.B) { 196 bench(b, color.RGBAModel, nil, nil, Over) 197 } 198 199 func BenchmarkFillSrc(b *testing.B) { 200 bench(b, color.RGBAModel, nil, nil, Src) 201 } 202 203 func BenchmarkCopyOver(b *testing.B) { 204 bench(b, color.RGBAModel, color.RGBAModel, nil, Over) 205 } 206 207 func BenchmarkCopySrc(b *testing.B) { 208 bench(b, color.RGBAModel, color.RGBAModel, nil, Src) 209 } 210 211 func BenchmarkNRGBAOver(b *testing.B) { 212 bench(b, color.RGBAModel, color.NRGBAModel, nil, Over) 213 } 214 215 func BenchmarkNRGBASrc(b *testing.B) { 216 bench(b, color.RGBAModel, color.NRGBAModel, nil, Src) 217 } 218 219 func BenchmarkYCbCr(b *testing.B) { 220 bench(b, color.RGBAModel, color.YCbCrModel, nil, Over) 221 } 222 223 func BenchmarkGray(b *testing.B) { 224 bench(b, color.RGBAModel, color.GrayModel, nil, Over) 225 } 226 227 func BenchmarkCMYK(b *testing.B) { 228 bench(b, color.RGBAModel, color.CMYKModel, nil, Over) 229 } 230 231 func BenchmarkGlyphOver(b *testing.B) { 232 bench(b, color.RGBAModel, nil, color.AlphaModel, Over) 233 } 234 235 func BenchmarkRGBA(b *testing.B) { 236 bench(b, color.RGBAModel, color.RGBA64Model, nil, Src) 237 } 238 239 func BenchmarkPaletted(b *testing.B) { 240 bench(b, palette, color.RGBAModel, nil, Src) 241 } 242 243 // The BenchmarkGenericFoo functions exercise the generic, slow-path code. 244 245 func BenchmarkGenericOver(b *testing.B) { 246 bench(b, color.RGBA64Model, color.RGBA64Model, nil, Over) 247 } 248 249 func BenchmarkGenericMaskOver(b *testing.B) { 250 bench(b, color.RGBA64Model, color.RGBA64Model, color.AlphaModel, Over) 251 } 252 253 func BenchmarkGenericSrc(b *testing.B) { 254 bench(b, color.RGBA64Model, color.RGBA64Model, nil, Src) 255 } 256 257 func BenchmarkGenericMaskSrc(b *testing.B) { 258 bench(b, color.RGBA64Model, color.RGBA64Model, color.AlphaModel, Src) 259 } 260