Skip to content

Commit

Permalink
refactor ChunkCache
Browse files Browse the repository at this point in the history
change to Singleton Pattern (only one instance makes sense)
removes passing around of object and mutex
renamed all x,z -> cx,cz to distinguish Chunk coordinates
  • Loading branch information
EtlamGit committed Aug 5, 2019
1 parent 48cd13f commit b62b1a4
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 51 deletions.
40 changes: 29 additions & 11 deletions chunkcache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
#include <windows.h>
#endif

ChunkID::ChunkID(int x, int z) : x(x), z(z) {
ChunkID::ChunkID(int cx, int cz) : cx(cx), cz(cz) {
}
bool ChunkID::operator==(const ChunkID &other) const {
return (other.x == x) && (other.z == z);
return (other.cx == cx) && (other.cz == cz);
}
uint qHash(const ChunkID &c) {
return (c.x << 16) ^ (c.z & 0xffff); // safe way to hash a pair of integers
return (c.cx << 16) ^ (c.cz & 0xffff); // safe way to hash a pair of integers
}

ChunkCache::ChunkCache() {
Expand Down Expand Up @@ -43,6 +43,11 @@ ChunkCache::ChunkCache() {
ChunkCache::~ChunkCache() {
}

ChunkCache& ChunkCache::Instance() {
static ChunkCache singleton;
return singleton;
}

void ChunkCache::clear() {
QThreadPool::globalInstance()->waitForDone();
mutex.lock();
Expand All @@ -51,14 +56,27 @@ void ChunkCache::clear() {
}

void ChunkCache::setPath(QString path) {
if (this->path != path)
clear();
this->path = path;
}
QString ChunkCache::getPath() {
QString ChunkCache::getPath() const {
return path;
}

Chunk *ChunkCache::fetch(int x, int z) {
ChunkID id(x, z);
Chunk *ChunkCache::fetchCached(int cx, int cz) {
// try to get Chunk from Cache
ChunkID id(cx, cz);
mutex.lock();
Chunk *chunk = cache[id]; // const operation
mutex.unlock();

return chunk;
}

Chunk *ChunkCache::fetch(int cx, int cz) {
// try to get Chunk from Cache
ChunkID id(cx, cz);
mutex.lock();
Chunk *chunk = cache[id]; // const operation
mutex.unlock();
Expand All @@ -74,23 +92,23 @@ Chunk *ChunkCache::fetch(int x, int z) {
mutex.lock();
cache.insert(id, chunk); // non-const operation !
mutex.unlock();
ChunkLoader *loader = new ChunkLoader(path, x, z, cache, &mutex);
ChunkLoader *loader = new ChunkLoader(path, cx, cz);
connect(loader, SIGNAL(loaded(int, int)),
this, SLOT(gotChunk(int, int)));
QThreadPool::globalInstance()->start(loader);
return NULL;
}

void ChunkCache::gotChunk(int x, int z) {
emit chunkLoaded(x, z);
void ChunkCache::gotChunk(int cx, int cz) {
emit chunkLoaded(cx, cz);
}

void ChunkCache::routeStructure(QSharedPointer<GeneratedStructure> structure) {
emit structureFound(structure);
}

void ChunkCache::adaptCacheToWindow(int x, int y) {
int chunks = ((x + 15) >> 4) * ((y + 15) >> 4); // number of chunks visible
void ChunkCache::adaptCacheToWindow(int wx, int wy) {
int chunks = ((wx + 15) >> 4) * ((wy + 15) >> 4); // number of chunks visible
chunks *= 1.10; // add 10%
cache.setMaxCost(qMin(chunks, maxcache));
}
31 changes: 20 additions & 11 deletions chunkcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,49 @@

class ChunkID {
public:
ChunkID(int x, int z);
ChunkID(int cx, int cz);
bool operator==(const ChunkID &) const;
friend uint qHash(const ChunkID &);
protected:
int x, z;
int cx, cz;
};

class ChunkCache : public QObject {
Q_OBJECT

public:
// singleton: access to global usable instance
static ChunkCache &Instance();
private:
// singleton: prevent access to constructor and copyconstructor
ChunkCache();
~ChunkCache();
ChunkCache(const ChunkCache &);
ChunkCache &operator=(const ChunkCache &);

public:
void clear();
void setPath(QString path);
QString getPath();
Chunk *fetch(int x, int z);
QString getPath() const;
Chunk *fetch(int cx, int cz); // fetch Chunk and load when not found
Chunk *fetchCached(int cx, int cz); // fetch Chunk only if cached

signals:
void chunkLoaded(int x, int z);
void chunkLoaded(int cx, int cz);
void structureFound(QSharedPointer<GeneratedStructure> structure);

public slots:
void adaptCacheToWindow(int x, int y);
void adaptCacheToWindow(int wx, int wy);

private slots:
void gotChunk(int x, int z);
void gotChunk(int cx, int cz);
void routeStructure(QSharedPointer<GeneratedStructure> structure);

private:
QString path;
QCache<ChunkID, Chunk> cache;
QMutex mutex;
int maxcache;
QString path; // path to folder with region files
QCache<ChunkID, Chunk> cache; // real Cache
QMutex mutex; // Mutex for accessing the Cache
int maxcache; // number of Chunks that fit into Cache
};

#endif // CHUNKCACHE_H_
33 changes: 15 additions & 18 deletions chunkloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,47 @@
#include "./chunkcache.h"
#include "./chunk.h"

ChunkLoader::ChunkLoader(QString path, int x, int z,
const QCache<ChunkID, Chunk> &cache,
QMutex *mutex) : path(path), x(x), z(z),
cache(cache), mutex(mutex) {
}
ChunkLoader::~ChunkLoader() {
}
ChunkLoader::ChunkLoader(QString path, int cx, int cz)
: path(path)
, cx(cx), cz(cz)
, cache(ChunkCache::Instance())
{}
ChunkLoader::~ChunkLoader()
{}

void ChunkLoader::run() {
// get coordinates of Region file
int rx = x >> 5;
int rz = z >> 5;
int rx = cx >> 5;
int rz = cz >> 5;

QFile f(path + "/region/r." + QString::number(rx) + "." +
QString::number(rz) + ".mca");
if (!f.open(QIODevice::ReadOnly)) { // no chunks in this region
emit loaded(x, z);
emit loaded(cx, cz);
return;
}
// map header into memory
uchar *header = f.map(0, 4096);
int offset = 4 * ((x & 31) + (z & 31) * 32);
int offset = 4 * ((cx & 31) + (cz & 31) * 32);
int coffset = (header[offset] << 16) | (header[offset + 1] << 8) |
header[offset + 2];
int numSectors = header[offset+3];
f.unmap(header);

if (coffset == 0) { // no chunk
f.close();
emit loaded(x, z);
emit loaded(cx, cz);
return;
}

uchar *raw = f.map(coffset * 4096, numSectors * 4096);
if (raw == NULL) {
f.close();
emit loaded(x, z);
emit loaded(cx, cz);
return;
}
// get existing Chunk entry from Cache
ChunkID id(x, z);
mutex->lock();
Chunk *chunk = cache[id]; // const operation
mutex->unlock();
Chunk *chunk = cache.fetchCached(cx, cz);
// parse Chunk data
// Chunk will be flagged "loaded" in a thread save way
if (chunk) {
Expand All @@ -57,5 +54,5 @@ void ChunkLoader::run() {
f.unmap(raw);
f.close();

emit loaded(x, z);
emit loaded(cx, cz);
}
17 changes: 8 additions & 9 deletions chunkloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,25 @@

#include <QObject>
#include <QRunnable>
class Chunk;
class ChunkID;
class QMutex;
#include "chunkcache.h"

class ChunkLoader : public QObject, public QRunnable {
Q_OBJECT

public:
ChunkLoader(QString path, int x, int z, const QCache<ChunkID, Chunk> &cache,
QMutex *mutex);
ChunkLoader(QString path, int cx, int cz);
~ChunkLoader();

signals:
void loaded(int x, int z);
void loaded(int cx, int cz);

protected:
void run();

private:
QString path;
int x, z;
const QCache<ChunkID, Chunk> &cache;
QMutex *mutex;
int cx, cz;
ChunkCache &cache;
};

#endif // CHUNKLOADER_H_
7 changes: 6 additions & 1 deletion mapview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@
#include <assert.h>

#include "./mapview.h"
#include "./chunkcache.h"
#include "./definitionmanager.h"
#include "./blockidentifier.h"
#include "./biomeidentifier.h"
#include "./clamp.h"

MapView::MapView(QWidget *parent) : QWidget(parent) {
MapView::MapView(QWidget *parent)
: QWidget(parent)
, cache(ChunkCache::Instance())
{
depth = 255;
scale = 1;
zoom = 1.0;
Expand Down Expand Up @@ -361,6 +365,7 @@ void MapView::drawChunk(int x, int z) {
uchar *src = placeholder;
// fetch the chunk
Chunk *chunk = cache.fetch(x, z);
if (chunk && !chunk->loaded) return;

if (chunk && (chunk->renderedAt != depth ||
chunk->renderedFlags != flags)) {
Expand Down
2 changes: 1 addition & 1 deletion mapview.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class MapView : public QWidget {
int scale;
double zoom;
int flags;
ChunkCache cache;
ChunkCache &cache;
QImage image;
DefinitionManager *dm;
uchar placeholder[16 * 16 * 4]; // no chunk found placeholder
Expand Down

0 comments on commit b62b1a4

Please sign in to comment.