Skip to content

Instantly share code, notes, and snippets.

@sansumbrella
Last active August 29, 2015 14:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sansumbrella/6372665d580ad7959e65 to your computer and use it in GitHub Desktop.
Save sansumbrella/6372665d580ad7959e65 to your computer and use it in GitHub Desktop.
Test of async and synchronous image load timing in Cinder.
#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 )
@sansumbrella
Copy link
Author

Demonstrates first draw hiccup issue experienced by AMD cards (at least).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment