Skip to content

Commit

Permalink
Add a FPS counter that's invoked every time a draw call is made.
Browse files Browse the repository at this point in the history
Change the codebase so that draws are now event-driven, and every time an event is pumped, there may be a draw performed. Draw-events have been turned into singletons, so there will never be more than one in the queue.
This code also disables the loadscreen since it'll conflict with master anyway. This is still work in progress, and not complete, but is a step towards getting there.
  • Loading branch information
aginor committed Apr 4, 2016
1 parent 5114137 commit ae16c90
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 91 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Expand Up @@ -779,6 +779,7 @@ set(wesnoth-main_SRC
formula/string_utils.cpp
formula/tokenizer.cpp
formula/variant.cpp
fpscounter.cpp
game_board.cpp
game_classification.cpp
game_config_manager.cpp
Expand Down
1 change: 1 addition & 0 deletions src/SConscript
Expand Up @@ -96,6 +96,7 @@ libwesnoth_sources = Split("""
floating_label.cpp
font.cpp
format_time_summary.cpp
fpscounter.cpp
generic_event.cpp
hotkey/hotkey_item.cpp
hotkey/hotkey_command.cpp
Expand Down
4 changes: 2 additions & 2 deletions src/controller_base.cpp
Expand Up @@ -204,7 +204,7 @@ void controller_base::play_slice(bool is_delay_enabled)

events::pump();
events::raise_process_event();
events::raise_draw_event();
//events::raise_draw_event();

// Update sound sources before scrolling
if (soundsource::manager *l = get_soundsource_man()) {
Expand Down Expand Up @@ -263,7 +263,7 @@ void controller_base::play_slice(bool is_delay_enabled)
scrolling_ = true;
}

get_display().draw();
//get_display().draw();

// be nice when window is not visible
// NOTE should be handled by display instead, to only disable drawing
Expand Down
172 changes: 99 additions & 73 deletions src/display.cpp
Expand Up @@ -1402,37 +1402,55 @@ void display::toggle_debug_foreground()

void display::flip()
{
if(video().faked()) {
return;
}

surface& frameBuffer = get_video_surface();
video().flip();

// This is just the debug function "sunset" to progressively darken the map area
static size_t sunset_timer = 0;
if (sunset_delay && ++sunset_timer > sunset_delay) {
sunset_timer = 0;
SDL_Rect r = map_outside_area(); // Use frameBuffer to also test the UI
const Uint32 color = SDL_MapRGBA(video().getSurface()->format,0,0,0,SDL_ALPHA_OPAQUE);
// Adjust the alpha if you want to balance cpu-cost / smooth sunset
sdl::fill_rect_alpha(r, color, 1, frameBuffer);
update_rect(r);
}

void display::post_draw() {
if(video().faked()) {
return;
}
#ifdef SDL_GPU
font::draw_floating_labels(screen_);
#else
font::draw_floating_labels(frameBuffer);
#endif
events::raise_volatile_draw_event();

video().flip();
surface& frameBuffer = get_video_surface();

events::raise_volatile_undraw_event();
#ifdef SDL_GPU
font::undraw_floating_labels(screen_);
#else
font::undraw_floating_labels(frameBuffer);
#endif

}

void display::clear_fps_label()
{
if(fps_handle_ != 0) {
font::remove_floating_label(fps_handle_);
fps_handle_ = 0;
}
drawn_hexes_ = 0;
invalidated_hexes_ = 0;
}

void display::make_fps_label()
{
std::ostringstream stream;
stream << "fps: " << fps_.get_fps();
if (game_config::debug) {
stream << "\nhex: " << drawn_hexes_ * 1.0 / fps_.get_sample_freq();
if (drawn_hexes_ != invalidated_hexes_)
stream << " ("
<< (invalidated_hexes_ - drawn_hexes_) * 1.0
/ fps_.get_sample_freq() << ")";
}
clear_fps_label();
font::floating_label flabel(stream.str());
flabel.set_font_size(12);
flabel.set_color(benchmark ? font::BAD_COLOR : font::NORMAL_COLOR);
flabel.set_position(10, 100);
flabel.set_alignment(font::LEFT_ALIGN);
fps_handle_ = font::add_floating_label(flabel);
}

void display::update_display()
Expand All @@ -1442,47 +1460,15 @@ void display::update_display()
}

if(preferences::show_fps() || benchmark) {
static int last_sample = SDL_GetTicks();
static int frames = 0;
++frames;
const int sample_freq = 10;
if(frames == sample_freq) {
const int this_sample = SDL_GetTicks();

const int fps = (frames*1000)/(this_sample - last_sample);
last_sample = this_sample;
frames = 0;

if(fps_handle_ != 0) {
font::remove_floating_label(fps_handle_);
fps_handle_ = 0;
}
std::ostringstream stream;
stream << "fps: " << fps;
if (game_config::debug) {
stream << "\nhex: " << drawn_hexes_*1.0/sample_freq;
if (drawn_hexes_ != invalidated_hexes_)
stream << " (" << (invalidated_hexes_-drawn_hexes_)*1.0/sample_freq << ")";
}
drawn_hexes_ = 0;
invalidated_hexes_ = 0;

font::floating_label flabel(stream.str());
flabel.set_font_size(12);
flabel.set_color(benchmark ? font::BAD_COLOR : font::NORMAL_COLOR);
flabel.set_position(10, 100);
flabel.set_alignment(font::LEFT_ALIGN);

fps_handle_ = font::add_floating_label(flabel);
if(fps_.get_frames_sampled() == 0) {
make_fps_label();
}
} else if(fps_handle_ != 0) {
font::remove_floating_label(fps_handle_);
fps_handle_ = 0;
drawn_hexes_ = 0;
invalidated_hexes_ = 0;
clear_fps_label();
}

flip();

}
#ifdef SDL_GPU
static void draw_panel(surface &target, const theme::panel& panel, std::vector<gui::button>& /*buttons*/)
Expand Down Expand Up @@ -1860,9 +1846,10 @@ void display::draw_init()

void display::draw_wrap(bool update, bool force)
{
static const int time_between_draws = preferences::draw_delay();
const int current_time = SDL_GetTicks();
const int wait_time = nextDraw_ - current_time;
//static const int time_between_draws = preferences::draw_delay();
//const int current_time = SDL_GetTicks();
//const int wait_time = nextDraw_ - current_time;
UNUSED(force);

if(redrawMinimap_) {
redrawMinimap_ = false;
Expand All @@ -1871,13 +1858,13 @@ void display::draw_wrap(bool update, bool force)

if(update) {
update_display();
if(!force && !benchmark && wait_time > 0) {
//if(!force && !benchmark && wait_time > 0) {
// If it's not time yet to draw, delay until it is
SDL_Delay(wait_time);
}
//SDL_Delay(wait_time);
//}

// Set the theoretical next draw time
nextDraw_ += time_between_draws;
//nextDraw_ += time_between_draws;

// If the next draw already should have been finished,
// we'll enter an update frenzy, so make sure that the
Expand Down Expand Up @@ -2702,6 +2689,17 @@ void display::draw(bool update) {
draw(update, false);
}

void display::pre_draw() {
// Trigger cache rebuild when preference gets changed
if (animate_water_ != preferences::animate_water()) {
animate_water_ = preferences::animate_water();
builder_->rebuild_cache_all();
}

set_scontext_unsynced leave_synced_context;

draw_init();
}

void display::draw(bool update,bool force) {
// log_scope("display::draw");
Expand All @@ -2716,16 +2714,9 @@ void display::draw(bool update,bool force) {
return;
}

// Trigger cache rebuild when preference gets changed
if (animate_water_ != preferences::animate_water()) {
animate_water_ = preferences::animate_water();
builder_->rebuild_cache_all();
}

set_scontext_unsynced leave_synced_context;
surface& frameBuffer = get_video_surface();

draw_init();
pre_draw();
// invalidate all that needs to be invalidated
invalidate_animations();
// at this stage we have everything that needs to be invalidated for this redraw
Expand Down Expand Up @@ -2758,7 +2749,26 @@ void display::draw(bool update,bool force) {
//SDL_Delay(2*simulate_delay + rand() % 20);
}
draw_wrap(update, force);
post_draw();

// This is just the debug function "sunset" to progressively darken the map area
static size_t sunset_timer = 0;
if (sunset_delay && ++sunset_timer > sunset_delay) {
sunset_timer = 0;
SDL_Rect r = map_outside_area(); // Use frameBuffer to also test the UI
const Uint32 color = SDL_MapRGBA(video().getSurface()->format,0,0,0,SDL_ALPHA_OPAQUE);
// Adjust the alpha if you want to balance cpu-cost / smooth sunset
sdl::fill_rect_alpha(r, color, 1, frameBuffer);
update_rect(r);
}

#ifdef SDL_GPU
font::draw_floating_labels(screen_);
#else
font::draw_floating_labels(frameBuffer);
#endif
events::raise_volatile_draw_event();


}

map_labels& display::labels()
Expand Down Expand Up @@ -3782,9 +3792,25 @@ void display::handle_window_event(const SDL_Event& event) {
}

void display::handle_event(const SDL_Event& event) {
if (event.type == DRAW_ALL_EVENT) {

switch(event.type) {
case PRE_DRAW_EVENT:
pre_draw();
break;
case DRAW_EVENT:
draw();
break;
case POST_DRAW_EVENT:
post_draw();
break;
case DRAW_ALL_EVENT:
pre_draw();
draw();
post_draw();
default:
break;
}

}

display *display::singleton_ = NULL;
Expand Down
19 changes: 15 additions & 4 deletions src/display.hpp
Expand Up @@ -72,6 +72,8 @@ namespace wb {
#include <list>
#include <map>

#include "fpscounter.hpp"

class gamemap;

class display : public filter_context, public video2::draw_layering
Expand Down Expand Up @@ -595,17 +597,21 @@ class display : public filter_context, public video2::draw_layering
/** Checks if location @a loc or one of the adjacent tiles is visible on screen. */
bool tile_nearly_on_screen(const map_location &loc) const;

virtual void pre_draw();

virtual void draw();

virtual void post_draw();

void draw(bool update);

/**
* Draws invalidated items.
* If update is true, will also copy the display to the frame buffer.
* If force is true, will not skip frames, even if running behind.
* Not virtual, since it gathers common actions. Calls various protected
* virtuals (further below) to allow specialized behavior in derived classes.
*/
virtual void draw();

void draw(bool update);

void draw(bool update, bool force);

map_labels& labels();
Expand Down Expand Up @@ -775,6 +781,8 @@ class display : public filter_context, public video2::draw_layering
boost::scoped_ptr<map_labels> map_labels_;
reports * reports_object_;

fps_counter fps_;

/** Event raised when the map is being scrolled */
mutable events::generic_event scroll_event_;

Expand Down Expand Up @@ -836,6 +844,9 @@ class display : public filter_context, public video2::draw_layering
surface get_flag(const map_location& loc);
#endif

void clear_fps_label();
void make_fps_label();

/** Animated flags for each team */
std::vector<animated<image::locator> > flags_;

Expand Down
4 changes: 0 additions & 4 deletions src/editor/editor_display.cpp
Expand Up @@ -93,10 +93,6 @@ void editor_display::rebuild_terrain(const map_location &loc) {
builder_->rebuild_terrain(loc);
}

void editor_display::pre_draw()
{
}

image::TYPE editor_display::get_image_type(const map_location& loc)
{
if (map().in_selection(loc)) {
Expand Down
2 changes: 1 addition & 1 deletion src/editor/editor_display.hpp
Expand Up @@ -41,7 +41,7 @@ class editor_display : public display
void set_palette_report(const config& palette_report) {palette_report_ = palette_report;}

protected:
void pre_draw();

/**
* The editor uses different rules for terrain highlighting (e.g. selections)
*/
Expand Down
20 changes: 17 additions & 3 deletions src/events.cpp
Expand Up @@ -316,7 +316,8 @@ SDL_Event last_resize_event;
bool last_resize_event_used = true;

static bool remove_on_resize(const SDL_Event &a) {
if (a.type == DRAW_EVENT || a.type == DRAW_ALL_EVENT) {
if (a.type == PRE_DRAW_EVENT || a.type == DRAW_EVENT ||
a.type == POST_DRAW_EVENT || a.type == DRAW_ALL_EVENT) {
return true;
}
if (a.type == SHOW_HELPTIP_EVENT) {
Expand Down Expand Up @@ -357,15 +358,28 @@ static Uint32 draw_timer(Uint32, void*)
SDL_Event event;
SDL_UserEvent data;

data.type = DRAW_EVENT;
data.type = PRE_DRAW_EVENT;
data.code = 0;
data.data1 = NULL;
data.data2 = NULL;

event.type = DRAW_EVENT;
event.type = PRE_DRAW_EVENT;
event.user = data;

SDL_FlushEvent(DRAW_EVENT);
SDL_FlushEvent(PRE_DRAW_EVENT);
SDL_FlushEvent(POST_DRAW_EVENT);

SDL_PushEvent(&event);

data.type = DRAW_EVENT;
event.type = DRAW_EVENT;
SDL_PushEvent(&event);

data.type = POST_DRAW_EVENT;
event.type = POST_DRAW_EVENT;
SDL_PushEvent(&event);

return draw_interval;
}

Expand Down

0 comments on commit ae16c90

Please sign in to comment.