blob: 83c43a8b8161f8d8216cb702766a0da7eee174f0 [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
Kenneth Waters52e113a2010-12-06 11:44:32 -080033#define MAX_ITERATION_DURATION_MS 1000000
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070034
35// Benchmark some draw commands, by running it many times.
Ilja H. Friedel8faad302011-04-26 14:40:49 -070036// We want to measure the marginal cost, so we try more and more
37// iterations until we get a somewhat linear response (to
38// eliminate constant cost), and we do a linear regression on
39// a few samples.
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070040bool Bench(TestBase* test, float *slope, int64_t *bias) {
41 // Do one iteration in case the driver needs to set up states.
42 if (TimeTest(test, 1) > MAX_ITERATION_DURATION_MS)
43 return false;
44 int64_t count = 0;
45 int64_t sum_x = 0;
46 int64_t sum_y = 0;
47 int64_t sum_xy = 0;
48 int64_t sum_x2 = 0;
49 uint64_t last_time = 0;
50 bool do_count = false;
51 uint64_t iter;
52 for (iter = 8; iter < 1<<30; iter *= 2) {
53 uint64_t time = TimeTest(test, iter);
Ilja H. Friedel8faad302011-04-26 14:40:49 -070054 if (last_time > 0 && (time > last_time * 1.8)) {
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070055 do_count = true;
Ilja H. Friedel8faad302011-04-26 14:40:49 -070056 }
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070057 last_time = time;
58 if (do_count) {
59 ++count;
60 sum_x += iter;
61 sum_y += time;
62 sum_xy += iter * time;
63 sum_x2 += iter * iter;
64 }
65 if ((time >= 500000 && count > 4))
66 break;
67 }
68 if (count < 2) {
69 *slope = 0.f;
70 *bias = 0;
71 }
72 *slope = static_cast<float>(sum_x * sum_y - count * sum_xy) /
73 (sum_x * sum_x - count * sum_x2);
74 *bias = (sum_x * sum_xy - sum_x2 * sum_y) / (sum_x * sum_x - count * sum_x2);
75 return true;
76}
77
Alexey Marinichevf50ecb12010-06-14 15:21:41 -070078void SaveImage(const char* name) {
79 const int size = g_width * g_height * 4;
80 scoped_array<char> pixels(new char[size]);
Ilja H. Friedel8faad302011-04-26 14:40:49 -070081 glReadPixels(0, 0, g_width, g_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
82 // I really think we want to use outdir as a straight argument
83 FilePath dirname = FilePath(FLAGS_outdir);
Alexey Marinichevf50ecb12010-06-14 15:21:41 -070084 file_util::CreateDirectory(dirname);
85 FilePath filename = dirname.Append(name);
Ilja H. Friedel8faad302011-04-26 14:40:49 -070086 write_png_file(filename.value().c_str(),
87 pixels.get(), g_width, g_height);
Alexey Marinichevf50ecb12010-06-14 15:21:41 -070088}
89
Ilja H. Friedel8faad302011-04-26 14:40:49 -070090void ComputeMD5(unsigned char digest[16]) {
91 MD5Context ctx;
92 MD5Init(&ctx);
93 const int size = g_width * g_height * 4;
94 scoped_array<char> pixels(new char[size]);
95 glReadPixels(0, 0, g_width, g_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
96 MD5Update(&ctx, (unsigned char *)pixels.get(), 4*g_width*g_height);
97 MD5Final(digest, &ctx);
98}
99
100void RunTest(TestBase* test, const char* testname,
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700101 float coefficient, bool inverse) {
102 float slope;
103 int64_t bias;
104
Ilja H. Friedel8faad302011-04-26 14:40:49 -0700105 GLenum error = glGetError();
106 if (error == GL_NO_ERROR) {
107 bool status = Bench(test, &slope, &bias);
108 if (status) {
109 // save as png with MD5 as hex string attached
110 char pixmd5[33];
111 unsigned char d[16];
112 ComputeMD5(d);
113 // translate to hexadecimal ASCII of MD5
114 sprintf(pixmd5,
115 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
116 d[ 0],d[ 1],d[ 2],d[ 3],d[ 4],d[ 5],d[ 6],d[ 7],
117 d[ 8],d[ 9],d[10],d[11],d[12],d[13],d[14],d[15]);
118 char name_png[512];
119 sprintf(name_png, "%s.pixmd5-%s.png", testname, pixmd5);
120
Alexey Marinichevf50ecb12010-06-14 15:21:41 -0700121 if (FLAGS_save)
Ilja H. Friedel8faad302011-04-26 14:40:49 -0700122 SaveImage(name_png);
123
124 // TODO(ihf) adjust string length based on longest test name
125 int length = strlen(testname);
126 if (length > 45)
127 printf("# Warning: adjust string formatting to length = %d\n",
128 length);
129 printf("%-45s= %10.2f [%s]\n",
130 testname,
131 coefficient * (inverse ? 1.f / slope : slope),
132 name_png);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700133 } else {
Ilja H. Friedel8faad302011-04-26 14:40:49 -0700134 printf("# Warning: %s is scales nonlinear, returning zero.\n",
135 testname);
136 printf("%-45s= 0 []\n", testname);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700137 }
Ilja H. Friedel8faad302011-04-26 14:40:49 -0700138 } else {
139 printf("# Error: %s aborted, glGetError returned 0x%02x.\n",
140 testname, error);
141 // float() in python will happily parse Nan.
142 printf("%-45s= Nan []\n", testname);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700143 }
144}
145
146bool DrawArraysTestFunc::TestFunc(int iter) {
147 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
148 glFlush();
149 for (int i = 0; i < iter-1; ++i) {
150 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
151 }
152 return true;
153}
154
155
156void DrawArraysTestFunc::FillRateTestNormal(const char* name) {
157 FillRateTestNormalSubWindow(name, g_width, g_height);
158}
159
160
161void DrawArraysTestFunc::FillRateTestNormalSubWindow(const char* name,
162 float width, float height)
163{
164 const int buffer_len = 64;
165 char buffer[buffer_len];
166 snprintf(buffer, buffer_len, "mpixels_sec_%s", name);
167 RunTest(this, buffer, width * height, true);
168}
169
170
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700171void DrawArraysTestFunc::FillRateTestBlendDepth(const char *name) {
172 const int buffer_len = 64;
173 char buffer[buffer_len];
174
175 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
176 glEnable(GL_BLEND);
177 snprintf(buffer, buffer_len, "mpixels_sec_%s_blended", name);
178 RunTest(this, buffer, g_width * g_height, true);
179 glDisable(GL_BLEND);
180
181 glEnable(GL_DEPTH_TEST);
182 glDepthFunc(GL_NOTEQUAL);
183 snprintf(buffer, buffer_len, "mpixels_sec_%s_depth_neq", name);
184 RunTest(this, buffer, g_width * g_height, true);
185 glDepthFunc(GL_NEVER);
186 snprintf(buffer, buffer_len, "mpixels_sec_%s_depth_never", name);
187 RunTest(this, buffer, g_width * g_height, true);
188 glDisable(GL_DEPTH_TEST);
189}
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700190
191
192bool DrawElementsTestFunc::TestFunc(int iter) {
Kenneth Watersa1a86cb2011-01-18 09:48:20 -0800193 glClearColor(0, 1.f, 0, 1.f);
194 glClear(GL_COLOR_BUFFER_BIT);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700195 glDrawElements(GL_TRIANGLES, count_, GL_UNSIGNED_INT, 0);
196 glFlush();
197 for (int i = 0 ; i < iter-1; ++i) {
198 glDrawElements(GL_TRIANGLES, count_, GL_UNSIGNED_INT, 0);
199 }
200 return true;
201}
202
203} // namespace glbench