blob: f748fcea494ca91721fedd1e65978e0b4e4eb637 [file] [log] [blame]
Alexey Marinichev9f9b8732010-05-20 19:33:44 -07001// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Alexey Marinichevf50ecb12010-06-14 15:21:41 -07005#include <gflags/gflags.h>
Alexey Marinichev9f9b8732010-05-20 19:33:44 -07006#include <stdio.h>
Ilja H. Friedel8faad302011-04-26 14:40:49 -07007#include <png.h>
Alexey Marinichev9f9b8732010-05-20 19:33:44 -07008
Chris Masone28cc0252011-05-13 11:45:07 -07009#include "base/memory/scoped_ptr.h"
Alexey Marinichevf50ecb12010-06-14 15:21:41 -070010#include "base/file_util.h"
11
Ilja H. Friedel8faad302011-04-26 14:40:49 -070012#include "png_helper.h"
13#include "md5.h"
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070014#include "testbase.h"
Alexey Marinichevf50ecb12010-06-14 15:21:41 -070015#include "utils.h"
16
17DEFINE_bool(save, false, "save images after each test case");
Ilja H. Friedel8faad302011-04-26 14:40:49 -070018DEFINE_string(outdir, "", "directory to save images");
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070019
20namespace glbench {
21
22uint64_t TimeTest(TestBase* test, int iter) {
Ilja H. Friedel8faad302011-04-26 14:40:49 -070023 SwapBuffers();
24 glFinish();
25 uint64_t time1 = GetUTime();
26 if (!test->TestFunc(iter))
27 return ~0;
28 glFinish();
29 uint64_t time2 = GetUTime();
30 return time2 - time1;
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070031}
32
Stuart Abercrombieddd7fae2012-06-04 11:55:24 -070033// Maximum iteration time of 0.1s for regression approach
34#define MAX_ITERATION_DURATION_US 100000
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070035
36// Benchmark some draw commands, by running it many times.
Ilja H. Friedel8faad302011-04-26 14:40:49 -070037// We want to measure the marginal cost, so we try more and more
38// iterations until we get a somewhat linear response (to
39// eliminate constant cost), and we do a linear regression on
40// a few samples.
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070041bool Bench(TestBase* test, float *slope, int64_t *bias) {
42 // Do one iteration in case the driver needs to set up states.
Stuart Abercrombieddd7fae2012-06-04 11:55:24 -070043 uint64_t initial_time = TimeTest(test, 1);
44 if (initial_time > MAX_ITERATION_DURATION_US) {
45 // The test is too slow to do the regression,
46 // so just return a single result.
47 *slope = static_cast<float>(TimeTest(test, 1));
48 *bias = 0;
49 return true;
50 }
51
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070052 int64_t count = 0;
53 int64_t sum_x = 0;
54 int64_t sum_y = 0;
55 int64_t sum_xy = 0;
56 int64_t sum_x2 = 0;
57 uint64_t last_time = 0;
58 bool do_count = false;
59 uint64_t iter;
60 for (iter = 8; iter < 1<<30; iter *= 2) {
61 uint64_t time = TimeTest(test, iter);
Ilja H. Friedel8faad302011-04-26 14:40:49 -070062 if (last_time > 0 && (time > last_time * 1.8)) {
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070063 do_count = true;
Ilja H. Friedel8faad302011-04-26 14:40:49 -070064 }
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070065 last_time = time;
66 if (do_count) {
67 ++count;
68 sum_x += iter;
69 sum_y += time;
70 sum_xy += iter * time;
71 sum_x2 += iter * iter;
72 }
73 if ((time >= 500000 && count > 4))
74 break;
75 }
76 if (count < 2) {
77 *slope = 0.f;
78 *bias = 0;
79 }
80 *slope = static_cast<float>(sum_x * sum_y - count * sum_xy) /
81 (sum_x * sum_x - count * sum_x2);
82 *bias = (sum_x * sum_xy - sum_x2 * sum_y) / (sum_x * sum_x - count * sum_x2);
83 return true;
84}
85
Alexey Marinichevf50ecb12010-06-14 15:21:41 -070086void SaveImage(const char* name) {
87 const int size = g_width * g_height * 4;
88 scoped_array<char> pixels(new char[size]);
Ilja H. Friedel8faad302011-04-26 14:40:49 -070089 glReadPixels(0, 0, g_width, g_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
90 // I really think we want to use outdir as a straight argument
91 FilePath dirname = FilePath(FLAGS_outdir);
Alexey Marinichevf50ecb12010-06-14 15:21:41 -070092 file_util::CreateDirectory(dirname);
93 FilePath filename = dirname.Append(name);
Ilja H. Friedel8faad302011-04-26 14:40:49 -070094 write_png_file(filename.value().c_str(),
95 pixels.get(), g_width, g_height);
Alexey Marinichevf50ecb12010-06-14 15:21:41 -070096}
97
Ilja H. Friedel8faad302011-04-26 14:40:49 -070098void ComputeMD5(unsigned char digest[16]) {
99 MD5Context ctx;
100 MD5Init(&ctx);
101 const int size = g_width * g_height * 4;
102 scoped_array<char> pixels(new char[size]);
103 glReadPixels(0, 0, g_width, g_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
104 MD5Update(&ctx, (unsigned char *)pixels.get(), 4*g_width*g_height);
105 MD5Final(digest, &ctx);
106}
107
108void RunTest(TestBase* test, const char* testname,
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700109 float coefficient, bool inverse) {
110 float slope;
111 int64_t bias;
112
Ilja H. Friedel8faad302011-04-26 14:40:49 -0700113 GLenum error = glGetError();
114 if (error == GL_NO_ERROR) {
115 bool status = Bench(test, &slope, &bias);
116 if (status) {
117 // save as png with MD5 as hex string attached
118 char pixmd5[33];
119 unsigned char d[16];
120 ComputeMD5(d);
121 // translate to hexadecimal ASCII of MD5
122 sprintf(pixmd5,
123 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
124 d[ 0],d[ 1],d[ 2],d[ 3],d[ 4],d[ 5],d[ 6],d[ 7],
125 d[ 8],d[ 9],d[10],d[11],d[12],d[13],d[14],d[15]);
126 char name_png[512];
127 sprintf(name_png, "%s.pixmd5-%s.png", testname, pixmd5);
128
Alexey Marinichevf50ecb12010-06-14 15:21:41 -0700129 if (FLAGS_save)
Ilja H. Friedel8faad302011-04-26 14:40:49 -0700130 SaveImage(name_png);
131
132 // TODO(ihf) adjust string length based on longest test name
133 int length = strlen(testname);
134 if (length > 45)
135 printf("# Warning: adjust string formatting to length = %d\n",
136 length);
137 printf("%-45s= %10.2f [%s]\n",
138 testname,
139 coefficient * (inverse ? 1.f / slope : slope),
140 name_png);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700141 } else {
Stuart Abercrombieddd7fae2012-06-04 11:55:24 -0700142 printf("# Warning: %s scales non-linearly, returning zero.\n",
Ilja H. Friedel8faad302011-04-26 14:40:49 -0700143 testname);
144 printf("%-45s= 0 []\n", testname);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700145 }
Ilja H. Friedel8faad302011-04-26 14:40:49 -0700146 } else {
147 printf("# Error: %s aborted, glGetError returned 0x%02x.\n",
148 testname, error);
149 // float() in python will happily parse Nan.
150 printf("%-45s= Nan []\n", testname);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700151 }
152}
153
154bool DrawArraysTestFunc::TestFunc(int iter) {
155 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
156 glFlush();
157 for (int i = 0; i < iter-1; ++i) {
158 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
159 }
160 return true;
161}
162
163
164void DrawArraysTestFunc::FillRateTestNormal(const char* name) {
165 FillRateTestNormalSubWindow(name, g_width, g_height);
166}
167
168
169void DrawArraysTestFunc::FillRateTestNormalSubWindow(const char* name,
170 float width, float height)
171{
172 const int buffer_len = 64;
173 char buffer[buffer_len];
174 snprintf(buffer, buffer_len, "mpixels_sec_%s", name);
175 RunTest(this, buffer, width * height, true);
176}
177
178
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700179void DrawArraysTestFunc::FillRateTestBlendDepth(const char *name) {
180 const int buffer_len = 64;
181 char buffer[buffer_len];
182
183 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
184 glEnable(GL_BLEND);
185 snprintf(buffer, buffer_len, "mpixels_sec_%s_blended", name);
186 RunTest(this, buffer, g_width * g_height, true);
187 glDisable(GL_BLEND);
188
189 glEnable(GL_DEPTH_TEST);
190 glDepthFunc(GL_NOTEQUAL);
191 snprintf(buffer, buffer_len, "mpixels_sec_%s_depth_neq", name);
192 RunTest(this, buffer, g_width * g_height, true);
193 glDepthFunc(GL_NEVER);
194 snprintf(buffer, buffer_len, "mpixels_sec_%s_depth_never", name);
195 RunTest(this, buffer, g_width * g_height, true);
196 glDisable(GL_DEPTH_TEST);
197}
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700198
199
200bool DrawElementsTestFunc::TestFunc(int iter) {
Kenneth Watersa1a86cb2011-01-18 09:48:20 -0800201 glClearColor(0, 1.f, 0, 1.f);
202 glClear(GL_COLOR_BUFFER_BIT);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700203 glDrawElements(GL_TRIANGLES, count_, GL_UNSIGNED_INT, 0);
204 glFlush();
205 for (int i = 0 ; i < iter-1; ++i) {
206 glDrawElements(GL_TRIANGLES, count_, GL_UNSIGNED_INT, 0);
207 }
208 return true;
209}
210
211} // namespace glbench