Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit29caaad

Browse files
committed
RenderDevice: Add support for multi-threaded image loading
For this initial commit, we are using it where it has the most impact,the animation system. Results may vary, but I got about a 2.5x speedupin opening GameStateLoad with several saves from flare-game with the newHD art assets.The usage is fairly simple: push images to load withRenderDevice::pushQueuedImage() and then callRenderDevice::loadQueuedImages() when ready to actually load them.In case this causes problems, I've added an option to the usersettings.txt to disable it.
1 parentfa6f635 commit29caaad

18 files changed

+270
-36
lines changed

‎src/Animation.cpp‎

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ FLARE. If not, see http://www.gnu.org/licenses/
3232
#include"RenderDevice.h"
3333

3434
Animation::Animation(const std::string &_name,const std::string &_type, AnimationMedia *_sprite,uint8_t _blend_mode,uint8_t _alpha_mod, Color _color_mod)
35-
: reverse_playback(false)
35+
: init(false)
36+
, reverse_playback(false)
3637
, active_frame_triggered(false)
3738
, type(_type =="play_once" ? ANIMTYPE_PLAY_ONCE :
3839
_type =="back_forth" ? ANIMTYPE_BACK_FORTH :
@@ -41,6 +42,7 @@ Animation::Animation(const std::string &_name, const std::string &_type, Animati
4142
, active_sub_frame(ACTIVE_SUBFRAME_END)
4243
, blend_mode(_blend_mode)
4344
, alpha_mod(_alpha_mod)
45+
, format(ANIMATION_COMPRESSED)
4446
, total_frame_count(0)
4547
, cur_frame(0)
4648
, sub_frame(0)
@@ -52,6 +54,8 @@ Animation::Animation(const std::string &_name, const std::string &_type, Animati
5254
, sprite(_sprite)
5355
, gfx()
5456
, render_offset()
57+
, keys()
58+
, dirs()
5559
, active_frames()
5660
, sub_frames()
5761
, name(_name)
@@ -68,24 +72,18 @@ void Animation::setupUncompressed(const Point& _render_size, const Point& _rende
6872
for (unsignedshort dir =0 ; dir < DIRECTIONS; dir++) {
6973
// TODO handle multiple images for uncompressed animation defintions
7074
unsigned f = base_index + dir;
71-
gfx[f].first = sprite->getImageFromKey("");
7275
gfx[f].second.x = _render_size.x * (_position + i);
7376
gfx[f].second.y = _render_size.y * dir;
7477
gfx[f].second.w = _render_size.x;
7578
gfx[f].second.h = _render_size.y;
7679
render_offset[f].x = _render_offset.x;
7780
render_offset[f].y = _render_offset.y;
78-
79-
// not all animations have multiple directions, but we need to handle when attempting to render an animation from any direction
80-
// we can try to use the rect data from the 0 direction
81-
// to determine if we should do so, we check if the bottom-right corner of a rect is out-of-bounds of the image
82-
if (dir >0 && gfx[f].first) {
83-
if (gfx[f].second.x + gfx[f].second.w > gfx[f].first->getWidth() || gfx[f].second.y + gfx[f].second.h > gfx[f].first->getHeight()) {
84-
gfx[f].second = gfx[base_index].second;
85-
}
86-
}
81+
keys[f] ="";
82+
dirs[f] = dir;
8783
}
8884
}
85+
86+
format = ANIMATION_UNCOMPRESSED;
8987
}
9088

9189
voidAnimation::setup(unsignedshort _frames,unsignedshort _duration) {
@@ -150,6 +148,8 @@ void Animation::setup(unsigned short _frames, unsigned short _duration) {
150148
unsigned i = DIRECTIONS * _frames;
151149
gfx.resize(i);
152150
render_offset.resize(i);
151+
keys.resize(i);
152+
dirs.resize(i);
153153
}
154154

155155
boolAnimation::addFrame(unsignedshort index,unsignedshort direction,const Rect& rect,const Point& _render_offset,const std::string& key) {
@@ -158,22 +158,11 @@ bool Animation::addFrame(unsigned short index, unsigned short direction, const R
158158
}
159159

160160
unsigned i = (DIRECTIONS * index) + direction;
161-
gfx[i].first = sprite->getImageFromKey(key);
162161
gfx[i].second = rect;
163162
render_offset[i] = _render_offset;
164-
165-
// not all animations have multiple directions, but we need to handle when attempting to render an animation from any direction
166-
// we can try to use the rect data from the 0 direction
167-
if (direction ==0 && gfx[i].first) {
168-
for (unsignedshort dir =1; dir < DIRECTIONS; ++dir) {
169-
unsigned f = (DIRECTIONS * index) + dir;
170-
if (!gfx[f].first) {
171-
gfx[f].first = gfx[i].first;
172-
gfx[f].second = gfx[i].second;
173-
render_offset[f] = render_offset[i];
174-
}
175-
}
176-
}
163+
keys[i] = key;
164+
dirs[i] = direction;
165+
format = ANIMATION_COMPRESSED;
177166

178167
returntrue;
179168
}
@@ -248,6 +237,9 @@ Renderable Animation::getCurrentFrame(unsigned short direction) {
248237
Renderable r;
249238
if (!sub_frames.empty()) {
250239
constunsignedshort index =static_cast<unsignedshort>(DIRECTIONS * sub_frames[sub_frame]) + direction;
240+
241+
checkInit();
242+
251243
r.src.x = gfx[index].second.x;
252244
r.src.y = gfx[index].second.y;
253245
r.src.w = gfx[index].second.w;
@@ -434,3 +426,45 @@ unsigned short Animation::getLastSubFrame(const short &frame) {
434426
voidAnimation::setSpeed(float val) {
435427
speed = val /100.0f;
436428
}
429+
430+
voidAnimation::checkInit() {
431+
if (!init) {
432+
for (unsignedshort i =0 ; i < frame_count; i++) {
433+
int base_index = DIRECTIONS * i;
434+
for (unsignedshort dir =0 ; dir < DIRECTIONS; dir++) {
435+
unsigned f = base_index + dir;
436+
437+
if (format == ANIMATION_COMPRESSED) {
438+
gfx[f].first = sprite->getImageFromKey(keys[f]);
439+
440+
// not all animations have multiple directions, but we need to handle when attempting to render an animation from any direction
441+
// we can try to use the rect data from the 0 direction
442+
if (dir ==0 && gfx[f].first) {
443+
for (unsignedshort test_dir =1; test_dir < DIRECTIONS; ++test_dir) {
444+
unsigned test_index = (DIRECTIONS * i) + test_dir;
445+
if (dirs[test_index] ==0) {
446+
gfx[test_index].first = gfx[f].first;
447+
gfx[test_index].second = gfx[f].second;
448+
render_offset[test_index] = render_offset[f];
449+
}
450+
}
451+
}
452+
}
453+
elseif (format == ANIMATION_UNCOMPRESSED) {
454+
gfx[f].first = sprite->getImageFromKey("");
455+
456+
// not all animations have multiple directions, but we need to handle when attempting to render an animation from any direction
457+
// we can try to use the rect data from the 0 direction
458+
// to determine if we should do so, we check if the bottom-right corner of a rect is out-of-bounds of the image
459+
if (dir >0 && gfx[f].first) {
460+
if (gfx[f].second.x + gfx[f].second.w > gfx[f].first->getWidth() || gfx[f].second.y + gfx[f].second.h > gfx[f].first->getHeight()) {
461+
gfx[f].second = gfx[base_index].second;
462+
}
463+
}
464+
}
465+
}
466+
}
467+
468+
init =true;
469+
}
470+
}

‎src/Animation.h‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,21 @@ class Animation {
5555
ACTIVE_SUBFRAME_ALL =2,
5656
};
5757

58+
enum {
59+
ANIMATION_COMPRESSED =0,
60+
ANIMATION_UNCOMPRESSED
61+
};
62+
63+
bool init;// image loading is deferred, so this flag is used to do some setup when calling getCurrentFrame() for the first time
64+
5865
bool reverse_playback;// only for type == BACK_FORTH
5966
bool active_frame_triggered;
6067

6168
constuint8_t type;// see ANIMTYPE enum above
6269
uint8_t active_sub_frame;
6370
uint8_t blend_mode;
6471
uint8_t alpha_mod;
72+
uint8_t format;
6573

6674
unsignedshort total_frame_count;// the total number of frames for this animation (is different from frame_count for back/forth animations)
6775
unsignedshort cur_frame;// counts up until reaching total_frame_count.
@@ -79,6 +87,8 @@ class Animation {
7987

8088
std::vector<std::pair<Image*, Rect> > gfx;// graphics for each frame taken from the spritesheet
8189
std::vector<Point> render_offset;// "virtual point on the floor"
90+
std::vector<std::string> keys;
91+
std::vector<unsignedshort> dirs;
8292
std::vector<short> active_frames;// frames that are marked as "active". Active frames are used to trigger various states (i.e power activation or hazard danger)
8393
std::vector<unsignedshort> sub_frames;// a list of frames to play on each tick
8494

@@ -142,6 +152,8 @@ class Animation {
142152
unsignedgetFrameCount() {return frame_count; }
143153

144154
voidsetSpeed(float val);
155+
156+
voidcheckInit();
145157
};
146158

147159
#endif

‎src/AnimationManager.cpp‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with
1616
FLARE. If not, see http://www.gnu.org/licenses/
1717
*/
1818

19+
#include"Animation.h"
1920
#include"AnimationManager.h"
2021
#include"AnimationSet.h"
2122
#include"CommonIncludes.h"
@@ -24,6 +25,7 @@ FLARE. If not, see http://www.gnu.org/licenses/
2425
#include"SharedResources.h"
2526

2627
#include<cassert>
28+
#include<vector>
2729

2830
AnimationSet *AnimationManager::getAnimationSet(const std::string& filename) {
2931
std::vector<std::string>::iterator found =find(names.begin(), names.end(), filename);
@@ -99,3 +101,11 @@ void AnimationManager::cleanUp() {
99101
--i;
100102
}
101103
}
104+
105+
voidAnimationManager::checkAnimationsInit() {
106+
for (size_t i =0; i < sets.size(); ++i) {
107+
for (size_t j =0; j < sets[i]->animations.size(); ++j) {
108+
sets[i]->animations[j]->checkInit();
109+
}
110+
}
111+
}

‎src/AnimationManager.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class AnimationManager {
4141
voiddecreaseCount(const std::string &name);
4242
voidincreaseCount(const std::string &name);
4343
voidcleanUp();
44+
45+
voidcheckAnimationsInit();
4446
};
4547

4648
#endif// __ANIMATION_MANAGER__

‎src/AnimationMedia.cpp‎

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,36 +21,46 @@ FLARE. If not, see http://www.gnu.org/licenses/
2121
#include"SharedResources.h"
2222

2323
AnimationMedia::AnimationMedia()
24-
: first_key("") {
24+
: first_key("")
25+
, first_path("") {
2526
}
2627

2728
AnimationMedia::~AnimationMedia() {
2829
}
2930

3031
voidAnimationMedia::loadImage(const std::string& path,const std::string& key) {
31-
Image* loaded_img = render_device->loadImage(path, RenderDevice::ERROR_NORMAL);
32-
if (!loaded_img)
33-
return;
32+
render_device->pushQueuedImage(path, RenderDevice::ERROR_NORMAL);
3433

3534
if (sprites.find(key) == sprites.end()) {
36-
sprites[key] = loaded_img;
35+
sprites[key] =NULL;
36+
paths[key] = path;
3737
}
3838
else {
39-
sprites[key]->unref();
40-
sprites[key] = loaded_img;
39+
if (sprites[key] !=NULL)
40+
sprites[key]->unref();
41+
42+
sprites[key] =NULL;
43+
paths[key] = path;
4144
}
4245

4346
if (sprites.size() ==1) {
4447
first_key = key;
48+
first_path = path;
4549
}
4650
}
4751

4852
Image*AnimationMedia::getImageFromKey(const std::string& key) {
4953
std::map<std::string, Image*>::iterator it = sprites.find(key);
5054
if (it != sprites.end()) {
55+
if (it->second ==NULL) {
56+
it->second = render_device->loadImage(paths[key], RenderDevice::ERROR_NORMAL);
57+
}
5158
return it->second;
5259
}
5360
elseif (!sprites.empty()) {
61+
if (sprites[first_key] ==NULL) {
62+
sprites[first_key] = render_device->loadImage(first_path, RenderDevice::ERROR_NORMAL);
63+
}
5464
return sprites[first_key];
5565
}
5666

‎src/AnimationMedia.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ FLARE. If not, see http://www.gnu.org/licenses/
2424
classAnimationMedia {
2525
private:
2626
std::map<std::string, Image*> sprites;
27+
std::map<std::string, std::string> paths;
2728
std::string first_key;
29+
std::string first_path;
2830

2931
public:
3032
AnimationMedia();

‎src/GameState.cpp‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ GameState& GameState::operator=(const GameState& other) {
6262
}
6363

6464
GameState::~GameState() {
65+
render_device->cleanupQueuedImages();
66+
6567
if (loading_tip)
6668
delete loading_tip;
6769
}

‎src/GameStatePlay.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ void GameStatePlay::checkTeleport() {
331331
inpt->lock_all = (teleport_mapname =="maps/spawn.txt");
332332
mapr->executeOnMapExitEvents();
333333
showLoading();
334+
render_device->cleanupQueuedImages();
334335
save_load->saveFOW();// TODO handle save_onload/save_onexit?
335336
mapr->load(teleport_mapname);
336337
setLoadingFrame();

‎src/GameSwitcher.cpp‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ FLARE. If not, see http://www.gnu.org/licenses/
3232
* - maybe full-video cutscenes
3333
*/
3434

35+
#include"AnimationManager.h"
3536
#include"CursorManager.h"
3637
#include"FileParser.h"
3738
#include"FontEngine.h"
@@ -279,6 +280,11 @@ bool GameSwitcher::isPaused() {
279280
}
280281

281282
voidGameSwitcher::render() {
283+
render_device->loadQueuedImages();
284+
285+
if (anim)
286+
anim->checkAnimationsInit();
287+
282288
// display background
283289
if (background && currentState->has_background) {
284290
render_device->render(background);

‎src/RenderDevice.cpp‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,3 +435,35 @@ unsigned short RenderDevice::getRefreshRate() {
435435
Utils::logInfo("RenderDevice: getRefreshRate() not implemented");
436436
return0;
437437
}
438+
439+
voidRenderDevice::pushQueuedImage(const std::string& filename,int error_type) {
440+
if (!settings->enable_threaded_image_load)
441+
return;
442+
443+
Image* cache_test =cacheLookup(filename);
444+
if (cache_test) {
445+
// image already in cache. We need to decrease the ref count because the lookup would have increased it
446+
cache_test->unref();
447+
return;
448+
}
449+
450+
for (size_t i =0; i < image_queue.size(); ++i) {
451+
if (image_queue[i].filename == filename) {
452+
// image already in queue
453+
return;
454+
}
455+
}
456+
457+
QueuedImage queued_image;
458+
queued_image.filename = filename;
459+
queued_image.error_type = error_type;
460+
461+
image_queue.push_back(queued_image);
462+
}
463+
464+
voidRenderDevice::cleanupQueuedImages() {
465+
for (size_t i =0; i < image_queue_cleanup.size(); ++i) {
466+
image_queue_cleanup[i]->unref();
467+
}
468+
image_queue_cleanup.clear();
469+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp