BufferPool

This commit is contained in:
MihailRis 2024-04-15 00:31:19 +03:00
parent a7a447552e
commit 4e5f6a5a7d
4 changed files with 113 additions and 64 deletions

View File

@ -1,27 +1,25 @@
#include "WorldFiles.h"
#include "rle.h"
#include "../window/Camera.h"
#include "../content/Content.h"
#include "../objects/Player.h"
#include "../physics/Hitbox.h"
#include "../voxels/voxel.h"
#include "../voxels/Block.h"
#include "../voxels/Chunk.h"
#include "../typedefs.h"
#include "../maths/voxmaths.h"
#include "../world/World.h"
#include "../lighting/Lightmap.h"
#include "../coders/byte_utils.h"
#include "../util/data_io.h"
#include "../coders/json.h"
#include "../constants.h"
#include "../items/ItemDef.h"
#include "../items/Inventory.h"
#include "../data/dynamic.h"
#include "../content/Content.h"
#include "../core_defs.h"
#include "../data/dynamic.h"
#include "../items/Inventory.h"
#include "../items/ItemDef.h"
#include "../lighting/Lightmap.h"
#include "../maths/voxmaths.h"
#include "../objects/Player.h"
#include "../physics/Hitbox.h"
#include "../typedefs.h"
#include "../util/data_io.h"
#include "../voxels/Block.h"
#include "../voxels/Chunk.h"
#include "../voxels/voxel.h"
#include "../window/Camera.h"
#include "../world/World.h"
#include "rle.h"
#include <cassert>
#include <iostream>
@ -48,7 +46,8 @@ regfile::regfile(fs::path filename) : file(filename) {
version = header[8];
if (uint(version) > REGION_FORMAT_VERSION) {
throw illegal_region_format(
"region format "+std::to_string(version)+" is not supported");
"region format "+std::to_string(version)+" is not supported"
);
}
}
@ -95,13 +94,7 @@ uint WorldRegion::getChunkDataSize(uint x, uint z) {
return sizes[z * REGION_SIZE + x];
}
WorldFiles::WorldFiles(fs::path directory, const DebugSettings& settings)
: directory(directory),
generatorTestMode(settings.generatorTestMode),
doWriteLights(settings.doWriteLights)
{
compressionBuffer = std::make_unique<ubyte[]>(CHUNK_DATA_LEN * 2);
// just ignore this
WorldFiles::WorldFiles(fs::path directory) : directory(directory) {
for (uint i = 0; i < sizeof(layers)/sizeof(RegionsLayer); i++) {
layers[i].layer = i;
}
@ -110,6 +103,13 @@ WorldFiles::WorldFiles(fs::path directory, const DebugSettings& settings)
layers[REGION_LAYER_INVENTORIES].folder = directory/fs::path("inventories");
}
WorldFiles::WorldFiles(fs::path directory, const DebugSettings& settings)
: WorldFiles(directory)
{
generatorTestMode = settings.generatorTestMode;
doWriteLights = settings.doWriteLights;
}
WorldFiles::~WorldFiles() {
}
@ -139,12 +139,13 @@ WorldRegion* WorldFiles::getOrCreateRegion(int x, int z, int layer) {
}
std::unique_ptr<ubyte[]> WorldFiles::compress(const ubyte* src, size_t srclen, size_t& len) {
ubyte* buffer = this->compressionBuffer.get();
auto buffer = bufferPool.get();
ubyte* bytes = buffer.get();
len = extrle::encode(src, srclen, buffer);
len = extrle::encode(src, srclen, bytes);
auto data = std::make_unique<ubyte[]>(len);
for (size_t i = 0; i < len; i++) {
data[i] = buffer[i];
data[i] = bytes[i];
}
return data;
}
@ -164,10 +165,6 @@ inline void calc_reg_coords(
localZ = z - (regionZ * REGION_SIZE);
}
/// @brief Store chunk voxels data in region
/// @param x chunk.x
/// @param z chunk.z
void WorldFiles::put(int x, int z, int layer, std::unique_ptr<ubyte[]> data, size_t size, bool rle) {
if (rle) {
size_t compressedSize;
@ -318,7 +315,7 @@ ubyte* WorldFiles::getData(
if (data == nullptr) {
auto regfile = getRegFile(glm::ivec3(regionX, regionZ, layer));
if (regfile != nullptr) {
data = readChunkData(x, z, size, regfile.get());
data = readChunkData(x, z, size, regfile.get()).release();
}
if (data != nullptr) {
region->put(localX, localZ, data, size);
@ -391,7 +388,7 @@ std::shared_ptr<regfile> WorldFiles::createRegFile(glm::ivec3 coord) {
}
}
ubyte* WorldFiles::readChunkData(
std::unique_ptr<ubyte[]> WorldFiles::readChunkData(
int x,
int z,
uint32_t& length,
@ -405,7 +402,6 @@ ubyte* WorldFiles::readChunkData(
int chunkIndex = localZ * REGION_SIZE + localX;
files::rafile& file = rfile->file;
size_t file_size = file.length();
size_t table_offset = file_size - REGION_CHUNKS_COUNT * 4;
@ -420,8 +416,8 @@ ubyte* WorldFiles::readChunkData(
file.seekg(offset);
file.read((char*)(&offset), 4);
length = dataio::read_int32_big((const ubyte*)(&offset), 0);
ubyte* data = new ubyte[length]{};
file.read((char*)data, length);
auto data = std::make_unique<ubyte[]>(length);
file.read((char*)data.get(), length);
return data;
}
@ -434,16 +430,11 @@ void WorldFiles::fetchChunks(WorldRegion* region, int x, int z, regfile* file) {
int chunk_x = (i % REGION_SIZE) + x * REGION_SIZE;
int chunk_z = (i / REGION_SIZE) + z * REGION_SIZE;
if (chunks[i] == nullptr) {
chunks[i] = readChunkData(chunk_x, chunk_z, sizes[i], file);
chunks[i] = readChunkData(chunk_x, chunk_z, sizes[i], file).release();
}
}
}
/// @brief Write or rewrite region file
/// @param x region X
/// @param z region Z
/// @param layer used as third part of openRegFiles map key
/// (see REGION_LAYER_* constants)
void WorldFiles::writeRegion(int x, int z, int layer, WorldRegion* entry){
fs::path filename = layers[layer].folder/getRegionFilename(x, z);
@ -616,3 +607,11 @@ void WorldFiles::processRegionVoxels(int x, int z, regionproc func) {
}
}
}
fs::path WorldFiles::getFolder() const {
return directory;
}
fs::path WorldFiles::getRegionsFolder(int layer) const {
return layers[layer].folder;
}

View File

@ -6,6 +6,7 @@
#include "../settings.h"
#include "../content/ContentPack.h"
#include "../voxels/Chunk.h"
#include "../util/BufferPool.h"
#include <map>
#include <mutex>
@ -84,13 +85,17 @@ struct RegionsLayer {
};
class WorldFiles {
fs::path directory;
std::unordered_map<glm::ivec3, std::unique_ptr<regfile>> openRegFiles;
std::mutex regFilesMutex;
std::condition_variable regFilesCv;
RegionsLayer layers[3] {};
bool generatorTestMode = false;
bool doWriteLights = true;
util::BufferPool<ubyte> bufferPool {
std::max(CHUNK_DATA_LEN, LIGHTMAP_DATA_LEN) * 2
};
void writeWorldInfo(const World* world);
fs::path getRegionFilename(int x, int y) const;
fs::path getWorldFile() const;
fs::path getIndicesFile() const;
@ -112,12 +117,13 @@ class WorldFiles {
/// @param dstlen max expected length of source buffer
/// @return decompressed bytes array
std::unique_ptr<ubyte[]> decompress(const ubyte* src, size_t srclen, size_t dstlen);
ubyte* readChunkData(int x, int y, uint32_t& length, regfile* file);
std::unique_ptr<ubyte[]> readChunkData(int x, int y, uint32_t& length, regfile* file);
void fetchChunks(WorldRegion* region, int x, int y, regfile* file);
void writeWorldInfo(const World* world);
void writeRegions(int layer);
void writeIndices(const ContentIndices* indices);
ubyte* getData(int x, int z, int layer, uint32_t& size);
@ -126,20 +132,23 @@ class WorldFiles {
std::shared_ptr<regfile> useRegFile(glm::ivec3 coord);
std::shared_ptr<regfile> createRegFile(glm::ivec3 coord);
public:
static bool parseRegionFilename(const std::string& name, int& x, int& y);
fs::path getPlayerFile() const;
fs::path directory;
std::unique_ptr<ubyte[]> compressionBuffer;
bool generatorTestMode;
bool doWriteLights;
WorldFiles(fs::path directory);
WorldFiles(fs::path directory, const DebugSettings& settings);
~WorldFiles();
fs::path getPlayerFile() const;
void createDirectories();
/// @brief Put all chunk data to regions
void put(Chunk* chunk);
/// @brief Store data in specified region
/// @param x chunk.x
/// @param z chunk.z
/// @param layer regions layer
/// @param data target data
/// @param size data size
/// @param rle compress with ext-RLE
void put(int x, int z, int layer, std::unique_ptr<ubyte[]> data, size_t size, bool rle);
std::unique_ptr<ubyte[]> getChunk(int x, int z);
@ -148,6 +157,10 @@ public:
bool readWorldInfo(World* world);
/// @brief Write or rewrite region file
/// @param x region X
/// @param z region Z
/// @param layer regions layer
void writeRegion(int x, int y, int layer, WorldRegion* entry);
/// @brief Write all unsaved data to world files
@ -156,17 +169,17 @@ public:
void write(const World* world, const Content* content);
void writePacks(const std::vector<ContentPack>& packs);
void writeIndices(const ContentIndices* indices);
void removeIndices(const std::vector<std::string>& packs);
void processRegionVoxels(int x, int z, regionproc func);
static const inline std::string WORLD_FILE = "world.json";
/// @return world folder
fs::path getFolder() const;
fs::path getRegionsFolder(int layer) const;
fs::path getRegionsFolder(int layer) {
return layers[layer].folder;
}
static const inline std::string WORLD_FILE = "world.json";
static bool parseRegionFilename(const std::string& name, int& x, int& y);
};
#endif /* FILES_WORLDFILES_H_ */

View File

@ -112,7 +112,7 @@ std::shared_ptr<Panel> menus::create_packs_panel(
}
static void reopen_world(Engine* engine, World* world) {
std::string wname = world->wfile->directory.stem().u8string();
std::string wname = world->wfile->getFolder().stem().u8string();
engine->setScreen(nullptr);
engine->setScreen(std::make_shared<MenuScreen>(engine));
menus::open_world(wname, engine, true);
@ -140,7 +140,7 @@ void menus::remove_packs(
runnable removeFunc = [=]() {
controller->saveWorld();
auto manager = engine->createPacksManager(world->wfile->directory);
auto manager = engine->createPacksManager(world->wfile->getFolder());
manager.scan();
auto names = PacksManager::getNames(world->getPacks());
@ -199,7 +199,7 @@ void create_content_panel(Engine* engine, LevelController* controller) {
auto new_packs = PacksManager::getNames(world->getPacks());
new_packs.push_back(pack.id);
auto manager = engine->createPacksManager(world->wfile->directory);
auto manager = engine->createPacksManager(world->wfile->getFolder());
manager.scan();
try {
new_packs = manager.assembly(new_packs);

37
src/util/BufferPool.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef UTIL_BUFFER_POOL_H_
#define UTIL_BUFFER_POOL_H_
#include "../typedefs.h"
#include <queue>
#include <mutex>
#include <vector>
#include <memory>
namespace util {
template<class T>
class BufferPool {
std::vector<std::unique_ptr<T[]>> buffers;
std::queue<T*> freeBuffers;
std::mutex mutex;
size_t bufferSize;
public:
BufferPool(size_t bufferSize) : bufferSize(bufferSize) {
}
std::shared_ptr<T[]> get() {
std::lock_guard lock(mutex);
if (freeBuffers.empty()) {
buffers.emplace_back(std::make_unique<T[]>(bufferSize));
freeBuffers.push(buffers[buffers.size()-1].get());
}
auto* buffer = freeBuffers.front();
freeBuffers.pop();
return std::shared_ptr<T[]>(buffer, [this](T* ptr) {
freeBuffers.push(ptr);
});
}
};
}
#endif // UTIL_BUFFER_POOL_H_