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