Home | History | Annotate | Download | only in draw
      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