1 // 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
5 #include <fcntl.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <sys/mman.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11
12 #include "base/logging.h"
13
14 #include "glinterface.h"
15 #include "main.h"
16 #include "utils.h"
17
18 using base::FilePath;
19
20 const char* kGlesHeader =
21 "#ifdef GL_ES\n"
22 "precision highp float;\n"
23 "#endif\n";
24
25 FilePath *g_base_path = new FilePath();
26 double g_initial_temperature = -1000.0;
27 const char* TEMPERATURE_SCRIPT_PATH = "/usr/local/autotest/bin/temperature.py";
28
29 // Sets the base path for MmapFile to `dirname($argv0)`/$relative.
SetBasePathFromArgv0(const char * argv0,const char * relative)30 void SetBasePathFromArgv0(const char* argv0, const char* relative) {
31 if (g_base_path) {
32 delete g_base_path;
33 }
34 FilePath argv0_path = FilePath(argv0).DirName();
35 FilePath base_path = relative ? argv0_path.Append(relative) : argv0_path;
36 g_base_path = new FilePath(base_path);
37 }
38
GetBasePath()39 const FilePath& GetBasePath() {
40 return *g_base_path;
41 }
42
MmapFile(const char * name,size_t * length)43 void *MmapFile(const char* name, size_t* length) {
44 FilePath filename = g_base_path->Append(name);
45 int fd = open(filename.value().c_str(), O_RDONLY);
46 if (fd == -1)
47 return NULL;
48
49 struct stat sb;
50 CHECK(fstat(fd, &sb) != -1);
51
52 char *mmap_ptr = static_cast<char *>(
53 mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0));
54
55 close(fd);
56
57 if (mmap_ptr)
58 *length = sb.st_size;
59
60 return mmap_ptr;
61 }
62
read_int_from_file(FilePath filename,int * value)63 bool read_int_from_file(FilePath filename, int *value) {
64 FILE *fd = fopen(filename.value().c_str(), "r");
65 if (!fd) {
66 return false;
67 }
68 int count = fscanf(fd, "%d", value);
69 if (count != 1) {
70 printf("Error: could not read integer from file. (%s)\n",
71 filename.value().c_str());
72 if(count != 1)
73 return false;
74 }
75 fclose(fd);
76 return true;
77 }
78
read_float_from_cmd_output(const char * command,double * value)79 bool read_float_from_cmd_output(const char *command, double *value) {
80 FILE *fd = popen(command, "r");
81 if (!fd) {
82 printf("Error: could not popen command. (%s)\n", command);
83 return false;
84 }
85 int count = fscanf(fd, "%lf", value);
86 if (count != 1) {
87 printf("Error: could not read float from command output. (%s)\n",
88 command);
89 return false;
90 }
91 pclose(fd);
92 return true;
93 }
94
95 // Returns temperature at which CPU gets throttled.
get_temperature_critical()96 double get_temperature_critical() {
97 char command[1024];
98 sprintf(command, "%s %s", TEMPERATURE_SCRIPT_PATH, "--critical");
99 double temperature_Celsius = 0.0;
100 if (!read_float_from_cmd_output(command, &temperature_Celsius)) {
101 // 85'C is the minimum observed critical temperature so far.
102 printf("Warning: guessing critical temperature as 85'C.\n");
103 return 85.0;
104 }
105 // Simple sanity check for reasonable critical temperatures.
106 assert(temperature_Celsius >= 60.0);
107 assert(temperature_Celsius <= 150.0);
108 return temperature_Celsius;
109 }
110
111
112 // Returns currently measured temperature.
get_temperature_input()113 double get_temperature_input() {
114 char command[1024];
115 sprintf(command, "%s %s", TEMPERATURE_SCRIPT_PATH, "--maximum");
116 double temperature_Celsius = -1000.0;
117 read_float_from_cmd_output(command, &temperature_Celsius);
118
119 if (temperature_Celsius < 10.0 || temperature_Celsius > 150.0) {
120 printf("Warning: ignoring temperature reading of %f'C.\n",
121 temperature_Celsius);
122 }
123
124 return temperature_Celsius;
125 }
126
GetInitialMachineTemperature()127 const double GetInitialMachineTemperature() {
128 return g_initial_temperature;
129 }
130
GetMachineTemperature()131 double GetMachineTemperature() {
132 double max_temperature = get_temperature_input();
133 return max_temperature;
134 }
135
136 // Waits up to timeout seconds to reach cold_temperature in Celsius.
WaitForCoolMachine(double cold_temperature,double timeout,double * temperature)137 double WaitForCoolMachine(double cold_temperature, double timeout,
138 double *temperature) {
139 // Integer times are in micro-seconds.
140 uint64_t time_start = GetUTime();
141 uint64_t time_now = time_start;
142 uint64_t time_end = time_now + 1e6 * timeout;
143 *temperature = GetMachineTemperature();
144 while (time_now < time_end) {
145 if (*temperature < cold_temperature)
146 break;
147 sleep(1.0);
148 time_now = GetUTime();
149 *temperature = GetMachineTemperature();
150 }
151 double wait_time = 1.0e-6 * (time_now - time_start);
152 assert(wait_time >= 0);
153 assert(wait_time < timeout + 5.0);
154 return wait_time;
155 }
156
157 namespace glbench {
158
SetupTexture(GLsizei size_log2)159 GLuint SetupTexture(GLsizei size_log2) {
160 GLsizei size = 1 << size_log2;
161 GLuint name = ~0;
162 glGenTextures(1, &name);
163 glBindTexture(GL_TEXTURE_2D, name);
164 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
165 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
166
167 unsigned char *pixels = new unsigned char[size * size * 4];
168 if (!pixels)
169 return 0;
170
171 for (GLint level = 0; size > 0; level++, size /= 2) {
172 unsigned char *p = pixels;
173 for (int i = 0; i < size; i++) {
174 for (int j = 0; j < size; j++) {
175 *p++ = level %3 != 0 ? (i ^ j) << level : 0;
176 *p++ = level %3 != 1 ? (i ^ j) << level : 0;
177 *p++ = level %3 != 2 ? (i ^ j) << level : 0;
178 *p++ = 255;
179 }
180 }
181 if (size == 1) {
182 unsigned char *p = pixels;
183 *p++ = 255;
184 *p++ = 255;
185 *p++ = 255;
186 *p++ = 255;
187 }
188 glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, size, size, 0,
189 GL_RGBA, GL_UNSIGNED_BYTE, pixels);
190 }
191 delete[] pixels;
192 return name;
193 }
194
SetupVBO(GLenum target,GLsizeiptr size,const GLvoid * data)195 GLuint SetupVBO(GLenum target, GLsizeiptr size, const GLvoid *data) {
196 GLuint buf = ~0;
197 glGenBuffers(1, &buf);
198 glBindBuffer(target, buf);
199 glBufferData(target, size, data, GL_STATIC_DRAW);
200 CHECK(!glGetError());
201 return buf;
202 }
203
204 // Generates a lattice symmetric around the origin (all quadrants).
CreateLattice(GLfloat ** vertices,GLsizeiptr * size,GLfloat size_x,GLfloat size_y,int width,int height)205 void CreateLattice(GLfloat **vertices, GLsizeiptr *size,
206 GLfloat size_x, GLfloat size_y, int width, int height)
207 {
208 GLfloat *vptr = *vertices = new GLfloat[2 * (width + 1) * (height + 1)];
209 GLfloat shift_x = size_x * width;
210 GLfloat shift_y = size_y * height;
211 for (int j = 0; j <= height; j++) {
212 for (int i = 0; i <= width; i++) {
213 *vptr++ = 2 * i * size_x - shift_x;
214 *vptr++ = 2 * j * size_y - shift_y;
215 }
216 }
217 *size = (vptr - *vertices) * sizeof(GLfloat);
218 }
219
220 // Generates a mesh of 2*width*height triangles. The ratio of front facing to
221 // back facing triangles is culled_ratio/RAND_MAX. Returns the number of
222 // vertices in the mesh.
CreateMesh(GLushort ** indices,GLsizeiptr * size,int width,int height,int culled_ratio)223 int CreateMesh(GLushort **indices, GLsizeiptr *size,
224 int width, int height, int culled_ratio) {
225 srand(0);
226
227 // We use 16 bit indices for compatibility with GL ES
228 CHECK(height * width + width + height <= 65535);
229
230 GLushort *iptr = *indices = new GLushort[2 * 3 * (width * height)];
231 const int swath_height = 4;
232
233 CHECK(width % swath_height == 0 && height % swath_height == 0);
234
235 for (int j = 0; j < height; j += swath_height) {
236 for (int i = 0; i < width; i++) {
237 for (int j2 = 0; j2 < swath_height; j2++) {
238 GLushort first = (j + j2) * (width + 1) + i;
239 GLushort second = first + 1;
240 GLushort third = first + (width + 1);
241 GLushort fourth = third + 1;
242
243 bool flag = rand() < culled_ratio;
244 *iptr++ = first;
245 *iptr++ = flag ? second : third;
246 *iptr++ = flag ? third : second;
247
248 *iptr++ = fourth;
249 *iptr++ = flag ? third : second;
250 *iptr++ = flag ? second : third;
251 }
252 }
253 }
254 *size = (iptr - *indices) * sizeof(GLushort);
255
256 return iptr - *indices;
257 }
258
print_info_log(int obj,bool shader)259 static void print_info_log(int obj, bool shader)
260 {
261 char info_log[4096];
262 int length;
263
264 if (shader)
265 glGetShaderInfoLog(obj, sizeof(info_log)-1, &length, info_log);
266 else
267 glGetProgramInfoLog(obj, sizeof(info_log)-1, &length, info_log);
268
269 char *p = info_log;
270 while (p < info_log + length) {
271 char *newline = strchr(p, '\n');
272 if (newline)
273 *newline = '\0';
274 printf("# Info: glGet%sInfoLog: %s\n", shader ? "Shader" : "Program", p);
275 if (!newline)
276 break;
277 p = newline + 1;
278 }
279 }
280
print_shader_log(int shader)281 static void print_shader_log(int shader)
282 {
283 print_info_log(shader, true);
284 }
285
print_program_log(int program)286 static void print_program_log(int program)
287 {
288 print_info_log(program, false);
289 }
290
291
InitShaderProgram(const char * vertex_src,const char * fragment_src)292 GLuint InitShaderProgram(const char *vertex_src, const char *fragment_src) {
293 return InitShaderProgramWithHeader(NULL, vertex_src, fragment_src);
294 }
295
InitShaderProgramWithHeader(const char * header,const char * vertex_src,const char * fragment_src)296 GLuint InitShaderProgramWithHeader(const char* header,
297 const char* vertex_src,
298 const char* fragment_src) {
299 const char* headers[] = {kGlesHeader, header};
300 return InitShaderProgramWithHeaders(headers,
301 arraysize(headers) - (header ? 0 : 1),
302 vertex_src, fragment_src);
303 }
304
InitShaderProgramWithHeaders(const char ** headers,int count,const char * vertex_src,const char * fragment_src)305 GLuint InitShaderProgramWithHeaders(const char** headers,
306 int count,
307 const char* vertex_src,
308 const char* fragment_src) {
309 GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
310 GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
311
312 const char** header_and_body = new const char*[count + 1];
313 if (count != 0)
314 memcpy(header_and_body, headers, count * sizeof(const char*));
315 header_and_body[count] = vertex_src;
316 glShaderSource(vertex_shader, count + 1, header_and_body, NULL);
317 header_and_body[count] = fragment_src;
318 glShaderSource(fragment_shader, count + 1, header_and_body, NULL);
319 delete[] header_and_body;
320
321 glCompileShader(vertex_shader);
322 print_shader_log(vertex_shader);
323 glCompileShader(fragment_shader);
324 print_shader_log(fragment_shader);
325
326 GLuint program = glCreateProgram();
327 glAttachShader(program, vertex_shader);
328 glAttachShader(program, fragment_shader);
329 glLinkProgram(program);
330 print_program_log(program);
331 glUseProgram(program);
332
333 glDeleteShader(vertex_shader);
334 glDeleteShader(fragment_shader);
335
336 return program;
337 }
338
ClearBuffers()339 void ClearBuffers() {
340 glClearColor(1.f, 0, 0, 1.f);
341 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
342 g_main_gl_interface->SwapBuffers();
343 glClearColor(0, 1.f, 0, 1.f);
344 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
345 g_main_gl_interface->SwapBuffers();
346 glClearColor(0, 0, 0.f, 1.f);
347 }
348
349 } // namespace glbench
350