Home | History | Annotate | Download | only in src
      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