}
}
+unsigned get_component_size(PixelFormat pf)
+{
+ switch(pf)
+ {
+ case RGB16F:
+ case RGBA16F:
+ case LUMINANCE16F:
+ case LUMINANCE_ALPHA16F:
+ return 2;
+ case RGB32F:
+ case RGBA32F:
+ case LUMINANCE32F:
+ case LUMINANCE_ALPHA32F:
+ return 4;
+ default:
+ return 1;
+ }
+}
+
+unsigned get_pixel_size(PixelFormat pf)
+{
+ return get_component_count(pf)*get_component_size(pf);
+}
+
void require_pixelformat(PixelFormat pf)
{
switch(pf)
PixelFormat get_base_pixelformat(PixelFormat);
PixelFormat get_srgb_pixelformat(PixelFormat);
unsigned get_component_count(PixelFormat);
+unsigned get_component_size(PixelFormat);
+unsigned get_pixel_size(PixelFormat);
void require_pixelformat(PixelFormat);
#ifndef MSP_GL_RESOURCE_H_
#define MSP_GL_RESOURCE_H_
+#include <msp/core/inttypes.h>
#include <msp/io/seekable.h>
namespace Msp {
void set_manager(ResourceManager *);
void *get_manager_data() const { return manager_data; }
virtual AsyncLoader *load(IO::Seekable &) = 0;
+ virtual UInt64 get_data_size() const = 0;
virtual void unload() = 0;
};
ResourceManager::ResourceManager():
policy(LOAD_ON_DEMAND),
async_loads(true),
+ size_limit(0),
frame(0),
+ min_retain_frames(30),
max_retain_frames(0),
next_unload(0),
thread(*this)
async_loads = a;
}
+void ResourceManager::set_size_limit(UInt64 s)
+{
+ size_limit = s;
+}
+
+void ResourceManager::set_min_retain_frames(unsigned f)
+{
+ min_retain_frames = f;
+}
+
void ResourceManager::set_max_retain_frames(unsigned f)
{
max_retain_frames = f;
void ResourceManager::tick()
{
LoadingThread::State thread_state = thread.get_state();
+ bool check_total_size = false;
if(thread_state==LoadingThread::SYNC_PENDING)
+ {
thread.sync();
+ check_total_size = true;
+ }
else if(thread_state==LoadingThread::IDLE && !queue.empty())
{
ManagedResource *managed = queue.front();
if(next_unload)
next_unload += max_retain_frames;
}
+
+ if(check_total_size)
+ {
+ while(get_total_data_size()>size_limit)
+ {
+ unsigned unload_limit = frame-min_retain_frames;
+ ManagedResource *best = 0;
+ UInt64 best_impact = 0;
+ for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i)
+ if(i->second.loaded && i->second.last_used<unload_limit)
+ {
+ UInt64 impact = i->second.data_size*(frame-i->second.last_used);
+ if(!best || impact<best_impact)
+ {
+ best = &i->second;
+ best_impact = impact;
+ }
+ }
+
+ if(!best)
+ break;
+
+ best->unload();
+ }
+ }
+}
+
+UInt64 ResourceManager::get_total_data_size() const
+{
+ UInt64 total = 0;
+ for(ResourceMap::const_iterator i=resources.begin(); i!=resources.end(); ++i)
+ if(i->second.loaded)
+ total += i->second.data_size;
+ return total;
}
io(0),
loader(0),
loaded(false),
- last_used(0)
+ last_used(0),
+ data_size(0)
{ }
void ResourceManager::ManagedResource::start_loading()
loaded = true;
delete io;
io = 0;
+ data_size = resource->get_data_size();
}
void ResourceManager::ManagedResource::unload()
#ifndef MSP_GL_RESOURCEMANAGER_H_
#define MSP_GL_RESOURCEMANAGER_H_
+#include <msp/core/inttypes.h>
#include <msp/core/mutex.h>
#include <msp/core/semaphore.h>
#include <msp/core/thread.h>
Resource::AsyncLoader *loader;
bool loaded;
unsigned last_used;
+ UInt64 data_size;
ManagedResource(Resource &);
bool async_loads;
ResourceMap resources;
LoadQueue queue;
+ UInt64 size_limit;
unsigned frame;
unsigned min_retain_frames;
unsigned max_retain_frames;
void set_loading_policy(LoadingPolicy);
void set_async_loads(bool);
+ void set_size_limit(UInt64);
+ void set_min_retain_frames(unsigned);
void set_max_retain_frames(unsigned);
void add_resource(Resource &);
void remove_resource(Resource &);
void tick();
+ UInt64 get_total_data_size() const;
};
} // namespace GL
static const Texture *current(unsigned = 0);
static void unbind() { unbind_from(0); }
static void unbind_from(unsigned);
+
+ virtual UInt64 get_data_size() const { return 0; }
};
} // namespace GL
Texture1D::Texture1D():
Texture(GL_TEXTURE_1D),
+ ifmt(RGB),
width(0),
allocated(0)
{ }
return width>>level;
}
+UInt64 Texture1D::get_data_size() const
+{
+ return id ? width*get_pixel_size(ifmt) : 0;
+}
+
} // namespace GL
} // namespace Msp
public:
virtual AsyncLoader *load(IO::Seekable &) { return 0; }
+ virtual UInt64 get_data_size() const;
virtual void unload() { }
};
Texture2D::Texture2D(ResourceManager *m):
Texture(GL_TEXTURE_2D, m),
+ ifmt(RGB),
width(0),
height(0),
allocated(0)
return new AsyncLoader(*this, io);
}
+UInt64 Texture2D::get_data_size() const
+{
+ return id ? width*height*get_component_count(ifmt) : 0;
+}
+
void Texture2D::unload()
{
glDeleteTextures(1, &id);
public:
virtual Resource::AsyncLoader *load(IO::Seekable &);
+ virtual UInt64 get_data_size() const;
virtual void unload();
};
Texture3D::Texture3D():
Texture(GL_TEXTURE_3D),
+ ifmt(RGB),
width(0),
height(0),
depth(0),
d = 1;
}
+UInt64 Texture3D::get_data_size() const
+{
+ return id ? width*height*depth*get_pixel_size(ifmt) : 0;
+}
+
} // namespace GL
} // namespace Msp
public:
virtual AsyncLoader *load(IO::Seekable &) { return 0; }
+ virtual UInt64 get_data_size() const;
virtual void unload() { }
};
TextureCube::TextureCube():
Texture(GL_TEXTURE_CUBE_MAP),
+ ifmt(RGB),
size(0),
allocated(0)
{
return fv+s*sv+t*tv;
}
+UInt64 TextureCube::get_data_size() const
+{
+ return id ? size*size*6*get_pixel_size(ifmt) : 0;
+}
+
TextureCube::Loader::Loader(TextureCube &t):
DataFile::DerivedObjectLoader<TextureCube, Texture::Loader>(t)
Vector3 get_texel_direction(TextureCubeFace, unsigned, unsigned);
virtual AsyncLoader *load(IO::Seekable &) { return 0; }
+ virtual UInt64 get_data_size() const;
virtual void unload() { }
};