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