Last active
August 29, 2015 14:18
-
-
Save sansumbrella/6372665d580ad7959e65 to your computer and use it in GitHub Desktop.
Test of async and synchronous image load timing in Cinder.
This file contains hidden or 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
#include "cinder/app/App.h" | |
#include "cinder/app/RendererGl.h" | |
#include "cinder/gl/gl.h" | |
#include "cinder/gl/Texture.h" | |
using namespace ci; | |
using namespace ci::app; | |
using namespace std; | |
struct TextureInfo { | |
std::string name; | |
gl::TextureRef texture; | |
}; | |
class ImageLoadingTestApp : public App { | |
public: | |
void setup() override; | |
void mouseDown( MouseEvent event ) override; | |
void update() override; | |
void draw() override; | |
void loadTestData(); | |
void testLoad( const fs::path &path ); | |
std::map<std::string, ImageSourceRef> sources; | |
TextureInfo testTexture; | |
gl::QueryTimeSwappedRef gpuTimer; | |
bool timeAsync = true; | |
const int framesToTime = 5; | |
int framesTimed = 0; | |
}; | |
void ImageLoadingTestApp::setup() | |
{ | |
gpuTimer = gl::QueryTimeSwapped::create(); | |
loadTestData(); | |
} | |
void ImageLoadingTestApp::loadTestData() | |
{ | |
auto path = getAssetPath("some_image.jpg"); | |
console() << "Testing 1080x1080 image load time: " << endl; | |
testLoad( path ); | |
} | |
gl::TextureRef asyncConvert( const ImageSourceRef &surface, const ci::gl::Context *shared_context ) | |
{ | |
Timer t(true); | |
auto context = gl::Context::create( shared_context ); | |
context->makeCurrent(); | |
auto texture = gl::Texture::create( surface ); | |
t.stop(); | |
app::console() << "Async conversion (in separate thread): " << t.getSeconds() * 1000 << "ms" << endl; | |
return texture; | |
} | |
void ImageLoadingTestApp::testLoad( const fs::path &path ) | |
{ | |
console() << endl; | |
Timer perfTimer( true ); | |
ImageSourceRef source = loadImage( path ); | |
int width = source->getWidth(); | |
int height = source->getHeight(); | |
perfTimer.stop(); | |
console() << "Create Source: " << ivec2( width, height ); | |
console() << ", Time: " << perfTimer.getSeconds() * 1000 << "ms" << endl; | |
// probably benefits from some HDD memory caching | |
Timer surfaceTimer( true ); | |
Surface surface = loadImage( path ); | |
width = surface.getWidth(); | |
height = surface.getHeight(); | |
surfaceTimer.stop(); | |
console() << "Create Surface: " << ivec2( width, height ); | |
console() << ", Time: " << surfaceTimer.getSeconds() * 1000 << "ms" << endl; | |
// Store surface | |
sources[path.string()] = source; | |
Timer textureTimer( true ); | |
gl::TextureRef texture = gl::Texture::create( loadImage( path ) ); | |
width = texture->getWidth(); | |
height = texture->getHeight(); | |
textureTimer.stop(); | |
console() << "Create Texture: " << ivec2( width, height ); | |
console() << ", Time: " << textureTimer.getSeconds() * 1000 << "ms" << endl; | |
// Load surface from map, start async loading to GPU | |
// Lets us store all textures in RAM to have faster access | |
Timer asyncTimer( true ); | |
const auto &s = sources.at( path.string() ); | |
width = s->getWidth(); | |
height = s->getHeight(); | |
auto *ctx = gl::context(); | |
auto future = std::async( std::launch::async, asyncConvert, s, ctx ); | |
asyncTimer.stop(); | |
console() << "Cue Async: " << ivec2( width, height ); | |
console() << ", Time: " << asyncTimer.getSeconds() * 1000 << "ms" << endl; | |
future.wait(); | |
// We can only test one or the other of sync vs async given how the GPU timer works. | |
// Both synchronous and asynchronous loaded textures suffer from the same initial draw penalty. | |
// It is in addition to any loading time. | |
if( timeAsync ) { | |
testTexture = { "Async", future.get() }; | |
} | |
else { | |
testTexture = { "Sync", texture }; | |
} | |
framesTimed = 0; | |
console() << endl; | |
} | |
void ImageLoadingTestApp::mouseDown( MouseEvent event ) | |
{ | |
timeAsync = ! timeAsync; | |
loadTestData(); | |
} | |
void ImageLoadingTestApp::update() | |
{ | |
} | |
void ImageLoadingTestApp::draw() | |
{ | |
if( framesTimed < framesToTime ) | |
{ | |
gl::clear( Color( 0, 0, 0 ) ); | |
gpuTimer->begin(); | |
gl::draw( testTexture.texture ); | |
gpuTimer->end(); | |
if( framesTimed >= 1 ) | |
{ | |
console() << testTexture.name << " "; | |
console() << "Draw time: " << gpuTimer->getElapsedMilliseconds() << endl; | |
} | |
framesTimed += 1; | |
} | |
} | |
CINDER_APP( ImageLoadingTestApp, RendererGl ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Demonstrates first draw hiccup issue experienced by AMD cards (at least).