blob: 6e97a54223e0173a3da22b7cc8b069dc7587f09b [file] [log] [blame]
/*
* Copyright © 2012 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
*/
#include "options.h"
#include "main-loop.h"
#include "util.h"
#include "log.h"
#include <string>
#include <sstream>
/************
* MainLoop *
************/
MainLoop::MainLoop(Canvas &canvas, const std::vector<Benchmark *> &benchmarks) :
canvas_(canvas), benchmarks_(benchmarks)
{
reset();
}
void
MainLoop::reset()
{
scene_ = 0;
score_ = 0;
benchmarks_run_ = 0;
bench_iter_ = benchmarks_.begin();
}
unsigned int
MainLoop::score()
{
if (benchmarks_run_)
return score_ / benchmarks_run_;
else
return score_;
}
bool
MainLoop::step()
{
/* Find the next normal scene */
if (!scene_) {
/* Find a normal scene */
while (bench_iter_ != benchmarks_.end()) {
scene_ = &(*bench_iter_)->scene();
/*
* Scenes with empty names are option-setting scenes.
* Just set them up and continue with the search.
*/
if (scene_->name().empty())
(*bench_iter_)->setup_scene();
else
break;
next_benchmark();
}
/* If we have found a valid scene, set it up */
if (bench_iter_ != benchmarks_.end()) {
if (!Options::reuse_context)
canvas_.reset();
before_scene_setup();
scene_ = &(*bench_iter_)->setup_scene();
after_scene_setup();
log_scene_info();
}
else {
/* ... otherwise we are done */
return false;
}
}
bool should_quit = canvas_.should_quit();
if (scene_ ->running() && !should_quit)
draw();
/*
* Need to recheck whether the scene is still running, because code
* in draw() may have changed the state.
*/
if (!scene_->running() || should_quit) {
score_ += scene_->average_fps();
log_scene_result();
(*bench_iter_)->teardown_scene();
scene_ = 0;
next_benchmark();
benchmarks_run_++;
}
return !should_quit;
}
void
MainLoop::draw()
{
canvas_.clear();
scene_->draw();
scene_->update();
canvas_.update();
}
void
MainLoop::log_scene_info()
{
Log::info("%s", scene_->info_string().c_str());
Log::flush();
}
void
MainLoop::log_scene_result()
{
static const std::string format_fps(Log::continuation_prefix + " FPS: %u");
static const std::string format_ms(Log::continuation_prefix + " FrameTime: %.3f ms\n");
Log::info(format_fps.c_str(), scene_->average_fps());
Log::info(format_ms.c_str(), 1000.0 / scene_->average_fps());
}
void
MainLoop::next_benchmark()
{
bench_iter_++;
if (bench_iter_ == benchmarks_.end() && Options::run_forever)
bench_iter_ = benchmarks_.begin();
}
/**********************
* MainLoopDecoration *
**********************/
MainLoopDecoration::MainLoopDecoration(Canvas &canvas, const std::vector<Benchmark *> &benchmarks) :
MainLoop(canvas, benchmarks), show_fps_(false), show_title_(false),
fps_renderer_(0), title_renderer_(0), last_fps_(0)
{
}
MainLoopDecoration::~MainLoopDecoration()
{
delete fps_renderer_;
fps_renderer_ = 0;
delete title_renderer_;
title_renderer_ = 0;
}
void
MainLoopDecoration::draw()
{
static const unsigned int fps_interval = 500000;
canvas_.clear();
scene_->draw();
scene_->update();
if (show_fps_) {
uint64_t now = Util::get_timestamp_us();
if (now - fps_timestamp_ >= fps_interval) {
last_fps_ = scene_->average_fps();
fps_renderer_update_text(last_fps_);
fps_timestamp_ = now;
}
fps_renderer_->render();
}
if (show_title_)
title_renderer_->render();
canvas_.update();
}
void
MainLoopDecoration::before_scene_setup()
{
delete fps_renderer_;
fps_renderer_ = 0;
delete title_renderer_;
title_renderer_ = 0;
}
void
MainLoopDecoration::after_scene_setup()
{
const Scene::Option &show_fps_option(scene_->options().find("show-fps")->second);
const Scene::Option &title_option(scene_->options().find("title")->second);
show_fps_ = show_fps_option.value == "true";
show_title_ = !title_option.value.empty();
if (show_fps_) {
const Scene::Option &fps_pos_option(scene_->options().find("fps-pos")->second);
const Scene::Option &fps_size_option(scene_->options().find("fps-size")->second);
fps_renderer_ = new TextRenderer(canvas_);
fps_renderer_->position(vec2_from_pos_string(fps_pos_option.value));
fps_renderer_->size(Util::fromString<float>(fps_size_option.value));
fps_renderer_update_text(last_fps_);
fps_timestamp_ = Util::get_timestamp_us();
}
if (show_title_) {
const Scene::Option &title_pos_option(scene_->options().find("title-pos")->second);
const Scene::Option &title_size_option(scene_->options().find("title-size")->second);
title_renderer_ = new TextRenderer(canvas_);
title_renderer_->position(vec2_from_pos_string(title_pos_option.value));
title_renderer_->size(Util::fromString<float>(title_size_option.value));
if (title_option.value == "#info#")
title_renderer_->text(scene_->info_string());
else if (title_option.value == "#name#")
title_renderer_->text(scene_->name());
else if (title_option.value == "#r2d2#")
title_renderer_->text("Help me, Obi-Wan Kenobi. You're my only hope.");
else
title_renderer_->text(title_option.value);
}
}
void
MainLoopDecoration::fps_renderer_update_text(unsigned int fps)
{
std::stringstream ss;
ss << "FPS: " << fps;
fps_renderer_->text(ss.str());
}
LibMatrix::vec2
MainLoopDecoration::vec2_from_pos_string(const std::string &s)
{
LibMatrix::vec2 v(0.0, 0.0);
std::vector<std::string> elems;
Util::split(s, ',', elems, Util::SplitModeNormal);
if (elems.size() > 0)
v.x(Util::fromString<float>(elems[0]));
if (elems.size() > 1)
v.y(Util::fromString<float>(elems[1]));
return v;
}
/**********************
* MainLoopValidation *
**********************/
MainLoopValidation::MainLoopValidation(Canvas &canvas, const std::vector<Benchmark *> &benchmarks) :
MainLoop(canvas, benchmarks)
{
}
void
MainLoopValidation::draw()
{
/* Draw only the first frame of the scene and stop */
canvas_.clear();
scene_->draw();
canvas_.update();
scene_->running(false);
}
void
MainLoopValidation::log_scene_result()
{
static const std::string format(Log::continuation_prefix + " Validation: %s\n");
std::string result;
switch(scene_->validate()) {
case Scene::ValidationSuccess:
result = "Success";
break;
case Scene::ValidationFailure:
result = "Failure";
break;
case Scene::ValidationUnknown:
result = "Unknown";
break;
default:
break;
}
Log::info(format.c_str(), result.c_str());
}