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. 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 39 const FilePath& GetBasePath() { 40 return *g_base_path; 41 } 42 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 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 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. 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. 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 127 const double GetInitialMachineTemperature() { 128 return g_initial_temperature; 129 } 130 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. 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 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 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). 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. 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 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 281 static void print_shader_log(int shader) 282 { 283 print_info_log(shader, true); 284 } 285 286 static void print_program_log(int program) 287 { 288 print_info_log(program, false); 289 } 290 291 292 GLuint InitShaderProgram(const char *vertex_src, const char *fragment_src) { 293 return InitShaderProgramWithHeader(NULL, vertex_src, fragment_src); 294 } 295 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 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 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