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
GenerateAndBindTexture()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
CreateBitmap(int w,int h)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
main(int argc,char * argv[])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