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#include <stdio.h>
6
7#include "main.h"
8#include "testbase.h"
9#include "utils.h"
10
11
12namespace glbench {
13
14const float kScreenScaleFactor = 1e6f * (WINDOW_WIDTH * WINDOW_HEIGHT) /
15    (1280.f * 768);
16
17class WindowManagerCompositingTest : public TestBase {
18 public:
19  WindowManagerCompositingTest(bool scissor)
20      : scissor_(scissor),
21      compositing_background_program_(0),
22      compositing_foreground_program_(0) {}
23  virtual ~WindowManagerCompositingTest() {}
24  virtual bool TestFunc(uint64_t iterations);
25  virtual bool Run();
26  virtual const char* Name() const { return "compositing"; }
27  virtual bool IsDrawTest() const { return true; }
28  virtual const char* Unit() const { return "1280x768_fps"; }
29
30  void InitializeCompositing();
31  void TeardownCompositing();
32  void InitBaseTexture();
33  void UpdateTexture();
34  void LoadTexture();
35
36 private:
37  bool scissor_;
38  uint32_t texture_base_[WINDOW_HEIGHT*WINDOW_WIDTH];
39  uint32_t texture_update_[WINDOW_HEIGHT*WINDOW_WIDTH];
40  GLuint compositing_textures_[5];
41  GLuint compositing_background_program_;
42  GLuint compositing_foreground_program_;
43  DISALLOW_COPY_AND_ASSIGN(WindowManagerCompositingTest);
44};
45
46TestBase* GetWindowManagerCompositingTest(bool enable_scissor) {
47  return new WindowManagerCompositingTest(enable_scissor);
48}
49
50bool WindowManagerCompositingTest::Run() {
51  const char* testname = "compositing";
52  if (scissor_) {
53    glScissor(0, 0, 1, 1);
54    glEnable(GL_SCISSOR_TEST);
55    testname = "compositing_no_fill";
56  }
57  InitializeCompositing();
58  RunTest(this, testname, kScreenScaleFactor, WINDOW_WIDTH, WINDOW_HEIGHT, true);
59  TeardownCompositing();
60  return true;
61}
62
63bool WindowManagerCompositingTest::TestFunc(uint64_t iterations) {
64  for (uint64_t i = 0 ; i < iterations; ++i) {
65    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
66
67    // Draw the background
68    glDisable(GL_BLEND);
69    glDisable(GL_DEPTH_TEST);
70    // We have to blend three textures, but we use multi-texture for this
71    // blending, not fb blend, to avoid the external memory traffic
72    glActiveTexture(GL_TEXTURE0);
73    glBindTexture(GL_TEXTURE_2D, compositing_textures_[0]);
74    glActiveTexture(GL_TEXTURE1);
75    glBindTexture(GL_TEXTURE_2D, compositing_textures_[1]);
76    glActiveTexture(GL_TEXTURE2);
77    glBindTexture(GL_TEXTURE_2D, compositing_textures_[2]);
78    // Use the right shader
79    glUseProgram(compositing_background_program_);
80    // Draw the quad
81    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
82
83    // Use the right shader
84    glUseProgram(compositing_foreground_program_);
85
86    // Compositing is blending, so we shall blend.
87    glEnable(GL_BLEND);
88    // Depth test is on for window occlusion
89    glEnable(GL_DEPTH_TEST);
90
91    // Draw window number one
92    // This update acts like a chrome webkit sw rendering update.
93    glActiveTexture(GL_TEXTURE0);
94    glBindTexture(GL_TEXTURE_2D, compositing_textures_[3]);
95    UpdateTexture();
96    // TODO(papakipos): this LoadTexture is likely doing more CPU memory copies
97    // than we would like.
98    LoadTexture();
99    // TODO(papakipos): add color interpolation here, and modulate
100    // texture against it.
101    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
102
103    // Draw window number two
104    // This is a static window, so we don't update it.
105    glActiveTexture(GL_TEXTURE0);
106    glBindTexture(GL_TEXTURE_2D, compositing_textures_[4]);
107    // TODO(papakipos): add color interpolation here, and modulate
108    // texture against it.
109    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
110  }
111  return true;
112}
113
114const char *kBasicTextureVertexShader =
115    "attribute vec4 c1;"
116    "attribute vec4 c2;"
117    "varying vec4 v1;"
118    "void main() {"
119    "    gl_Position = c1;"
120    "    v1 = c2;"
121    "}";
122
123const char *kBasicTextureFragmentShader =
124    "uniform sampler2D texture_sampler;"
125    "varying vec4 v1;"
126    "void main() {"
127    "    gl_FragColor = texture2D(texture_sampler, v1.st);"
128    "}";
129
130GLuint BasicTextureShaderProgram(GLuint vertex_buffer, GLuint texture_buffer) {
131  GLuint program = InitShaderProgram(kBasicTextureVertexShader,
132                                     kBasicTextureFragmentShader);
133
134  // Set up the texture sampler
135  int textureSampler = glGetUniformLocation(program, "texture_sampler");
136  glUniform1i(textureSampler, 0);
137
138  // Set up vertex attribute
139  int attribute_index = glGetAttribLocation(program, "c1");
140  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
141  glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL);
142  glEnableVertexAttribArray(attribute_index);
143
144  // Set up texture attribute
145  attribute_index = glGetAttribLocation(program, "c2");
146  glBindBuffer(GL_ARRAY_BUFFER, texture_buffer);
147  glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL);
148  glEnableVertexAttribArray(attribute_index);
149
150  return program;
151}
152
153const char *kDoubleTextureBlendVertexShader =
154    "attribute vec4 c1;"
155    "attribute vec4 c2;"
156    "attribute vec4 c3;"
157    "varying vec4 v1;"
158    "varying vec4 v2;"
159    "void main() {"
160    "    gl_Position = c1;"
161    "    v1 = c2;"
162    "    v2 = c3;"
163    "}";
164
165const char *kDoubleTextureBlendFragmentShader =
166    "uniform sampler2D texture_sampler_0;"
167    "uniform sampler2D texture_sampler_1;"
168    "varying vec4 v1;"
169    "varying vec4 v2;"
170    "void main() {"
171    "    vec4 one = texture2D(texture_sampler_0, v1.st);"
172    "    vec4 two = texture2D(texture_sampler_1, v2.st);"
173    "    gl_FragColor = mix(one, two, 0.5);"
174    "}";
175
176// This shader blends the three textures
177GLuint DoubleTextureBlendShaderProgram(GLuint vertex_buffer,
178                                       GLuint texture_buffer_0,
179                                       GLuint texture_buffer_1) {
180  GLuint program = InitShaderProgram(kDoubleTextureBlendVertexShader,
181                                     kDoubleTextureBlendFragmentShader);
182  // Set up the texture sampler
183  int textureSampler0 = glGetUniformLocation(program, "texture_sampler_0");
184  glUniform1i(textureSampler0, 0);
185  int textureSampler1 = glGetUniformLocation(program, "texture_sampler_1");
186  glUniform1i(textureSampler1, 1);
187
188  // Set up vertex attribute
189  int attribute_index = glGetAttribLocation(program, "c1");
190  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
191  glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL);
192  glEnableVertexAttribArray(attribute_index);
193
194  // Set up texture attributes
195  attribute_index = glGetAttribLocation(program, "c2");
196  glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_0);
197  glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL);
198  glEnableVertexAttribArray(attribute_index);
199
200  attribute_index = glGetAttribLocation(program, "c3");
201  glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_1);
202  glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL);
203  glEnableVertexAttribArray(attribute_index);
204
205  return program;
206}
207
208const char *triple_texture_blend_vertex_shader =
209"attribute vec4 c1;"
210"attribute vec4 c2;"
211"attribute vec4 c3;"
212"attribute vec4 c4;"
213"varying vec4 v1;"
214"varying vec4 v2;"
215"varying vec4 v3;"
216"void main() {"
217"    gl_Position = c1;"
218"    v1 = c2;"
219"    v2 = c3;"
220"    v3 = c4;"
221"}";
222
223const char *triple_texture_blend_fragment_shader =
224"uniform sampler2D texture_sampler_0;"
225"uniform sampler2D texture_sampler_1;"
226"uniform sampler2D texture_sampler_2;"
227"varying vec4 v1;"
228"varying vec4 v2;"
229"varying vec4 v3;"
230"void main() {"
231"    vec4 one = texture2D(texture_sampler_0, v1.st);"
232"    vec4 two = texture2D(texture_sampler_1, v2.st);"
233"    vec4 three = texture2D(texture_sampler_2, v3.st);"
234"    gl_FragColor = mix(mix(one, two, 0.5), three, 0.5);"
235"}";
236
237// This shader blends the three textures
238GLuint TripleTextureBlendShaderProgram(GLuint vertex_buffer,
239                                              GLuint texture_buffer_0,
240                                              GLuint texture_buffer_1,
241                                              GLuint texture_buffer_2) {
242  GLuint program =
243    InitShaderProgram(triple_texture_blend_vertex_shader,
244                      triple_texture_blend_fragment_shader);
245
246  // Set up the texture sampler
247  int textureSampler0 = glGetUniformLocation(program, "texture_sampler_0");
248  glUniform1i(textureSampler0, 0);
249  int textureSampler1 = glGetUniformLocation(program, "texture_sampler_1");
250  glUniform1i(textureSampler1, 1);
251  int textureSampler2 = glGetUniformLocation(program, "texture_sampler_2");
252  glUniform1i(textureSampler2, 2);
253
254  // Set up vertex attribute
255  int attribute_index = glGetAttribLocation(program, "c1");
256  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
257  glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL);
258  glEnableVertexAttribArray(attribute_index);
259
260  // Set up texture attributes
261  attribute_index = glGetAttribLocation(program, "c2");
262  glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_0);
263  glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL);
264  glEnableVertexAttribArray(attribute_index);
265
266  attribute_index = glGetAttribLocation(program, "c3");
267  glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_1);
268  glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL);
269  glEnableVertexAttribArray(attribute_index);
270
271  attribute_index = glGetAttribLocation(program, "c4");
272  glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_2);
273  glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL);
274  glEnableVertexAttribArray(attribute_index);
275
276  return program;
277}
278
279void WindowManagerCompositingTest::InitializeCompositing() {
280  InitBaseTexture();
281
282  glClearColor(0.f, 0.f, 0.f, 0.f);
283  glDisable(GL_DEPTH_TEST);
284  glDisable(GL_BLEND);
285  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
286  glDepthFunc(GL_LEQUAL);
287
288  glGenTextures(5, compositing_textures_);
289  glActiveTexture(GL_TEXTURE0);
290  for (int i = 0; i < 5; i++) {
291    glBindTexture(GL_TEXTURE_2D, compositing_textures_[i]);
292    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
293                    GL_LINEAR);
294    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
295                    GL_LINEAR);
296  }
297
298  // Set up the vertex arrays for drawing textured quads later on.
299  GLfloat buffer_vertex[8] = {
300    -1.f, -1.f,
301    1.f,  -1.f,
302    -1.f, 1.f,
303    1.f,  1.f,
304  };
305  GLuint vbo_vertex = SetupVBO(GL_ARRAY_BUFFER,
306                               sizeof(buffer_vertex), buffer_vertex);
307
308  GLfloat buffer_texture[8] = {
309    0.f, 0.f,
310    1.f, 0.f,
311    0.f, 1.f,
312    1.f, 1.f,
313  };
314  GLuint vbo_texture = SetupVBO(GL_ARRAY_BUFFER,
315                                sizeof(buffer_texture), buffer_texture);
316
317  // Set up the static background textures.
318  UpdateTexture();
319  UpdateTexture();
320  UpdateTexture();
321  // Load these textures into bound texture ids and keep using them
322  // from there to avoid having to reload this texture every frame
323  glActiveTexture(GL_TEXTURE0);
324  glBindTexture(GL_TEXTURE_2D, compositing_textures_[0]);
325  LoadTexture();
326  glActiveTexture(GL_TEXTURE1);
327  glBindTexture(GL_TEXTURE_2D, compositing_textures_[1]);
328  LoadTexture();
329  glActiveTexture(GL_TEXTURE2);
330  glBindTexture(GL_TEXTURE_2D, compositing_textures_[2]);
331  LoadTexture();
332
333  glActiveTexture(GL_TEXTURE0);
334  glBindTexture(GL_TEXTURE_2D, compositing_textures_[3]);
335  UpdateTexture();
336  LoadTexture();
337
338  glActiveTexture(GL_TEXTURE0);
339  glBindTexture(GL_TEXTURE_2D, compositing_textures_[4]);
340  UpdateTexture();
341  LoadTexture();
342
343  // Set up vertex & fragment shaders.
344  compositing_background_program_ =
345      TripleTextureBlendShaderProgram(vbo_vertex,
346                                      vbo_texture, vbo_texture, vbo_texture);
347  compositing_foreground_program_ =
348      BasicTextureShaderProgram(vbo_vertex, vbo_texture);
349  if (!compositing_background_program_ || !compositing_foreground_program_) {
350    printf("# Warning: Could not set up compositing shader.\n");
351  }
352}
353
354void WindowManagerCompositingTest::TeardownCompositing() {
355  glDeleteProgram(compositing_background_program_);
356  glDeleteProgram(compositing_foreground_program_);
357}
358
359void WindowManagerCompositingTest::InitBaseTexture() {
360  for (int y = 0; y < WINDOW_HEIGHT; y++) {
361    for (int x = 0; x < WINDOW_WIDTH; x++) {
362      // This color is gray, half alpha.
363      texture_base_[y*WINDOW_WIDTH+x] = 0x80808080;
364    }
365  }
366}
367
368// UpdateTexture simulates Chrome updating tab contents.
369// We cause a bunch of read and write cpu memory bandwidth.
370// It's a very rough approximation.
371void WindowManagerCompositingTest::UpdateTexture() {
372  memcpy(texture_update_, texture_base_, sizeof(texture_base_));
373}
374
375void WindowManagerCompositingTest::LoadTexture() {
376  // Use GL_RGBA for compatibility with GLES2.0.
377  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
378               WINDOW_WIDTH, WINDOW_HEIGHT, 0,
379               GL_RGBA, GL_UNSIGNED_BYTE, texture_update_);
380}
381
382} // namespace glbench
383