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