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 
12 namespace glbench {
13 
14 const float kScreenScaleFactor = 1e6f * (WINDOW_WIDTH * WINDOW_HEIGHT) /
15     (1280.f * 768);
16 
17 class WindowManagerCompositingTest : public TestBase {
18  public:
WindowManagerCompositingTest(bool scissor)19   WindowManagerCompositingTest(bool scissor)
20       : scissor_(scissor),
21       compositing_background_program_(0),
22       compositing_foreground_program_(0) {}
~WindowManagerCompositingTest()23   virtual ~WindowManagerCompositingTest() {}
24   virtual bool TestFunc(uint64_t iterations);
25   virtual bool Run();
Name() const26   virtual const char* Name() const { return "compositing"; }
IsDrawTest() const27   virtual bool IsDrawTest() const { return true; }
Unit() const28   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 
GetWindowManagerCompositingTest(bool enable_scissor)46 TestBase* GetWindowManagerCompositingTest(bool enable_scissor) {
47   return new WindowManagerCompositingTest(enable_scissor);
48 }
49 
Run()50 bool 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 
TestFunc(uint64_t iterations)63 bool 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 
114 const 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 
123 const char *kBasicTextureFragmentShader =
124     "uniform sampler2D texture_sampler;"
125     "varying vec4 v1;"
126     "void main() {"
127     "    gl_FragColor = texture2D(texture_sampler, v1.st);"
128     "}";
129 
BasicTextureShaderProgram(GLuint vertex_buffer,GLuint texture_buffer)130 GLuint 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 
153 const 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 
165 const 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
DoubleTextureBlendShaderProgram(GLuint vertex_buffer,GLuint texture_buffer_0,GLuint texture_buffer_1)177 GLuint 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 
208 const 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 
223 const 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
TripleTextureBlendShaderProgram(GLuint vertex_buffer,GLuint texture_buffer_0,GLuint texture_buffer_1,GLuint texture_buffer_2)238 GLuint 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 
InitializeCompositing()279 void 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 
TeardownCompositing()354 void WindowManagerCompositingTest::TeardownCompositing() {
355   glDeleteProgram(compositing_background_program_);
356   glDeleteProgram(compositing_foreground_program_);
357 }
358 
InitBaseTexture()359 void 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.
UpdateTexture()371 void WindowManagerCompositingTest::UpdateTexture() {
372   memcpy(texture_update_, texture_base_, sizeof(texture_base_));
373 }
374 
LoadTexture()375 void 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