Add parallel analysis of unit invalidation using OpenMP.

This is ifdefed out by default, mail to wesnoth-dev to follow shortly
This commit is contained in:
Jérémy Rosen 2011-02-28 20:37:38 +00:00
parent 2e5c727b87
commit 6edcc85bc3
7 changed files with 112 additions and 56 deletions

View file

@ -64,6 +64,7 @@ Version 1.9.4+svn:
* Fixed a replay OOS issue caused by ToD areas defined outside of events
(bug #17783).
* Changed: when loading a file fails to open try with a .gz file.
* Unit invalidation is processed in parallel using OpenMP
Version 1.9.4:
* AI:

View file

@ -2416,6 +2416,9 @@ void display::invalidate_all()
{
DBG_DP << "invalidate_all()\n";
invalidateAll_ = true;
#ifdef _OPENMP
#pragma omp critical(invalidated_)
#endif //_OPENMP
invalidated_.clear();
update_rect(map_area());
}
@ -2425,7 +2428,12 @@ bool display::invalidate(const map_location& loc)
if(invalidateAll_)
return false;
return invalidated_.insert(loc).second;
bool tmp;
#ifdef _OPENMP
#pragma omp critical(invalidated_)
#endif //_OPENMP
tmp = invalidated_.insert(loc).second;
return tmp;
}
bool display::invalidate(const std::set<map_location>& locs)
@ -2434,6 +2442,9 @@ bool display::invalidate(const std::set<map_location>& locs)
return false;
bool ret = false;
foreach (const map_location& loc, locs) {
#ifdef _OPENMP
#pragma omp critical(invalidated_)
#endif //_OPENMP
ret = invalidated_.insert(loc).second || ret;
}
return ret;
@ -2447,19 +2458,26 @@ bool display::propagate_invalidation(const std::set<map_location>& locs)
if(locs.size()<=1)
return false; // propagation never needed
// search the first hex invalidated (if any)
std::set<map_location>::const_iterator i = locs.begin();
for(; i != locs.end() && invalidated_.count(*i) == 0 ; ++i) {}
bool result = false;
#ifdef _OPENMP
#pragma omp critical(invalidated_)
#endif //_OPENMP
{
// search the first hex invalidated (if any)
std::set<map_location>::const_iterator i = locs.begin();
for(; i != locs.end() && invalidated_.count(*i) == 0 ; ++i) {}
if (i == locs.end())
return false; // no invalidation, don't propagate
if (i != locs.end()) {
// propagate invalidation
// 'i' is already in, but I suspect that splitting the range is bad
// especially because locs are often adjacents
size_t previous_size = invalidated_.size();
invalidated_.insert(locs.begin(), locs.end());
return previous_size < invalidated_.size();
// propagate invalidation
// 'i' is already in, but I suspect that splitting the range is bad
// especially because locs are often adjacents
size_t previous_size = invalidated_.size();
invalidated_.insert(locs.begin(), locs.end());
result = previous_size < invalidated_.size();
}
}
return result;
}
bool display::invalidate_visible_locations_in_rect(const SDL_Rect& rect)

View file

@ -297,14 +297,6 @@ public:
*/
virtual void invalidate_animations_location(const map_location& /*loc*/) {}
/**
* What hex are currently invalidated (read only)
* used for some fine grained invalidation algorithm which need recurstion
*/
const std::set<map_location> & get_invalidated() const { return invalidated_; }
const gamemap& get_map() const { return *map_; }
/**

View file

@ -905,16 +905,23 @@ void game_display::invalidate_animations()
foreach(unit* temp_unit, temp_units_) {
temp_unit->refresh();
}
bool new_inval = true;
while(new_inval) {
new_inval = false;
foreach (unit& u, units_) {
new_inval |= u.invalidate(u.get_location());
}
foreach(unit* temp_unit, temp_units_) {
new_inval |= temp_unit->invalidate(temp_unit->get_location());
}
std::vector<unit*> unit_list;
foreach (unit &u, units_) {
unit_list.push_back(&u);
}
foreach (unit *u, temp_units_) {
unit_list.push_back(u);
}
bool new_inval;
do {
new_inval = false;
#ifdef _OPENMP
#pragma omp parallel for reduction(|:new_inval) shared(unit_list) schedule(guided)
#endif //_OPENMP
for(unsigned int i=0; i < unit_list.size(); i++) {
new_inval |= unit_list[i]->invalidate(unit_list[i]->get_location());
}
}while(new_inval);
}
int& game_display::debug_highlight(const map_location& loc)

View file

@ -146,19 +146,24 @@ static int last_index_ = 0;
void flush_cache()
{
images_.flush();
hexed_images_.flush();
tod_colored_images_.flush();
scaled_to_zoom_.flush();
scaled_to_hex_images_.flush();
brightened_images_.flush();
semi_brightened_images_.flush();
in_hex_info_.flush();
mini_terrain_cache.clear();
mini_fogged_terrain_cache.clear();
reversed_images_.clear();
image_existence_map.clear();
precached_dirs.clear();
#ifdef _OPENMP
#pragma omp critical(image_cache)
#endif //_OPENMP
{
images_.flush();
hexed_images_.flush();
tod_colored_images_.flush();
scaled_to_zoom_.flush();
scaled_to_hex_images_.flush();
brightened_images_.flush();
semi_brightened_images_.flush();
in_hex_info_.flush();
mini_terrain_cache.clear();
mini_fogged_terrain_cache.clear();
reversed_images_.clear();
image_existence_map.clear();
precached_dirs.clear();
}
/* We can't reset last_index_, since some locators are still alive
when using :refresh. That would cause them to point to the wrong
images. Not resetting the variable causes a memory leak, though. */
@ -1080,8 +1085,20 @@ surface get_image(const image::locator& i_locator, TYPE type)
}
// return the image if already cached
if(i_locator.in_cache(*imap))
return i_locator.locate_in_cache(*imap);
bool tmp;
#ifdef _OPENMP
#pragma omp critical(image_cache)
#endif //_OPENMP
tmp=i_locator.in_cache(*imap);
if(tmp) {
surface result;
#ifdef _OPENMP
#pragma omp critical(image_cache)
#endif //_OPENMP
result = i_locator.locate_in_cache(*imap);
return result;
}
// not cached, generate it
switch(type) {
@ -1115,6 +1132,9 @@ surface get_image(const image::locator& i_locator, TYPE type)
if(res)
res = create_optimized_surface(res);
#ifdef _OPENMP
#pragma omp critical(image_cache)
#endif //_OPENMP
i_locator.add_to_cache(*imap, res);
return res;
@ -1128,8 +1148,13 @@ surface get_hexmask()
bool is_in_hex(const locator& i_locator)
{
bool result;
#ifdef _OPENMP
#pragma omp critical(in_hex_info_)
#endif //_OPENMP
{
if(i_locator.in_cache(in_hex_info_)) {
return i_locator.locate_in_cache(in_hex_info_);
result= i_locator.locate_in_cache(in_hex_info_);
} else {
const surface image(get_image(i_locator, UNSCALED));
@ -1140,8 +1165,10 @@ bool is_in_hex(const locator& i_locator)
//std::cout << "in_hex : " << i_locator.get_filename()
// << " " << (res ? "yes" : "no") << "\n";
return res;
result= res;
}
}
return result;
}

View file

@ -1996,7 +1996,7 @@ bool unit::invalidate(const map_location &loc)
// Very early calls, anim not initialized yet
if(get_animation()) {
frame_parameters params;
game_display * disp = game_display::get_singleton();
const game_display * disp = game_display::get_singleton();
const gamemap & map = disp->get_map();
const t_translation::t_terrain terrain = map.get_terrain(loc);
const terrain_type& terrain_info = map.get_terrain_info(terrain);

View file

@ -663,13 +663,24 @@ std::set<map_location> unit_frame::get_overlaped_hex(const int frame_time,const
result.insert(src.get_direction(map_location::SOUTH_WEST));
}
} else {
surface image;
if(!image_loc.is_void() && image_loc.get_filename() != "") { // invalid diag image, or not diagonal
image=image::get_image(image_loc,
image::SCALED_TO_ZOOM
);
int w=0;
int h =0;
#ifdef _OPENMP
#pragma omp critical(frame_surface) // with the way surfaces work it's hard to lock the refcount within sdl_utils
#endif //_OPENMP
{
surface image;
if(!image_loc.is_void() && image_loc.get_filename() != "") { // invalid diag image, or not diagonal
image=image::get_image(image_loc,
image::SCALED_TO_ZOOM
);
}
if(image != NULL) {
w = image->w;
h = image->h;
}
}
if (image != NULL) {
if (w != 0 || h != 0) {
const int x = static_cast<int>(tmp_offset * xdst + (1.0-tmp_offset) * xsrc);
const int y = static_cast<int>(tmp_offset * ydst + (1.0-tmp_offset) * ysrc);
#ifdef LOW_MEM
@ -680,8 +691,8 @@ std::set<map_location> unit_frame::get_overlaped_hex(const int frame_time,const
bool facing_north = direction == map_location::NORTH_WEST || direction == map_location::NORTH || direction == map_location::NORTH_EAST;
if(!current_data.auto_vflip) facing_north = true;
if(!current_data.auto_hflip) facing_west = false;
int my_x = x +current_data.x+d2- image->w/2;
int my_y = y +current_data.y+d2- image->h/2;
int my_x = x +current_data.x+d2- w/2;
int my_y = y +current_data.y+d2- h/2;
if(facing_west) {
my_x += current_data.directional_x;
} else {
@ -693,7 +704,7 @@ std::set<map_location> unit_frame::get_overlaped_hex(const int frame_time,const
my_y -= current_data.directional_y;
}
const SDL_Rect r = create_rect(my_x, my_y, image->w, image->h);
const SDL_Rect r = create_rect(my_x, my_y, w, h);
// check if our underlying hexes are invalidated
// if we need to update ourselve because we changed, invalidate our hexes
// and return whether or not our hexs was invalidated