From patchwork Tue Sep 13 10:17:13 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: alexandros.frantzis@linaro.org X-Patchwork-Id: 4041 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id B2A0C23EFD for ; Tue, 13 Sep 2011 10:17:15 +0000 (UTC) Received: from mail-fx0-f52.google.com (mail-fx0-f52.google.com [209.85.161.52]) by fiordland.canonical.com (Postfix) with ESMTP id 97EC3A18442 for ; Tue, 13 Sep 2011 10:17:15 +0000 (UTC) Received: by mail-fx0-f52.google.com with SMTP id 23so520649fxe.11 for ; Tue, 13 Sep 2011 03:17:15 -0700 (PDT) Received: by 10.223.74.89 with SMTP id t25mr250355faj.65.1315909035488; Tue, 13 Sep 2011 03:17:15 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.152.11.8 with SMTP id m8cs2062lab; Tue, 13 Sep 2011 03:17:15 -0700 (PDT) Received: by 10.213.15.73 with SMTP id j9mr170153eba.128.1315909034231; Tue, 13 Sep 2011 03:17:14 -0700 (PDT) Received: from indium.canonical.com (indium.canonical.com [91.189.90.7]) by mx.google.com with ESMTPS id e19si326603eeb.2.2011.09.13.03.17.13 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 13 Sep 2011 03:17:14 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) client-ip=91.189.90.7; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) smtp.mail=bounces@canonical.com Received: from ackee.canonical.com ([91.189.89.26]) by indium.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1R3Q3F-0006K0-MI for ; Tue, 13 Sep 2011 10:17:13 +0000 Received: from ackee.canonical.com (localhost [127.0.0.1]) by ackee.canonical.com (Postfix) with ESMTP id 9B1DCE0304 for ; Tue, 13 Sep 2011 10:17:13 +0000 (UTC) MIME-Version: 1.0 X-Launchpad-Project: glmark2 X-Launchpad-Branch: ~glmark2-dev/glmark2/trunk X-Launchpad-Message-Rationale: Subscriber X-Launchpad-Branch-Revision-Number: 130 X-Launchpad-Notification-Type: branch-revision To: Linaro Patch Tracker From: noreply@launchpad.net Subject: [Branch ~glmark2-dev/glmark2/trunk] Rev 130: Merge desktop scene and blur effect. Message-Id: <20110913101713.7098.6728.launchpad@ackee.canonical.com> Date: Tue, 13 Sep 2011 10:17:13 -0000 Reply-To: noreply@launchpad.net Sender: bounces@canonical.com Errors-To: bounces@canonical.com Precedence: bulk X-Generated-By: Launchpad (canonical.com); Revision="13921"; Instance="initZopeless config overlay" X-Launchpad-Hash: 21e3189236717f7daef28d28ff521de4a506a3df Merge authors: Alexandros Frantzis (afrantzis) Related merge proposals: https://code.launchpad.net/~linaro-graphics-wg/glmark2/desktop/+merge/75039 proposed by: Alexandros Frantzis (afrantzis) ------------------------------------------------------------ revno: 130 [merge] committer: Alexandros Frantzis branch nick: trunk timestamp: Tue 2011-09-13 13:15:12 +0300 message: Merge desktop scene and blur effect. added: data/shaders/desktop-blur.frag data/shaders/desktop.frag data/shaders/desktop.vert data/textures/desktop-window.png src/scene-desktop.cpp modified: src/android.cpp src/canvas-android.cpp src/canvas-x11.cpp src/main.cpp src/scene.h --- lp:glmark2 https://code.launchpad.net/~glmark2-dev/glmark2/trunk You are subscribed to branch lp:glmark2. To unsubscribe from this branch go to https://code.launchpad.net/~glmark2-dev/glmark2/trunk/+edit-subscription === added file 'data/shaders/desktop-blur.frag' --- data/shaders/desktop-blur.frag 1970-01-01 00:00:00 +0000 +++ data/shaders/desktop-blur.frag 2011-09-12 15:39:23 +0000 @@ -0,0 +1,17 @@ +#ifdef GL_ES +precision mediump float; +#endif + +uniform sampler2D Texture0; + +varying vec2 TextureCoord; + +void main(void) +{ + vec4 result; + + $CONVOLUTION$ + + gl_FragColor = result; +} + === added file 'data/shaders/desktop.frag' --- data/shaders/desktop.frag 1970-01-01 00:00:00 +0000 +++ data/shaders/desktop.frag 2011-09-09 13:57:53 +0000 @@ -0,0 +1,14 @@ +#ifdef GL_ES +precision mediump float; +#endif + +uniform sampler2D MaterialTexture0; + +varying vec2 TextureCoord; + +void main(void) +{ + vec4 texel = texture2D(MaterialTexture0, TextureCoord); + gl_FragColor = texel; +} + === added file 'data/shaders/desktop.vert' --- data/shaders/desktop.vert 1970-01-01 00:00:00 +0000 +++ data/shaders/desktop.vert 2011-09-09 13:57:53 +0000 @@ -0,0 +1,11 @@ +attribute vec2 position; +attribute vec2 texcoord; + +varying vec2 TextureCoord; + +void main(void) +{ + gl_Position = vec4(position, 0.0, 1.0); + + TextureCoord = texcoord; +} === added file 'data/textures/desktop-window.png' Binary files data/textures/desktop-window.png 1970-01-01 00:00:00 +0000 and data/textures/desktop-window.png 2011-09-09 13:57:53 +0000 differ === modified file 'src/android.cpp' --- src/android.cpp 2011-08-18 15:03:40 +0000 +++ src/android.cpp 2011-09-12 16:08:24 +0000 @@ -44,6 +44,7 @@ "effect2d:kernel=0,1,0;1,-4,1;0,1,0;", "effect2d:kernel=1,1,1,1,1;1,1,1,1,1;1,1,1,1,1;", "pulsar:quads=5:texture=false:light=false", + "desktop:windows=4:effect=blur:blur-radius=5:passes=1:separable=true", "conditionals:vertex-steps=0:fragment-steps=0", "conditionals:vertex-steps=0:fragment-steps=5", "conditionals:vertex-steps=5:fragment-steps=0", @@ -85,6 +86,7 @@ Benchmark::register_scene(*new SceneBump(*g_canvas)); Benchmark::register_scene(*new SceneEffect2D(*g_canvas)); Benchmark::register_scene(*new ScenePulsar(*g_canvas)); + Benchmark::register_scene(*new SceneDesktop(canvas)); add_default_benchmarks(g_benchmarks); === modified file 'src/canvas-android.cpp' --- src/canvas-android.cpp 2011-08-10 18:00:03 +0000 +++ src/canvas-android.cpp 2011-09-09 11:24:17 +0000 @@ -35,8 +35,6 @@ if (!eglSwapInterval(eglGetCurrentDisplay(), 0)) Log::info("** Failed to set swap interval. Results may be bounded above by refresh rate.\n"); - glClearColor(0.0f, 0.0f, 0.0f, 0.5f); - glClearDepthf(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glEnable(GL_CULL_FACE); @@ -56,6 +54,8 @@ void CanvasAndroid::clear() { + glClearColor(0.0f, 0.0f, 0.0f, 0.5f); + glClearDepthf(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } === modified file 'src/canvas-x11.cpp' --- src/canvas-x11.cpp 2011-08-09 10:51:03 +0000 +++ src/canvas-x11.cpp 2011-09-09 11:24:17 +0000 @@ -84,12 +84,6 @@ if (!make_current()) return false; - glClearColor(0.0f, 0.0f, 0.0f, 0.5f); -#if USE_GL - glClearDepth(1.0f); -#elif USE_GLESv2 - glClearDepthf(1.0f); -#endif glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glEnable(GL_CULL_FACE); @@ -110,6 +104,12 @@ void CanvasX11::clear() { + glClearColor(0.0f, 0.0f, 0.0f, 0.5f); +#if USE_GL + glClearDepth(1.0f); +#elif USE_GLESv2 + glClearDepthf(1.0f); +#endif glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } === modified file 'src/main.cpp' --- src/main.cpp 2011-09-07 09:40:57 +0000 +++ src/main.cpp 2011-09-12 16:08:24 +0000 @@ -54,6 +54,7 @@ "effect2d:kernel=0,1,0;1,-4,1;0,1,0;", "effect2d:kernel=1,1,1,1,1;1,1,1,1,1;1,1,1,1,1;", "pulsar:quads=5:texture=false:light=false", + "desktop:windows=4:effect=blur:blur-radius=5:passes=1:separable=true", "conditionals:vertex-steps=0:fragment-steps=0", "conditionals:vertex-steps=0:fragment-steps=5", "conditionals:vertex-steps=5:fragment-steps=0", @@ -96,6 +97,7 @@ scenes.push_back(new SceneBump(canvas)); scenes.push_back(new SceneEffect2D(canvas)); scenes.push_back(new ScenePulsar(canvas)); + scenes.push_back(new SceneDesktop(canvas)); for (vector::const_iterator iter = scenes.begin(); iter != scenes.end(); === added file 'src/scene-desktop.cpp' --- src/scene-desktop.cpp 1970-01-01 00:00:00 +0000 +++ src/scene-desktop.cpp 2011-09-13 09:36:32 +0000 @@ -0,0 +1,775 @@ +/* + * Copyright © 2010-2011 Linaro Limited + * + * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark. + * + * glmark2 is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * glmark2. If not, see . + * + * Authors: + * Alexandros Frantzis (glmark2) + */ +#include + +#include "scene.h" +#include "mat.h" +#include "stack.h" +#include "vec.h" +#include "log.h" +#include "program.h" +#include "shader-source.h" +#include "util.h" + +enum BlurDirection { + BlurDirectionHorizontal, + BlurDirectionVertical, + BlurDirectionBoth +}; + +static void +create_blur_shaders(ShaderSource& vtx_source, ShaderSource& frg_source, + unsigned int radius, float sigma, BlurDirection direction) +{ + vtx_source.append_file(GLMARK_DATA_PATH"/shaders/desktop.vert"); + frg_source.append_file(GLMARK_DATA_PATH"/shaders/desktop-blur.frag"); + + /* Don't let the gaussian curve become too narrow */ + if (sigma < 1.0) + sigma = 1.0; + + unsigned int side = 2 * radius + 1; + + for (size_t i = 0; i < radius + 1; i++) { + float s2 = 2.0 * sigma * sigma; + float k = 1.0 / std::sqrt(M_PI * s2) * std::exp( - ((float)i * i) / s2); + std::stringstream ss_tmp; + ss_tmp << "Kernel" << i; + frg_source.add_const(ss_tmp.str(), k); + } + + std::stringstream ss; + ss << "result = " << std::endl; + + if (direction == BlurDirectionHorizontal) { + for (size_t i = 0; i < side; i++) { + int offset = (int)(i - radius); + ss << "texture2D(Texture0, TextureCoord + vec2(" << + offset << ".0 * TextureStepX, 0.0)) * Kernel" << + std::abs(offset) << " +" << std::endl; + } + ss << "0.0 ;" << std::endl; + } + else if (direction == BlurDirectionVertical) { + for (size_t i = 0; i < side; i++) { + int offset = (int)(i - radius); + ss << "texture2D(Texture0, TextureCoord + vec2(0.0, " << + offset << ".0 * TextureStepY)) * Kernel" << + std::abs(offset) << " +" << std::endl; + } + ss << "0.0 ;" << std::endl; + } + else if (direction == BlurDirectionBoth) { + for (size_t i = 0; i < side; i++) { + int ioffset = (int)(i - radius); + for (size_t j = 0; j < side; j++) { + int joffset = (int)(j - radius); + ss << "texture2D(Texture0, TextureCoord + vec2(" << + ioffset << ".0 * TextureStepX, " << + joffset << ".0 * TextureStepY))" << + " * Kernel" << std::abs(ioffset) << + " * Kernel" << std::abs(joffset) << " +" << std::endl; + } + } + ss << " 0.0;" << std::endl; + } + + frg_source.replace("$CONVOLUTION$", ss.str()); +} + +/** + * A RenderObject represents a source and target of rendering + * operations. + */ +class RenderObject +{ +public: + RenderObject() : texture_(0), fbo_(0) { } + + virtual ~RenderObject() { release(); } + + virtual void init() + { + /* Create a texture to draw to */ + glGenTextures(1, &texture_); + glBindTexture(GL_TEXTURE_2D, texture_); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size_.x(), size_.y(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, 0); + + /* Create a FBO */ + glGenFramebuffers(1, &fbo_); + glBindFramebuffer(GL_FRAMEBUFFER, fbo_); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, texture_, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + /* Load the shader program when this class if first used */ + if (RenderObject::use_count == 0) { + ShaderSource vtx_source(GLMARK_DATA_PATH"/shaders/desktop.vert"); + ShaderSource frg_source(GLMARK_DATA_PATH"/shaders/desktop.frag"); + Scene::load_shaders_from_strings(main_program, vtx_source.str(), + frg_source.str()); + } + + RenderObject::use_count++; + } + + virtual void release() + { + /* Release resources */ + glDeleteTextures(1, &texture_); + glDeleteFramebuffers(1, &fbo_); + texture_ = 0; + fbo_ = 0; + + /* + * Release the shader program when object of this class + * are no longer in use. + */ + RenderObject::use_count--; + if (RenderObject::use_count == 0) + RenderObject::main_program.release(); + } + + void make_current() + { + glBindFramebuffer(GL_FRAMEBUFFER, fbo_); + glViewport(0, 0, size_.x(), size_.y()); + } + + void position(const LibMatrix::vec2& pos) { pos_ = pos; } + const LibMatrix::vec2& position() { return pos_; } + + + virtual void size(const LibMatrix::vec2& size) + { + /* Recreate the backing texture with correct size */ + if (size_.x() != size.x() || size_.y() != size.y()) { + size_ = size; + glBindTexture(GL_TEXTURE_2D, texture_); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size_.x(), size_.y(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, 0); + clear(); + } + } + + const LibMatrix::vec2& size() { return size_; } + + const LibMatrix::vec2& speed() { return speed_; } + void speed(const LibMatrix::vec2& speed) { speed_ = speed; } + + GLuint texture() { return texture_; } + + virtual void clear() + { + make_current(); + glClear(GL_COLOR_BUFFER_BIT); + } + + virtual void render_to(RenderObject& target, Program& program = main_program) + { + LibMatrix::vec2 final_pos(pos_ + size_); + LibMatrix::vec2 ll(target.normalize_position(pos_)); + LibMatrix::vec2 ur(target.normalize_position(final_pos)); + + GLfloat position[2 * 4] = { + ll.x(), ll.y(), + ur.x(), ll.y(), + ll.x(), ur.y(), + ur.x(), ur.y(), + }; + + static const GLfloat texcoord[2 * 4] = { + 0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + 1.0, 1.0, + }; + + target.make_current(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture_); + draw_quad_with_program(position, texcoord, program); + } + + virtual void render_from(RenderObject& target, Program& program = main_program) + { + LibMatrix::vec2 final_pos(pos_ + size_); + LibMatrix::vec2 ll_tex(target.normalize_texcoord(pos_)); + LibMatrix::vec2 ur_tex(target.normalize_texcoord(final_pos)); + + static const GLfloat position_blur[2 * 4] = { + -1.0, -1.0, + 1.0, -1.0, + -1.0, 1.0, + 1.0, 1.0, + }; + GLfloat texcoord_blur[2 * 4] = { + ll_tex.x(), ll_tex.y(), + ur_tex.x(), ll_tex.y(), + ll_tex.x(), ur_tex.y(), + ur_tex.x(), ur_tex.y(), + }; + + make_current(); + glBindTexture(GL_TEXTURE_2D, target.texture()); + draw_quad_with_program(position_blur, texcoord_blur, program); + } + + /** + * Normalizes a position from [0, size] to [-1.0, 1.0] + */ + LibMatrix::vec2 normalize_position(LibMatrix::vec2& pos) + { + return LibMatrix::vec2(2.0 * pos.x() / size_.x() - 1.0, + 2.0 * pos.y() / size_.y() - 1.0); + } + + /** + * Normalizes a position from [0, size] to [0.0, 1.0] + */ + LibMatrix::vec2 normalize_texcoord(LibMatrix::vec2& pos) + { + return LibMatrix::vec2(pos.x() / size_.x(), + pos.y() / size_.y()); + } + + +protected: + void draw_quad_with_program(const GLfloat *position, const GLfloat *texcoord, + Program &program) + { + int pos_index = program["position"].location(); + int tex_index = program["texcoord"].location(); + + program.start(); + + glEnableVertexAttribArray(pos_index); + glEnableVertexAttribArray(tex_index); + glVertexAttribPointer(pos_index, 2, + GL_FLOAT, GL_FALSE, 0, position); + glVertexAttribPointer(tex_index, 2, + GL_FLOAT, GL_FALSE, 0, texcoord); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glDisableVertexAttribArray(tex_index); + glDisableVertexAttribArray(pos_index); + + program.stop(); + } + + static Program main_program; + + LibMatrix::vec2 pos_; + LibMatrix::vec2 size_; + LibMatrix::vec2 speed_; + GLuint texture_; + GLuint fbo_; + +private: + static int use_count; + +}; + +int RenderObject::use_count = 0; +Program RenderObject::main_program; + +/** + * A RenderObject representing the screen. + * + * Rendering to this objects renders to the screen framebuffer. + */ +class RenderScreen : public RenderObject +{ +public: + virtual void init() {} +}; + +/** + * A RenderObject with a background image. + * + * The image is drawn to the RenderObject automatically when the + * object is cleared, resized etc + */ +class RenderClearImage : public RenderObject +{ +public: + RenderClearImage(const std::string& texture) : + RenderObject(), background_texture_name(texture), + background_texture_(0) {} + + virtual void init() + { + RenderObject::init(); + + /* Load the image into a texture */ + Texture::load(background_texture_name, + &background_texture_, GL_LINEAR, GL_LINEAR, 0); + + } + + virtual void release() + { + glDeleteTextures(1, &background_texture_); + background_texture_ = 0; + + RenderObject::release(); + } + + virtual void clear() + { + static const GLfloat position[2 * 4] = { + -1.0, -1.0, + 1.0, -1.0, + -1.0, 1.0, + 1.0, 1.0, + }; + static const GLfloat texcoord[2 * 4] = { + 0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + 1.0, 1.0, + }; + + make_current(); + glClear(GL_COLOR_BUFFER_BIT); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, background_texture_); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + draw_quad_with_program(position, texcoord, main_program); + glDisable(GL_BLEND); + } + +private: + std::string background_texture_name; + GLuint background_texture_; +}; + +/** + * A RenderObject that blurs the target it is drawn to. + */ +class RenderWindowBlur : public RenderObject +{ +public: + RenderWindowBlur(unsigned int passes, unsigned int radius, bool separable, + bool draw_contents = true) : + RenderObject(), passes_(passes), radius_(radius), separable_(separable), + draw_contents_(draw_contents) {} + + virtual void init() + { + RenderObject::init(); + + /* Only have one instance of the window contents data */ + if (draw_contents_ && RenderWindowBlur::use_count == 0) + window_contents_.init(); + + RenderWindowBlur::use_count++; + } + + virtual void release() + { + RenderWindowBlur::use_count--; + + /* Only have one instance of the window contents data */ + if (draw_contents_ && RenderWindowBlur::use_count == 0) + window_contents_.release(); + + RenderObject::release(); + } + + virtual void size(const LibMatrix::vec2& size) + { + RenderObject::size(size); + if (draw_contents_) + window_contents_.size(size); + } + + virtual void render_to(RenderObject& target, Program& program) + { + (void)program; + + if (separable_) { + Program& blur_program_h1 = blur_program_h(target.size().x()); + Program& blur_program_v1 = blur_program_v(target.size().y()); + + for (unsigned int i = 0; i < passes_; i++) { + render_from(target, blur_program_h1); + RenderObject::render_to(target, blur_program_v1); + } + } + else { + Program& blur_program1 = blur_program(target.size().x(), target.size().y()); + + for (unsigned int i = 0; i < passes_; i++) { + if (i % 2 == 0) + render_from(target, blur_program1); + else + RenderObject::render_to(target, blur_program1); + } + + if (passes_ % 2 == 1) + RenderObject::render_to(target); + } + + /* + * Blend the window contents with the target texture. + */ + if (draw_contents_) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + window_contents_.position(position()); + window_contents_.render_to(target); + glDisable(GL_BLEND); + } + } + +private: + Program& blur_program(unsigned int w, unsigned int h) + { + /* + * If the size of the window has changed we must recreate + * the shader to contain the correct texture step values. + */ + if (blur_program_dim_.x() != w || blur_program_dim_.y() != h || + !blur_program_.ready()) + { + blur_program_dim_.x(w); + blur_program_dim_.y(h); + + blur_program_.release(); + + ShaderSource vtx_source; + ShaderSource frg_source; + create_blur_shaders(vtx_source, frg_source, radius_, + radius_ / 3.0, BlurDirectionBoth); + frg_source.add_const("TextureStepX", 1.0 / w); + frg_source.add_const("TextureStepY", 1.0 / h); + Scene::load_shaders_from_strings(blur_program_, vtx_source.str(), + frg_source.str()); + } + + return blur_program_; + } + + Program& blur_program_h(unsigned int w) + { + /* + * If the size of the window has changed we must recreate + * the shader to contain the correct texture step values. + */ + if (blur_program_dim_.x() != w || + !blur_program_h_.ready()) + { + blur_program_dim_.x(w); + + blur_program_h_.release(); + + ShaderSource vtx_source; + ShaderSource frg_source; + create_blur_shaders(vtx_source, frg_source, radius_, + radius_ / 3.0, BlurDirectionHorizontal); + frg_source.add_const("TextureStepX", 1.0 / w); + Scene::load_shaders_from_strings(blur_program_h_, vtx_source.str(), + frg_source.str()); + } + + return blur_program_h_; + } + + Program& blur_program_v(unsigned int h) + { + /* + * If the size of the window has changed we must recreate + * the shader to contain the correct texture step values. + */ + if (blur_program_dim_.y() != h || + !blur_program_v_.ready()) + { + blur_program_dim_.y(h); + + blur_program_v_.release(); + + ShaderSource vtx_source; + ShaderSource frg_source; + create_blur_shaders(vtx_source, frg_source, radius_, + radius_ / 3.0, BlurDirectionVertical); + frg_source.add_const("TextureStepY", 1.0 / h); + Scene::load_shaders_from_strings(blur_program_v_, vtx_source.str(), + frg_source.str()); + } + + return blur_program_v_; + } + + LibMatrix::uvec2 blur_program_dim_; + Program blur_program_; + Program blur_program_h_; + Program blur_program_v_; + unsigned int passes_; + unsigned int radius_; + bool separable_; + bool draw_contents_; + + static int use_count; + static RenderClearImage window_contents_; + +}; + +int RenderWindowBlur::use_count = 0; +RenderClearImage RenderWindowBlur::window_contents_(GLMARK_DATA_PATH"/textures/desktop-window.png"); + +/******************************* + * SceneDesktop implementation * + *******************************/ + +/** + * Private structure used to avoid contaminating scene.h with all of the + * SceneDesktop internal classes. + */ +struct SceneDesktopPrivate +{ + RenderScreen screen; + RenderClearImage desktop; + std::vector windows; + + SceneDesktopPrivate() : + desktop(GLMARK_DATA_PATH"/textures/effect-2d.png") {} + + ~SceneDesktopPrivate() { Util::dispose_pointer_vector(windows); } + +}; + + +SceneDesktop::SceneDesktop(Canvas &canvas) : + Scene(canvas, "desktop") +{ + priv_ = new SceneDesktopPrivate(); + mOptions["effect"] = Scene::Option("effect", "blur", + "the effect to use [blur]"); + mOptions["windows"] = Scene::Option("windows", "4", + "the number of windows"); + mOptions["window-size"] = Scene::Option("window-size", "0.35", + "the window size as a percentage of the minimum screen dimension [0.0 - 0.5]"); + mOptions["passes"] = Scene::Option("passes", "1", + "the number of effect passes (effect dependent)"); + mOptions["blur-radius"] = Scene::Option("blur-radius", "5", + "the blur effect radius (in pixels)"); + mOptions["separable"] = Scene::Option("separable", "true", + "use separable convolution for the blur effect"); +} + +SceneDesktop::~SceneDesktop() +{ + delete priv_; +} + +int +SceneDesktop::load() +{ + priv_->screen.init(); + priv_->desktop.init(); + return 1; +} + +void +SceneDesktop::unload() +{ + priv_->desktop.release(); + priv_->screen.release(); +} + +void +SceneDesktop::setup() +{ + Scene::setup(); + + std::stringstream ss; + unsigned int windows(0); + unsigned int passes(0); + unsigned int blur_radius(0); + float window_size_factor(0.0); + bool separable(mOptions["separable"].value == "true"); + + ss << mOptions["windows"].value; + ss >> windows; + ss.clear(); + ss << mOptions["window-size"].value; + ss >> window_size_factor; + ss.clear(); + ss << mOptions["passes"].value; + ss >> passes; + ss.clear(); + ss << mOptions["blur-radius"].value; + ss >> blur_radius; + + /* Ensure we get a transparent clear color for all following operations */ + glClearColor(0.0, 0.0, 0.0, 0.0); + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + /* Set up the screen and desktop RenderObjects */ + priv_->screen.size(LibMatrix::vec2(mCanvas.width(), mCanvas.height())); + priv_->desktop.size(LibMatrix::vec2(mCanvas.width(), mCanvas.height())); + + /* Create the windows */ + float angular_step(2.0 * M_PI / windows); + unsigned int min_dimension = std::min(mCanvas.width(), mCanvas.height()); + float window_size(min_dimension * window_size_factor); + static const LibMatrix::vec2 corner_offset(window_size / 2.0, + window_size / 2.0); + + for (unsigned int i = 0; i < windows; i++) { + LibMatrix::vec2 center(mCanvas.width() * (0.5 + 0.25 * cos(i * angular_step)), + mCanvas.height() * (0.5 + 0.25 * sin(i * angular_step))); + RenderObject* win(new RenderWindowBlur(passes, blur_radius, separable)); + (void)angular_step; + + win->init(); + win->position(center - corner_offset); + win->size(LibMatrix::vec2(window_size, window_size)); + /* + * Set the speed in increments of about 30 degrees (but not exactly, + * so we don't get windows moving just on the X axis or Y axis). + */ + win->speed(LibMatrix::vec2(cos(0.1 + i * M_PI / 6.0) * mCanvas.width() / 3, + sin(0.1 + i * M_PI / 6.0) * mCanvas.height() / 3)); + /* + * Perform a dummy rendering to ensure internal shaders are initialized + * now, in order not to affect the benchmarking. + */ + win->render_to(priv_->desktop); + priv_->windows.push_back(win); + } + + /* + * Ensure the screen is the current rendering target (it might have changed + * to a FBO in the previous steps). + */ + priv_->screen.make_current(); + + mCurrentFrame = 0; + mRunning = true; + mStartTime = Scene::get_timestamp_us() / 1000000.0; + mLastUpdateTime = mStartTime; +} + +void +SceneDesktop::teardown() +{ + Util::dispose_pointer_vector(priv_->windows); + priv_->screen.make_current(); + + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + + Scene::teardown(); +} + +void +SceneDesktop::update() +{ + double current_time = Scene::get_timestamp_us() / 1000000.0; + double dt = current_time - mLastUpdateTime; + double elapsed_time = current_time - mStartTime; + + mLastUpdateTime = current_time; + + std::vector& windows(priv_->windows); + + /* + * Move the windows around the screen, bouncing them back when + * they reach the edge. + */ + for (std::vector::const_iterator iter = windows.begin(); + iter != windows.end(); + iter++) + { + bool should_update = true; + RenderObject *win = *iter; + LibMatrix::vec2 new_pos( + win->position().x() + win->speed().x() * dt, + win->position().y() + win->speed().y() * dt); + + if (new_pos.x() < 0.0 || + new_pos.x() + win->size().x() > ((float)mCanvas.width())) + { + win->speed(LibMatrix::vec2(-win->speed().x(), win->speed().y())); + should_update = false; + } + + if (new_pos.y() < 0.0 || + new_pos.y() + win->size().y() > ((float)mCanvas.height())) + { + win->speed(LibMatrix::vec2(win->speed().x(), -win->speed().y())); + should_update = false; + } + + if (should_update) + win->position(new_pos); + } + + if (elapsed_time >= mDuration) { + mAverageFPS = mCurrentFrame / elapsed_time; + mRunning = false; + } + + mCurrentFrame++; +} + +void +SceneDesktop::draw() +{ + std::vector& windows(priv_->windows); + + /* Ensure we get a transparent clear color for all following operations */ + glClearColor(0.0, 0.0, 0.0, 0.0); + + priv_->desktop.clear(); + + for (std::vector::const_iterator iter = windows.begin(); + iter != windows.end(); + iter++) + { + RenderObject *win = *iter; + win->render_to(priv_->desktop); + } + + priv_->desktop.render_to(priv_->screen); + +} + +Scene::ValidationResult +SceneDesktop::validate() +{ + return ValidationUnknown; +} === modified file 'src/scene.h' --- src/scene.h 2011-08-18 13:20:04 +0000 +++ src/scene.h 2011-09-09 13:57:53 +0000 @@ -331,4 +331,23 @@ void create_and_setup_mesh(); }; +struct SceneDesktopPrivate; + +class SceneDesktop : public Scene +{ +public: + SceneDesktop(Canvas &canvas); + int load(); + void unload(); + void setup(); + void teardown(); + void update(); + void draw(); + ValidationResult validate(); + + ~SceneDesktop(); + +private: + SceneDesktopPrivate *priv_; +}; #endif