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 "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 "../coders/byte_utils.h"
#include "../util/data_io.h"
#include "../coders/json.h" #include "../coders/json.h"
#include "../constants.h" #include "../constants.h"
#include "../items/ItemDef.h" #include "../content/Content.h"
#include "../items/Inventory.h"
#include "../data/dynamic.h"
#include "../core_defs.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 <cassert>
#include <iostream> #include <iostream>
@ -48,7 +46,8 @@ regfile::regfile(fs::path filename) : file(filename) {
version = header[8]; version = header[8];
if (uint(version) > REGION_FORMAT_VERSION) { if (uint(version) > REGION_FORMAT_VERSION) {
throw illegal_region_format( 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]; return sizes[z * REGION_SIZE + x];
} }
WorldFiles::WorldFiles(fs::path directory, const DebugSettings& settings) WorldFiles::WorldFiles(fs::path directory) : directory(directory) {
: directory(directory),
generatorTestMode(settings.generatorTestMode),
doWriteLights(settings.doWriteLights)
{
compressionBuffer = std::make_unique<ubyte[]>(CHUNK_DATA_LEN * 2);
// just ignore this
for (uint i = 0; i < sizeof(layers)/sizeof(RegionsLayer); i++) { for (uint i = 0; i < sizeof(layers)/sizeof(RegionsLayer); i++) {
layers[i].layer = 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"); 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() { 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) { 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); auto data = std::make_unique<ubyte[]>(len);
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
data[i] = buffer[i]; data[i] = bytes[i];
} }
return data; return data;
} }
@ -164,10 +165,6 @@ inline void calc_reg_coords(
localZ = z - (regionZ * REGION_SIZE); 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) { void WorldFiles::put(int x, int z, int layer, std::unique_ptr<ubyte[]> data, size_t size, bool rle) {
if (rle) { if (rle) {
size_t compressedSize; size_t compressedSize;
@ -318,7 +315,7 @@ ubyte* WorldFiles::getData(
if (data == nullptr) { if (data == nullptr) {
auto regfile = getRegFile(glm::ivec3(regionX, regionZ, layer)); auto regfile = getRegFile(glm::ivec3(regionX, regionZ, layer));
if (regfile != nullptr) { if (regfile != nullptr) {
data = readChunkData(x, z, size, regfile.get()); data = readChunkData(x, z, size, regfile.get()).release();
} }
if (data != nullptr) { if (data != nullptr) {
region->put(localX, localZ, data, size); 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 x,
int z, int z,
uint32_t& length, uint32_t& length,
@ -405,7 +402,6 @@ ubyte* WorldFiles::readChunkData(
int chunkIndex = localZ * REGION_SIZE + localX; int chunkIndex = localZ * REGION_SIZE + localX;
files::rafile& file = rfile->file; files::rafile& file = rfile->file;
size_t file_size = file.length(); size_t file_size = file.length();
size_t table_offset = file_size - REGION_CHUNKS_COUNT * 4; size_t table_offset = file_size - REGION_CHUNKS_COUNT * 4;
@ -420,8 +416,8 @@ ubyte* WorldFiles::readChunkData(
file.seekg(offset); file.seekg(offset);
file.read((char*)(&offset), 4); file.read((char*)(&offset), 4);
length = dataio::read_int32_big((const ubyte*)(&offset), 0); length = dataio::read_int32_big((const ubyte*)(&offset), 0);
ubyte* data = new ubyte[length]{}; auto data = std::make_unique<ubyte[]>(length);
file.read((char*)data, length); file.read((char*)data.get(), length);
return data; 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_x = (i % REGION_SIZE) + x * REGION_SIZE;
int chunk_z = (i / REGION_SIZE) + z * REGION_SIZE; int chunk_z = (i / REGION_SIZE) + z * REGION_SIZE;
if (chunks[i] == nullptr) { 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){ void WorldFiles::writeRegion(int x, int z, int layer, WorldRegion* entry){
fs::path filename = layers[layer].folder/getRegionFilename(x, z); 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 "../settings.h"
#include "../content/ContentPack.h" #include "../content/ContentPack.h"
#include "../voxels/Chunk.h" #include "../voxels/Chunk.h"
#include "../util/BufferPool.h"
#include <map> #include <map>
#include <mutex> #include <mutex>
@ -84,13 +85,17 @@ struct RegionsLayer {
}; };
class WorldFiles { class WorldFiles {
fs::path directory;
std::unordered_map<glm::ivec3, std::unique_ptr<regfile>> openRegFiles; std::unordered_map<glm::ivec3, std::unique_ptr<regfile>> openRegFiles;
std::mutex regFilesMutex; std::mutex regFilesMutex;
std::condition_variable regFilesCv; std::condition_variable regFilesCv;
RegionsLayer layers[3] {}; 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 getRegionFilename(int x, int y) const;
fs::path getWorldFile() const; fs::path getWorldFile() const;
fs::path getIndicesFile() const; fs::path getIndicesFile() const;
@ -112,12 +117,13 @@ class WorldFiles {
/// @param dstlen max expected length of source buffer /// @param dstlen max expected length of source buffer
/// @return decompressed bytes array /// @return decompressed bytes array
std::unique_ptr<ubyte[]> decompress(const ubyte* src, size_t srclen, size_t dstlen); std::unique_ptr<ubyte[]> decompress(const ubyte* src, size_t srclen, size_t dstlen);
std::unique_ptr<ubyte[]> readChunkData(int x, int y, uint32_t& length, regfile* file);
ubyte* readChunkData(int x, int y, uint32_t& length, regfile* file);
void fetchChunks(WorldRegion* region, int x, int y, regfile* file); void fetchChunks(WorldRegion* region, int x, int y, regfile* file);
void writeWorldInfo(const World* world);
void writeRegions(int layer); void writeRegions(int layer);
void writeIndices(const ContentIndices* indices);
ubyte* getData(int x, int z, int layer, uint32_t& size); 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> useRegFile(glm::ivec3 coord);
std::shared_ptr<regfile> createRegFile(glm::ivec3 coord); std::shared_ptr<regfile> createRegFile(glm::ivec3 coord);
public: public:
static bool parseRegionFilename(const std::string& name, int& x, int& y); WorldFiles(fs::path directory);
fs::path getPlayerFile() const;
fs::path directory;
std::unique_ptr<ubyte[]> compressionBuffer;
bool generatorTestMode;
bool doWriteLights;
WorldFiles(fs::path directory, const DebugSettings& settings); WorldFiles(fs::path directory, const DebugSettings& settings);
~WorldFiles(); ~WorldFiles();
fs::path getPlayerFile() const;
void createDirectories(); void createDirectories();
/// @brief Put all chunk data to regions
void put(Chunk* chunk); 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); 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); std::unique_ptr<ubyte[]> getChunk(int x, int z);
@ -148,6 +157,10 @@ public:
bool readWorldInfo(World* world); 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); void writeRegion(int x, int y, int layer, WorldRegion* entry);
/// @brief Write all unsaved data to world files /// @brief Write all unsaved data to world files
@ -156,17 +169,17 @@ public:
void write(const World* world, const Content* content); void write(const World* world, const Content* content);
void writePacks(const std::vector<ContentPack>& packs); void writePacks(const std::vector<ContentPack>& packs);
void writeIndices(const ContentIndices* indices);
void removeIndices(const std::vector<std::string>& packs); void removeIndices(const std::vector<std::string>& packs);
void processRegionVoxels(int x, int z, regionproc func); 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) { static const inline std::string WORLD_FILE = "world.json";
return layers[layer].folder; static bool parseRegionFilename(const std::string& name, int& x, int& y);
}
}; };
#endif /* FILES_WORLDFILES_H_ */ #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) { 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(nullptr);
engine->setScreen(std::make_shared<MenuScreen>(engine)); engine->setScreen(std::make_shared<MenuScreen>(engine));
menus::open_world(wname, engine, true); menus::open_world(wname, engine, true);
@ -140,7 +140,7 @@ void menus::remove_packs(
runnable removeFunc = [=]() { runnable removeFunc = [=]() {
controller->saveWorld(); controller->saveWorld();
auto manager = engine->createPacksManager(world->wfile->directory); auto manager = engine->createPacksManager(world->wfile->getFolder());
manager.scan(); manager.scan();
auto names = PacksManager::getNames(world->getPacks()); 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()); auto new_packs = PacksManager::getNames(world->getPacks());
new_packs.push_back(pack.id); new_packs.push_back(pack.id);
auto manager = engine->createPacksManager(world->wfile->directory); auto manager = engine->createPacksManager(world->wfile->getFolder());
manager.scan(); manager.scan();
try { try {
new_packs = manager.assembly(new_packs); 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_