vcglib/apps/nexus/patchserver.cpp

165 lines
4.2 KiB
C++

#include "patchserver.h"
#include <iostream>
#include <algorithm>
using namespace std;
using namespace nxs;
//TODO support compression!
bool PatchServer::Create(const std::string &filename,
Signature sig,
unsigned int csize,
unsigned int rsize) {
signature = sig;
chunk_size = csize;
frame = 0;
ram_size = rsize;
ram_used = 0;
lru.clear();
return File::Create(filename);
}
bool PatchServer::Load(const std::string &filename, Signature sig,
unsigned int csize, bool readonly,
unsigned int rsize) {
signature = sig;
chunk_size = csize;
ram_size = rsize;
frame = 0;
ram_used = 0;
lru.clear();
return File::Load(filename, readonly);
}
void PatchServer::Close() {
FlushAll();
File::Close();
}
//TODO add error checking.
bool PatchServer::ReadEntries(FILE *fp) {
unsigned int n;
fread(&n, 1, sizeof(int), fp);
patches.resize(n);
for(unsigned int i = 0; i < n; i++) {
patches[i].patch = NULL;
fread(&(patches[i].patch_start), 1, sizeof(unsigned int), fp);
fread(&(patches[i].patch_size), 1, sizeof(unsigned short), fp);
fread(&(patches[i].ram_used), 1, sizeof(unsigned short), fp);
patches[i].lru_pos = 0xffffffff;
}
return true;
}
bool PatchServer::WriteEntries(FILE *fp) {
unsigned int n = patches.size();
fwrite(&n, 1, sizeof(int), fp);
for(unsigned int i = 0; i < patches.size(); i++) {
fwrite(&(patches[i].patch_start), 1, sizeof(unsigned int), fp);
fwrite(&(patches[i].patch_size), 1, sizeof(unsigned short), fp);
fwrite(&(patches[i].ram_used), 1, sizeof(unsigned short), fp);
}
return true;
}
void PatchServer::AddPatch(unsigned short nvert, unsigned short nface) {
PatchEntry entry;
entry.patch = NULL;
entry.patch_start = Length()/chunk_size;
entry.patch_size = Patch::ChunkSize(signature, nvert, nface, chunk_size);
entry.ram_used = entry.patch_size;
entry.lru_pos = 0xffffffff;
patches.push_back(entry);
Redim(Length() + entry.patch_size * chunk_size);
}
Patch &PatchServer::GetPatch(unsigned int idx,
unsigned short nvert, unsigned short nface,
bool flush) {
assert(idx < patches.size());
PatchEntry &entry = patches[idx];
if(entry.patch) {
assert(entry.lru_pos < lru.size());
assert(lru[entry.lru_pos].patch == idx);
lru[entry.lru_pos].frame = frame++;
} else {
SetPosition(entry.patch_start * chunk_size);
assert(entry.patch_size != 0);
char *start = new char[entry.patch_size * chunk_size];
ReadBuffer(start, entry.patch_size * chunk_size);
entry.patch = new Patch(signature, start, nvert, nface);
entry.lru_pos = lru.size();
lru.push_back(PTime(idx, frame++));
ram_used += entry.ram_used;
}
//avoid frame overflow!
if(frame > (1<<30)) {
cerr << "oVERFLOW! (nothing dangerous... just warning." << endl;;
for(unsigned int i = 0; i < lru.size(); i++) {
if(lru[i].frame < (1<<29)) lru[i].frame = 0;
else lru[i].frame -= (1<<29);
}
make_heap(lru.begin(), lru.end());
for(unsigned int i = 0; i < lru.size(); i++)
patches[lru[i].patch].lru_pos = i;
}
if(flush && ram_used > ram_size * 1.1)
Flush();
return *(entry.patch);
}
void PatchServer::Flush() {
cerr << "FLUSHING\n\n\n n";
cerr << "ram_size: " << ram_size << endl;
cerr << "ram_used: " << ram_used << endl;
make_heap(lru.begin(), lru.end());
while(ram_used > ram_size) {
pop_heap(lru.begin(), lru.end());
PTime &ptime = lru.back();
Flush(ptime.patch);
lru.pop_back();
}
make_heap(lru.begin(), lru.end());
for(unsigned int i = 0; i < lru.size(); i++)
patches[lru[i].patch].lru_pos = i;
}
void PatchServer::FlushAll() {
for(unsigned int i = 0; i < lru.size(); i++) {
PTime &ptime = lru[i];
Flush(ptime.patch);
}
assert(ram_used == 0);
lru.clear();
}
void PatchServer::Flush(unsigned int patch) {
PatchEntry &entry = patches[patch];
assert(entry.patch);
if(!readonly) { //write back patch
SetPosition(entry.patch_start * chunk_size);
WriteBuffer(entry.patch->start, entry.patch_size * chunk_size);
}
delete [](entry.patch->start);
delete entry.patch;
entry.patch = NULL;
entry.lru_pos = 0xffffffff;
ram_used -= entry.ram_used;
}