| // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stdio.h> |
| |
| #include "glbench/main.h" |
| #include "glbench/testbase.h" |
| #include "glbench/utils.h" |
| |
| |
| namespace glbench { |
| |
| const float kScreenScaleFactor = 1e6f * (WINDOW_WIDTH * WINDOW_HEIGHT) / |
| (1280.f * 768); |
| |
| class WindowManagerCompositingTest : public TestBase { |
| public: |
| explicit WindowManagerCompositingTest(bool scissor) |
| : scissor_(scissor), |
| compositing_background_program_(0), |
| compositing_foreground_program_(0) {} |
| virtual ~WindowManagerCompositingTest() {} |
| virtual bool TestFunc(uint64_t iterations); |
| virtual bool Run(); |
| virtual const char* Name() const { return "compositing"; } |
| virtual bool IsDrawTest() const { return true; } |
| virtual const char* Unit() const { return "1280x768_fps"; } |
| |
| void InitializeCompositing(); |
| void TeardownCompositing(); |
| void InitBaseTexture(); |
| void UpdateTexture(); |
| void LoadTexture(); |
| |
| private: |
| bool scissor_; |
| uint32_t texture_base_[WINDOW_HEIGHT*WINDOW_WIDTH]; |
| uint32_t texture_update_[WINDOW_HEIGHT*WINDOW_WIDTH]; |
| GLuint compositing_textures_[5]; |
| GLuint compositing_background_program_; |
| GLuint compositing_foreground_program_; |
| DISALLOW_COPY_AND_ASSIGN(WindowManagerCompositingTest); |
| }; |
| |
| TestBase* GetWindowManagerCompositingTest(bool enable_scissor) { |
| return new WindowManagerCompositingTest(enable_scissor); |
| } |
| |
| bool WindowManagerCompositingTest::Run() { |
| const char* testname = "compositing"; |
| if (scissor_) { |
| glScissor(0, 0, 1, 1); |
| glEnable(GL_SCISSOR_TEST); |
| testname = "compositing_no_fill"; |
| } |
| InitializeCompositing(); |
| RunTest(this, testname, kScreenScaleFactor, WINDOW_WIDTH, WINDOW_HEIGHT, |
| true); |
| TeardownCompositing(); |
| return true; |
| } |
| |
| bool WindowManagerCompositingTest::TestFunc(uint64_t iterations) { |
| for (uint64_t i = 0 ; i < iterations; ++i) { |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| // Draw the background |
| glDisable(GL_BLEND); |
| glDisable(GL_DEPTH_TEST); |
| // We have to blend three textures, but we use multi-texture for this |
| // blending, not fb blend, to avoid the external memory traffic |
| glActiveTexture(GL_TEXTURE0); |
| glBindTexture(GL_TEXTURE_2D, compositing_textures_[0]); |
| glActiveTexture(GL_TEXTURE1); |
| glBindTexture(GL_TEXTURE_2D, compositing_textures_[1]); |
| glActiveTexture(GL_TEXTURE2); |
| glBindTexture(GL_TEXTURE_2D, compositing_textures_[2]); |
| // Use the right shader |
| glUseProgram(compositing_background_program_); |
| // Draw the quad |
| glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| |
| // Use the right shader |
| glUseProgram(compositing_foreground_program_); |
| |
| // Compositing is blending, so we shall blend. |
| glEnable(GL_BLEND); |
| // Depth test is on for window occlusion |
| glEnable(GL_DEPTH_TEST); |
| |
| // Draw window number one |
| // This update acts like a chrome webkit sw rendering update. |
| glActiveTexture(GL_TEXTURE0); |
| glBindTexture(GL_TEXTURE_2D, compositing_textures_[3]); |
| UpdateTexture(); |
| // TODO(papakipos): this LoadTexture is likely doing more CPU memory copies |
| // than we would like. |
| LoadTexture(); |
| // TODO(papakipos): add color interpolation here, and modulate |
| // texture against it. |
| glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| |
| // Draw window number two |
| // This is a static window, so we don't update it. |
| glActiveTexture(GL_TEXTURE0); |
| glBindTexture(GL_TEXTURE_2D, compositing_textures_[4]); |
| // TODO(papakipos): add color interpolation here, and modulate |
| // texture against it. |
| glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| } |
| return true; |
| } |
| |
| const char *kBasicTextureVertexShader = |
| "attribute vec4 c1;" |
| "attribute vec4 c2;" |
| "varying vec4 v1;" |
| "void main() {" |
| " gl_Position = c1;" |
| " v1 = c2;" |
| "}"; |
| |
| const char *kBasicTextureFragmentShader = |
| "uniform sampler2D texture_sampler;" |
| "varying vec4 v1;" |
| "void main() {" |
| " gl_FragColor = texture2D(texture_sampler, v1.st);" |
| "}"; |
| |
| GLuint BasicTextureShaderProgram(GLuint vertex_buffer, GLuint texture_buffer) { |
| GLuint program = InitShaderProgram(kBasicTextureVertexShader, |
| kBasicTextureFragmentShader); |
| |
| // Set up the texture sampler |
| int textureSampler = glGetUniformLocation(program, "texture_sampler"); |
| glUniform1i(textureSampler, 0); |
| |
| // Set up vertex attribute |
| int attribute_index = glGetAttribLocation(program, "c1"); |
| glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); |
| glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
| glEnableVertexAttribArray(attribute_index); |
| |
| // Set up texture attribute |
| attribute_index = glGetAttribLocation(program, "c2"); |
| glBindBuffer(GL_ARRAY_BUFFER, texture_buffer); |
| glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
| glEnableVertexAttribArray(attribute_index); |
| |
| return program; |
| } |
| |
| const char *kDoubleTextureBlendVertexShader = |
| "attribute vec4 c1;" |
| "attribute vec4 c2;" |
| "attribute vec4 c3;" |
| "varying vec4 v1;" |
| "varying vec4 v2;" |
| "void main() {" |
| " gl_Position = c1;" |
| " v1 = c2;" |
| " v2 = c3;" |
| "}"; |
| |
| const char *kDoubleTextureBlendFragmentShader = |
| "uniform sampler2D texture_sampler_0;" |
| "uniform sampler2D texture_sampler_1;" |
| "varying vec4 v1;" |
| "varying vec4 v2;" |
| "void main() {" |
| " vec4 one = texture2D(texture_sampler_0, v1.st);" |
| " vec4 two = texture2D(texture_sampler_1, v2.st);" |
| " gl_FragColor = mix(one, two, 0.5);" |
| "}"; |
| |
| // This shader blends the three textures |
| GLuint DoubleTextureBlendShaderProgram(GLuint vertex_buffer, |
| GLuint texture_buffer_0, |
| GLuint texture_buffer_1) { |
| GLuint program = InitShaderProgram(kDoubleTextureBlendVertexShader, |
| kDoubleTextureBlendFragmentShader); |
| // Set up the texture sampler |
| int textureSampler0 = glGetUniformLocation(program, "texture_sampler_0"); |
| glUniform1i(textureSampler0, 0); |
| int textureSampler1 = glGetUniformLocation(program, "texture_sampler_1"); |
| glUniform1i(textureSampler1, 1); |
| |
| // Set up vertex attribute |
| int attribute_index = glGetAttribLocation(program, "c1"); |
| glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); |
| glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
| glEnableVertexAttribArray(attribute_index); |
| |
| // Set up texture attributes |
| attribute_index = glGetAttribLocation(program, "c2"); |
| glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_0); |
| glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
| glEnableVertexAttribArray(attribute_index); |
| |
| attribute_index = glGetAttribLocation(program, "c3"); |
| glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_1); |
| glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
| glEnableVertexAttribArray(attribute_index); |
| |
| return program; |
| } |
| |
| const char *triple_texture_blend_vertex_shader = |
| "attribute vec4 c1;" |
| "attribute vec4 c2;" |
| "attribute vec4 c3;" |
| "attribute vec4 c4;" |
| "varying vec4 v1;" |
| "varying vec4 v2;" |
| "varying vec4 v3;" |
| "void main() {" |
| " gl_Position = c1;" |
| " v1 = c2;" |
| " v2 = c3;" |
| " v3 = c4;" |
| "}"; |
| |
| const char *triple_texture_blend_fragment_shader = |
| "uniform sampler2D texture_sampler_0;" |
| "uniform sampler2D texture_sampler_1;" |
| "uniform sampler2D texture_sampler_2;" |
| "varying vec4 v1;" |
| "varying vec4 v2;" |
| "varying vec4 v3;" |
| "void main() {" |
| " vec4 one = texture2D(texture_sampler_0, v1.st);" |
| " vec4 two = texture2D(texture_sampler_1, v2.st);" |
| " vec4 three = texture2D(texture_sampler_2, v3.st);" |
| " gl_FragColor = mix(mix(one, two, 0.5), three, 0.5);" |
| "}"; |
| |
| // This shader blends the three textures |
| GLuint TripleTextureBlendShaderProgram(GLuint vertex_buffer, |
| GLuint texture_buffer_0, |
| GLuint texture_buffer_1, |
| GLuint texture_buffer_2) { |
| GLuint program = |
| InitShaderProgram(triple_texture_blend_vertex_shader, |
| triple_texture_blend_fragment_shader); |
| |
| // Set up the texture sampler |
| int textureSampler0 = glGetUniformLocation(program, "texture_sampler_0"); |
| glUniform1i(textureSampler0, 0); |
| int textureSampler1 = glGetUniformLocation(program, "texture_sampler_1"); |
| glUniform1i(textureSampler1, 1); |
| int textureSampler2 = glGetUniformLocation(program, "texture_sampler_2"); |
| glUniform1i(textureSampler2, 2); |
| |
| // Set up vertex attribute |
| int attribute_index = glGetAttribLocation(program, "c1"); |
| glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); |
| glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
| glEnableVertexAttribArray(attribute_index); |
| |
| // Set up texture attributes |
| attribute_index = glGetAttribLocation(program, "c2"); |
| glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_0); |
| glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
| glEnableVertexAttribArray(attribute_index); |
| |
| attribute_index = glGetAttribLocation(program, "c3"); |
| glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_1); |
| glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
| glEnableVertexAttribArray(attribute_index); |
| |
| attribute_index = glGetAttribLocation(program, "c4"); |
| glBindBuffer(GL_ARRAY_BUFFER, texture_buffer_2); |
| glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
| glEnableVertexAttribArray(attribute_index); |
| |
| return program; |
| } |
| |
| void WindowManagerCompositingTest::InitializeCompositing() { |
| InitBaseTexture(); |
| |
| glClearColor(0.f, 0.f, 0.f, 0.f); |
| glDisable(GL_DEPTH_TEST); |
| glDisable(GL_BLEND); |
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| glDepthFunc(GL_LEQUAL); |
| |
| glGenTextures(5, compositing_textures_); |
| glActiveTexture(GL_TEXTURE0); |
| for (int i = 0; i < 5; i++) { |
| glBindTexture(GL_TEXTURE_2D, compositing_textures_[i]); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, |
| GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, |
| GL_LINEAR); |
| } |
| |
| // Set up the vertex arrays for drawing textured quads later on. |
| GLfloat buffer_vertex[8] = { |
| -1.f, -1.f, |
| 1.f, -1.f, |
| -1.f, 1.f, |
| 1.f, 1.f, |
| }; |
| GLuint vbo_vertex = SetupVBO(GL_ARRAY_BUFFER, |
| sizeof(buffer_vertex), buffer_vertex); |
| |
| GLfloat buffer_texture[8] = { |
| 0.f, 0.f, |
| 1.f, 0.f, |
| 0.f, 1.f, |
| 1.f, 1.f, |
| }; |
| GLuint vbo_texture = SetupVBO(GL_ARRAY_BUFFER, |
| sizeof(buffer_texture), buffer_texture); |
| |
| // Set up the static background textures. |
| UpdateTexture(); |
| UpdateTexture(); |
| UpdateTexture(); |
| // Load these textures into bound texture ids and keep using them |
| // from there to avoid having to reload this texture every frame |
| glActiveTexture(GL_TEXTURE0); |
| glBindTexture(GL_TEXTURE_2D, compositing_textures_[0]); |
| LoadTexture(); |
| glActiveTexture(GL_TEXTURE1); |
| glBindTexture(GL_TEXTURE_2D, compositing_textures_[1]); |
| LoadTexture(); |
| glActiveTexture(GL_TEXTURE2); |
| glBindTexture(GL_TEXTURE_2D, compositing_textures_[2]); |
| LoadTexture(); |
| |
| glActiveTexture(GL_TEXTURE0); |
| glBindTexture(GL_TEXTURE_2D, compositing_textures_[3]); |
| UpdateTexture(); |
| LoadTexture(); |
| |
| glActiveTexture(GL_TEXTURE0); |
| glBindTexture(GL_TEXTURE_2D, compositing_textures_[4]); |
| UpdateTexture(); |
| LoadTexture(); |
| |
| // Set up vertex & fragment shaders. |
| compositing_background_program_ = |
| TripleTextureBlendShaderProgram(vbo_vertex, |
| vbo_texture, vbo_texture, vbo_texture); |
| compositing_foreground_program_ = |
| BasicTextureShaderProgram(vbo_vertex, vbo_texture); |
| if (!compositing_background_program_ || !compositing_foreground_program_) { |
| printf("# Warning: Could not set up compositing shader.\n"); |
| } |
| } |
| |
| void WindowManagerCompositingTest::TeardownCompositing() { |
| glDeleteProgram(compositing_background_program_); |
| glDeleteProgram(compositing_foreground_program_); |
| } |
| |
| void WindowManagerCompositingTest::InitBaseTexture() { |
| for (int y = 0; y < WINDOW_HEIGHT; y++) { |
| for (int x = 0; x < WINDOW_WIDTH; x++) { |
| // This color is gray, half alpha. |
| texture_base_[y*WINDOW_WIDTH+x] = 0x80808080; |
| } |
| } |
| } |
| |
| // UpdateTexture simulates Chrome updating tab contents. |
| // We cause a bunch of read and write cpu memory bandwidth. |
| // It's a very rough approximation. |
| void WindowManagerCompositingTest::UpdateTexture() { |
| memcpy(texture_update_, texture_base_, sizeof(texture_base_)); |
| } |
| |
| void WindowManagerCompositingTest::LoadTexture() { |
| // Use GL_RGBA for compatibility with GLES2.0. |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, |
| WINDOW_WIDTH, WINDOW_HEIGHT, 0, |
| GL_RGBA, GL_UNSIGNED_BYTE, texture_update_); |
| } |
| |
| } // namespace glbench |