瀏覽代碼

Added AsyncImageLoader to load images on threads

Inverted image/all.h and thread/all.h to ensure build
Added Image::DummyFill that uses DummyImageCodec to fill empty image
Added Log:: Error/Info in image Load/Save
undefined
Benjamin ‘Touky’ Huet Sam Hocevar <sam@hocevar.net> 9 年之前
父節點
當前提交
e1d1ecfd81
共有 15 個文件被更改,包括 166 次插入29 次删除
  1. +1
    -0
      src/image/codec/android-image.cpp
  2. +5
    -2
      src/image/codec/dummy-image.cpp
  3. +1
    -0
      src/image/codec/gdiplus-image.cpp
  4. +1
    -0
      src/image/codec/ios-image.cpp
  5. +1
    -0
      src/image/codec/oric-image.cpp
  6. +1
    -0
      src/image/codec/sdl-image.cpp
  7. +2
    -1
      src/image/codec/zed-image.cpp
  8. +2
    -1
      src/image/codec/zed-palette-image.cpp
  9. +1
    -0
      src/image/image-private.h
  10. +49
    -11
      src/image/image.cpp
  11. +3
    -0
      src/lol/image/image.h
  12. +1
    -1
      src/lol/public.h
  13. +1
    -6
      src/lol/sys/thread.h
  14. +96
    -4
      src/lol/sys/threadtypes.h
  15. +1
    -3
      src/sys/thread.cpp

+ 1
- 0
src/image/codec/android-image.cpp 查看文件

@@ -33,6 +33,7 @@ extern ANativeActivity *g_activity;
class AndroidImageCodec : public ImageCodec
{
public:
virtual char const *GetName() { return "<AndroidImageCodec>"; }
virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path);
virtual bool Close();


+ 5
- 2
src/image/codec/dummy-image.cpp 查看文件

@@ -22,10 +22,12 @@ namespace lol
class DummyImageCodec : public ImageCodec
{
public:
virtual char const *GetName() { return "<DummyImageCodec>"; }
virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path);
};

//Priority 0 because it's supposed to be the last one
DECLARE_IMAGE_CODEC(DummyImageCodec, 0)

/*
@@ -49,14 +51,15 @@ bool DummyImageCodec::Load(Image *image, char const *path)
}
image->Unlock(pixels);

return true;
//return false, because we're not supposed to be here.
return false;
}

bool DummyImageCodec::Save(Image *image, char const *path)
{
UNUSED(path);

return true;
return false;
}

} /* namespace lol */


+ 1
- 0
src/image/codec/gdiplus-image.cpp 查看文件

@@ -36,6 +36,7 @@ namespace lol
class GdiPlusImageCodec : public ImageCodec
{
public:
virtual char const *GetName() { return "<GdiPlusImageCodec>"; }
virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path);
};


+ 1
- 0
src/image/codec/ios-image.cpp 查看文件

@@ -26,6 +26,7 @@ namespace lol
class IosImageCodec : public ImageCodec
{
public:
virtual char const *GetName() { return "<IosImageCodec>"; }
virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path);
};


+ 1
- 0
src/image/codec/oric-image.cpp 查看文件

@@ -30,6 +30,7 @@ namespace lol
class OricImageCodec : public ImageCodec
{
public:
virtual char const *GetName() { return "<OricImageCodec>"; }
virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path);



+ 1
- 0
src/image/codec/sdl-image.cpp 查看文件

@@ -35,6 +35,7 @@ namespace lol
class SdlImageCodec : public ImageCodec
{
public:
virtual char const *GetName() { return "<SdlImageCodec>"; }
virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path);



+ 2
- 1
src/image/codec/zed-image.cpp 查看文件

@@ -23,6 +23,7 @@ namespace lol
class ZedImageCodec : public ImageCodec
{
public:
virtual char const *GetName() { return "<ZedImageCodec>"; }
virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path);

@@ -39,7 +40,7 @@ private:
array<ivec2, ivec2> m_tiles;
};

DECLARE_IMAGE_CODEC(ZedImageCodec, 0)
DECLARE_IMAGE_CODEC(ZedImageCodec, 10)

/*
* Public Image class


+ 2
- 1
src/image/codec/zed-palette-image.cpp 查看文件

@@ -22,11 +22,12 @@ namespace lol
class ZedPaletteImageCodec : public ImageCodec
{
public:
virtual char const *GetName() { return "<ZedPaletteImageCodec>"; }
virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path);
};

DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 0)
DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 10)

/*
* Public Image class


+ 1
- 0
src/image/image-private.h 查看文件

@@ -69,6 +69,7 @@ public:
class ImageCodec
{
public:
virtual char const *GetName() { return "<ImageCodec>"; }
virtual bool Load(Image *image, char const *path) = 0;
virtual bool Save(Image *image, char const *path) = 0;



+ 49
- 11
src/image/image.cpp 查看文件

@@ -98,17 +98,7 @@ Image::Image(ivec2 size)
Image::Image (Image const &other)
: m_data(new ImageData())
{
ivec2 size = other.GetSize();
PixelFormat fmt = other.GetFormat();

SetSize(size);
if (fmt != PixelFormat::Unknown)
{
SetFormat(fmt);
memcpy(m_data->m_pixels[(int)fmt]->data(),
other.m_data->m_pixels[(int)fmt]->data(),
size.x * size.y * BytesPerPixel(fmt));
}
Copy(other);
}

Image & Image::operator =(Image other)
@@ -127,19 +117,67 @@ Image::~Image()
delete m_data;
}

void Image::DummyFill()
{
//TODO: This is not very beautiful
for (auto codec : g_image_loader.m_codecs)
{
if (String(codec->GetName()).Contains("Dummy"))
{
codec->Load(this, nullptr);
return;
}
}
}

void Image::Copy(Image const &other)
{
ivec2 size = other.GetSize();
PixelFormat fmt = other.GetFormat();

SetSize(size);
if (fmt != PixelFormat::Unknown)
{
SetFormat(fmt);
memcpy(m_data->m_pixels[(int)fmt]->data(),
other.m_data->m_pixels[(int)fmt]->data(),
size.x * size.y * BytesPerPixel(fmt));
}
}

bool Image::Load(char const *path)
{
ImageCodec* last_codec = nullptr;
for (auto codec : g_image_loader.m_codecs)
{
last_codec = codec;
if (codec->Load(this, path))
{
Log::Info("Image::Load: Codec %s succesfully loaded %s.\n", codec->GetName(), path);
return true;
}
}

//Log error, because we shouldn't be here
Log::Error("Image::Load: Last codec %s, Error loading image %s.\n", last_codec->GetName(), path);
return false;
}

bool Image::Save(char const *path)
{
ImageCodec* last_codec = nullptr;
for (auto codec : g_image_loader.m_codecs)
{
last_codec = codec;
if (codec->Save(this, path))
{
Log::Info("Image::Save: Codec %s succesfully saved %s.\n", codec->GetName(), path);
return true;
}
}

//Log error, because we shouldn't be here
Log::Error("Image::Save: Last codec %s, Error saving image %s.\n", last_codec->GetName(), path);
return false;
}



+ 3
- 0
src/lol/image/image.h 查看文件

@@ -56,6 +56,7 @@ enum class EdiffAlgorithm : uint8_t
Lite,
};

//Image -----------------------------------------------------------------------
class Image
{
public:
@@ -70,6 +71,8 @@ public:
Image & operator =(Image other);
~Image();

void DummyFill();
void Copy(Image const &other);
bool Load(char const *path);
bool Save(char const *path);



+ 1
- 1
src/lol/public.h 查看文件

@@ -18,8 +18,8 @@
#include <lol/base/all.h>
#include <lol/math/all.h>
#include <lol/algorithm/all.h>
#include <lol/sys/all.h>
#include <lol/image/all.h>
#include <lol/sys/all.h>
#include <lol/gpu/all.h>
#include <lol/debug/all.h>


+ 1
- 6
src/lol/sys/thread.h 查看文件

@@ -113,21 +113,16 @@ protected:
class BaseThreadManager : public Entity
{
public:
char const *GetName() { return "<BaseThreadManager>"; }
BaseThreadManager(int thread_count);
BaseThreadManager(int thread_count, int thread_min);
~BaseThreadManager();

char const *GetName() { return "<BaseThreadManager>"; }

//Initialize, Ticker::Ref and start the thread
bool Start();
//Stop the threads
bool Stop();

//Children class intergace
virtual bool AddJob(ThreadJob* job) { ASSERT(false); return false; }
virtual bool GetWorkResult(array<ThreadJob*>& results) { ASSERT(false); return false; }

protected:
//Thread addition
void AddThreads(int nb);


+ 96
- 4
src/lol/sys/threadtypes.h 查看文件

@@ -25,6 +25,7 @@ namespace lol
class DefaultThreadManager : public BaseThreadManager
{
public:
char const *GetName() { return "<DefaultThreadManager>"; }
DefaultThreadManager(int thread_count)
: BaseThreadManager(thread_count, thread_count)
{ }
@@ -32,8 +33,6 @@ public:
: BaseThreadManager(thread_count, thread_min)
{ }

char const *GetName() { return "<DefaultThreadManager>"; }

//Work stuff
bool AddJob(ThreadJob* job);
bool GetWorkResult(array<ThreadJob*>& results);
@@ -70,7 +69,8 @@ protected:
bool m_updated = false;
};

//Test the files registered and warns when they update ------------------------
//FileUpdateTester ------------------------------------------------------------
//Test the files registered and warns when they update
class FileUpdateTester : public BaseThreadManager
{
typedef BaseThreadManager super;
@@ -80,9 +80,9 @@ public:
bool m_updated = false;
};
public:
char const *GetName() { return "<FileUpdateTester>"; }
FileUpdateTester() : BaseThreadManager(1) { }
~FileUpdateTester() { }
char const *GetName() { return "<FileUpdateTester>"; }

//-------------------------------------------------------------------------
FileUpdateTester::Status* RegisterFile(String const& path);
@@ -94,5 +94,97 @@ private:
map<String, Status*> m_files;
};

//AsyncImageJob ---------------------------------------------------------------
class AsyncImageJob : public ThreadJob
{
public:
AsyncImageJob()
: ThreadJob(ThreadJobType::NONE)
{
m_path = String();
}
AsyncImageJob(String path)
: ThreadJob(ThreadJobType::WORK_TODO)
{
m_path = path;
}
String const& GetPath() { return m_path; }
Image const& GetImage() { return m_image; }

protected:
virtual bool DoWork()
{
return m_image.Load(m_path.C());
}

String m_path;
Image m_image;
};

//AsyncImageLoader ------------------------------------------------------------
//Load images asynchronously, automatically updating the dummy image
class AsyncImageLoader : public BaseThreadManager
{
public:
char const *GetName() { return "<AsyncImageLoader>"; }
AsyncImageLoader(int thread_count)
: BaseThreadManager(thread_count, 0)
{
m_dummy_image.DummyFill();
}
~AsyncImageLoader()
{ }

//Returns a dummy image, and start a job to load the image on a thread
Image* Load(const lol::String& path)
{
//Create a job
AsyncImageJob* job = new AsyncImageJob(path);
//Create a dummy image
Image* image = new Image(m_dummy_image);
//Link the two
m_images[path] = image;
//Add job
AddWork(job);
//return Dummy image
return image;
}
bool CheckStatus(Image* image)
{
if (m_loaded_images.find(image) != INDEX_NONE)
{
m_loaded_images.remove_item(image);
return true;
}
return false;
}

protected:
virtual void TreatResult(ThreadJob* result)
{
AsyncImageJob* job = dynamic_cast<AsyncImageJob*>(result);
ASSERT(job);
//Copy image if work is OK
if (job->GetJobType() != ThreadJobType::WORK_FAILED)
{
Image* src = m_images[job->GetPath()];
m_images.remove(job->GetPath());
src->Copy(job->GetImage());
m_loaded_images.PushUnique(src);
}
else
{
Log::Error("AsyncImageJob FAILED. See load image error above.\n");
}
//Delete all that
delete(result);
}

private:
Image m_dummy_image;
map<String, Image*> m_images;
array<Image*> m_loaded_images;
};

} /* namespace lol */


+ 1
- 3
src/sys/thread.cpp 查看文件

@@ -166,10 +166,8 @@ void BaseThreadManager::TickGame(float seconds)
{
ThreadJob* job = result[i];
if (job->GetJobType() == ThreadJobType::WORK_DONE)
{
job->SetJobType(ThreadJobType::WORK_FETCHED);
TreatResult(job);
}
TreatResult(job);
}
}



Loading…
取消
儲存