Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Added threaded image loading sample
- Loading branch information
Benjamin Bojko
committed
Jan 12, 2017
1 parent
45c23e5
commit 3376bf4
Showing
17 changed files
with
1,014 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#pragma once | ||
#include "cinder/CinderResources.h" | ||
|
||
//#define RES_MY_RES CINDER_RESOURCE( ../resources/, image_name.png, 128, IMAGE ) | ||
|
||
|
||
|
||
|
||
|
Binary file not shown.
Binary file not shown.
130 changes: 130 additions & 0 deletions
130
samples/ThreadedImageLoadingSample/src/ThreadedImageLoader.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
|
||
#include "ThreadedImageLoader.h" | ||
|
||
#include "cinder/Filesystem.h" | ||
#include "cinder/imageIo.h" | ||
|
||
using namespace ci; | ||
using namespace ci::app; | ||
using namespace std; | ||
|
||
namespace bluecadet { | ||
namespace utils { | ||
|
||
ThreadedImageLoader::ThreadedImageLoader(const unsigned int numThreads) { | ||
mTasks.setup(numThreads); | ||
} | ||
|
||
ThreadedImageLoader::~ThreadedImageLoader() { | ||
|
||
} | ||
|
||
void ThreadedImageLoader::load(const std::string path, Callback callback) { | ||
// check texture cache | ||
auto texIt = mTextureCache.find(path); | ||
if (texIt != mTextureCache.end()) { | ||
callback(path, texIt->second); | ||
return; | ||
} | ||
|
||
// check existing load tasks/callbacks | ||
lock_guard<mutex> lock(mCallbackMutex); | ||
auto cbIt = mCallbacks.find(path); | ||
if (cbIt != mCallbacks.end()) { | ||
mCallbacks[path].push_back(callback); | ||
return; | ||
} | ||
|
||
// load file and add callback | ||
mCallbacks[path].push_back(callback); | ||
|
||
mTasks.addTask([=] () { | ||
// worker thread | ||
auto data = loadFile(path); | ||
createSurface(path, data); | ||
|
||
App::get()->dispatchAsync([=]{ | ||
// main thread | ||
createTexture(path); // this could be offloaded to a timed queue for additional optimization | ||
triggerCallbacks(path); | ||
}); | ||
}); | ||
} | ||
|
||
void ThreadedImageLoader::cancel(const std::string path) { | ||
triggerCallbacks(path); | ||
} | ||
|
||
bool ThreadedImageLoader::hasTexture(const std::string path) const { | ||
return mTextureCache.find(path) != mTextureCache.end(); | ||
} | ||
|
||
const ci::gl::TextureRef ThreadedImageLoader::getTexture(const std::string path) const { | ||
auto it = mTextureCache.find(path); | ||
if (it == mTextureCache.end()) { | ||
return nullptr; | ||
} | ||
return it->second; | ||
} | ||
|
||
bool ThreadedImageLoader::isLoading(const std::string path) { | ||
lock_guard<mutex> lock(mCallbackMutex); | ||
auto cbIt = mCallbacks.find(path); | ||
return cbIt != mCallbacks.end(); | ||
} | ||
|
||
void ThreadedImageLoader::triggerCallbacks(const std::string path) { | ||
lock_guard<mutex> lock(mCallbackMutex); | ||
auto cbIt = mCallbacks.find(path); | ||
if (cbIt != mCallbacks.end()) { | ||
|
||
// try to get texture | ||
gl::TextureRef tex = nullptr; | ||
auto texIt = mTextureCache.find(path); | ||
if (texIt != mTextureCache.end()) { | ||
tex = texIt->second; | ||
} | ||
|
||
// trigger callbacks w texture or nullptr | ||
for (auto callback : cbIt->second) { | ||
callback(path, tex); | ||
} | ||
|
||
// clear callbacks for this path | ||
mCallbacks.erase(cbIt); | ||
} | ||
} | ||
|
||
ci::ImageSourceRef ThreadedImageLoader::loadFile(const std::string path) { | ||
return ci::loadImage(path); | ||
} | ||
|
||
void ThreadedImageLoader::createSurface(const std::string path, const ci::ImageSourceRef source) { | ||
lock_guard<mutex> lock(mSurfaceMutex); | ||
// create surface and store on cpu memory | ||
mSurfaceCache[path] = Surface::create(source); | ||
} | ||
|
||
void ThreadedImageLoader::createTexture(const std::string path) { | ||
ci::SurfaceRef surface = nullptr; | ||
|
||
{ | ||
lock_guard<mutex> lock(mSurfaceMutex); | ||
auto surfIt = mSurfaceCache.find(path); | ||
if (surfIt == mSurfaceCache.end()) { | ||
return; | ||
} | ||
|
||
// save surface locally so the mutex doesn't get locked for too long | ||
surface = surfIt->second; | ||
|
||
// remove surface from cache when done | ||
mSurfaceCache.erase(surfIt); | ||
} | ||
|
||
// create texture and store data on gpu memory | ||
mTextureCache[path] = gl::Texture::create(*surface); | ||
} | ||
|
||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
samples/ThreadedImageLoadingSample/src/ThreadedImageLoader.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
#pragma once | ||
|
||
#include "cinder/app/App.h" | ||
#include "cinder/app/RendererGl.h" | ||
#include "cinder/gl/gl.h" | ||
#include "cinder/gl/Texture.h" | ||
|
||
#include "ThreadedTaskQueue.h" | ||
|
||
namespace bluecadet { | ||
namespace utils { | ||
|
||
class ThreadedImageLoader { | ||
// texture will be nullptr if no success or canceled | ||
typedef std::function<void(const std::string path, ci::gl::TextureRef textureOrNull)> Callback; | ||
|
||
public: | ||
|
||
ThreadedImageLoader(const unsigned int numThreads = 3); | ||
virtual ~ThreadedImageLoader(); | ||
|
||
void load(const std::string path, Callback callback); | ||
void cancel(const std::string path); | ||
|
||
bool isLoading(const std::string path); | ||
bool hasTexture(const std::string path) const; | ||
const ci::gl::TextureRef getTexture(const std::string path) const; | ||
|
||
protected: | ||
ci::ImageSourceRef loadFile(const std::string path); // on worker thread | ||
void createSurface(const std::string path, const ci::ImageSourceRef source); // on worker thread | ||
|
||
void createTexture(const std::string path); // on main thread | ||
void triggerCallbacks(const std::string path); // on main thread | ||
|
||
std::map<std::string, std::vector<Callback>> mCallbacks; | ||
std::map<std::string, ci::gl::TextureRef> mTextureCache; | ||
std::map<std::string, ci::SurfaceRef> mSurfaceCache; | ||
|
||
std::mutex mCallbackMutex; | ||
std::mutex mSurfaceMutex; | ||
|
||
ThreadedTaskQueue mTasks; | ||
|
||
}; | ||
|
||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
samples/ThreadedImageLoadingSample/src/ThreadedImageLoadingSampleApp.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#include "cinder/app/App.h" | ||
#include "cinder/app/RendererGl.h" | ||
#include "cinder/gl/gl.h" | ||
|
||
#include "ThreadedImageLoader.h" | ||
|
||
using namespace ci; | ||
using namespace ci::app; | ||
using namespace std; | ||
using namespace bluecadet::utils; | ||
|
||
class ThreadedImageLoadingSampleApp : public App { | ||
public: | ||
void setup() override; | ||
void mouseDown( MouseEvent event ) override; | ||
void update() override; | ||
void draw() override; | ||
|
||
ThreadedImageLoader mLoader; | ||
|
||
}; | ||
|
||
void ThreadedImageLoadingSampleApp::setup() | ||
{ | ||
console() << "starting setup..." << endl; | ||
mLoader.load(getAssetPath("blue.png").string(), [=] (const string path, gl::TextureRef texture) { | ||
console() << "loaded " << path << endl; | ||
}); | ||
mLoader.load(getAssetPath("white.png").string(), [=] (const string path, gl::TextureRef texture) { | ||
console() << "loaded " << path << endl; | ||
}); | ||
mLoader.load(getAssetPath("small-cadet_black-01.png").string(), [=] (const string path, gl::TextureRef texture) { | ||
console() << "loaded " << path << endl; | ||
}); | ||
console() << "...setup complete" << endl; | ||
} | ||
|
||
void ThreadedImageLoadingSampleApp::mouseDown( MouseEvent event ) | ||
{ | ||
} | ||
|
||
void ThreadedImageLoadingSampleApp::update() | ||
{ | ||
} | ||
|
||
void ThreadedImageLoadingSampleApp::draw() | ||
{ | ||
gl::clear(Color(0, 0, 0)); | ||
gl::enableAlphaBlending(); | ||
|
||
// getTexture will return nullptr if it doesn't exist, so the below would be safe | ||
gl::draw(mLoader.getTexture(getAssetPath("blue.png").string())); | ||
gl::draw(mLoader.getTexture(getAssetPath("white.png").string())); | ||
gl::draw(mLoader.getTexture(getAssetPath("small-cadet_black-01.png").string())); | ||
|
||
// you can also check for textures explicitly | ||
// if (mLoader.hasTexture(getAssetPath("small-cadet_black-01.png").string())) { | ||
// gl::draw(mLoader.getTexture(getAssetPath("small-cadet_black-01.png").string())); | ||
// } | ||
} | ||
|
||
CINDER_APP( ThreadedImageLoadingSampleApp, RendererGl ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#include "../include/Resources.h" | ||
|
||
1 ICON "..\\resources\\cinder_app_icon.ico" |
26 changes: 26 additions & 0 deletions
26
samples/ThreadedImageLoadingSample/vc2013/ThreadedImageLoadingSample.sln
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio 2013 | ||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ThreadedImageLoadingSample", "ThreadedImageLoadingSample.vcxproj", "{1E7BB131-F2F6-4913-824D-FB927A2D9171}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Win32 = Debug|Win32 | ||
Release|Win32 = Release|Win32 | ||
Debug|x64 = Debug|x64 | ||
Release|x64 = Release|x64 | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{1E7BB131-F2F6-4913-824D-FB927A2D9171}.Debug|Win32.ActiveCfg = Debug|Win32 | ||
{1E7BB131-F2F6-4913-824D-FB927A2D9171}.Debug|Win32.Build.0 = Debug|Win32 | ||
{1E7BB131-F2F6-4913-824D-FB927A2D9171}.Release|Win32.ActiveCfg = Release|Win32 | ||
{1E7BB131-F2F6-4913-824D-FB927A2D9171}.Release|Win32.Build.0 = Release|Win32 | ||
{1E7BB131-F2F6-4913-824D-FB927A2D9171}.Debug|x64.ActiveCfg = Debug|x64 | ||
{1E7BB131-F2F6-4913-824D-FB927A2D9171}.Debug|x64.Build.0 = Debug|x64 | ||
{1E7BB131-F2F6-4913-824D-FB927A2D9171}.Release|x64.ActiveCfg = Release|x64 | ||
{1E7BB131-F2F6-4913-824D-FB927A2D9171}.Release|x64.Build.0 = Release|x64 | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
EndGlobal |
Oops, something went wrong.