// Copyright (c) 2010 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include #include #include #include #include #include #include "arraysize.h" #include "filepath.h" #include "glinterface.h" #include "main.h" #include "utils.h" const char* kGlesHeader = "#ifdef GL_ES\n" "precision highp float;\n" "#endif\n"; FilePath* g_base_path = new FilePath(); double g_initial_temperature = -1000.0; std::string autotest_temperature_script = "/usr/local/autotest/bin/temperature.py"; DEFINE_string(TEMPERATURE_SCRIPT_PATH, autotest_temperature_script, "The path to temperature measurement executable."); // Sets the base path for MmapFile to `dirname($argv0)`/$relative. void SetBasePathFromArgv0(const char* argv0, const char* relative) { if (g_base_path) { delete g_base_path; } FilePath argv0_path = FilePath(argv0).DirName(); FilePath base_path = relative ? argv0_path.Append(relative) : argv0_path; g_base_path = new FilePath(base_path); } void* MmapFile(const char* name, size_t* length) { FilePath filename = g_base_path->Append(name); int fd = open(filename.value().c_str(), O_RDONLY); if (fd == -1) return NULL; struct stat sb; CHECK(fstat(fd, &sb) != -1); char* mmap_ptr = static_cast(mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0)); close(fd); if (mmap_ptr) *length = sb.st_size; return mmap_ptr; } bool read_int_from_file(FilePath filename, int* value) { FILE* fd = fopen(filename.value().c_str(), "r"); if (!fd) { return false; } int count = fscanf(fd, "%d", value); if (count != 1) { printf("Error: could not read integer from file. (%s)\n", filename.value().c_str()); if (count != 1) return false; } fclose(fd); return true; } bool read_float_from_cmd_output(const char* command, double* value) { FILE* fd = popen(command, "r"); if (!fd) { printf("Error: could not popen command. (%s)\n", command); return false; } int count = fscanf(fd, "%lf", value); if (count != 1) { printf("Error: could not read float from command output. (%s)\n", command); return false; } pclose(fd); return true; } bool check_file_existence(const char* file_path, struct stat* buffer = NULL) { struct stat local_buf; bool exist = stat(file_path, &local_buf) == 0; if (buffer && exist) memcpy(buffer, &local_buf, sizeof(local_buf)); return exist; } bool check_dir_existence(const char* file_path) { struct stat buffer; bool exist = check_file_existence(file_path, &buffer); if (!exist) return false; return S_ISDIR(buffer.st_mode); } // Returns currently measured temperature. double get_temperature_input() { std::string command = FLAGS_TEMPERATURE_SCRIPT_PATH; if (command == autotest_temperature_script) { command += " --maximum"; } double temperature_Celsius = -1000.0; read_float_from_cmd_output(command.c_str(), &temperature_Celsius); if (temperature_Celsius < 10.0 || temperature_Celsius > 150.0) { printf("Warning: ignoring temperature reading of %f'C.\n", temperature_Celsius); } return temperature_Celsius; } const double GetInitialMachineTemperature() { return g_initial_temperature; } double GetMachineTemperature() { double max_temperature = get_temperature_input(); return max_temperature; } // Waits up to timeout seconds to reach cold_temperature in Celsius. double WaitForCoolMachine(double cold_temperature, double timeout, double* temperature) { // Integer times are in micro-seconds. uint64_t time_start = GetUTime(); uint64_t time_now = time_start; uint64_t time_end = time_now + 1e6 * timeout; *temperature = GetMachineTemperature(); while (time_now < time_end) { if (*temperature < cold_temperature) break; sleep(1.0); time_now = GetUTime(); *temperature = GetMachineTemperature(); } double wait_time = 1.0e-6 * (time_now - time_start); assert(wait_time >= 0); assert(wait_time < timeout + 5.0); return wait_time; } std::vector SplitString(std::string& input, std::string delimiter, bool trim_space) { std::vector result; if (input.empty()) return result; size_t start = 0; while (start != std::string::npos) { size_t end = input.find(delimiter, start); std::string piece; if (end == std::string::npos) { piece = input.substr(start); start = end; } else { piece = input.substr(start, end - start); start = end + 1; } trim(piece); result.push_back(piece); } return result; } namespace glbench { GLuint SetupTexture(GLsizei size_log2) { GLsizei size = 1 << size_log2; GLuint name = ~0; glGenTextures(1, &name); glBindTexture(GL_TEXTURE_2D, name); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); unsigned char* pixels = new unsigned char[size * size * 4]; if (!pixels) return 0; for (GLint level = 0; size > 0; level++, size /= 2) { unsigned char* p = pixels; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { *p++ = level % 3 != 0 ? (i ^ j) << level : 0; *p++ = level % 3 != 1 ? (i ^ j) << level : 0; *p++ = level % 3 != 2 ? (i ^ j) << level : 0; *p++ = 255; } } if (size == 1) { unsigned char* p = pixels; *p++ = 255; *p++ = 255; *p++ = 255; *p++ = 255; } glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); } delete[] pixels; return name; } GLuint SetupVBO(GLenum target, GLsizeiptr size, const GLvoid* data) { GLuint buf = ~0; glGenBuffers(1, &buf); glBindBuffer(target, buf); glBufferData(target, size, data, GL_STATIC_DRAW); CHECK(!glGetError()); return buf; } // Generates a lattice symmetric around the origin (all quadrants). void CreateLattice(GLfloat** vertices, GLsizeiptr* size, GLfloat size_x, GLfloat size_y, int width, int height) { GLfloat* vptr = *vertices = new GLfloat[2 * (width + 1) * (height + 1)]; GLfloat shift_x = size_x * width; GLfloat shift_y = size_y * height; for (int j = 0; j <= height; j++) { for (int i = 0; i <= width; i++) { *vptr++ = 2 * i * size_x - shift_x; *vptr++ = 2 * j * size_y - shift_y; } } *size = (vptr - *vertices) * sizeof(GLfloat); } // Generates a mesh of 2*width*height triangles. The ratio of front facing to // back facing triangles is culled_ratio/RAND_MAX. Returns the number of // vertices in the mesh. int CreateMesh(GLushort** indices, GLsizeiptr* size, int width, int height, int culled_ratio) { srand(0); // We use 16 bit indices for compatibility with GL ES CHECK(height * width + width + height <= 65535); GLushort* iptr = *indices = new GLushort[2 * 3 * (width * height)]; const int swath_height = 4; CHECK(width % swath_height == 0 && height % swath_height == 0); for (int j = 0; j < height; j += swath_height) { for (int i = 0; i < width; i++) { for (int j2 = 0; j2 < swath_height; j2++) { GLushort first = (j + j2) * (width + 1) + i; GLushort second = first + 1; GLushort third = first + (width + 1); GLushort fourth = third + 1; bool flag = rand() < culled_ratio; *iptr++ = first; *iptr++ = flag ? second : third; *iptr++ = flag ? third : second; *iptr++ = fourth; *iptr++ = flag ? third : second; *iptr++ = flag ? second : third; } } } *size = (iptr - *indices) * sizeof(GLushort); return iptr - *indices; } static void print_info_log(int obj, bool shader) { char info_log[4096]; int length; if (shader) glGetShaderInfoLog(obj, sizeof(info_log) - 1, &length, info_log); else glGetProgramInfoLog(obj, sizeof(info_log) - 1, &length, info_log); char* p = info_log; while (p < info_log + length) { char* newline = strchr(p, '\n'); if (newline) *newline = '\0'; printf("# Info: glGet%sInfoLog: %s\n", shader ? "Shader" : "Program", p); if (!newline) break; p = newline + 1; } } static void print_shader_log(int shader) { print_info_log(shader, true); } static void print_program_log(int program) { print_info_log(program, false); } GLuint InitShaderProgram(const char* vertex_src, const char* fragment_src) { return InitShaderProgramWithHeader(NULL, vertex_src, fragment_src); } GLuint InitShaderProgramWithHeader(const char* header, const char* vertex_src, const char* fragment_src) { const char* headers[] = {kGlesHeader, header}; return InitShaderProgramWithHeaders( headers, arraysize(headers) - (header ? 0 : 1), vertex_src, fragment_src); } GLuint InitShaderProgramWithHeaders(const char** headers, int count, const char* vertex_src, const char* fragment_src) { GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); const char** header_and_body = new const char*[count + 1]; if (count != 0) memcpy(header_and_body, headers, count * sizeof(const char*)); header_and_body[count] = vertex_src; glShaderSource(vertex_shader, count + 1, header_and_body, NULL); header_and_body[count] = fragment_src; glShaderSource(fragment_shader, count + 1, header_and_body, NULL); delete[] header_and_body; glCompileShader(vertex_shader); print_shader_log(vertex_shader); glCompileShader(fragment_shader); print_shader_log(fragment_shader); GLuint program = glCreateProgram(); glAttachShader(program, vertex_shader); glAttachShader(program, fragment_shader); glLinkProgram(program); print_program_log(program); glUseProgram(program); glDeleteShader(vertex_shader); glDeleteShader(fragment_shader); return program; } void ClearBuffers() { glClearColor(1.f, 0, 0, 1.f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); g_main_gl_interface->SwapBuffers(); glClearColor(0, 1.f, 0, 1.f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); g_main_gl_interface->SwapBuffers(); glClearColor(0, 0, 0.f, 1.f); } } // namespace glbench