diff --git a/apps/nexus/nexusmt.cpp b/apps/nexus/nexusmt.cpp index 0379ed66..78c38e8e 100644 --- a/apps/nexus/nexusmt.cpp +++ b/apps/nexus/nexusmt.cpp @@ -1,8 +1,11 @@ -#include -#include "nexusmt.h" #include #include +#include + +#include + +#include "nexusmt.h" using namespace nxs; using namespace vcg; @@ -104,6 +107,8 @@ NexusMt::NexusMt(): vbo_mode(VBO_AUTO), NexusMt::~NexusMt() { if(metric) delete metric; + prefetch.signal(); + prefetch.waitfor(); } bool NexusMt::Load(const string &filename) { @@ -174,6 +179,9 @@ bool NexusMt::Load(const string &filename) { SetComponent(DATA, true); SetPrefetchSize(patches.ram_max/2); + cerr << "Start!\n"; + prefetch.start(); + cerr << "Started\n"; return true; } @@ -204,7 +212,7 @@ void NexusMt::Render() { } void NexusMt::Draw(vector &cells) { - + prefetch.init(this, cells, visited); tri_total = 0; tri_rendered = 0; @@ -218,94 +226,117 @@ void NexusMt::Draw(vector &cells) { glEnableClientState(GL_NORMAL_ARRAY); //TODO textures and data. - for(unsigned int i = 0; i < cells.size(); i++) { - unsigned int cell = cells[i]; + unsigned int count = cells.size(); + while(count) { + // cerr << "Getting message: " << count << endl; + pt::message *msg = patches.queue.getmessage(); + QueuePServer::Data *data = (QueuePServer::Data *)(msg->param); + if(msg->id == QueuePServer::FLUSH) { + // cerr << "Flush...\n"; + if(data->vbo_element) { + glDeleteBuffersARB(1, &(data->vbo_element)); + glDeleteBuffersARB(1, &(data->vbo_array)); + } + delete data; + delete msg; + continue; + } + + if(msg->id != QueuePServer::DRAW) { + cerr << "Unknown message!\n"; + continue; + } + + unsigned int cell = msg->result; PatchInfo &entry = index[cell]; tri_total += entry.nface; //frustum culling - if(frustum.IsOutside(entry.sphere.Center(), entry.sphere.Radius())) - continue; - - tri_rendered += entry.nface; - - QueuePServer::Data &data = patches.Lookup(cell,entry.nvert,entry.nface, 0); - Patch &patch = *data.patch; - char *fstart; - char *vstart; - char *cstart; - char *nstart; - - if(vbo_mode != VBO_OFF) { - // unsigned int vbo_array; - // unsigned int vbo_element; - // patches.GetVbo(cell, vbo_element, vbo_array); - assert(data.vbo_element); - assert(data.vbo_array); - - glBindBufferARB(GL_ARRAY_BUFFER_ARB, data.vbo_array); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, data.vbo_element); - - fstart = NULL; - vstart = NULL; - cstart = (char *)(sizeof(float) * patch.cstart); - nstart = (char *)(sizeof(float) * patch.nstart); - } else { - fstart = (char *)patch.FaceBegin(); - vstart = (char *)patch.VertBegin(); - cstart = (char *)patch.ColorBegin(); - nstart = (char *)patch.Norm16Begin(); + if(!frustum.IsOutside(entry.sphere.Center(), entry.sphere.Radius())) { + tri_rendered += entry.nface; + Draw(cell, *data); } - glVertexPointer(3, GL_FLOAT, 0, vstart); - if(use_colors) - glColorPointer(4, GL_UNSIGNED_BYTE, 0, cstart); - if(use_normals) - glNormalPointer(GL_SHORT, 8, nstart); - - switch(mode) { - case POINTS: - glDrawArrays(GL_POINTS, 0, patch.nv); break; - case PATCHES: - glColor3ub((cell * 27)%255, (cell * 37)%255, (cell * 87)%255); - case SMOOTH: - if(signature & NXS_FACES) - glDrawElements(GL_TRIANGLES, patch.nf * 3, - GL_UNSIGNED_SHORT, fstart); - else if(signature & NXS_STRIP) - glDrawElements(GL_TRIANGLE_STRIP, patch.nf, - GL_UNSIGNED_SHORT, fstart); - break; - case FLAT: - if(signature & NXS_FACES) { - glBegin(GL_TRIANGLES); - for(int i = 0; i < patch.nf; i++) { - unsigned short *f = patch.Face(i); - Point3f &p0 = patch.Vert(f[0]); - Point3f &p1 = patch.Vert(f[1]); - Point3f &p2 = patch.Vert(f[2]); - Point3f n = ((p1 - p0) ^ (p2 - p0)); - glNormal3f(n[0], n[1], n[2]); - glVertex3f(p0[0], p0[1], p0[2]); - glVertex3f(p1[0], p1[1], p1[2]); - glVertex3f(p2[0], p2[1], p2[2]); - } - glEnd(); - } else if(signature & NXS_STRIP) { - cerr << "Unsupported rendering mode sorry\n"; - exit(0); - } - break; - default: - cerr << "Unsupported rendering mode sorry\n"; - exit(0); - break; - } + delete msg; + count--; } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); } +void NexusMt::Draw(unsigned int cell, QueuePServer::Data &data) { + + Patch &patch = *(data.patch); + char *fstart; + char *vstart; + char *cstart; + char *nstart; + + if(vbo_mode != VBO_OFF) { + if(!data.vbo_element) { + patches.LoadVbo(data); + } + + glBindBufferARB(GL_ARRAY_BUFFER_ARB, data.vbo_array); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, data.vbo_element); + + fstart = NULL; + vstart = NULL; + cstart = (char *)(sizeof(float) * patch.cstart); + nstart = (char *)(sizeof(float) * patch.nstart); + } else { + fstart = (char *)patch.FaceBegin(); + vstart = (char *)patch.VertBegin(); + cstart = (char *)patch.ColorBegin(); + nstart = (char *)patch.Norm16Begin(); + } + + glVertexPointer(3, GL_FLOAT, 0, vstart); + if(use_colors) + glColorPointer(4, GL_UNSIGNED_BYTE, 0, cstart); + if(use_normals) + glNormalPointer(GL_SHORT, 8, nstart); + + switch(mode) { + case POINTS: + glDrawArrays(GL_POINTS, 0, patch.nv); break; + case PATCHES: + glColor3ub((cell * 27)%255, (cell * 37)%255, (cell * 87)%255); + case SMOOTH: + if(signature & NXS_FACES) + glDrawElements(GL_TRIANGLES, patch.nf * 3, + GL_UNSIGNED_SHORT, fstart); + else if(signature & NXS_STRIP) + glDrawElements(GL_TRIANGLE_STRIP, patch.nf, + GL_UNSIGNED_SHORT, fstart); + break; + case FLAT: + if(signature & NXS_FACES) { + glBegin(GL_TRIANGLES); + for(int i = 0; i < patch.nf; i++) { + unsigned short *f = patch.Face(i); + Point3f &p0 = patch.Vert(f[0]); + Point3f &p1 = patch.Vert(f[1]); + Point3f &p2 = patch.Vert(f[2]); + Point3f n = ((p1 - p0) ^ (p2 - p0)); + glNormal3f(n[0], n[1], n[2]); + glVertex3f(p0[0], p0[1], p0[2]); + glVertex3f(p1[0], p1[1], p1[2]); + glVertex3f(p2[0], p2[1], p2[2]); + } + glEnd(); + } else if(signature & NXS_STRIP) { + cerr << "Unsupported rendering mode sorry\n"; + exit(0); + } + break; + default: + cerr << "Unsupported rendering mode sorry\n"; + exit(0); + break; + } +} + void NexusMt::SetExtractionSize(unsigned int r_size) { extraction_max = r_size/patches.chunk_size; } @@ -471,6 +502,7 @@ void NexusMt::ClearHistory() { void NexusMt::Extract(std::vector &selected) { extraction_used = 0; + visited.clear(); std::vector::iterator n; for(n = nodes.begin(); n != nodes.end(); n++) { diff --git a/apps/nexus/nexusmt.h b/apps/nexus/nexusmt.h index 316ac6bb..8beab69d 100644 --- a/apps/nexus/nexusmt.h +++ b/apps/nexus/nexusmt.h @@ -3,7 +3,6 @@ #include #include -#include #include #include "nexusbase.h" @@ -121,9 +120,12 @@ class NexusMt: public NexusBase { unsigned int tri_total; std::vector visited; + QueuePServer patches; BorderServer borders; + Prefetch prefetch; + NexusMt(); ~NexusMt(); @@ -146,6 +148,7 @@ class NexusMt: public NexusBase { bool SetComponents(unsigned int mask); void Draw(std::vector &selected); + void Draw(unsigned int cell, QueuePServer::Data &data); void Extract(std::vector &selected); protected: diff --git a/apps/nexus/prefetch.cpp b/apps/nexus/prefetch.cpp index fa390fd1..ed405160 100644 --- a/apps/nexus/prefetch.cpp +++ b/apps/nexus/prefetch.cpp @@ -1,4 +1,5 @@ #include "prefetch.h" +#include "nexusmt.h" using namespace std; using namespace nxs; @@ -6,23 +7,35 @@ using namespace nxs; void Prefetch::init(NexusMt *m, std::vector &selected, std::vector &visited) { + + // cerr << "Init\n"; + safety.lock(); mt = m; missing.clear(); + unsigned int notloaded = 0; std::map tmp; for(unsigned int i = 0; i < selected.size(); i++) { unsigned int patch = selected[i]; tmp[patch] = 0.0f; + if(!mt->patches.IsLoaded(patch)) + notloaded++; + // if(mt->patches.IsLoaded(patch)) + // mt->todraw.push_back(make_pair(patch, (Patch *)NULL)); + // else missing.push_back(PServer::Item(patch, 0.0f)); } + if(notloaded) + cerr << "Patches to load: " << notloaded << endl; + for(unsigned int i = 0; i < visited.size(); i++) { PServer::Item &item = visited[i]; if(tmp.count(item.patch)) continue; if(mt->patches.IsLoaded(item.patch)) tmp[item.patch] = item.priority; - else - missing.push_back(item); + + missing.push_back(item); } QueuePServer &ps = mt->patches; @@ -34,6 +47,7 @@ void Prefetch::init(NexusMt *m, std::vector &selected, item.priority = 1e40; } make_heap(ps.heap.begin(), ps.heap.end()); + sort(missing.begin(), missing.end()); //CRITICAL reverse pero'! reverse(missing.begin(), missing.end()); safety.unlock(); @@ -44,13 +58,26 @@ void Prefetch::execute() { if(get_signaled()) return; while(1) { safety.lock(); - if(missing.size() == 0) break; + if(missing.size() == 0) { + safety.unlock(); + break; + } PServer::Item item = missing.back(); missing.pop_back(); + + if(item.priority > 0 && + mt->patches.ram_used > mt->patches.ram_max && + item.priority >= mt->patches.MaxPriority()) { + safety.unlock(); + break; + } PatchInfo &info = mt->index[item.patch]; + + // cerr << "prefetching: " << item.patch << endl; mt->patches.Lookup(item.patch, info.nvert, info.nface, item.priority); + safety.unlock(); } - relax(50); + relax(5); } } diff --git a/apps/nexus/prefetch.h b/apps/nexus/prefetch.h index da51e4fe..a2e6a012 100644 --- a/apps/nexus/prefetch.h +++ b/apps/nexus/prefetch.h @@ -7,7 +7,6 @@ #include -#include "nexusmt.h" #include "queuepserver.h" namespace nxs { @@ -20,7 +19,7 @@ class Prefetch: public pt::thread{ pt::mutex safety; unsigned int ram_max; unsigned int ram_used; - + NexusMt *mt; std::vector missing; diff --git a/apps/nexus/queuepserver.cpp b/apps/nexus/queuepserver.cpp index 65f7f2a4..c8e6315c 100644 --- a/apps/nexus/queuepserver.cpp +++ b/apps/nexus/queuepserver.cpp @@ -4,28 +4,74 @@ using namespace std; using namespace nxs; +using namespace pt; QueuePServer::Data &QueuePServer::Lookup(unsigned int patch, unsigned short nv, unsigned short nf, float priority) { if(index.count(patch)) { - return index[patch]; + Data &data = index[patch]; + if(priority == 0) { + // cerr << "Posting draw!\n"; + message *msg = new message(DRAW, (unsigned int)&data); + msg->result = patch; + queue.post(msg); + } + return data; } else { while(ram_used > ram_max) { pop_heap(heap.begin(), heap.end()); Item item = heap.back(); if(item.priority == 0) break; //no deleting needed patches. - Data &data = index[patch]; + // cerr << "Dropping: " << item.patch << endl; + Data &data = index[item.patch]; FlushVbo(data); - FlushPatch(patch, data.patch); - index.erase(patch); + Data *d = new Data(data); + queue.post(FLUSH, (unsigned int)d); + + FlushPatch(item.patch, data.patch); + index.erase(item.patch); } Item item(patch, priority); heap.push_back(item); push_heap(heap.begin(), heap.end()); Data &data = index[patch]; + // cerr << "Loading: " << patch << endl; data.patch = LoadPatch(patch, nv, nf); + + if(priority == 0) { + message *msg = new message(DRAW, (unsigned int)&data); + msg->result = patch; + queue.post(msg); + } + return data; + } +} + +QueuePServer::Data &QueuePServer::Lookup(unsigned int patch, + Patch *mem, + float priority) { + if(index.count(patch)) { + Data &data = index[patch]; + return data; + } else { + while(ram_used > ram_max) { + pop_heap(heap.begin(), heap.end()); + Item item = heap.back(); + if(item.priority == 0) break; //no deleting needed patches. + // cerr << "Dropping: " << item.patch << endl; + Data &data = index[item.patch]; + FlushVbo(data); + FlushPatch(item.patch, data.patch); + index.erase(item.patch); + } + Item item(patch, priority); + heap.push_back(item); + push_heap(heap.begin(), heap.end()); + Data &data = index[patch]; + // cerr << "Loading: " << patch << endl; + data.patch = mem; LoadVbo(data); return data; } @@ -34,6 +80,12 @@ QueuePServer::Data &QueuePServer::Lookup(unsigned int patch, bool QueuePServer::IsLoaded(unsigned int patch) { return index.count(patch); } + +float QueuePServer::MaxPriority() { + if(!heap.size()) return 0; + return heap.front().priority; +} + void QueuePServer::Flush() { std::map::iterator i; for(i = index.begin(); i != index.end(); i++) { @@ -70,12 +122,11 @@ void QueuePServer::LoadVbo(Data &data) { } void QueuePServer::FlushVbo(Data &data) { if(!vbo_max) return; - assert(data.vbo_element); - assert(data.vbo_array); - glDeleteBuffersARB(1, &data.vbo_element); - glDeleteBuffersARB(1, &data.vbo_array); - data.vbo_element = 0; - data.vbo_array = 0; + if(!data.vbo_element) return; + //glDeleteBuffersARB(1, &data.vbo_element); + //glDeleteBuffersARB(1, &data.vbo_array); + //data.vbo_element = 0; + // data.vbo_array = 0; Patch &patch = *data.patch; vbo_used -= patch.nf * sizeof(unsigned short); diff --git a/apps/nexus/queuepserver.h b/apps/nexus/queuepserver.h index e9b262fa..e5bc8a73 100644 --- a/apps/nexus/queuepserver.h +++ b/apps/nexus/queuepserver.h @@ -5,6 +5,8 @@ #include #include +#include + #include "pserver.h" namespace nxs { @@ -12,6 +14,7 @@ namespace nxs { class QueuePServer: public PServer { public: + enum Action { DRAW = 1, FLUSH = 0 }; struct Data { Patch *patch; unsigned int vbo_array; @@ -19,6 +22,8 @@ class QueuePServer: public PServer { Data(): patch(NULL), vbo_array(0), vbo_element(0) {} }; + pt::jobqueue queue; + unsigned int vbo_used; unsigned int vbo_max; @@ -28,10 +33,11 @@ class QueuePServer: public PServer { Data &Lookup(unsigned int patch, unsigned short nv, unsigned short nf, float priority = 0.0f); - bool IsLoaded(unsigned int patch); - void Flush(); + Data &Lookup(unsigned int patch, Patch *mem, float priority = 0.0f); - protected: + bool IsLoaded(unsigned int patch); + float MaxPriority(); + void Flush(); void LoadVbo(Data &data); void FlushVbo(Data &data);