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 // Application that displays graphics using OpenGL [ES] with the intent 6 // of being used in functional tests. 7 8 #include <gflags/gflags.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <time.h> 13 14 #include <cmath> 15 16 #include "glinterface.h" 17 #include "main.h" 18 #include "utils.h" 19 20 GLuint GenerateAndBindTexture() { 21 GLuint name = ~0; 22 glGenTextures(1, &name); 23 glBindTexture(GL_TEXTURE_2D, name); 24 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 25 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 26 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 27 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 28 return name; 29 } 30 31 unsigned char* CreateBitmap(int w, int h) { 32 unsigned char* bitmap = new unsigned char[4 * w * h]; 33 unsigned char* pixel = bitmap; 34 float w2 = 0.5f * w; 35 float h2 = 0.5f * h; 36 for (int y = 0; y < h; y++) { 37 for (int x = 0; x < w; x++) { 38 // Fill with soft ellipse 39 float dx = fabs((x - w2) / w2); 40 float dy = fabs((y - h2) / h2); 41 float dist2 = dx * dx + dy * dy; 42 if (dist2 > 1.f) 43 dist2 = 1.f; 44 *pixel = (1.f - dist2) * 255.f; 45 pixel++; 46 *pixel = (1.f - dist2) * 255.f; 47 pixel++; 48 *pixel = (1.f - dist2) * 255.f; 49 pixel++; 50 *pixel = 0; 51 pixel++; 52 } 53 } 54 return bitmap; 55 } 56 57 const char kVertexShader[] = 58 "attribute vec4 vertices;" 59 "varying vec2 v1;" 60 "void main() {" 61 " gl_Position = vec4(vertices.x, vertices.y, 0.0, 1.0);" 62 " v1 = vec2(0.5 * vertices.x + 0.5, 0.5 * vertices.y + 0.5);" 63 "}"; 64 65 const char kFragmentShader[] = 66 "uniform sampler2D tex;" 67 "uniform vec4 color;" 68 "varying vec2 v1;" 69 "void main() {" 70 " gl_FragColor = color * texture2D(tex, v1);" 71 "}"; 72 73 // Command line flags 74 DEFINE_double(screenshot1_sec, 2.f, "seconds delay before screenshot1_cmd"); 75 DEFINE_double(screenshot2_sec, 1.f, "seconds delay before screenshot2_cmd"); 76 DEFINE_string(screenshot1_cmd, "", "system command to take a screen shot 1"); 77 DEFINE_string(screenshot2_cmd, "", "system command to take a screen shot 2"); 78 DEFINE_double(cooldown_sec, 1.f, "seconds delay after all screenshots"); 79 80 int main(int argc, char* argv[]) { 81 // Configure full screen 82 g_width = -1; 83 g_height = -1; 84 85 gflags::ParseCommandLineFlags(&argc, &argv, true); 86 87 g_main_gl_interface.reset(GLInterface::Create()); 88 if (!g_main_gl_interface->Init()) { 89 printf("# Error: Failed to initialize %s.\n", argv[0]); 90 return 1; 91 } 92 93 GLint viewport[2]; 94 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, viewport); 95 printf("# MAX_VIEWPORT_DIMS=(%d, %d)\n", viewport[0], viewport[1]); 96 if (viewport[0] < g_width || viewport[1] < g_height) { 97 printf("# Error: MAX_VIEWPORT_DIMS too small\n"); 98 return 1; 99 } 100 glViewport(0, 0, g_width, g_height); 101 102 unsigned char* bitmap = CreateBitmap(g_height, g_width); 103 GLuint texture = GenerateAndBindTexture(); 104 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, g_height, g_width, 0, GL_RGBA, 105 GL_UNSIGNED_BYTE, bitmap); 106 107 GLfloat vertices[8] = { 108 -1.f, -1.f, 109 1.f, -1.f, 110 -1.f, 1.f, 111 1.f, 1.f, 112 }; 113 114 GLuint program = glbench::InitShaderProgram(kVertexShader, kFragmentShader); 115 int attribute_index = glGetAttribLocation(program, "vertices"); 116 glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, vertices); 117 glEnableVertexAttribArray(attribute_index); 118 119 int texture_sampler = glGetUniformLocation(program, "tex"); 120 glUniform1i(texture_sampler, 0); 121 122 int display_color = glGetUniformLocation(program, "color"); 123 float white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; 124 float blue[4] = {0.5f, 0.5f, 1.0f, 1.0f}; 125 126 uint64_t last_event_time = GetUTime(); 127 enum State { 128 kStateScreenShot1, 129 kStateScreenShot2, 130 kStateCooldown, 131 kStateExit 132 } state = kStateScreenShot1; 133 float seconds_delay_for_next_state[] = { 134 static_cast<float>(FLAGS_screenshot1_sec), 135 static_cast<float>(FLAGS_screenshot2_sec), 136 static_cast<float>(FLAGS_cooldown_sec), 0}; 137 138 do { 139 // Draw 140 glClear(GL_COLOR_BUFFER_BIT); 141 if (state == kStateScreenShot1) 142 glUniform4fv(display_color, 1, white); 143 else 144 glUniform4fv(display_color, 1, blue); 145 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 146 g_main_gl_interface->SwapBuffers(); 147 // Loop until next event 148 float seconds_since_last_event = 149 static_cast<float>(GetUTime() - last_event_time) / 1000000ULL; 150 if (seconds_since_last_event < seconds_delay_for_next_state[state]) 151 continue; 152 153 // State change. Perform action. 154 switch (state) { 155 case kStateScreenShot1: 156 system(FLAGS_screenshot1_cmd.c_str()); 157 break; 158 case kStateScreenShot2: 159 system(FLAGS_screenshot2_cmd.c_str()); 160 break; 161 default: 162 break; 163 } 164 165 // Advance to next state 166 last_event_time = GetUTime(); 167 state = static_cast<State>(state + 1); 168 169 } while (state != kStateExit); 170 171 glDeleteTextures(1, &texture); 172 g_main_gl_interface->Cleanup(); 173 return 0; 174 } 175