From: Mikko Rasa Date: Tue, 23 Sep 2014 21:08:21 +0000 (+0300) Subject: Enable asynchronous loading of Meshes X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=f1c404eda3ae4173ceb63a4f9d1f0bbccf7091a6;p=libs%2Fgl.git Enable asynchronous loading of Meshes This currently causes object bounding spheres to be incorrect when using managed meshes. The situation will be rectified shortly. --- diff --git a/source/mesh.cpp b/source/mesh.cpp index 150822ce..055345fa 100644 --- a/source/mesh.cpp +++ b/source/mesh.cpp @@ -1,34 +1,41 @@ #include #include +#include #include "buffer.h" #include "error.h" #include "mesh.h" #include "renderer.h" +#include "resourcemanager.h" using namespace std; namespace Msp { namespace GL { -Mesh::Mesh(): - vertices(VERTEX3), - vbuf(0), - ibuf(0), - vao_id(0), - defer_buffers(true), - dirty(true), - winding(0) -{ } - -Mesh::Mesh(const VertexFormat &f): - vertices(f), - vbuf(0), - ibuf(0), - vao_id(0), - defer_buffers(true), - dirty(true), - winding(0) -{ } +Mesh::Mesh(ResourceManager *rm): + vertices(VERTEX3) +{ + init(rm); +} + +Mesh::Mesh(const VertexFormat &f, ResourceManager *rm): + vertices(f) +{ + init(rm); +} + +void Mesh::init(ResourceManager *rm) +{ + vbuf = 0; + ibuf = 0; + vao_id = 0; + defer_buffers = true; + dirty = true; + winding = 0; + + if(rm) + set_manager(rm); +} Mesh::~Mesh() { @@ -136,6 +143,13 @@ void Mesh::draw() const if(cur && cur!=this) throw invalid_operation("Mesh::draw"); + if(manager) + { + manager->resource_used(*this); + if(disallow_rendering) + return; + } + if(!current()) vertices.apply(); Bind bind_ibuf(ibuf, ELEMENT_ARRAY_BUFFER); @@ -147,6 +161,13 @@ void Mesh::draw() const void Mesh::draw(Renderer &renderer) const { + if(manager) + { + manager->resource_used(*this); + if(disallow_rendering) + return; + } + renderer.set_mesh(this); renderer.set_element_buffer(ibuf); renderer.set_winding_test(winding); @@ -179,6 +200,33 @@ void Mesh::unbind() glBindVertexArray(0); } +Resource::AsyncLoader *Mesh::load(IO::Seekable &io) +{ + return new AsyncLoader(*this, io); +} + +UInt64 Mesh::get_data_size() const +{ + UInt64 size = 0; + if(vbuf) + size += vbuf->get_size(); + if(ibuf) + size += ibuf->get_size(); + return size; +} + +void Mesh::unload() +{ + vertices.clear(); + vertices.use_buffer(0); + batches.clear(); + delete vbuf; + delete ibuf; + defer_buffers = (vbuf || ibuf); + vbuf = 0; + ibuf = 0; +} + Mesh::Loader::Loader(Mesh &m): DataFile::ObjectLoader(m) @@ -216,5 +264,65 @@ void Mesh::Loader::winding(FaceWinding w) obj.winding = &WindingTest::counterclockwise(); } + +Mesh::AsyncLoader::AsyncLoader(Mesh &m, IO::Seekable &i): + mesh(m), + io(i), + vertex_updater(0), + index_updater(0), + phase(0) +{ + // Make sure the extension is initialized in the rendering thread. + (bool)NV_primitive_restart; + + mesh.disallow_rendering = true; + if(mesh.defer_buffers) + mesh.create_buffers(); +} + +Mesh::AsyncLoader::~AsyncLoader() +{ + mesh.disallow_rendering = false; +} + +bool Mesh::AsyncLoader::needs_sync() const +{ + return phase%2; +} + +bool Mesh::AsyncLoader::process() +{ + if(phase==0) + { + // TODO use correct filename + DataFile::Parser parser(io, "async"); + Loader loader(mesh); + loader.load(parser); + } + else if(phase==1) + { + vertex_updater = mesh.vertices.refresh_async(); + if(!mesh.batches.empty()) + index_updater = mesh.batches.front().refresh_async(); + } + else if(phase==2) + { + if(vertex_updater) + vertex_updater->upload_data(); + if(index_updater) + index_updater->upload_data(); + } + else if(phase==3) + { + delete vertex_updater; + delete index_updater; + } + + ++phase; + if(phase==1 && !mesh.vbuf && !mesh.ibuf) + phase += 3; + return phase>3; +} + } // namespace GL } // namespace Msp diff --git a/source/mesh.h b/source/mesh.h index 730b724c..14cb072d 100644 --- a/source/mesh.h +++ b/source/mesh.h @@ -3,6 +3,7 @@ #include #include "batch.h" +#include "resource.h" #include "vertexarray.h" #include "windingtest.h" @@ -17,7 +18,7 @@ Raw mesh data, consisting of a VertexArray and one or more Batches. Though a Mesh can draw itself, it's usually used as part of Renderables rather than on its own. */ -class Mesh: public Bindable +class Mesh: public Bindable, public Resource { friend class MeshBuilder; @@ -33,6 +34,23 @@ public: }; private: + class AsyncLoader: public Resource::AsyncLoader + { + private: + Mesh &mesh; + IO::Seekable &io; + Bufferable::AsyncUpdater *vertex_updater; + Bufferable::AsyncUpdater *index_updater; + unsigned phase; + + public: + AsyncLoader(Mesh &, IO::Seekable &); + ~AsyncLoader(); + + virtual bool needs_sync() const; + virtual bool process(); + }; + VertexArray vertices; std::list batches; Buffer *vbuf; @@ -40,11 +58,15 @@ private: unsigned vao_id; bool defer_buffers; mutable bool dirty; + bool disallow_rendering; const WindingTest *winding; public: - Mesh(); - Mesh(const VertexFormat &f); + Mesh(ResourceManager * = 0); + Mesh(const VertexFormat &, ResourceManager * = 0); +private: + void init(ResourceManager *); +public: ~Mesh(); void clear(); @@ -70,6 +92,10 @@ public: void bind() const; static void unbind(); + + virtual Resource::AsyncLoader *load(IO::Seekable &); + virtual UInt64 get_data_size() const; + virtual void unload(); }; } // namespace GL diff --git a/source/resources.cpp b/source/resources.cpp index 79c5e85f..2fd69503 100644 --- a/source/resources.cpp +++ b/source/resources.cpp @@ -29,7 +29,7 @@ Resources::Resources(): add_type().keyword("font"); add_type().suffix(".kframe").keyword("keyframe"); add_type().suffix(".mat").keyword("material"); - add_type().keyword("mesh"); + add_type().keyword("mesh").creator(&Resources::create_mesh); add_type().keyword("object"); add_type().keyword("pose"); add_type().keyword("shader"); @@ -53,6 +53,21 @@ void Resources::set_resource_manager(ResourceManager *m) resource_manager = m; } +Mesh *Resources::create_mesh(const string &name) +{ + if(!resource_manager) + return 0; + + if(RefPtr io = open_from_sources(name)) + { + RefPtr mesh = new GL::Mesh(resource_manager); + resource_manager->set_resource_location(*mesh, *this, name); + return mesh.release(); + } + + return 0; +} + Texture2D *Resources::create_texture2d(const string &name) { string ext = FS::extpart(name); diff --git a/source/resources.h b/source/resources.h index e2503298..e939f7ce 100644 --- a/source/resources.h +++ b/source/resources.h @@ -7,6 +7,7 @@ namespace Msp { namespace GL { +class Mesh; class ResourceManager; class Texture2D; @@ -35,6 +36,7 @@ public: void set_resource_manager(ResourceManager *); protected: + Mesh *create_mesh(const std::string &); Texture2D *create_texture2d(const std::string &); };