blob: 2b5dda542bdc8aa591c73cdde782554280756d02 [file] [log] [blame]
Hal Canaryd7b38452017-12-11 17:46:26 -05001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7package main
8
9import (
10 "encoding/json"
11 "errors"
12 "fmt"
13 "image"
14 "image/draw"
15 "image/png"
16 "log"
17 "net/http"
18 "os"
19 "path"
20 "sort"
21 "strings"
22 "sync"
23
24 "go.skia.org/infra/golden/go/search"
25)
26
27const (
28 min_png = "min.png"
29 max_png = "max.png"
30)
31
32type ExportTestRecordArray []search.ExportTestRecord
33
34func (a ExportTestRecordArray) Len() int { return len(a) }
35func (a ExportTestRecordArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
36func (a ExportTestRecordArray) Less(i, j int) bool { return a[i].TestName < a[j].TestName }
37
38func in(v string, a []string) bool {
39 for _, u := range a {
40 if u == v {
41 return true
42 }
43 }
44 return false
45}
46
Hal Canary9ef09892018-01-24 11:22:57 -050047func clampU8(v int) uint8 {
48 if v < 0 {
49 return 0
50 } else if v > 255 {
51 return 255
52 }
53 return uint8(v)
54}
55
Hal Canaryac7f23c2018-11-26 14:07:41 -050056func processTest(testName string, imgUrls []string, output string) (bool, error) {
Hal Canaryd7b38452017-12-11 17:46:26 -050057 if strings.ContainsRune(testName, '/') {
Hal Canaryac7f23c2018-11-26 14:07:41 -050058 return false, nil
Hal Canaryd7b38452017-12-11 17:46:26 -050059 }
60 output_directory := path.Join(output, testName)
61 var img_max image.NRGBA
62 var img_min image.NRGBA
63 for _, url := range imgUrls {
64 resp, err := http.Get(url)
65 if err != nil {
Hal Canaryac7f23c2018-11-26 14:07:41 -050066 return false, err
Hal Canaryd7b38452017-12-11 17:46:26 -050067 }
68 img, err := png.Decode(resp.Body)
69 resp.Body.Close()
70 if err != nil {
Hal Canaryac7f23c2018-11-26 14:07:41 -050071 return false, err
Hal Canaryd7b38452017-12-11 17:46:26 -050072 }
73 if img_max.Rect.Max.X == 0 {
74 // N.B. img_max.Pix may alias img.Pix (if they're already NRGBA).
75 img_max = toNrgba(img)
76 img_min = copyNrgba(img_max)
77 continue
78 }
79 w := img.Bounds().Max.X - img.Bounds().Min.X
80 h := img.Bounds().Max.Y - img.Bounds().Min.Y
81 if img_max.Rect.Max.X != w || img_max.Rect.Max.Y != h {
Hal Canaryac7f23c2018-11-26 14:07:41 -050082 return false, errors.New("size mismatch")
Hal Canaryd7b38452017-12-11 17:46:26 -050083 }
84 img_nrgba := toNrgba(img)
85 for i, value := range img_nrgba.Pix {
86 if value > img_max.Pix[i] {
87 img_max.Pix[i] = value
88 } else if value < img_min.Pix[i] {
89 img_min.Pix[i] = value
90 }
91 }
92 }
93 if img_max.Rect.Max.X == 0 {
Hal Canaryac7f23c2018-11-26 14:07:41 -050094 return false, nil
Hal Canaryd7b38452017-12-11 17:46:26 -050095 }
Hal Canary9ef09892018-01-24 11:22:57 -050096
Hal Canaryd7b38452017-12-11 17:46:26 -050097 if err := os.Mkdir(output_directory, os.ModePerm); err != nil && !os.IsExist(err) {
Hal Canaryac7f23c2018-11-26 14:07:41 -050098 return false, err
Hal Canaryd7b38452017-12-11 17:46:26 -050099 }
100 if err := writePngToFile(path.Join(output_directory, min_png), &img_min); err != nil {
Hal Canaryac7f23c2018-11-26 14:07:41 -0500101 return false, err
Hal Canaryd7b38452017-12-11 17:46:26 -0500102 }
103 if err := writePngToFile(path.Join(output_directory, max_png), &img_max); err != nil {
Hal Canaryac7f23c2018-11-26 14:07:41 -0500104 return false, err
Hal Canaryd7b38452017-12-11 17:46:26 -0500105 }
Hal Canaryac7f23c2018-11-26 14:07:41 -0500106 return true, nil
Hal Canaryd7b38452017-12-11 17:46:26 -0500107}
108
Hal Canaryac7f23c2018-11-26 14:07:41 -0500109type LockedStringList struct {
110 List []string
111 mux sync.Mutex
112}
113
114func (l *LockedStringList) add(v string) {
115 l.mux.Lock()
116 defer l.mux.Unlock()
117 l.List = append(l.List, v)
118}
119
120
Hal Canaryd7b38452017-12-11 17:46:26 -0500121func readMetaJsonFile(filename string) ([]search.ExportTestRecord, error) {
122 file, err := os.Open(filename)
123 if err != nil {
124 return nil, err
125 }
126 dec := json.NewDecoder(file)
127 var records []search.ExportTestRecord
128 err = dec.Decode(&records)
129 return records, err
130}
131
132func writePngToFile(path string, img image.Image) error {
133 file, err := os.Create(path)
134 if err != nil {
135 return err
136 }
137 defer file.Close()
138 return png.Encode(file, img)
139}
140
141// to_nrgb() may return a shallow copy of img if it's already NRGBA.
142func toNrgba(img image.Image) image.NRGBA {
143 switch v := img.(type) {
144 case *image.NRGBA:
145 return *v
146 }
147 nimg := *image.NewNRGBA(img.Bounds())
148 draw.Draw(&nimg, img.Bounds(), img, image.Point{0, 0}, draw.Src)
149 return nimg
150}
151
152func copyNrgba(src image.NRGBA) image.NRGBA {
153 dst := image.NRGBA{make([]uint8, len(src.Pix)), src.Stride, src.Rect}
154 copy(dst.Pix, src.Pix)
155 return dst
156}
157
158func main() {
159 if len(os.Args) != 3 {
160 log.Printf("Usage:\n %s INPUT.json OUTPUT_DIRECTORY\n\n", os.Args[0])
161 os.Exit(1)
162 }
163 input := os.Args[1]
164 output := os.Args[2]
Hal Canary2a7f0aa2017-12-18 16:59:56 -0500165 // output is removed and replaced with a clean directory.
166 if err := os.RemoveAll(output); err != nil && !os.IsNotExist(err) {
167 log.Fatal(err)
168 }
169 if err := os.MkdirAll(output, os.ModePerm); err != nil && !os.IsExist(err) {
Hal Canaryd7b38452017-12-11 17:46:26 -0500170 log.Fatal(err)
171 }
172
173 records, err := readMetaJsonFile(input)
174 if err != nil {
175 log.Fatal(err)
176 }
177 sort.Sort(ExportTestRecordArray(records))
178
Hal Canaryac7f23c2018-11-26 14:07:41 -0500179 var results LockedStringList
Hal Canaryd7b38452017-12-11 17:46:26 -0500180 var wg sync.WaitGroup
181 for _, record := range records {
Hal Canaryd7b38452017-12-11 17:46:26 -0500182 var goodUrls []string
183 for _, digest := range record.Digests {
184 if (in("vk", digest.ParamSet["config"]) ||
185 in("gles", digest.ParamSet["config"])) &&
186 digest.Status == "positive" {
187 goodUrls = append(goodUrls, digest.URL)
188 }
189 }
190 wg.Add(1)
Hal Canaryac7f23c2018-11-26 14:07:41 -0500191 go func(testName string, imgUrls []string, output string, results* LockedStringList) {
Hal Canaryd7b38452017-12-11 17:46:26 -0500192 defer wg.Done()
Hal Canaryac7f23c2018-11-26 14:07:41 -0500193 success, err := processTest(testName, imgUrls, output)
194 if err != nil {
Hal Canaryd7b38452017-12-11 17:46:26 -0500195 log.Fatal(err)
196 }
Hal Canaryac7f23c2018-11-26 14:07:41 -0500197 if success {
198 results.add(testName)
199 }
Hal Canaryd7b38452017-12-11 17:46:26 -0500200 fmt.Printf("\r%-60s", testName)
Hal Canaryac7f23c2018-11-26 14:07:41 -0500201 }(record.TestName, goodUrls, output, &results)
Hal Canaryd7b38452017-12-11 17:46:26 -0500202 }
203 wg.Wait()
204 fmt.Printf("\r%60s\n", "")
Hal Canaryac7f23c2018-11-26 14:07:41 -0500205 sort.Strings(results.List)
206 modelFile, err := os.Create(path.Join(output, "models.txt"))
207 if err != nil {
208 log.Fatal(err)
209 }
210 for _, v := range results.List {
211 fmt.Fprintln(modelFile, v)
212 }
Hal Canaryd7b38452017-12-11 17:46:26 -0500213}