=== added file 'data/shaders/text-renderer.frag'
@@ -0,0 +1,10 @@
+uniform sampler2D Texture0;
+
+varying vec2 TextureCoord;
+
+void main(void)
+{
+ vec4 texel = texture2D(Texture0, TextureCoord);
+ gl_FragColor = texel;
+}
+
=== added file 'data/shaders/text-renderer.vert'
@@ -0,0 +1,10 @@
+attribute vec2 position;
+attribute vec2 texcoord;
+
+varying vec2 TextureCoord;
+
+void main(void)
+{
+ TextureCoord = texcoord;
+ gl_Position = vec4(position, 0.0, 1.0);
+}
=== added file 'data/textures/glyph-atlas.png'
Binary files data/textures/glyph-atlas.png 1970-01-01 00:00:00 +0000 and data/textures/glyph-atlas.png 2011-12-13 14:25:41 +0000 differ
=== modified file 'doc/glmark2.1.in'
@@ -36,6 +36,10 @@
Show all scene option values used for benchmarks
(only explicitly set options are shown by default)
.TP
+\fB\-\-show-fps\fR
+Show live FPS count on screen (showing live FPS
+affects benchmarking results, use with care!)
+.TP
\fB\-d\fR, \fB\-\-debug\fR
Display debug messages
.TP
=== modified file 'src/main.cpp'
@@ -28,6 +28,7 @@
#include "log.h"
#include "util.h"
#include "default-benchmarks.h"
+#include "text-renderer.h"
#include <iostream>
#include <fstream>
@@ -149,6 +150,8 @@
void
do_benchmark(Canvas &canvas, vector<Benchmark *> &benchmarks)
{
+ static const unsigned int fps_interval = 500000;
+ TextRenderer fps_renderer(canvas);
unsigned score = 0;
unsigned int benchmarks_run = 0;
@@ -158,6 +161,7 @@
{
bool keep_running = true;
Benchmark *bench = *bench_iter;
+ uint64_t fps_timestamp = Util::get_timestamp_us();
Scene &scene = bench->setup_scene();
if (!scene.name().empty()) {
@@ -172,6 +176,17 @@
scene.draw();
scene.update();
+ if (Options::show_fps) {
+ uint64_t now = Util::get_timestamp_us();
+ if (now - fps_timestamp >= fps_interval) {
+ std::stringstream ss;
+ ss << "FPS: " << scene.average_fps();
+ fps_renderer.text(ss.str());
+ fps_timestamp = now;
+ }
+ fps_renderer.render();
+ }
+
canvas.update();
}
=== modified file 'src/options.cpp'
@@ -39,6 +39,7 @@
bool Options::list_scenes = false;
bool Options::show_all_options = false;
bool Options::show_debug = false;
+bool Options::show_fps = false;
bool Options::show_help = false;
static struct option long_options[] = {
@@ -49,6 +50,7 @@
{"size", 1, 0, 0},
{"list-scenes", 0, 0, 0},
{"show-all-options", 0, 0, 0},
+ {"show-fps", 0, 0, 0},
{"debug", 0, 0, 0},
{"help", 0, 0, 0},
{0, 0, 0, 0}
@@ -98,6 +100,8 @@
" and their options\n"
" --show-all-options Show all scene option values used for benchmarks\n"
" (only explicitly set options are shown by default)\n"
+ " --show-fps Show live FPS count on screen (showing live FPS\n"
+ " affects benchmarking results, use with care!)\n"
" -d, --debug Display debug messages\n"
" -h, --help Display help\n");
}
@@ -134,6 +138,8 @@
Options::list_scenes = true;
else if (!strcmp(optname, "show-all-options"))
Options::show_all_options = true;
+ else if (!strcmp(optname, "show-fps"))
+ Options::show_fps = true;
else if (c == 'd' || !strcmp(optname, "debug"))
Options::show_debug = true;
else if (c == 'h' || !strcmp(optname, "help"))
=== modified file 'src/options.h'
@@ -39,6 +39,7 @@
static bool list_scenes;
static bool show_all_options;
static bool show_debug;
+ static bool show_fps;
static bool show_help;
};
=== added file 'src/text-renderer.cpp'
@@ -0,0 +1,291 @@
+/*
+ * Copyright © 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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexandros Frantzis (glmark2)
+ */
+#include "text-renderer.h"
+#include "gl-headers.h"
+#include "scene.h"
+#include "shader-source.h"
+#include "vec.h"
+#include "mat.h"
+#include "texture.h"
+
+using LibMatrix::vec2;
+using LibMatrix::mat4;
+
+/* These are specific to the glyph texture atlas we are using */
+static const unsigned int texture_size(512);
+static const vec2 glyph_size_pixels(29.0, 57.0);
+static const vec2 glyph_size(glyph_size_pixels/texture_size);
+
+/******************
+ * Public methods *
+ ******************/
+
+/**
+ * TextRenderer default constructor.
+ */
+TextRenderer::TextRenderer(Canvas& canvas) :
+ canvas_(canvas), dirty_(false), position_(-1.0, -1.0),
+ texture_(0)
+{
+ size(0.03);
+
+ glGenBuffers(2, vbo_);
+ ShaderSource vtx_source(GLMARK_DATA_PATH"/shaders/text-renderer.vert");
+ ShaderSource frg_source(GLMARK_DATA_PATH"/shaders/text-renderer.frag");
+
+ if (!Scene::load_shaders_from_strings(program_, vtx_source.str(),
+ frg_source.str()))
+ {
+ return;
+ }
+
+ GLint prev_program;
+ glGetIntegerv(GL_CURRENT_PROGRAM, &prev_program);
+
+ program_.start();
+ program_["Texture0"] = 0;
+
+ glUseProgram(prev_program);
+
+ /* Load the glyph texture atlas */
+ Texture::load(GLMARK_DATA_PATH"/textures/glyph-atlas.png", &texture_,
+ GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR,0);
+}
+
+TextRenderer::~TextRenderer()
+{
+ glDeleteBuffers(2, vbo_);
+ glDeleteTextures(1, &texture_);
+}
+
+/**
+ * Sets the text string to render.
+ *
+ * @param t the text string
+ */
+void
+TextRenderer::text(const std::string& t)
+{
+ if (text_ != t) {
+ text_ = t;
+ dirty_ = true;
+ }
+}
+
+/**
+ * Sets the screen position to render at.
+ *
+ * @param t the position
+ */
+void
+TextRenderer::position(LibMatrix::vec2& p)
+{
+ if (position_ != p) {
+ position_ = p;
+ dirty_ = true;
+ }
+}
+
+/**
+ * Sets the size of each rendered glyph.
+ *
+ * The size corresponds to the width of each glyph
+ * in normalized screen coordinates.
+ *
+ * @param s the size of each glyph
+ */
+void
+TextRenderer::size(float s)
+{
+ if (size_.x() != s) {
+ /* Take into account the glyph and canvas aspect ratio */
+ double canvas_aspect =
+ static_cast<double>(canvas_.width()) / canvas_.height();
+ double glyph_aspect_rev = glyph_size.y() / glyph_size.x();
+ size_ = vec2(s, s * canvas_aspect * glyph_aspect_rev);
+ dirty_ = true;
+ }
+}
+
+/**
+ * Renders the text.
+ */
+void
+TextRenderer::render()
+{
+ /* Save state */
+ GLint prev_program = 0;
+ GLint prev_array_buffer = 0;
+ GLint prev_elem_array_buffer = 0;
+ GLint prev_blend_src_rgb = 0;
+ GLint prev_blend_dst_rgb = 0;
+ GLint prev_blend_src_alpha = 0;
+ GLint prev_blend_dst_alpha = 0;
+ GLboolean prev_blend = GL_FALSE;
+ GLboolean prev_depth_test = GL_FALSE;
+ glGetIntegerv(GL_CURRENT_PROGRAM, &prev_program);
+ glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prev_array_buffer);
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &prev_elem_array_buffer);
+ glGetIntegerv(GL_BLEND_SRC_RGB, &prev_blend_src_rgb);
+ glGetIntegerv(GL_BLEND_DST_RGB, &prev_blend_dst_rgb);
+ glGetIntegerv(GL_BLEND_SRC_ALPHA, &prev_blend_src_alpha);
+ glGetIntegerv(GL_BLEND_DST_ALPHA, &prev_blend_dst_alpha);
+ glGetBooleanv(GL_BLEND, &prev_blend);
+ glGetBooleanv(GL_DEPTH_TEST, &prev_depth_test);
+
+ /* Set new state */
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture_);
+ glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_[1]);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_DEPTH_TEST);
+
+ if (dirty_) {
+ create_geometry();
+ dirty_ = false;
+ }
+
+ program_.start();
+ GLint position_loc = program_["position"].location();
+ GLint texcoord_loc = program_["texcoord"].location();
+
+ /* Render */
+ glEnableVertexAttribArray(position_loc);
+ glEnableVertexAttribArray(texcoord_loc);
+ glVertexAttribPointer(position_loc, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
+ glVertexAttribPointer(texcoord_loc, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float),
+ reinterpret_cast<const GLvoid *>(2 * sizeof(float)));
+
+ glDrawElements(GL_TRIANGLES, 6 * text_.length(), GL_UNSIGNED_SHORT, 0);
+
+ glDisableVertexAttribArray(texcoord_loc);
+ glDisableVertexAttribArray(position_loc);
+
+ /* Restore state */
+ if (prev_depth_test == GL_TRUE)
+ glEnable(GL_DEPTH_TEST);
+ if (prev_blend == GL_FALSE)
+ glDisable(GL_BLEND);
+ glBlendFuncSeparate(prev_blend_src_rgb, prev_blend_dst_rgb,
+ prev_blend_src_alpha, prev_blend_dst_alpha);
+ glBindBuffer(GL_ARRAY_BUFFER, prev_array_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prev_elem_array_buffer);
+ glUseProgram(prev_program);
+}
+
+/*******************
+ * Private methods *
+ *******************/
+
+/**
+ * Creates the geometry needed to render the text.
+ *
+ * This method assumes that the text VBOs are properly bound.
+ */
+void
+TextRenderer::create_geometry()
+{
+ std::vector<float> array;
+ std::vector<GLushort> elem_array;
+ vec2 pos(position_);
+
+ for (size_t i = 0; i < text_.size(); i++) {
+ vec2 texcoord = get_glyph_coords(text_[i]);
+
+ /* Emit the elements for this glyph quad */
+ /* Lower left */
+ array.push_back(pos.x());
+ array.push_back(pos.y());
+ array.push_back(texcoord.x());
+ array.push_back(texcoord.y());
+
+ /* Lower right */
+ pos.x(pos.x() + size_.x());
+ texcoord.x(texcoord.x() + glyph_size.x());
+ array.push_back(pos.x());
+ array.push_back(pos.y());
+ array.push_back(texcoord.x());
+ array.push_back(texcoord.y());
+
+ /* Upper left */
+ pos.x(pos.x() - size_.x());
+ pos.y(pos.y() + size_.y());
+ texcoord.x(texcoord.x() - glyph_size.x());
+ texcoord.y(texcoord.y() + glyph_size.y());
+ array.push_back(pos.x());
+ array.push_back(pos.y());
+ array.push_back(texcoord.x());
+ array.push_back(texcoord.y());
+
+ /* Upper right */
+ pos.x(pos.x() + size_.x());
+ texcoord.x(texcoord.x() + glyph_size.x());
+ array.push_back(pos.x());
+ array.push_back(pos.y());
+ array.push_back(texcoord.x());
+ array.push_back(texcoord.y());
+
+ /* Prepare for the next glyph */
+ pos.y(pos.y() - size_.y());
+
+ /* Emit the element indices for this glyph quad */
+ elem_array.push_back(4 * i);
+ elem_array.push_back(4 * i + 1);
+ elem_array.push_back(4 * i + 2);
+ elem_array.push_back(4 * i + 2);
+ elem_array.push_back(4 * i + 1);
+ elem_array.push_back(4 * i + 3);
+ }
+
+ /* Load the data into the corresponding VBOs */
+ glBufferData(GL_ARRAY_BUFFER, array.size() * sizeof(float),
+ &array[0], GL_DYNAMIC_DRAW);
+
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, elem_array.size() * sizeof(GLushort),
+ &elem_array[0], GL_DYNAMIC_DRAW);
+}
+
+/**
+ * Gets the texcoords of a glyph in the glyph texture atlas.
+ *
+ * @param c the character to get the glyph texcoords of
+ *
+ * @return the texcoords
+ */
+vec2
+TextRenderer::get_glyph_coords(char c)
+{
+ static const unsigned int glyphs_per_row(texture_size / glyph_size_pixels.x());
+
+ /* We only support the ASCII printable characters */
+ if (c < 32 || c >= 127)
+ c = 32;
+
+ int n = c - 32;
+ int row = n / glyphs_per_row;
+ int col = n % glyphs_per_row;
+
+ return vec2(col * glyph_size.x(), 1.0 - (row + 1) * glyph_size.y());
+}
+
=== added file 'src/text-renderer.h'
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexandros Frantzis (glmark2)
+ */
+#ifndef GLMARK2_TEXT_RENDERER_H_
+#define GLMARK2_TEXT_RENDERER_H_
+
+#include <string>
+#include "gl-headers.h"
+#include "vec.h"
+#include "program.h"
+#include "canvas.h"
+
+/**
+ * Renders text using OpenGL textures.
+ */
+class TextRenderer
+{
+public:
+ TextRenderer(Canvas& canvas);
+ ~TextRenderer();
+
+ void text(const std::string& t);
+ void position(LibMatrix::vec2& p);
+ void size(float s);
+
+ void render();
+
+private:
+ void create_geometry();
+ LibMatrix::vec2 get_glyph_coords(char c);
+
+ Canvas& canvas_;
+ bool dirty_;
+ std::string text_;
+ LibMatrix::vec2 position_;
+ LibMatrix::vec2 size_;
+ Program program_;
+ GLuint vbo_[2];
+ GLuint texture_;
+};
+
+#endif