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